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

Reply via email to