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
