Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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()),
Copy link
Collaborator

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).

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.
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down
52 changes: 28 additions & 24 deletions clang/lib/CIR/CodeGen/CIRGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
71 changes: 71 additions & 0 deletions clang/test/CIR/CodeGen/predefined-expr.c
Original file line number Diff line number Diff line change
@@ -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;
}