Fix PR575, patch provided by John Mellor-Crummey. Thanks!
[oota-llvm.git] / lib / Transforms / IPO / LowerSetJmp.cpp
index 36f06bd607f545d75a346f100a2416433afc23bd..c040025115bdb5e0a9f5f09e2cd2faefade9e708 100644 (file)
@@ -1,5 +1,12 @@
 //===- LowerSetJmp.cpp - Code pertaining to lowering set/long jumps -------===//
 //
+//                     The LLVM Compiler Infrastructure
+//
+// This file was developed by the LLVM research group and is distributed under
+// the University of Illinois Open Source License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
 //  This file implements the lowering of setjmp and longjmp to use the
 //  LLVM invoke and unwind instructions as necessary.
 //
@@ -26,6 +33,7 @@
 // pass invokable via the "opt" command at will.
 //===----------------------------------------------------------------------===//
 
+#include "llvm/Transforms/IPO.h"
 #include "llvm/Constants.h"
 #include "llvm/DerivedTypes.h"
 #include "llvm/Instructions.h"
 #include "llvm/Pass.h"
 #include "llvm/Support/CFG.h"
 #include "llvm/Support/InstVisitor.h"
-#include "Support/DepthFirstIterator.h"
-#include "Support/Statistic.h"
-#include "Support/StringExtras.h"
-#include "Support/VectorExtras.h"
+#include "llvm/Transforms/Utils/Local.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/VectorExtras.h"
+using namespace llvm;
 
 namespace {
   Statistic<> LongJmpsTransformed("lowersetjmp",
                                   "Number of longjmps transformed");
   Statistic<> SetJmpsTransformed("lowersetjmp",
                                  "Number of setjmps transformed");
+  Statistic<> CallsTransformed("lowersetjmp",
+                               "Number of calls invokified");
+  Statistic<> InvokesTransformed("lowersetjmp",
+                                 "Number of invokes modified");
 
   //===--------------------------------------------------------------------===//
-  // LowerSetJmp pass implementation. This is subclassed from the "Pass"
-  // class because it works on a module as a whole, not a function at a
-  // time.
-
-  class LowerSetJmp : public Pass,
+  // LowerSetJmp pass implementation.
+  class LowerSetJmp : public ModulePass,
                       public InstVisitor<LowerSetJmp> {
     // LLVM library functions...
     Function* InitSJMap;        // __llvm_sjljeh_init_setjmpmap
@@ -105,7 +116,7 @@ namespace {
     void visitReturnInst(ReturnInst& RI);
     void visitUnwindInst(UnwindInst& UI);
 
-    bool run(Module& M);
+    bool runOnModule(Module& M);
     bool doInitialization(Module& M);
   };
 
@@ -115,8 +126,7 @@ namespace {
 // run - Run the transformation on the program. We grab the function
 // prototypes for longjmp and setjmp. If they are used in the program,
 // then we can go directly to the places they're at and transform them.
-bool LowerSetJmp::run(Module& M)
-{
+bool LowerSetJmp::runOnModule(Module& M) {
   bool Changed = false;
 
   // These are what the functions are called.
@@ -132,12 +142,12 @@ bool LowerSetJmp::run(Module& M)
   doInitialization(M);
 
   if (SetJmp) {
-    std::set<BasicBlock*> BBSet;
-    
     for (Value::use_iterator B = SetJmp->use_begin(), E = SetJmp->use_end();
          B != E; ++B) {
       BasicBlock* BB = cast<Instruction>(*B)->getParent();
-      DFSBlocks.insert(df_begin(BB), df_end(BB));
+      for (df_ext_iterator<BasicBlock*> I = df_ext_begin(BB, DFSBlocks),
+             E = df_ext_end(BB, DFSBlocks); I != E; ++I)
+        /* empty */;
     }
 
     while (!SetJmp->use_empty()) {
@@ -194,32 +204,32 @@ bool LowerSetJmp::doInitialization(Module& M)
 
   // void __llvm_sjljeh_init_setjmpmap(void**)
   InitSJMap = M.getOrInsertFunction("__llvm_sjljeh_init_setjmpmap",
-                                    Type::VoidTy, SBPPTy, 0); 
+                                    Type::VoidTy, SBPPTy, NULL);
   // void __llvm_sjljeh_destroy_setjmpmap(void**)
   DestroySJMap = M.getOrInsertFunction("__llvm_sjljeh_destroy_setjmpmap",
-                                       Type::VoidTy, SBPPTy, 0);
+                                       Type::VoidTy, SBPPTy, NULL);
 
   // void __llvm_sjljeh_add_setjmp_to_map(void**, void*, unsigned)
   AddSJToMap = M.getOrInsertFunction("__llvm_sjljeh_add_setjmp_to_map",
                                      Type::VoidTy, SBPPTy, SBPTy,
-                                     Type::UIntTy, 0);
+                                     Type::UIntTy, NULL);
 
   // void __llvm_sjljeh_throw_longjmp(int*, int)
   ThrowLongJmp = M.getOrInsertFunction("__llvm_sjljeh_throw_longjmp",
-                                       Type::VoidTy, SBPTy, Type::IntTy, 0);
+                                       Type::VoidTy, SBPTy, Type::IntTy, NULL);
 
   // unsigned __llvm_sjljeh_try_catching_longjmp_exception(void **)
   TryCatchLJ =
     M.getOrInsertFunction("__llvm_sjljeh_try_catching_longjmp_exception",
-                          Type::UIntTy, SBPPTy, 0);
+                          Type::UIntTy, SBPPTy, NULL);
 
   // bool __llvm_sjljeh_is_longjmp_exception()
   IsLJException = M.getOrInsertFunction("__llvm_sjljeh_is_longjmp_exception",
-                                        Type::BoolTy, 0);
+                                        Type::BoolTy, NULL);
 
   // int __llvm_sjljeh_get_longjmp_value()
   GetLJValue = M.getOrInsertFunction("__llvm_sjljeh_get_longjmp_value",
-                                     Type::IntTy, 0);
+                                     Type::IntTy, NULL);
   return true;
 }
 
@@ -228,8 +238,7 @@ bool LowerSetJmp::doInitialization(Module& M)
 // "llvm.{setjmp,longjmp}" functions and none of the setjmp/longjmp error
 // handling functions (beginning with __llvm_sjljeh_...they don't throw
 // exceptions).
-bool LowerSetJmp::IsTransformableFunction(const std::string& Name)
-{
+bool LowerSetJmp::IsTransformableFunction(const std::string& Name) {
   std::string SJLJEh("__llvm_sjljeh");
 
   if (Name.size() > SJLJEh.size())
@@ -263,9 +272,17 @@ void LowerSetJmp::TransformLongJmpCall(CallInst* Inst)
   else
     new UnwindInst(Inst);
 
-  // Remove all insts after the branch/unwind inst.
-  Inst->getParent()->getInstList().erase(Inst,
-                                       Inst->getParent()->getInstList().end());
+  // Remove all insts after the branch/unwind inst.  Go from back to front to
+  // avoid replaceAllUsesWith if possible.
+  BasicBlock *BB = Inst->getParent();
+  Instruction *Removed;
+  do {
+    Removed = &BB->back();
+    // If the removed instructions have any users, replace them now.
+    if (!Removed->use_empty())
+      Removed->replaceAllUsesWith(UndefValue::get(Removed->getType()));
+    Removed->eraseFromParent();
+  } while (Removed != Inst);
 
   ++LongJmpsTransformed;
 }
@@ -300,12 +317,11 @@ BasicBlock* LowerSetJmp::GetRethrowBB(Function* Func)
   // The basic block we're going to jump to if we need to rethrow the
   // exception.
   BasicBlock* Rethrow = new BasicBlock("RethrowExcept", Func);
-  BasicBlock::InstListType& RethrowBlkIL = Rethrow->getInstList();
 
   // Fill in the "Rethrow" BB with a call to rethrow the exception. This
   // is the last instruction in the BB since at this point the runtime
   // should exit this function and go to the next function.
-  RethrowBlkIL.push_back(new UnwindInst());
+  new UnwindInst(Rethrow);
   return RethrowBBMap[Func] = Rethrow;
 }
 
@@ -334,7 +350,7 @@ LowerSetJmp::SwitchValuePair LowerSetJmp::GetSJSwitch(Function* Func,
   BasicBlock* DecisionBB = new BasicBlock("LJDecisionBB", Func);
   BasicBlock::InstListType& DecisionBBIL = DecisionBB->getInstList();
 
-  LongJmpPreIL.push_back(new BranchInst(DecisionBB, Rethrow, Cond));
+  new BranchInst(DecisionBB, Rethrow, Cond, LongJmpPre);
 
   // Fill in the "decision" basic block.
   CallInst* LJVal = new CallInst(GetLJValue, std::vector<Value*>(), "LJVal");
@@ -343,8 +359,7 @@ LowerSetJmp::SwitchValuePair LowerSetJmp::GetSJSwitch(Function* Func,
     CallInst(TryCatchLJ, make_vector<Value*>(GetSetJmpMap(Func), 0), "SJNum");
   DecisionBBIL.push_back(SJNum);
 
-  SwitchInst* SI = new SwitchInst(SJNum, Rethrow);
-  DecisionBBIL.push_back(SI);
+  SwitchInst* SI = new SwitchInst(SJNum, Rethrow, 0, DecisionBB);
   return SwitchValMap[Func] = SwitchValuePair(SI, LJVal);
 }
 
@@ -366,17 +381,43 @@ void LowerSetJmp::TransformSetJmpCall(CallInst* Inst)
                                                      SetJmpIDMap[Func]++), 0),
                "", Inst);
 
+  // We are guaranteed that there are no values live across basic blocks
+  // (because we are "not in SSA form" yet), but there can still be values live
+  // in basic blocks.  Because of this, splitting the setjmp block can cause
+  // values above the setjmp to not dominate uses which are after the setjmp
+  // call.  For all of these occasions, we must spill the value to the stack.
+  //
+  std::set<Instruction*> InstrsAfterCall;
+
+  // The call is probably very close to the end of the basic block, for the
+  // common usage pattern of: 'if (setjmp(...))', so keep track of the
+  // instructions after the call.
+  for (BasicBlock::iterator I = ++BasicBlock::iterator(Inst), E = ABlock->end();
+       I != E; ++I)
+    InstrsAfterCall.insert(I);
+
+  for (BasicBlock::iterator II = ABlock->begin();
+       II != BasicBlock::iterator(Inst); ++II)
+    // Loop over all of the uses of instruction.  If any of them are after the
+    // call, "spill" the value to the stack.
+    for (Value::use_iterator UI = II->use_begin(), E = II->use_end();
+         UI != E; ++UI)
+      if (cast<Instruction>(*UI)->getParent() != ABlock ||
+          InstrsAfterCall.count(cast<Instruction>(*UI))) {
+        DemoteRegToStack(*II);
+        break;
+      }
+  InstrsAfterCall.clear();
+
   // Change the setjmp call into a branch statement. We'll remove the
   // setjmp call in a little bit. No worries.
   BasicBlock* SetJmpContBlock = ABlock->splitBasicBlock(Inst);
   assert(SetJmpContBlock && "Couldn't split setjmp BB!!");
 
-  SetJmpContBlock->setName("SetJmpContBlock");
+  SetJmpContBlock->setName(ABlock->getName()+"SetJmpCont");
 
-  // Reposition the split BB in the BB list to make things tidier.
-  Func->getBasicBlockList().remove(SetJmpContBlock);
-  Func->getBasicBlockList().insert(++Function::iterator(ABlock),
-                                   SetJmpContBlock);
+  // Add the SetJmpContBlock to the set of blocks reachable from a setjmp.
+  DFSBlocks.insert(SetJmpContBlock);
 
   // This PHI node will be in the new block created from the
   // splitBasicBlock call.
@@ -418,19 +459,17 @@ void LowerSetJmp::visitCallInst(CallInst& CI)
 
   BasicBlock* NewBB = OldBB->splitBasicBlock(CI);
   assert(NewBB && "Couldn't split BB of \"call\" instruction!!");
+  DFSBlocks.insert(NewBB);
   NewBB->setName("Call2Invoke");
 
-  // Reposition the split BB in the BB list to make things tidier.
   Function* Func = OldBB->getParent();
-  Func->getBasicBlockList().remove(NewBB);
-  Func->getBasicBlockList().insert(++Function::iterator(OldBB), NewBB);
 
   // Construct the new "invoke" instruction.
   TerminatorInst* Term = OldBB->getTerminator();
   std::vector<Value*> Params(CI.op_begin() + 1, CI.op_end());
   InvokeInst* II = new
     InvokeInst(CI.getCalledValue(), NewBB, PrelimBBMap[Func],
-               Params, CI.getName(), Term); 
+               Params, CI.getName(), Term);
 
   // Replace the old call inst with the invoke inst and remove the call.
   CI.replaceAllUsesWith(II);
@@ -438,6 +477,7 @@ void LowerSetJmp::visitCallInst(CallInst& CI)
 
   // The old terminator is useless now that we have the invoke inst.
   Term->getParent()->getInstList().erase(Term);
+  ++CallsTransformed;
 }
 
 // visitInvokeInst - Converting the "invoke" instruction is fairly
@@ -456,7 +496,7 @@ void LowerSetJmp::visitInvokeInst(InvokeInst& II)
   if (!DFSBlocks.count(BB)) return;
 
   BasicBlock* NormalBB = II.getNormalDest();
-  BasicBlock* ExceptBB = II.getExceptionalDest();
+  BasicBlock* ExceptBB = II.getUnwindDest();
 
   Function* Func = BB->getParent();
   BasicBlock* NewExceptBB = new BasicBlock("InvokeExcept", Func);
@@ -468,16 +508,15 @@ void LowerSetJmp::visitInvokeInst(InvokeInst& II)
     CallInst(IsLJException, std::vector<Value*>(), "IsLJExcept");
   InstList.push_back(IsLJExcept);
 
-  BranchInst* BR = new BranchInst(PrelimBBMap[Func], ExceptBB, IsLJExcept);
-  InstList.push_back(BR);
+  new BranchInst(PrelimBBMap[Func], ExceptBB, IsLJExcept, NewExceptBB);
 
-  II.setExceptionalDest(NewExceptBB);
+  II.setUnwindDest(NewExceptBB);
+  ++InvokesTransformed;
 }
 
 // visitReturnInst - We want to destroy the setjmp map upon exit from the
 // function.
-void LowerSetJmp::visitReturnInst(ReturnInst& RI)
-{
+void LowerSetJmp::visitReturnInst(ReturnInst &RI) {
   Function* Func = RI.getParent()->getParent();
   new CallInst(DestroySJMap, make_vector<Value*>(GetSetJmpMap(Func), 0),
                "", &RI);
@@ -485,14 +524,13 @@ void LowerSetJmp::visitReturnInst(ReturnInst& RI)
 
 // visitUnwindInst - We want to destroy the setjmp map upon exit from the
 // function.
-void LowerSetJmp::visitUnwindInst(UnwindInst& UI)
-{
+void LowerSetJmp::visitUnwindInst(UnwindInst &UI) {
   Function* Func = UI.getParent()->getParent();
   new CallInst(DestroySJMap, make_vector<Value*>(GetSetJmpMap(Func), 0),
                "", &UI);
 }
 
-Pass* createLowerSetJmpPass()
-{
+ModulePass *llvm::createLowerSetJmpPass() {
   return new LowerSetJmp();
 }
+