https://github.com/andykaylor created https://github.com/llvm/llvm-project/pull/186284
This implements AggExprEmitter::VisitAbstractConditionalOperator for CIR. >From f0a39a19c24eff7622a2be1e61ea99128ce2b972 Mon Sep 17 00:00:00 2001 From: Andy Kaylor <[email protected]> Date: Thu, 12 Mar 2026 16:07:02 -0700 Subject: [PATCH] [CIR] Implement abstract conditional operator handling for aggregate types This implements AggExprEmitter::VisitAbstractConditionalOperator for CIR. --- clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 56 ++++++++++++++++++- clang/test/CIR/CodeGen/abstract-cond.c | 53 ++++++++++++++++++ 2 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 clang/test/CIR/CodeGen/abstract-cond.c diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp index 9f390fec97613..ea5a2422f4717 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp @@ -348,8 +348,60 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> { VisitInitListExpr(e->getUpdater()); } void VisitAbstractConditionalOperator(const AbstractConditionalOperator *e) { - cgf.cgm.errorNYI(e->getSourceRange(), - "AggExprEmitter: VisitAbstractConditionalOperator"); + mlir::Location loc = cgf.getLoc(e->getSourceRange()); + + CIRGenFunction::OpaqueValueMapping binding(cgf, e); + CIRGenFunction::ConditionalEvaluation eval(cgf); + + // Save whether the destination's lifetime is externally managed. + bool isExternallyDestructed = dest.isExternallyDestructed(); + bool destructNonTrivialCStruct = + !isExternallyDestructed && + e->getType().isDestructedType() == QualType::DK_nontrivial_c_struct; + isExternallyDestructed |= destructNonTrivialCStruct; + + cgf.emitIfOnBoolExpr( + e->getCond(), + /*thenBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + eval.beginEvaluation(); + { + CIRGenFunction::LexicalScope lexScope{cgf, loc, + b.getInsertionBlock()}; + cgf.curLexScope->setAsTernary(); + dest.setExternallyDestructed(isExternallyDestructed); + assert(!cir::MissingFeatures::incrementProfileCounter()); + Visit(e->getTrueExpr()); + cir::YieldOp::create(b, loc); + } + eval.endEvaluation(); + }, + loc, + /*elseBuilder=*/ + [&](mlir::OpBuilder &b, mlir::Location loc) { + eval.beginEvaluation(); + { + CIRGenFunction::LexicalScope lexScope{cgf, loc, + b.getInsertionBlock()}; + cgf.curLexScope->setAsTernary(); + + // If the result of an agg expression is unused, then the emission + // of the LHS might need to create a destination slot. That's fine + // with us, and we can safely emit the RHS into the same slot, but + // we shouldn't claim that it's already being destructed. + dest.setExternallyDestructed(isExternallyDestructed); + assert(!cir::MissingFeatures::incrementProfileCounter()); + Visit(e->getFalseExpr()); + cir::YieldOp::create(b, loc); + } + eval.endEvaluation(); + }, + loc); + + if (destructNonTrivialCStruct) + cgf.cgm.errorNYI( + e->getSourceRange(), + "Abstract conditional aggregate: destructNonTrivialCStruct"); } void VisitChooseExpr(const ChooseExpr *e) { Visit(e->getChosenSubExpr()); } void VisitCXXParenListInitExpr(CXXParenListInitExpr *e) { diff --git a/clang/test/CIR/CodeGen/abstract-cond.c b/clang/test/CIR/CodeGen/abstract-cond.c new file mode 100644 index 0000000000000..c3f4c10f25fd9 --- /dev/null +++ b/clang/test/CIR/CodeGen/abstract-cond.c @@ -0,0 +1,53 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +// ?: in "lvalue" +struct s6 { int f0; }; +int f6(int a0, struct s6 a1, struct s6 a2) { + return (a0 ? a1 : a2).f0; +} + +// CIR: cir.func {{.*}} @f6 +// CIR: %[[A0:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["a0" +// CIR: %[[A1:.*]] = cir.alloca !rec_s6, !cir.ptr<!rec_s6>, ["a1" +// CIR: %[[A2:.*]] = cir.alloca !rec_s6, !cir.ptr<!rec_s6>, ["a2" +// CIR: cir.scope { +// CIR: %[[TMP:.*]] = cir.alloca !rec_s6, !cir.ptr<!rec_s6>, ["ref.tmp0"] +// CIR: %[[LOAD_A0:.*]] = cir.load{{.*}} %[[A0]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[COND:.*]] = cir.cast int_to_bool %[[LOAD_A0]] : !s32i -> !cir.bool +// CIR: cir.if %[[COND]] { +// CIR: cir.copy %[[A1]] to %[[TMP]] : !cir.ptr<!rec_s6> +// CIR: } else { +// CIR: cir.copy %[[A2]] to %[[TMP]] : !cir.ptr<!rec_s6> +// CIR: } +// CIR: cir.get_member %[[TMP]][0] {name = "f0"} : !cir.ptr<!rec_s6> -> !cir.ptr<!s32i> + +// LLVM: define {{.*}} i32 @f6 +// LLVM: %[[LOAD_A0:.*]] = load i32, ptr {{.*}} +// LLVM: %[[COND:.*]] = icmp ne i32 %[[LOAD_A0]], 0 +// LLVM: br i1 %[[COND]], label %[[A1_PATH:.*]], label %[[A2_PATH:.*]] +// LLVM: [[A1_PATH]]: +// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[TMP:.*]], ptr {{.*}}, i64 4, i1 false) +// LLVM: br label %[[EXIT:.*]] +// LLVM: [[A2_PATH]]: +// LLVM: call void @llvm.memcpy.p0.p0.i64(ptr %[[TMP]], ptr {{.*}}, i64 4, i1 false) +// LLVM: br label %[[EXIT]] +// LLVM: [[EXIT]]: +// LLVM: getelementptr {{.*}}, ptr %[[TMP]], i32 0, i32 0 + +// OGCG: define {{.*}} i32 @f6 +// OGCG: %[[LOAD_A0:.*]] = load i32, ptr {{.*}} +// OGCG: %[[COND:.*]] = icmp ne i32 %[[LOAD_A0]], 0 +// OGCG: br i1 %[[COND]], label %[[A1_PATH:.*]], label %[[A2_PATH:.*]] +// OGCG: [[A1_PATH]]: +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}} %[[TMP:.*]], ptr {{.*}}, i64 4, i1 false) +// OGCG: br label %[[EXIT:.*]] +// OGCG: [[A2_PATH]]: +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}} %[[TMP]], ptr {{.*}}, i64 4, i1 false) +// OGCG: br label %[[EXIT]] +// OGCG: [[EXIT]]: +// OGCG: getelementptr {{.*}}, ptr %[[TMP]], i32 0, i32 0 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
