https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/192298
>From 91f3f54d515d53c6e2bce745b1596f7544bd66d2 Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Wed, 15 Apr 2026 07:01:15 -0700 Subject: [PATCH 1/2] [CIR] Implement LValue InitListExpr and FunctionalCastExpr lowering First, this fixes the InitListExpr lowering. This copies the same implementation from classic-codegen, and adds some tests (this is otherwise untested in classic codegen?). Second, while I was writing tests for the above, I accidented into the FunctionalCastExpr, which just calls emitCastLValue, so this fixes that as well. --- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 16 ++++- clang/lib/CIR/CodeGen/CIRGenFunction.h | 1 + clang/test/CIR/CodeGen/init-list-lvalue.cpp | 74 +++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 clang/test/CIR/CodeGen/init-list-lvalue.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index fcfbeb809371e..0dfa6104d97ef 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1010,6 +1010,17 @@ clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd, return retTy; } +LValue CIRGenFunction::emitInitListLValue(const InitListExpr *e) { + // Initializing an aggregate temporary in C++11: T{...}. + if (!e->isGLValue()) { + return emitAggExprToLValue(e); + } + + // An lvalue initializer list must be initializing a reference. + assert(e->isTransparent() && "non-transparent glvalue init list"); + return emitLValue(e->getInit(0)); +} + /// Emit code to compute a designator that specifies the location /// of the expression. /// FIXME: document this function better. @@ -1084,7 +1095,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { case Expr::CXXDynamicCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: - // TODO(cir): The above list is missing CXXFunctionalCastExprClass, + case Expr::CXXFunctionalCastExprClass: + // TODO(cir): The above list is missing // CXXAddrSpaceCastExprClass, and ObjCBridgedCastExprClass. return emitCastLValue(cast<CastExpr>(e)); case Expr::MaterializeTemporaryExprClass: @@ -1095,6 +1107,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) { return emitLValue(cast<ChooseExpr>(e)->getChosenSubExpr()); case Expr::SubstNonTypeTemplateParmExprClass: return emitLValue(cast<SubstNonTypeTemplateParmExpr>(e)->getReplacement()); + case Expr::InitListExprClass: + return emitInitListLValue(cast<InitListExpr>(e)); } } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 4f0f33a933e01..dbe67efa41d1c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1447,6 +1447,7 @@ class CIRGenFunction : public CIRGenTypeCache { mlir::Value emitArrayLength(const clang::ArrayType *arrayType, QualType &baseType, Address &addr); LValue emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e); + LValue emitInitListLValue(const InitListExpr *e); LValue emitExtVectorElementExpr(const ExtVectorElementExpr *e); diff --git a/clang/test/CIR/CodeGen/init-list-lvalue.cpp b/clang/test/CIR/CodeGen/init-list-lvalue.cpp new file mode 100644 index 0000000000000..fd4df4558318b --- /dev/null +++ b/clang/test/CIR/CodeGen/init-list-lvalue.cpp @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=LLVM + +struct Struct { + int i; + const char *c; +}; + +void test1(int i) { + // CIR: cir.func {{.*}}@_Z5test1i(%[[I_ARG:.*]]: {{.*}}) + // LLVM: define {{.*}}void @_Z5test1i(i32 {{.*}}%[[I_ARG:.*]]) + int &refI = {i}; + // CIR: %[[I_ALLOCA:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["i", init] + // CIR: %[[REFI_ALLOCA:.*]] = cir.alloca !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>>, ["refI", init, const] + // CIR: cir.store %[[I_ARG]], %[[I_ALLOCA]] : !s32i, !cir.ptr<!s32i> + // CIR: cir.store {{.*}}%[[I_ALLOCA]], %[[REFI_ALLOCA]] : !cir.ptr<!s32i>, !cir.ptr<!cir.ptr<!s32i>> + // LLVM: %[[I_ALLOCA:.*]] = alloca i32 + // LLVM: %[[REFI_ALLOCA:.*]] = alloca ptr + // LLVM: store i32 %[[I_ARG]], ptr %[[I_ALLOCA]] + // LLVM: store ptr %[[I_ALLOCA]], ptr %[[REFI_ALLOCA]] +} + +void test2() { + // CIR-LABEL: cir.func {{.*}}@_Z5test2v() + // LLVM-LABEL: define {{.*}}void @_Z5test2v() + Struct s {1, "asdf"}; + Struct &refS = {s}; + // CIR: %[[S_ALLOCA:.*]] = cir.alloca !rec_Struct, !cir.ptr<!rec_Struct>, ["s", init] + // CIR: %[[REFS_ALLOCA:.*]] = cir.alloca !cir.ptr<!rec_Struct>, !cir.ptr<!cir.ptr<!rec_Struct>>, ["refS", init, const] + // CIR: %[[GET_S_INIT:.*]] = cir.get_global @__const._Z5test2v.s : !cir.ptr<!rec_Struct> + // CIR: cir.copy %[[GET_S_INIT]] to %[[S_ALLOCA]] : !cir.ptr<!rec_Struct> loc(#loc33) + // CIR: cir.store {{.*}}%[[S_ALLOCA]], %[[REFS_ALLOCA]] : !cir.ptr<!rec_Struct>, !cir.ptr<!cir.ptr<!rec_Struct>> + // LLVM: %[[S_ALLOCA:.*]] = alloca %struct.Struct + // LLVM: %[[REFS_ALLOCA:.*]] = alloca ptr + // LLVM: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}}%[[S_ALLOCA]], ptr {{.*}}@__const._Z5test2v.s, i64 16, i1 false) + // LLVM: store ptr %[[S_ALLOCA]], ptr %[[REFS_ALLOCA]] +} + +// Note: In addition to testing init-list-lvalue, this also tests +// FunctionalCastExpr. +void test3(Struct &s) { + // CIR: cir.func {{.*}}@_Z5test3R6Struct(%[[S_ARG:.*]]: !cir.ptr<!rec_Struct> {{.*}}) + // LLVM: define dso_local void @_Z5test3R6Struct(ptr{{.*}}%[[S_ARG:.*]]) + using refSTy = Struct &; + Struct &refS = refSTy{s}; + // CIR: %[[S_ALLOCA:.*]] = cir.alloca !cir.ptr<!rec_Struct>, !cir.ptr<!cir.ptr<!rec_Struct>>, ["s", init, const] + // CIR: %[[REFS_ALLOCA:.*]] = cir.alloca !cir.ptr<!rec_Struct>, !cir.ptr<!cir.ptr<!rec_Struct>>, ["refS", init, const] + // CIR: cir.store %[[S_ARG]], %[[S_ALLOCA]] : !cir.ptr<!rec_Struct>, !cir.ptr<!cir.ptr<!rec_Struct>> + // CIR: %[[S_LOAD:.*]] = cir.load %[[S_ALLOCA]] : !cir.ptr<!cir.ptr<!rec_Struct>>, !cir.ptr<!rec_Struct> + // CIR: cir.store {{.*}}%[[S_LOAD]], %[[REFS_ALLOCA]] : !cir.ptr<!rec_Struct>, !cir.ptr<!cir.ptr<!rec_Struct>> + // LLVM: %[[S_ALLOCA:.*]] = alloca ptr + // LLVM: %[[REFS_ALLOCA:.*]] = alloca ptr + // LLVM: store ptr %[[S_ARG]], ptr %[[S_ALLOCA]] + // LLVM: %[[S_LOAD:.*]] = load ptr, ptr %[[S_ALLOCA]] + // LLVM: store ptr %[[S_LOAD]], ptr %[[REFS_ALLOCA]] +} + +void test4() { + // CIR-LABEL: cir.func {{.*}}@_Z5test4v() + // LLVM-LABEL: define {{.*}}void @_Z5test4v() + Struct s; + auto& [sb1, sb2] {s}; + + // CIR: %[[S_ALLOCA:.*]] = cir.alloca !rec_Struct, !cir.ptr<!rec_Struct>, ["s"] {alignment = 8 : i64} + // CIR: %[[SB_ALLOCA:.*]] = cir.alloca !cir.ptr<!rec_Struct>, !cir.ptr<!cir.ptr<!rec_Struct>>, ["", init, const] + // CIR: cir.store {{.*}}%[[S_ALLOCA]], %[[SB_ALLOCA]] : !cir.ptr<!rec_Struct>, !cir.ptr<!cir.ptr<!rec_Struct>> + // LLVM: %[[S_ALLOCA:.*]] = alloca %struct.Struct + // LLVM: %[[SB_ALLOCA:.*]] = alloca ptr + // LLVM: store ptr %[[S_ALLOCA]], ptr %[[SB_ALLOCA]] +} >From bee3c6279bcb4520c2681f4010cd40758e89293c Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Wed, 15 Apr 2026 12:14:01 -0700 Subject: [PATCH 2/2] Remove unnecessary parens --- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 0dfa6104d97ef..47d90581e8a53 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -1012,9 +1012,8 @@ clang::QualType CIRGenFunction::buildFunctionArgList(clang::GlobalDecl gd, LValue CIRGenFunction::emitInitListLValue(const InitListExpr *e) { // Initializing an aggregate temporary in C++11: T{...}. - if (!e->isGLValue()) { + if (!e->isGLValue()) return emitAggExprToLValue(e); - } // An lvalue initializer list must be initializing a reference. assert(e->isTransparent() && "non-transparent glvalue init list"); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
