From ff564e64a2ca9948e51c174a5e7a71b05acea510 Mon Sep 17 00:00:00 2001 From: Andres Salamanca 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(*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 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 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->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 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(sub), condType, buildingTopLevelCase); } else if (subStmtKind == SubStmtKind::Default) { - getCIRGenModule().errorNYI(sub->getSourceRange(), "Default case"); - return mlir::failure(); + result = emitDefaultStmt(*cast(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 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(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(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 +// 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 +// CIR-NEXT: %6 = cir.load %1 : !cir.ptr, !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 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 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 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 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 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 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->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 mlir::LogicalResult CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType, @@ -502,7 +456,8 @@ CIRGenFunction::emitCaseDefaultCascade(const T *stmt, mlir::Type condType, if (isa(sub) && isa(stmt)) { subStmtKind = SubStmtKind::Default; builder.createYield(loc); - } else if (isa(sub) && isa(stmt)) { + } else if ((isa(sub) && isa(stmt)) || + (isa(sub) && isa(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 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 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, ["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 +// 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 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(sub) && isa(stmt)) { subStmtKind = SubStmtKind::Default; builder.createYield(loc); - } else if ((isa(sub) && isa(stmt)) || - (isa(sub) && isa(stmt))) { + } else if (isa(sub) && isa(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 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 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 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 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, ["yolo", init] -// CIR-NEXT: %2 = cir.alloca !s32i, !cir.ptr, ["fomo", init] -// CIR: cir.switch (%4 : !s32i) { +// CIR-NEXT: %[[YOLO:.*]] = cir.alloca !s32i, !cir.ptr, ["yolo", init] +// CIR-NEXT: %[[FOMO:.*]] = cir.alloca !s32i, !cir.ptr, ["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 +// CIR-NEXT: %[[ZERO:.*]] = cir.const #cir.int<0> : !s32i +// CIR-NEXT: cir.store %[[ZERO]], %[[FOMO]] : !s32i, !cir.ptr // 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 -// CIR-NEXT: cir.switch (%1 : !s32i) { +// CIR-NEXT: %[[COND:.*]] = cir.load %[[A:.*]] : !cir.ptr, !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 -// CIR-NEXT: %6 = cir.load %1 : !cir.ptr, !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 +// CIR-NEXT: %[[RET3:.*]] = cir.load %[[RETVAL]] : !cir.ptr, !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 -// CIR-NEXT: %6 = cir.load %1 : !cir.ptr, !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 +// CIR-NEXT: %[[RET2:.*]] = cir.load %[[RETVAL]] : !cir.ptr, !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, ["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: }