1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

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.)
This commit is contained in:
Fangrui Song 2020-05-25 15:05:35 -07:00
parent 11b91362f5
commit b7d65e895d
7 changed files with 73 additions and 4 deletions

View File

@ -427,6 +427,7 @@ public:
/// 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 {

View File

@ -857,6 +857,7 @@ public:
/// 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);

View File

@ -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);
}

View File

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

View File

@ -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);
}

View File

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

View File

@ -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}