summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Homerding <homerdin@gmail.com>2018-08-23 15:05:22 +0000
committerBrian Homerding <homerdin@gmail.com>2018-08-23 15:05:22 +0000
commit3ecabd709f7d7031df9368d27d0b300460d51cf1 (patch)
tree797f11dddac85063e9b39da25aa143a06d8114b6
parent1715efd7ff6825bf8633759a43560f47b492128b (diff)
downloadbcm5719-llvm-3ecabd709f7d7031df9368d27d0b300460d51cf1.tar.gz
bcm5719-llvm-3ecabd709f7d7031df9368d27d0b300460d51cf1.zip
[FunctionAttrs] Infer WriteOnly Function Attribute
These changes expand the FunctionAttr logic in order to mark functions as WriteOnly when appropriate. This is done through an additional bool variable and extended logic. Reviewers: hfinkel, jdoerfert Differential Revision: https://reviews.llvm.org/D48387 llvm-svn: 340537
-rw-r--r--llvm/include/llvm/Transforms/IPO/FunctionAttrs.h3
-rw-r--r--llvm/lib/Transforms/IPO/FunctionAttrs.cpp48
-rw-r--r--llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll7
3 files changed, 44 insertions, 14 deletions
diff --git a/llvm/include/llvm/Transforms/IPO/FunctionAttrs.h b/llvm/include/llvm/Transforms/IPO/FunctionAttrs.h
index dc9f18c7941..901fed7a0fa 100644
--- a/llvm/include/llvm/Transforms/IPO/FunctionAttrs.h
+++ b/llvm/include/llvm/Transforms/IPO/FunctionAttrs.h
@@ -32,7 +32,8 @@ class Pass;
enum MemoryAccessKind {
MAK_ReadNone = 0,
MAK_ReadOnly = 1,
- MAK_MayWrite = 2
+ MAK_MayWrite = 2,
+ MAK_WriteOnly = 3
};
/// Returns the memory access properties of this copy of the function.
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index 925f4af9d48..d40ee30f453 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -66,6 +66,7 @@ using namespace llvm;
STATISTIC(NumReadNone, "Number of functions marked readnone");
STATISTIC(NumReadOnly, "Number of functions marked readonly");
+STATISTIC(NumWriteOnly, "Number of functions marked writeonly");
STATISTIC(NumNoCapture, "Number of arguments marked nocapture");
STATISTIC(NumReturned, "Number of arguments marked returned");
STATISTIC(NumReadNoneArg, "Number of arguments marked readnone");
@@ -113,12 +114,16 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody,
if (AliasAnalysis::onlyReadsMemory(MRB))
return MAK_ReadOnly;
- // Conservatively assume it writes to memory.
+ if (AliasAnalysis::doesNotReadMemory(MRB))
+ return MAK_WriteOnly;
+
+ // Conservatively assume it reads and writes to memory.
return MAK_MayWrite;
}
// Scan the function body for instructions that may read or write memory.
bool ReadsMemory = false;
+ bool WritesMemory = false;
for (inst_iterator II = inst_begin(F), E = inst_end(F); II != E; ++II) {
Instruction *I = &*II;
@@ -141,9 +146,9 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody,
continue;
if (!AliasAnalysis::onlyAccessesArgPointees(MRB)) {
- // The call could access any memory. If that includes writes, give up.
+ // The call could access any memory. If that includes writes, note it.
if (isModSet(MRI))
- return MAK_MayWrite;
+ WritesMemory = true;
// If it reads, note it.
if (isRefSet(MRI))
ReadsMemory = true;
@@ -168,8 +173,8 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody,
continue;
if (isModSet(MRI))
- // Writes non-local memory. Give up.
- return MAK_MayWrite;
+ // Writes non-local memory.
+ WritesMemory = true;
if (isRefSet(MRI))
// Ok, it reads non-local memory.
ReadsMemory = true;
@@ -198,14 +203,21 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody,
// Any remaining instructions need to be taken seriously! Check if they
// read or write memory.
- if (I->mayWriteToMemory())
- // Writes memory. Just give up.
- return MAK_MayWrite;
+ //
+ // Writes memory, remember that.
+ WritesMemory |= I->mayWriteToMemory();
// If this instruction may read memory, remember that.
ReadsMemory |= I->mayReadFromMemory();
}
+ if (WritesMemory) {
+ if (!ReadsMemory)
+ return MAK_WriteOnly;
+ else
+ return MAK_MayWrite;
+ }
+
return ReadsMemory ? MAK_ReadOnly : MAK_ReadNone;
}
@@ -220,6 +232,7 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
// Check if any of the functions in the SCC read or write memory. If they
// write memory then they can't be marked readnone or readonly.
bool ReadsMemory = false;
+ bool WritesMemory = false;
for (Function *F : SCCNodes) {
// Call the callable parameter to look up AA results for this function.
AAResults &AAR = AARGetter(*F);
@@ -234,6 +247,9 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
case MAK_ReadOnly:
ReadsMemory = true;
break;
+ case MAK_WriteOnly:
+ WritesMemory = true;
+ break;
case MAK_ReadNone:
// Nothing to do!
break;
@@ -243,6 +259,9 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
// Success! Functions in this SCC do not access memory, or only read memory.
// Give them the appropriate attribute.
bool MadeChange = false;
+
+ assert(!(ReadsMemory && WritesMemory) &&
+ "Function marked read-only and write-only");
for (Function *F : SCCNodes) {
if (F->doesNotAccessMemory())
// Already perfect!
@@ -252,16 +271,25 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) {
// No change.
continue;
+ if (F->doesNotReadMemory() && WritesMemory)
+ continue;
+
MadeChange = true;
// Clear out any existing attributes.
F->removeFnAttr(Attribute::ReadOnly);
F->removeFnAttr(Attribute::ReadNone);
+ F->removeFnAttr(Attribute::WriteOnly);
// Add in the new attribute.
- F->addFnAttr(ReadsMemory ? Attribute::ReadOnly : Attribute::ReadNone);
+ if (WritesMemory && !ReadsMemory)
+ F->addFnAttr(Attribute::WriteOnly);
+ else
+ F->addFnAttr(ReadsMemory ? Attribute::ReadOnly : Attribute::ReadNone);
- if (ReadsMemory)
+ if (WritesMemory && !ReadsMemory)
+ ++NumWriteOnly;
+ else if (ReadsMemory)
++NumReadOnly;
else
++NumReadNone;
diff --git a/llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll b/llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll
index 71f606c37f6..e2b7c971dd8 100644
--- a/llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll
+++ b/llvm/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll
@@ -63,7 +63,7 @@ define i32 @test3_yes(i8* %p) nounwind {
ret i32 %t
}
-; CHECK: define i32 @test3_no(i8* nocapture %p) #1 {
+; CHECK: define i32 @test3_no(i8* nocapture %p) #5 {
define i32 @test3_no(i8* %p) nounwind {
%t = va_arg i8* %p, i32, !tbaa !2
ret i32 %t
@@ -73,11 +73,12 @@ declare void @callee(i32* %p) nounwind
declare void @llvm.memcpy.p0i8.p0i8.i64(i8*, i8*, i64, i1) nounwind
; CHECK: attributes #0 = { norecurse nounwind readnone }
-; CHECK: attributes #1 = { norecurse nounwind }
+; CHECK: attributes #1 = { norecurse nounwind writeonly }
; CHECK: attributes #2 = { nounwind readonly }
; CHECK: attributes #3 = { nounwind }
; CHECK: attributes #4 = { nounwind readnone }
-; CHECK: attributes #5 = { argmemonly nounwind }
+; CHECK: attributes #5 = { norecurse nounwind }
+; CHECK: attributes #6 = { argmemonly nounwind }
; Root note.
!0 = !{ }
OpenPOWER on IntegriCloud