[llvm] eec6d87 - [Attributor] Deduce attributes for non-exact functions
Johannes Doerfert via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 4 09:36:23 PDT 2020
Author: Luofan Chen
Date: 2020-04-04T11:34:58-05:00
New Revision: eec6d87626e7528d5ffb3609f30fe7f1b00e30a0
URL: https://github.com/llvm/llvm-project/commit/eec6d87626e7528d5ffb3609f30fe7f1b00e30a0
DIFF: https://github.com/llvm/llvm-project/commit/eec6d87626e7528d5ffb3609f30fe7f1b00e30a0.diff
LOG: [Attributor] Deduce attributes for non-exact functions
This patch is based on D63312 and D63319. For now we create shallow wrappers for all functions that are IPO amendable.
See also [this github issue](https://github.com/llvm/llvm-project/issues/172).
Reviewed By: jdoerfert
Differential Revision: https://reviews.llvm.org/D76404
Added:
llvm/test/Transforms/Attributor/wrapper.ll
Modified:
llvm/lib/Transforms/IPO/Attributor.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp
index 6a148f991b4e..fe8ce92e66c5 100644
--- a/llvm/lib/Transforms/IPO/Attributor.cpp
+++ b/llvm/lib/Transforms/IPO/Attributor.cpp
@@ -57,6 +57,7 @@ STATISTIC(NumFnWithExactDefinition,
"Number of functions with exact definitions");
STATISTIC(NumFnWithoutExactDefinition,
"Number of functions without exact definitions");
+STATISTIC(NumFnShallowWrapperCreated, "Number of shallow wrappers created");
STATISTIC(NumAttributesTimedOut,
"Number of abstract attributes timed out before fixpoint");
STATISTIC(NumAttributesValidFixpoint,
@@ -184,6 +185,12 @@ static cl::opt<bool> EnableHeapToStack("enable-heap-to-stack-conversion",
static cl::opt<int> MaxHeapToStackSize("max-heap-to-stack-size", cl::init(128),
cl::Hidden);
+static cl::opt<bool>
+ AllowShallowWrappers("attributor-allow-shallow-wrappers", cl::Hidden,
+ cl::desc("Allow the Attributor to create shallow "
+ "wrappers for non-exact definitions."),
+ cl::init(false));
+
/// Logic operators for the change status enum class.
///
///{
@@ -8139,6 +8146,69 @@ ChangeStatus Attributor::run() {
return ManifestChange;
}
+/// Create a shallow wrapper for \p F such that \p F has internal linkage
+/// afterwards. It also sets the original \p F 's name to anonymous
+///
+/// A wrapper is a function with the same type (and attributes) as \p F
+/// that will only call \p F and return the result, if any.
+///
+/// Assuming the declaration of looks like:
+/// rty F(aty0 arg0, ..., atyN argN);
+///
+/// The wrapper will then look as follows:
+/// rty wrapper(aty0 arg0, ..., atyN argN) {
+/// return F(arg0, ..., argN);
+/// }
+///
+static void createShallowWrapper(Function &F) {
+ assert(AllowShallowWrappers &&
+ "Cannot create a wrapper if it is not allowed!");
+ assert(!F.isDeclaration() && "Cannot create a wrapper around a declaration!");
+
+ Module &M = *F.getParent();
+ LLVMContext &Ctx = M.getContext();
+ FunctionType *FnTy = F.getFunctionType();
+
+ Function *Wrapper =
+ Function::Create(FnTy, F.getLinkage(), F.getAddressSpace(), F.getName());
+ F.setName(""); // set the inside function anonymous
+ M.getFunctionList().insert(F.getIterator(), Wrapper);
+
+ F.setLinkage(GlobalValue::InternalLinkage);
+
+ F.replaceAllUsesWith(Wrapper);
+ assert(F.getNumUses() == 0 && "Uses remained after wrapper was created!");
+
+ // Move the COMDAT section to the wrapper.
+ // TODO: Check if we need to keep it for F as well.
+ Wrapper->setComdat(F.getComdat());
+ F.setComdat(nullptr);
+
+ // Copy all metadata and attributes but keep them on F as well.
+ SmallVector<std::pair<unsigned, MDNode *>, 1> MDs;
+ F.getAllMetadata(MDs);
+ for (auto MDIt : MDs)
+ Wrapper->addMetadata(MDIt.first, *MDIt.second);
+ Wrapper->setAttributes(F.getAttributes());
+
+ // Create the call in the wrapper.
+ BasicBlock *EntryBB = BasicBlock::Create(Ctx, "entry", Wrapper);
+
+ SmallVector<Value *, 8> Args;
+ auto FArgIt = F.arg_begin();
+ for (Argument &Arg : Wrapper->args()) {
+ Args.push_back(&Arg);
+ Arg.setName((FArgIt++)->getName());
+ }
+
+ CallInst *CI = CallInst::Create(&F, Args, "", EntryBB);
+ CI->setTailCall(true);
+ CI->addAttribute(AttributeList::FunctionIndex, Attribute::NoInline);
+ ReturnInst::Create(Ctx, CI->getType()->isVoidTy() ? nullptr : CI, EntryBB);
+
+ NumFnShallowWrapperCreated++;
+}
+
bool Attributor::isValidFunctionSignatureRewrite(
Argument &Arg, ArrayRef<Type *> ReplacementTypes) {
@@ -8789,6 +8859,12 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache,
for (Function *F : Functions)
A.initializeInformationCache(*F);
+ // Create shallow wrappers for all functions that are not IPO amendable
+ if (AllowShallowWrappers)
+ for (Function *F : Functions)
+ if (!A.isFunctionIPOAmendable(*F))
+ createShallowWrapper(*F);
+
for (Function *F : Functions) {
if (F->hasExactDefinition())
NumFnWithExactDefinition++;
diff --git a/llvm/test/Transforms/Attributor/wrapper.ll b/llvm/test/Transforms/Attributor/wrapper.ll
new file mode 100644
index 000000000000..f965dbee2c73
--- /dev/null
+++ b/llvm/test/Transforms/Attributor/wrapper.ll
@@ -0,0 +1,88 @@
+; RUN: opt -passes=attributor-cgscc -attributor-disable=false -attributor-annotate-decl-cs -attributor-allow-shallow-wrappers -S < %s | FileCheck %s --check-prefix=CHECK
+
+; TEST 1: simple test, without argument
+; A wrapper will be generated for this function, Check the wrapper first
+; CHECK-NOT: Function Attrs:
+; CHECK: define linkonce i32 @inner1()
+; CHECK: tail call i32 @0()
+; CHECK: ret
+;
+; Check the original function, which is wrapped and becomes anonymous
+; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; CHECK: define internal i32 @0()
+; CHECK: %a = alloca i32
+; CHECK: store i32 1, i32* %a
+; CHECK: %b = load i32, i32* %a
+; CHECK: ret i32 %b
+define linkonce i32 @inner1() {
+entry:
+ %a = alloca i32
+ store i32 1, i32* %a
+ %b = load i32, i32* %a
+ ret i32 %b
+}
+
+; Check for call
+; CHECK: define i32 @outer1
+; CHECK: call i32 @inner1
+; CHECK: ret
+define i32 @outer1() {
+entry:
+ %ret = call i32 @inner1()
+ ret i32 %ret
+}
+
+; TEST 2: with argument
+; CHECK-NOT: Function Attrs
+; CHECK: define linkonce i32 @inner2(i32 %a, i32 %b)
+; CHECK: tail call i32 @1(i32 %a, i32 %b)
+; CHECK: ret
+;
+; CHECK: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; CHECK: define internal i32 @1(i32 %a, i32 %b)
+; CHECK: %c = add i32 %a, %b
+; CHECK: ret i32 %c
+define linkonce i32 @inner2(i32 %a, i32 %b) {
+entry:
+ %c = add i32 %a, %b
+ ret i32 %c
+}
+
+; CHECK: define i32 @outer2
+; CHECK: call i32 @inner2
+; CHECK: ret
+define i32 @outer2() {
+entry:
+ %ret = call i32 @inner2(i32 1, i32 2)
+ ret i32 %ret
+}
+
+; TEST 3: check nocurse
+; This function calls itself, there will be no attribute
+; CHECK-NOT: Function Attrs
+; CHECK: define linkonce i32 @inner3(i32 %0)
+; CHECK: tail call i32 @2(i32 %0)
+; CHECK: ret
+;
+; CHECK-NOT: Function Attrs:
+; CHECK: define internal i32 @2(i32 %0)
+define linkonce i32 @inner3(i32) {
+entry:
+ %1 = alloca i32
+ store i32 %0, i32* %1
+ br label %2
+2:
+ %3 = load i32, i32* %1
+ %4 = icmp slt i32 %3, 4
+ br i1 %4, label %5, label %9
+5:
+ %6 = load i32, i32* %1
+ %7 = add nsw i32 %6, 1
+ %8 = call i32 @inner3(i32 %7)
+ store i32 %8, i32* %1
+ br label %2
+9:
+ %10 = load i32, i32* %1
+ ret i32 %10
+}
+
More information about the llvm-commits
mailing list