-
Notifications
You must be signed in to change notification settings - Fork 15.1k
[Clang] Allow vanilla C function symbol name to be used in __attribute__((alias)) when -funique-internal-linkage-names is specified #145652
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
base: main
Are you sure you want to change the base?
Changes from all commits
9a29dd6
aedff8d
80e7bda
1e116a9
3beeb6a
0003a3f
cab9bf6
18e9543
a81a5c7
cc5b165
7b30a80
75ae162
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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); | ||
|
|
@@ -598,6 +599,23 @@ static bool checkAliasedGlobal( | |
| return false; | ||
| } | ||
|
|
||
| // Only resolve unique internal linkage symbols for C code | ||
| if (!CGM->getLangOpts().CPlusPlus) { | ||
| 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) { | ||
|
|
@@ -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; | ||
| } | ||
|
|
@@ -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()); | ||
|
|
||
|
|
@@ -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. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem is we need |
||
| 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 | ||
|
|
@@ -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; | ||
|
|
@@ -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 | ||
|
|
@@ -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>()) | ||
|
|
@@ -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); | ||
|
|
||
| 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;} |
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.
Is this C-only? Consider something like:
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.
Yup, we are trying to build a codebase written entirely in C... I'm not too sure how
namespaceandextern "C"would translate in C tho...