OLD | NEW |
| (Empty) |
1 //===- LowerEmExceptions - Lower exceptions for Emscripten/JS -----------===// | |
2 // | |
3 // The LLVM Compiler Infrastructure | |
4 // | |
5 // This file is distributed under the University of Illinois Open Source | |
6 // License. See LICENSE.TXT for details. | |
7 // | |
8 //===----------------------------------------------------------------------===// | |
9 // | |
10 // This is based off the 'cheap' version of LowerInvoke. It does two things: | |
11 // | |
12 // 1) Lower | |
13 // invoke() to l1 unwind l2 | |
14 // into | |
15 // preinvoke(); // (will clear __THREW__) | |
16 // call(); | |
17 // threw = postinvoke(); (check __THREW__) | |
18 // br threw, l1, l2 | |
19 // | |
20 // We do this to avoid introducing a new LLVM IR type, or to try to reuse | |
21 // invoke-landingpad for our special purposes (as they are checked very | |
22 // carefully by llvm) | |
23 // | |
24 // 2) Lower landingpads to a call to emscripten_landingpad | |
25 // | |
26 // 3) Lower resume to emscripten_resume which receives non-aggregate inputs | |
27 // | |
28 //===----------------------------------------------------------------------===// | |
29 | |
30 #include "llvm/Transforms/Scalar.h" | |
31 #include "llvm/ADT/SmallVector.h" | |
32 #include "llvm/ADT/Statistic.h" | |
33 #include "llvm/IR/Constants.h" | |
34 #include "llvm/IR/DerivedTypes.h" | |
35 #include "llvm/IR/Instructions.h" | |
36 #include "llvm/IR/Intrinsics.h" | |
37 #include "llvm/IR/LLVMContext.h" | |
38 #include "llvm/IR/Module.h" | |
39 #include "llvm/Pass.h" | |
40 #include "llvm/Support/CommandLine.h" | |
41 #include "llvm/Target/TargetLowering.h" | |
42 #include "llvm/Transforms/Utils/BasicBlockUtils.h" | |
43 #include "llvm/Transforms/Utils/Local.h" | |
44 #include "llvm/Transforms/NaCl.h" | |
45 #include "llvm/Support/raw_ostream.h" | |
46 | |
47 #include <vector> | |
48 #include <set> | |
49 | |
50 #ifdef NDEBUG | |
51 #undef assert | |
52 #define assert(x) { if (!(x)) report_fatal_error(#x); } | |
53 #endif | |
54 | |
55 using namespace llvm; | |
56 | |
57 static cl::list<std::string> | |
58 Whitelist("emscripten-cxx-exceptions-whitelist", | |
59 cl::desc("Enables C++ exceptions in emscripten (see emscripten EXCEPTI
ON_CATCHING_WHITELIST option)"), | |
60 cl::CommaSeparated); | |
61 | |
62 namespace { | |
63 class LowerEmExceptions : public ModulePass { | |
64 Function *GetHigh, *PreInvoke, *PostInvoke, *LandingPad, *Resume; | |
65 Module *TheModule; | |
66 | |
67 public: | |
68 static char ID; // Pass identification, replacement for typeid | |
69 explicit LowerEmExceptions() : ModulePass(ID), GetHigh(NULL), PreInvoke(NULL
), PostInvoke(NULL), LandingPad(NULL), Resume(NULL), TheModule(NULL) { | |
70 initializeLowerEmExceptionsPass(*PassRegistry::getPassRegistry()); | |
71 } | |
72 bool runOnModule(Module &M); | |
73 }; | |
74 } | |
75 | |
76 char LowerEmExceptions::ID = 0; | |
77 INITIALIZE_PASS(LowerEmExceptions, "loweremexceptions", | |
78 "Lower invoke and unwind for js/emscripten", | |
79 false, false) | |
80 | |
81 bool canThrow(Value *V) { | |
82 if (Function *F = dyn_cast<Function>(V)) { | |
83 // intrinsics and some emscripten builtins cannot throw | |
84 if (F->isIntrinsic()) return false; | |
85 StringRef Name = F->getName(); | |
86 if (Name.startswith("emscripten_asm_")) return false; | |
87 if (Name == "setjmp" || Name == "longjmp") return false; // leave setjmp and
longjmp (mostly) alone, we process them properly later | |
88 return true; | |
89 } | |
90 return true; // not a function, so an indirect call - can throw, we can't tell | |
91 } | |
92 | |
93 bool LowerEmExceptions::runOnModule(Module &M) { | |
94 TheModule = &M; | |
95 | |
96 // Add functions | |
97 | |
98 Type *i32 = Type::getInt32Ty(M.getContext()); | |
99 Type *i8 = Type::getInt8Ty(M.getContext()); | |
100 Type *i1 = Type::getInt1Ty(M.getContext()); | |
101 Type *i8P = i8->getPointerTo(); | |
102 Type *Void = Type::getVoidTy(M.getContext()); | |
103 | |
104 if (!(GetHigh = TheModule->getFunction("getHigh32"))) { | |
105 FunctionType *GetHighFunc = FunctionType::get(i32, false); | |
106 GetHigh = Function::Create(GetHighFunc, GlobalValue::ExternalLinkage, | |
107 "getHigh32", TheModule); | |
108 } | |
109 | |
110 if (!(PreInvoke = TheModule->getFunction("emscripten_preinvoke"))) { | |
111 FunctionType *VoidFunc = FunctionType::get(Void, false); | |
112 PreInvoke = Function::Create(VoidFunc, GlobalValue::ExternalLinkage, "emscri
pten_preinvoke", TheModule); | |
113 } | |
114 | |
115 if (!(PostInvoke = TheModule->getFunction("emscripten_postinvoke"))) { | |
116 FunctionType *IntFunc = FunctionType::get(i32, false); | |
117 PostInvoke = Function::Create(IntFunc, GlobalValue::ExternalLinkage, "emscri
pten_postinvoke", TheModule); | |
118 } | |
119 | |
120 FunctionType *LandingPadFunc = FunctionType::get(i8P, true); | |
121 LandingPad = Function::Create(LandingPadFunc, GlobalValue::ExternalLinkage, "e
mscripten_landingpad", TheModule); | |
122 | |
123 FunctionType *ResumeFunc = FunctionType::get(Void, true); | |
124 Resume = Function::Create(ResumeFunc, GlobalValue::ExternalLinkage, "emscripte
n_resume", TheModule); | |
125 | |
126 // Process | |
127 | |
128 std::set<std::string> WhitelistSet(Whitelist.begin(), Whitelist.end()); | |
129 | |
130 bool Changed = false; | |
131 | |
132 for (Module::iterator Iter = M.begin(), E = M.end(); Iter != E; ) { | |
133 Function *F = Iter++; | |
134 | |
135 std::vector<Instruction*> ToErase; | |
136 std::set<LandingPadInst*> LandingPads; | |
137 | |
138 bool AllowExceptionsInFunc = WhitelistSet.empty() || (WhitelistSet.count("_"
+ F->getName().str()) != 0); | |
139 | |
140 for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { | |
141 // check terminator for invokes | |
142 if (InvokeInst *II = dyn_cast<InvokeInst>(BB->getTerminator())) { | |
143 LandingPads.insert(II->getLandingPadInst()); | |
144 | |
145 bool NeedInvoke = AllowExceptionsInFunc && canThrow(II->getCalledValue()
); | |
146 | |
147 if (NeedInvoke) { | |
148 // If we are calling a function that is noreturn, we must remove that
attribute. The code we | |
149 // insert here does expect it to return, after we catch the exception. | |
150 if (II->doesNotReturn()) { | |
151 if (Function *F = dyn_cast<Function>(II->getCalledValue())) { | |
152 F->removeFnAttr(Attribute::NoReturn); | |
153 } | |
154 II->setAttributes(II->getAttributes().removeAttribute(TheModule->get
Context(), AttributeSet::FunctionIndex, Attribute::NoReturn)); | |
155 assert(!II->doesNotReturn()); | |
156 } | |
157 | |
158 // Insert a normal call instruction folded in between pre- and post-in
voke | |
159 CallInst::Create(PreInvoke, "", II); | |
160 | |
161 SmallVector<Value*,16> CallArgs(II->op_begin(), II->op_end() - 3); | |
162 CallInst *NewCall = CallInst::Create(II->getCalledValue(), | |
163 CallArgs, "", II); | |
164 NewCall->takeName(II); | |
165 NewCall->setCallingConv(II->getCallingConv()); | |
166 NewCall->setAttributes(II->getAttributes()); | |
167 NewCall->setDebugLoc(II->getDebugLoc()); | |
168 II->replaceAllUsesWith(NewCall); | |
169 ToErase.push_back(II); | |
170 | |
171 CallInst *Post = CallInst::Create(PostInvoke, "", II); | |
172 Instruction *Post1 = new TruncInst(Post, i1, "", II); | |
173 | |
174 // Insert a branch based on the postInvoke | |
175 BranchInst::Create(II->getUnwindDest(), II->getNormalDest(), Post1, II
); | |
176 } else { | |
177 // This can't throw, and we don't need this invoke, just replace it wi
th a call+branch | |
178 SmallVector<Value*,16> CallArgs(II->op_begin(), II->op_end() - 3); | |
179 CallInst *NewCall = CallInst::Create(II->getCalledValue(), | |
180 CallArgs, "", II); | |
181 NewCall->takeName(II); | |
182 NewCall->setCallingConv(II->getCallingConv()); | |
183 NewCall->setAttributes(II->getAttributes()); | |
184 NewCall->setDebugLoc(II->getDebugLoc()); | |
185 II->replaceAllUsesWith(NewCall); | |
186 ToErase.push_back(II); | |
187 | |
188 BranchInst::Create(II->getNormalDest(), II); | |
189 | |
190 // Remove any PHI node entries from the exception destination. | |
191 II->getUnwindDest()->removePredecessor(BB); | |
192 } | |
193 | |
194 Changed = true; | |
195 } | |
196 // scan the body of the basic block for resumes | |
197 for (BasicBlock::iterator Iter = BB->begin(), E = BB->end(); | |
198 Iter != E; ) { | |
199 Instruction *I = Iter++; | |
200 if (ResumeInst *R = dyn_cast<ResumeInst>(I)) { | |
201 // split the input into legal values | |
202 Value *Input = R->getValue(); | |
203 ExtractValueInst *Low = ExtractValueInst::Create(Input, 0, "", R); | |
204 ExtractValueInst *High = ExtractValueInst::Create(Input, 1, "", R); | |
205 | |
206 // create a resume call | |
207 SmallVector<Value*,2> CallArgs; | |
208 CallArgs.push_back(Low); | |
209 CallArgs.push_back(High); | |
210 CallInst::Create(Resume, CallArgs, "", R); | |
211 | |
212 new UnreachableInst(TheModule->getContext(), R); // add a terminator t
o the block | |
213 | |
214 ToErase.push_back(R); | |
215 } | |
216 } | |
217 } | |
218 | |
219 // Look for orphan landingpads, can occur in blocks with no predecesors | |
220 for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { | |
221 Instruction *I = BB->getFirstNonPHI(); | |
222 if (LandingPadInst *LP = dyn_cast<LandingPadInst>(I)) { | |
223 LandingPads.insert(LP); | |
224 } | |
225 } | |
226 | |
227 // Handle all the landingpad for this function together, as multiple invokes
may share a single lp | |
228 for (std::set<LandingPadInst*>::iterator I = LandingPads.begin(); I != Landi
ngPads.end(); I++) { | |
229 // Replace the landingpad with a landingpad call to get the low part, and
a getHigh for the high | |
230 LandingPadInst *LP = *I; | |
231 unsigned Num = LP->getNumClauses(); | |
232 SmallVector<Value*,16> NewLPArgs; | |
233 NewLPArgs.push_back(LP->getPersonalityFn()); | |
234 for (unsigned i = 0; i < Num; i++) { | |
235 Value *Arg = LP->getClause(i); | |
236 // As a temporary workaround for the lack of aggregate varargs support | |
237 // in the varargs lowering code, break out filter operands into their | |
238 // component elements. | |
239 if (LP->isFilter(i)) { | |
240 ArrayType *ATy = cast<ArrayType>(Arg->getType()); | |
241 for (unsigned elem = 0, elemEnd = ATy->getNumElements(); elem != elemE
nd; ++elem) { | |
242 Instruction *EE = ExtractValueInst::Create(Arg, makeArrayRef(elem),
"", LP); | |
243 NewLPArgs.push_back(EE); | |
244 } | |
245 } else { | |
246 NewLPArgs.push_back(Arg); | |
247 } | |
248 } | |
249 NewLPArgs.push_back(LP->isCleanup() ? ConstantInt::getTrue(i1) : ConstantI
nt::getFalse(i1)); | |
250 CallInst *NewLP = CallInst::Create(LandingPad, NewLPArgs, "", LP); | |
251 | |
252 Instruction *High = CallInst::Create(GetHigh, "", LP); | |
253 | |
254 // New recreate an aggregate for them, which will be all simplified later
(simplification cannot handle landingpad, hence all this) | |
255 InsertValueInst *IVA = InsertValueInst::Create(UndefValue::get(LP->getType
()), NewLP, 0, "", LP); | |
256 InsertValueInst *IVB = InsertValueInst::Create(IVA, High, 1, "", LP); | |
257 | |
258 LP->replaceAllUsesWith(IVB); | |
259 ToErase.push_back(LP); | |
260 } | |
261 | |
262 // erase everything we no longer need in this function | |
263 for (unsigned i = 0; i < ToErase.size(); i++) ToErase[i]->eraseFromParent(); | |
264 } | |
265 | |
266 return Changed; | |
267 } | |
268 | |
269 ModulePass *llvm::createLowerEmExceptionsPass() { | |
270 return new LowerEmExceptions(); | |
271 } | |
272 | |
OLD | NEW |