-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[CIR] Add support for emitting predefined expressions #161757
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This adds support for emitting predefined expressions (such as __func__) as l-values.
@llvm/pr-subscribers-clangir @llvm/pr-subscribers-clang Author: Andy Kaylor (andykaylor) ChangesThis adds support for emitting predefined expressions (such as func) as l-values. Full diff: https://github.com/llvm/llvm-project/pull/161757.diff 6 Files Affected:
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;
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize you're picking the description of predefinedexpr out of the documentation (though pretty sure you got it wrong :D) , but these are the 'special' macro-like-things that tell you SOMETHING about the name of a function, etc.
So:
__func__
__FUNCTION__
__FUNCDNAME__
L__FUNCTION__
__PRETTY_FUNCTION__
__FUNCSIG__
and
L__FUNCSIG__
Other than that + the suggestion on cleaning that up a tad, LGTM.
clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Outdated
auto fn = cast<cir::FuncOp>(curFn); | ||
StringRef fnName = fn.getName(); | ||
fnName.consume_front("\01"); | ||
StringRef nameItems[] = {PredefinedExpr::getIdentKindName(e->getIdentKind()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we just make this a std::array<StringRef,2> here? That way we can use the range-version of llvm::join and not have the magic 2 there (and yes, i know we'd have it HERE, but at least then the compiler would figure it out).
Do you mean my PR description got it wrong? I can expand it a bit to say something meaningful I suppose. Otherwise, my description actually does reference |
Right, yeah, expouse a little and use the tildes to make sure it doesn't eat the underscores. Future people will thank us :) |
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.