Allow readonly functions to unwind exceptions. Teach
authorDuncan Sands <baldrick@free.fr>
Wed, 6 May 2009 06:49:50 +0000 (06:49 +0000)
committerDuncan Sands <baldrick@free.fr>
Wed, 6 May 2009 06:49:50 +0000 (06:49 +0000)
the optimizers about this.  For example, a readonly
function with no uses cannot be removed unless it is
also marked nounwind.

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

13 files changed:
docs/LangRef.html
include/llvm/Instruction.h
lib/Transforms/Scalar/ADCE.cpp
lib/Transforms/Scalar/GVN.cpp
lib/Transforms/Scalar/InstructionCombining.cpp
lib/Transforms/Scalar/LoopDeletion.cpp
lib/Transforms/Scalar/LoopIndexSplit.cpp
lib/Transforms/Scalar/LoopUnswitch.cpp
lib/Transforms/Scalar/TailDuplication.cpp
lib/Transforms/Scalar/TailRecursionElimination.cpp
lib/Transforms/Utils/Local.cpp
lib/VMCore/Instruction.cpp
test/Transforms/ADCE/dce_pure_call.ll

index f07fc31083ea28d1b4f2eca7c79106df44353960..db59e0d0738149cb251ac5fab67964385e75a55b 100644 (file)
@@ -1061,23 +1061,24 @@ unwind or exceptional control flow.  If the function does unwind, its runtime
 behavior is undefined.</dd>
 
 <dt><tt>readnone</tt></dt>
-<dd>This attribute indicates that the function computes its result (or the
-exception it throws) based strictly on its arguments, without dereferencing any
+<dd>This attribute indicates that the function computes its result (or decides to
+unwind an exception) based strictly on its arguments, without dereferencing any
 pointer arguments or otherwise accessing any mutable state (e.g. memory, control
 registers, etc) visible to caller functions.  It does not write through any
 pointer arguments (including <tt><a href="#byval">byval</a></tt> arguments) and
-never changes any state visible to callers.  readnone functions may not throw
-an exception that escapes into the caller.</dd>
+never changes any state visible to callers.  This means that it cannot unwind
+exceptions by calling the <tt>C++</tt> exception throwing methods, but could
+use the <tt>unwind</tt> instruction.</dd>
 
 <dt><tt><a name="readonly">readonly</a></tt></dt>
 <dd>This attribute indicates that the function does not write through any
 pointer arguments (including <tt><a href="#byval">byval</a></tt> arguments)
 or otherwise modify any state (e.g. memory, control registers, etc) visible to
 caller functions.  It may dereference pointer arguments and read state that may
-be set in the caller.  A readonly function always returns the same value when
-called with the same set of arguments and global
-state.  readonly functions may not throw an exception that escapes into the
-caller.</dd>
+be set in the caller.  A readonly function always returns the same value (or
+unwinds an exception identically) when called with the same set of arguments
+and global state.  It cannot unwind an exception by calling the <tt>C++</tt>
+exception throwing methods, but may use the <tt>unwind</tt> instruction.</dd>
 
 <dt><tt><a name="ssp">ssp</a></tt></dt>
 <dd>This attribute indicates that the function should emit a stack smashing
index 0a39b08461d65615138e87eb538eedbf8e0cbd19..7d946e85a6d006b325b6f6dea25752bf7950f009 100644 (file)
@@ -40,14 +40,6 @@ public:
   // Out of line virtual method, so the vtable, etc has a home.
   ~Instruction();
   
-  /// mayWriteToMemory - Return true if this instruction may modify memory.
-  ///
-  bool mayWriteToMemory() const;
-
-  /// mayReadFromMemory - Return true if this instruction may read memory.
-  ///
-  bool mayReadFromMemory() const;
-  
   /// clone() - Create a copy of 'this' instruction that is identical in all
   /// ways except the following:
   ///   * The instruction has no parent
@@ -181,6 +173,24 @@ public:
   }
   static bool isTrapping(unsigned op);
 
+  /// mayWriteToMemory - Return true if this instruction may modify memory.
+  ///
+  bool mayWriteToMemory() const;
+
+  /// mayReadFromMemory - Return true if this instruction may read memory.
+  ///
+  bool mayReadFromMemory() const;
+
+  /// mayThrow - Return true if this instruction may throw an exception.
+  ///
+  bool mayThrow() const;
+
+  /// mayHaveSideEffects - Return true if the instruction may have side effects.
+  ///
+  bool mayHaveSideEffects() const {
+    return mayWriteToMemory() || mayThrow();
+  }
+
   /// 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 bfea2b278417da4e8015ae0443d047c5d58d867e..9c55f664ebbd0e723c1b9f71d982b6b62a1605eb 100644 (file)
@@ -57,7 +57,7 @@ bool ADCE::runOnFunction(Function& F) {
   for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I)
     if (isa<TerminatorInst>(I.getInstructionIterator()) ||
         isa<DbgInfoIntrinsic>(I.getInstructionIterator()) ||
-        I->mayWriteToMemory()) {
+        I->mayHaveSideEffects()) {
       alive.insert(I.getInstructionIterator());
       worklist.push_back(I.getInstructionIterator());
     }
index d605ffb6602ed81488b00280bad956c8e5a93a9c..260bbedddc92e8b340e8880bd2522cbd0fb8bd17 100644 (file)
@@ -1479,13 +1479,13 @@ bool GVN::performPRE(Function& F) {
     for (BasicBlock::iterator BI = CurrentBlock->begin(),
          BE = CurrentBlock->end(); BI != BE; ) {
       Instruction *CurInst = BI++;
-      
+
       if (isa<AllocationInst>(CurInst) || isa<TerminatorInst>(CurInst) ||
           isa<PHINode>(CurInst) || (CurInst->getType() == Type::VoidTy) ||
-          CurInst->mayReadFromMemory() || CurInst->mayWriteToMemory() ||
+          CurInst->mayReadFromMemory() || CurInst->mayHaveSideEffects() ||
           isa<DbgInfoIntrinsic>(CurInst))
         continue;
-      
+
       uint32_t valno = VN.lookup(CurInst);
       
       // Look for the predecessors for PRE opportunities.  We're
index eebac00a10c058da9e2c5e1fc767bf21ad46743d..9feb442df97ec48e31393a4afecbc52195532049 100644 (file)
@@ -12579,7 +12579,7 @@ static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock) {
   assert(I->hasOneUse() && "Invariants didn't hold!");
 
   // Cannot move control-flow-involving, volatile loads, vaarg, etc.
-  if (isa<PHINode>(I) || I->mayWriteToMemory() || isa<TerminatorInst>(I))
+  if (isa<PHINode>(I) || I->mayHaveSideEffects() || isa<TerminatorInst>(I))
     return false;
 
   // Do not sink alloca instructions out of the entry block.
index 96b7a5288a7e912bcc036ca3a01a22fad3717985..65126728c7fc885308e8ab8389ea88cc3bf4c416 100644 (file)
@@ -136,11 +136,8 @@ bool LoopDeletion::IsLoopDead(Loop* L,
        LI != LE; ++LI) {
     for (BasicBlock::iterator BI = (*LI)->begin(), BE = (*LI)->end();
          BI != BE; ++BI) {
-      if (BI->mayWriteToMemory())
+      if (BI->mayHaveSideEffects())
         return false;
-      else if (LoadInst* L = dyn_cast<LoadInst>(BI))
-        if (L->isVolatile())
-          return false;
     }
   }
   
index ffa1d902b777d206c535ab18089388fa511a97a4..40d2e4a9d8b3275165d81948013cb147d92978ca 100644 (file)
@@ -1148,7 +1148,7 @@ bool LoopIndexSplit::cleanBlock(BasicBlock *BB) {
         || isa<DbgInfoIntrinsic>(I))
       continue;
 
-    if (I->mayWriteToMemory())
+    if (I->mayHaveSideEffects())
       return false;
 
     // I is used only inside this block then it is OK.
index 2afb3c8ed7a026b39e4cbf43eef8aa303e16f852..e3e881f0812b205cd4b7a91c6fe9a8836e40d01c 100644 (file)
@@ -300,7 +300,7 @@ static bool isTrivialLoopExitBlockHelper(Loop *L, BasicBlock *BB,
   // Okay, everything after this looks good, check to make sure that this block
   // doesn't include any side effects.
   for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
-    if (I->mayWriteToMemory())
+    if (I->mayHaveSideEffects())
       return false;
   
   return true;
@@ -383,7 +383,7 @@ bool LoopUnswitch::IsTrivialUnswitchCondition(Value *Cond, Constant **Val,
   // part of the loop that the code *would* execute.  We already checked the
   // tail, check the header now.
   for (BasicBlock::iterator I = Header->begin(), E = Header->end(); I != E; ++I)
-    if (I->mayWriteToMemory())
+    if (I->mayHaveSideEffects())
       return false;
   return true;
 }
index 78690699bd5d329d3f97336f230955b6685ae524..99a7dee39887dc51e33a3839779fc4b11b44b47c 100644 (file)
@@ -258,7 +258,7 @@ void TailDup::eliminateUnconditionalBranch(BranchInst *Branch) {
     while (!isa<TerminatorInst>(BBI)) {
       Instruction *I = BBI++;
 
-      bool CanHoist = !I->isTrapping() && !I->mayWriteToMemory();
+      bool CanHoist = !I->isTrapping() && !I->mayHaveSideEffects();
       if (CanHoist) {
         for (unsigned op = 0, e = I->getNumOperands(); op != e; ++op)
           if (Instruction *OpI = dyn_cast<Instruction>(I->getOperand(op)))
index e1234efb57881e57d232b432c16d1dbcb5eefdf0..682d069923e4f1e7b9f08c7f1f4c56549677d3ed 100644 (file)
@@ -201,7 +201,7 @@ bool TailCallElim::runOnFunction(Function &F) {
 bool TailCallElim::CanMoveAboveCall(Instruction *I, CallInst *CI) {
   // FIXME: We can move load/store/call/free instructions above the call if the
   // call does not mod/ref the memory location being processed.
-  if (I->mayWriteToMemory() || isa<LoadInst>(I))
+  if (I->mayHaveSideEffects() || isa<LoadInst>(I))
     return false;
 
   // Otherwise, if this is a side-effect free instruction, check to make sure
index fea739cb46b071b7b42369949943f7afbe4aef7e..4f2bb1e3de7a80665c8d4bbbe028d326e29cd709 100644 (file)
@@ -164,17 +164,15 @@ bool llvm::isInstructionTriviallyDead(Instruction *I) {
 
   // We don't want debug info removed by anything this general.
   if (isa<DbgInfoIntrinsic>(I)) return false;
-    
-  if (!I->mayWriteToMemory())
-    return true;
 
-  // Special case intrinsics that "may write to memory" but can be deleted when
-  // dead.
+  if (!I->mayHaveSideEffects()) return true;
+
+  // Special case intrinsics that "may have side effects" but can be deleted
+  // when dead.
   if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I))
     // Safe to delete llvm.stacksave if dead.
     if (II->getIntrinsicID() == Intrinsic::stacksave)
       return true;
-  
   return false;
 }
 
@@ -230,7 +228,7 @@ llvm::RecursivelyDeleteDeadPHINode(PHINode *PN) {
   SmallPtrSet<PHINode *, 4> PHIs;
   PHIs.insert(PN);
   for (Instruction *J = cast<Instruction>(*PN->use_begin());
-       J->hasOneUse() && !J->mayWriteToMemory();
+       J->hasOneUse() && !J->mayHaveSideEffects();
        J = cast<Instruction>(*J->use_begin()))
     // If we find a PHI more than once, we're on a cycle that
     // won't prove fruitful.
index f33c1a23f2389c2c9e97844b00c6da88717114b2..9e030b78e9e5ba0dd9b033eb171d60abd51714cb 100644 (file)
@@ -320,6 +320,14 @@ bool Instruction::mayWriteToMemory() const {
   }
 }
 
+/// mayThrow - Return true if this instruction may throw an exception.
+///
+bool Instruction::mayThrow() const {
+  if (const CallInst *CI = dyn_cast<CallInst>(this))
+    return !CI->doesNotThrow();
+  return false;
+}
+
 /// isAssociative - Return true if the instruction is associative:
 ///
 ///   Associative operators satisfy:  x op (y op z) === (x op y) op z)
index a7414e027eadf7fd9ac007fb26abd903089775cf..3935bf72b9c14e775ac47841b7bfd3b2d36607b4 100644 (file)
@@ -1,8 +1,8 @@
 ; RUN: llvm-as < %s | opt -adce | llvm-dis | not grep call
 
-declare i32 @strlen(i8*) readonly
+declare i32 @strlen(i8*) readonly nounwind
 
 define void @test() {
-       call i32 @strlen( i8* null ) readonly           ; <i32>:1 [#uses=0]
+       call i32 @strlen( i8* null )            ; <i32>:1 [#uses=0]
        ret void
 }