Skip to content

Commit 78b01a3

Browse files
keryelllanza
authored andcommitted
[CIR][CIRGen] Implement "if constexpr" code generation (#436)
1 parent 84f410e commit 78b01a3

File tree

2 files changed

+106
-0
lines changed

2 files changed

+106
-0
lines changed

clang/lib/CIR/CodeGen/CIRGenStmt.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,17 @@ mlir::LogicalResult CIRGenFunction::buildIfStmt(const IfStmt &S) {
401401
bool CondConstant;
402402
if (ConstantFoldsToSimpleInteger(S.getCond(), CondConstant,
403403
S.isConstexpr())) {
404+
if (S.isConstexpr()) {
405+
// Handle "if constexpr" explicitly here to avoid generating some
406+
// ill-formed code since in CIR the "if" is no longer simplified
407+
// in this lambda like in Clang but postponed to other MLIR
408+
// passes.
409+
if (const Stmt *Executed = CondConstant ? S.getThen() : S.getElse())
410+
return buildStmt(Executed, /*useCurrentScope=*/true);
411+
// There is nothing to execute at runtime.
412+
// TODO(cir): there is still an empty cir.scope generated by the caller.
413+
return mlir::success();
414+
}
404415
assert(!UnimplementedFeature::constantFoldsToSimpleInteger());
405416
}
406417

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir-enable -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s
3+
4+
void if0() {
5+
int x = 0;
6+
if constexpr (0 == 0) {
7+
// Declare a variable with same name to be sure we handle the
8+
// scopes correctly
9+
int x = 2;
10+
} else {
11+
int x = 3;
12+
}
13+
if constexpr (0 == 1) {
14+
int x = 4;
15+
} else {
16+
int x = 5;
17+
}
18+
if constexpr (int x = 7; 8 == 8) {
19+
int y = x;
20+
} else {
21+
int y = 2*x;
22+
}
23+
if constexpr (int x = 9; 8 == 10) {
24+
int y = x;
25+
} else {
26+
int y = 3*x;
27+
}
28+
if constexpr (10 == 10) {
29+
int x = 20;
30+
}
31+
if constexpr (10 == 11) {
32+
int x = 30;
33+
}
34+
if constexpr (int x = 70; 80 == 80) {
35+
int y = 10*x;
36+
}
37+
if constexpr (int x = 90; 80 == 100) {
38+
int y = 11*x;
39+
}
40+
}
41+
42+
// CHECK: cir.func @_Z3if0v() {{.*}}
43+
// CHECK: cir.store %1, %0 : !s32i, cir.ptr <!s32i> loc({{.*}})
44+
// CHECK-NEXT: cir.scope {
45+
// CHECK-NEXT: %2 = cir.alloca !s32i, cir.ptr <!s32i>, ["x", init] {{.*}}
46+
// CHECK-NEXT: %3 = cir.const(#cir.int<2> : !s32i) : !s32i loc({{.*}})
47+
// CHECK-NEXT: cir.store %3, %2 : !s32i, cir.ptr <!s32i> loc({{.*}})
48+
// CHECK-NEXT: } loc({{.*}})
49+
// CHECK-NEXT: cir.scope {
50+
// CHECK-NEXT: %2 = cir.alloca !s32i, cir.ptr <!s32i>, ["x", init] {{.*}}
51+
// CHECK-NEXT: %3 = cir.const(#cir.int<5> : !s32i) : !s32i loc({{.*}})
52+
// CHECK-NEXT: cir.store %3, %2 : !s32i, cir.ptr <!s32i> loc({{.*}})
53+
// CHECK-NEXT: } loc({{.*}})
54+
// CHECK-NEXT: cir.scope {
55+
// CHECK-NEXT: %2 = cir.alloca !s32i, cir.ptr <!s32i>, ["x", init] {{.*}}
56+
// CHECK-NEXT: %3 = cir.alloca !s32i, cir.ptr <!s32i>, ["y", init] {{.*}}
57+
// CHECK-NEXT: %4 = cir.const(#cir.int<7> : !s32i) : !s32i loc({{.*}})
58+
// CHECK-NEXT: cir.store %4, %2 : !s32i, cir.ptr <!s32i> loc({{.*}})
59+
// CHECK-NEXT: %5 = cir.load %2 : cir.ptr <!s32i>, !s32i loc({{.*}})
60+
// CHECK-NEXT: cir.store %5, %3 : !s32i, cir.ptr <!s32i> loc({{.*}})
61+
// CHECK-NEXT: } loc({{.*}})
62+
// CHECK-NEXT: cir.scope {
63+
// CHECK-NEXT: %2 = cir.alloca !s32i, cir.ptr <!s32i>, ["x", init] {{.*}}
64+
// CHECK-NEXT: %3 = cir.alloca !s32i, cir.ptr <!s32i>, ["y", init] {{.*}}
65+
// CHECK-NEXT: %4 = cir.const(#cir.int<9> : !s32i) : !s32i loc({{.*}})
66+
// CHECK-NEXT: cir.store %4, %2 : !s32i, cir.ptr <!s32i> loc({{.*}})
67+
// CHECK-NEXT: %5 = cir.const(#cir.int<3> : !s32i) : !s32i loc({{.*}})
68+
// CHECK-NEXT: %6 = cir.load %2 : cir.ptr <!s32i>, !s32i loc({{.*}})
69+
// CHECK-NEXT: %7 = cir.binop(mul, %5, %6) : !s32i loc({{.*}})
70+
// CHECK-NEXT: cir.store %7, %3 : !s32i, cir.ptr <!s32i> loc({{.*}})
71+
// CHECK-NEXT: } loc({{.*}})
72+
// CHECK-NEXT: cir.scope {
73+
// CHECK-NEXT: %2 = cir.alloca !s32i, cir.ptr <!s32i>, ["x", init] {{.*}}
74+
// CHECK-NEXT: %3 = cir.const(#cir.int<20> : !s32i) : !s32i loc({{.*}})
75+
// CHECK-NEXT: cir.store %3, %2 : !s32i, cir.ptr <!s32i> loc({{.*}})
76+
// CHECK-NEXT: } loc({{.*}})
77+
// CHECK-NEXT: cir.scope {
78+
// Note that Clang does not even emit a block in this case
79+
// CHECK-NEXT: } loc({{.*}})
80+
// CHECK-NEXT: cir.scope {
81+
// CHECK-NEXT: %2 = cir.alloca !s32i, cir.ptr <!s32i>, ["x", init] {{.*}}
82+
// CHECK-NEXT: %3 = cir.alloca !s32i, cir.ptr <!s32i>, ["y", init] {{.*}}
83+
// CHECK-NEXT: %4 = cir.const(#cir.int<70> : !s32i) : !s32i loc({{.*}})
84+
// CHECK-NEXT: cir.store %4, %2 : !s32i, cir.ptr <!s32i> loc({{.*}})
85+
// CHECK-NEXT: %5 = cir.const(#cir.int<10> : !s32i) : !s32i loc({{.*}})
86+
// CHECK-NEXT: %6 = cir.load %2 : cir.ptr <!s32i>, !s32i loc({{.*}})
87+
// CHECK-NEXT: %7 = cir.binop(mul, %5, %6) : !s32i loc({{.*}})
88+
// CHECK-NEXT: cir.store %7, %3 : !s32i, cir.ptr <!s32i> loc({{.*}})
89+
// CHECK-NEXT: } loc({{.*}})
90+
// CHECK-NEXT: cir.scope {
91+
// CHECK-NEXT: %2 = cir.alloca !s32i, cir.ptr <!s32i>, ["x", init] {{.*}}
92+
// CHECK-NEXT: %3 = cir.const(#cir.int<90> : !s32i) : !s32i loc({{.*}})
93+
// CHECK-NEXT: cir.store %3, %2 : !s32i, cir.ptr <!s32i> loc({{.*}})
94+
// CHECK-NEXT: } loc({{.*}})
95+
// CHECK-NEXT: cir.return loc({{.*}})

0 commit comments

Comments
 (0)