[clang] [CIR] Upstream support for switch statements case kinds (PR #138003)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 5 13:33:57 PDT 2025
https://github.com/Andres-Salamanca updated https://github.com/llvm/llvm-project/pull/138003
>From ff564e64a2ca9948e51c174a5e7a71b05acea510 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Wed, 30 Apr 2025 12:17:31 -0500
Subject: [PATCH 1/8] add support for anyOf, default, and range case kinds
---
clang/lib/CIR/CodeGen/CIRGenFunction.h | 8 +
clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 80 ++++++--
clang/test/CIR/CodeGen/switch.cpp | 247 +++++++++++++++++++++++--
3 files changed, 309 insertions(+), 26 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 592d39930089d..fb1a7dc75161d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -278,6 +278,9 @@ class CIRGenFunction : public CIRGenTypeCache {
/// addressed later.
RValue getUndefRValue(clang::QualType ty);
+ const CaseStmt *foldCaseStmt(const clang::CaseStmt &s, mlir::Type condType,
+ mlir::ArrayAttr &value, cir::CaseOpKind &kind);
+
cir::FuncOp generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
cir::FuncType funcType);
@@ -532,6 +535,11 @@ 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 31e29e7828156..e9e163d5090d8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -253,6 +253,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);
@@ -428,6 +429,53 @@ mlir::LogicalResult CIRGenFunction::emitBreakStmt(const clang::BreakStmt &s) {
return mlir::success();
}
+
+const CaseStmt *CIRGenFunction::foldCaseStmt(const clang::CaseStmt &s,
+ mlir::Type condType,
+ mlir::ArrayAttr &value,
+ cir::CaseOpKind &kind) {
+ const CaseStmt *caseStmt = &s;
+ const CaseStmt *lastCase = &s;
+ SmallVector<mlir::Attribute, 4> caseEltValueListAttr;
+
+ // Fold cascading cases whenever possible to simplify codegen a bit.
+ while (caseStmt) {
+ lastCase = caseStmt;
+
+ auto intVal = caseStmt->getLHS()->EvaluateKnownConstInt(getContext());
+
+ if (auto *rhs = caseStmt->getRHS()) {
+ auto endVal = rhs->EvaluateKnownConstInt(getContext());
+ SmallVector<mlir::Attribute, 4> rangeCaseAttr = {
+ cir::IntAttr::get(condType, intVal),
+ cir::IntAttr::get(condType, endVal)};
+ value = builder.getArrayAttr(rangeCaseAttr);
+ kind = cir::CaseOpKind::Range;
+
+ // We may not be able to fold rangaes. Due to we can't present range case
+ // with other trivial cases now.
+ return caseStmt;
+ }
+
+ caseEltValueListAttr.push_back(cir::IntAttr::get(condType, intVal));
+
+ caseStmt = dyn_cast_or_null<CaseStmt>(caseStmt->getSubStmt());
+
+ // Break early if we found ranges. We can't fold ranges due to the same
+ // reason above.
+ if (caseStmt && caseStmt->getRHS())
+ break;
+ }
+
+ if (!caseEltValueListAttr.empty()) {
+ value = builder.getArrayAttr(caseEltValueListAttr);
+ kind = caseEltValueListAttr.size() > 1 ? cir::CaseOpKind::Anyof
+ : cir::CaseOpKind::Equal;
+ }
+
+ return lastCase;
+}
+
template <typename T>
mlir::LogicalResult
CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType,
@@ -500,8 +548,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
@@ -515,19 +563,22 @@ CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType,
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");
- return mlir::failure();
- }
+ cir::CaseOpKind kind;
+ mlir::ArrayAttr value;
assert(!cir::MissingFeatures::foldCaseStmt());
- return emitCaseDefaultCascade(&s, condType, value, cir::CaseOpKind::Equal,
+ const CaseStmt *caseStmt = foldCaseStmt(s, condType, value, kind);
+ return emitCaseDefaultCascade(caseStmt, 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() &&
@@ -537,10 +588,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..ea0e95e7eb553 100644
--- a/clang/test/CIR/CodeGen/switch.cpp
+++ b/clang/test/CIR/CodeGen/switch.cpp
@@ -16,6 +16,7 @@ void sw1(int a) {
}
}
}
+
// CIR: cir.func @_Z3sw1i
// CIR: cir.switch (%3 : !s32i) {
// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
@@ -91,12 +92,40 @@ 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: %1 = cir.load %0 : !cir.ptr<!s32i>, !s32i
+// CIR-NEXT: cir.switch (%1 : !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;
}
@@ -112,24 +141,31 @@ int sw4(int a) {
// CIR-NEXT: }
// CIR-NEXT: cir.yield
// CIR-NEXT: }
+// CIR-NEXT: cir.case(default, []) {
+// CIR-NEXT: %5 = cir.const #cir.int<2> : !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: }
+// 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:;
@@ -156,13 +192,97 @@ 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 (%1 : !s32i) {
+// CIR-NEXT: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
+// CIR-NEXT: cir.break
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i, #cir.int<4> : !s32i, #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: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
+// CIR-NEXT: cir.yield
+// CIR-NEXT: }
+// CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i]) {
+// CIR-NEXT: cir.break
+// CIR-NEXT: }
+
+
+// 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;
}
}
@@ -172,6 +292,9 @@ void sw8(int a) {
// 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,24 +303,25 @@ 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;
}
@@ -207,6 +331,9 @@ void sw9(int a) {
// CIR: 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 +342,115 @@ 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.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.case(equal, [#cir.int<3> : !s32i]) {
+//CIR-NEXT: cir.break
+//CIR-NEXT: }
+//CIR-NEXT: cir.case(anyof, [#cir.int<4> : !s32i, #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(anyof, [#cir.int<6> : !s32i, #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)
{
>From ee0b0aad5b11bcd34c13a17fdcd828ead499b345 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Wed, 30 Apr 2025 12:49:09 -0500
Subject: [PATCH 2/8] Remove foldcase from missing features
---
clang/include/clang/CIR/MissingFeatures.h | 1 -
clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 1 -
2 files changed, 2 deletions(-)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 4d4951aa0e126..8f58e10d9070e 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -161,7 +161,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; }
// Missing types
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index e9e163d5090d8..56e9ba04c8ce0 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -565,7 +565,6 @@ mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
bool buildingTopLevelCase) {
cir::CaseOpKind kind;
mlir::ArrayAttr value;
- assert(!cir::MissingFeatures::foldCaseStmt());
const CaseStmt *caseStmt = foldCaseStmt(s, condType, value, kind);
return emitCaseDefaultCascade(caseStmt, condType, value, kind,
buildingTopLevelCase);
>From 3142924881f46b36799c753940aea2a7e9f1b384 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Wed, 30 Apr 2025 13:16:02 -0500
Subject: [PATCH 3/8] Fix code formatting
---
clang/lib/CIR/CodeGen/CIRGenFunction.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index fb1a7dc75161d..9a1abe380cb3f 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -535,7 +535,6 @@ 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);
>From b032de77d12a987c9292037a4c9eaa526fca0a47 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Wed, 30 Apr 2025 13:22:34 -0500
Subject: [PATCH 4/8] Fix code formatting
---
clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 56e9ba04c8ce0..13b9cdf400702 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -429,7 +429,6 @@ mlir::LogicalResult CIRGenFunction::emitBreakStmt(const clang::BreakStmt &s) {
return mlir::success();
}
-
const CaseStmt *CIRGenFunction::foldCaseStmt(const clang::CaseStmt &s,
mlir::Type condType,
mlir::ArrayAttr &value,
@@ -570,10 +569,9 @@ mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
buildingTopLevelCase);
}
-
- mlir::LogicalResult CIRGenFunction::emitDefaultStmt(const clang::DefaultStmt &s,
- mlir::Type condType,
- bool buildingTopLevelCase) {
+mlir::LogicalResult CIRGenFunction::emitDefaultStmt(const clang::DefaultStmt &s,
+ mlir::Type condType,
+ bool buildingTopLevelCase) {
return emitCaseDefaultCascade(&s, condType, builder.getArrayAttr({}),
cir::CaseOpKind::Default, buildingTopLevelCase);
}
>From 39861ddfa7cf5b8156c4197cc6cd7a1a2d880363 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Sat, 3 May 2025 13:42:57 -0500
Subject: [PATCH 5/8] Remove early optimization for cascading cases and update
test cases accordingly
---
clang/include/clang/CIR/MissingFeatures.h | 3 +
clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 77 ++++-------
clang/test/CIR/CodeGen/switch.cpp | 160 ++++++++++++++++++++--
3 files changed, 180 insertions(+), 60 deletions(-)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 8f58e10d9070e..98e2830c025ff 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -97,6 +97,9 @@ struct MissingFeatures {
// Unary operator handling
static bool opUnaryPromotionType() { return false; }
+ // SwitchOp handling
+ static bool foldRangeCase() { return false; }
+
// Clang early optimizations or things defered to LLVM lowering.
static bool mayHaveIntegerOverflow() { return false; }
static bool shouldReverseUnaryCondOnBoolExpr() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 13b9cdf400702..861bdbec21ea1 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -429,52 +429,6 @@ mlir::LogicalResult CIRGenFunction::emitBreakStmt(const clang::BreakStmt &s) {
return mlir::success();
}
-const CaseStmt *CIRGenFunction::foldCaseStmt(const clang::CaseStmt &s,
- mlir::Type condType,
- mlir::ArrayAttr &value,
- cir::CaseOpKind &kind) {
- const CaseStmt *caseStmt = &s;
- const CaseStmt *lastCase = &s;
- SmallVector<mlir::Attribute, 4> caseEltValueListAttr;
-
- // Fold cascading cases whenever possible to simplify codegen a bit.
- while (caseStmt) {
- lastCase = caseStmt;
-
- auto intVal = caseStmt->getLHS()->EvaluateKnownConstInt(getContext());
-
- if (auto *rhs = caseStmt->getRHS()) {
- auto endVal = rhs->EvaluateKnownConstInt(getContext());
- SmallVector<mlir::Attribute, 4> rangeCaseAttr = {
- cir::IntAttr::get(condType, intVal),
- cir::IntAttr::get(condType, endVal)};
- value = builder.getArrayAttr(rangeCaseAttr);
- kind = cir::CaseOpKind::Range;
-
- // We may not be able to fold rangaes. Due to we can't present range case
- // with other trivial cases now.
- return caseStmt;
- }
-
- caseEltValueListAttr.push_back(cir::IntAttr::get(condType, intVal));
-
- caseStmt = dyn_cast_or_null<CaseStmt>(caseStmt->getSubStmt());
-
- // Break early if we found ranges. We can't fold ranges due to the same
- // reason above.
- if (caseStmt && caseStmt->getRHS())
- break;
- }
-
- if (!caseEltValueListAttr.empty()) {
- value = builder.getArrayAttr(caseEltValueListAttr);
- kind = caseEltValueListAttr.size() > 1 ? cir::CaseOpKind::Anyof
- : cir::CaseOpKind::Equal;
- }
-
- return lastCase;
-}
-
template <typename T>
mlir::LogicalResult
CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType,
@@ -502,7 +456,8 @@ 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>(stmt)) ||
+ (isa<CaseStmt>(sub) && isa<CaseStmt>(stmt))) {
subStmtKind = SubStmtKind::Case;
builder.createYield(loc);
} else {
@@ -564,8 +519,32 @@ mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
bool buildingTopLevelCase) {
cir::CaseOpKind kind;
mlir::ArrayAttr value;
- const CaseStmt *caseStmt = foldCaseStmt(s, condType, value, kind);
- return emitCaseDefaultCascade(caseStmt, condType, value, kind,
+
+ SmallVector<mlir::Attribute, 1> caseEltValueListAttr;
+ llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());
+
+ // 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());
+ SmallVector<mlir::Attribute, 4> rangeCaseAttr = {
+ cir::IntAttr::get(condType, intVal),
+ cir::IntAttr::get(condType, endVal)};
+ value = builder.getArrayAttr(rangeCaseAttr);
+ kind = cir::CaseOpKind::Range;
+
+ // We don't currently fold case range statements with other case statements.
+ // TODO(cir): Add this capability.
+ assert(!cir::MissingFeatures::foldRangeCase());
+ } else {
+ caseEltValueListAttr.push_back(cir::IntAttr::get(condType, intVal));
+ value = builder.getArrayAttr(caseEltValueListAttr);
+ kind = cir::CaseOpKind::Equal;
+ }
+
+ return emitCaseDefaultCascade(&s, condType, value, kind,
buildingTopLevelCase);
}
diff --git a/clang/test/CIR/CodeGen/switch.cpp b/clang/test/CIR/CodeGen/switch.cpp
index ea0e95e7eb553..c4f14cdba7db8 100644
--- a/clang/test/CIR/CodeGen/switch.cpp
+++ b/clang/test/CIR/CodeGen/switch.cpp
@@ -207,12 +207,25 @@ void sw6(int a) {
// CIR: cir.func @_Z3sw6i
// CIR: cir.switch (%1 : !s32i) {
-// CIR-NEXT: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
-// CIR-NEXT: cir.break
+// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
+// CIR-NEXT: cir.yield
// CIR-NEXT: }
-// CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i]) {
-// CIR-NEXT: cir.break
+// 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:
@@ -248,13 +261,24 @@ void sw7(int a) {
}
// CIR: cir.func @_Z3sw7i
-// CIR: cir.case(anyof, [#cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<2> : !s32i]) {
-// CIR-NEXT: cir.yield
+// CIR: cir.case(equal, [#cir.int<0> : !s32i]) {
+// CIR-NEXT: cir.yield
// CIR-NEXT: }
-// CIR-NEXT: cir.case(anyof, [#cir.int<3> : !s32i, #cir.int<4> : !s32i, #cir.int<5> : !s32i]) {
-// CIR-NEXT: cir.break
+// 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: }
-
// OGCG: define dso_local void @_Z3sw7i
// OGCG: entry:
@@ -419,13 +443,19 @@ void sw11(int a) {
//CIR: cir.case(equal, [#cir.int<3> : !s32i]) {
//CIR-NEXT: cir.break
//CIR-NEXT: }
-//CIR-NEXT: cir.case(anyof, [#cir.int<4> : !s32i, #cir.int<5> : !s32i]) {
+//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(anyof, [#cir.int<6> : !s32i, #cir.int<7> : !s32i]) {
+//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: }
@@ -527,6 +557,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:
>From c7727363b5ccff99c8c59f73647dd31acd369ff2 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Mon, 5 May 2025 12:51:44 -0500
Subject: [PATCH 6/8] Add foldCascadingCases to MissingFeatures and update case
handling
---
clang/include/clang/CIR/MissingFeatures.h | 1 +
clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 7 ++++---
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index 98e2830c025ff..f20f859598645 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -98,6 +98,7 @@ struct MissingFeatures {
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.
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 861bdbec21ea1..67f7cd936311c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -456,8 +456,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)) ||
- (isa<CaseStmt>(sub) && isa<CaseStmt>(stmt))) {
+ } else if (isa<CaseStmt>(sub) && isa<DefaultStmt, CaseStmt>(stmt)) {
subStmtKind = SubStmtKind::Case;
builder.createYield(loc);
} else {
@@ -536,8 +535,10 @@ mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
kind = cir::CaseOpKind::Range;
// We don't currently fold case range statements with other case statements.
- // TODO(cir): Add this capability.
+ // 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 {
caseEltValueListAttr.push_back(cir::IntAttr::get(condType, intVal));
value = builder.getArrayAttr(caseEltValueListAttr);
>From 906e6974ddf2848ad4356a2d3750a8a62fb82943 Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Mon, 5 May 2025 13:17:31 -0500
Subject: [PATCH 7/8] remove foldCaseStmt
---
clang/lib/CIR/CodeGen/CIRGenFunction.h | 3 ---
1 file changed, 3 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 9a1abe380cb3f..33741e627c91d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -278,9 +278,6 @@ class CIRGenFunction : public CIRGenTypeCache {
/// addressed later.
RValue getUndefRValue(clang::QualType ty);
- const CaseStmt *foldCaseStmt(const clang::CaseStmt &s, mlir::Type condType,
- mlir::ArrayAttr &value, cir::CaseOpKind &kind);
-
cir::FuncOp generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
cir::FuncType funcType);
>From f470023b708ade40709e857b67f64eb6773b995c Mon Sep 17 00:00:00 2001
From: Andres Salamanca <andrealebarbaritos at gmail.com>
Date: Mon, 5 May 2025 15:33:22 -0500
Subject: [PATCH 8/8] Updated test with pattern matching and removed
caseEltValueListAttr variable
---
clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 12 +--
clang/test/CIR/CodeGen/switch.cpp | 122 ++++++++++++++-------------
2 files changed, 68 insertions(+), 66 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
index 67f7cd936311c..e7c6ff343a923 100644
--- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp
@@ -518,20 +518,15 @@ mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
bool buildingTopLevelCase) {
cir::CaseOpKind kind;
mlir::ArrayAttr value;
-
- SmallVector<mlir::Attribute, 1> caseEltValueListAttr;
llvm::APSInt intVal = s.getLHS()->EvaluateKnownConstInt(getContext());
// 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());
- SmallVector<mlir::Attribute, 4> rangeCaseAttr = {
- cir::IntAttr::get(condType, intVal),
- cir::IntAttr::get(condType, endVal)};
- value = builder.getArrayAttr(rangeCaseAttr);
+ 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.
@@ -540,8 +535,7 @@ mlir::LogicalResult CIRGenFunction::emitCaseStmt(const CaseStmt &s,
assert(!cir::MissingFeatures::foldRangeCase());
assert(!cir::MissingFeatures::foldCascadingCases());
} else {
- caseEltValueListAttr.push_back(cir::IntAttr::get(condType, intVal));
- value = builder.getArrayAttr(caseEltValueListAttr);
+ value = builder.getArrayAttr({cir::IntAttr::get(condType, intVal)});
kind = cir::CaseOpKind::Equal;
}
diff --git a/clang/test/CIR/CodeGen/switch.cpp b/clang/test/CIR/CodeGen/switch.cpp
index c4f14cdba7db8..0bd4e0759e634 100644
--- a/clang/test/CIR/CodeGen/switch.cpp
+++ b/clang/test/CIR/CodeGen/switch.cpp
@@ -18,7 +18,7 @@ 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]) {
@@ -67,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:
@@ -101,8 +101,8 @@ void sw3(int a) {
// CIR: cir.func @_Z3sw3i
// CIR: cir.scope {
-// CIR-NEXT: %1 = cir.load %0 : !cir.ptr<!s32i>, !s32i
-// CIR-NEXT: cir.switch (%1 : !s32i) {
+// 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: }
@@ -131,24 +131,24 @@ int sw4(int a) {
}
// 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: %5 = cir.const #cir.int<2> : !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: %[[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: }
+// CIR-NEXT: }
// OGCG: define dso_local noundef i32 @_Z3sw4i
// OGCG: entry:
@@ -173,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: }
@@ -206,7 +206,7 @@ void sw6(int a) {
}
// CIR: cir.func @_Z3sw6i
-// CIR: cir.switch (%1 : !s32i) {
+// CIR: cir.switch (%[[A:.*]] : !s32i) {
// CIR-NEXT: cir.case(equal, [#cir.int<0> : !s32i]) {
// CIR-NEXT: cir.yield
// CIR-NEXT: }
@@ -261,7 +261,9 @@ void sw7(int a) {
}
// CIR: cir.func @_Z3sw7i
-// CIR: cir.case(equal, [#cir.int<0> : !s32i]) {
+// 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]) {
@@ -279,6 +281,8 @@ void sw7(int a) {
// 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:
@@ -312,7 +316,8 @@ void sw8(int a) {
}
// 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]) {
@@ -352,7 +357,8 @@ void sw9(int a) {
}
// 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, []) {
@@ -391,19 +397,20 @@ void sw10(int a) {
}
}
-//CIR: cir.func @_Z4sw10i
-//CIR: 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: }
+// 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:
@@ -439,25 +446,26 @@ void sw11(int a) {
}
}
-//CIR: cir.func @_Z4sw11i
-//CIR: 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: }
+// 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:
@@ -533,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
@@ -688,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