================ @@ -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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits