Treat lifetime begin/end markers as allocations/frees respectively for the
authorOwen Anderson <resistor@mac.com>
Wed, 28 Oct 2009 07:05:35 +0000 (07:05 +0000)
committerOwen Anderson <resistor@mac.com>
Wed, 28 Oct 2009 07:05:35 +0000 (07:05 +0000)
purposes for GVN/DSE.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@85383 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/MemoryDependenceAnalysis.cpp
lib/Transforms/Scalar/DeadStoreElimination.cpp
lib/Transforms/Scalar/GVN.cpp
test/Transforms/DeadStoreElimination/lifetime-simple.ll [new file with mode: 0644]
test/Transforms/GVN/lifetime-simple.ll [new file with mode: 0644]

index be5f9c1ae041a208f08074e20c4d09e3789d498d..0ec0e74233b399e779884c26003d91ecf80ef932 100644 (file)
@@ -185,10 +185,9 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad,
     if (invariantTag == Inst) {
       invariantTag = 0;
       continue;
-    
-    // If we pass an invariant-end marker, then we've just entered an invariant
-    // region and can start ignoring dependencies.
     } else if (IntrinsicInst* II = dyn_cast<IntrinsicInst>(Inst)) {
+      // If we pass an invariant-end marker, then we've just entered an
+      // invariant region and can start ignoring dependencies.
       if (II->getIntrinsicID() == Intrinsic::invariant_end) {
         uint64_t invariantSize = ~0ULL;
         if (ConstantInt* CI = dyn_cast<ConstantInt>(II->getOperand(2)))
@@ -200,6 +199,19 @@ getPointerDependencyFrom(Value *MemPtr, uint64_t MemSize, bool isLoad,
           invariantTag = II->getOperand(1);
           continue;
         }
+      
+      // If we reach a lifetime begin or end marker, then the query ends here
+      // because the value is undefined.
+      } else if (II->getIntrinsicID() == Intrinsic::lifetime_start ||
+                   II->getIntrinsicID() == Intrinsic::lifetime_end) {
+        uint64_t invariantSize = ~0ULL;
+        if (ConstantInt* CI = dyn_cast<ConstantInt>(II->getOperand(1)))
+          invariantSize = CI->getZExtValue();
+
+        AliasAnalysis::AliasResult R =
+          AA->alias(II->getOperand(2), invariantSize, MemPtr, MemSize);
+        if (R == AliasAnalysis::MustAlias)
+          return MemDepResult::getDef(II);
       }
     }
 
index e3f43372ec1ab9b144f25c94974be396162917d0..60b12fd8679ed92a2b172a188f5a398ae08f044e 100644 (file)
@@ -154,6 +154,26 @@ bool DSE::runOnBasicBlock(BasicBlock &BB) {
         continue;
       }
     }
+    
+    // If this is a lifetime end marker, we can throw away the store.
+    if (IntrinsicInst* II = dyn_cast<IntrinsicInst>(InstDep.getInst())) {
+      if (II->getIntrinsicID() == Intrinsic::lifetime_end) {
+        // Delete the store and now-dead instructions that feed it.
+        // DeleteDeadInstruction can delete the current instruction.  Save BBI
+        // in case we need it.
+        WeakVH NextInst(BBI);
+        
+        DeleteDeadInstruction(SI);
+        
+        if (NextInst == 0)  // Next instruction deleted.
+          BBI = BB.begin();
+        else if (BBI != BB.begin())  // Revisit this instruction if possible.
+          --BBI;
+        NumFastStores++;
+        MadeChange = true;
+        continue;
+      }
+    }
   }
   
   // If this block ends in a return, unwind, or unreachable, all allocas are
index 32d027aa36d82da46dfb0cbc7a859a20b44d30ee..dd8859b5e845f7c6d18151e9fedd3272bed21990 100644 (file)
@@ -1248,6 +1248,15 @@ bool GVN::processNonLocalLoad(LoadInst *LI,
                                              UndefValue::get(LI->getType())));
       continue;
     }
+    
+    // Loading immediately after lifetime begin or end -> undef.
+    if (IntrinsicInst* II = dyn_cast<IntrinsicInst>(DepInst)) {
+      if (II->getIntrinsicID() == Intrinsic::lifetime_start ||
+          II->getIntrinsicID() == Intrinsic::lifetime_end) {
+        ValuesPerBlock.push_back(AvailableValueInBlock::get(DepBB,
+                                             UndefValue::get(LI->getType())));
+      }
+    }
 
     if (StoreInst *S = dyn_cast<StoreInst>(DepInst)) {
       // Reject loads and stores that are to the same address but are of
@@ -1591,6 +1600,18 @@ bool GVN::processLoad(LoadInst *L, SmallVectorImpl<Instruction*> &toErase) {
     NumGVNLoad++;
     return true;
   }
+  
+  // If this load occurs either right after a lifetime begin or a lifetime end,
+  // then the loaded value is undefined.
+  if (IntrinsicInst* II = dyn_cast<IntrinsicInst>(DepInst)) {
+    if (II->getIntrinsicID() == Intrinsic::lifetime_start ||
+        II->getIntrinsicID() == Intrinsic::lifetime_end) {
+      L->replaceAllUsesWith(UndefValue::get(L->getType()));
+      toErase.push_back(L);
+      NumGVNLoad++;
+      return true;
+    }
+  }
 
   return false;
 }
diff --git a/test/Transforms/DeadStoreElimination/lifetime-simple.ll b/test/Transforms/DeadStoreElimination/lifetime-simple.ll
new file mode 100644 (file)
index 0000000..430e700
--- /dev/null
@@ -0,0 +1,18 @@
+; RUN: opt < %s -dse -S | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
+target triple = "i386-apple-darwin7"
+
+define i8 @test2(i8* %P) nounwind {
+; CHECK: @test2
+; CHECK-NOT: store i8 1
+; CHECK: ret i8 0
+entry:
+  call void @llvm.lifetime.start(i64 32, i8* %P)
+  call void @llvm.lifetime.end(i64 32, i8* %P)
+  store i8 1, i8* %P
+  ret i8 0
+}
+
+declare {}* @llvm.lifetime.start(i64 %S, i8* nocapture %P) readonly
+declare void @llvm.lifetime.end(i64 %S, i8* nocapture %P)
\ No newline at end of file
diff --git a/test/Transforms/GVN/lifetime-simple.ll b/test/Transforms/GVN/lifetime-simple.ll
new file mode 100644 (file)
index 0000000..00a0c29
--- /dev/null
@@ -0,0 +1,20 @@
+; RUN: opt < %s -gvn -S | FileCheck %s
+
+target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
+target triple = "i386-apple-darwin7"
+
+define i8 @test(i8* %P) nounwind {
+; CHECK: @test
+; CHECK-NOT: load
+; CHECK: ret i8 undef
+entry:
+  call void @llvm.lifetime.start(i64 32, i8* %P)
+  %0 = load i8* %P
+  store i8 1, i8* %P
+  call void @llvm.lifetime.end(i64 32, i8* %P)
+  %1 = load i8* %P
+  ret i8 %1
+}
+
+declare {}* @llvm.lifetime.start(i64 %S, i8* nocapture %P) readonly
+declare void @llvm.lifetime.end(i64 %S, i8* nocapture %P)
\ No newline at end of file