-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[CIR] Add the ability to detect if SwitchOp covers all the cases #171246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-clangir Author: Jasmine Tang (badumbatish) ChangesFull diff: https://github.com/llvm/llvm-project/pull/171246.diff 3 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 9bd24cf0bcf27..d6099388886d7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1047,6 +1047,11 @@ def CIR_SwitchOp : CIR_Op<"switch", [
conditionally executing multiple regions of code. The operand to an switch
is an integral condition value.
+ Besides accepting an int type of condition and regions of cir code, it also accepts
+ a boolean allEnumCasesCovered indicating if all cases of an enum is covered. Note that
+ having a default CaseOp inside the switch doesn't imply allEnumCasesCovered, the OG AST switch
+ needs to have each case spelled out.
+
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`
@@ -1173,7 +1178,8 @@ def CIR_SwitchOp : CIR_Op<"switch", [
```
}];
- let arguments = (ins CIR_IntType:$condition);
+ let arguments = (ins CIR_IntType:$condition,
+ DefaultValuedAttr<BoolAttr, "false">:$allEnumCasesCovered);
let regions = (region AnyRegion:$body);
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index da7ab0691cb63..0ff19abaffc08 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -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;
}
diff --git a/clang/test/CIR/IR/switch.cir b/clang/test/CIR/IR/switch.cir
index 87d45bf1f5219..78c0273b8c97e 100644
--- a/clang/test/CIR/IR/switch.cir
+++ b/clang/test/CIR/IR/switch.cir
@@ -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) {
+ 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
+ } { allEnumCasesCovered = true}
+ cir.return
+}
+// CHECK: cir.switch (%arg0 : !s32i) {
+// 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: } {allEnumCasesCovered = true}
|
|
@llvm/pr-subscribers-clang Author: Jasmine Tang (badumbatish) ChangesFull diff: https://github.com/llvm/llvm-project/pull/171246.diff 3 Files Affected:
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 9bd24cf0bcf27..d6099388886d7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1047,6 +1047,11 @@ def CIR_SwitchOp : CIR_Op<"switch", [
conditionally executing multiple regions of code. The operand to an switch
is an integral condition value.
+ Besides accepting an int type of condition and regions of cir code, it also accepts
+ a boolean allEnumCasesCovered indicating if all cases of an enum is covered. Note that
+ having a default CaseOp inside the switch doesn't imply allEnumCasesCovered, the OG AST switch
+ needs to have each case spelled out.
+
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`
@@ -1173,7 +1178,8 @@ def CIR_SwitchOp : CIR_Op<"switch", [
```
}];
- let arguments = (ins CIR_IntType:$condition);
+ let arguments = (ins CIR_IntType:$condition,
+ DefaultValuedAttr<BoolAttr, "false">:$allEnumCasesCovered);
let regions = (region AnyRegion:$body);
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index da7ab0691cb63..0ff19abaffc08 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -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;
}
diff --git a/clang/test/CIR/IR/switch.cir b/clang/test/CIR/IR/switch.cir
index 87d45bf1f5219..78c0273b8c97e 100644
--- a/clang/test/CIR/IR/switch.cir
+++ b/clang/test/CIR/IR/switch.cir
@@ -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) {
+ 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
+ } { allEnumCasesCovered = true}
+ cir.return
+}
+// CHECK: cir.switch (%arg0 : !s32i) {
+// 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: } {allEnumCasesCovered = true}
|
andykaylor
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good. It could also be useful to know that the switch condition variable is an enum, for cases where it's not fully covered, but that could be a separate PR.
No description provided.