diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index fd75de42515da..e44d9d3c6691c 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -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()) { + if (EA->isError()) + dyn_cast(CalleePtr)->addFnAttr("dontcall-error", + EA->getUserDiagnostic()); + else if (EA->isWarning()) + dyn_cast(CalleePtr)->addFnAttr("dontcall-warn", + EA->getUserDiagnostic()); + } + } + // 3. Perform the actual call. // Deactivate any cleanups that we're supposed to do immediately before diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 16688810d0685..35aa35cc02a42 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -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 &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(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(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(AD.getDecl()); + const AliasAttr *AA = D->getAttr(); + if (AA && AA->getAliasee() == ND->getName()) + return true; + } + return false; +} + void CodeGenModule::EmitGlobal(GlobalDecl GD) { const auto *Global = cast(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. + 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(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(GVDef); + } else { + GA = llvm::Function::Create(Fn->getFunctionType(), + llvm::GlobalValue::InternalLinkage, + II->getName(), &getModule()); + GA->setAttributes(Fn->getAttributes()); + } + if (D->hasAttr() || D->hasAttr()) { + 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 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(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()) AddGlobalCtor(Fn, CA->getPriority()); if (const DestructorAttr *DA = D->getAttr()) @@ -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(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); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 1b67d4354efc0..e7d3f0276566c 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -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 EmittedCompoundLiterals; diff --git a/clang/test/CodeGen/unique-internal-linkage-names-alias.c b/clang/test/CodeGen/unique-internal-linkage-names-alias.c new file mode 100644 index 0000000000000..4eaac7c7b8f98 --- /dev/null +++ b/clang/test/CodeGen/unique-internal-linkage-names-alias.c @@ -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;}