Author: Erich Keane
Date: 2026-06-02T23:51:15Z
New Revision: 678891b586ab0f3b97c83987eb2df0d2d5743ffb

URL: 
https://github.com/llvm/llvm-project/commit/678891b586ab0f3b97c83987eb2df0d2d5743ffb
DIFF: 
https://github.com/llvm/llvm-project/commit/678891b586ab0f3b97c83987eb2df0d2d5743ffb.diff

LOG: [CIR] Implement lowering for const-emitted global compound literals 
(#201152)

This came up in a test suite as a NYI, it is just emitting a
constant-backing literal for an initializer. These are specific to C, as
global compound literals have static storage duration in C. This patch,
just like classic codgen, just creates a '.compoundliteral' object as
backing for these variables, and lets us create references to them.

---------

Co-authored-by: Andy Kaylor <[email protected]>

Added: 
    clang/test/CIR/CodeGen/compound_literal.c

Modified: 
    clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h
    clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
    clang/lib/CIR/CodeGen/CIRGenModule.h

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h 
b/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h
index 5280198524773..2591b53704a8d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h
+++ b/clang/lib/CIR/CodeGen/CIRGenConstantEmitter.h
@@ -53,7 +53,7 @@ class ConstantEmitter {
   /// block addresses or PredefinedExprs.
   ConstantEmitter(CIRGenFunction &cgf) : cgm(cgf.cgm), cgf(&cgf) {}
 
-  ConstantEmitter(CIRGenModule &cgm, CIRGenFunction *cgf = nullptr)
+  ConstantEmitter(CIRGenModule &cgm, const CIRGenFunction *cgf = nullptr)
       : cgm(cgm), cgf(cgf) {}
 
   ConstantEmitter(const ConstantEmitter &other) = delete;
@@ -61,9 +61,13 @@ class ConstantEmitter {
 
   ~ConstantEmitter();
 
+  bool isInConstantContext() const { return inConstantContext; }
+  void setInConstantContext(bool value) { inConstantContext = value; }
+
   /// Try to emit the initializer of the given declaration as an abstract
   /// constant.  If this succeeds, the emission must be finalized.
   mlir::Attribute tryEmitForInitializer(const VarDecl &d);
+  mlir::Attribute tryEmitForInitializer(const Expr *e, QualType destType);
 
   mlir::Attribute emitForInitializer(const APValue &value, QualType destType);
 

diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp 
b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index c6346542b4b44..5208af44412a3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -1439,10 +1439,48 @@ ConstantLValue 
ConstantLValueEmitter::VisitConstantExpr(const ConstantExpr *e) {
   return {};
 }
 
+static cir::GlobalViewAttr
+tryEmitGlobalCompoundLiteral(ConstantEmitter &emitter,
+                             const CompoundLiteralExpr *e) {
+  CIRGenModule &cgm = emitter.cgm;
+  CIRGenBuilderTy &builder = cgm.getBuilder();
+  CharUnits align = cgm.getASTContext().getTypeAlignInChars(e->getType());
+
+  if (cir::GlobalOp addr = cgm.getAddrOfConstantCompoundLiteralIfEmitted(e))
+    return builder.getGlobalViewAttr(addr);
+
+  assert(!cir::MissingFeatures::addressSpace());
+  mlir::Attribute c =
+      emitter.tryEmitForInitializer(e->getInitializer(), e->getType());
+  if (!c) {
+    assert(!e->isFileScope() &&
+           "file-scope compound literal did not have constant initializer!");
+    return {};
+  }
+
+  auto typedInit = mlir::cast<mlir::TypedAttr>(c);
+  bool isConstant = e->getType().isConstantStorage(cgm.getASTContext(),
+                                                   /*ExcludeCtor=*/true,
+                                                   /*ExcludeDtor=*/false);
+
+  std::string name = cgm.getUniqueGlobalName(".compoundliteral");
+  mlir::Location loc = cgm.getLoc(e->getSourceRange());
+  cir::GlobalOp gv =
+      cgm.createGlobalOp(loc, name, typedInit.getType(), isConstant);
+  gv.setLinkage(cir::GlobalLinkageKind::InternalLinkage);
+  gv.setAlignment(align.getAsAlign().value());
+  CIRGenModule::setInitializer(gv, c);
+
+  emitter.finalize(gv);
+  cgm.setAddrOfConstantCompoundLiteral(e, gv);
+  return builder.getGlobalViewAttr(gv);
+}
+
 ConstantLValue
 ConstantLValueEmitter::VisitCompoundLiteralExpr(const CompoundLiteralExpr *e) {
-  cgm.errorNYI(e->getSourceRange(), "ConstantLValueEmitter: compound literal");
-  return {};
+  ConstantEmitter compoundLiteralEmitter(cgm, emitter.cgf);
+  compoundLiteralEmitter.setInConstantContext(emitter.isInConstantContext());
+  return tryEmitGlobalCompoundLiteral(compoundLiteralEmitter, e);
 }
 
 ConstantLValue
@@ -1518,6 +1556,12 @@ mlir::Attribute 
ConstantEmitter::tryEmitForInitializer(const VarDecl &d) {
   return markIfFailed(tryEmitPrivateForVarInit(d));
 }
 
+mlir::Attribute ConstantEmitter::tryEmitForInitializer(const Expr *e,
+                                                       QualType destType) {
+  initializeNonAbstract();
+  return markIfFailed(tryEmitPrivateForMemory(e, destType));
+}
+
 mlir::Attribute ConstantEmitter::emitForInitializer(const APValue &value,
                                                     QualType destType) {
   initializeNonAbstract();

diff  --git a/clang/lib/CIR/CodeGen/CIRGenModule.h 
b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 38436fa0ea5db..d52d3559a238b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -447,6 +447,18 @@ class CIRGenModule : public CIRGenTypeCache {
   llvm::DenseMap<mlir::Attribute, cir::GlobalOp> constantStringMap;
   llvm::DenseMap<const UnnamedGlobalConstantDecl *, cir::GlobalOp>
       unnamedGlobalConstantDeclMap;
+  llvm::DenseMap<const CompoundLiteralExpr *, cir::GlobalOp>
+      emittedCompoundLiterals;
+
+  cir::GlobalOp
+  getAddrOfConstantCompoundLiteralIfEmitted(const CompoundLiteralExpr *e) {
+    return emittedCompoundLiterals.lookup(e);
+  }
+  void setAddrOfConstantCompoundLiteral(const CompoundLiteralExpr *e,
+                                        cir::GlobalOp gv) {
+    [[maybe_unused]] bool ok = emittedCompoundLiterals.insert({e, gv}).second;
+    assert(ok && "compound literal global already emitted");
+  }
 
   /// Return a constant array for the given string.
   mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e);

diff  --git a/clang/test/CIR/CodeGen/compound_literal.c 
b/clang/test/CIR/CodeGen/compound_literal.c
new file mode 100644
index 0000000000000..d3d45f5af8e27
--- /dev/null
+++ b/clang/test/CIR/CodeGen/compound_literal.c
@@ -0,0 +1,67 @@
+// 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 -Wno-unused-value 
-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 -Wno-unused-value 
-emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+int *p1 = (int[]){1, 2, 3};
+// CIR: cir.global "private" internal @".compoundliteral" = 
#cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : 
!s32i]> : !cir.array<!s32i x 3> {alignment = 4 : i64}
+// CIR: cir.global external @p1 = #cir.global_view<@".compoundliteral"> : 
!cir.ptr<!s32i> {alignment = 8 : i64}
+// LLVM: @.compoundliteral = internal global [3 x i32] [i32 1, i32 2, i32 3], 
align 4
+// LLVM: @p1 = global ptr @.compoundliteral, align 8
+
+int *p2 = &(int){42};
+// CIR: cir.global "private" internal @".compoundliteral.1" = #cir.int<42> : 
!s32i {alignment = 4 : i64}
+// CIR: cir.global external @p2 = #cir.global_view<@".compoundliteral.1"> : 
!cir.ptr<!s32i> {alignment = 8 : i64}
+// LLVM: @.compoundliteral.1 = internal global i32 42, align 4
+// LLVM: @p2 = global ptr @.compoundliteral.1, align 8
+
+struct S { int x, y; };
+struct S *p3 = &(struct S){5, 10};
+// CIR: cir.global "private" internal @".compoundliteral.2" = 
#cir.const_record<{#cir.int<5> : !s32i, #cir.int<10> : !s32i}> : !rec_S 
{alignment = 4 : i64}
+// CIR: cir.global external @p3 = #cir.global_view<@".compoundliteral.2"> : 
!cir.ptr<!rec_S> {alignment = 8 : i64}
+// LLVM: @.compoundliteral.2 = internal global %struct.S { i32 5, i32 10 }, 
align 4
+// LLVM: @p3 = global ptr @.compoundliteral.2, align 8
+
+int *p4[2] = { (int[]){1, 2}, (int[]){3, 4} };
+// CIR: cir.global "private" internal @".compoundliteral.3" = 
#cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i]> : !cir.array<!s32i 
x 2> {alignment = 4 : i64}
+// CIR: cir.global "private" internal @".compoundliteral.4" = 
#cir.const_array<[#cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.array<!s32i 
x 2> {alignment = 4 : i64}
+// CIR: cir.global external @p4 = 
#cir.const_array<[#cir.global_view<@".compoundliteral.3"> : !cir.ptr<!s32i>, 
#cir.global_view<@".compoundliteral.4"> : !cir.ptr<!s32i>]> : 
!cir.array<!cir.ptr<!s32i> x 2> {alignment = 16 : i64}
+// LLVM: @.compoundliteral.3 = internal global [2 x i32] [i32 1, i32 2], align 
4
+// LLVM: @.compoundliteral.4 = internal global [2 x i32] [i32 3, i32 4], align 
4
+// LLVM: @p4 = global [2 x ptr] [ptr @.compoundliteral.3, ptr 
@.compoundliteral.4], align 16
+
+struct W { int *p; };
+struct W p5 = { (int[]){10, 20} };
+// CIR: cir.global "private" internal @".compoundliteral.5" = 
#cir.const_array<[#cir.int<10> : !s32i, #cir.int<20> : !s32i]> : 
!cir.array<!s32i x 2> {alignment = 4 : i64}
+// CIR: cir.global external @p5 = 
#cir.const_record<{#cir.global_view<@".compoundliteral.5"> : !cir.ptr<!s32i>}> 
: !rec_W {alignment = 8 : i64}
+// LLVM: @.compoundliteral.5 = internal global [2 x i32] [i32 10, i32 20], 
align 4
+// LLVM: @p5 = global %struct.W { ptr @.compoundliteral.5 }, align 8
+
+const int *p6 = (const int[]){1, 2, 3};
+// CIR: cir.global "private" constant internal @".compoundliteral.6" = 
#cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : 
!s32i]> : !cir.array<!s32i x 3> {alignment = 4 : i64}
+// CIR: cir.global external @p6 = #cir.global_view<@".compoundliteral.6"> : 
!cir.ptr<!s32i> {alignment = 8 : i64}
+// LLVM: @.compoundliteral.6 = internal constant [3 x i32] [i32 1, i32 2, i32 
3], align 4
+// LLVM: @p6 = global ptr @.compoundliteral.6, align 8
+
+char *p7 = (char[]){"hi"};
+// CIR: cir.global "private" internal @".compoundliteral.7" = 
#cir.const_array<"hi" : !cir.array<!s8i x 2>, trailing_zeros> : !cir.array<!s8i 
x 3> {alignment = 1 : i64}
+// CIR: cir.global external @p7 = #cir.global_view<@".compoundliteral.7"> : 
!cir.ptr<!s8i> {alignment = 8 : i64}
+// LLVM: @.compoundliteral.7 = internal global [3 x i8] c"hi\00", align 1
+// LLVM: @p7 = global ptr @.compoundliteral.7, align 8
+
+int *p8 = &((int[]){10, 20, 30})[1];
+// CIR: cir.global "private" internal @".compoundliteral.8" = 
#cir.const_array<[#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.int<30> : 
!s32i]> : !cir.array<!s32i x 3> {alignment = 4 : i64}
+// CIR: cir.global external @p8 = #cir.global_view<@".compoundliteral.8", [1 : 
i32]> : !cir.ptr<!s32i> {alignment = 8 : i64}
+// LLVM: @.compoundliteral.8 = internal global [3 x i32] [i32 10, i32 20, i32 
30], align 4
+// LLVM: @p8 = global ptr getelementptr {{(inbounds nuw )?}}(i8, ptr 
@.compoundliteral.8, i64 4), align 8
+
+int x;
+int **p9 = (int*[]){&x, &x};
+// CIR: cir.global external @x
+// CIR: cir.global "private" internal @".compoundliteral.9" = 
#cir.const_array<[#cir.global_view<@x> : !cir.ptr<!s32i>, #cir.global_view<@x> 
: !cir.ptr<!s32i>]> : !cir.array<!cir.ptr<!s32i> x 2> {alignment = 8 : i64}
+// CIR: cir.global external @p9 = #cir.global_view<@".compoundliteral.9"> : 
!cir.ptr<!cir.ptr<!s32i>> {alignment = 8 : i64}
+// LLVM: @x = global i32 0, align 4
+// LLVM: @.compoundliteral.9 = internal global [2 x ptr] [ptr @x, ptr @x], 
align 8
+// LLVM: @p9 = global ptr @.compoundliteral.9, align 8


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

Reply via email to