summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/lib/Transforms/IPO/FunctionAttrs.cpp33
-rw-r--r--llvm/test/Transforms/FunctionAttrs/writeonly.ll30
2 files changed, 52 insertions, 11 deletions
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index 5ccd8bc4b0f..0e923a717e6 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -664,6 +664,25 @@ static bool addArgumentAttrsFromCallsites(Function &F) {
return Changed;
}
+static bool addReadAttr(Argument *A, Attribute::AttrKind R) {
+ assert((R == Attribute::ReadOnly || R == Attribute::ReadNone)
+ && "Must be a Read attribute.");
+ assert(A && "Argument must not be null.");
+
+ // If the argument already has the attribute, nothing needs to be done.
+ if (A->hasAttribute(R))
+ return false;
+
+ // Otherwise, remove potentially conflicting attribute, add the new one,
+ // and update statistics.
+ A->removeAttr(Attribute::WriteOnly);
+ A->removeAttr(Attribute::ReadOnly);
+ A->removeAttr(Attribute::ReadNone);
+ A->addAttr(R);
+ R == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg;
+ return true;
+}
+
/// Deduce nocapture attributes for the SCC.
static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
bool Changed = false;
@@ -732,11 +751,8 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
SmallPtrSet<Argument *, 8> Self;
Self.insert(&*A);
Attribute::AttrKind R = determinePointerReadAttrs(&*A, Self);
- if (R != Attribute::None) {
- A->addAttr(R);
- Changed = true;
- R == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg;
- }
+ if (R != Attribute::None)
+ Changed = addReadAttr(A, R);
}
}
}
@@ -833,12 +849,7 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
if (ReadAttr != Attribute::None) {
for (unsigned i = 0, e = ArgumentSCC.size(); i != e; ++i) {
Argument *A = ArgumentSCC[i]->Definition;
- // Clear out existing readonly/readnone attributes
- A->removeAttr(Attribute::ReadOnly);
- A->removeAttr(Attribute::ReadNone);
- A->addAttr(ReadAttr);
- ReadAttr == Attribute::ReadOnly ? ++NumReadOnlyArg : ++NumReadNoneArg;
- Changed = true;
+ Changed = addReadAttr(A, ReadAttr);
}
}
}
diff --git a/llvm/test/Transforms/FunctionAttrs/writeonly.ll b/llvm/test/Transforms/FunctionAttrs/writeonly.ll
new file mode 100644
index 00000000000..6514cd9d106
--- /dev/null
+++ b/llvm/test/Transforms/FunctionAttrs/writeonly.ll
@@ -0,0 +1,30 @@
+; RUN: opt < %s -functionattrs -S | FileCheck %s
+; RUN: opt < %s -passes=function-attrs -S | FileCheck %s
+
+; CHECK: define void @nouses-argworn-funrn(i32* nocapture readnone %.aaa) #0 {
+define void @nouses-argworn-funrn(i32* writeonly %.aaa) {
+nouses-argworn-funrn_entry:
+ ret void
+}
+
+; CHECK: define void @nouses-argworn-funro(i32* nocapture readnone %.aaa, i32* nocapture readonly %.bbb) #1 {
+define void @nouses-argworn-funro(i32* writeonly %.aaa, i32* %.bbb) {
+nouses-argworn-funro_entry:
+ %val = load i32 , i32* %.bbb
+ ret void
+}
+
+%_type_of_d-ccc = type <{ i8*, i8, i8, i8, i8 }>
+
+@d-ccc = internal global %_type_of_d-ccc <{ i8* null, i8 1, i8 13, i8 0, i8 -127 }>, align 8
+
+; CHECK: define void @nouses-argworn-funwo(i32* nocapture readnone %.aaa) #2 {
+define void @nouses-argworn-funwo(i32* writeonly %.aaa) {
+nouses-argworn-funwo_entry:
+ store i8 0, i8* getelementptr inbounds (%_type_of_d-ccc, %_type_of_d-ccc* @d-ccc, i32 0, i32 3)
+ ret void
+}
+
+; CHECK: attributes #0 = { {{.*}} readnone }
+; CHECK: attributes #1 = { {{.*}} readonly }
+; CHECK: attributes #2 = { {{.*}} writeonly }
OpenPOWER on IntegriCloud