From 1edc6541038297c54939d02433df052b9d979c57 Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Thu, 16 Jan 2020 11:56:41 +0100 Subject: [PATCH] Implement -fsemantic-interposition First attempt at implementing -fsemantic-interposition. Rely on GlobalValue::isInterposable that already captures most of the expected behavior. Rely on a ModuleFlag to state whether we should respect SemanticInterposition or not. The default remains no. So this should be a no-op if -fsemantic-interposition isn't used, and if it is, isInterposable being already used in most optimisation, they should honor it properly. Note that it only impacts architecture compiled with -fPIC and no pie. Differential Revision: https://reviews.llvm.org/D72829 --- include/llvm/IR/GlobalValue.h | 8 +++--- include/llvm/IR/Module.h | 6 +++++ lib/IR/Globals.cpp | 7 +++++ lib/IR/Module.cpp | 14 ++++++++++ lib/IR/Verifier.cpp | 7 +++++ .../Inline/inline-semantic-interposition.ll | 26 +++++++++++++++++++ .../module-flags-semantic-interposition.ll | 12 +++++++++ 7 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 test/Transforms/Inline/inline-semantic-interposition.ll create mode 100644 test/Verifier/module-flags-semantic-interposition.ll diff --git a/include/llvm/IR/GlobalValue.h b/include/llvm/IR/GlobalValue.h index 0171356914d..89adf5e5cee 100644 --- a/include/llvm/IR/GlobalValue.h +++ b/include/llvm/IR/GlobalValue.h @@ -423,10 +423,10 @@ public: } /// Return true if this global's definition can be substituted with an - /// *arbitrary* definition at link time. We cannot do any IPO or inlinining - /// across interposable call edges, since the callee can be replaced with - /// something arbitrary at link time. - bool isInterposable() const { return isInterposableLinkage(getLinkage()); } + /// *arbitrary* definition at link time or load time. We cannot do any IPO or + /// inlining across interposable call edges, since the callee can be + /// replaced with something arbitrary. + bool isInterposable() const; bool hasExternalLinkage() const { return isExternalLinkage(getLinkage()); } bool hasAvailableExternallyLinkage() const { diff --git a/include/llvm/IR/Module.h b/include/llvm/IR/Module.h index 71e67b4bedc..c65113a6f3e 100644 --- a/include/llvm/IR/Module.h +++ b/include/llvm/IR/Module.h @@ -848,6 +848,12 @@ public: Metadata *getProfileSummary(bool IsCS); /// @} + /// Returns whether semantic interposition is to be respected. + bool getSemanticInterposition() const; + + /// Set whether semantic interposition is to be respected. + void setSemanticInterposition(bool); + /// Returns true if PLT should be avoided for RTLib calls. bool getRtLibUseGOT() const; diff --git a/lib/IR/Globals.cpp b/lib/IR/Globals.cpp index 9a07a689e88..344fda36ea6 100644 --- a/lib/IR/Globals.cpp +++ b/lib/IR/Globals.cpp @@ -94,6 +94,13 @@ void GlobalValue::eraseFromParent() { llvm_unreachable("not a global"); } +bool GlobalValue::isInterposable() const { + if (isInterposableLinkage(getLinkage())) + return true; + return getParent() && getParent()->getSemanticInterposition() && + !isDSOLocal(); +} + unsigned GlobalValue::getAlignment() const { if (auto *GA = dyn_cast(this)) { // In general we cannot compute this at the IR level, but we try. diff --git a/lib/IR/Module.cpp b/lib/IR/Module.cpp index 3b351763900..c2083f5db89 100644 --- a/lib/IR/Module.cpp +++ b/lib/IR/Module.cpp @@ -555,6 +555,20 @@ Metadata *Module::getProfileSummary(bool IsCS) { : getModuleFlag("ProfileSummary")); } +bool Module::getSemanticInterposition() const { + Metadata *MF = getModuleFlag("SemanticInterposition"); + + auto *Val = cast_or_null(MF); + if (!Val) + return false; + + return cast(Val->getValue())->getZExtValue(); +} + +void Module::setSemanticInterposition(bool SI) { + addModuleFlag(ModFlagBehavior::Error, "SemanticInterposition", SI); +} + void Module::setOwnedMemoryBuffer(std::unique_ptr MB) { OwnedMemoryBuffer = std::move(MB); } diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index 4eef66ffe36..6698a6860b3 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -1476,6 +1476,13 @@ Verifier::visitModuleFlag(const MDNode *Op, "'Linker Options' named metadata no longer supported"); } + if (ID->getString() == "SemanticInterposition") { + ConstantInt *Value = + mdconst::dyn_extract_or_null(Op->getOperand(2)); + Assert(Value, + "SemanticInterposition metadata requires constant integer argument"); + } + if (ID->getString() == "CG Profile") { for (const MDOperand &MDO : cast(Op->getOperand(2))->operands()) visitModuleFlagCGProfileEntry(MDO); diff --git a/test/Transforms/Inline/inline-semantic-interposition.ll b/test/Transforms/Inline/inline-semantic-interposition.ll new file mode 100644 index 00000000000..234136e7ca3 --- /dev/null +++ b/test/Transforms/Inline/inline-semantic-interposition.ll @@ -0,0 +1,26 @@ +; Check that @callee1 gets inlined while @callee2 is not, because of +; SemanticInterposition. + +; RUN: opt < %s -inline -S | FileCheck %s + +define internal i32 @callee1(i32 %A) { + ret i32 %A +} + +define i32 @callee2(i32 %A) { + ret i32 %A +} + +; CHECK-LABEL: @caller +define i32 @caller(i32 %A) { +; CHECK-NOT: call i32 @callee1(i32 %A) + %A1 = call i32 @callee1(i32 %A) +; CHECK: %A2 = call i32 @callee2(i32 %A) + %A2 = call i32 @callee2(i32 %A) +; CHECK: add i32 %A, %A2 + %R = add i32 %A1, %A2 + ret i32 %R +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"SemanticInterposition", i32 1} diff --git a/test/Verifier/module-flags-semantic-interposition.ll b/test/Verifier/module-flags-semantic-interposition.ll new file mode 100644 index 00000000000..2c209e5c58c --- /dev/null +++ b/test/Verifier/module-flags-semantic-interposition.ll @@ -0,0 +1,12 @@ +; RUN: not llvm-as < %s -o /dev/null 2>&1 | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = dso_local global i32 1, align 4 + +!llvm.module.flags = !{!0} + +!0 = !{i32 1, !"SemanticInterposition", float 1.} + +; CHECK: SemanticInterposition metadata requires constant integer argument