https://github.com/erichkeane created 
https://github.com/llvm/llvm-project/pull/190631

An aggregate initialized by a ConstantExpr happens when you have a consteval 
constructor. This patch implements this lowering.

There is a bit of a difference in decisions between classic-codegen and cir 
lowering, where classic-codegen will do init-via-GEP, whereas CIR does either a 
struct-store, or a memcpy, otherwise these seem identical.

There IS a branch (if emitting a constant-expr fails) that appears dead to the 
best of my knowledge, but since classic-codegen does it, I left the version 
there. It is at most a pessimisation of the constant-emit (just emitting the 
expression), so it shouldn't cause problems.

>From d48f8ad7eeee38802a943532991e7d528bc8747e Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Mon, 6 Apr 2026 09:41:50 -0700
Subject: [PATCH] [CIR] Implement aggregate-expr-init with a const-expr
 lowering

An aggregate initialized by a ConstantExpr happens when you have a
consteval constructor. This patch implements this lowering.

There is a bit of a difference in decisions between classic-codegen and
cir lowering, where classic-codegen will do init-via-GEP, whereas CIR
does either a struct-store, or a memcpy, otherwise these seem identical.

There IS a branch (if emitting a constant-expr fails) that appears dead
to the best of my knowledge, but since classic-codegen does it, I left
the version there. It is at most a pessimisation of the constant-emit
(just emitting the expression), so it shouldn't cause problems.
---
 clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp | 15 ++++++-
 clang/test/CIR/CodeGen/agg-init-constexpr.cpp | 39 +++++++++++++++++++
 2 files changed, 53 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CIR/CodeGen/agg-init-constexpr.cpp

diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
index 8e63a64b3e664..169a26ca3d375 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
@@ -11,6 +11,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "CIRGenBuilder.h"
+#include "CIRGenConstantEmitter.h"
 #include "CIRGenFunction.h"
 #include "CIRGenValue.h"
 #include "mlir/IR/Builders.h"
@@ -303,7 +304,19 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
                      "AggExprEmitter: VisitSubstNonTypeTemplateParmExpr");
   }
   void VisitConstantExpr(ConstantExpr *e) {
-    cgf.cgm.errorNYI(e->getSourceRange(), "AggExprEmitter: VisitConstantExpr");
+    ensureDest(cgf.getLoc(e->getSourceRange()), e->getType());
+
+    if (mlir::Attribute result = ConstantEmitter(cgf).tryEmitConstantExpr(e)) {
+      mlir::Value resultVal = cgf.getBuilder().getConstant(
+          cgf.getLoc(e->getSourceRange()), 
mlir::cast<mlir::TypedAttr>(result));
+      LValue destLVal = cgf.makeAddrLValue(dest.getAddress(), e->getType());
+      cgf.emitStoreThroughLValue(RValue::get(resultVal), destLVal);
+      return;
+    }
+
+    // It isn't clear that it is possible to get to here,  but this branch is
+    // present in classic codegen, so we leave it here too.
+    return Visit(e->getSubExpr());
   }
   void VisitMemberExpr(MemberExpr *e) { emitAggLoadOfLValue(e); }
   void VisitUnaryDeref(UnaryOperator *e) { emitAggLoadOfLValue(e); }
diff --git a/clang/test/CIR/CodeGen/agg-init-constexpr.cpp 
b/clang/test/CIR/CodeGen/agg-init-constexpr.cpp
new file mode 100644
index 0000000000000..8cef9ef33bda5
--- /dev/null
+++ b/clang/test/CIR/CodeGen/agg-init-constexpr.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -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 -std=c++20 -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 -std=c++20 -emit-llvm %s 
-o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+struct HasVal {
+  int x = 5;
+};
+struct WithCtor {
+  consteval WithCtor(int a, long b) : x(a*a), y(a*b) {}
+  int x;
+  long y;
+  HasVal a;
+};
+
+extern "C" void construct() {
+  WithCtor c(2,5);
+}
+
+// CIR-LABEL: construct()
+// CIR-NEXT: %[[WC_ALLOCA:.*]] = cir.alloca !rec_WithCtor
+// CIR-NEXT: %[[CONST_VAL:.*]] = cir.const #cir.const_record<{#cir.int<4> : 
!s32i, #cir.int<10> : !s64i, #cir.const_record<{#cir.int<5> : !s32i}> : 
!rec_HasVal}>
+// CIR-NEXT: %[[BITCAST:.*]] = cir.cast bitcast %[[WC_ALLOCA]]
+// CIR-NEXT: cir.store{{.*}}%[[CONST_VAL]], %[[BITCAST]]
+
+// LLVM-LABEL: construct()
+// LLVM-NEXT: %[[WC_ALLOCA:.*]] = alloca %struct.WithCtor
+// LLVM-NEXT: store { i32, i64, %struct.HasVal } { i32 4, i64 10, 
%struct.HasVal { i32 5 } }, ptr %[[WC_ALLOCA]]
+
+// OGCG-LABEL: construct()
+// OGCG: %[[WC_ALLOCA:.*]] = alloca %struct.WithCtor
+// OGCG-NEXT: %[[X_GEP:.*]] = getelementptr{{.*}} { i32, i64, %struct.HasVal 
}, ptr %[[WC_ALLOCA]], i32 0, i32 0
+// OGCG-NEXT: store i32 4, ptr %[[X_GEP]]
+// OGCG-NEXT: %[[Y_GEP:.*]] = getelementptr{{.*}} { i32, i64, %struct.HasVal 
}, ptr %[[WC_ALLOCA]], i32 0, i32 1
+// OGCG-NEXT: store i64 10, ptr %[[Y_GEP]]
+// OGCG-NEXT: %[[A_GEP:.*]] = getelementptr{{.*}} { i32, i64, %struct.HasVal 
}, ptr %[[WC_ALLOCA]], i32 0, i32 2
+// OGCG-NEXT: store %struct.HasVal { i32 5 }, ptr %[[A_GEP]]

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to