summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Collingbourne <peter@pcc.me.uk>2015-06-10 21:14:34 +0000
committerPeter Collingbourne <peter@pcc.me.uk>2015-06-10 21:14:34 +0000
commit115fe3762108b7aca37274cb31f10a48d9b35b01 (patch)
tree053d0f65a0b3419b91b2f115362ca7fab301088a
parent95d83959d89df84804500798cb98defc75b9b0be (diff)
downloadbcm5719-llvm-115fe3762108b7aca37274cb31f10a48d9b35b01.tar.gz
bcm5719-llvm-115fe3762108b7aca37274cb31f10a48d9b35b01.zip
ArgumentPromotion: Drop sret attribute on functions that are only called directly.
If the first argument to a function is a 'this' argument and the second has the sret attribute, the ArgumentPromotion pass may promote the 'this' argument to more than one argument, violating the IR constraint that 'sret' may only be applied to the first or second argument. Although this IR constraint is arguably unnecessary, it highlighted the fact that ArgPromotion does not need to preserve this attribute. Dropping the attribute reduces register pressure in the backend by avoiding the register copy required by sret. Because sret implies noalias, we also replace the former with the latter. Differential Revision: http://reviews.llvm.org/D10353 llvm-svn: 239488
-rw-r--r--llvm/lib/IR/Function.cpp4
-rw-r--r--llvm/lib/Transforms/IPO/ArgumentPromotion.cpp18
-rw-r--r--llvm/test/Transforms/ArgumentPromotion/sret.ll28
3 files changed, 47 insertions, 3 deletions
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index cf8e3ed571e..2b439bb46bf 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -154,10 +154,8 @@ bool Argument::hasNoCaptureAttr() const {
/// it in its containing function.
bool Argument::hasStructRetAttr() const {
if (!getType()->isPointerTy()) return false;
- if (this != getParent()->arg_begin())
- return false; // StructRet param must be first param
return getParent()->getAttributes().
- hasAttribute(1, Attribute::StructRet);
+ hasAttribute(getArgNo()+1, Attribute::StructRet);
}
/// hasReturnedAttr - Return true if this argument has the returned attribute on
diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
index c7c57ab5644..440f3f20d61 100644
--- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
+++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
@@ -245,6 +245,24 @@ CallGraphNode *ArgPromotion::PromoteArguments(CallGraphNode *CGN) {
Argument *PtrArg = PointerArgs[i];
Type *AgTy = cast<PointerType>(PtrArg->getType())->getElementType();
+ // Replace sret attribute with noalias. This reduces register pressure by
+ // avoiding a register copy.
+ if (PtrArg->hasStructRetAttr()) {
+ unsigned ArgNo = PtrArg->getArgNo();
+ F->setAttributes(
+ F->getAttributes()
+ .removeAttribute(F->getContext(), ArgNo + 1, Attribute::StructRet)
+ .addAttribute(F->getContext(), ArgNo + 1, Attribute::NoAlias));
+ for (Use &U : F->uses()) {
+ CallSite CS(U.getUser());
+ CS.setAttributes(
+ CS.getAttributes()
+ .removeAttribute(F->getContext(), ArgNo + 1,
+ Attribute::StructRet)
+ .addAttribute(F->getContext(), ArgNo + 1, Attribute::NoAlias));
+ }
+ }
+
// If this is a byval argument, and if the aggregate type is small, just
// pass the elements, which is always safe, if the passed value is densely
// packed or if we can prove the padding bytes are never accessed. This does
diff --git a/llvm/test/Transforms/ArgumentPromotion/sret.ll b/llvm/test/Transforms/ArgumentPromotion/sret.ll
new file mode 100644
index 00000000000..8e5521f48d1
--- /dev/null
+++ b/llvm/test/Transforms/ArgumentPromotion/sret.ll
@@ -0,0 +1,28 @@
+; RUN: opt < %s -argpromotion -S | FileCheck %s
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+; CHECK: define internal void @add(i32 %[[THIS1:.*]], i32 %[[THIS2:.*]], i32* noalias %[[SR:.*]])
+define internal void @add({i32, i32}* %this, i32* sret %r) {
+ %ap = getelementptr {i32, i32}, {i32, i32}* %this, i32 0, i32 0
+ %bp = getelementptr {i32, i32}, {i32, i32}* %this, i32 0, i32 1
+ %a = load i32, i32* %ap
+ %b = load i32, i32* %bp
+ ; CHECK: %[[AB:.*]] = add i32 %[[THIS1]], %[[THIS2]]
+ %ab = add i32 %a, %b
+ ; CHECK: store i32 %[[AB]], i32* %[[SR]]
+ store i32 %ab, i32* %r
+ ret void
+}
+
+; CHECK: define void @f()
+define void @f() {
+ ; CHECK: %[[R:.*]] = alloca i32
+ %r = alloca i32
+ %pair = alloca {i32, i32}
+
+ ; CHECK: call void @add(i32 %{{.*}}, i32 %{{.*}}, i32* noalias %[[R]])
+ call void @add({i32, i32}* %pair, i32* sret %r)
+ ret void
+}
OpenPOWER on IntegriCloud