[PATCH] D116609: [EarlyCSE] Allow elimination of redundant writeonly calls

Benjamin Kramer via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 4 11:11:36 PST 2022


bkramer created this revision.
bkramer added reviewers: fhahn, hfinkel.
Herald added subscribers: asbirlea, george.burgess.iv, hiraditya.
bkramer requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

A writeonly call behaves like a readnone call that also contains a store
to a global determined by the call arguments. This means we can remove
duplicated calls if there are no intervening stores.

This only works if MemorySSA is enabled as we use it to check if there
are conflicting memory accesses.

With this change CSE can handle things like "cos(x)+cos(x) => 2*cos(x)"
even with -fmath-errno.

Based on D48388 <https://reviews.llvm.org/D48388> by Brian Homerding!


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D116609

Files:
  llvm/lib/Transforms/Scalar/EarlyCSE.cpp
  llvm/test/Transforms/EarlyCSE/memoryssa.ll


Index: llvm/test/Transforms/EarlyCSE/memoryssa.ll
===================================================================
--- llvm/test/Transforms/EarlyCSE/memoryssa.ll
+++ llvm/test/Transforms/EarlyCSE/memoryssa.ll
@@ -148,3 +148,33 @@
 
 declare void @llvm.lifetime.end.p0i8(i64, i32*)
 declare void @llvm.lifetime.start.p0i8(i64, i32*)
+
+;; Check that writeonly call gets CSE'd when using MSSA
+declare i32 @write_only() writeonly
+
+; CHECK-LABEL: @test_write_only
+; CHECK-NOMEMSSA-LABEL: @test_write_only
+define void @test_write_only(i1 %c, i32* %p) {
+; CHECK: call i32 @write_only()
+; CHECK-NOMEMSSA: call i32 @write_only()
+  %call = call i32 @write_only()
+; CHECK: %v1 = load i32, i32* @G1
+; CHECK-NOMEMSSA: %v1 = load i32, i32* @G1
+  %v1 = load i32, i32* @G1
+; CHECK-NOT: call i32 @write_only()
+; CHECK-NOMEMSSA: call i32 @write_only()
+  %call2 =  call i32 @write_only()
+; CHECK: store
+; CHECK-NOMEMSSA: store
+  store i32 %v1, i32* @G2
+; CHECK: call i32 @write_only()
+; CHECK-NOMEMSSA: call i32 @write_only()
+  %call3 = call i32 @write_only()
+; CHECK: store
+; CHECK-NOMEMSSA: store
+  store i32 %v1, i32* @G2
+; CHECK: call i32 @write_only()
+; CHECK-NOMEMSSA: call i32 @write_only()
+  %call4 = call i32 @write_only()
+  ret void
+}
Index: llvm/lib/Transforms/Scalar/EarlyCSE.cpp
===================================================================
--- llvm/lib/Transforms/Scalar/EarlyCSE.cpp
+++ llvm/lib/Transforms/Scalar/EarlyCSE.cpp
@@ -460,7 +460,8 @@
       return false;
 
     CallInst *CI = dyn_cast<CallInst>(Inst);
-    if (!CI || !CI->onlyReadsMemory())
+    // Handle readnone, readonly and writeonly.
+    if (!CI || !(CI->doesNotReadMemory() || CI->onlyReadsMemory()))
       return false;
     return true;
   }
@@ -1455,13 +1456,22 @@
         !(MemInst.isValid() && !MemInst.mayReadFromMemory()))
       LastStore = nullptr;
 
-    // If this is a read-only call, process it.
+    // If this is a read-only or write-ony call, process it.
     if (CallValue::canHandle(&Inst)) {
+      // Write-only calls can be CSE'd. Increment the generation to prevent
+      // replacement if there are intervening stores.
+      auto PreStoreGeneration = CurrentGeneration;
+      if (Inst.mayWriteToMemory()) {
+        assert(!Inst.mayReadFromMemory());
+        ++CurrentGeneration;
+        LastStore = nullptr;
+      }
+
       // If we have an available version of this call, and if it is the right
       // generation, replace this instruction.
       std::pair<Instruction *, unsigned> InVal = AvailableCalls.lookup(&Inst);
       if (InVal.first != nullptr &&
-          isSameMemGeneration(InVal.second, CurrentGeneration, InVal.first,
+          isSameMemGeneration(InVal.second, PreStoreGeneration, InVal.first,
                               &Inst)) {
         LLVM_DEBUG(dbgs() << "EarlyCSE CSE CALL: " << Inst
                           << "  to: " << *InVal.first << '\n');
@@ -1480,7 +1490,7 @@
       }
 
       // Otherwise, remember that we have this instruction.
-      AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration));
+      AvailableCalls.insert(&Inst, std::make_pair(&Inst, PreStoreGeneration));
       continue;
     }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D116609.397347.patch
Type: text/x-patch
Size: 3201 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20220104/f6e403a1/attachment.bin>


More information about the llvm-commits mailing list