[llvm] r340537 - [FunctionAttrs] Infer WriteOnly Function Attribute

Brian Homerding via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 23 08:05:22 PDT 2018


Author: homerdin
Date: Thu Aug 23 08:05:22 2018
New Revision: 340537

URL: http://llvm.org/viewvc/llvm-project?rev=340537&view=rev
Log:
[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

Modified:
    llvm/trunk/include/llvm/Transforms/IPO/FunctionAttrs.h
    llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp
    llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll

Modified: llvm/trunk/include/llvm/Transforms/IPO/FunctionAttrs.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/IPO/FunctionAttrs.h?rev=340537&r1=340536&r2=340537&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/IPO/FunctionAttrs.h (original)
+++ llvm/trunk/include/llvm/Transforms/IPO/FunctionAttrs.h Thu Aug 23 08:05:22 2018
@@ -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.

Modified: llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp?rev=340537&r1=340536&r2=340537&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp Thu Aug 23 08:05:22 2018
@@ -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 checkFunctionMem
     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 checkFunctionMem
         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 checkFunctionMem
           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 checkFunctionMem
 
     // 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 SCCNodeSe
   // 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 SCCNodeSe
     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 SCCNodeSe
   // 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 SCCNodeSe
       // 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;

Modified: llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll?rev=340537&r1=340536&r2=340537&view=diff
==============================================================================
--- llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll (original)
+++ llvm/trunk/test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll Thu Aug 23 08:05:22 2018
@@ -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 = !{ }




More information about the llvm-commits mailing list