https://github.com/Andres-Salamanca updated 
https://github.com/llvm/llvm-project/pull/137106

>From da645e2445e5539e7ea53307596de684203ecd27 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbari...@gmail.com>
Date: Tue, 22 Apr 2025 15:16:19 -0500
Subject: [PATCH 1/4] Add initial CIR support for switch operation

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td | 224 ++++++++++++++++++-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp      | 131 ++++++++++-
 clang/test/CIR/IR/switch.cir                 |  38 ++++
 3 files changed, 389 insertions(+), 4 deletions(-)
 create mode 100644 clang/test/CIR/IR/switch.cir

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index bb19de31b4fa5..04bfb76c3b95b 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -470,7 +470,8 @@ def StoreOp : CIR_Op<"store", [
 
//===----------------------------------------------------------------------===//
 
 def ReturnOp : CIR_Op<"return", [ParentOneOf<["FuncOp", "ScopeOp", "IfOp",
-                                              "DoWhileOp", "WhileOp", 
"ForOp"]>,
+                                              "SwitchOp", 
"DoWhileOp","WhileOp",
+                                              "ForOp", "CaseOp"]>,
                                  Terminator]> {
   let summary = "Return from function";
   let description = [{
@@ -609,8 +610,9 @@ def ConditionOp : CIR_Op<"condition", [
 
//===----------------------------------------------------------------------===//
 
 def YieldOp : CIR_Op<"yield", [ReturnLike, Terminator,
-                               ParentOneOf<["IfOp", "ScopeOp", "WhileOp",
-                                            "ForOp", "DoWhileOp"]>]> {
+                               ParentOneOf<["IfOp", "ScopeOp", "SwitchOp",
+                                            "WhileOp", "ForOp", "CaseOp",
+                                            "DoWhileOp"]>]> {
   let summary = "Represents the default branching behaviour of a region";
   let description = [{
     The `cir.yield` operation terminates regions on different CIR operations,
@@ -753,6 +755,222 @@ def ScopeOp : CIR_Op<"scope", [
   ];
 }
 
+//===----------------------------------------------------------------------===//
+// SwitchOp
+//===----------------------------------------------------------------------===//
+
+def CaseOpKind_DT : I32EnumAttrCase<"Default", 1, "default">;
+def CaseOpKind_EQ : I32EnumAttrCase<"Equal", 2, "equal">;
+def CaseOpKind_AO : I32EnumAttrCase<"Anyof", 3, "anyof">;
+def CaseOpKind_RG : I32EnumAttrCase<"Range", 4, "range">;
+
+def CaseOpKind : I32EnumAttr<
+    "CaseOpKind",
+    "case kind",
+    [CaseOpKind_DT, CaseOpKind_EQ, CaseOpKind_AO, CaseOpKind_RG]> {
+  let cppNamespace = "::cir";
+}
+
+def CaseOp : CIR_Op<"case", [
+       DeclareOpInterfaceMethods<RegionBranchOpInterface>,
+       RecursivelySpeculatable, AutomaticAllocationScope]> {
+  let summary = "Case operation";
+  let description = [{
+    The `cir.case` operation represents a case within a C/C++ switch.
+    The `cir.case` operation must be in a `cir.switch` operation directly or 
indirectly.
+
+    The `cir.case` have 4 kinds:
+    - `equal, <constant>`: equality of the second case operand against the
+    condition.
+    - `anyof, [constant-list]`: equals to any of the values in a subsequent
+    following list.
+    - `range, [lower-bound, upper-bound]`: the condition is within the closed 
interval.
+    - `default`: any other value.
+
+    Each case region must be explicitly terminated.
+  }];
+
+  let arguments = (ins ArrayAttr:$value, CaseOpKind:$kind);
+  let regions = (region AnyRegion:$caseRegion);
+
+  let assemblyFormat = "`(` $kind `,` $value `)` $caseRegion attr-dict";
+
+  let hasVerifier = 1;
+
+  let skipDefaultBuilders = 1;
+let builders = [
+    OpBuilder<(ins "mlir::ArrayAttr":$value,
+                   "CaseOpKind":$kind,
+                   "mlir::OpBuilder::InsertPoint &":$insertPoint)>
+  ];
+}
+
+def SwitchOp : CIR_Op<"switch",
+      [SameVariadicOperandSize,
+       DeclareOpInterfaceMethods<RegionBranchOpInterface>,
+       RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments]> {
+  let summary = "Switch operation";
+  let description = [{
+    The `cir.switch` operation represents C/C++ switch functionality for
+    conditionally executing multiple regions of code. The operand to an switch
+    is an integral condition value.
+
+    The set of `cir.case` operations and their enclosing `cir.switch`
+    represents the semantics of a C/C++ switch statement. Users can use
+    `collectCases(llvm::SmallVector<CaseOp> &cases)` to collect the `cir.case`
+    operation in the `cir.switch` operation easily.
+
+    The `cir.case` operations doesn't have to be in the region of `cir.switch`
+    directly. However, when all the `cir.case` operations lives in the region
+    of `cir.switch` directly and there is no other operations except the ending
+    `cir.yield` operation in the region of `cir.switch` directly, we call the
+    `cir.switch` operation is in a simple form. Users can use
+    `bool isSimpleForm(llvm::SmallVector<CaseOp> &cases)` member function to
+    detect if the `cir.switch` operation is in a simple form. The simple form
+    makes analysis easier to handle the `cir.switch` operation
+    and makes the boundary to give up pretty clear.
+
+    To make the simple form as common as possible, CIR code generation attaches
+    operations corresponding to the statements that lives between top level
+    cases into the closest `cir.case` operation.
+
+    For example,
+
+    ```
+    switch(int cond) {
+      case 4:
+        a++;
+
+      b++;
+      case 5;
+        c++;
+
+      ...
+    }
+    ```
+
+    The statement `b++` is not a sub-statement of the case statement `case 4`.
+    But to make the generated `cir.switch` a simple form, we will attach the
+    statement `b++` into the closest `cir.case` operation. So that the 
generated
+    code will be like:
+
+    ```
+    cir.switch(int cond) {
+      cir.case(equal, 4) {
+        a++;
+        b++;
+        cir.yield
+      }
+      cir.case(equal, 5) {
+        c++;
+        cir.yield
+      }
+      ...
+    }
+    ```
+
+    For the same reason, we will hoist the case statement as the substatement
+    of another case statement so that they will be in the same level. For
+    example,
+
+    ```
+    switch(int cond) {
+      case 4:
+      default;
+      case 5;
+        a++;
+      ...
+    }
+    ```
+
+    will be generated as
+
+    ```
+    cir.switch(int cond) {
+      cir.case(equal, 4) {
+        cir.yield
+      }
+      cir.case(default) {
+        cir.yield
+      }
+      cir.case(equal, 5) {
+        a++;
+        cir.yield
+      }
+      ...
+    }
+    ```
+
+    The cir.switch might not be considered "simple" if any of the following is
+    true:
+    - There are case statements of the switch statement lives in other scopes
+      other than the top level compound statement scope. Note that a case
+      statement itself doesn't form a scope.
+    - The sub-statement of the switch statement is not a compound statement.
+    - There are codes before the first case statement. For example,
+
+    ```
+    switch(int cond) {
+      l:
+        b++;
+
+      case 4:
+        a++;
+        break;
+
+      case 5:
+        goto l;
+      ...
+    }
+    ```
+
+    the generated CIR for this non-simple switch would be:
+
+    ```
+    cir.switch(int cond) {
+      cir.label "l"
+      b++;
+      cir.case(4) {
+        a++;
+        cir.break
+      }
+      cir.case(5) {
+        goto "l"
+      }
+      cir.yield
+    }
+    ```
+  }];
+
+  let arguments = (ins CIR_IntType:$condition);
+
+  let regions = (region AnyRegion:$body);
+
+  let hasVerifier = 1;
+
+  let skipDefaultBuilders = 1;
+  let builders = [
+    OpBuilder<(ins "mlir::Value":$condition,
+               "llvm::function_ref<void(mlir::OpBuilder &, mlir::Location, 
mlir::OperationState &)>":$switchBuilder)>
+  ];
+
+  let assemblyFormat = [{
+    custom<SwitchOp>(
+      $body, $condition, type($condition)
+    )
+    attr-dict
+  }];
+
+  let extraClassDeclaration = [{
+    // Collect cases in the switch.
+    void collectCases(llvm::SmallVector<CaseOp> &cases);
+
+    // Check if the switch is in a simple form. If yes, collect the cases to 
\param cases.
+    // This is an expensive and need to be used with caution.
+    bool isSimpleForm(llvm::SmallVector<CaseOp> &cases);
+  }];
+}
+
 
//===----------------------------------------------------------------------===//
 // BrOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 3cd17053a52ba..06f413acc8263 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -12,8 +12,10 @@
 
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 
+#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 
+#include "mlir/IR/Builders.h"
 #include "mlir/Interfaces/ControlFlowInterfaces.h"
 #include "mlir/Interfaces/FunctionImplementation.h"
 #include "mlir/Support/LogicalResult.h"
@@ -166,7 +168,8 @@ void cir::AllocaOp::build(mlir::OpBuilder &odsBuilder,
 
 LogicalResult cir::BreakOp::verify() {
   assert(!cir::MissingFeatures::switchOp());
-  if (!getOperation()->getParentOfType<LoopOpInterface>())
+  if (!getOperation()->getParentOfType<LoopOpInterface>() &&
+      !getOperation()->getParentOfType<SwitchOp>())
     return emitOpError("must be within a loop");
   return success();
 }
@@ -802,6 +805,132 @@ Block 
*cir::BrCondOp::getSuccessorForOperands(ArrayRef<Attribute> operands) {
   return nullptr;
 }
 
+//===----------------------------------------------------------------------===//
+// CaseOp
+//===----------------------------------------------------------------------===//
+
+void cir::CaseOp::getSuccessorRegions(
+    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {
+  if (!point.isParent()) {
+    regions.push_back(RegionSuccessor());
+    return;
+  }
+  regions.push_back(RegionSuccessor(&getCaseRegion()));
+}
+
+void cir::CaseOp::build(OpBuilder &builder, OperationState &result,
+                        ArrayAttr value, CaseOpKind kind,
+                        OpBuilder::InsertPoint &insertPoint) {
+  OpBuilder::InsertionGuard guardSwitch(builder);
+  result.addAttribute("value", value);
+  result.getOrAddProperties<Properties>().kind =
+      cir::CaseOpKindAttr::get(builder.getContext(), kind);
+  Region *caseRegion = result.addRegion();
+  builder.createBlock(caseRegion);
+
+  insertPoint = builder.saveInsertionPoint();
+}
+
+LogicalResult cir::CaseOp::verify() { return success(); }
+
+//===----------------------------------------------------------------------===//
+// 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()) {
+    region.push_back(RegionSuccessor());
+    return;
+  }
+
+  region.push_back(RegionSuccessor(&getBody()));
+}
+
+LogicalResult cir::SwitchOp::verify() { return success(); }
+
+void cir::SwitchOp::build(
+    OpBuilder &builder, OperationState &result, Value cond,
+    function_ref<void(OpBuilder &, Location, OperationState &)> switchBuilder) 
{
+  assert(switchBuilder && "the builder callback for regions must be present");
+  OpBuilder::InsertionGuard guardSwitch(builder);
+  Region *switchRegion = result.addRegion();
+  builder.createBlock(switchRegion);
+  result.addOperands({cond});
+  switchBuilder(builder, result.location, result);
+}
+
+void cir::SwitchOp::collectCases(llvm::SmallVector<CaseOp> &cases) {
+  walk<mlir::WalkOrder::PreOrder>([&](mlir::Operation *op) {
+    // Don't walk in nested switch op.
+    if (isa<cir::SwitchOp>(op) && op != *this)
+      return WalkResult::skip();
+
+    if (auto caseOp = dyn_cast<cir::CaseOp>(op))
+      cases.push_back(caseOp);
+
+    return WalkResult::advance();
+  });
+}
+
+// Check if the switch is in a simple form. If yes, collect the cases to \param
+// cases. This is an expensive and need to be used with caution.
+bool cir::SwitchOp::isSimpleForm(llvm::SmallVector<CaseOp> &cases) {
+  collectCases(cases);
+
+  if (getBody().empty())
+    return false;
+
+  if (!isa<YieldOp>(getBody().front().back()))
+    return false;
+
+  if (!llvm::all_of(getBody().front(),
+                    [](Operation &op) { return isa<CaseOp, YieldOp>(op); }))
+    return false;
+
+  return llvm::all_of(cases, [this](CaseOp op) {
+    return op->getParentOfType<SwitchOp>() == *this;
+  });
+}
+
 
//===----------------------------------------------------------------------===//
 // GlobalOp
 
//===----------------------------------------------------------------------===//
diff --git a/clang/test/CIR/IR/switch.cir b/clang/test/CIR/IR/switch.cir
new file mode 100644
index 0000000000000..0bdc9c1e7e896
--- /dev/null
+++ b/clang/test/CIR/IR/switch.cir
@@ -0,0 +1,38 @@
+// RUN: cir-opt %s | FileCheck %s
+!s32i = !cir.int<s, 32>
+
+cir.func @s0() {
+  %1 = cir.const #cir.int<2> : !s32i
+  cir.switch (%1 : !s32i) {
+    cir.case (default, []) {
+      cir.return
+    }
+    cir.case (equal, [#cir.int<3> : !s32i]) {
+      cir.yield
+    }
+    cir.case (anyof, [#cir.int<6> : !s32i, #cir.int<7> : !s32i, #cir.int<8> : 
!s32i]) {
+      cir.break
+    }
+    cir.case (equal, [#cir.int<5> : !s32i]) {
+      cir.yield
+    }
+    cir.yield
+  }
+  cir.return
+}
+
+// CHECK: cir.switch (%0 : !s32i) {
+// CHECK-NEXT: cir.case(default, [])  {
+// CHECK-NEXT:   cir.return
+// CHECK-NEXT: }
+// CHECK-NEXT: cir.case(equal, [#cir.int<3> : !s32i])  {
+// CHECK-NEXT:   cir.yield
+// CHECK-NEXT: }
+// CHECK-NEXT: cir.case(anyof, [#cir.int<6> : !s32i, #cir.int<7> : !s32i, 
#cir.int<8> : !s32i]) {
+// CHECK-NEXT:   cir.break
+// CHECK-NEXT: }
+// CHECK-NEXT: cir.case(equal, [#cir.int<5> : !s32i])  {
+// CHECK-NEXT:   cir.yield
+// CHECK-NEXT: }
+// CHECK-NEXT: cir.yield
+// CHECK-NEXT: }

>From 91a10519cfa36c2dc288e5493c52592925be568b Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbari...@gmail.com>
Date: Wed, 23 Apr 2025 17:16:17 -0500
Subject: [PATCH 2/4] Add codegen for switch and EqualCase kind

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td |   9 +-
 clang/include/clang/CIR/MissingFeatures.h    |   1 +
 clang/lib/CIR/CodeGen/CIRGenFunction.h       |  18 ++
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp         | 210 ++++++++++++++++++-
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp      |   1 -
 clang/test/CIR/CodeGen/switch.cpp            |  92 ++++++++
 6 files changed, 326 insertions(+), 5 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/switch.cpp

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 04bfb76c3b95b..25cdf156659c7 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -777,14 +777,16 @@ def CaseOp : CIR_Op<"case", [
   let summary = "Case operation";
   let description = [{
     The `cir.case` operation represents a case within a C/C++ switch.
-    The `cir.case` operation must be in a `cir.switch` operation directly or 
indirectly.
+    The `cir.case` operation must be in a `cir.switch` operation directly
+    or indirectly.
 
     The `cir.case` have 4 kinds:
     - `equal, <constant>`: equality of the second case operand against the
     condition.
     - `anyof, [constant-list]`: equals to any of the values in a subsequent
     following list.
-    - `range, [lower-bound, upper-bound]`: the condition is within the closed 
interval.
+    - `range, [lower-bound, upper-bound]`: the condition is within the closed
+                                           interval.
     - `default`: any other value.
 
     Each case region must be explicitly terminated.
@@ -965,7 +967,8 @@ def SwitchOp : CIR_Op<"switch",
     // Collect cases in the switch.
     void collectCases(llvm::SmallVector<CaseOp> &cases);
 
-    // Check if the switch is in a simple form. If yes, collect the cases to 
\param cases.
+    // Check if the switch is in a simple form.
+    // If yes, collect the cases to \param cases.
     // This is an expensive and need to be used with caution.
     bool isSimpleForm(llvm::SmallVector<CaseOp> &cases);
   }];
diff --git a/clang/include/clang/CIR/MissingFeatures.h 
b/clang/include/clang/CIR/MissingFeatures.h
index 6bfc1199aea55..4783468036ec3 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -159,6 +159,7 @@ struct MissingFeatures {
   static bool bitfields() { return false; }
   static bool typeChecks() { return false; }
   static bool lambdaFieldToName() { return false; }
+  static bool foldCaseStmt() { return false; }
 
   // Missing types
   static bool dataMemberType() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h 
b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index f533d0ab53cd2..f08a0521d7881 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -63,6 +63,9 @@ class CIRGenFunction : public CIRGenTypeCache {
   /// declarations.
   DeclMapTy localDeclMap;
 
+  /// The type of the condition for the emitting switch statement.
+  llvm::SmallVector<mlir::Type, 2> condTypeStack;
+
   clang::ASTContext &getContext() const { return cgm.getASTContext(); }
 
   CIRGenBuilderTy &getBuilder() { return builder; }
@@ -469,6 +472,16 @@ class CIRGenFunction : public CIRGenTypeCache {
                       ReturnValueSlot returnValue = ReturnValueSlot());
   CIRGenCallee emitCallee(const clang::Expr *e);
 
+  template <typename T>
+  mlir::LogicalResult emitCaseDefaultCascade(const T *stmt, mlir::Type 
condType,
+                                             mlir::ArrayAttr value,
+                                             cir::CaseOpKind kind,
+                                             bool buildingTopLevelCase);
+
+  mlir::LogicalResult emitCaseStmt(const clang::CaseStmt &s,
+                                   mlir::Type condType,
+                                   bool buildingTopLevelCase);
+
   mlir::LogicalResult emitContinueStmt(const clang::ContinueStmt &s);
   mlir::LogicalResult emitDoStmt(const clang::DoStmt &s);
 
@@ -595,6 +608,11 @@ class CIRGenFunction : public CIRGenTypeCache {
 
   mlir::Value emitStoreThroughBitfieldLValue(RValue src, LValue dstresult);
 
+  mlir::LogicalResult emitSwitchBody(const clang::Stmt *s);
+  mlir::LogicalResult emitSwitchCase(const clang::SwitchCase &s,
+                                     bool buildingTopLevelCase);
+  mlir::LogicalResult emitSwitchStmt(const clang::SwitchStmt &s);
+
   /// Given a value and its clang type, returns the value casted to its memory
   /// representation.
   /// Note: CIR defers most of the special casting to the final lowering passes
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 82ac53706b7f9..76fa7bf07f097 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -89,6 +89,8 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
     }
   case Stmt::IfStmtClass:
     return emitIfStmt(cast<IfStmt>(*s));
+  case Stmt::SwitchStmtClass:
+    return emitSwitchStmt(cast<SwitchStmt>(*s));
   case Stmt::ForStmtClass:
     return emitForStmt(cast<ForStmt>(*s));
   case Stmt::WhileStmtClass:
@@ -132,7 +134,6 @@ mlir::LogicalResult CIRGenFunction::emitStmt(const Stmt *s,
   case Stmt::CaseStmtClass:
   case Stmt::SEHLeaveStmtClass:
   case Stmt::SYCLKernelCallStmtClass:
-  case Stmt::SwitchStmtClass:
   case Stmt::CoroutineBodyStmtClass:
   case Stmt::CoreturnStmtClass:
   case Stmt::CXXTryStmtClass:
@@ -422,6 +423,117 @@ mlir::LogicalResult CIRGenFunction::emitBreakStmt(const 
clang::BreakStmt &s) {
   return mlir::success();
 }
 
+template <typename T>
+mlir::LogicalResult
+CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType,
+                                       mlir::ArrayAttr value, CaseOpKind kind,
+                                       bool buildingTopLevelCase) {
+
+  assert((isa<CaseStmt, DefaultStmt>(stmt)) &&
+         "only case or default stmt go here");
+
+  mlir::LogicalResult result = mlir::success();
+
+  mlir::Location loc = getLoc(stmt->getBeginLoc());
+
+  enum class SubStmtKind { Case, Default, Other };
+  SubStmtKind subStmtKind = SubStmtKind::Other;
+  const Stmt *sub = stmt->getSubStmt();
+
+  mlir::OpBuilder::InsertPoint insertPoint;
+  builder.create<CaseOp>(loc, value, kind, insertPoint);
+
+  {
+    mlir::OpBuilder::InsertionGuard guardSwitch(builder);
+    builder.restoreInsertionPoint(insertPoint);
+
+    if (isa<DefaultStmt>(sub) && isa<CaseStmt>(stmt)) {
+      subStmtKind = SubStmtKind::Default;
+      builder.createYield(loc);
+    } else if (isa<CaseStmt>(sub) && isa<DefaultStmt>(stmt)) {
+      subStmtKind = SubStmtKind::Case;
+      builder.createYield(loc);
+    } else
+      result = emitStmt(sub, /*useCurrentScope=*/!isa<CompoundStmt>(sub));
+
+    insertPoint = builder.saveInsertionPoint();
+  }
+
+  // If the substmt is default stmt or case stmt, try to handle the special 
case
+  // to make it into the simple form. e.g.
+  //
+  //  swtich () {
+  //    case 1:
+  //    default:
+  //      ...
+  //  }
+  //
+  // we prefer generating
+  //
+  //  cir.switch() {
+  //     cir.case(equal, 1) {
+  //        cir.yield
+  //     }
+  //     cir.case(default) {
+  //        ...
+  //     }
+  //  }
+  //
+  // than
+  //
+  //  cir.switch() {
+  //     cir.case(equal, 1) {
+  //       cir.case(default) {
+  //         ...
+  //       }
+  //     }
+  //  }
+  //
+  // We don't need to revert this if we find the current switch can't be in
+  // simple form later since the conversion itself should be harmless.
+  if (subStmtKind == SubStmtKind::Case)
+    result = emitCaseStmt(*cast<CaseStmt>(sub), condType, 
buildingTopLevelCase);
+  else if (subStmtKind == SubStmtKind::Default)
+    getCIRGenModule().errorNYI(sub->getSourceRange(), "Default case");
+  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
+    // case to make generating `cir.switch` operation to be a simple form.
+    builder.restoreInsertionPoint(insertPoint);
+
+  return result;
+}
+
+mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
+                                                 mlir::Type condType,
+                                                 bool buildingTopLevelCase) {
+  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");
+  }
+  assert(!cir::MissingFeatures::foldCaseStmt());
+  return emitCaseDefaultCascade(&s, condType, value, cir::CaseOpKind::Equal,
+                                buildingTopLevelCase);
+}
+
+mlir::LogicalResult CIRGenFunction::emitSwitchCase(const SwitchCase &s,
+                                                   bool buildingTopLevelCase) {
+  assert(!condTypeStack.empty() &&
+         "build switch case without specifying the type of the condition");
+
+  if (s.getStmtClass() == Stmt::CaseStmtClass)
+    return emitCaseStmt(cast<CaseStmt>(s), condTypeStack.back(),
+                        buildingTopLevelCase);
+
+  if (s.getStmtClass() == Stmt::DefaultStmtClass)
+    getCIRGenModule().errorNYI(s.getSourceRange(), "Default case");
+
+  llvm_unreachable("expect case or default stmt");
+}
+
 mlir::LogicalResult CIRGenFunction::emitForStmt(const ForStmt &s) {
   cir::ForOp forOp;
 
@@ -600,3 +712,99 @@ mlir::LogicalResult CIRGenFunction::emitWhileStmt(const 
WhileStmt &s) {
   terminateBody(builder, whileOp.getBody(), getLoc(s.getEndLoc()));
   return mlir::success();
 }
+
+mlir::LogicalResult CIRGenFunction::emitSwitchBody(const Stmt *s) {
+  // It is rare but legal if the switch body is not a compound stmt. e.g.,
+  //
+  //  switch(a)
+  //    while(...) {
+  //      case1
+  //      ...
+  //      case2
+  //      ...
+  //    }
+  if (!isa<CompoundStmt>(s))
+    return emitStmt(s, /*useCurrentScope=*/!false);
+
+  auto *compoundStmt = cast<CompoundStmt>(s);
+
+  mlir::Block *swtichBlock = builder.getBlock();
+  for (auto *c : compoundStmt->body()) {
+    if (auto *switchCase = dyn_cast<SwitchCase>(c)) {
+      builder.setInsertionPointToEnd(swtichBlock);
+      // Reset insert point automatically, so that we can attach following
+      // random stmt to the region of previous built case op to try to make
+      // the being generated `cir.switch` to be in simple form.
+      if (mlir::failed(
+              emitSwitchCase(*switchCase, /*buildingTopLevelCase=*/true)))
+        return mlir::failure();
+
+      continue;
+    }
+
+    // Otherwise, just build the statements in the nearest case region.
+    if (mlir::failed(emitStmt(c, /*useCurrentScope=*/!isa<CompoundStmt>(c))))
+      return mlir::failure();
+  }
+
+  return mlir::success();
+}
+
+mlir::LogicalResult CIRGenFunction::emitSwitchStmt(const clang::SwitchStmt &s) 
{
+  // TODO: LLVM codegen does some early optimization to fold the condition and
+  // only emit live cases. CIR should use MLIR to achieve similar things,
+  // nothing to be done here.
+  // if (ConstantFoldsToSimpleInteger(S.getCond(), ConstantCondValue))...
+
+  SwitchOp swop;
+  auto switchStmtBuilder = [&]() -> mlir::LogicalResult {
+    if (s.getInit())
+      if (emitStmt(s.getInit(), /*useCurrentScope=*/true).failed())
+        return mlir::failure();
+
+    if (s.getConditionVariable())
+      emitDecl(*s.getConditionVariable());
+
+    mlir::Value condV = emitScalarExpr(s.getCond());
+
+    // TODO: PGO and likelihood (e.g. PGO.haveRegionCounts())
+    assert(!cir::MissingFeatures::pgoUse());
+    assert(!cir::MissingFeatures::emitCondLikelihoodViaExpectIntrinsic());
+    // TODO: if the switch has a condition wrapped by __builtin_unpredictable?
+    assert(!cir::MissingFeatures::insertBuiltinUnpredictable());
+
+    mlir::LogicalResult res = mlir::success();
+    swop = builder.create<SwitchOp>(
+        getLoc(s.getBeginLoc()), condV,
+        /*switchBuilder=*/
+        [&](mlir::OpBuilder &b, mlir::Location loc, mlir::OperationState &os) {
+          curLexScope->setAsSwitch();
+
+          condTypeStack.push_back(condV.getType());
+
+          res = emitSwitchBody(s.getBody());
+
+          condTypeStack.pop_back();
+        });
+
+    return res;
+  };
+
+  // The switch scope contains the full source range for SwitchStmt.
+  mlir::Location scopeLoc = getLoc(s.getSourceRange());
+  mlir::LogicalResult res = mlir::success();
+  builder.create<cir::ScopeOp>(scopeLoc, /*scopeBuilder=*/
+                               [&](mlir::OpBuilder &b, mlir::Location loc) {
+                                 LexicalScope lexScope{
+                                     *this, loc, builder.getInsertionBlock()};
+                                 res = switchStmtBuilder();
+                               });
+
+  llvm::SmallVector<CaseOp> cases;
+  swop.collectCases(cases);
+  for (auto caseOp : cases)
+    terminateBody(builder, caseOp.getCaseRegion(), caseOp.getLoc());
+  terminateBody(builder, swop.getBody(), swop.getLoc());
+
+  return res;
+}
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 06f413acc8263..85ba12d41a516 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -15,7 +15,6 @@
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 
-#include "mlir/IR/Builders.h"
 #include "mlir/Interfaces/ControlFlowInterfaces.h"
 #include "mlir/Interfaces/FunctionImplementation.h"
 #include "mlir/Support/LogicalResult.h"
diff --git a/clang/test/CIR/CodeGen/switch.cpp 
b/clang/test/CIR/CodeGen/switch.cpp
new file mode 100644
index 0000000000000..5667949b9a0c0
--- /dev/null
+++ b/clang/test/CIR/CodeGen/switch.cpp
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir 
-emit-cir %s -o %t.cir
+/// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm %s 
-o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG
+void sw1(int a) {
+  switch (int b = 1; a) {
+  case 0:
+    b = b + 1;
+    break;
+  case 1:
+    break;
+  case 2: {
+    b = b + 1;
+    int yolo = 100;
+    break;
+  }
+  }
+}
+// CIR: cir.func @sw1
+// CIR: cir.switch (%3 : !s32i) {
+// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
+// CIR: cir.break
+// CIR: cir.case(equal, [#cir.int<1> : !s32i]) {
+// CIR-NEXT: cir.break
+// CIR: cir.case(equal, [#cir.int<2> : !s32i]) {
+// CIR: cir.scope {
+// CIR: cir.alloca !s32i, !cir.ptr<!s32i>, ["yolo", init]
+// CIR: cir.break
+
+// OGCG: define dso_local void @_Z3sw1i
+// OGCG: entry:
+// OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[B:.*]] = alloca i32, align 4
+// OGCG:   %[[YOLO:.*]] = alloca i32, align 4
+// OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   switch i32 %[[A_VAL]], label %[[SW_EPILOG:.*]] [
+// OGCG:     i32 0, label %[[SW0:.*]]
+// OGCG:     i32 1, label %[[SW1:.*]]
+// OGCG:     i32 2, label %[[SW2:.*]]
+// OGCG:   ]
+// OGCG: [[SW0]]:
+// OGCG:   %[[B_LOAD0:.*]] = load i32, ptr %[[B]], align 4
+// OGCG:   %[[B_INC0:.*]] = add nsw i32 %[[B_LOAD0]], 1
+// OGCG:   store i32 %[[B_INC0]], ptr %[[B]], align 4
+// OGCG:   br label %[[SW_EPILOG]]
+// OGCG: [[SW1]]:
+// OGCG:   br label %[[SW_EPILOG]]
+// OGCG: [[SW2]]:
+// OGCG:   %[[B_LOAD2:.*]] = load i32, ptr %[[B]], align 4
+// OGCG:   %[[B_INC2:.*]] = add nsw i32 %[[B_LOAD2]], 1
+// OGCG:   store i32 %[[B_INC2]], ptr %[[B]], align 4
+// OGCG:   store i32 100, ptr %[[YOLO]], align 4
+// OGCG:   br label %[[SW_EPILOG]]
+// OGCG: [[SW_EPILOG]]:
+// OGCG:   ret void
+
+void sw2(int a) {
+  switch (int yolo = 2; a) {
+  case 3:
+    // "fomo" has the same lifetime as "yolo"
+    int fomo = 0;
+    yolo = yolo + fomo;
+    break;
+  }
+}
+
+// CIR: cir.func @sw2
+// 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:   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>
+
+// OGCG: define dso_local void @_Z3sw2i
+// OGCG: entry:
+// OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[YOLO:.*]] = alloca i32, align 4
+// OGCG:   %[[FOMO:.*]] = alloca i32, align 4
+// OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   switch i32 %[[A_VAL]], label %[[SW_EPILOG:.*]] [
+// OGCG:     i32 3, label %[[SW3:.*]]
+// OGCG:   ]
+// OGCG: [[SW3]]:
+// OGCG:   %[[Y:.*]] = load i32, ptr %[[YOLO]], align 4
+// OGCG:   %[[F:.*]] = load i32, ptr %[[FOMO]], align 4
+// OGCG:   %[[SUM:.*]] = add nsw i32 %[[Y]], %[[F]]
+// OGCG:   store i32 %[[SUM]], ptr %[[YOLO]], align 4
+// OGCG:   br label %[[SW_EPILOG]]
+// OGCG: [[SW_EPILOG]]:
+// OGCG:   ret void

>From 1fe966e32213e6235d8aad734a786d9878d31e01 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbari...@gmail.com>
Date: Wed, 23 Apr 2025 18:43:23 -0500
Subject: [PATCH 3/4] Add early return after NYI to prevent crashes

---
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 76fa7bf07f097..9c17821415f32 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -493,9 +493,10 @@ CIRGenFunction::emitCaseDefaultCascade(const T *stmt, 
mlir::Type condType,
   // simple form later since the conversion itself should be harmless.
   if (subStmtKind == SubStmtKind::Case)
     result = emitCaseStmt(*cast<CaseStmt>(sub), condType, 
buildingTopLevelCase);
-  else if (subStmtKind == SubStmtKind::Default)
+  else if (subStmtKind == SubStmtKind::Default) {
     getCIRGenModule().errorNYI(sub->getSourceRange(), "Default case");
-  else if (buildingTopLevelCase)
+    return mlir::failure();
+  } 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
     // case to make generating `cir.switch` operation to be a simple form.
@@ -513,6 +514,7 @@ mlir::LogicalResult CIRGenFunction::emitCaseStmt(const 
CaseStmt &s,
   mlir::ArrayAttr value = builder.getArrayAttr(caseEltValueListAttr);
   if (s.getRHS()) {
     getCIRGenModule().errorNYI(s.getSourceRange(), "SwitchOp range kind");
+    return mlir::failure();
   }
   assert(!cir::MissingFeatures::foldCaseStmt());
   return emitCaseDefaultCascade(&s, condType, value, cir::CaseOpKind::Equal,
@@ -528,8 +530,10 @@ mlir::LogicalResult CIRGenFunction::emitSwitchCase(const 
SwitchCase &s,
     return emitCaseStmt(cast<CaseStmt>(s), condTypeStack.back(),
                         buildingTopLevelCase);
 
-  if (s.getStmtClass() == Stmt::DefaultStmtClass)
+  if (s.getStmtClass() == Stmt::DefaultStmtClass) {
     getCIRGenModule().errorNYI(s.getSourceRange(), "Default case");
+    return mlir::failure();
+  }
 
   llvm_unreachable("expect case or default stmt");
 }
@@ -724,7 +728,7 @@ mlir::LogicalResult CIRGenFunction::emitSwitchBody(const 
Stmt *s) {
   //      ...
   //    }
   if (!isa<CompoundStmt>(s))
-    return emitStmt(s, /*useCurrentScope=*/!false);
+    return emitStmt(s, /*useCurrentScope=*/true);
 
   auto *compoundStmt = cast<CompoundStmt>(s);
 

>From 94f2aa74ab1518a105e3c84ad976afa1b6332148 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbari...@gmail.com>
Date: Thu, 24 Apr 2025 17:53:24 -0500
Subject: [PATCH 4/4] Fixed format, addressed reviews, and added more tests for
 better coverage

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td |   4 +-
 clang/lib/CIR/CodeGen/CIRGenStmt.cpp         |   5 +
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp      |  14 +-
 clang/test/CIR/CodeGen/switch.cpp            | 191 +++++++++++++++++++
 4 files changed, 204 insertions(+), 10 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td 
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 25cdf156659c7..bab1e994a1577 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -800,8 +800,8 @@ def CaseOp : CIR_Op<"case", [
   let hasVerifier = 1;
 
   let skipDefaultBuilders = 1;
-let builders = [
-    OpBuilder<(ins "mlir::ArrayAttr":$value,
+  let builders = [
+      OpBuilder<(ins "mlir::ArrayAttr":$value,
                    "CaseOpKind":$kind,
                    "mlir::OpBuilder::InsertPoint &":$insertPoint)>
   ];
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp 
b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 9c17821415f32..dfa290d7e415e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -252,6 +252,11 @@ mlir::LogicalResult CIRGenFunction::emitSimpleStmt(const 
Stmt *s,
   // NullStmt doesn't need any handling, but we need to say we handled it.
   case Stmt::NullStmtClass:
     break;
+  case Stmt::CaseStmtClass:
+    // If we reached here, we must not handling a switch case in the top level.
+    return emitSwitchCase(cast<SwitchCase>(*s),
+                          /*buildingTopLevelCase=*/false);
+    break;
 
   case Stmt::BreakStmtClass:
     return emitBreakStmt(cast<BreakStmt>(*s));
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp 
b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 85ba12d41a516..de942cc88c42e 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -842,22 +842,22 @@ static ParseResult parseSwitchOp(OpAsmParser &parser, 
mlir::Region &regions,
   cir::IntType intCondType;
 
   if (parser.parseLParen())
-    return ::mlir::failure();
+    return mlir::failure();
 
   if (parser.parseOperand(cond))
-    return ::mlir::failure();
+    return mlir::failure();
   if (parser.parseColon())
-    return ::mlir::failure();
+    return mlir::failure();
   if (parser.parseCustomTypeWithFallback(intCondType))
-    return ::mlir::failure();
+    return mlir::failure();
   condType = intCondType;
 
   if (parser.parseRParen())
-    return ::mlir::failure();
+    return mlir::failure();
   if (parser.parseRegion(regions, /*arguments=*/{}, /*argTypes=*/{}))
     return failure();
 
-  return ::mlir::success();
+  return mlir::success();
 }
 
 static void printSwitchOp(OpAsmPrinter &p, cir::SwitchOp op,
@@ -910,8 +910,6 @@ void cir::SwitchOp::collectCases(llvm::SmallVector<CaseOp> 
&cases) {
   });
 }
 
-// Check if the switch is in a simple form. If yes, collect the cases to \param
-// cases. This is an expensive and need to be used with caution.
 bool cir::SwitchOp::isSimpleForm(llvm::SmallVector<CaseOp> &cases) {
   collectCases(cases);
 
diff --git a/clang/test/CIR/CodeGen/switch.cpp 
b/clang/test/CIR/CodeGen/switch.cpp
index 5667949b9a0c0..dbcb2694aac5b 100644
--- a/clang/test/CIR/CodeGen/switch.cpp
+++ b/clang/test/CIR/CodeGen/switch.cpp
@@ -90,3 +90,194 @@ void sw2(int a) {
 // OGCG:   br label %[[SW_EPILOG]]
 // OGCG: [[SW_EPILOG]]:
 // OGCG:   ret void
+
+void sw5(int a) {
+  switch (a) {
+  case 1:;
+  }
+}
+
+// CIR: cir.func @sw5
+// CIR: cir.switch (%1 : !s32i) {
+// CIR-NEXT:   cir.case(equal, [#cir.int<1> : !s32i]) {
+// CIR-NEXT:     cir.yield
+// CIR-NEXT:   }
+// CIR-NEXT:   cir.yield
+// CIR-NEXT:   }
+
+// OGCG: define dso_local void @_Z3sw5i
+// 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 %[[SW_EPILOG:.*]] [
+// OGCG:     i32 1, label %[[SW1:.*]]
+// OGCG:   ]
+// OGCG: [[SW1]]:
+// OGCG:   br label %[[SW_EPILOG]]
+// OGCG: [[SW_EPILOG]]:
+// OGCG:   ret void
+
+void sw12(int a) {
+  switch (a)
+  {
+  case 3:
+    return;
+    break;
+  }
+}
+
+//      CIR: cir.func @sw12
+//      CIR:   cir.scope {
+//      CIR:     cir.switch
+// CIR-NEXT:     cir.case(equal, [#cir.int<3> : !s32i]) {
+// CIR-NEXT:       cir.return
+// CIR-NEXT:     ^bb1:  // no predecessors
+// CIR-NEXT:       cir.break
+// CIR-NEXT:     }
+
+// OGCG: define dso_local void @_Z4sw12i
+// 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 %[[SW_DEFAULT:.*]] [
+// OGCG:     i32 3, label %[[SW3:.*]]
+// OGCG:   ]
+// OGCG: [[SW3]]:
+// OGCG:   br label %[[SW_DEFAULT]]
+// OGCG: [[SW_DEFAULT]]:
+// OGCG:   ret void
+
+void sw13(int a, int b) {
+  switch (a) {
+  case 1:
+    switch (b) {
+    case 2:
+      break;
+    }
+  }
+}
+
+//      CIR:  cir.func @sw13
+//      CIR:    cir.scope {
+//      CIR:      cir.switch
+// CIR-NEXT:      cir.case(equal, [#cir.int<1> : !s32i]) {
+// CIR-NEXT:        cir.scope {
+//      CIR:          cir.switch
+// CIR-NEXT:          cir.case(equal, [#cir.int<2> : !s32i]) {
+// CIR-NEXT:            cir.break
+// CIR-NEXT:          }
+// CIR-NEXT:          cir.yield
+// CIR-NEXT:        }
+// CIR-NEXT:      }
+// CIR:         cir.yield
+//      CIR:    }
+//      CIR:    cir.return
+
+// OGCG: define dso_local void @_Z4sw13ii
+// OGCG: entry:
+// OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[B_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[A_VAL:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   switch i32 %[[A_VAL]], label %[[EPILOG2:.*]] [
+// OGCG:     i32 1, label %[[SW1:.*]]
+// OGCG:   ]
+// OGCG: [[SW1]]:
+// OGCG:   %[[B_VAL:.*]] = load i32, ptr %[[B_ADDR]], align 4
+// OGCG:   switch i32 %[[B_VAL]], label %[[EPILOG:.*]] [
+// OGCG:     i32 2, label %[[SW12:.*]]
+// OGCG:   ]
+// OGCG: [[SW12]]:
+// OGCG:   br label %[[EPILOG]]
+// OGCG: [[EPILOG]]:
+// OGCG:   br label %[[EPILOG2]]
+// OGCG: [[EPILOG2]]:
+// OGCG:   ret void
+
+int nested_switch(int a) {
+  switch (int b = 1; a) {
+  case 0:
+    b = b + 1;
+  case 1:
+    return b;
+  case 2: {
+    b = b + 1;
+    if (a > 1000) {
+        case 9:
+          b = a + b;
+    }
+    if (a > 500) {
+        case 7:
+          return a + b;
+    }
+    break;
+  }
+  }
+
+  return 0;
+}
+
+// CIR: cir.switch (%6 : !s32i) {
+// CIR:   cir.case(equal, [#cir.int<0> : !s32i]) {
+// CIR:     cir.yield
+// CIR:   }
+// CIR:   cir.case(equal, [#cir.int<1> : !s32i]) {
+// CIR:     cir.return
+// CIR:   }
+// CIR:   cir.case(equal, [#cir.int<2> : !s32i]) {
+// CIR:     cir.scope {
+// CIR:     cir.scope {
+// CIR:       cir.if
+// CIR:         cir.case(equal, [#cir.int<9> : !s32i]) {
+// CIR:         cir.yield
+// CIR:     cir.scope {
+// CIR:         cir.if
+// CIR:           cir.case(equal, [#cir.int<7> : !s32i]) {
+// CIR:           cir.return
+
+// OGCG: define dso_local noundef i32 @_Z13nested_switchi
+// OGCG: entry:
+// OGCG:   %[[RETVAL:.*]] = alloca i32, align 4
+// OGCG:   %[[A_ADDR:.*]] = alloca i32, align 4
+// OGCG:   %[[B:.*]] = 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 %[[SW0:.*]]
+// OGCG:     i32 1, label %[[SW1:.*]]
+// OGCG:     i32 2, label %[[SW2:.*]]
+// OGCG:     i32 9, label %[[SW4:.*]]
+// OGCG:     i32 7, label %[[SW8:.*]]
+// OGCG:   ]
+// OGCG: [[SW0]]:
+// OGCG:   %[[B_VAL0:.*]] = load i32, ptr %[[B]], align 4
+// OGCG:   %[[ADD0:.*]] = add nsw i32 %[[B_VAL0]], 1
+// OGCG:   br label %[[SW1]]
+// OGCG: [[SW1]]:
+// OGCG:   %[[B_VAL1:.*]] = load i32, ptr %[[B]], align 4
+// OGCG:   br label %[[RETURN:.*]]
+// OGCG: [[SW2]]:
+// OGCG:   %[[B_VAL2:.*]] = load i32, ptr %[[B]], align 4
+// OGCG:   %[[ADD2:.*]] = add nsw i32 %[[B_VAL2]], 1
+// OGCG:   %[[A_VAL2:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   %[[CMP1000:.*]] = icmp sgt i32 %[[A_VAL2]], 1000
+// OGCG:   br i1 %[[CMP1000]], label %[[IFTHEN:.*]], label %[[IFEND:.*]]
+// OGCG: [[IFTHEN]]:
+// OGCG:   br label %[[SW4]]
+// OGCG: [[SW4]]:
+// OGCG:   %[[A_VAL4:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   %[[B_VAL4:.*]] = load i32, ptr %[[B]], align 4
+// OGCG:   %[[ADD4:.*]] = add nsw i32 %[[A_VAL4]], %[[B_VAL4]]
+// OGCG:   br label %[[IFEND]]
+// OGCG: [[IFEND]]:
+// OGCG:   %[[A_VAL5:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   %[[CMP500:.*]] = icmp sgt i32 %[[A_VAL5]], 500
+// OGCG:   br i1 %[[CMP500]], label %[[IFTHEN7:.*]], label %[[IFEND10:.*]]
+// OGCG: [[IFTHEN7]]:
+// OGCG:   br label %[[SW8]]
+// OGCG: [[SW8]]:
+// OGCG:   %[[A_VAL8:.*]] = load i32, ptr %[[A_ADDR]], align 4
+// OGCG:   %[[B_VAL8:.*]] = load i32, ptr %[[B]], align 4
+// OGCG:   %[[ADD8:.*]] = add nsw i32 %[[A_VAL8]], %[[B_VAL8]]
+// OGCG:   br label %[[RETURN]]
+// OGCG: [[IFEND10]]:
+// OGCG:   br label %[[EPILOG]]
+// OGCG: [[EPILOG]]:

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to