[clang] [CIR] Upstream lowering of conditional operators to TernaryOp (PR #138156)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Thu May 1 16:34:30 PDT 2025
================
@@ -875,6 +877,174 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
// NOTE: We don't need to EnsureInsertPoint() like LLVM codegen.
return Visit(e->getRHS());
}
+
+ mlir::Value VisitBinLAnd(const clang::BinaryOperator *e) {
+ if (e->getType()->isVectorType()) {
+ assert(!cir::MissingFeatures::vectorType());
+ return {};
+ }
+
+ bool instrumentRegions = cgf.cgm.getCodeGenOpts().hasProfileClangInstr();
+ mlir::Type resTy = cgf.convertType(e->getType());
+ mlir::Location loc = cgf.getLoc(e->getExprLoc());
+
+ // If we have 0 && RHS, see if we can elide RHS, if so, just return 0.
+ // If we have 1 && X, just emit X without inserting the control flow.
+ bool lhsCondVal;
+ if (cgf.constantFoldsToSimpleInteger(e->getLHS(), lhsCondVal)) {
+ if (lhsCondVal) { // If we have 1 && X, just emit X.
+
+ mlir::Value rhsCond = cgf.evaluateExprAsBool(e->getRHS());
+
+ if (instrumentRegions) {
+ assert(!cir::MissingFeatures::instrumenation());
+ cgf.cgm.errorNYI(e->getExprLoc(), "instrumenation");
+ }
+ // ZExt result to int or bool.
+ return builder.createZExtOrBitCast(rhsCond.getLoc(), rhsCond, resTy);
+ }
+ // 0 && RHS: If it is safe, just elide the RHS, and return 0/false.
+ if (!cgf.containsLabel(e->getRHS()))
+ return builder.getNullValue(resTy, loc);
+ }
+
+ CIRGenFunction::ConditionalEvaluation eval(cgf);
+
+ mlir::Value lhsCondV = cgf.evaluateExprAsBool(e->getLHS());
+ auto resOp = builder.create<cir::TernaryOp>(
+ loc, lhsCondV, /*trueBuilder=*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ CIRGenFunction::LexicalScope lexScope{cgf, loc,
+ b.getInsertionBlock()};
+ cgf.curLexScope->setAsTernary();
+ mlir::Value rhsCondV = cgf.evaluateExprAsBool(e->getRHS());
+ auto res = b.create<cir::TernaryOp>(
+ loc, rhsCondV, /*trueBuilder*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ CIRGenFunction::LexicalScope lexScope{cgf, loc,
+ b.getInsertionBlock()};
+ cgf.curLexScope->setAsTernary();
+ auto res =
+ b.create<cir::ConstantOp>(loc, builder.getTrueAttr());
+ b.create<cir::YieldOp>(loc, res.getRes());
+ },
+ /*falseBuilder*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ CIRGenFunction::LexicalScope lexScope{cgf, loc,
+ b.getInsertionBlock()};
+ cgf.curLexScope->setAsTernary();
+ auto res =
+ b.create<cir::ConstantOp>(loc, builder.getFalseAttr());
+ b.create<cir::YieldOp>(loc, res.getRes());
+ });
+ b.create<cir::YieldOp>(loc, res.getResult());
+ },
+ /*falseBuilder*/
+ [&](mlir::OpBuilder &b, mlir::Location loc) {
+ CIRGenFunction::LexicalScope lexScope{cgf, loc,
+ b.getInsertionBlock()};
+ cgf.curLexScope->setAsTernary();
+ auto res = b.create<cir::ConstantOp>(loc, builder.getFalseAttr());
+ b.create<cir::YieldOp>(loc, res.getRes());
+ });
+ return builder.createZExtOrBitCast(resOp.getLoc(), resOp.getResult(),
----------------
andykaylor wrote:
VisitUnaryLNot does this:
```
// ZExt result to the expr type.
mlir::Type dstTy = cgf.convertType(e->getType());
if (mlir::isa<cir::IntType>(dstTy))
return builder.createBoolToInt(boolVal, dstTy);
if (mlir::isa<cir::BoolType>(dstTy))
return boolVal;
cgf.cgm.errorNYI("destination type for logical-not unary operator is NYI");
```
A helper function seems reasonable, but I'd prefer to see it be named something like `maybePromoteBoolResult`.
https://github.com/llvm/llvm-project/pull/138156
More information about the cfe-commits
mailing list