https://github.com/mmha updated https://github.com/llvm/llvm-project/pull/151073
>From 22b36ac0fb0323f518de18fa4058f0c168c8d476 Mon Sep 17 00:00:00 2001 From: Morris Hafner <mhaf...@nvidia.com> Date: Tue, 29 Jul 2025 04:23:46 +0200 Subject: [PATCH 1/3] [CIR] Upstream support for function-level variable decompositions This implements support for structured bindings on a function scope level. It does not add support for global structured bindings. --- clang/include/clang/CIR/MissingFeatures.h | 1 + clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 8 ++- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 5 ++ clang/lib/CIR/CodeGen/CIRGenModule.cpp | 7 ++- .../CIR/CodeGen/variable-decomposition.cpp | 55 +++++++++++++++++++ 5 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 clang/test/CIR/CodeGen/variable-decomposition.cpp diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index ad3329d3be32e..adc7b5f239ea9 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -217,6 +217,7 @@ struct MissingFeatures { static bool intrinsics() { return false; } static bool isMemcpyEquivalentSpecialMember() { return false; } static bool isTrivialCtorOrDtor() { return false; } + static bool lambdaCaptures() { return false; } static bool lambdaFieldToName() { return false; } static bool loopInfoStack() { return false; } static bool lowerAggregateLoadStore() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 6527fb5697f7c..66a6555b21f1b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -608,11 +608,16 @@ void CIRGenFunction::emitDecl(const Decl &d) { case Decl::UsingDirective: // using namespace X; [C++] assert(!cir::MissingFeatures::generateDebugInfo()); return; - case Decl::Var: { + case Decl::Var: + case Decl::Decomposition: { const VarDecl &vd = cast<VarDecl>(d); assert(vd.isLocalVarDecl() && "Should not see file-scope variables inside a function!"); emitVarDecl(vd); + if (auto *dd = dyn_cast<DecompositionDecl>(&vd)) + for (BindingDecl *b : dd->bindings()) + if (VarDecl *hd = b->getHoldingVar()) + emitVarDecl(*hd); return; } case Decl::OpenACCDeclare: @@ -632,7 +637,6 @@ void CIRGenFunction::emitDecl(const Decl &d) { case Decl::ImplicitConceptSpecialization: case Decl::TopLevelStmt: case Decl::UsingPack: - case Decl::Decomposition: // This could be moved to join Decl::Var case Decl::OMPDeclareReduction: case Decl::OMPDeclareMapper: cgm.errorNYI(d.getSourceRange(), diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index c18498f80e99f..e1fc64428043b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -584,6 +584,11 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) { return lv; } + if (const auto *bd = dyn_cast<BindingDecl>(nd)) { + assert(!e->refersToEnclosingVariableOrCapture() && !cir::MissingFeatures::lambdaCaptures()); + return emitLValue(bd->getBinding()); + } + cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type"); return LValue(); } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 623b84f031c13..96892f8a2ddd4 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1308,8 +1308,13 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) { break; } - case Decl::Var: { + case Decl::Var: + case Decl::Decomposition: { auto *vd = cast<VarDecl>(decl); + if(isa<DecompositionDecl>(decl)) { + errorNYI(decl->getSourceRange(), "global variable decompositions"); + break; + } emitGlobal(vd); break; } diff --git a/clang/test/CIR/CodeGen/variable-decomposition.cpp b/clang/test/CIR/CodeGen/variable-decomposition.cpp new file mode 100644 index 0000000000000..b82e0c62424d4 --- /dev/null +++ b/clang/test/CIR/CodeGen/variable-decomposition.cpp @@ -0,0 +1,55 @@ +// RUN: %clang_cc1 -std=c++17 -triple x86_64-pc-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-pc-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -std=c++17 -triple x86_64-pc-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct some_struct { + int a; + float b; +}; + +float function() { + auto[a, b] = some_struct{1, 2.f}; + + return a + b; +} + +// CIR-LABEL: cir.func dso_local @_Z8functionv() -> !cir.float +// CIR: %[[RETVAL:.+]] = cir.alloca !cir.float, !cir.ptr<!cir.float>, ["__retval"] +// CIR: %[[STRUCT:.+]] = cir.alloca !rec_some_struct, !cir.ptr<!rec_some_struct>, [""] +// CIR: %[[MEMBER_A:.+]] = cir.get_member %[[STRUCT]][0] {name = "a"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!s32i> +// CIR: %[[LOAD_A:.+]] = cir.load align(4) %[[MEMBER_A]] : !cir.ptr<!s32i>, !s32i +// CIR: %[[CAST_A:.+]] = cir.cast(int_to_float, %[[LOAD_A]] : !s32i), !cir.float +// CIR: %[[MEMBER_B:.+]] = cir.get_member %[[STRUCT]][1] {name = "b"} : !cir.ptr<!rec_some_struct> -> !cir.ptr<!cir.float> +// CIR: %[[LOAD_B:.+]] = cir.load align(4) %[[MEMBER_B]] : !cir.ptr<!cir.float>, !cir.float +// CIR: %[[ADD:.+]] = cir.binop(add, %[[CAST_A]], %[[LOAD_B]]) : !cir.float +// CIR: cir.store %[[ADD]], %[[RETVAL]] : !cir.float, !cir.ptr<!cir.float> +// CIR: %[[RET:.+]] = cir.load %[[RETVAL]] : !cir.ptr<!cir.float>, !cir.float +// CIR: cir.return %[[RET]] : !cir.float + +// LLVM-LABEL: define dso_local float @_Z8functionv() +// LLVM: %[[RETVAL:.+]] = alloca float, i64 1 +// LLVM: %[[STRUCT:.+]] = alloca %struct.some_struct, i64 1 +// LLVM: %[[GEP_A:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0 +// LLVM: %[[LOAD_A:.+]] = load i32, ptr %[[GEP_A]] +// LLVM: %[[CAST_A:.+]] = sitofp i32 %[[LOAD_A]] to float +// LLVM: %[[GEP_B:.+]] = getelementptr %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1 +// LLVM: %[[LOAD_B:.+]] = load float, ptr %[[GEP_B]] +// LLVM: %[[ADD:.+]] = fadd float %[[CAST_A]], %[[LOAD_B]] +// LLVM: store float %[[ADD]], ptr %[[RETVAL]] +// LLVM: %[[RET:.+]] = load float, ptr %[[RETVAL]] +// LLVM: ret float %[[RET]] + +// OGCG: @__const._Z8functionv.{{.*}} = private unnamed_addr constant %struct.some_struct { i32 1, float 2.000000e+00 } +// OGCG-LABEL: define dso_local noundef float @_Z8functionv() +// OGCG: %[[STRUCT:.+]] = alloca %struct.some_struct +// OGCG: call void @llvm.memcpy.p0.p0.i64(ptr align 4 %[[STRUCT]], ptr align 4 @__const._Z8functionv.{{.*}}, i64 8, i1 false) +// OGCG: %[[GEP_A:.+]] = getelementptr inbounds nuw %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 0 +// OGCG: %[[LOAD_A:.+]] = load i32, ptr %[[GEP_A]] +// OGCG: %[[CAST_A:.+]] = sitofp i32 %[[LOAD_A]] to float +// OGCG: %[[GEP_B:.+]] = getelementptr inbounds nuw %struct.some_struct, ptr %[[STRUCT]], i32 0, i32 1 +// OGCG: %[[LOAD_B:.+]] = load float, ptr %[[GEP_B]] +// OGCG: %[[ADD:.+]] = fadd float %[[CAST_A]], %[[LOAD_B]] +// OGCG: ret float %[[ADD]] >From 6f62ea0ef1c9d3a982582735da8f763450792775 Mon Sep 17 00:00:00 2001 From: Morris Hafner <mhaf...@nvidia.com> Date: Tue, 29 Jul 2025 15:28:00 +0200 Subject: [PATCH 2/3] clang-format --- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 3 ++- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index e1fc64428043b..abeea6273253e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -585,7 +585,8 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) { } if (const auto *bd = dyn_cast<BindingDecl>(nd)) { - assert(!e->refersToEnclosingVariableOrCapture() && !cir::MissingFeatures::lambdaCaptures()); + assert(!e->refersToEnclosingVariableOrCapture() && + !cir::MissingFeatures::lambdaCaptures()); return emitLValue(bd->getBinding()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 96892f8a2ddd4..6130f7c4c4544 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -1311,7 +1311,7 @@ void CIRGenModule::emitTopLevelDecl(Decl *decl) { case Decl::Var: case Decl::Decomposition: { auto *vd = cast<VarDecl>(decl); - if(isa<DecompositionDecl>(decl)) { + if (isa<DecompositionDecl>(decl)) { errorNYI(decl->getSourceRange(), "global variable decompositions"); break; } >From 2676b6aeee620cf4abf7d97902c924fa050c5201 Mon Sep 17 00:00:00 2001 From: Morris Hafner <mhaf...@nvidia.com> Date: Wed, 30 Jul 2025 17:56:41 +0200 Subject: [PATCH 3/3] * introduce maybeEmitDeferredVarDeclInit * reformat rest --- clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 16 +++++++++++----- clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 7 +++++-- clang/lib/CIR/CodeGen/CIRGenFunction.h | 4 +++- clang/lib/CIR/CodeGen/CIRGenStmt.cpp | 6 +++--- .../test/CIR/CodeGen/variable-decomposition.cpp | 8 ++++---- 5 files changed, 26 insertions(+), 15 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 66a6555b21f1b..6251308c75e78 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -520,7 +520,7 @@ void CIRGenFunction::emitExprAsInit(const Expr *init, const ValueDecl *d, llvm_unreachable("bad evaluation kind"); } -void CIRGenFunction::emitDecl(const Decl &d) { +void CIRGenFunction::emitDecl(const Decl &d, bool evaluateConditionDecl) { switch (d.getKind()) { case Decl::BuiltinTemplate: case Decl::TranslationUnit: @@ -614,10 +614,8 @@ void CIRGenFunction::emitDecl(const Decl &d) { assert(vd.isLocalVarDecl() && "Should not see file-scope variables inside a function!"); emitVarDecl(vd); - if (auto *dd = dyn_cast<DecompositionDecl>(&vd)) - for (BindingDecl *b : dd->bindings()) - if (VarDecl *hd = b->getHoldingVar()) - emitVarDecl(*hd); + if (evaluateConditionDecl) + maybeEmitDeferredVarDeclInit(&vd); return; } case Decl::OpenACCDeclare: @@ -801,3 +799,11 @@ void CIRGenFunction::emitAutoVarTypeCleanup( assert(!cir::MissingFeatures::ehCleanupFlags()); ehStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer); } + +void CIRGenFunction::maybeEmitDeferredVarDeclInit(const VarDecl *vd) { + if (auto *dd = dyn_cast_if_present<DecompositionDecl>(vd)) { + for (auto *b : dd->flat_bindings()) + if (auto *hd = b->getHoldingVar()) + emitVarDecl(*hd); + } +} \ No newline at end of file diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp index abeea6273253e..a509ffa9be961 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp @@ -585,8 +585,11 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr *e) { } if (const auto *bd = dyn_cast<BindingDecl>(nd)) { - assert(!e->refersToEnclosingVariableOrCapture() && - !cir::MissingFeatures::lambdaCaptures()); + if (e->refersToEnclosingVariableOrCapture()) { + assert(!cir::MissingFeatures::lambdaCaptures()); + cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: lambda captures"); + return LValue(); + } return emitLValue(bd->getBinding()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 603f75078c519..f9c8636ab0220 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -870,6 +870,8 @@ class CIRGenFunction : public CIRGenTypeCache { void emitAutoVarTypeCleanup(const AutoVarEmission &emission, clang::QualType::DestructionKind dtorKind); + void maybeEmitDeferredVarDeclInit(const VarDecl *vd); + void emitBaseInitializer(mlir::Location loc, const CXXRecordDecl *classDecl, CXXCtorInitializer *baseInit); @@ -1059,7 +1061,7 @@ class CIRGenFunction : public CIRGenTypeCache { void emitCompoundStmtWithoutScope(const clang::CompoundStmt &s); - void emitDecl(const clang::Decl &d); + void emitDecl(const clang::Decl &d, bool evaluateConditionDecl = false); mlir::LogicalResult emitDeclStmt(const clang::DeclStmt &s); LValue emitDeclRefLValue(const clang::DeclRefExpr *e); diff --git a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp index 21bee3312eb0f..75da229e64c6c 100644 --- a/clang/lib/CIR/CodeGen/CIRGenStmt.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenStmt.cpp @@ -363,8 +363,8 @@ mlir::LogicalResult CIRGenFunction::emitIfStmt(const IfStmt &s) { mlir::LogicalResult CIRGenFunction::emitDeclStmt(const DeclStmt &s) { assert(builder.getInsertionBlock() && "expected valid insertion point"); - for (const Decl *I : s.decls()) - emitDecl(*I); + for (const Decl *i : s.decls()) + emitDecl(*i, /*evaluateConditionDecl=*/true); return mlir::success(); } @@ -875,7 +875,7 @@ mlir::LogicalResult CIRGenFunction::emitSwitchStmt(const clang::SwitchStmt &s) { return mlir::failure(); if (s.getConditionVariable()) - emitDecl(*s.getConditionVariable()); + emitDecl(*s.getConditionVariable(), /*evaluateConditionDecl=*/true); mlir::Value condV = emitScalarExpr(s.getCond()); diff --git a/clang/test/CIR/CodeGen/variable-decomposition.cpp b/clang/test/CIR/CodeGen/variable-decomposition.cpp index b82e0c62424d4..022d06a97e369 100644 --- a/clang/test/CIR/CodeGen/variable-decomposition.cpp +++ b/clang/test/CIR/CodeGen/variable-decomposition.cpp @@ -6,14 +6,14 @@ // RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s struct some_struct { - int a; - float b; + int a; + float b; }; float function() { - auto[a, b] = some_struct{1, 2.f}; + auto[a, b] = some_struct{1, 2.f}; - return a + b; + return a + b; } // CIR-LABEL: cir.func dso_local @_Z8functionv() -> !cir.float _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits