[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