[clang] 8a9877d - [CIR] __builtin_source_location lowering for constant (#194505)

via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 28 15:56:44 PDT 2026


Author: Erich Keane
Date: 2026-04-28T15:56:39-07:00
New Revision: 8a9877dce0e4705d470dc66944ee3c9e35a04fdd

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

LOG: [CIR] __builtin_source_location lowering for constant (#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.

Added: 
    

Modified: 
    clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
    clang/lib/CIR/CodeGen/CIRGenModule.cpp
    clang/lib/CIR/CodeGen/CIRGenModule.h
    clang/test/CIR/CodeGen/source-loc.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp b/clang/lib/CIR/CodeGen/CIRGenExprConstant.cpp
index 490703d9b5052..79ba2e2b26708 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..ddf36e7fa9166 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -3570,6 +3570,50 @@ 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 = dyn_cast<mlir::TypedAttr>(init);
+
+  if (!typedInit)
+    errorNYI(gcd->getSourceRange(),
+             "getAddrOfUnnamedGlobalConstantDecl: non-typed initializer");
+
+  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 = numEntries == 0
+                         ? ".constant"
+                         : (Twine(".constant.") + Twine(numEntries)).str();
+  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..d6f675841a227 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 *gcd);
 
   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..b811964eca3b8 100644
--- a/clang/test/CIR/CodeGen/source-loc.cpp
+++ b/clang/test/CIR/CodeGen/source-loc.cpp
@@ -5,6 +5,65 @@
 // 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
+//
+// Note: the naming 
diff erence between LLVM and OGCG here is because of the
+// uniquification 
diff erences when we encounter duplicate names. LLVM has a
+// global counter that manages these, CIR just increments the single names, each
+// with its own counter.  As a result, .str and .constant names don't match.
+// 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 +71,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<68> : !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 68, 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 68, ptr %[[A_ADDR]], align 4
 // OGCG: store i32 20, ptr %[[B_ADDR]], align 4
 
 void function_file() {
@@ -36,23 +95,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