Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
18 changes: 18 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5741,6 +5741,24 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
IRFuncTy = OrigFn->getFunctionType();
}

// Propogate Error Attribute if Callee is declared within the function body
// e.g.
// void foo() {
// __extern__ void nocall(void) __attribute__((__error__(msg)));
// if (nobranch)
// nocall();
// }
if (CalleePtr && CalleeDecl) {
if (const auto *EA = CalleeDecl->getAttr<ErrorAttr>()) {
if (EA->isError())
dyn_cast<llvm::Function>(CalleePtr)->addFnAttr("dontcall-error",
EA->getUserDiagnostic());
else if (EA->isWarning())
dyn_cast<llvm::Function>(CalleePtr)->addFnAttr("dontcall-warn",
EA->getUserDiagnostic());
}
}

// 3. Perform the actual call.

// Deactivate any cleanups that we're supposed to do immediately before
Expand Down
110 changes: 105 additions & 5 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -588,8 +588,9 @@ static const llvm::GlobalValue *getAliasedGlobal(const llvm::GlobalValue *GV) {
}

static bool checkAliasedGlobal(
const ASTContext &Context, DiagnosticsEngine &Diags, SourceLocation Location,
bool IsIFunc, const llvm::GlobalValue *Alias, const llvm::GlobalValue *&GV,
const CodeGenModule *CGM, const ASTContext &Context,
DiagnosticsEngine &Diags, SourceLocation Location, bool IsIFunc,
const llvm::GlobalValue *Alias, const llvm::GlobalValue *&GV,
const llvm::MapVector<GlobalDecl, StringRef> &MangledDeclNames,
SourceRange AliasRange) {
GV = getAliasedGlobal(Alias);
Expand All @@ -598,6 +599,23 @@ static bool checkAliasedGlobal(
return false;
}

// Only resolve unique internal linkage symbols for C code
if (!CGM->getLangOpts().CPlusPlus) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this C-only? Consider something like:

long bar(const struct A*p) __attribute__((__alias__("foo")));
namespace {
extern "C" long foo(const struct A*p) {return 1;}
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, we are trying to build a codebase written entirely in C... I'm not too sure how namespace and extern "C" would translate in C tho...

for (const auto &[Decl, Name] : MangledDeclNames) {
if (const auto *ND = dyn_cast<NamedDecl>(Decl.getDecl())) {
IdentifierInfo *II = ND->getIdentifier();
if (II && II->getName() == GV->getName() &&
Name.contains(llvm::FunctionSamples::UniqSuffix)) {
GlobalDecl GD;
if (CGM->lookupRepresentativeDecl(Name, GD)) {
GV = CGM->getModule().getNamedValue(Name);
break;
}
}
}
}
}

if (GV->hasCommonLinkage()) {
const llvm::Triple &Triple = Context.getTargetInfo().getTriple();
if (Triple.getObjectFormat() == llvm::Triple::XCOFF) {
Expand Down Expand Up @@ -687,8 +705,8 @@ void CodeGenModule::checkAliases() {
StringRef MangledName = getMangledName(GD);
llvm::GlobalValue *Alias = GetGlobalValue(MangledName);
const llvm::GlobalValue *GV = nullptr;
if (!checkAliasedGlobal(getContext(), Diags, Location, IsIFunc, Alias, GV,
MangledDeclNames, Range)) {
if (!checkAliasedGlobal(this, getContext(), Diags, Location, IsIFunc, Alias,
GV, MangledDeclNames, Range)) {
Error = true;
continue;
}
Expand Down Expand Up @@ -3884,6 +3902,22 @@ bool CodeGenModule::shouldEmitCUDAGlobalVar(const VarDecl *Global) const {
Global->getType()->isCUDADeviceBuiltinTextureType();
}

bool CodeGenModule::shouldEmitUniqLinkageName(GlobalDecl GD) {
const auto *ND = dyn_cast<FunctionDecl>(GD.getDecl());
if (!ND || !getCXXABI().getMangleContext().shouldMangleDeclName(ND))
return false;
StringRef MangledName = getMangledName(GD);
if (!MangledName.contains(llvm::FunctionSamples::UniqSuffix))
return false;
for (const GlobalDecl &AD : Aliases) {
const auto *D = cast<ValueDecl>(AD.getDecl());
const AliasAttr *AA = D->getAttr<AliasAttr>();
if (AA && AA->getAliasee() == ND->getName())
return true;
}
return false;
}

void CodeGenModule::EmitGlobal(GlobalDecl GD) {
const auto *Global = cast<ValueDecl>(GD.getDecl());

Expand Down Expand Up @@ -4046,6 +4080,10 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
// The value must be emitted, but cannot be emitted eagerly.
assert(!MayBeEmittedEagerly(Global));
addDeferredDeclToEmit(GD);
} else if (!getLangOpts().CPlusPlus && shouldEmitUniqLinkageName(GD)) {
// Emit static C function that is mangled with
// -funique-internal-linkage-names.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really happy with this. The code for deferred declarations and diagnosing name conflicts is complicated enough without adding the possibility that the name of a declaration can change later.

Can we just suppress mangling in cases where we reference a symbol without knowing if it's internal, then it turns out to be internal later?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is we need -funique-internal-linkage-names to keep all the static function symbols unique... It is to make sure that we have unique symbols names in the DWARF info after linking. Besides.... it's also a bit weird to specify something like __attribute__((__alias__(_ZL3fooPK1A.__uniq.43626431813877880438002914689114607187))) in the C Code.. It's only a problem with attribute alias tho... Do you think we should add more unit tests for this change?

addDeferredDeclToEmit(GD);
} else {
// Otherwise, remember that we saw a deferred decl with this name. The
// first use of the mangled name will cause it to move into
Expand Down Expand Up @@ -6189,6 +6227,51 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
/*DontDefer=*/true,
ForDefinition));

auto *Fn = cast<llvm::Function>(GV);
llvm::Function *GA = nullptr;
if (!getLangOpts().CPlusPlus &&
getCXXABI().getMangleContext().shouldMangleDeclName(D)) {
// -funique-internal-linkage-names may change the symbol name of C function.
// Replace all uses of old symbol with the emitted global value.
if (IdentifierInfo *II = D->getIdentifier()) {
if (II->getName() != GV->getName() &&
GV->getName().contains(llvm::FunctionSamples::UniqSuffix)) {
if (llvm::GlobalValue *GVDef =
getModule().getNamedValue(II->getName())) {
GVDef->replaceAllUsesWith(GV);
GA = dyn_cast<llvm::Function>(GVDef);
} else {
GA = llvm::Function::Create(Fn->getFunctionType(),
llvm::GlobalValue::InternalLinkage,
II->getName(), &getModule());
GA->setAttributes(Fn->getAttributes());
}
if (D->hasAttr<GNUInlineAttr>() || D->hasAttr<AlwaysInlineAttr>()) {
GA->eraseFromParent();
GA = nullptr;
}
// Create a wrapper with the original symbol in case the mangled
// function is referenced in any hardcoded inline assembly
if (GA) {
if (!GA->isDeclaration())
GA->deleteBody();
GA->setLinkage(llvm::GlobalValue::InternalLinkage);
llvm::BasicBlock *BB =
llvm::BasicBlock::Create(GA->getContext(), "", GA);
llvm::SmallVector<llvm::Value *> Args;
for (auto &arg : GA->args())
Args.push_back(&arg);
llvm::CallInst *CI = llvm::CallInst::Create(Fn->getFunctionType(), GV,
Args, "", BB->end());
if (Fn->getReturnType()->isVoidTy())
llvm::ReturnInst::Create(GA->getContext(), BB);
else
llvm::ReturnInst::Create(GA->getContext(), CI, BB->end());
}
}
}
}

// Already emitted.
if (!GV->isDeclaration())
return;
Expand All @@ -6197,7 +6280,6 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
// generating code for it because various parts of IR generation
// want to propagate this information down (e.g. to local static
// declarations).
auto *Fn = cast<llvm::Function>(GV);
setFunctionLinkage(GD, Fn);

// FIXME: this is redundant with part of setFunctionDefinitionAttributes
Expand Down Expand Up @@ -6228,6 +6310,12 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,

SetLLVMFunctionAttributesForDefinition(D, Fn);

// Set Attributes to perserve the internal GlobalValues
if (GA) {
setNonAliasAttributes(GD, GA);
SetLLVMFunctionAttributesForDefinition(D, GA);
}

if (const ConstructorAttr *CA = D->getAttr<ConstructorAttr>())
AddGlobalCtor(Fn, CA->getPriority());
if (const DestructorAttr *DA = D->getAttr<DestructorAttr>())
Expand All @@ -6248,6 +6336,18 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) {
return;
}

// Deferred emit for aliased C function when __attribute__((alias)) might be
// used after the definition of aliasee function
if (!getLangOpts().CPlusPlus) {
for (const auto &[Name, Decl] : DeferredDecls) {
const auto *FD = dyn_cast<FunctionDecl>(Decl.getDecl());
if (FD && FD->getName() == AA->getAliasee() &&
Name.contains(llvm::FunctionSamples::UniqSuffix)) {
addDeferredDeclToEmit(Decl);
}
}
}

// If there is a definition in the module, then it wins over the alias.
// This is dubious, but allow it to be safe. Just ignore the alias.
llvm::GlobalValue *Entry = GetGlobalValue(MangledName);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenModule.h
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,7 @@ class CodeGenModule : public CodeGenTypeCache {
// related attributes.
bool shouldEmitCUDAGlobalVar(const VarDecl *VD) const;
bool shouldOpportunisticallyEmitVTables();
bool shouldEmitUniqLinkageName(GlobalDecl GD);
/// Map used to be sure we don't emit the same CompoundLiteral twice.
llvm::DenseMap<const CompoundLiteralExpr *, llvm::GlobalVariable *>
EmittedCompoundLiterals;
Expand Down
15 changes: 15 additions & 0 deletions clang/test/CodeGen/unique-internal-linkage-names-alias.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux %s -emit-llvm -funique-internal-linkage-names -o - | FileCheck %s

struct A;
static long foo(const struct A*p);

long bar(const struct A*p);
long bar(const struct A*p) __attribute__((__alias__("foo")));

// CHECK: ; Function Attrs: noinline nounwind optnone
// CHECK-NEXT: define internal i64 @foo(ptr noundef %0) #0 {
// CHECK-NEXT: %2 = call i64 @_ZL3fooPK1A.__uniq.[[ATTR:[0-9]+]](ptr %0)
// CHECK-NEXT: ret i64 %2
// CHECK-NEXT: }
// CHECK: define internal i64 @_ZL3fooPK1A.__uniq.[[ATTR:[0-9]+]](ptr noundef %p) #1 {
static long foo(const struct A*p) {return 1;}