[clang] [CIR] Upstream support for switch statements case kinds (PR #138003)
via cfe-commits
cfe-commits at lists.llvm.org
Fri May 2 14:19:05 PDT 2025
================
@@ -428,6 +429,52 @@ 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
----------------
Andres-Salamanca wrote:
If we're no longer folding cascading case statements, then this function could be simplified we wouldn’t need the while loop anymore since we're just extracting the kind and value from a single case. In that scenario, the assertion proposed by @andykaylor would no longer be necessary, because range cases would only ever be processed once at the top level.
```cpp
const CaseStmt *CIRGenFunction::foldCaseStmt(const clang::CaseStmt &s,
mlir::Type condType,
mlir::ArrayAttr &value,
cir::CaseOpKind &kind) {
const CaseStmt *caseStmt = &s;
SmallVector<mlir::Attribute, 1> caseEltValueListAttr;
llvm::APSInt intVal = caseStmt->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 = caseStmt->getRHS()) {
assert(caseStmt == &s && "Range case must be the first case processed");
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());
return caseStmt;
}
caseEltValueListAttr.push_back(cir::IntAttr::get(condType, intVal));
if (!caseEltValueListAttr.empty()) {
value = builder.getArrayAttr(caseEltValueListAttr);
kind = cir::CaseOpKind::Equal;
}
return caseStmt;
}
```
We don’t need the while loop anymore because we must break as soon as we encounter a cascading case or default statement.
```cpp
// Break early if we found a range. We can't fold ranges.
// Also break if we found a cascading case/default.
if (caseStmt) {
const Stmt *sub = caseStmt->getSubStmt();
if (caseStmt->getRHS() || isa<CaseStmt>(sub) || isa<DefaultStmt>(sub))
break;
}
```
Also, given that we're no longer folding multiple cases, I think we should consider renaming the function to better reflect its new behavior. Something like `getCaseInfo` ?
Is my approach correct ?
https://github.com/llvm/llvm-project/pull/138003
More information about the cfe-commits
mailing list