Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(981)

Unified Diff: lib/Transforms/NaCl/LowerEmSetjmp.cpp

Issue 1692803002: Remove Emscripten support (Closed) Base URL: https://chromium.googlesource.com/a/native_client/pnacl-llvm.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « lib/Transforms/NaCl/LowerEmExceptionsPass.cpp ('k') | lib/Transforms/NaCl/NoExitRuntime.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: lib/Transforms/NaCl/LowerEmSetjmp.cpp
diff --git a/lib/Transforms/NaCl/LowerEmSetjmp.cpp b/lib/Transforms/NaCl/LowerEmSetjmp.cpp
deleted file mode 100644
index 9b2eab5b73a7befd1a60539fc6433c13d6778e18..0000000000000000000000000000000000000000
--- a/lib/Transforms/NaCl/LowerEmSetjmp.cpp
+++ /dev/null
@@ -1,349 +0,0 @@
-//===- LowerEmSetjmp - Lower setjmp/longjmp for Emscripten/JS -----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Lowers setjmp to a reasonably-performant approach for emscripten. The idea
-// is that each block with a setjmp is broken up into the part right after
-// the setjmp, and a new basic block is added which is either reached from
-// the setjmp, or later from a longjmp. To handle the longjmp, all calls that
-// might longjmp are checked immediately afterwards.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Transforms/Scalar.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Statistic.h"
-#include "llvm/IR/Constants.h"
-#include "llvm/IR/DerivedTypes.h"
-#include "llvm/IR/Instructions.h"
-#include "llvm/IR/Intrinsics.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Pass.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Target/TargetLowering.h"
-#include "llvm/Transforms/Utils/BasicBlockUtils.h"
-#include "llvm/Transforms/Utils/Local.h"
-#include "llvm/Transforms/NaCl.h"
-#include "llvm/IR/Dominators.h"
-#include "llvm/Transforms/Utils/PromoteMemToReg.h"
-#include <vector>
-#include <set>
-#include <list>
-
-#include "llvm/Support/raw_ostream.h"
-
-#ifdef NDEBUG
-#undef assert
-#define assert(x) { if (!(x)) report_fatal_error(#x); }
-#endif
-
-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_user_iterator UI = Inst->user_begin(),E = Inst->user_end();
- UI != E; ++UI) {
- const User *U = *UI;
- const Instruction *I = cast<Instruction>(U);
- 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
-
- DominatorTreeWrapperPass DTW;
- DTW.runOnFunction(F);
- DominatorTree& DT = DTW.getDomTree();
-
- 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;
-
- public:
- static char ID; // Pass identification, replacement for typeid
- explicit LowerEmSetjmp() : ModulePass(ID), TheModule(NULL) {
- initializeLowerEmSetjmpPass(*PassRegistry::getPassRegistry());
- }
- bool runOnModule(Module &M);
- };
-}
-
-char LowerEmSetjmp::ID = 0;
-INITIALIZE_PASS(LowerEmSetjmp, "loweremsetjmp",
- "Lower setjmp and longjmp for js/emscripten",
- false, false)
-
-bool LowerEmSetjmp::runOnModule(Module &M) {
- TheModule = &M;
-
- Function *Setjmp = TheModule->getFunction("setjmp");
- Function *Longjmp = TheModule->getFunction("longjmp");
- if (!Setjmp && !Longjmp) return false;
-
- Type *i32 = Type::getInt32Ty(M.getContext());
- Type *Void = Type::getVoidTy(M.getContext());
-
- // Add functions
-
- Function *EmSetjmp = NULL;
-
- if (Setjmp) {
- SmallVector<Type*, 2> EmSetjmpTypes;
- EmSetjmpTypes.push_back(Setjmp->getFunctionType()->getParamType(0));
- EmSetjmpTypes.push_back(i32); // extra param that says which setjmp in the function it is
- FunctionType *EmSetjmpFunc = FunctionType::get(i32, EmSetjmpTypes, false);
- EmSetjmp = Function::Create(EmSetjmpFunc, GlobalValue::ExternalLinkage, "emscripten_setjmp", TheModule);
- }
-
- Function *EmLongjmp = Longjmp ? Function::Create(Longjmp->getFunctionType(), GlobalValue::ExternalLinkage, "emscripten_longjmp", TheModule) : NULL;
-
- SmallVector<Type*, 1> IntArgTypes;
- IntArgTypes.push_back(i32);
- FunctionType *IntIntFunc = FunctionType::get(i32, IntArgTypes, false);
-
- Function *CheckLongjmp = Function::Create(IntIntFunc, GlobalValue::ExternalLinkage, "emscripten_check_longjmp", TheModule); // gets control flow
-
- Function *GetLongjmpResult = Function::Create(IntIntFunc, GlobalValue::ExternalLinkage, "emscripten_get_longjmp_result", TheModule); // gets int value longjmp'd
-
- FunctionType *VoidFunc = FunctionType::get(Void, false);
- Function *PrepSetjmp = Function::Create(VoidFunc, GlobalValue::ExternalLinkage, "emscripten_prep_setjmp", TheModule);
-
- Function *CleanupSetjmp = Function::Create(VoidFunc, GlobalValue::ExternalLinkage, "emscripten_cleanup_setjmp", TheModule);
-
- Function *PreInvoke = TheModule->getFunction("emscripten_preinvoke");
- if (!PreInvoke) PreInvoke = Function::Create(VoidFunc, GlobalValue::ExternalLinkage, "emscripten_preinvoke", TheModule);
-
- FunctionType *IntFunc = FunctionType::get(i32, false);
- Function *PostInvoke = TheModule->getFunction("emscripten_postinvoke");
- if (!PostInvoke) PostInvoke = Function::Create(IntFunc, GlobalValue::ExternalLinkage, "emscripten_postinvoke", TheModule);
-
- // Process all callers of setjmp and longjmp. Start with setjmp.
-
- typedef std::vector<PHINode*> Phis;
- typedef std::map<Function*, Phis> FunctionPhisMap;
- FunctionPhisMap SetjmpOutputPhis;
- std::vector<Instruction*> ToErase;
-
- if (Setjmp) {
- for (Instruction::user_iterator UI = Setjmp->user_begin(), UE = Setjmp->user_end(); UI != UE; ++UI) {
- User *U = *UI;
- if (CallInst *CI = dyn_cast<CallInst>(U)) {
- BasicBlock *SJBB = CI->getParent();
- // The tail is everything right after the call, and will be reached once when setjmp is
- // called, and later when longjmp returns to the setjmp
- BasicBlock *Tail = SplitBlock(SJBB, CI->getNextNode());
- // Add a phi to the tail, which will be the output of setjmp, which indicates if this is the
- // first call or a longjmp back. The phi directly uses the right value based on where we
- // arrive from
- PHINode *SetjmpOutput = PHINode::Create(i32, 2, "", Tail->getFirstNonPHI());
- SetjmpOutput->addIncoming(ConstantInt::get(i32, 0), SJBB); // setjmp initial call returns 0
- CI->replaceAllUsesWith(SetjmpOutput); // The proper output is now this, not the setjmp call itself
- // longjmp returns to the setjmp will add themselves to this phi
- Phis& P = SetjmpOutputPhis[SJBB->getParent()];
- P.push_back(SetjmpOutput);
- // fix call target
- SmallVector<Value *, 2> Args;
- Args.push_back(CI->getArgOperand(0));
- Args.push_back(ConstantInt::get(i32, P.size())); // our index in the function is our place in the array + 1
- CallInst::Create(EmSetjmp, Args, "", CI);
- ToErase.push_back(CI);
- } else {
- errs() << **UI << "\n";
- report_fatal_error("bad use of setjmp, should only call it");
- }
- }
- }
-
- // Update longjmp FIXME: we could avoid throwing in longjmp as an optimization when longjmping back into the current function perhaps?
-
- if (Longjmp) Longjmp->replaceAllUsesWith(EmLongjmp);
-
- // Update all setjmping functions
-
- for (FunctionPhisMap::iterator I = SetjmpOutputPhis.begin(); I != SetjmpOutputPhis.end(); I++) {
- Function *F = I->first;
- Phis& P = I->second;
-
- CallInst::Create(PrepSetjmp, "", F->begin()->begin());
-
- // Update each call that can longjmp so it can return to a setjmp where relevant
-
- for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ) {
- BasicBlock *BB = BBI++;
- for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); Iter != E; ) {
- Instruction *I = Iter++;
- CallInst *CI;
- if ((CI = dyn_cast<CallInst>(I))) {
- Value *V = CI->getCalledValue();
- if (V == PrepSetjmp || V == EmSetjmp || V == CheckLongjmp || V == GetLongjmpResult || V == PreInvoke || V == PostInvoke) continue;
- if (Function *CF = dyn_cast<Function>(V)) if (CF->isIntrinsic()) continue;
- // TODO: proper analysis of what can actually longjmp. Currently we assume anything but setjmp can.
- // This may longjmp, so we need to check if it did. Split at that point, and
- // envelop the call in pre/post invoke, if we need to
- CallInst *After;
- Instruction *Check = NULL;
- if (Iter != E && (After = dyn_cast<CallInst>(Iter)) && After->getCalledValue() == PostInvoke) {
- // use the pre|postinvoke that exceptions lowering already made
- Check = Iter++;
- }
- BasicBlock *Tail = SplitBlock(BB, Iter); // Iter already points to the next instruction, as we need
- TerminatorInst *TI = BB->getTerminator();
- if (!Check) {
- // no existing pre|postinvoke, create our own
- CallInst::Create(PreInvoke, "", CI);
- Check = CallInst::Create(PostInvoke, "", TI); // CI is at the end of the block
-
- // If we are calling a function that is noreturn, we must remove that attribute. The code we
- // insert here does expect it to return, after we catch the exception.
- if (CI->doesNotReturn()) {
- if (Function *F = dyn_cast<Function>(CI->getCalledValue())) {
- F->removeFnAttr(Attribute::NoReturn);
- }
- CI->setAttributes(CI->getAttributes().removeAttribute(TheModule->getContext(), AttributeSet::FunctionIndex, Attribute::NoReturn));
- assert(!CI->doesNotReturn());
- }
- }
-
- // We need to replace the terminator in Tail - SplitBlock makes BB go straight to Tail, we need to check if a longjmp occurred, and
- // go to the right setjmp-tail if so
- SmallVector<Value *, 1> Args;
- Args.push_back(Check);
- Instruction *LongjmpCheck = CallInst::Create(CheckLongjmp, Args, "", BB);
- Instruction *LongjmpResult = CallInst::Create(GetLongjmpResult, Args, "", BB);
- SwitchInst *SI = SwitchInst::Create(LongjmpCheck, Tail, 2, BB);
- // -1 means no longjmp happened, continue normally (will hit the default switch case). 0 means a longjmp that is not ours to handle, needs a rethrow. Otherwise
- // the index mean is the same as the index in P+1 (to avoid 0).
- for (unsigned i = 0; i < P.size(); i++) {
- SI->addCase(cast<ConstantInt>(ConstantInt::get(i32, i+1)), P[i]->getParent());
- P[i]->addIncoming(LongjmpResult, BB);
- }
- ToErase.push_back(TI); // new terminator is now the switch
-
- // we are splitting the block here, and must continue to find other calls in the block - which is now split. so continue
- // to traverse in the Tail
- BB = Tail;
- Iter = BB->begin();
- E = BB->end();
- } else if (InvokeInst *CI = dyn_cast<InvokeInst>(I)) { // XXX check if target is setjmp
- (void)CI;
- report_fatal_error("TODO: invoke inside setjmping functions");
- }
- }
- }
-
- // add a cleanup before each return
- for (Function::iterator BBI = F->begin(), E = F->end(); BBI != E; ) {
- BasicBlock *BB = BBI++;
- TerminatorInst *TI = BB->getTerminator();
- if (isa<ReturnInst>(TI)) {
- CallInst::Create(CleanupSetjmp, "", TI);
- }
- }
- }
-
- for (unsigned i = 0; i < ToErase.size(); i++) {
- ToErase[i]->eraseFromParent();
- }
-
- // 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;
-}
-
-ModulePass *llvm::createLowerEmSetjmpPass() {
- return new LowerEmSetjmp();
-}
« no previous file with comments | « lib/Transforms/NaCl/LowerEmExceptionsPass.cpp ('k') | lib/Transforms/NaCl/NoExitRuntime.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698