[clang] [CIR] __builtin_source_location lowering for constant (PR #194505)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 27 18:09:43 PDT 2026


https://github.com/erichkeane created https://github.com/llvm/llvm-project/pull/194505

This handles the UnnamedGlobalConstantDecl lowering, which is only used for the source-location object.  This uses similar logic to the classic compiler, so we end up with roughly the same IR.

There is a slight difference in how we choose which strings to uniquify (preexisting) and how we name them/name duplicates, but it isn't really relevant to the text itself.

>From 9a8984a926d801e89281fcb1fd43bb148a0c4eec Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Mon, 27 Apr 2026 17:59:07 -0700
Subject: [PATCH] [CIR] __builtin_source_location lowering for constant

This handles the UnnamedGlobalConstantDecl lowering, which is only used
for the source-location object.  This uses similar logic to the classic
compiler, so we end up with roughly the same IR.

There is a slight difference in how we choose which strings to uniquify
(preexisting) and how we name them/name duplicates, but it isn't really
relevant to the text itself.
---
 clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp |  6 +-
 clang/lib/CIR/CodeGen/CIRGenModule.cpp       | 40 ++++++++++
 clang/lib/CIR/CodeGen/CIRGenModule.h         |  5 ++
 clang/test/CIR/CodeGen/source-loc.cpp        | 79 +++++++++++++++++---
 4 files changed, 115 insertions(+), 15 deletions(-)

diff --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 438f99246306e..331d1c37281ca 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
@@ -1414,9 +1414,9 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
     if (isa<MSGuidDecl>(d))
       cgm.errorNYI(d->getSourceRange(), "ConstantLValueEmitter: MSGuidDecl");
 
-    if (isa<UnnamedGlobalConstantDecl>(d))
-      cgm.errorNYI(d->getSourceRange(),
-                   "ConstantLValueEmitter: Unnamed global constant");
+    if (const auto *gcd = dyn_cast<UnnamedGlobalConstantDecl>(d))
+      return cgm.getBuilder().getGlobalViewAttr(
+          cgm.getAddrOfUnnamedGlobalConstantDecl(gcd));
 
     if (const auto *tpo = dyn_cast<TemplateParamObjectDecl>(d))
       return cgm.getBuilder().getGlobalViewAttr(
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 7d719600a6025..0e147cd9a22c8 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -3570,6 +3570,46 @@ CIRGenModule::getAddrOfGlobalTemporary(const MaterializeTemporaryExpr *mte,
   return cv;
 }
 
+cir::GlobalOp CIRGenModule::getAddrOfUnnamedGlobalConstantDecl(
+    const UnnamedGlobalConstantDecl *gcd) {
+  unsigned numEntries = unnamedGlobalConstantDeclMap.size();
+  cir::GlobalOp *globalOpEntry = &unnamedGlobalConstantDeclMap[gcd];
+
+  if (*globalOpEntry)
+    return *globalOpEntry;
+
+  ConstantEmitter emitter(*this);
+
+  const APValue &value = gcd->getValue();
+  assert(!value.isAbsent());
+  assert(!cir::MissingFeatures::addressSpace() &&
+         "emitForInitializer should take gcd->getType().getAddressSpace()");
+  mlir::Attribute init = emitter.emitForInitializer(value, gcd->getType());
+  auto typedInit = cast<mlir::TypedAttr>(init);
+
+  assert(!cir::MissingFeatures::addressSpace());
+
+  // Classic codegen always creates these with .constant, then counts on the
+  // auto-addition of '.#'. CIR global doesn't have this, so we'll just auto-add
+  // one if this isn't the first.  We could probably choose a better name than
+  // .constant to be unique for this type of decl, but this is consistent with
+  // classic codegen.
+  std::string name = ".constant";
+  if (numEntries != 0)
+    name += '.' + std::to_string(numEntries);
+  auto globalOp = createGlobalOp(*this, builder.getUnknownLoc(), name,
+                                 typedInit.getType(), /*is_constant=*/true);
+  globalOp.setLinkage(cir::GlobalLinkageKind::PrivateLinkage);
+
+  CharUnits alignment = getASTContext().getTypeAlignInChars(gcd->getType());
+  globalOp.setAlignment(alignment.getAsAlign().value());
+  CIRGenModule::setInitializer(globalOp, init);
+
+  emitter.finalize(globalOp);
+  *globalOpEntry = globalOp;
+  return globalOp;
+}
+
 cir::GlobalOp
 CIRGenModule::getAddrOfTemplateParamObject(const TemplateParamObjectDecl *tpo) {
   StringRef name = getMangledName(tpo);
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index b2c630ca7defd..4d04351973cbb 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -360,6 +360,9 @@ class CIRGenModule : public CIRGenTypeCache {
   /// Get the GlobalOp of a template parameter object.
   cir::GlobalOp
   getAddrOfTemplateParamObject(const TemplateParamObjectDecl *tpo);
+  // Get the GlobalOp of a source_location object.
+  cir::GlobalOp
+  getAddrOfUnnamedGlobalConstantDecl(const UnnamedGlobalConstantDecl *tpo);
 
   CharUnits computeNonVirtualBaseClassOffset(
       const CXXRecordDecl *derivedClass,
@@ -429,6 +432,8 @@ class CIRGenModule : public CIRGenTypeCache {
   }
 
   llvm::DenseMap<mlir::Attribute, cir::GlobalOp> constantStringMap;
+  llvm::DenseMap<const UnnamedGlobalConstantDecl *, cir::GlobalOp>
+      unnamedGlobalConstantDeclMap;
 
   /// Return a constant array for the given string.
   mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e);
diff --git a/clang/test/CIR/CodeGen/source-loc.cpp b/clang/test/CIR/CodeGen/source-loc.cpp
index fc8ab76a9bbb8..f6ebdebd98a6c 100644
--- a/clang/test/CIR/CodeGen/source-loc.cpp
+++ b/clang/test/CIR/CodeGen/source-loc.cpp
@@ -5,6 +5,61 @@
 // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
 // RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG
 
+namespace std {
+  struct source_location {
+    struct __impl {
+    const char * _M_file_name;
+    const char * _M_function_name;
+    unsigned _M_line;
+    unsigned _M_column;
+    };
+
+    const __impl * _impl = nullptr;
+
+    static constexpr source_location
+    current(const __impl *p = __builtin_source_location()) {
+      source_location loc;
+      loc._impl = p;
+      return loc;
+    }
+  };
+}
+
+// CIR: cir.global "private" constant cir_private dso_local @".str" = #cir.const_array<
+// LLVM: @.str = private constant 
+// OGCG: @.str = private unnamed_addr constant 
+//
+// CIR: cir.global "private" constant cir_private dso_local @".str.1" = #cir.const_array<"void use1()" : !cir.array<!s8i x 11>, trailing_zeros> : !cir.array<!s8i x 12>
+// LLVM: @.str.1 = private constant [{{.*}} x i8] c"void use1
+// OGCG: @.str.1 = private unnamed_addr constant [{{.*}} x i8] c"void use1
+//
+// CIR: cir.global "private" constant cir_private @".constant" = #cir.const_record<{#cir.global_view<@".str"> : !cir.ptr<!s8i>, #cir.global_view<@".str.1"> : !cir.ptr<!s8i>, #cir.int<{{.*}}> : !u32i, #cir.int<{{.*}}> : !u32i}> : !rec_std3A3Asource_location3A3A__impl
+// LLVM: @.constant = private constant %"struct.std::source_location::__impl" { ptr @.str, ptr @.str.1, i32 {{.*}}, i32 {{.*}} }
+// OGCG: @.constant = private unnamed_addr constant %"struct.std::source_location::__impl" { ptr @.str, ptr @.str.1, i32 {{.*}}, i32 {{.*}} }
+//
+// CIR: cir.global "private" constant cir_private dso_local @".str.2" = #cir.const_array<"void use2()" : !cir.array<!s8i x 11>, trailing_zeros> : !cir.array<!s8i x 12> {alignment = 1 : i64} loc(#loc1)
+// LLVM: @.str.2 = private constant [{{.*}} x i8] c"void use2
+// OGCG: @.str.2 = private unnamed_addr constant [{{.*}} x i8] c"void use2
+//
+// CIR: cir.global "private" constant cir_private @".constant.1" = #cir.const_record<{#cir.global_view<@".str"> : !cir.ptr<!s8i>, #cir.global_view<@".str.2"> : !cir.ptr<!s8i>, #cir.int<{{.*}}> : !u32i, #cir.int<{{.*}}> : !u32i}> : !rec_std3A3Asource_location3A3A__impl
+// LLVM: @.constant.1 = private constant %"struct.std::source_location::__impl" { ptr @.str, ptr @.str.2, i32 {{.*}}, i32 {{.*}} }
+// OGCG: @.constant.3 = private unnamed_addr constant %"struct.std::source_location::__impl" { ptr @.str, ptr @.str.2, i32 {{.*}}, i32 {{.*}} }
+
+
+void has_sl(std::source_location loc = std::source_location::current());
+void use1() { has_sl(); }
+// CIR-LABEL: cir.func{{.*}} @_Z4use1v
+// CIR: cir.const #cir.global_view<@".constant"> : !cir.ptr<!rec_std3A3Asource_location3A3A__impl>
+// LLVM: define {{.*}}@_Z4use1v()
+// LLVM: call {{.*}}@_ZNSt15source_location7currentEPKNS_6__implE(ptr noundef @.constant)
+// OGCG: call {{.*}}@_ZNSt15source_location7currentEPKNS_6__implE(ptr noundef @.constant)
+void use2() { has_sl(); }
+// CIR-LABEL: cir.func{{.*}} @_Z4use2v
+// CIR: cir.const #cir.global_view<@".constant.1"> : !cir.ptr<!rec_std3A3Asource_location3A3A__impl>
+// LLVM: define {{.*}}@_Z4use2v()
+// LLVM: call {{.*}}@_ZNSt15source_location7currentEPKNS_6__implE(ptr noundef @.constant.1)
+// OGCG: call {{.*}}@_ZNSt15source_location7currentEPKNS_6__implE(ptr noundef @.constant.3)
+
 void line_column() {
   unsigned int a = __builtin_LINE();
   unsigned int b = __builtin_COLUMN();
@@ -12,19 +67,19 @@ void line_column() {
 
 // CIR: %[[A_ADDR:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["a", init]
 // CIR: %[[B_ADDR:.*]] = cir.alloca !u32i, !cir.ptr<!u32i>, ["b", init]
-// CIR: %[[CONST_9:.*]] = cir.const #cir.int<9> : !u32i
+// CIR: %[[CONST_9:.*]] = cir.const #cir.int<64> : !u32i
 // CIR: cir.store {{.*}} %[[CONST_9]], %[[A_ADDR]] : !u32i, !cir.ptr<!u32i>
 // CIR: %[[CONST_20:.*]] = cir.const #cir.int<20> : !u32i
 // CIR: cir.store {{.*}} %[[CONST_20]], %[[B_ADDR]] : !u32i, !cir.ptr<!u32i>
 
 // LLVM: %[[A_ADDR:.*]] = alloca i32, i64 1, align 4
 // LLVM: %[[B_ADDR:.*]] = alloca i32, i64 1, align 4
-// LLVM: store i32 9, ptr %[[A_ADDR]], align 4
+// LLVM: store i32 64, ptr %[[A_ADDR]], align 4
 // LLVM: store i32 20, ptr %[[B_ADDR]], align 4
 
 // OGCG: %[[A_ADDR:.*]] = alloca i32, align 4
 // OGCG: %[[B_ADDR:.*]] = alloca i32, align 4
-// OGCG: store i32 9, ptr %[[A_ADDR]], align 4
+// OGCG: store i32 64, ptr %[[A_ADDR]], align 4
 // OGCG: store i32 20, ptr %[[B_ADDR]], align 4
 
 void function_file() {
@@ -36,23 +91,23 @@ void function_file() {
 // CIR: %[[A_ADDR:.*]] = cir.alloca !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>, ["a", init]
 // CIR: %[[B_ADDR:.*]] = cir.alloca !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>, ["b", init]
 // CIR: %[[C_ADDR:.*]] = cir.alloca !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>, ["c", init]
-// CIR: %[[FUNC__GV:.*]] = cir.const #cir.global_view<@".str"> : !cir.ptr<!s8i>
+// CIR: %[[FUNC__GV:.*]] = cir.const #cir.global_view<@".str.3"> : !cir.ptr<!s8i>
 // CIR: cir.store {{.*}} %[[FUNC__GV]], %[[A_ADDR]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
-// CIR: %[[FILE_PATH_GV:.*]] = cir.const #cir.global_view<@".str.1"> : !cir.ptr<!s8i>
+// CIR: %[[FILE_PATH_GV:.*]] = cir.const #cir.global_view<@".str"> : !cir.ptr<!s8i>
 // CIR: cir.store {{.*}} %[[FILE_PATH_GV]], %[[B_ADDR]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
-// CIR: %[[FILE_GV:.*]] = cir.const #cir.global_view<@".str.2"> : !cir.ptr<!s8i>
+// CIR: %[[FILE_GV:.*]] = cir.const #cir.global_view<@".str.4"> : !cir.ptr<!s8i>
 // CIR: cir.store {{.*}} %[[FILE_GV]], %[[C_ADDR]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
 
 // LLVM: %[[A_ADDR:.*]] = alloca ptr, i64 1, align 8
 // LLVM: %[[B_ADDR:.*]] = alloca ptr, i64 1, align 8
 // LLVM: %[[C_ADDR:.*]] = alloca ptr, i64 1, align 8
-// LLVM: store ptr @.str, ptr %[[A_ADDR]], align 8
-// LLVM: store ptr @.str.1, ptr %[[B_ADDR]], align 8
-// LLVM: store ptr @.str.2, ptr %[[C_ADDR]], align 8
+// LLVM: store ptr @.str.3, ptr %[[A_ADDR]], align 8
+// LLVM: store ptr @.str, ptr %[[B_ADDR]], align 8
+// LLVM: store ptr @.str.4, ptr %[[C_ADDR]], align 8
 
 // OGCG: %[[A_ADDR:.*]] = alloca ptr, align 8
 // OGCG: %[[B_ADDR:.*]] = alloca ptr, align 8
 // OGCG: %[[C_ADDR:.*]] = alloca ptr, align 8
-// OGCG: store ptr @.str, ptr %[[A_ADDR]], align 8
-// OGCG: store ptr @.str.1, ptr %[[B_ADDR]], align 8
-// OGCG: store ptr @.str.2, ptr %[[C_ADDR]], align 8
+// OGCG: store ptr @.str.4, ptr %[[A_ADDR]], align 8
+// OGCG: store ptr @.str, ptr %[[B_ADDR]], align 8
+// OGCG: store ptr @.str.5, ptr %[[C_ADDR]], align 8



More information about the cfe-commits mailing list