[clang] f74d893 - [CIR] Upstream support for switch statements case kinds (#138003)

via cfe-commits cfe-commits at lists.llvm.org
Wed May 7 12:28:38 PDT 2025


Author: Andres-Salamanca
Date: 2025-05-07T12:28:35-07:00
New Revision: f74d893987dd72c6a7dc6b4f219877204a7681f4

URL: https://github.com/llvm/llvm-project/commit/f74d893987dd72c6a7dc6b4f219877204a7681f4
DIFF: https://github.com/llvm/llvm-project/commit/f74d893987dd72c6a7dc6b4f219877204a7681f4.diff

LOG: [CIR] Upstream support for switch statements case kinds (#138003)

This introduces support for the following cir::case kinds:
- `Equal`
- `AnyOf`
- `Range`

Added: 
    

Modified: 
    clang/include/clang/CIR/MissingFeatures.h
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/lib/CIR/CodeGen/CIRGenStmt.cpp
    clang/test/CIR/CodeGen/switch.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 06636cd6c554c..fb4d8b1c2de2b 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -111,6 +111,10 @@ struct MissingFeatures {
   // Unary operator handling
   static bool opUnaryPromotionType() { return false; }
 
+  // SwitchOp handling
+  static bool foldCascadingCases() { return false; }
+  static bool foldRangeCase() { return false; }
+
   // Clang early optimizations or things defered to LLVM lowering.
   static bool mayHaveIntegerOverflow() { return false; }
   static bool shouldReverseUnaryCondOnBoolExpr() { return false; }
@@ -176,7 +180,6 @@ struct MissingFeatures {
   static bool targetSpecificCXXABI() { return false; }
   static bool moduleNameHash() { return false; }
   static bool setDSOLocal() { return false; }
-  static bool foldCaseStmt() { return false; }
   static bool constantFoldSwitchStatement() { return false; }
   static bool cudaSupport() { return false; }
   static bool maybeHandleStaticInExternC() { return false; }

diff  --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index c3aada89c09c4..9066107af595e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -581,6 +581,10 @@ class CIRGenFunction : public CIRGenTypeCache {
   mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s);
   LValue emitDeclRefLValue(const clang::DeclRefExpr *e);
 
+  mlir::LogicalResult emitDefaultStmt(const clang::DefaultStmt &s,
+                                      mlir::Type condType,
+                                      bool buildingTopLevelCase);
+
   /// Emit an `if` on a boolean condition to the specified blocks.
   /// FIXME: Based on the condition, this might try to simplify the codegen of
   /// the conditional based on the branch.

diff  --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index ee4dcc861a1f2..cc96e65e4ce1d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -254,6 +254,7 @@ mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const Stmt *s,
   case Stmt::NullStmtClass:
     break;
   case Stmt::CaseStmtClass:
+  case Stmt::DefaultStmtClass:
     // If we reached here, we must not handling a switch case in the top level.
     return emitSwitchCase(cast<SwitchCase>(*s),
                           /*buildingTopLevelCase=*/false);
@@ -458,7 +459,7 @@ CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType,
     if (isa<DefaultStmt>(sub) && isa<CaseStmt>(stmt)) {
       subStmtKind = SubStmtKind::Default;
       builder.createYield(loc);
-    } else if (isa<CaseStmt>(sub) && isa<DefaultStmt>(stmt)) {
+    } else if (isa<CaseStmt>(sub) && isa<DefaultStmt, CaseStmt>(stmt)) {
       subStmtKind = SubStmtKind::Case;
       builder.createYield(loc);
     } else {
@@ -503,8 +504,8 @@ CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType,
   if (subStmtKind == SubStmtKind::Case) {
     result = emitCaseStmt(*cast<CaseStmt>(sub), condType, buildingTopLevelCase);
   } else if (subStmtKind == SubStmtKind::Default) {
-    getCIRGenModule().errorNYI(sub->getSourceRange(), "Default case");
-    return mlir::failure();
+    result = emitDefaultStmt(*cast<DefaultStmt>(sub), condType,
+                             buildingTopLevelCase);
   } else if (buildingTopLevelCase) {
     // If we're building a top level case, try to restore the insert point to
     // the case we're building, then we can attach more random stmts to the
@@ -518,19 +519,40 @@ CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType,
 mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
                                                  mlir::Type condType,
                                                  bool buildingTopLevelCase) {
+  cir::CaseOpKind kind;
+  mlir::ArrayAttr value;
   llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());
-  SmallVector<mlir::Attribute, 1> caseEltValueListAttr;
-  caseEltValueListAttr.push_back(cir::IntAttr::get(condType, intVal));
-  mlir::ArrayAttr value = builder.getArrayAttr(caseEltValueListAttr);
-  if (s.getRHS()) {
-    getCIRGenModule().errorNYI(s.getSourceRange(), "SwitchOp range kind");
-    return mlir::failure();
+
+  // If the case statement has an RHS value, it is representing a GNU
+  // case range statement, where LHS is the beginning of the range
+  // and RHS is the end of the range.
+  if (const Expr *rhs = s.getRHS()) {
+    llvm::APSInt endVal = rhs->EvaluateKnownConstInt(getContext());
+    value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal),
+                                  cir::IntAttr::get(condType, endVal)});
+    kind = cir::CaseOpKind::Range;
+
+    // We don't currently fold case range statements with other case statements.
+    // TODO(cir): Add this capability. Folding these cases is going to be
+    // implemented in CIRSimplify when it is upstreamed.
+    assert(!cir::MissingFeatures::foldRangeCase());
+    assert(!cir::MissingFeatures::foldCascadingCases());
+  } else {
+    value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});
+    kind = cir::CaseOpKind::Equal;
   }
-  assert(!cir::MissingFeatures::foldCaseStmt());
-  return emitCaseDefaultCascade(&s, condType, value, cir::CaseOpKind::Equal,
+
+  return emitCaseDefaultCascade(&s, condType, value, kind,
                                 buildingTopLevelCase);
 }
 
+mlir::LogicalResult CIRGenFunction::emitDefaultStmt(const clang::DefaultStmt &s,
+                                                    mlir::Type condType,
+                                                    bool buildingTopLevelCase) {
+  return emitCaseDefaultCascade(&s, condType, builder.getArrayAttr({}),
+                                cir::CaseOpKind::Default, buildingTopLevelCase);
+}
+
 mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,
                                                    bool buildingTopLevelCase) {
   assert(!condTypeStack.empty() &&
@@ -540,10 +562,9 @@ mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,
     return emitCaseStmt(cast<CaseStmt>(s), condTypeStack.back(),
                         buildingTopLevelCase);
 
-  if (s.getStmtClass() == Stmt::DefaultStmtClass) {
-    getCIRGenModule().errorNYI(s.getSourceRange(), "Default case");
-    return mlir::failure();
-  }
+  if (s.getStmtClass() == Stmt::DefaultStmtClass)
+    return emitDefaultStmt(cast<DefaultStmt>(s), condTypeStack.back(),
+                           buildingTopLevelCase);
 
   llvm_unreachable("expect case or default stmt");
 }

diff  --git a/clang/test/CIR/CodeGen/switch.cpp b/clang/test/CIR/CodeGen/switch.cpp
index 36523755376a1..0bd4e0759e634 100644
--- a/clang/test/CIR/CodeGen/switch.cpp
+++ b/clang/test/CIR/CodeGen/switch.cpp
@@ -16,8 +16,9 @@ void sw1(int a) {
   }
   }
 }
+
 // CIR: cir.func @_Z3sw1i
-// CIR: cir.switch (%3 : !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]) {
@@ -66,12 +67,12 @@ void sw2(int a) {
 
 // CIR: cir.func @_Z3sw2i
 // CIR: cir.scope {
-// CIR-NEXT:   %1 = cir.alloca !s32i, !cir.ptr<!s32i>, ["yolo", init]
-// CIR-NEXT:   %2 = cir.alloca !s32i, !cir.ptr<!s32i>, ["fomo", init]
-// CIR:        cir.switch (%4 : !s32i) {
+// 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-NEXT:   cir.case(equal, [#cir.int<3> : !s32i]) {
-// CIR-NEXT:     %5 = cir.const #cir.int<0> : !s32i
-// CIR-NEXT:     cir.store %5, %2 : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:     %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR-NEXT:     cir.store %[[ZERO]], %[[FOMO]] : !s32i, !cir.ptr<!s32i>
 
 // OGCG: define dso_local void @_Z3sw2i
 // OGCG: entry:
@@ -91,45 +92,80 @@ void sw2(int a) {
 // OGCG: [[SW_EPILOG]]:
 // OGCG:   ret void
 
+void sw3(int a) {
+  switch (a) {
+  default:
+    break;
+  }
+}
+
+// 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.case(default, []) {
+// CIR-NEXT:     cir.break
+// CIR-NEXT:   }
+// CIR-NEXT:   cir.yield
+// CIR-NEXT:   }
+
+// OGCG: define dso_local void @_Z3sw3i
+// OGCG: entry:
+// OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   switch i32 %[[A_VAL]], label %[[DEFAULT:.*]] [
+// OGCG: [[DEFAULT]]:
+// OGCG:   br label %[[EPILOG:.*]]
+// OGCG: [[EPILOG]]:
+// OGCG:   ret void
+
 int sw4(int a) {
   switch (a) {
   case 42: {
     return 3;
   }
-  // TODO: add default case when it is upstreamed
+  default:
+    return 2;
   }
   return 0;
 }
 
 // CIR: cir.func @_Z3sw4i
-// CIR:       cir.switch (%4 : !s32i) {
+// CIR:       cir.switch (%[[COND:.*]] : !s32i) {
 // CIR-NEXT:       cir.case(equal, [#cir.int<42> : !s32i]) {
 // CIR-NEXT:         cir.scope {
-// CIR-NEXT:           %5 = cir.const #cir.int<3> : !s32i
-// CIR-NEXT:           cir.store %5, %1 : !s32i, !cir.ptr<!s32i>
-// CIR-NEXT:           %6 = cir.load %1 : !cir.ptr<!s32i>, !s32i
-// CIR-NEXT:           cir.return %6 : !s32i
+// CIR-NEXT:           %[[THREE:.*]] = cir.const #cir.int<3> : !s32i
+// CIR-NEXT:           cir.store %[[THREE]], %[[RETVAL:.*]] : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:           %[[RET3:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i
+// CIR-NEXT:           cir.return %[[RET3]] : !s32i
 // CIR-NEXT:         }
 // CIR-NEXT:         cir.yield
 // CIR-NEXT:       }
+// CIR-NEXT:       cir.case(default, []) {
+// CIR-NEXT:         %[[TWO:.*]] = cir.const #cir.int<2> : !s32i
+// CIR-NEXT:         cir.store %[[TWO]], %[[RETVAL]] : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:         %[[RET2:.*]] = cir.load %[[RETVAL]] : !cir.ptr<!s32i>, !s32i
+// CIR-NEXT:         cir.return %[[RET2]] : !s32i
+// CIR-NEXT:       }
+// CIR-NEXT:       cir.yield
+// CIR-NEXT:  }
 
 // OGCG: define dso_local noundef i32 @_Z3sw4i
 // OGCG: entry:
 // OGCG:   %[[RETVAL:.*]] = alloca i32, align 4
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
 // OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
-// OGCG:   switch i32 %[[A_VAL]], label %[[EPILOG:.*]] [
+// OGCG:   switch i32 %[[A_VAL]], label %[[DEFAULT:.*]] [
 // OGCG:     i32 42, label %[[SW42:.*]]
 // OGCG:   ]
 // OGCG: [[SW42]]:
 // OGCG:   br label %[[RETURN:.*]]
-// OGCG: [[EPILOG]]:
+// OGCG: [[DEFAULT]]:
 // OGCG:   br label %[[RETURN]]
 // OGCG: [[RETURN]]:
 // OGCG:   %[[RETVAL_LOAD:.*]] = load i32, ptr %[[RETVAL]], align 4
 // OGCG:   ret i32 %[[RETVAL_LOAD]]
 
-
 void sw5(int a) {
   switch (a) {
   case 1:;
@@ -137,7 +173,7 @@ void sw5(int a) {
 }
 
 // CIR: cir.func @_Z3sw5i
-// CIR: cir.switch (%1 : !s32i) {
+// CIR: cir.switch (%[[A:.*]] : !s32i) {
 // CIR-NEXT:   cir.case(equal, [#cir.int<1> : !s32i]) {
 // CIR-NEXT:     cir.yield
 // CIR-NEXT:   }
@@ -156,22 +192,138 @@ void sw5(int a) {
 // OGCG: [[SW_EPILOG]]:
 // OGCG:   ret void
 
+void sw6(int a) {
+  switch (a) {
+  case 0:
+  case 1:
+  case 2:
+    break;
+  case 3:
+  case 4:
+  case 5:
+    break;
+  }
+}
+
+// CIR: cir.func @_Z3sw6i
+// CIR: cir.switch (%[[A:.*]] : !s32i) {
+// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<2> : !s32i]) {
+// CIR-NEXT:     cir.break
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<4> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<5> : !s32i]) {
+// CIR-NEXT:     cir.break
+// CIR-NEXT: }
+
+
+// OGCG: define dso_local void @_Z3sw6i
+// OGCG: entry:
+// OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG:   store i32 %a, ptr %[[A_ADDR]], align 4
+// OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   switch i32 %[[A_VAL]], label %[[EPILOG:.*]] [
+// OGCG:     i32 0, label %[[BB0:.*]]
+// OGCG:     i32 1, label %[[BB0]]
+// OGCG:     i32 2, label %[[BB0]]
+// OGCG:     i32 3, label %[[BB1:.*]]
+// OGCG:     i32 4, label %[[BB1]]
+// OGCG:     i32 5, label %[[BB1]]
+// OGCG:   ]
+// OGCG: [[BB0]]:
+// OGCG:   br label %[[EPILOG]]
+// OGCG: [[BB1]]:
+// OGCG:   br label %[[EPILOG]]
+// OGCG: [[EPILOG]]:
+// OGCG:   ret void
+
+void sw7(int a) {
+  switch (a) {
+  case 0:
+  case 1:
+  case 2:
+    int x;
+  case 3:
+  case 4:
+  case 5:
+    break;
+  }
+}
+
+// CIR: cir.func @_Z3sw7i
+// CIR: %[[X:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x"]
+// CIR: cir.switch (%[[A:.*]] : !s32i)
+// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<2> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<4> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<5> : !s32i]) {
+// CIR-NEXT:     cir.break
+// CIR-NEXT: }
+// CIR-NEXT: cir.yield
+// CIR: }
+
+// OGCG: define dso_local void @_Z3sw7i
+// OGCG: entry:
+// OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   switch i32 %[[A_VAL]], label %[[EPILOG:.*]] [
+// OGCG:     i32 0, label %[[BB0:.*]]
+// OGCG:     i32 1, label %[[BB0]]
+// OGCG:     i32 2, label %[[BB0]]
+// OGCG:     i32 3, label %[[BB1:.*]]
+// OGCG:     i32 4, label %[[BB1]]
+// OGCG:     i32 5, label %[[BB1]]
+// OGCG:   ]
+// OGCG: [[BB0]]:
+// OGCG:   br label %[[BB1]]
+// OGCG: [[BB1]]:
+// OGCG:   br label %[[EPILOG]]
+// OGCG: [[EPILOG]]:
+// OGCG:   ret void
+
+
 void sw8(int a) {
   switch (a)
   {
   case 3:
     break;
   case 4:
-  // TODO: add default case when it is upstreamed
+  default:
     break;
   }
 }
 
 // CIR:    cir.func @_Z3sw8i
-// CIR:      cir.case(equal, [#cir.int<3> : !s32i]) {
+// CIR:    cir.switch (%[[A:.*]] : !s32i)
+// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
 // CIR-NEXT: cir.case(equal, [#cir.int<4> : !s32i]) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(default, []) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
 
@@ -180,33 +332,38 @@ void sw8(int a) {
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
 // OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
-// OGCG:   switch i32 %[[A_VAL]], label %[[EPILOG:.*]] [
+// OGCG:   switch i32 %[[A_VAL]], label %[[DEFAULT:.*]] [
 // OGCG:     i32 3, label %[[SW3:.*]]
 // OGCG:     i32 4, label %[[SW4:.*]]
 // OGCG:   ]
 // OGCG: [[SW3]]:
-// OGCG:   br label %[[EPILOG]]
+// OGCG:   br label %[[EPILOG:.*]]
 // OGCG: [[SW4]]:
+// OGCG:   br label %[[DEFAULT]]
+// OGCG: [[DEFAULT]]:
 // OGCG:   br label %[[EPILOG]]
 // OGCG: [[EPILOG]]:
 // OGCG:   ret void
 
-
 void sw9(int a) {
   switch (a)
   {
   case 3:
     break;
-  // TODO: add default case when it is upstreamed
+  default:
   case 4:
     break;
   }
 }
 
 // CIR:    cir.func @_Z3sw9i
-// CIR:      cir.case(equal, [#cir.int<3> : !s32i]) {
+// CIR:    cir.switch (%[[A:.*]] : !s32i)
+// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
+// CIR-NEXT: cir.case(default, []) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
 // CIR-NEXT: cir.case(equal, [#cir.int<4> : !s32i]) {
 // CIR-NEXT:   cir.break
 // CIR-NEXT: }
@@ -215,17 +372,123 @@ void sw9(int a) {
 // OGCG: entry:
 // OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
 // OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
-// OGCG:   switch i32 %[[A_VAL]], label %[[EPILOG:.*]] [
+// OGCG:   switch i32 %[[A_VAL]], label %[[DEFAULT:.*]] [
 // OGCG:     i32 3, label %[[SW3:.*]]
 // OGCG:     i32 4, label %[[SW4:.*]]
 // OGCG:   ]
 // OGCG: [[SW3]]:
-// OGCG:   br label %[[EPILOG]]
+// OGCG:   br label %[[EPILOG:.*]]
+// OGCG: [[DEFAULT]]:
+// OGCG:   br label %[[SW4]]
 // OGCG: [[SW4]]:
 // OGCG:   br label %[[EPILOG]]
 // OGCG: [[EPILOG]]:
 // OGCG:   ret void
 
+void sw10(int a) {
+  switch (a)
+  {
+  case 3:
+    break;
+  case 4:
+  default:
+  case 5:
+    break;
+  }
+}
+
+// CIR:    cir.func @_Z4sw10i
+// CIR:    cir.switch (%[[A:.*]] : !s32i)
+// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
+// CIR-NEXT:   cir.break
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<4> : !s32i]) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(default, []) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<5> : !s32i]) {
+// CIR-NEXT:   cir.break
+// CIR-NEXT: }
+
+// OGCG: define dso_local void @_Z4sw10i
+// OGCG: entry:
+// OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   switch i32 %[[A_VAL]], label %[[DEFAULT:.*]] [
+// OGCG:     i32 3, label %[[BB3:.*]]
+// OGCG:     i32 4, label %[[BB4:.*]]
+// OGCG:     i32 5, label %[[BB5:.*]]
+// OGCG:   ]
+// OGCG: [[BB3]]:
+// OGCG:   br label %[[EPILOG:.*]]
+// OGCG: [[BB4]]:
+// OGCG:   br label %[[DEFAULT]]
+// OGCG: [[DEFAULT]]:
+// OGCG:   br label %[[BB5]]
+// OGCG: [[BB5]]:
+// OGCG:   br label %[[EPILOG]]
+// OGCG: [[EPILOG]]:
+// OGCG:   ret void
+
+void sw11(int a) {
+  switch (a)
+  {
+  case 3:
+    break;
+  case 4:
+  case 5:
+  default:
+  case 6:
+  case 7:
+    break;
+  }
+}
+
+// CIR:    cir.func @_Z4sw11i
+// CIR:    cir.switch (%[[A:.*]] : !s32i)
+// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
+// CIR-NEXT:   cir.break
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<4> : !s32i]) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<5> : !s32i]) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(default, []) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<6> : !s32i]) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<7> : !s32i]) {
+// CIR-NEXT:   cir.break
+// CIR-NEXT: }
+
+// OGCG: define dso_local void @_Z4sw11i
+// OGCG: entry:
+// OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   switch i32 %[[A_VAL]], label %[[DEFAULT:.*]] [
+// OGCG:     i32 3, label %[[BB3:.*]]
+// OGCG:     i32 4, label %[[BB4:.*]]
+// OGCG:     i32 5, label %[[BB4]]
+// OGCG:     i32 6, label %[[BB6:.*]]
+// OGCG:     i32 7, label %[[BB6]]
+// OGCG:   ]
+// OGCG: [[BB3]]:
+// OGCG:   br label %[[EPILOG:.*]]
+// OGCG: [[BB4]]:
+// OGCG:   br label %[[DEFAULT]]
+// OGCG: [[DEFAULT]]:
+// OGCG:   br label %[[BB6]]
+// OGCG: [[BB6]]:
+// OGCG:   br label %[[EPILOG]]
+// OGCG: [[EPILOG]]:
+// OGCG:   ret void
+
 void sw12(int a) {
   switch (a)
   {
@@ -278,7 +541,7 @@ void sw13(int a, int b) {
 // CIR-NEXT:          cir.yield
 // CIR-NEXT:        }
 // CIR-NEXT:      }
-// CIR:         cir.yield
+//      CIR:    cir.yield
 //      CIR:    }
 //      CIR:    cir.return
 
@@ -302,6 +565,114 @@ void sw13(int a, int b) {
 // OGCG: [[EPILOG2]]:
 // OGCG:   ret void
 
+void sw14(int x) {
+  switch (x) {
+    case 1:
+    case 2:
+    case 3 ... 6:
+    case 7:
+      break;
+    default:
+      break;
+  }
+}
+
+// CIR:      cir.func @_Z4sw14i
+// CIR:      cir.switch
+// CIR-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<2> : !s32i]) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(range, [#cir.int<3> : !s32i, #cir.int<6> : !s32i]) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<7> : !s32i]) {
+// CIR-NEXT:   cir.break
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(default, []) {
+// CIR-NEXT:   cir.break
+// CIR-NEXT: }
+
+// OGCG: define dso_local void @_Z4sw14i
+// OGCG: entry:
+// OGCG:   %[[X_ADDR:.*]] = alloca i32, align 4
+// OGCG:   store i32 %x, ptr %[[X_ADDR]], align 4
+// OGCG:   %[[X_VAL:.*]] = load i32, ptr %[[X_ADDR]], align 4
+
+// OGCG:   switch i32 %[[X_VAL]], label %[[DEFAULT:.*]] [
+// OGCG-DAG:     i32 1, label %[[BB1:.*]]
+// OGCG-DAG:     i32 2, label %[[BB1]]
+// OGCG-DAG:     i32 3, label %[[BB2:.*]]
+// OGCG-DAG:     i32 4, label %[[BB2]]
+// OGCG-DAG:     i32 5, label %[[BB2]]
+// OGCG-DAG:     i32 6, label %[[BB2]]
+// OGCG-DAG:     i32 7, label %[[BB3:.*]]
+// OGCG:   ]
+// OGCG: [[BB1]]:
+// OGCG:   br label %[[BB2]]
+// OGCG: [[BB2]]:
+// OGCG:   br label %[[BB3]]
+// OGCG: [[BB3]]:
+// OGCG:   br label %[[EPILOG:.*]]
+// OGCG: [[DEFAULT]]:
+// OGCG:   br label %[[EPILOG]]
+// OGCG: [[EPILOG]]:
+// OGCG:   ret void
+
+void sw15(int x) {
+  int y;
+  switch (x) {
+    case 1:
+    case 2:
+      y = 0;
+    case 3:
+      break;
+    default:
+      break;
+  }
+}
+
+// CIR:      cir.func @_Z4sw15i
+// CIR:      %[[Y:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y"]
+// CIR:      cir.switch
+// CIR-NEXT: cir.case(equal, [#cir.int<1> : !s32i]) {
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<2> : !s32i]) {
+// CIR-NEXT:   %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i
+// CIR-NEXT:   cir.store %[[ZERO]], %[[Y]] : !s32i, !cir.ptr<!s32i>
+// CIR-NEXT:   cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(equal, [#cir.int<3> : !s32i]) {
+// CIR-NEXT:   cir.break
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(default, []) {
+// CIR-NEXT:   cir.break
+// CIR-NEXT: }
+
+// OGCG: define dso_local void @_Z4sw15i
+// OGCG: entry:
+// OGCG:   %[[X_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[Y:.*]] = alloca i32, align 4
+// OGCG:   store i32 %x, ptr %[[X_ADDR]], align 4
+// OGCG:   %[[X_VAL:.*]] = load i32, ptr %[[X_ADDR]], align 4
+// OGCG:   switch i32 %[[X_VAL]], label %[[DEFAULT:.*]] [
+// OGCG-DAG:     i32 1, label %[[BB0:.*]]
+// OGCG-DAG:     i32 2, label %[[BB0]]
+// OGCG-DAG:     i32 3, label %[[BB1:.*]]
+// OGCG:   ]
+// OGCG: [[BB0]]:
+// OGCG:   store i32 0, ptr %[[Y]], align 4
+// OGCG:   br label %[[BB1]]
+// OGCG: [[BB1]]:
+// OGCG:   br label %[[EPILOG:.*]]
+// OGCG: [[DEFAULT]]:
+// OGCG:   br label %[[EPILOG]]
+// OGCG: [[EPILOG]]:
+// OGCG:   ret void
+
 int nested_switch(int a) {
   switch (int b = 1; a) {
   case 0:
@@ -325,7 +696,7 @@ int nested_switch(int a) {
   return 0;
 }
 
-// CIR: cir.switch (%6 : !s32i) {
+// CIR: cir.switch (%[[COND:.*]] : !s32i) {
 // CIR:   cir.case(equal, [#cir.int<0> : !s32i]) {
 // CIR:     cir.yield
 // CIR:   }


        


More information about the cfe-commits mailing list