[clang] [CIR] Add support for emitting predefined expressions (PR #161757)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 2 18:02:03 PDT 2025
https://github.com/andykaylor created https://github.com/llvm/llvm-project/pull/161757
This adds support for emitting predefined expressions (such as __func__) as l-values.
>From 71dc79edb42e6fbb39af837ebbe0627b3a2167af Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Thu, 2 Oct 2025 17:58:23 -0700
Subject: [PATCH] [CIR] Add support for emitting predefined expressions
This adds support for emitting predefined expressions (such as __func__)
as l-values.
---
clang/lib/CIR/CodeGen/CIRGenExpr.cpp | 20 ++++++-
clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 2 +
clang/lib/CIR/CodeGen/CIRGenFunction.h | 5 +-
clang/lib/CIR/CodeGen/CIRGenModule.cpp | 52 +++++++++--------
clang/lib/CIR/CodeGen/CIRGenModule.h | 2 +
clang/test/CIR/CodeGen/predefined-expr.c | 71 ++++++++++++++++++++++++
6 files changed, 125 insertions(+), 27 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/predefined-expr.c
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index fa68ad931ba74..3074e1a3c845d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -1108,8 +1108,9 @@ CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) {
return lv;
}
-LValue CIRGenFunction::emitStringLiteralLValue(const StringLiteral *e) {
- cir::GlobalOp globalOp = cgm.getGlobalForStringLiteral(e);
+LValue CIRGenFunction::emitStringLiteralLValue(const StringLiteral *e,
+ llvm::StringRef name) {
+ cir::GlobalOp globalOp = cgm.getGlobalForStringLiteral(e, name);
assert(globalOp.getAlignment() && "expected alignment for string literal");
unsigned align = *(globalOp.getAlignment());
mlir::Value addr =
@@ -2372,6 +2373,21 @@ mlir::Value CIRGenFunction::emitScalarConstant(
return builder.getConstant(getLoc(e->getSourceRange()), constant.getValue());
}
+LValue CIRGenFunction::emitPredefinedLValue(const PredefinedExpr *e) {
+ const StringLiteral *sl = e->getFunctionName();
+ assert(sl != nullptr && "No StringLiteral name in PredefinedExpr");
+ auto fn = cast<cir::FuncOp>(curFn);
+ StringRef fnName = fn.getName();
+ fnName.consume_front("\01");
+ StringRef nameItems[] = {PredefinedExpr::getIdentKindName(e->getIdentKind()),
+ fnName};
+ std::string gvName = llvm::join(nameItems, nameItems + 2, ".");
+ if (isa_and_nonnull<BlockDecl>(curCodeDecl))
+ cgm.errorNYI(e->getSourceRange(), "predefined lvalue in block");
+
+ return emitStringLiteralLValue(sl, gvName);
+}
+
/// An LValue is a candidate for having its loads and stores be made atomic if
/// we are operating under /volatile:ms *and* the LValue itself is volatile and
/// performing such an operation can be performed without a libcall.
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index b26b4f2500579..3e34f5ca541fe 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -815,6 +815,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
return emitMemberExpr(cast<MemberExpr>(e));
case Expr::CompoundLiteralExprClass:
return emitCompoundLiteralLValue(cast<CompoundLiteralExpr>(e));
+ case Expr::PredefinedExprClass:
+ return emitPredefinedLValue(cast<PredefinedExpr>(e));
case Expr::BinaryOperatorClass:
return emitBinaryOperatorLValue(cast<BinaryOperator>(e));
case Expr::CompoundAssignOperatorClass: {
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index cb7cf983006e9..3eba242550c2c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -1279,6 +1279,8 @@ class CIRGenFunction : public CIRGenTypeCache {
void emitInitializerForField(clang::FieldDecl *field, LValue lhs,
clang::Expr *init);
+ LValue emitPredefinedLValue(const PredefinedExpr *e);
+
mlir::Value emitPromotedComplexExpr(const Expr *e, QualType promotionType);
mlir::Value emitPromotedScalarExpr(const Expr *e, QualType promotionType);
@@ -1473,7 +1475,8 @@ class CIRGenFunction : public CIRGenTypeCache {
mlir::Value emitStoreThroughBitfieldLValue(RValue src, LValue dstresult);
- LValue emitStringLiteralLValue(const StringLiteral *e);
+ LValue emitStringLiteralLValue(const StringLiteral *e,
+ llvm::StringRef name = ".str");
mlir::LogicalResult emitSwitchBody(const clang::Stmt *s);
mlir::LogicalResult emitSwitchCase(const clang::SwitchCase &s,
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 2bd2729f0b0fb..beeabafaeb964 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -1343,32 +1343,36 @@ cir::GlobalOp CIRGenModule::getGlobalForStringLiteral(const StringLiteral *s,
mlir::Attribute c = getConstantArrayFromStringLiteral(s);
- if (getLangOpts().WritableStrings) {
- errorNYI(s->getSourceRange(),
- "getGlobalForStringLiteral: Writable strings");
- }
-
- // Mangle the string literal if that's how the ABI merges duplicate strings.
- // Don't do it if they are writable, since we don't want writes in one TU to
- // affect strings in another.
- if (getCXXABI().getMangleContext().shouldMangleStringLiteral(s) &&
- !getLangOpts().WritableStrings) {
- errorNYI(s->getSourceRange(),
- "getGlobalForStringLiteral: mangle string literals");
- }
-
- // Unlike LLVM IR, CIR doesn't automatically unique names for globals, so
- // we need to do that explicitly.
- std::string uniqueName = getUniqueGlobalName(name.str());
- mlir::Location loc = getLoc(s->getSourceRange());
- auto typedC = llvm::cast<mlir::TypedAttr>(c);
- cir::GlobalOp gv =
- generateStringLiteral(loc, typedC, cir::GlobalLinkageKind::PrivateLinkage,
- *this, uniqueName, alignment);
- setDSOLocal(static_cast<mlir::Operation *>(gv));
+ cir::GlobalOp gv;
+ if (!getLangOpts().WritableStrings && constantStringMap.count(c)) {
+ gv = constantStringMap[c];
+ // The bigger alignment always wins.
+ if (!gv.getAlignment() ||
+ uint64_t(alignment.getQuantity()) > *gv.getAlignment())
+ gv.setAlignmentAttr(getSize(alignment));
+ } else {
+ // Mangle the string literal if that's how the ABI merges duplicate strings.
+ // Don't do it if they are writable, since we don't want writes in one TU to
+ // affect strings in another.
+ if (getCXXABI().getMangleContext().shouldMangleStringLiteral(s) &&
+ !getLangOpts().WritableStrings) {
+ errorNYI(s->getSourceRange(),
+ "getGlobalForStringLiteral: mangle string literals");
+ }
- assert(!cir::MissingFeatures::sanitizers());
+ // Unlike LLVM IR, CIR doesn't automatically unique names for globals, so
+ // we need to do that explicitly.
+ std::string uniqueName = getUniqueGlobalName(name.str());
+ mlir::Location loc = getLoc(s->getSourceRange());
+ auto typedC = llvm::cast<mlir::TypedAttr>(c);
+ gv = generateStringLiteral(loc, typedC,
+ cir::GlobalLinkageKind::PrivateLinkage, *this,
+ uniqueName, alignment);
+ setDSOLocal(static_cast<mlir::Operation *>(gv));
+ constantStringMap[c] = gv;
+ assert(!cir::MissingFeatures::sanitizers());
+ }
return gv;
}
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h
index 2c4c6dd14e2ff..541432407fea5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.h
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.h
@@ -274,6 +274,8 @@ class CIRGenModule : public CIRGenTypeCache {
llvm_unreachable("unknown visibility!");
}
+ llvm::DenseMap<mlir::Attribute, cir::GlobalOp> constantStringMap;
+
/// Return a constant array for the given string.
mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e);
diff --git a/clang/test/CIR/CodeGen/predefined-expr.c b/clang/test/CIR/CodeGen/predefined-expr.c
new file mode 100644
index 0000000000000..674c9bd02b5cf
--- /dev/null
+++ b/clang/test/CIR/CodeGen/predefined-expr.c
@@ -0,0 +1,71 @@
+// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -o %t.cir
+// RUN: FileCheck %s --input-file=%t.cir --check-prefix=CIR
+// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -o %t-cir.ll
+// RUN: FileCheck %s --input-file=%t-cir.ll --check-prefix=LLVM
+// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -o %t.ll
+// RUN: FileCheck %s --input-file=%t.ll --check-prefix=OGCG
+
+// CIR: cir.global "private" constant cir_private dso_local @__func__.plainFunction = #cir.const_array<"plainFunction\00" : !cir.array<!s8i x 14>>
+// CIR: cir.global "private" constant cir_private dso_local @__PRETTY_FUNCTION__.plainFunction = #cir.const_array<"void plainFunction(void)\00" : !cir.array<!s8i x 25>>
+// CIR: cir.global "private" constant cir_private dso_local @__func__.externFunction = #cir.const_array<"externFunction\00" : !cir.array<!s8i x 15>>
+// CIR: cir.global "private" constant cir_private dso_local @__PRETTY_FUNCTION__.externFunction = #cir.const_array<"void externFunction(void)\00" : !cir.array<!s8i x 26>>
+// CIR: cir.global "private" constant cir_private dso_local @__func__.privateExternFunction = #cir.const_array<"privateExternFunction\00" : !cir.array<!s8i x 22>>
+// CIR: cir.global "private" constant cir_private dso_local @__PRETTY_FUNCTION__.privateExternFunction = #cir.const_array<"void privateExternFunction(void)\00" : !cir.array<!s8i x 33>>
+// CIR: cir.global "private" constant cir_private dso_local @__func__.staticFunction = #cir.const_array<"staticFunction\00" : !cir.array<!s8i x 15>>
+// CIR: cir.global "private" constant cir_private dso_local @__PRETTY_FUNCTION__.staticFunction = #cir.const_array<"void staticFunction(void)\00" : !cir.array<!s8i x 26>>
+
+// TODO(cir): These should be unnamed_addr
+// LLVM: @__func__.plainFunction = private constant [14 x i8] c"plainFunction\00"
+// LLVM: @__PRETTY_FUNCTION__.plainFunction = private constant [25 x i8] c"void plainFunction(void)\00"
+// LLVM: @__func__.externFunction = private constant [15 x i8] c"externFunction\00"
+// LLVM: @__PRETTY_FUNCTION__.externFunction = private constant [26 x i8] c"void externFunction(void)\00"
+// LLVM: @__func__.privateExternFunction = private constant [22 x i8] c"privateExternFunction\00"
+// LLVM: @__PRETTY_FUNCTION__.privateExternFunction = private constant [33 x i8] c"void privateExternFunction(void)\00"
+// LLVM: @__func__.staticFunction = private constant [15 x i8] c"staticFunction\00"
+// LLVM: @__PRETTY_FUNCTION__.staticFunction = private constant [26 x i8] c"void staticFunction(void)\00"
+
+// OGCG: @__func__.plainFunction = private unnamed_addr constant [14 x i8] c"plainFunction\00"
+// OGCG: @__PRETTY_FUNCTION__.plainFunction = private unnamed_addr constant [25 x i8] c"void plainFunction(void)\00"
+// OGCG: @__func__.externFunction = private unnamed_addr constant [15 x i8] c"externFunction\00"
+// OGCG: @__PRETTY_FUNCTION__.externFunction = private unnamed_addr constant [26 x i8] c"void externFunction(void)\00"
+// OGCG: @__func__.privateExternFunction = private unnamed_addr constant [22 x i8] c"privateExternFunction\00"
+// OGCG: @__PRETTY_FUNCTION__.privateExternFunction = private unnamed_addr constant [33 x i8] c"void privateExternFunction(void)\00"
+// OGCG: @__func__.staticFunction = private unnamed_addr constant [15 x i8] c"staticFunction\00"
+// OGCG: @__PRETTY_FUNCTION__.staticFunction = private unnamed_addr constant [26 x i8] c"void staticFunction(void)\00"
+
+int printf(const char *, ...);
+
+void plainFunction(void) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+extern void externFunction(void) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+__private_extern__ void privateExternFunction(void) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+// TODO(cir): Add support for __captured_stmt
+
+static void staticFunction(void) {
+ printf("__func__ %s\n", __func__);
+ printf("__FUNCTION__ %s\n", __FUNCTION__);
+ printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
+}
+
+int main(void) {
+ plainFunction();
+ externFunction();
+ privateExternFunction();
+ staticFunction();
+
+ return 0;
+}
More information about the cfe-commits
mailing list