diff options
author | Alon Zakai <alonzakai@gmail.com> | 2014-02-12 15:09:48 -0800 |
---|---|---|
committer | Alon Zakai <alonzakai@gmail.com> | 2014-02-12 15:09:48 -0800 |
commit | bbad4173768d7836818df697396860bdc14d3827 (patch) | |
tree | 650b683668822c528921662cf3184c0291fec486 | |
parent | 04db312c9612033c07ed11e081645686b09dd76a (diff) |
optimize reg/mem stuff around setjmp lowering
-rw-r--r-- | lib/Transforms/NaCl/LowerEmSetjmp.cpp | 106 | ||||
-rw-r--r-- | lib/Transforms/NaCl/PNaClABISimplify.cpp | 2 |
2 files changed, 106 insertions, 2 deletions
diff --git a/lib/Transforms/NaCl/LowerEmSetjmp.cpp b/lib/Transforms/NaCl/LowerEmSetjmp.cpp index f47ea795bb..1bd3fe37a7 100644 --- a/lib/Transforms/NaCl/LowerEmSetjmp.cpp +++ b/lib/Transforms/NaCl/LowerEmSetjmp.cpp @@ -30,6 +30,8 @@ #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/NaCl.h" +#include "llvm/Analysis/Dominators.h" +#include "llvm/Transforms/Utils/PromoteMemToReg.h" #include <vector> #include <set> @@ -50,6 +52,96 @@ using namespace llvm; +// Utilities for mem/reg: based on Reg2Mem and MemToReg + +bool valueEscapes(const Instruction *Inst) { + const BasicBlock *BB = Inst->getParent(); + for (Value::const_use_iterator UI = Inst->use_begin(),E = Inst->use_end(); + UI != E; ++UI) { + const Instruction *I = cast<Instruction>(*UI); + if (I->getParent() != BB || isa<PHINode>(I)) + return true; + } + return false; +} + +void doRegToMem(Function &F) { // see Reg2Mem.cpp + // Insert all new allocas into entry block. + BasicBlock *BBEntry = &F.getEntryBlock(); + assert(pred_begin(BBEntry) == pred_end(BBEntry) && + "Entry block to function must not have predecessors!"); + + // Find first non-alloca instruction and create insertion point. This is + // safe if block is well-formed: it always have terminator, otherwise + // we'll get and assertion. + BasicBlock::iterator I = BBEntry->begin(); + while (isa<AllocaInst>(I)) ++I; + + CastInst *AllocaInsertionPoint = + new BitCastInst(Constant::getNullValue(Type::getInt32Ty(F.getContext())), + Type::getInt32Ty(F.getContext()), + "reg2mem alloca point", I); + + // Find the escaped instructions. But don't create stack slots for + // allocas in entry block. + std::list<Instruction*> WorkList; + for (Function::iterator ibb = F.begin(), ibe = F.end(); + ibb != ibe; ++ibb) + for (BasicBlock::iterator iib = ibb->begin(), iie = ibb->end(); + iib != iie; ++iib) { + if (!(isa<AllocaInst>(iib) && iib->getParent() == BBEntry) && + valueEscapes(iib)) { + WorkList.push_front(&*iib); + } + } + + // Demote escaped instructions + for (std::list<Instruction*>::iterator ilb = WorkList.begin(), + ile = WorkList.end(); ilb != ile; ++ilb) + DemoteRegToStack(**ilb, false, AllocaInsertionPoint); + + WorkList.clear(); + + // Find all phi's + for (Function::iterator ibb = F.begin(), ibe = F.end(); + ibb != ibe; ++ibb) + for (BasicBlock::iterator iib = ibb->begin(), iie = ibb->end(); + iib != iie; ++iib) + if (isa<PHINode>(iib)) + WorkList.push_front(&*iib); + + // Demote phi nodes + for (std::list<Instruction*>::iterator ilb = WorkList.begin(), + ile = WorkList.end(); ilb != ile; ++ilb) + DemotePHIToStack(cast<PHINode>(*ilb), AllocaInsertionPoint); +} + +void doMemToReg(Function &F) { + std::vector<AllocaInst*> Allocas; + + BasicBlock &BB = F.getEntryBlock(); // Get the entry node for the function + + DominatorTree DT; + DT.runOnFunction(F); + + while (1) { + Allocas.clear(); + + // Find allocas that are safe to promote, by looking at all instructions in + // the entry node + for (BasicBlock::iterator I = BB.begin(), E = --BB.end(); I != E; ++I) + if (AllocaInst *AI = dyn_cast<AllocaInst>(I)) // Is it an alloca? + if (isAllocaPromotable(AI)) + Allocas.push_back(AI); + + if (Allocas.empty()) break; + + PromoteMemToReg(Allocas, DT); + } +} + +// LowerEmSetjmp + namespace { class LowerEmSetjmp : public ModulePass { Module *TheModule; @@ -212,6 +304,20 @@ bool LowerEmSetjmp::runOnModule(Module &M) { } } + // Finally, our modifications to the cfg can break dominance of SSA variables. For example, + // if (x()) { .. setjmp() .. } + // if (y()) { .. longjmp() .. } + // We must split the longjmp block, and it can jump into the setjmp one. But that means that when + // we split the setjmp block, it's first part no longer dominates its second part - there is + // a theoretically possible control flow path where x() is false, then y() is true and we + // reach the second part of the setjmp block, without ever reaching the first part. So, + // we recalculate regs vs. mem + for (FunctionPhisMap::iterator I = SetjmpOutputPhis.begin(); I != SetjmpOutputPhis.end(); I++) { + Function *F = I->first; + doRegToMem(*F); + doMemToReg(*F); + } + return true; } diff --git a/lib/Transforms/NaCl/PNaClABISimplify.cpp b/lib/Transforms/NaCl/PNaClABISimplify.cpp index f563bc0d6a..5689556f21 100644 --- a/lib/Transforms/NaCl/PNaClABISimplify.cpp +++ b/lib/Transforms/NaCl/PNaClABISimplify.cpp @@ -49,9 +49,7 @@ void llvm::PNaClABISimplifyAddPreOptPasses(PassManager &PM) { PM.add(createCFGSimplificationPass()); } - PM.add(createDemoteRegisterToMemoryPass()); // XXX EMSCRIPTEN we just need this for functions with setjmp in them... PM.add(createLowerEmSetjmpPass()); // XXX EMSCRIPTEN - PM.add(createPromoteMemoryToRegisterPass()); // XXX EMSCRIPTEN we just need this for functions with setjmp in them... #if 0 // EMSCRIPTEN: we allow arbitrary symbols to be preserved // Internalize all symbols in the module except _start, which is the only |