|
| 1 | +// WebAssemblyLowerEmscriptenExceptions.cpp - Lower exceptions for Emscripten // |
| 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 | +/// \file |
| 11 | +/// \brief This file lowers exception-related instructions in order to use |
| 12 | +/// Emscripten's JavaScript try and catch mechanism to handle exceptions. |
| 13 | +/// |
| 14 | +/// To handle exceptions, this scheme relies on JavaScript's try and catch |
| 15 | +/// syntax and relevant exception-related libraries implemented in JavaScript |
| 16 | +/// glue code that will be produced by Emscripten. This is similar to the |
| 17 | +/// current Emscripten asm.js exception handling in fastcomp. |
| 18 | +/// For fastcomp's EH scheme, see these files in fastcomp LLVM branch: |
| 19 | +/// (Location: https://github.com/kripken/emscripten-fastcomp) |
| 20 | +/// lib/Target/JSBackend/NaCl/LowerEmExceptionsPass.cpp |
| 21 | +/// lib/Target/JSBackend/JSBackend.cpp |
| 22 | +/// lib/Target/JSBackend/CallHandlers.h |
| 23 | +/// |
| 24 | +/// This pass does following things: |
| 25 | +/// |
| 26 | +/// 1) Create three global variables: __THREW__, threwValue, and tempRet0. |
| 27 | +/// tempRet0 will be set within ___cxa_find_matching_catch() function in |
| 28 | +/// JS library, and __THREW__ and threwValue will be set in invoke wrappers |
| 29 | +/// in JS glue code. For what invoke wrappers are, refer to 3). |
| 30 | +/// |
| 31 | +/// 2) Create setThrew and setTempRet0 functions. |
| 32 | +/// The global variables created in 1) will exist in wasm address space, |
| 33 | +/// but their values should be set in JS code, so we provide these functions |
| 34 | +/// as interfaces to JS glue code. These functions are equivalent to the |
| 35 | +/// following JS functions, which actually exist in asm.js version of JS |
| 36 | +/// library. |
| 37 | +/// |
| 38 | +/// function setThrew(threw, value) { |
| 39 | +/// if (__THREW__ == 0) { |
| 40 | +/// __THREW__ = threw; |
| 41 | +/// threwValue = value; |
| 42 | +/// } |
| 43 | +/// } |
| 44 | +/// |
| 45 | +/// function setTempRet0(value) { |
| 46 | +/// tempRet0 = value; |
| 47 | +/// } |
| 48 | +/// |
| 49 | +/// 3) Lower |
| 50 | +/// invoke @func(arg1, arg2) to label %invoke.cont unwind label %lpad |
| 51 | +/// into |
| 52 | +/// __THREW__ = 0; |
| 53 | +/// call @invoke_SIG(func, arg1, arg2) |
| 54 | +/// %__THREW__.val = __THREW__; |
| 55 | +/// __THREW__ = 0; |
| 56 | +/// br %__THREW__.val, label %lpad, label %invoke.cont |
| 57 | +/// SIG is a mangled string generated based on the LLVM IR-level function |
| 58 | +/// signature. After LLVM IR types are lowered to the target wasm types, |
| 59 | +/// the names for these wrappers will change based on wasm types as well, |
| 60 | +/// as in invoke_vi (function takes an int and returns void). The bodies of |
| 61 | +/// these wrappers will be generated in JS glue code, and inside those |
| 62 | +/// wrappers we use JS try-catch to generate actual exception effects. It |
| 63 | +/// also calls the original callee function. An example wrapper in JS code |
| 64 | +/// would look like this: |
| 65 | +/// function invoke_vi(index,a1) { |
| 66 | +/// try { |
| 67 | +/// Module["dynCall_vi"](index,a1); // This calls original callee |
| 68 | +/// } catch(e) { |
| 69 | +/// if (typeof e !== 'number' && e !== 'longjmp') throw e; |
| 70 | +/// asm["setThrew"](1, 0); // setThrew is called here |
| 71 | +/// } |
| 72 | +/// } |
| 73 | +/// If an exception is thrown, __THREW__ will be set to true in a wrapper, |
| 74 | +/// so we can jump to the right BB based on this value. |
| 75 | +/// |
| 76 | +/// 4) Lower |
| 77 | +/// %val = landingpad catch c1 catch c2 catch c3 ... |
| 78 | +/// ... use %val ... |
| 79 | +/// into |
| 80 | +/// %fmc = call @___cxa_find_matching_catch_N(c1, c2, c3, ...) |
| 81 | +/// %val = {%fmc, tempRet0} |
| 82 | +/// ... use %val ... |
| 83 | +/// Here N is a number calculated based on the number of clauses. |
| 84 | +/// Global variable tempRet0 is set within ___cxa_find_matching_catch() in |
| 85 | +/// JS glue code. |
| 86 | +/// |
| 87 | +/// 5) Lower |
| 88 | +/// resume {%a, %b} |
| 89 | +/// into |
| 90 | +/// call @___resumeException(%a) |
| 91 | +/// where ___resumeException() is a function in JS glue code. |
| 92 | +/// |
| 93 | +/// TODO: Handle i64 types |
| 94 | +/// |
| 95 | +///===----------------------------------------------------------------------===// |
| 96 | + |
| 97 | +#include "WebAssembly.h" |
| 98 | +#include "llvm/ADT/IndexedMap.h" |
| 99 | +#include "llvm/IR/Constants.h" |
| 100 | +#include "llvm/IR/IRBuilder.h" |
| 101 | +#include "llvm/IR/Instructions.h" |
| 102 | +#include "llvm/IR/Module.h" |
| 103 | +#include "llvm/Pass.h" |
| 104 | +#include "llvm/Support/raw_ostream.h" |
| 105 | + |
| 106 | +using namespace llvm; |
| 107 | + |
| 108 | +#define DEBUG_TYPE "wasm-lower-em-exceptions" |
| 109 | + |
| 110 | +namespace { |
| 111 | +class WebAssemblyLowerEmscriptenExceptions final : public ModulePass { |
| 112 | + const char *getPassName() const override { |
| 113 | + return "WebAssembly Lower Emscripten Exceptions"; |
| 114 | + } |
| 115 | + |
| 116 | + bool runOnFunction(Function &F); |
| 117 | + // Returns ___cxa_find_matching_catch_N function, where N = NumClauses + 2. |
| 118 | + // This is because a landingpad instruction contains two more arguments, |
| 119 | + // a personality function and a cleanup bit, and ___cxa_find_matching_catch_N |
| 120 | + // functions are named after the number of arguments in the original |
| 121 | + // landingpad instruction. |
| 122 | + Function *getFindMatchingCatch(Module &M, unsigned NumClauses); |
| 123 | + |
| 124 | + Function *getInvokeWrapper(Module &M, InvokeInst *II); |
| 125 | + |
| 126 | + GlobalVariable *ThrewGV; // __THREW__ |
| 127 | + GlobalVariable *ThrewValueGV; // threwValue |
| 128 | + GlobalVariable *TempRet0GV; // tempRet0 |
| 129 | + Function *ResumeF; |
| 130 | + // ___cxa_find_matching_catch_N functions. |
| 131 | + // Indexed by the number of clauses in an original landingpad instruction. |
| 132 | + DenseMap<int, Function *> FindMatchingCatches; |
| 133 | + // Map of <function signature string, invoke_ wrappers> |
| 134 | + StringMap<Function *> InvokeWrappers; |
| 135 | + |
| 136 | +public: |
| 137 | + static char ID; |
| 138 | + |
| 139 | + WebAssemblyLowerEmscriptenExceptions() |
| 140 | + : ModulePass(ID), ThrewGV(nullptr), ThrewValueGV(nullptr), |
| 141 | + TempRet0GV(nullptr) {} |
| 142 | + bool runOnModule(Module &M) override; |
| 143 | +}; |
| 144 | +} // End anonymous namespace |
| 145 | + |
| 146 | +char WebAssemblyLowerEmscriptenExceptions::ID = 0; |
| 147 | +INITIALIZE_PASS(WebAssemblyLowerEmscriptenExceptions, DEBUG_TYPE, |
| 148 | + "WebAssembly Lower Emscripten Exceptions", false, false) |
| 149 | + |
| 150 | +ModulePass *llvm::createWebAssemblyLowerEmscriptenExceptions() { |
| 151 | + return new WebAssemblyLowerEmscriptenExceptions(); |
| 152 | +} |
| 153 | + |
| 154 | +static bool canThrow(const Value *V) { |
| 155 | + if (const auto *F = dyn_cast<const Function>(V)) { |
| 156 | + // Intrinsics cannot throw |
| 157 | + if (F->isIntrinsic()) |
| 158 | + return false; |
| 159 | + StringRef Name = F->getName(); |
| 160 | + // leave setjmp and longjmp (mostly) alone, we process them properly later |
| 161 | + if (Name == "setjmp" || Name == "longjmp") |
| 162 | + return false; |
| 163 | + return true; |
| 164 | + } |
| 165 | + return true; // not a function, so an indirect call - can throw, we can't tell |
| 166 | +} |
| 167 | + |
| 168 | +// Returns an available name for a global value. |
| 169 | +// If the proposed name already exists in the module, adds '_' at the end of |
| 170 | +// the name until the name is available. |
| 171 | +static inline std::string createGlobalValueName(const Module &M, |
| 172 | + const std::string &Propose) { |
| 173 | + std::string Name = Propose; |
| 174 | + while (M.getNamedGlobal(Name)) |
| 175 | + Name += "_"; |
| 176 | + return Name; |
| 177 | +} |
| 178 | + |
| 179 | +// Simple function name mangler. |
| 180 | +// This function simply takes LLVM's string representation of parameter types |
| 181 | +// concatenate them with '_'. There are non-alphanumeric characters but llc is |
| 182 | +// ok with it, and we need to postprocess these names after the lowering phase |
| 183 | +// anyway. |
| 184 | +static std::string getSignature(FunctionType *FTy) { |
| 185 | + std::string Sig; |
| 186 | + raw_string_ostream OS(Sig); |
| 187 | + OS << *FTy->getReturnType(); |
| 188 | + for (Type *ParamTy : FTy->params()) |
| 189 | + OS << "_" << *ParamTy; |
| 190 | + if (FTy->isVarArg()) |
| 191 | + OS << "_..."; |
| 192 | + Sig = OS.str(); |
| 193 | + Sig.erase(std::remove_if(Sig.begin(), Sig.end(), isspace), Sig.end()); |
| 194 | + return Sig; |
| 195 | +} |
| 196 | + |
| 197 | +Function *WebAssemblyLowerEmscriptenExceptions::getFindMatchingCatch( |
| 198 | + Module &M, unsigned NumClauses) { |
| 199 | + if (FindMatchingCatches.count(NumClauses)) |
| 200 | + return FindMatchingCatches[NumClauses]; |
| 201 | + PointerType *Int8PtrTy = Type::getInt8PtrTy(M.getContext()); |
| 202 | + SmallVector<Type *, 16> Args(NumClauses, Int8PtrTy); |
| 203 | + FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false); |
| 204 | + Function *F = Function::Create( |
| 205 | + FTy, GlobalValue::ExternalLinkage, |
| 206 | + "___cxa_find_matching_catch_" + Twine(NumClauses + 2), &M); |
| 207 | + FindMatchingCatches[NumClauses] = F; |
| 208 | + return F; |
| 209 | +} |
| 210 | + |
| 211 | +Function * |
| 212 | +WebAssemblyLowerEmscriptenExceptions::getInvokeWrapper(Module &M, |
| 213 | + InvokeInst *II) { |
| 214 | + SmallVector<Type *, 16> ArgTys; |
| 215 | + Value *Callee = II->getCalledValue(); |
| 216 | + FunctionType *CalleeFTy; |
| 217 | + if (auto *F = dyn_cast<Function>(Callee)) |
| 218 | + CalleeFTy = F->getFunctionType(); |
| 219 | + else { |
| 220 | + auto *CalleeTy = dyn_cast<PointerType>(Callee->getType())->getElementType(); |
| 221 | + CalleeFTy = dyn_cast<FunctionType>(CalleeTy); |
| 222 | + } |
| 223 | + |
| 224 | + std::string Sig = getSignature(CalleeFTy); |
| 225 | + if (InvokeWrappers.find(Sig) != InvokeWrappers.end()) |
| 226 | + return InvokeWrappers[Sig]; |
| 227 | + |
| 228 | + // Put the pointer to the callee as first argument |
| 229 | + ArgTys.push_back(PointerType::getUnqual(CalleeFTy)); |
| 230 | + // Add argument types |
| 231 | + ArgTys.append(CalleeFTy->param_begin(), CalleeFTy->param_end()); |
| 232 | + |
| 233 | + FunctionType *FTy = FunctionType::get(CalleeFTy->getReturnType(), ArgTys, |
| 234 | + CalleeFTy->isVarArg()); |
| 235 | + Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage, |
| 236 | + "__invoke_" + Sig, &M); |
| 237 | + InvokeWrappers[Sig] = F; |
| 238 | + return F; |
| 239 | +} |
| 240 | + |
| 241 | +bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) { |
| 242 | + IRBuilder<> Builder(M.getContext()); |
| 243 | + IntegerType *Int1Ty = Builder.getInt1Ty(); |
| 244 | + PointerType *Int8PtrTy = Builder.getInt8PtrTy(); |
| 245 | + IntegerType *Int32Ty = Builder.getInt32Ty(); |
| 246 | + |
| 247 | + // Create global variables __THREW__, threwValue, and tempRet0 |
| 248 | + ThrewGV = new GlobalVariable(M, Int1Ty, false, GlobalValue::ExternalLinkage, |
| 249 | + Builder.getFalse(), |
| 250 | + createGlobalValueName(M, "__THREW__")); |
| 251 | + ThrewValueGV = new GlobalVariable( |
| 252 | + M, Int32Ty, false, GlobalValue::ExternalLinkage, Builder.getInt32(0), |
| 253 | + createGlobalValueName(M, "threwValue")); |
| 254 | + TempRet0GV = new GlobalVariable( |
| 255 | + M, Int32Ty, false, GlobalValue::ExternalLinkage, Builder.getInt32(0), |
| 256 | + createGlobalValueName(M, "tempRet0")); |
| 257 | + |
| 258 | + // Register ___resumeException function |
| 259 | + Type *VoidTy = Type::getVoidTy(M.getContext()); |
| 260 | + FunctionType *ResumeFTy = FunctionType::get(VoidTy, Int8PtrTy, false); |
| 261 | + ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage, |
| 262 | + "___resumeException", &M); |
| 263 | + |
| 264 | + bool Changed = false; |
| 265 | + for (Function &F : M) { |
| 266 | + if (F.isDeclaration()) |
| 267 | + continue; |
| 268 | + Changed |= runOnFunction(F); |
| 269 | + } |
| 270 | + |
| 271 | + if (!Changed) |
| 272 | + return false; |
| 273 | + |
| 274 | + assert(!M.getNamedGlobal("setThrew") && "setThrew already exists"); |
| 275 | + assert(!M.getNamedGlobal("setTempRet0") && "setTempRet0 already exists"); |
| 276 | + |
| 277 | + // Create setThrew function |
| 278 | + SmallVector<Type *, 2> Params = {Int1Ty, Int32Ty}; |
| 279 | + FunctionType *FTy = FunctionType::get(VoidTy, Params, false); |
| 280 | + Function *F = |
| 281 | + Function::Create(FTy, GlobalValue::ExternalLinkage, "setThrew", &M); |
| 282 | + Argument *Arg1 = &*(F->arg_begin()); |
| 283 | + Argument *Arg2 = &*(++F->arg_begin()); |
| 284 | + Arg1->setName("threw"); |
| 285 | + Arg2->setName("value"); |
| 286 | + BasicBlock *EntryBB = BasicBlock::Create(M.getContext(), "entry", F); |
| 287 | + BasicBlock *ThenBB = BasicBlock::Create(M.getContext(), "if.then", F); |
| 288 | + BasicBlock *EndBB = BasicBlock::Create(M.getContext(), "if.end", F); |
| 289 | + |
| 290 | + Builder.SetInsertPoint(EntryBB); |
| 291 | + Value *Threw = Builder.CreateLoad(ThrewGV, ThrewGV->getName() + ".val"); |
| 292 | + Value *Cmp = Builder.CreateICmpEQ(Threw, Builder.getFalse(), "cmp"); |
| 293 | + Builder.CreateCondBr(Cmp, ThenBB, EndBB); |
| 294 | + |
| 295 | + Builder.SetInsertPoint(ThenBB); |
| 296 | + Builder.CreateStore(Arg1, ThrewGV); |
| 297 | + Builder.CreateStore(Arg2, ThrewValueGV); |
| 298 | + Builder.CreateBr(EndBB); |
| 299 | + |
| 300 | + Builder.SetInsertPoint(EndBB); |
| 301 | + Builder.CreateRetVoid(); |
| 302 | + |
| 303 | + // Create setTempRet0 function |
| 304 | + Params = {Int32Ty}; |
| 305 | + FTy = FunctionType::get(VoidTy, Params, false); |
| 306 | + F = Function::Create(FTy, GlobalValue::ExternalLinkage, "setTempRet0", &M); |
| 307 | + F->arg_begin()->setName("value"); |
| 308 | + EntryBB = BasicBlock::Create(M.getContext(), "entry", F); |
| 309 | + Builder.SetInsertPoint(EntryBB); |
| 310 | + Builder.CreateStore(&*F->arg_begin(), TempRet0GV); |
| 311 | + Builder.CreateRetVoid(); |
| 312 | + |
| 313 | + return true; |
| 314 | +} |
| 315 | + |
| 316 | +bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) { |
| 317 | + Module &M = *F.getParent(); |
| 318 | + IRBuilder<> Builder(M.getContext()); |
| 319 | + bool Changed = false; |
| 320 | + SmallVector<Instruction *, 64> ToErase; |
| 321 | + SmallPtrSet<LandingPadInst *, 32> LandingPads; |
| 322 | + |
| 323 | + for (BasicBlock &BB : F) { |
| 324 | + auto *II = dyn_cast<InvokeInst>(BB.getTerminator()); |
| 325 | + if (!II) |
| 326 | + continue; |
| 327 | + Changed = true; |
| 328 | + LandingPads.insert(II->getLandingPadInst()); |
| 329 | + Builder.SetInsertPoint(II); |
| 330 | + |
| 331 | + if (canThrow(II->getCalledValue())) { |
| 332 | + // If we are calling a function that is noreturn, we must remove that |
| 333 | + // attribute. The code we insert here does expect it to return, after we |
| 334 | + // catch the exception. |
| 335 | + if (II->doesNotReturn()) { |
| 336 | + if (auto *F = dyn_cast<Function>(II->getCalledValue())) |
| 337 | + F->removeFnAttr(Attribute::NoReturn); |
| 338 | + AttributeSet NewAttrs = II->getAttributes(); |
| 339 | + NewAttrs.removeAttribute(M.getContext(), AttributeSet::FunctionIndex, |
| 340 | + Attribute::NoReturn); |
| 341 | + II->setAttributes(NewAttrs); |
| 342 | + } |
| 343 | + |
| 344 | + // Pre-invoke |
| 345 | + // __THREW__ = 0; |
| 346 | + Builder.CreateStore(Builder.getFalse(), ThrewGV); |
| 347 | + |
| 348 | + // Invoke function wrapper in JavaScript |
| 349 | + SmallVector<Value *, 16> CallArgs; |
| 350 | + // Put the pointer to the callee as first argument, so it can be called |
| 351 | + // within the invoke wrapper later |
| 352 | + CallArgs.push_back(II->getCalledValue()); |
| 353 | + CallArgs.append(II->arg_begin(), II->arg_end()); |
| 354 | + CallInst *NewCall = Builder.CreateCall(getInvokeWrapper(M, II), CallArgs); |
| 355 | + NewCall->takeName(II); |
| 356 | + NewCall->setCallingConv(II->getCallingConv()); |
| 357 | + NewCall->setAttributes(II->getAttributes()); |
| 358 | + NewCall->setDebugLoc(II->getDebugLoc()); |
| 359 | + II->replaceAllUsesWith(NewCall); |
| 360 | + ToErase.push_back(II); |
| 361 | + |
| 362 | + // Post-invoke |
| 363 | + // %__THREW__.val = __THREW__; __THREW__ = 0; |
| 364 | + Value *Threw = Builder.CreateLoad(ThrewGV, ThrewGV->getName() + ".val"); |
| 365 | + Builder.CreateStore(Builder.getFalse(), ThrewGV); |
| 366 | + |
| 367 | + // Insert a branch based on __THREW__ variable |
| 368 | + Builder.CreateCondBr(Threw, II->getUnwindDest(), II->getNormalDest()); |
| 369 | + |
| 370 | + } else { |
| 371 | + // This can't throw, and we don't need this invoke, just replace it with a |
| 372 | + // call+branch |
| 373 | + SmallVector<Value *, 16> CallArgs(II->arg_begin(), II->arg_end()); |
| 374 | + CallInst *NewCall = Builder.CreateCall(II->getCalledValue(), CallArgs); |
| 375 | + NewCall->takeName(II); |
| 376 | + NewCall->setCallingConv(II->getCallingConv()); |
| 377 | + NewCall->setAttributes(II->getAttributes()); |
| 378 | + NewCall->setDebugLoc(II->getDebugLoc()); |
| 379 | + II->replaceAllUsesWith(NewCall); |
| 380 | + ToErase.push_back(II); |
| 381 | + |
| 382 | + Builder.CreateBr(II->getNormalDest()); |
| 383 | + |
| 384 | + // Remove any PHI node entries from the exception destination |
| 385 | + II->getUnwindDest()->removePredecessor(&BB); |
| 386 | + } |
| 387 | + } |
| 388 | + |
| 389 | + // Process resume instructions |
| 390 | + for (BasicBlock &BB : F) { |
| 391 | + // Scan the body of the basic block for resumes |
| 392 | + for (Instruction &I : BB) { |
| 393 | + auto *RI = dyn_cast<ResumeInst>(&I); |
| 394 | + if (!RI) |
| 395 | + continue; |
| 396 | + |
| 397 | + // Split the input into legal values |
| 398 | + Value *Input = RI->getValue(); |
| 399 | + Builder.SetInsertPoint(RI); |
| 400 | + Value *Low = Builder.CreateExtractValue(Input, 0, "low"); |
| 401 | + |
| 402 | + // Create a call to ___resumeException function |
| 403 | + Value *Args[] = {Low}; |
| 404 | + Builder.CreateCall(ResumeF, Args); |
| 405 | + |
| 406 | + // Add a terminator to the block |
| 407 | + Builder.CreateUnreachable(); |
| 408 | + ToErase.push_back(RI); |
| 409 | + } |
| 410 | + } |
| 411 | + |
| 412 | + // Look for orphan landingpads, can occur in blocks with no predecesors |
| 413 | + for (BasicBlock &BB : F) { |
| 414 | + Instruction *I = BB.getFirstNonPHI(); |
| 415 | + if (auto *LPI = dyn_cast<LandingPadInst>(I)) |
| 416 | + LandingPads.insert(LPI); |
| 417 | + } |
| 418 | + |
| 419 | + // Handle all the landingpad for this function together, as multiple invokes |
| 420 | + // may share a single lp |
| 421 | + for (LandingPadInst *LPI : LandingPads) { |
| 422 | + Builder.SetInsertPoint(LPI); |
| 423 | + SmallVector<Value *, 16> FMCArgs; |
| 424 | + for (unsigned i = 0, e = LPI->getNumClauses(); i < e; ++i) { |
| 425 | + Constant *Clause = LPI->getClause(i); |
| 426 | + // As a temporary workaround for the lack of aggregate varargs support |
| 427 | + // in the interface between JS and wasm, break out filter operands into |
| 428 | + // their component elements. |
| 429 | + if (LPI->isFilter(i)) { |
| 430 | + ArrayType *ATy = cast<ArrayType>(Clause->getType()); |
| 431 | + for (unsigned j = 0, e = ATy->getNumElements(); j < e; ++j) { |
| 432 | + Value *EV = |
| 433 | + Builder.CreateExtractValue(Clause, makeArrayRef(j), "filter"); |
| 434 | + FMCArgs.push_back(EV); |
| 435 | + } |
| 436 | + } else |
| 437 | + FMCArgs.push_back(Clause); |
| 438 | + } |
| 439 | + |
| 440 | + // Create a call to ___cxa_find_matching_catch_N function |
| 441 | + Function *FMCF = getFindMatchingCatch(M, FMCArgs.size()); |
| 442 | + CallInst *FMCI = Builder.CreateCall(FMCF, FMCArgs, "fmc"); |
| 443 | + Value *Undef = UndefValue::get(LPI->getType()); |
| 444 | + Value *Pair0 = Builder.CreateInsertValue(Undef, FMCI, 0, "pair0"); |
| 445 | + Value *TempRet0 = |
| 446 | + Builder.CreateLoad(TempRet0GV, TempRet0GV->getName() + "val"); |
| 447 | + Value *Pair1 = Builder.CreateInsertValue(Pair0, TempRet0, 1, "pair1"); |
| 448 | + |
| 449 | + LPI->replaceAllUsesWith(Pair1); |
| 450 | + ToErase.push_back(LPI); |
| 451 | + } |
| 452 | + |
| 453 | + // Erase everything we no longer need in this function |
| 454 | + for (Instruction *I : ToErase) |
| 455 | + I->eraseFromParent(); |
| 456 | + |
| 457 | + return Changed; |
| 458 | +} |
0 commit comments