Author: Morris Hafner
Date: 2025-07-31T17:34:41+02:00
New Revision: 8a5d3631230ab4ce7ede76df2faf8b6494fc876e

URL: 
https://github.com/llvm/llvm-project/commit/8a5d3631230ab4ce7ede76df2faf8b6494fc876e
DIFF: 
https://github.com/llvm/llvm-project/commit/8a5d3631230ab4ce7ede76df2faf8b6494fc876e.diff

LOG: [CIR] Upstream support for function-level variable decompositions (#151073)

This implements support for structured bindings on a function scope
level. It does not add support for global structured bindings.

Added: 
    clang/test/CIR/CodeGen/variable-decomposition.cpp

Modified: 
    clang/include/clang/CIR/MissingFeatures.h
    clang/lib/CIR/CodeGen/CIRGenDecl.cpp
    clang/lib/CIR/CodeGen/CIRGenExpr.cpp
    clang/lib/CIR/CodeGen/CIRGenFunction.h
    clang/lib/CIR/CodeGen/CIRGenModule.cpp
    clang/lib/CIR/CodeGen/CIRGenStmt.cpp

Removed: 
    


################################################################################
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..9e8eaa5afa1e6 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:
@@ -608,11 +608,14 @@ 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 (evaluateConditionDecl)
+      maybeEmitDeferredVarDeclInit(&vd);
     return;
   }
   case Decl::OpenACCDeclare:
@@ -632,7 +635,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(),
@@ -797,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);
+  }
+}

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index c18498f80e99f..a509ffa9be961 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -584,6 +584,15 @@ LValue CIRGenFunction::emitDeclRefLValue(const DeclRefExpr 
*e) {
     return lv;
   }
 
+  if (const auto *bd = dyn_cast<BindingDecl>(nd)) {
+    if (e->refersToEnclosingVariableOrCapture()) {
+      assert(!cir::MissingFeatures::lambdaCaptures());
+      cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: lambda captures");
+      return LValue();
+    }
+    return emitLValue(bd->getBinding());
+  }
+
   cgm.errorNYI(e->getSourceRange(), "emitDeclRefLValue: unhandled decl type");
   return LValue();
 }

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/CIRGenModule.cpp 
b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 01f365f64356c..d0f9fc3bd48d2 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/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
new file mode 100644
index 0000000000000..022d06a97e369
--- /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]]


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to