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

Side by Side Diff: lib/Transforms/NaCl/LowerEmExceptionsPass.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 unified diff | Download patch
« no previous file with comments | « lib/Transforms/NaCl/LowerEmAsyncify.cpp ('k') | lib/Transforms/NaCl/LowerEmSetjmp.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « lib/Transforms/NaCl/LowerEmAsyncify.cpp ('k') | lib/Transforms/NaCl/LowerEmSetjmp.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698