Skip to content

Commit 952d4b4

Browse files
authored
[CIR] Fix assignment ignore in ScalarExprEmitter (#166118)
We are missing a couple of cases were we are not supposed to ignore assignment results but did so, which results in compiler crashes. Fix that. Also start ignoring IgnoredExprs unless there's side effects (assignments) inside.
1 parent 0c73009 commit 952d4b4

File tree

4 files changed

+126
-6
lines changed

4 files changed

+126
-6
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1630,7 +1630,7 @@ RValue CIRGenFunction::emitAnyExpr(const Expr *e, AggValueSlot aggSlot,
16301630
bool ignoreResult) {
16311631
switch (CIRGenFunction::getEvaluationKind(e->getType())) {
16321632
case cir::TEK_Scalar:
1633-
return RValue::get(emitScalarExpr(e));
1633+
return RValue::get(emitScalarExpr(e, ignoreResult));
16341634
case cir::TEK_Complex:
16351635
return RValue::getComplex(emitComplexExpr(e));
16361636
case cir::TEK_Aggregate: {

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,15 @@ struct BinOpInfo {
7878
class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
7979
CIRGenFunction &cgf;
8080
CIRGenBuilderTy &builder;
81+
// Unlike classic codegen we set this to false or use std::exchange to read
82+
// the value instead of calling TestAndClearIgnoreResultAssign to make it
83+
// explicit when the value is used
8184
bool ignoreResultAssign;
8285

8386
public:
84-
ScalarExprEmitter(CIRGenFunction &cgf, CIRGenBuilderTy &builder)
85-
: cgf(cgf), builder(builder) {}
87+
ScalarExprEmitter(CIRGenFunction &cgf, CIRGenBuilderTy &builder,
88+
bool ignoreResultAssign = false)
89+
: cgf(cgf), builder(builder), ignoreResultAssign(ignoreResultAssign) {}
8690

8791
//===--------------------------------------------------------------------===//
8892
// Utilities
@@ -221,6 +225,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
221225
}
222226

223227
mlir::Value VisitArraySubscriptExpr(ArraySubscriptExpr *e) {
228+
ignoreResultAssign = false;
229+
224230
if (e->getBase()->getType()->isVectorType()) {
225231
assert(!cir::MissingFeatures::scalableVectors());
226232

@@ -839,6 +845,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
839845

840846
BinOpInfo emitBinOps(const BinaryOperator *e,
841847
QualType promotionType = QualType()) {
848+
ignoreResultAssign = false;
842849
BinOpInfo result;
843850
result.lhs = cgf.emitPromotedScalarExpr(e->getLHS(), promotionType);
844851
result.rhs = cgf.emitPromotedScalarExpr(e->getRHS(), promotionType);
@@ -924,6 +931,7 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
924931
#undef HANDLEBINOP
925932

926933
mlir::Value emitCmp(const BinaryOperator *e) {
934+
ignoreResultAssign = false;
927935
const mlir::Location loc = cgf.getLoc(e->getExprLoc());
928936
mlir::Value result;
929937
QualType lhsTy = e->getLHS()->getType();
@@ -1406,11 +1414,13 @@ CIRGenFunction::emitCompoundAssignmentLValue(const CompoundAssignOperator *e) {
14061414
}
14071415

14081416
/// Emit the computation of the specified expression of scalar type.
1409-
mlir::Value CIRGenFunction::emitScalarExpr(const Expr *e) {
1417+
mlir::Value CIRGenFunction::emitScalarExpr(const Expr *e,
1418+
bool ignoreResultAssign) {
14101419
assert(e && hasScalarEvaluationKind(e->getType()) &&
14111420
"Invalid scalar expression to emit");
14121421

1413-
return ScalarExprEmitter(*this, builder).Visit(const_cast<Expr *>(e));
1422+
return ScalarExprEmitter(*this, builder, ignoreResultAssign)
1423+
.Visit(const_cast<Expr *>(e));
14141424
}
14151425

14161426
mlir::Value CIRGenFunction::emitPromotedScalarExpr(const Expr *e,
@@ -2054,6 +2064,11 @@ mlir::Value ScalarExprEmitter::VisitMemberExpr(MemberExpr *e) {
20542064
mlir::Value ScalarExprEmitter::VisitInitListExpr(InitListExpr *e) {
20552065
const unsigned numInitElements = e->getNumInits();
20562066

2067+
[[maybe_unused]] const bool ignore = std::exchange(ignoreResultAssign, false);
2068+
assert((ignore == false ||
2069+
(numInitElements == 0 && e->getType()->isVoidType())) &&
2070+
"init list ignored");
2071+
20572072
if (e->hadArrayRangeDesignator()) {
20582073
cgf.cgm.errorNYI(e->getSourceRange(), "ArrayRangeDesignator");
20592074
return {};

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,8 @@ class CIRGenFunction : public CIRGenTypeCache {
15011501
llvm::ArrayRef<mlir::Value> args = {});
15021502

15031503
/// Emit the computation of the specified expression of scalar type.
1504-
mlir::Value emitScalarExpr(const clang::Expr *e);
1504+
mlir::Value emitScalarExpr(const clang::Expr *e,
1505+
bool ignoreResultAssign = false);
15051506

15061507
mlir::Value emitScalarPrePostIncDec(const UnaryOperator *e, LValue lv,
15071508
cir::UnaryOpKind kind, bool isPre);

clang/test/CIR/CodeGen/binassign.c

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,107 @@ void binary_assign_struct() {
100100
// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[LS_PTR]], ptr align 4 @gs, i64 8, i1 false)
101101
// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[LSV_PTR]], ptr align 4 @gsv, i64 8, i1 true)
102102
// OGCG: ret void
103+
104+
int ignore_result_assign() {
105+
int arr[10];
106+
int i, j;
107+
j = i = 123, 0;
108+
j = arr[i = 5];
109+
int *p, *q = 0;
110+
if(p = q)
111+
return 1;
112+
return 0;
113+
}
114+
115+
// CIR-LABEL: cir.func{{.*}} @ignore_result_assign() -> !s32i
116+
// CIR: %[[RETVAL:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["__retval"]
117+
// CIR: %[[ARR:.*]] = cir.alloca !cir.array<!s32i x 10>, !cir.ptr<!cir.array<!s32i x 10>>, ["arr"]
118+
// CIR: %[[I:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i"]
119+
// CIR: %[[J:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["j"]
120+
// CIR: %[[P:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["p"]
121+
// CIR: %[[Q:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["q", init]
122+
// CIR: %[[VAL_123:.*]] = cir.const #cir.int<123> : !s32i
123+
// CIR: cir.store{{.*}} %[[VAL_123]], %[[I]] : !s32i, !cir.ptr<!s32i>
124+
// CIR: cir.store{{.*}} %[[VAL_123]], %[[J]] : !s32i, !cir.ptr<!s32i>
125+
// CIR: %[[VAL_0:.*]] = cir.const #cir.int<0> : !s32i
126+
// CIR: %[[VAL_5:.*]] = cir.const #cir.int<5> : !s32i
127+
// CIR: cir.store{{.*}} %[[VAL_5]], %[[I]] : !s32i, !cir.ptr<!s32i>
128+
// CIR: %[[ARR_DECAY:.*]] = cir.cast array_to_ptrdecay %[[ARR]] : !cir.ptr<!cir.array<!s32i x 10>> -> !cir.ptr<!s32i>
129+
// CIR: %[[ARR_ELEM:.*]] = cir.ptr_stride %[[ARR_DECAY]], %[[VAL_5]] : (!cir.ptr<!s32i>, !s32i) -> !cir.ptr<!s32i>
130+
// CIR: %[[ARR_LOAD:.*]] = cir.load{{.*}} %[[ARR_ELEM]] : !cir.ptr<!s32i>, !s32i
131+
// CIR: cir.store{{.*}} %[[ARR_LOAD]], %[[J]] : !s32i, !cir.ptr<!s32i>
132+
// CIR: %[[NULL:.*]] = cir.const #cir.ptr<null> : !cir.ptr<!s32i>
133+
// CIR: cir.store{{.*}} %[[NULL]], %[[Q]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
134+
// CIR: cir.scope {
135+
// CIR: %[[Q_VAL:.*]] = cir.load{{.*}} %[[Q]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
136+
// CIR: cir.store{{.*}} %[[Q_VAL]], %[[P]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>
137+
// CIR: %[[COND:.*]] = cir.cast ptr_to_bool %[[Q_VAL]] : !cir.ptr<!s32i> -> !cir.bool
138+
// CIR: cir.if %[[COND]] {
139+
// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
140+
// CIR: cir.store %[[ONE]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i>
141+
// CIR: %{{.*}} = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i
142+
// CIR: cir.return
143+
// CIR: }
144+
// CIR: }
145+
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
146+
// CIR: cir.store %[[ZERO]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i>
147+
// CIR: %{{.*}} = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i
148+
// CIR: cir.return
149+
150+
// LLVM-LABEL: define {{.*}}i32 @ignore_result_assign()
151+
// LLVM: %[[RETVAL_PTR:.*]] = alloca i32
152+
// LLVM: %[[ARR_PTR:.*]] = alloca [10 x i32]
153+
// LLVM: %[[I_PTR:.*]] = alloca i32
154+
// LLVM: %[[J_PTR:.*]] = alloca i32
155+
// LLVM: %[[P_PTR:.*]] = alloca ptr
156+
// LLVM: %[[Q_PTR:.*]] = alloca ptr
157+
// LLVM: store i32 123, ptr %[[I_PTR]]
158+
// LLVM: store i32 123, ptr %[[J_PTR]]
159+
// LLVM: store i32 5, ptr %[[I_PTR]]
160+
// LLVM: %[[GEP1:.*]] = getelementptr i32, ptr %[[ARR_PTR]], i32 0
161+
// LLVM: %[[GEP2:.*]] = getelementptr i32, ptr %[[GEP1]], i64 5
162+
// LLVM: %[[ARR_VAL:.*]] = load i32, ptr %[[GEP2]]
163+
// LLVM: store i32 %[[ARR_VAL]], ptr %[[J_PTR]]
164+
// LLVM: store ptr null, ptr %[[Q_PTR]]
165+
// LLVM: br label
166+
// LLVM: %[[Q_VAL:.*]] = load ptr, ptr %[[Q_PTR]]
167+
// LLVM: store ptr %[[Q_VAL]], ptr %[[P_PTR]]
168+
// LLVM: %[[CMP:.*]] = icmp ne ptr %[[Q_VAL]], null
169+
// LLVM: br i1 %[[CMP]], label %[[THEN:.*]], label %[[ELSE:.*]]
170+
// LLVM: [[THEN]]:
171+
// LLVM: store i32 1, ptr %[[RETVAL_PTR]]
172+
// LLVM: %{{.*}} = load i32, ptr %[[RETVAL_PTR]]
173+
// LLVM: ret i32
174+
// LLVM: [[ELSE]]:
175+
// LLVM: br label
176+
// LLVM: store i32 0, ptr %[[RETVAL_PTR]]
177+
// LLVM: %{{.*}} = load i32, ptr %[[RETVAL_PTR]]
178+
// LLVM: ret i32
179+
180+
// OGCG-LABEL: define {{.*}}i32 @ignore_result_assign()
181+
// OGCG: %[[RETVAL:.*]] = alloca i32
182+
// OGCG: %[[ARR:.*]] = alloca [10 x i32]
183+
// OGCG: %[[I:.*]] = alloca i32
184+
// OGCG: %[[J:.*]] = alloca i32
185+
// OGCG: %[[P:.*]] = alloca ptr
186+
// OGCG: %[[Q:.*]] = alloca ptr
187+
// OGCG: store i32 123, ptr %[[I]]
188+
// OGCG: store i32 123, ptr %[[J]]
189+
// OGCG: store i32 5, ptr %[[I]]
190+
// OGCG: %[[ARRAYIDX:.*]] = getelementptr inbounds [10 x i32], ptr %[[ARR]], i64 0, i64 5
191+
// OGCG: %[[ARR_VAL:.*]] = load i32, ptr %[[ARRAYIDX]]
192+
// OGCG: store i32 %[[ARR_VAL]], ptr %[[J]]
193+
// OGCG: store ptr null, ptr %[[Q]]
194+
// OGCG: %[[Q_VAL:.*]] = load ptr, ptr %[[Q]]
195+
// OGCG: store ptr %[[Q_VAL]], ptr %[[P]]
196+
// OGCG: %[[TOBOOL:.*]] = icmp ne ptr %[[Q_VAL]], null
197+
// OGCG: br i1 %[[TOBOOL]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
198+
// OGCG: [[IF_THEN]]:
199+
// OGCG: store i32 1, ptr %[[RETVAL]]
200+
// OGCG: br label %[[RETURN:.*]]
201+
// OGCG: [[IF_END]]:
202+
// OGCG: store i32 0, ptr %[[RETVAL]]
203+
// OGCG: br label %[[RETURN]]
204+
// OGCG: [[RETURN]]:
205+
// OGCG: %{{.*}} = load i32, ptr %[[RETVAL]]
206+
// OGCG: ret i32

0 commit comments

Comments
 (0)