Skip to content

Conversation

@badumbatish
Copy link
Contributor

No description provided.

@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Dec 9, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 9, 2025

@llvm/pr-subscribers-clangir

Author: Jasmine Tang (badumbatish)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/171246.diff

3 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+7-1)
  • (modified) clang/lib/CIR/CodeGen/CIRGenStmt.cpp (+2)
  • (modified) clang/test/CIR/IR/switch.cir (+30)
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}

@llvmbot
Copy link
Member

llvmbot commented Dec 9, 2025

@llvm/pr-subscribers-clang

Author: Jasmine Tang (badumbatish)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/171246.diff

3 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+7-1)
  • (modified) clang/lib/CIR/CodeGen/CIRGenStmt.cpp (+2)
  • (modified) clang/test/CIR/IR/switch.cir (+30)
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}

Copy link
Contributor

@andykaylor andykaylor left a 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants