Author: Fangrui Song Date: 2020-05-25T20:48:18-07:00 New Revision: 9d55e4ee1367b440bb8402ce3a33d5a8b99aee06
URL: https://github.com/llvm/llvm-project/commit/9d55e4ee1367b440bb8402ce3a33d5a8b99aee06 DIFF: https://github.com/llvm/llvm-project/commit/9d55e4ee1367b440bb8402ce3a33d5a8b99aee06.diff LOG: Make explicit -fno-semantic-interposition (in -fpic mode) infer dso_local -fno-semantic-interposition is currently the CC1 default. (The opposite disables some interprocedural optimizations.) However, it does not infer dso_local: on most targets accesses to ExternalLinkage functions/variables defined in the current module still need PLT/GOT. This patch makes explicit -fno-semantic-interposition infer dso_local, so that PLT/GOT can be eliminated if targets implement local aliases for AsmPrinter::getSymbolPreferLocal (currently only x86). Currently we check whether the module flag "SemanticInterposition" is 0. If yes, infer dso_local. In the future, we can infer dso_local unless "SemanticInterposition" is 1: frontends other than clang will also benefit from the optimization if they don't bother setting the flag. (There will be risks if they do want ELF interposition: they need to set "SemanticInterposition" to 1.) Added: llvm/test/CodeGen/X86/semantic-interposition-infer-dsolocal.ll Modified: clang/include/clang/Basic/LangOptions.def clang/include/clang/Driver/Options.td clang/lib/CodeGen/CodeGenModule.cpp clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Frontend/CompilerInvocation.cpp clang/test/CodeGen/semantic-interposition.c clang/test/Driver/fsemantic-interposition.c llvm/include/llvm/IR/GlobalValue.h llvm/include/llvm/IR/Module.h llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp llvm/lib/IR/Globals.cpp llvm/lib/IR/Module.cpp llvm/lib/Target/TargetMachine.cpp Removed: ################################################################################ diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index e94305da46ba..6e72b47f489b 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -301,6 +301,7 @@ ENUM_LANGOPT(TypeVisibilityMode, Visibility, 3, DefaultVisibility, LANGOPT(SetVisibilityForExternDecls, 1, 0, "apply global symbol visibility to external declarations without an explicit visibility") BENIGN_LANGOPT(SemanticInterposition , 1, 0, "semantic interposition") +BENIGN_LANGOPT(ExplicitNoSemanticInterposition, 1, 0, "explicitly no semantic interposition") ENUM_LANGOPT(StackProtector, StackProtectorMode, 2, SSPOff, "stack protector mode") ENUM_LANGOPT(TrivialAutoVarInit, TrivialAutoVarInitKind, 2, TrivialAutoVarInitKind::Uninitialized, diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 7213af1731c1..e88e6cf8a130 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -3371,7 +3371,7 @@ defm ipa_cp : BooleanFFlag<"ipa-cp">, Group<clang_ignored_gcc_optimization_f_Group>; defm ivopts : BooleanFFlag<"ivopts">, Group<clang_ignored_gcc_optimization_f_Group>; def fsemantic_interposition : Flag<["-"], "fsemantic-interposition">, Group<f_Group>, Flags<[CC1Option]>; -def fno_semantic_interposition: Flag<["-"], "fno-semantic-interposition">, Group<f_Group>; +def fno_semantic_interposition: Flag<["-"], "fno-semantic-interposition">, Group<f_Group>, Flags<[CC1Option]>; defm non_call_exceptions : BooleanFFlag<"non-call-exceptions">, Group<clang_ignored_f_Group>; defm peel_loops : BooleanFFlag<"peel-loops">, Group<clang_ignored_gcc_optimization_f_Group>; defm permissive : BooleanFFlag<"permissive">, Group<clang_ignored_f_Group>; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 8ba7fb756ada..f43bc6434daf 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -493,6 +493,9 @@ void CodeGenModule::Release() { if (Context.getLangOpts().SemanticInterposition) // Require various optimization to respect semantic interposition. getModule().setSemanticInterposition(1); + else if (Context.getLangOpts().ExplicitNoSemanticInterposition) + // Allow dso_local on applicable targets. + getModule().setSemanticInterposition(0); if (CodeGenOpts.EmitCodeView) { // Indicate that we want CodeView in the metadata. diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index deb60ed68cfc..f33983db3e1e 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4471,10 +4471,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } - if (Args.hasFlag(options::OPT_fsemantic_interposition, - options::OPT_fno_semantic_interposition, false) && - RelocationModel != llvm::Reloc::Static && !IsPIE) - CmdArgs.push_back("-fsemantic-interposition"); + // The default is -fno-semantic-interposition. We render it just because we + // require explicit -fno-semantic-interposition to infer dso_local. + if (Arg *A = Args.getLastArg(options::OPT_fsemantic_interposition, + options::OPT_fno_semantic_interposition)) + if (RelocationModel != llvm::Reloc::Static && !IsPIE) + A->render(Args, CmdArgs); CmdArgs.push_back("-mthread-model"); if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) { diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b4bc027e832b..f98490cd9a11 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3049,6 +3049,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, } Opts.SemanticInterposition = Args.hasArg(OPT_fsemantic_interposition); + // An explicit -fno-semantic-interposition infers dso_local. + Opts.ExplicitNoSemanticInterposition = + Args.hasArg(OPT_fno_semantic_interposition); // -mrtd option if (Arg *A = Args.getLastArg(OPT_mrtd)) { diff --git a/clang/test/CodeGen/semantic-interposition.c b/clang/test/CodeGen/semantic-interposition.c index 43656e36021f..3d6c5f2872b5 100644 --- a/clang/test/CodeGen/semantic-interposition.c +++ b/clang/test/CodeGen/semantic-interposition.c @@ -1,5 +1,9 @@ // RUN: %clang_cc1 -emit-llvm -fsemantic-interposition %s -o - | FileCheck --check-prefix=INTERPOSITION %s // RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck --check-prefix=NO %s +/// With explicit -fno-semantic-interposition, add a module flag to inform the +/// backend that dso_local can be inferred. +// RUN: %clang_cc1 -emit-llvm -fno-semantic-interposition %s -o - | FileCheck --check-prefix=EXPLICIT_NO %s // INTERPOSITION: !{{[0-9]+}} = !{i32 1, !"SemanticInterposition", i32 1} // NO-NOT: "SemanticInterposition" +// EXPLICIT_NO: !{{[0-9]+}} = !{i32 1, !"SemanticInterposition", i32 0} diff --git a/clang/test/Driver/fsemantic-interposition.c b/clang/test/Driver/fsemantic-interposition.c index 20bc2c6f7270..af3e7575a799 100644 --- a/clang/test/Driver/fsemantic-interposition.c +++ b/clang/test/Driver/fsemantic-interposition.c @@ -2,8 +2,12 @@ // RUN: %clang -target x86_64 %s -Werror -fPIC -fsemantic-interposition -c -### 2>&1 | FileCheck %s // CHECK: "-fsemantic-interposition" -// RUN: %clang -target x86_64 %s -Werror -fPIC -fsemantic-interposition -fno-semantic-interposition -c -### 2>&1 | FileCheck --check-prefix=NO %s +/// Require explicit -fno-semantic-interposition to infer dso_local. +// RUN: %clang -target x86_64 %s -Werror -fPIC -fsemantic-interposition -fno-semantic-interposition -c -### 2>&1 | FileCheck --check-prefix=EXPLICIT_NO %s +// EXPLICIT_NO: "-fno-semantic-interposition" + // RUN: %clang -target x86_64 %s -Werror -fsemantic-interposition -c -### 2>&1 | FileCheck --check-prefix=NO %s // RUN: %clang -target x86_64 %s -Werror -fPIC -c -### 2>&1 | FileCheck --check-prefix=NO %s // RUN: %clang -target x86_64 %s -Werror -fPIE -fsemantic-interposition -c -### 2>&1 | FileCheck --check-prefix=NO %s // NO-NOT: "-fsemantic-interposition" +// NO-NOT: "-fno-semantic-interposition" diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h index 398eca2d9b2e..1c19011c9131 100644 --- a/llvm/include/llvm/IR/GlobalValue.h +++ b/llvm/include/llvm/IR/GlobalValue.h @@ -427,6 +427,7 @@ class GlobalValue : public Constant { /// inlining across interposable call edges, since the callee can be /// replaced with something arbitrary. bool isInterposable() const; + bool canBenefitFromLocalAlias() const; bool hasExternalLinkage() const { return isExternalLinkage(getLinkage()); } bool hasAvailableExternallyLinkage() const { diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h index 3052651a3722..ead003007904 100644 --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -857,6 +857,7 @@ class Module { /// Returns whether semantic interposition is to be respected. bool getSemanticInterposition() const; + bool noSemanticInterposition() const; /// Set whether semantic interposition is to be respected. void setSemanticInterposition(bool); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index db458e2b8a92..5fba0f01ba52 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -462,10 +462,10 @@ MCSymbol *AsmPrinter::getSymbolPreferLocal(const GlobalValue &GV) const { // assembler would otherwise be conservative and assume a global default // visibility symbol can be interposable, even if the code generator already // assumed it. - if (TM.getTargetTriple().isOSBinFormatELF() && - GlobalObject::isExternalLinkage(GV.getLinkage()) && GV.isDSOLocal() && - !GV.isDeclaration() && !isa<GlobalIFunc>(GV) && !GV.hasComdat()) - return getSymbolWithGlobalValueBase(&GV, "$local"); + if (TM.getTargetTriple().isOSBinFormatELF() && GV.canBenefitFromLocalAlias()) + if (GV.isDSOLocal() || (TM.getTargetTriple().isX86() && + GV.getParent()->noSemanticInterposition())) + return getSymbolWithGlobalValueBase(&GV, "$local"); return TM.getSymbol(&GV); } diff --git a/llvm/lib/IR/Globals.cpp b/llvm/lib/IR/Globals.cpp index 7c1c682d0262..eefd221ec389 100644 --- a/llvm/lib/IR/Globals.cpp +++ b/llvm/lib/IR/Globals.cpp @@ -101,6 +101,12 @@ bool GlobalValue::isInterposable() const { !isDSOLocal(); } +bool GlobalValue::canBenefitFromLocalAlias() const { + // See AsmPrinter::getSymbolPreferLocal(). + return GlobalObject::isExternalLinkage(getLinkage()) && !isDeclaration() && + !isa<GlobalIFunc>(this) && !hasComdat(); +} + unsigned GlobalValue::getAlignment() const { if (auto *GA = dyn_cast<GlobalAlias>(this)) { // In general we cannot compute this at the IR level, but we try. diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp index 9ac1edb2519d..1416cdce9974 100644 --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -600,6 +600,13 @@ void Module::setSemanticInterposition(bool SI) { addModuleFlag(ModFlagBehavior::Error, "SemanticInterposition", SI); } +bool Module::noSemanticInterposition() const { + // Conservatively require an explicit zero value for now. + Metadata *MF = getModuleFlag("SemanticInterposition"); + auto *Val = cast_or_null<ConstantAsMetadata>(MF); + return Val && cast<ConstantInt>(Val->getValue())->getZExtValue() == 0; +} + void Module::setOwnedMemoryBuffer(std::unique_ptr<MemoryBuffer> MB) { OwnedMemoryBuffer = std::move(MB); } diff --git a/llvm/lib/Target/TargetMachine.cpp b/llvm/lib/Target/TargetMachine.cpp index 1de6e871569c..074e9fde79e6 100644 --- a/llvm/lib/Target/TargetMachine.cpp +++ b/llvm/lib/Target/TargetMachine.cpp @@ -193,6 +193,14 @@ bool TargetMachine::shouldAssumeDSOLocal(const Module &M, // Check if we can use copy relocations. if (!(GV && GV->isThreadLocal()) && RM == Reloc::Static) return true; + } else if (TT.isOSBinFormatELF()) { + // If dso_local allows AsmPrinter::getSymbolPreferLocal to use a local + // alias, set the flag. We cannot set dso_local for other global values, + // because otherwise direct accesses to a probably interposable symbol (even + // if the codegen assumes not) will be rejected by the linker. + if (!GV || !GV->canBenefitFromLocalAlias()) + return false; + return TT.isX86() && M.noSemanticInterposition(); } // ELF & wasm support preemption of other symbols. diff --git a/llvm/test/CodeGen/X86/semantic-interposition-infer-dsolocal.ll b/llvm/test/CodeGen/X86/semantic-interposition-infer-dsolocal.ll new file mode 100644 index 000000000000..a0391d036468 --- /dev/null +++ b/llvm/test/CodeGen/X86/semantic-interposition-infer-dsolocal.ll @@ -0,0 +1,46 @@ +; RUN: llc -mtriple=x86_64 -relocation-model=pic < %s | FileCheck %s + +;; With a module flag SemanticInterposition=0, infer dso_local flags even if PIC. +;; Local aliases will be generated for applicable variables and functions. + +@var = global i32 0, align 4 + +@ifunc = ifunc i32 (), bitcast (i32 ()* ()* @ifunc_resolver to i32 ()*) + +define i32 @ifunc_impl() { +entry: + ret i32 0 +} + +define i32 ()* @ifunc_resolver() { +entry: + ret i32 ()* @ifunc_impl +} + +declare i32 @external() + +define i32 @func() { + ret i32 0 +} + +;; Don't set dso_local on declarations or ifuncs. +define i32 @foo() { +; CHECK: movl .Lvar$local(%rip), %ebp +; CHECK: callq external@PLT +; CHECK: callq ifunc@PLT +; CHECK: callq .Lfunc$local{{$}} +entry: + %0 = load i32, i32* @var, align 4 + %call = tail call i32 @external() + %add = add nsw i32 %call, %0 + %call1 = tail call i32 @ifunc() + %add2 = add nsw i32 %add, %call1 + %call2 = tail call i32 @func() + %add3 = add nsw i32 %add, %call2 + ret i32 %add3 +} + +!llvm.module.flags = !{!0, !1} + +!0 = !{i32 1, !"SemanticInterposition", i32 0} +!1 = !{i32 7, !"PIC Level", i32 2} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits