aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2014-02-12 15:09:48 -0800
committerAlon Zakai <alonzakai@gmail.com>2014-02-12 15:09:48 -0800
commitbbad4173768d7836818df697396860bdc14d3827 (patch)
tree650b683668822c528921662cf3184c0291fec486
parent04db312c9612033c07ed11e081645686b09dd76a (diff)
optimize reg/mem stuff around setjmp lowering
-rw-r--r--lib/Transforms/NaCl/LowerEmSetjmp.cpp106
-rw-r--r--lib/Transforms/NaCl/PNaClABISimplify.cpp2
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