Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -1047,6 +1047,12 @@ def CIR_SwitchOp : CIR_Op<"switch", [
conditionally executing multiple regions of code. The operand to an switch
is an integral condition value.

Besides taking an integer condition and CIR regions, it also accepts an
`all_enum_cases_covered` attribute indicating whether all enum cases are
handled by the operation. Note that the presence of a default CaseOp does
not imply `all_enum_cases_covered`. The original AST switch must explicitly list
every enum case.

The set of `cir.case` operations and their enclosing `cir.switch`
represent the semantics of a C/C++ switch statement. Users can use
`collectCases(llvm::SmallVector<CaseOp> &cases)` to collect the `cir.case`
Expand Down Expand Up @@ -1173,7 +1179,10 @@ def CIR_SwitchOp : CIR_Op<"switch", [
```
}];

let arguments = (ins CIR_IntType:$condition);
let arguments = (ins
CIR_IntType:$condition,
UnitAttr:$allEnumCasesCovered
);

let regions = (region AnyRegion:$body);

Expand All @@ -1184,9 +1193,9 @@ def CIR_SwitchOp : CIR_Op<"switch", [
];

let assemblyFormat = [{
custom<SwitchOp>(
$body, $condition, type($condition)
)
`(` $condition `:` qualified(type($condition)) `)`
(`allEnumCasesCovered` $allEnumCasesCovered^)?
$body
attr-dict
}];

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,8 @@ mlir::LogicalResult CIRGenFunction::emitSwitchStmt(const clang::SwitchStmt &s) {
terminateBody(builder, caseOp.getCaseRegion(), caseOp.getLoc());
terminateBody(builder, swop.getBody(), swop.getLoc());

swop.setAllEnumCasesCovered(s.isAllEnumCasesCovered());

return res;
}

Expand Down
38 changes: 0 additions & 38 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1353,44 +1353,6 @@ void cir::CaseOp::build(OpBuilder &builder, OperationState &result,
// SwitchOp
//===----------------------------------------------------------------------===//

static ParseResult parseSwitchOp(OpAsmParser &parser, mlir::Region &regions,
mlir::OpAsmParser::UnresolvedOperand &cond,
mlir::Type &condType) {
cir::IntType intCondType;

if (parser.parseLParen())
return mlir::failure();

if (parser.parseOperand(cond))
return mlir::failure();
if (parser.parseColon())
return mlir::failure();
if (parser.parseCustomTypeWithFallback(intCondType))
return mlir::failure();
condType = intCondType;

if (parser.parseRParen())
return mlir::failure();
if (parser.parseRegion(regions, /*arguments=*/{}, /*argTypes=*/{}))
return failure();

return mlir::success();
}

static void printSwitchOp(OpAsmPrinter &p, cir::SwitchOp op,
mlir::Region &bodyRegion, mlir::Value condition,
mlir::Type condType) {
p << "(";
p << condition;
p << " : ";
p.printStrippedAttrOrType(condType);
p << ")";

p << ' ';
p.printRegion(bodyRegion, /*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/true);
}

void cir::SwitchOp::getSuccessorRegions(
mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &region) {
if (!point.isParent()) {
Expand Down
6 changes: 3 additions & 3 deletions clang/test/CIR/CodeGen/atomic.c
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,7 @@ int atomic_load_dynamic_order(int *ptr, int order) {

// CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.switch (%[[ORDER]] : !s32i) {
// CIR-NEXT: cir.switch(%[[ORDER]] : !s32i) {
// CIR-NEXT: cir.case(default, []) {
// CIR-NEXT: %[[RES:.+]] = cir.load align(4) atomic(relaxed) %[[PTR]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.store align(4) %[[RES]], %[[RES_SLOT:.+]] : !s32i, !cir.ptr<!s32i>
Expand Down Expand Up @@ -1219,7 +1219,7 @@ void atomic_store_dynamic_order(int *ptr, int order) {

// CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR: cir.switch (%[[ORDER]] : !s32i) {
// CIR: cir.switch(%[[ORDER]] : !s32i) {
// CIR-NEXT: cir.case(default, []) {
// CIR-NEXT: %[[VALUE:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.store align(4) atomic(relaxed) %[[VALUE]], %[[PTR]] : !s32i, !cir.ptr<!s32i>
Expand Down Expand Up @@ -1288,7 +1288,7 @@ int atomic_load_and_store_dynamic_order(int *ptr, int order) {

// CIR: %[[PTR:.+]] = cir.load align(8) %{{.+}} : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: %[[ORDER:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR: cir.switch (%[[ORDER]] : !s32i) {
// CIR: cir.switch(%[[ORDER]] : !s32i) {
// CIR-NEXT: cir.case(default, []) {
// CIR-NEXT: %[[LIT:.+]] = cir.load align(4) %{{.+}} : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[RES:.+]] = cir.atomic.xchg relaxed %[[PTR]], %[[LIT]] : (!cir.ptr<!s32i>, !s32i) -> !s32i
Expand Down
48 changes: 35 additions & 13 deletions clang/test/CIR/CodeGen/switch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void sw1(int a) {
}

// CIR: cir.func{{.*}} @_Z3sw1i
// CIR: cir.switch (%[[COND:.*]] : !s32i) {
// CIR: cir.switch(%[[COND:.*]] : !s32i) {
// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
// CIR: cir.break
// CIR: cir.case(equal, [#cir.int<1> : !s32i]) {
Expand Down Expand Up @@ -101,7 +101,7 @@ void sw2(int a) {
// CIR: cir.scope {
// CIR-NEXT: %[[YOLO:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["yolo", init]
// CIR-NEXT: %[[FOMO:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["fomo", init]
// CIR: cir.switch (%[[COND:.*]] : !s32i) {
// CIR: cir.switch(%[[COND:.*]] : !s32i) {
// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR-NEXT: cir.store{{.*}} %[[ZERO]], %[[FOMO]] : !s32i, !cir.ptr<!s32i>
Expand Down Expand Up @@ -154,7 +154,7 @@ void sw3(int a) {
// CIR: cir.func{{.*}} @_Z3sw3i
// CIR: cir.scope {
// CIR-NEXT: %[[COND:.*]] = cir.load{{.*}} %[[A:.*]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.switch (%[[COND]] : !s32i) {
// CIR-NEXT: cir.switch(%[[COND]] : !s32i) {
// CIR-NEXT: cir.case(default, []) {
// CIR-NEXT: cir.break
// CIR-NEXT: }
Expand Down Expand Up @@ -196,7 +196,7 @@ int sw4(int a) {
}

// CIR: cir.func{{.*}} @_Z3sw4i
// CIR: cir.switch (%[[COND:.*]] : !s32i) {
// CIR: cir.switch(%[[COND:.*]] : !s32i) {
// CIR-NEXT: cir.case(equal, [#cir.int<42> : !s32i]) {
// CIR-NEXT: cir.scope {
// CIR-NEXT: %[[THREE:.*]] = cir.const #cir.int<3> : !s32i
Expand Down Expand Up @@ -264,7 +264,7 @@ void sw5(int a) {
}

// CIR: cir.func{{.*}} @_Z3sw5i
// CIR: cir.switch (%[[A:.*]] : !s32i) {
// CIR: cir.switch(%[[A:.*]] : !s32i) {
// CIR-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) {
// CIR-NEXT: cir.yield
// CIR-NEXT: }
Expand Down Expand Up @@ -314,7 +314,7 @@ void sw6(int a) {
}

// CIR: cir.func{{.*}} @_Z3sw6i
// CIR: cir.switch (%[[A:.*]] : !s32i) {
// CIR: cir.switch(%[[A:.*]] : !s32i) {
// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
// CIR-NEXT: cir.yield
// CIR-NEXT: }
Expand Down Expand Up @@ -406,7 +406,7 @@ void sw7(int a) {

// CIR: cir.func{{.*}} @_Z3sw7i
// CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"]
// CIR: cir.switch (%[[A:.*]] : !s32i)
// CIR: cir.switch(%[[A:.*]] : !s32i)
// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
// CIR-NEXT: cir.yield
// CIR-NEXT: }
Expand Down Expand Up @@ -499,7 +499,7 @@ void sw8(int a) {
}

// CIR: cir.func{{.*}} @_Z3sw8i
// CIR: cir.switch (%[[A:.*]] : !s32i)
// CIR: cir.switch(%[[A:.*]] : !s32i)
// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
// CIR-NEXT: cir.break
// CIR-NEXT: }
Expand Down Expand Up @@ -557,7 +557,7 @@ void sw9(int a) {
}

// CIR: cir.func{{.*}} @_Z3sw9i
// CIR: cir.switch (%[[A:.*]] : !s32i)
// CIR: cir.switch(%[[A:.*]] : !s32i)
// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
// CIR-NEXT: cir.break
// CIR-NEXT: }
Expand Down Expand Up @@ -616,7 +616,7 @@ void sw10(int a) {
}

// CIR: cir.func{{.*}} @_Z4sw10i
// CIR: cir.switch (%[[A:.*]] : !s32i)
// CIR: cir.switch(%[[A:.*]] : !s32i)
// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
// CIR-NEXT: cir.break
// CIR-NEXT: }
Expand Down Expand Up @@ -688,7 +688,7 @@ void sw11(int a) {
}

// CIR: cir.func{{.*}} @_Z4sw11i
// CIR: cir.switch (%[[A:.*]] : !s32i)
// CIR: cir.switch(%[[A:.*]] : !s32i)
// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
// CIR-NEXT: cir.break
// CIR-NEXT: }
Expand Down Expand Up @@ -1063,7 +1063,7 @@ int nested_switch(int a) {
return 0;
}

// CIR: cir.switch (%[[COND:.*]] : !s32i) {
// CIR: cir.switch(%[[COND:.*]] : !s32i) {
// CIR: cir.case(equal, [#cir.int<0> : !s32i]) {
// CIR: cir.yield
// CIR: }
Expand Down Expand Up @@ -1198,7 +1198,7 @@ int sw_return_multi_cases(int x) {
}

// CIR-LABEL: cir.func{{.*}} @_Z21sw_return_multi_casesi
// CIR: cir.switch (%{{.*}} : !s32i) {
// CIR: cir.switch(%{{.*}} : !s32i) {
// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
// CIR: cir.store{{.*}} %[[ZERO]], %{{.*}} : !s32i, !cir.ptr<!s32i>
Expand Down Expand Up @@ -1270,3 +1270,25 @@ int sw_return_multi_cases(int x) {
// OGCG: [[RETURN]]:
// OGCG: %[[RETVAL_LOAD:.*]] = load i32, ptr %[[RETVAL]], align 4
// OGCG: ret i32 %[[RETVAL_LOAD]]

enum M {
Six,
Seven
};

void testSwitchCoverAllCase(M m) {
switch (m) {
case Six:case Seven:
break;
}
}
// CIR: cir.switch(%[[ARG:.*]] : !s32i) allEnumCasesCovered {

void testSwitchNotCoverAllCase(M m) {
switch (m) {
case Six:
default:
break;
}
}
// CIR: cir.switch(%[[ARG:.*]] : !s32i) {
2 changes: 1 addition & 1 deletion clang/test/CIR/CodeGen/switch_flat_op.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ void swf(int a) {
// BEFORE: cir.func{{.*}} @_Z3swfi
// BEFORE: %[[VAR_B:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["b", init] {alignment = 4 : i64}
// BEFORE: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i
// BEFORE: cir.switch (%[[COND:.*]] : !s32i) {
// BEFORE: cir.switch(%[[COND:.*]] : !s32i) {
// BEFORE: cir.case(equal, [#cir.int<3> : !s32i]) {
// BEFORE: %[[LOAD_B_EQ:.*]] = cir.load{{.*}} %[[VAR_B]] : !cir.ptr<!s32i>, !s32i
// BEFORE: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i
Expand Down
32 changes: 31 additions & 1 deletion clang/test/CIR/IR/switch.cir
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ cir.func @s0() {
cir.return
}

// CHECK: cir.switch (%0 : !s32i) {
// CHECK: cir.switch(%0 : !s32i) {
// CHECK-NEXT: cir.case(default, []) {
// CHECK-NEXT: cir.return
// CHECK-NEXT: }
Expand All @@ -36,3 +36,33 @@ cir.func @s0() {
// CHECK-NEXT: }
// CHECK-NEXT: cir.yield
// CHECK-NEXT: }


// Pretends that this is lowered from a C file and was tagged with allEnumCasesCovered = true
cir.func @s1(%1 : !s32i) {
cir.switch (%1 : !s32i) allEnumCasesCovered {
cir.case (default, []) {
cir.return
}
cir.case (equal, [#cir.int<1> : !s32i]) {
cir.yield
}
cir.case (equal, [#cir.int<2> : !s32i]) {
cir.yield
}
cir.yield
} { }
cir.return
}
// CHECK: cir.switch(%[[ARG:.*]] : !s32i) allEnumCasesCovered {
// CHECK-NEXT: cir.case(default, []) {
// CHECK-NEXT: cir.return
// CHECK-NEXT: }
// CHECK-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) {
// CHECK-NEXT: cir.yield
// CHECK-NEXT: }
// CHECK-NEXT: cir.case(equal, [#cir.int<2> : !s32i]) {
// CHECK-NEXT: cir.yield
// CHECK-NEXT: }
// CHECK-NEXT: cir.yield
// CHECK-NEXT: }
10 changes: 5 additions & 5 deletions clang/test/CIR/Transforms/switch-fold.cir
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module {
cir.return
}
//CHECK: cir.func @foldCascade
//CHECK: cir.switch (%[[COND:.*]] : !s32i) {
//CHECK: cir.switch(%[[COND:.*]] : !s32i) {
//CHECK-NEXT: cir.case(anyof, [#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i]) {
//CHECK-NEXT: %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
//CHECK-NEXT: cir.store %[[TWO]], %[[ARG0:.*]] : !s32i, !cir.ptr<!s32i>
Expand Down Expand Up @@ -66,7 +66,7 @@ module {
cir.return
}
//CHECK: @foldCascade2
//CHECK: cir.switch (%[[COND2:.*]] : !s32i) {
//CHECK: cir.switch(%[[COND2:.*]] : !s32i) {
//CHECK: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<2> : !s32i, #cir.int<4> : !s32i]) {
//CHECK: cir.break
//cehck: }
Expand Down Expand Up @@ -106,7 +106,7 @@ module {
cir.return
}
//CHECK: cir.func @foldCascade3
//CHECK: cir.switch (%[[COND3:.*]] : !s32i) {
//CHECK: cir.switch(%[[COND3:.*]] : !s32i) {
//CHECK: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i]) {
//CHECK: cir.break
//CHECK: }
Expand Down Expand Up @@ -142,7 +142,7 @@ module {
cir.return
}
//CHECK: cir.func @foldCascadeWithDefault
//CHECK: cir.switch (%[[COND:.*]] : !s32i) {
//CHECK: cir.switch(%[[COND:.*]] : !s32i) {
//CHECK: cir.case(equal, [#cir.int<3> : !s32i]) {
//CHECK: cir.break
//CHECK: }
Expand Down Expand Up @@ -187,7 +187,7 @@ module {
cir.return
}
//CHECK: cir.func @foldAllCascade
//CHECK: cir.switch (%[[COND:.*]] : !s32i) {
//CHECK: cir.switch(%[[COND:.*]] : !s32i) {
//CHECK: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i]) {
//CHECK: cir.yield
//CHECK: }
Expand Down