Skip to content

Commit d6449b5

Browse files
authored
[CIR] Add support for emitting predefined expressions (#161757)
This adds support for emitting pseudo-macro expressions that represent some form of the name of a function (such as `__func__` or `__PRETTY_FUNCTION__`) as l-values.
1 parent c54d0d7 commit d6449b5

File tree

6 files changed

+125
-27
lines changed

6 files changed

+125
-27
lines changed

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,8 +1108,9 @@ CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) {
11081108
return lv;
11091109
}
11101110

1111-
LValue CIRGenFunction::emitStringLiteralLValue(const StringLiteral *e) {
1112-
cir::GlobalOp globalOp = cgm.getGlobalForStringLiteral(e);
1111+
LValue CIRGenFunction::emitStringLiteralLValue(const StringLiteral *e,
1112+
llvm::StringRef name) {
1113+
cir::GlobalOp globalOp = cgm.getGlobalForStringLiteral(e, name);
11131114
assert(globalOp.getAlignment() && "expected alignment for string literal");
11141115
unsigned align = *(globalOp.getAlignment());
11151116
mlir::Value addr =
@@ -2372,6 +2373,21 @@ mlir::Value CIRGenFunction::emitScalarConstant(
23722373
return builder.getConstant(getLoc(e->getSourceRange()), constant.getValue());
23732374
}
23742375

2376+
LValue CIRGenFunction::emitPredefinedLValue(const PredefinedExpr *e) {
2377+
const StringLiteral *sl = e->getFunctionName();
2378+
assert(sl != nullptr && "No StringLiteral name in PredefinedExpr");
2379+
auto fn = cast<cir::FuncOp>(curFn);
2380+
StringRef fnName = fn.getName();
2381+
fnName.consume_front("\01");
2382+
std::array<StringRef, 2> nameItems = {
2383+
PredefinedExpr::getIdentKindName(e->getIdentKind()), fnName};
2384+
std::string gvName = llvm::join(nameItems, ".");
2385+
if (isa_and_nonnull<BlockDecl>(curCodeDecl))
2386+
cgm.errorNYI(e->getSourceRange(), "predefined lvalue in block");
2387+
2388+
return emitStringLiteralLValue(sl, gvName);
2389+
}
2390+
23752391
/// An LValue is a candidate for having its loads and stores be made atomic if
23762392
/// we are operating under /volatile:ms *and* the LValue itself is volatile and
23772393
/// performing such an operation can be performed without a libcall.

clang/lib/CIR/CodeGen/CIRGenFunction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
815815
return emitMemberExpr(cast<MemberExpr>(e));
816816
case Expr::CompoundLiteralExprClass:
817817
return emitCompoundLiteralLValue(cast<CompoundLiteralExpr>(e));
818+
case Expr::PredefinedExprClass:
819+
return emitPredefinedLValue(cast<PredefinedExpr>(e));
818820
case Expr::BinaryOperatorClass:
819821
return emitBinaryOperatorLValue(cast<BinaryOperator>(e));
820822
case Expr::CompoundAssignOperatorClass: {

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,8 @@ class CIRGenFunction : public CIRGenTypeCache {
12791279
void emitInitializerForField(clang::FieldDecl *field, LValue lhs,
12801280
clang::Expr *init);
12811281

1282+
LValue emitPredefinedLValue(const PredefinedExpr *e);
1283+
12821284
mlir::Value emitPromotedComplexExpr(const Expr *e, QualType promotionType);
12831285

12841286
mlir::Value emitPromotedScalarExpr(const Expr *e, QualType promotionType);
@@ -1473,7 +1475,8 @@ class CIRGenFunction : public CIRGenTypeCache {
14731475

14741476
mlir::Value emitStoreThroughBitfieldLValue(RValue src, LValue dstresult);
14751477

1476-
LValue emitStringLiteralLValue(const StringLiteral *e);
1478+
LValue emitStringLiteralLValue(const StringLiteral *e,
1479+
llvm::StringRef name = ".str");
14771480

14781481
mlir::LogicalResult emitSwitchBody(const clang::Stmt *s);
14791482
mlir::LogicalResult emitSwitchCase(const clang::SwitchCase &s,

clang/lib/CIR/CodeGen/CIRGenModule.cpp

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,32 +1343,36 @@ cir::GlobalOp CIRGenModule::getGlobalForStringLiteral(const StringLiteral *s,
13431343

13441344
mlir::Attribute c = getConstantArrayFromStringLiteral(s);
13451345

1346-
if (getLangOpts().WritableStrings) {
1347-
errorNYI(s->getSourceRange(),
1348-
"getGlobalForStringLiteral: Writable strings");
1349-
}
1350-
1351-
// Mangle the string literal if that's how the ABI merges duplicate strings.
1352-
// Don't do it if they are writable, since we don't want writes in one TU to
1353-
// affect strings in another.
1354-
if (getCXXABI().getMangleContext().shouldMangleStringLiteral(s) &&
1355-
!getLangOpts().WritableStrings) {
1356-
errorNYI(s->getSourceRange(),
1357-
"getGlobalForStringLiteral: mangle string literals");
1358-
}
1359-
1360-
// Unlike LLVM IR, CIR doesn't automatically unique names for globals, so
1361-
// we need to do that explicitly.
1362-
std::string uniqueName = getUniqueGlobalName(name.str());
1363-
mlir::Location loc = getLoc(s->getSourceRange());
1364-
auto typedC = llvm::cast<mlir::TypedAttr>(c);
1365-
cir::GlobalOp gv =
1366-
generateStringLiteral(loc, typedC, cir::GlobalLinkageKind::PrivateLinkage,
1367-
*this, uniqueName, alignment);
1368-
setDSOLocal(static_cast<mlir::Operation *>(gv));
1346+
cir::GlobalOp gv;
1347+
if (!getLangOpts().WritableStrings && constantStringMap.count(c)) {
1348+
gv = constantStringMap[c];
1349+
// The bigger alignment always wins.
1350+
if (!gv.getAlignment() ||
1351+
uint64_t(alignment.getQuantity()) > *gv.getAlignment())
1352+
gv.setAlignmentAttr(getSize(alignment));
1353+
} else {
1354+
// Mangle the string literal if that's how the ABI merges duplicate strings.
1355+
// Don't do it if they are writable, since we don't want writes in one TU to
1356+
// affect strings in another.
1357+
if (getCXXABI().getMangleContext().shouldMangleStringLiteral(s) &&
1358+
!getLangOpts().WritableStrings) {
1359+
errorNYI(s->getSourceRange(),
1360+
"getGlobalForStringLiteral: mangle string literals");
1361+
}
13691362

1370-
assert(!cir::MissingFeatures::sanitizers());
1363+
// Unlike LLVM IR, CIR doesn't automatically unique names for globals, so
1364+
// we need to do that explicitly.
1365+
std::string uniqueName = getUniqueGlobalName(name.str());
1366+
mlir::Location loc = getLoc(s->getSourceRange());
1367+
auto typedC = llvm::cast<mlir::TypedAttr>(c);
1368+
gv = generateStringLiteral(loc, typedC,
1369+
cir::GlobalLinkageKind::PrivateLinkage, *this,
1370+
uniqueName, alignment);
1371+
setDSOLocal(static_cast<mlir::Operation *>(gv));
1372+
constantStringMap[c] = gv;
13711373

1374+
assert(!cir::MissingFeatures::sanitizers());
1375+
}
13721376
return gv;
13731377
}
13741378

clang/lib/CIR/CodeGen/CIRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ class CIRGenModule : public CIRGenTypeCache {
274274
llvm_unreachable("unknown visibility!");
275275
}
276276

277+
llvm::DenseMap<mlir::Attribute, cir::GlobalOp> constantStringMap;
278+
277279
/// Return a constant array for the given string.
278280
mlir::Attribute getConstantArrayFromStringLiteral(const StringLiteral *e);
279281

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -o %t.cir
2+
// RUN: FileCheck %s --input-file=%t.cir --check-prefix=CIR
3+
// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -o %t-cir.ll
4+
// RUN: FileCheck %s --input-file=%t-cir.ll --check-prefix=LLVM
5+
// RUN: %clang_cc1 %s -triple x86_64-unknown-linux-gnu -emit-llvm -o %t.ll
6+
// RUN: FileCheck %s --input-file=%t.ll --check-prefix=OGCG
7+
8+
// CIR: cir.global "private" constant cir_private dso_local @__func__.plainFunction = #cir.const_array<"plainFunction\00" : !cir.array<!s8i x 14>>
9+
// CIR: cir.global "private" constant cir_private dso_local @__PRETTY_FUNCTION__.plainFunction = #cir.const_array<"void plainFunction(void)\00" : !cir.array<!s8i x 25>>
10+
// CIR: cir.global "private" constant cir_private dso_local @__func__.externFunction = #cir.const_array<"externFunction\00" : !cir.array<!s8i x 15>>
11+
// CIR: cir.global "private" constant cir_private dso_local @__PRETTY_FUNCTION__.externFunction = #cir.const_array<"void externFunction(void)\00" : !cir.array<!s8i x 26>>
12+
// CIR: cir.global "private" constant cir_private dso_local @__func__.privateExternFunction = #cir.const_array<"privateExternFunction\00" : !cir.array<!s8i x 22>>
13+
// CIR: cir.global "private" constant cir_private dso_local @__PRETTY_FUNCTION__.privateExternFunction = #cir.const_array<"void privateExternFunction(void)\00" : !cir.array<!s8i x 33>>
14+
// CIR: cir.global "private" constant cir_private dso_local @__func__.staticFunction = #cir.const_array<"staticFunction\00" : !cir.array<!s8i x 15>>
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>>
16+
17+
// TODO(cir): These should be unnamed_addr
18+
// LLVM: @__func__.plainFunction = private constant [14 x i8] c"plainFunction\00"
19+
// LLVM: @__PRETTY_FUNCTION__.plainFunction = private constant [25 x i8] c"void plainFunction(void)\00"
20+
// LLVM: @__func__.externFunction = private constant [15 x i8] c"externFunction\00"
21+
// LLVM: @__PRETTY_FUNCTION__.externFunction = private constant [26 x i8] c"void externFunction(void)\00"
22+
// LLVM: @__func__.privateExternFunction = private constant [22 x i8] c"privateExternFunction\00"
23+
// LLVM: @__PRETTY_FUNCTION__.privateExternFunction = private constant [33 x i8] c"void privateExternFunction(void)\00"
24+
// LLVM: @__func__.staticFunction = private constant [15 x i8] c"staticFunction\00"
25+
// LLVM: @__PRETTY_FUNCTION__.staticFunction = private constant [26 x i8] c"void staticFunction(void)\00"
26+
27+
// OGCG: @__func__.plainFunction = private unnamed_addr constant [14 x i8] c"plainFunction\00"
28+
// OGCG: @__PRETTY_FUNCTION__.plainFunction = private unnamed_addr constant [25 x i8] c"void plainFunction(void)\00"
29+
// OGCG: @__func__.externFunction = private unnamed_addr constant [15 x i8] c"externFunction\00"
30+
// OGCG: @__PRETTY_FUNCTION__.externFunction = private unnamed_addr constant [26 x i8] c"void externFunction(void)\00"
31+
// OGCG: @__func__.privateExternFunction = private unnamed_addr constant [22 x i8] c"privateExternFunction\00"
32+
// OGCG: @__PRETTY_FUNCTION__.privateExternFunction = private unnamed_addr constant [33 x i8] c"void privateExternFunction(void)\00"
33+
// OGCG: @__func__.staticFunction = private unnamed_addr constant [15 x i8] c"staticFunction\00"
34+
// OGCG: @__PRETTY_FUNCTION__.staticFunction = private unnamed_addr constant [26 x i8] c"void staticFunction(void)\00"
35+
36+
int printf(const char *, ...);
37+
38+
void plainFunction(void) {
39+
printf("__func__ %s\n", __func__);
40+
printf("__FUNCTION__ %s\n", __FUNCTION__);
41+
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
42+
}
43+
44+
extern void externFunction(void) {
45+
printf("__func__ %s\n", __func__);
46+
printf("__FUNCTION__ %s\n", __FUNCTION__);
47+
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
48+
}
49+
50+
__private_extern__ void privateExternFunction(void) {
51+
printf("__func__ %s\n", __func__);
52+
printf("__FUNCTION__ %s\n", __FUNCTION__);
53+
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
54+
}
55+
56+
// TODO(cir): Add support for __captured_stmt
57+
58+
static void staticFunction(void) {
59+
printf("__func__ %s\n", __func__);
60+
printf("__FUNCTION__ %s\n", __FUNCTION__);
61+
printf("__PRETTY_FUNCTION__ %s\n\n", __PRETTY_FUNCTION__);
62+
}
63+
64+
int main(void) {
65+
plainFunction();
66+
externFunction();
67+
privateExternFunction();
68+
staticFunction();
69+
70+
return 0;
71+
}

0 commit comments

Comments
 (0)