Replace isTrapping with a new, similar method called
authorEli Friedman <eli.friedman@gmail.com>
Fri, 17 Jul 2009 04:28:42 +0000 (04:28 +0000)
committerEli Friedman <eli.friedman@gmail.com>
Fri, 17 Jul 2009 04:28:42 +0000 (04:28 +0000)
isSafeToSpeculativelyExecute. The new method is a bit closer to what
the callers actually care about in that it rejects more things callers
don't want.  It also adds more precise handling for integer
division, and unifies code for analyzing the legality of a speculative
load.

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

include/llvm/Instruction.h
lib/Analysis/LoopInfo.cpp
lib/Transforms/Scalar/LICM.cpp
lib/Transforms/Scalar/TailDuplication.cpp
lib/Transforms/Utils/SimplifyCFG.cpp
lib/VMCore/Instruction.cpp

index e06ae2d71120db8b59296d10d6dd93fc9b43fed4..1d1f0f42d12fcccfed1b58f2e0e27f224233a7d9 100644 (file)
@@ -168,13 +168,6 @@ public:
   bool isCommutative() const { return isCommutative(getOpcode()); }
   static bool isCommutative(unsigned op);
 
-  /// isTrapping - Return true if the instruction may trap.
-  ///
-  bool isTrapping() const {
-    return isTrapping(getOpcode());
-  }
-  static bool isTrapping(unsigned op);
-
   /// mayWriteToMemory - Return true if this instruction may modify memory.
   ///
   bool mayWriteToMemory() const;
@@ -193,6 +186,17 @@ public:
     return mayWriteToMemory() || mayThrow();
   }
 
+  /// isSafeToSpeculativelyExecute - Return true if the instruction does not
+  /// have any effects besides calculating the result and does not have
+  /// undefined behavior. Unlike in mayHaveSideEffects(), allocating memory
+  /// is considered an effect.
+  ///
+  /// This method only looks at the instruction itself and its operands, so if
+  /// this method returns true, it is safe to move the instruction as long as
+  /// the operands still dominate it.  However, care must be taken with
+  /// instructions which read memory.
+  bool isSafeToSpeculativelyExecute() const;
+
   /// Methods for support type inquiry through isa, cast, and dyn_cast:
   static inline bool classof(const Instruction *) { return true; }
   static inline bool classof(const Value *V) {
index d350fa6f9eb174bed27fdd99a7528f9fe3891fb1..bef6bef337013c9a19b10c8ef744e3a5058d3d19 100644 (file)
@@ -79,14 +79,9 @@ bool Loop::makeLoopInvariant(Instruction *I, bool &Changed,
   // Test if the value is already loop-invariant.
   if (isLoopInvariant(I))
     return true;
-  // Don't hoist instructions with side-effects.
-  if (I->isTrapping())
+  if (!I->isSafeToSpeculativelyExecute())
     return false;
-  // Don't hoist PHI nodes.
-  if (isa<PHINode>(I))
-    return false;
-  // Don't hoist allocation instructions.
-  if (isa<AllocationInst>(I))
+  if (I->mayReadFromMemory())
     return false;
   // Determine the insertion point, unless one was given.
   if (!InsertPt) {
index 52dd06affe5fcf2ed46340d18f587fbfc42931f7..bdf7dee66203d204f8cd54a17dff683845624eb1 100644 (file)
@@ -623,7 +623,8 @@ void LICM::hoist(Instruction &I) {
 ///
 bool LICM::isSafeToExecuteUnconditionally(Instruction &Inst) {
   // If it is not a trapping instruction, it is always safe to hoist.
-  if (!Inst.isTrapping()) return true;
+  if (Inst.isSafeToSpeculativelyExecute())
+    return true;
 
   // Otherwise we have to check to make sure that the instruction dominates all
   // of the exit blocks.  If it doesn't, then there is a path out of the loop
@@ -635,12 +636,6 @@ bool LICM::isSafeToExecuteUnconditionally(Instruction &Inst) {
   if (Inst.getParent() == CurLoop->getHeader())
     return true;
 
-  // It's always safe to load from a global or alloca.
-  if (isa<LoadInst>(Inst))
-    if (isa<AllocationInst>(Inst.getOperand(0)) ||
-        isa<GlobalVariable>(Inst.getOperand(0)))
-      return true;
-
   // Get the exit blocks for the current loop.
   SmallVector<BasicBlock*, 8> ExitBlocks;
   CurLoop->getExitBlocks(ExitBlocks);
index 684b0963456ea5f2238a33be371f203f55e7db06..6d05fdf18c23836b880b20a8ea3cd79a9c03bda6 100644 (file)
@@ -258,7 +258,8 @@ void TailDup::eliminateUnconditionalBranch(BranchInst *Branch) {
     while (!isa<TerminatorInst>(BBI)) {
       Instruction *I = BBI++;
 
-      bool CanHoist = !I->isTrapping() && !I->mayHaveSideEffects();
+      bool CanHoist = I->isSafeToSpeculativelyExecute() &&
+                      !I->mayReadFromMemory();
       if (CanHoist) {
         for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op)
           if (Instruction *OpI = dyn_cast<Instruction>(I->getOperand(op)))
index 55e1bf225c2ef1fb0554279e0246f3fe08d48161..3b6b77f5fb8a4cab42f0cd51ceeb016ac3ca1dcd 100644 (file)
@@ -384,26 +384,15 @@ static bool DominatesMergePoint(Value *V, BasicBlock *BB,
       // Okay, it looks like the instruction IS in the "condition".  Check to
       // see if its a cheap instruction to unconditionally compute, and if it
       // only uses stuff defined outside of the condition.  If so, hoist it out.
+      if (!I->isSafeToSpeculativelyExecute())
+        return false;
+
       switch (I->getOpcode()) {
       default: return false;  // Cannot hoist this out safely.
       case Instruction::Load: {
-        // We can hoist loads that are non-volatile and obviously cannot trap.
-        if (cast<LoadInst>(I)->isVolatile())
-          return false;
-        // FIXME: A computation of a constant can trap!
-        if (!isa<AllocaInst>(I->getOperand(0)) &&
-            !isa<Constant>(I->getOperand(0)))
-          return false;
-        // External weak globals may have address 0, so we can't load them.
-        Value *V2 = I->getOperand(0)->getUnderlyingObject();
-        if (V2) {
-          GlobalVariable* GV = dyn_cast<GlobalVariable>(V2);
-          if (GV && GV->hasExternalWeakLinkage())
-            return false;
-        }
-        // Finally, we have to check to make sure there are no instructions
-        // before the load in its basic block, as we are going to hoist the loop
-        // out to its predecessor.
+        // We have to check to make sure there are no instructions before the
+        // load in its basic block, as we are going to hoist the loop out to
+        // its predecessor.
         BasicBlock::iterator IP = PBB->begin();
         while (isa<DbgInfoIntrinsic>(IP))
           IP++;
index 99fd8d09e5bd13d349da7d050a2626ac88664c20..e19ad1c16f9e78e71ed3b0a06ed6fc2799577dd9 100644 (file)
@@ -14,6 +14,8 @@
 #include "llvm/Type.h"
 #include "llvm/Instructions.h"
 #include "llvm/Function.h"
+#include "llvm/Constants.h"
+#include "llvm/GlobalVariable.h"
 #include "llvm/Support/CallSite.h"
 #include "llvm/Support/LeakDetector.h"
 using namespace llvm;
@@ -365,24 +367,56 @@ bool Instruction::isCommutative(unsigned op) {
   }
 }
 
-/// isTrapping - Return true if the instruction may trap.
-///
-bool Instruction::isTrapping(unsigned op) {
-  switch(op) {
+bool Instruction::isSafeToSpeculativelyExecute() const {
+  for (unsigned i = 0, e = getNumOperands(); i != e; ++i)
+    if (Constant *C = dyn_cast<Constant>(getOperand(i)))
+      if (C->canTrap())
+        return false;
+
+  switch (getOpcode()) {
+  default:
+    return true;
   case UDiv:
+  case URem: {
+    // x / y is undefined if y == 0, but calcuations like x / 3 are safe.
+    ConstantInt *Op = dyn_cast<ConstantInt>(getOperand(1));
+    return Op && !Op->isNullValue();
+  }
   case SDiv:
-  case FDiv:
-  case URem:
-  case SRem:
-  case FRem:
-  case Load:
-  case Store:
+  case SRem: {
+    // x / y is undefined if y == 0, and might be undefined if y == -1,
+    // but calcuations like x / 3 are safe.
+    ConstantInt *Op = dyn_cast<ConstantInt>(getOperand(1));
+    return Op && !Op->isNullValue() && !Op->isAllOnesValue();
+  }
+  case Load: {
+    if (cast<LoadInst>(this)->isVolatile())
+      return false;
+    if (isa<AllocationInst>(getOperand(0)))
+      return true;
+    if (GlobalVariable *GV = dyn_cast<GlobalVariable>(getOperand(0)))
+      return !GV->hasExternalWeakLinkage();
+    // FIXME: Handle cases involving GEPs.  We have to be careful because
+    // a load of a out-of-bounds GEP has undefined behavior.
+    return false;
+  }
   case Call:
-  case Invoke:
+    return false; // The called function could have undefined behavior or
+                  // side-effects.
+                  // FIXME: We should special-case some intrinsics (bswap,
+                  // overflow-checking arithmetic, etc.)
   case VAArg:
+  case Alloca:
+  case Malloc:
+  case Invoke:
+  case PHI:
+  case Store:
   case Free:
-    return true;
-  default:
-    return false;
+  case Ret:
+  case Br:
+  case Switch:
+  case Unwind:
+  case Unreachable:
+    return false; // Misc instructions which have effects
   }
 }