Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 1 | //=== WebAssemblyLateEHPrepare.cpp - WebAssembly Exception Preparation -===// |
| 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | /// |
| 9 | /// \file |
| 10 | /// \brief Does various transformations for exception handling. |
| 11 | /// |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" |
| 15 | #include "WebAssembly.h" |
| 16 | #include "WebAssemblySubtarget.h" |
| 17 | #include "WebAssemblyUtilities.h" |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 18 | #include "llvm/ADT/SmallSet.h" |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 19 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
| 20 | #include "llvm/CodeGen/WasmEHFuncInfo.h" |
| 21 | #include "llvm/MC/MCAsmInfo.h" |
| 22 | using namespace llvm; |
| 23 | |
| 24 | #define DEBUG_TYPE "wasm-exception-prepare" |
| 25 | |
| 26 | namespace { |
| 27 | class WebAssemblyLateEHPrepare final : public MachineFunctionPass { |
| 28 | StringRef getPassName() const override { |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 29 | return "WebAssembly Late Prepare Exception"; |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 30 | } |
| 31 | |
| 32 | bool runOnMachineFunction(MachineFunction &MF) override; |
Heejin Ahn | 095796a | 2018-11-16 00:47:18 +0000 | [diff] [blame] | 33 | bool removeUnnecessaryUnreachables(MachineFunction &MF); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 34 | bool replaceFuncletReturns(MachineFunction &MF); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 35 | bool addCatches(MachineFunction &MF); |
| 36 | bool addExceptionExtraction(MachineFunction &MF); |
Heejin Ahn | 0bb9865 | 2019-01-30 22:44:45 +0000 | [diff] [blame] | 37 | bool restoreStackPointer(MachineFunction &MF); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 38 | |
| 39 | public: |
| 40 | static char ID; // Pass identification, replacement for typeid |
| 41 | WebAssemblyLateEHPrepare() : MachineFunctionPass(ID) {} |
| 42 | }; |
| 43 | } // end anonymous namespace |
| 44 | |
| 45 | char WebAssemblyLateEHPrepare::ID = 0; |
| 46 | INITIALIZE_PASS(WebAssemblyLateEHPrepare, DEBUG_TYPE, |
Heejin Ahn | a93e726 | 2018-08-17 00:12:04 +0000 | [diff] [blame] | 47 | "WebAssembly Late Exception Preparation", false, false) |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 48 | |
| 49 | FunctionPass *llvm::createWebAssemblyLateEHPrepare() { |
| 50 | return new WebAssemblyLateEHPrepare(); |
| 51 | } |
| 52 | |
| 53 | // Returns the nearest EH pad that dominates this instruction. This does not use |
| 54 | // dominator analysis; it just does BFS on its predecessors until arriving at an |
| 55 | // EH pad. This assumes valid EH scopes so the first EH pad it arrives in all |
| 56 | // possible search paths should be the same. |
| 57 | // Returns nullptr in case it does not find any EH pad in the search, or finds |
| 58 | // multiple different EH pads. |
Heejin Ahn | 095796a | 2018-11-16 00:47:18 +0000 | [diff] [blame] | 59 | static MachineBasicBlock *getMatchingEHPad(MachineInstr *MI) { |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 60 | MachineFunction *MF = MI->getParent()->getParent(); |
| 61 | SmallVector<MachineBasicBlock *, 2> WL; |
| 62 | SmallPtrSet<MachineBasicBlock *, 2> Visited; |
| 63 | WL.push_back(MI->getParent()); |
| 64 | MachineBasicBlock *EHPad = nullptr; |
| 65 | while (!WL.empty()) { |
| 66 | MachineBasicBlock *MBB = WL.pop_back_val(); |
| 67 | if (Visited.count(MBB)) |
| 68 | continue; |
| 69 | Visited.insert(MBB); |
| 70 | if (MBB->isEHPad()) { |
| 71 | if (EHPad && EHPad != MBB) |
| 72 | return nullptr; |
| 73 | EHPad = MBB; |
| 74 | continue; |
| 75 | } |
| 76 | if (MBB == &MF->front()) |
| 77 | return nullptr; |
| 78 | WL.append(MBB->pred_begin(), MBB->pred_end()); |
| 79 | } |
| 80 | return EHPad; |
| 81 | } |
| 82 | |
Heejin Ahn | 095796a | 2018-11-16 00:47:18 +0000 | [diff] [blame] | 83 | // Erase the specified BBs if the BB does not have any remaining predecessors, |
| 84 | // and also all its dead children. |
Benjamin Kramer | 83996e4 | 2018-08-08 10:13:19 +0000 | [diff] [blame] | 85 | template <typename Container> |
Heejin Ahn | 095796a | 2018-11-16 00:47:18 +0000 | [diff] [blame] | 86 | static void eraseDeadBBsAndChildren(const Container &MBBs) { |
Benjamin Kramer | 83996e4 | 2018-08-08 10:13:19 +0000 | [diff] [blame] | 87 | SmallVector<MachineBasicBlock *, 8> WL(MBBs.begin(), MBBs.end()); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 88 | while (!WL.empty()) { |
| 89 | MachineBasicBlock *MBB = WL.pop_back_val(); |
Heejin Ahn | 095796a | 2018-11-16 00:47:18 +0000 | [diff] [blame] | 90 | if (!MBB->pred_empty()) |
| 91 | continue; |
Heejin Ahn | b68d591 | 2018-10-04 21:03:35 +0000 | [diff] [blame] | 92 | SmallVector<MachineBasicBlock *, 4> Succs(MBB->succ_begin(), |
| 93 | MBB->succ_end()); |
| 94 | WL.append(MBB->succ_begin(), MBB->succ_end()); |
| 95 | for (auto *Succ : Succs) |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 96 | MBB->removeSuccessor(Succ); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 97 | MBB->eraseFromParent(); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | bool WebAssemblyLateEHPrepare::runOnMachineFunction(MachineFunction &MF) { |
Heejin Ahn | 569f090 | 2019-01-09 23:05:21 +0000 | [diff] [blame] | 102 | LLVM_DEBUG(dbgs() << "********** Late EH Prepare **********\n" |
| 103 | "********** Function: " |
| 104 | << MF.getName() << '\n'); |
| 105 | |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 106 | if (MF.getTarget().getMCAsmInfo()->getExceptionHandlingType() != |
| 107 | ExceptionHandling::Wasm) |
| 108 | return false; |
| 109 | |
| 110 | bool Changed = false; |
Heejin Ahn | 095796a | 2018-11-16 00:47:18 +0000 | [diff] [blame] | 111 | Changed |= removeUnnecessaryUnreachables(MF); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 112 | if (!MF.getFunction().hasPersonalityFn()) |
| 113 | return Changed; |
| 114 | Changed |= replaceFuncletReturns(MF); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 115 | Changed |= addCatches(MF); |
| 116 | Changed |= addExceptionExtraction(MF); |
Heejin Ahn | 0bb9865 | 2019-01-30 22:44:45 +0000 | [diff] [blame] | 117 | Changed |= restoreStackPointer(MF); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 118 | return Changed; |
| 119 | } |
| 120 | |
Heejin Ahn | 095796a | 2018-11-16 00:47:18 +0000 | [diff] [blame] | 121 | bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables( |
| 122 | MachineFunction &MF) { |
| 123 | bool Changed = false; |
| 124 | for (auto &MBB : MF) { |
| 125 | for (auto &MI : MBB) { |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 126 | if (MI.getOpcode() != WebAssembly::THROW && |
| 127 | MI.getOpcode() != WebAssembly::RETHROW) |
Heejin Ahn | 095796a | 2018-11-16 00:47:18 +0000 | [diff] [blame] | 128 | continue; |
| 129 | Changed = true; |
| 130 | |
| 131 | // The instruction after the throw should be an unreachable or a branch to |
| 132 | // another BB that should eventually lead to an unreachable. Delete it |
| 133 | // because throw itself is a terminator, and also delete successors if |
| 134 | // any. |
| 135 | MBB.erase(std::next(MachineBasicBlock::iterator(MI)), MBB.end()); |
| 136 | SmallVector<MachineBasicBlock *, 8> Succs(MBB.succ_begin(), |
| 137 | MBB.succ_end()); |
| 138 | for (auto *Succ : Succs) |
| 139 | MBB.removeSuccessor(Succ); |
| 140 | eraseDeadBBsAndChildren(Succs); |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | return Changed; |
| 145 | } |
| 146 | |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 147 | bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) { |
| 148 | bool Changed = false; |
| 149 | const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 150 | |
| 151 | for (auto &MBB : MF) { |
| 152 | auto Pos = MBB.getFirstTerminator(); |
| 153 | if (Pos == MBB.end()) |
| 154 | continue; |
| 155 | MachineInstr *TI = &*Pos; |
| 156 | |
| 157 | switch (TI->getOpcode()) { |
| 158 | case WebAssembly::CATCHRET: { |
| 159 | // Replace a catchret with a branch |
| 160 | MachineBasicBlock *TBB = TI->getOperand(0).getMBB(); |
| 161 | if (!MBB.isLayoutSuccessor(TBB)) |
| 162 | BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::BR)) |
| 163 | .addMBB(TBB); |
| 164 | TI->eraseFromParent(); |
| 165 | Changed = true; |
| 166 | break; |
| 167 | } |
| 168 | case WebAssembly::CLEANUPRET: { |
| 169 | // Replace a cleanupret with a rethrow |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 170 | BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW)); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 171 | TI->eraseFromParent(); |
| 172 | Changed = true; |
| 173 | break; |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | return Changed; |
| 178 | } |
| 179 | |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 180 | // Add catch instruction to beginning of catchpads and cleanuppads. |
| 181 | bool WebAssemblyLateEHPrepare::addCatches(MachineFunction &MF) { |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 182 | bool Changed = false; |
| 183 | const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 184 | MachineRegisterInfo &MRI = MF.getRegInfo(); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 185 | for (auto &MBB : MF) { |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 186 | if (MBB.isEHPad()) { |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 187 | Changed = true; |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 188 | unsigned DstReg = |
| 189 | MRI.createVirtualRegister(&WebAssembly::EXCEPT_REFRegClass); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 190 | BuildMI(MBB, MBB.begin(), MBB.begin()->getDebugLoc(), |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 191 | TII.get(WebAssembly::CATCH), DstReg); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 192 | } |
| 193 | } |
| 194 | return Changed; |
| 195 | } |
| 196 | |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 197 | // Wasm uses 'br_on_exn' instruction to check the tag of an exception. It takes |
| 198 | // except_ref type object returned by 'catch', and branches to the destination |
| 199 | // if it matches a given tag. We currently use __cpp_exception symbol to |
| 200 | // represent the tag for all C++ exceptions. |
| 201 | // |
| 202 | // block $l (result i32) |
| 203 | // ... |
| 204 | // ;; except_ref $e is on the stack at this point |
| 205 | // br_on_exn $l $e ;; branch to $l with $e's arguments |
| 206 | // ... |
| 207 | // end |
| 208 | // ;; Here we expect the extracted values are on top of the wasm value stack |
| 209 | // ... Handle exception using values ... |
| 210 | // |
| 211 | // br_on_exn takes an except_ref object and branches if it matches the given |
| 212 | // tag. There can be multiple br_on_exn instructions if we want to match for |
| 213 | // another tag, but for now we only test for __cpp_exception tag, and if it does |
| 214 | // not match, i.e., it is a foreign exception, we rethrow it. |
| 215 | // |
| 216 | // In the destination BB that's the target of br_on_exn, extracted exception |
| 217 | // values (in C++'s case a single i32, which represents an exception pointer) |
| 218 | // are placed on top of the wasm stack. Because we can't model wasm stack in |
| 219 | // LLVM instruction, we use 'extract_exception' pseudo instruction to retrieve |
| 220 | // it. The pseudo instruction will be deleted later. |
| 221 | bool WebAssemblyLateEHPrepare::addExceptionExtraction(MachineFunction &MF) { |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 222 | const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); |
| 223 | auto *EHInfo = MF.getWasmEHFuncInfo(); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 224 | SmallVector<MachineInstr *, 16> ExtractInstrs; |
Heejin Ahn | d2a56ac | 2019-02-26 04:08:49 +0000 | [diff] [blame] | 225 | SmallVector<MachineInstr *, 8> ToDelete; |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 226 | for (auto &MBB : MF) { |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 227 | for (auto &MI : MBB) { |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 228 | if (MI.getOpcode() == WebAssembly::EXTRACT_EXCEPTION_I32) { |
| 229 | if (MI.getOperand(0).isDead()) |
Heejin Ahn | d2a56ac | 2019-02-26 04:08:49 +0000 | [diff] [blame] | 230 | ToDelete.push_back(&MI); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 231 | else |
| 232 | ExtractInstrs.push_back(&MI); |
| 233 | } |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 234 | } |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 235 | } |
Heejin Ahn | d2a56ac | 2019-02-26 04:08:49 +0000 | [diff] [blame] | 236 | bool Changed = !ToDelete.empty() || !ExtractInstrs.empty(); |
| 237 | for (auto *MI : ToDelete) |
| 238 | MI->eraseFromParent(); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 239 | if (ExtractInstrs.empty()) |
Heejin Ahn | d2a56ac | 2019-02-26 04:08:49 +0000 | [diff] [blame] | 240 | return Changed; |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 241 | |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 242 | // Find terminate pads. |
| 243 | SmallSet<MachineBasicBlock *, 8> TerminatePads; |
| 244 | for (auto &MBB : MF) { |
| 245 | for (auto &MI : MBB) { |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 246 | if (MI.isCall()) { |
| 247 | const MachineOperand &CalleeOp = MI.getOperand(0); |
| 248 | if (CalleeOp.isGlobal() && CalleeOp.getGlobal()->getName() == |
| 249 | WebAssembly::ClangCallTerminateFn) |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 250 | TerminatePads.insert(getMatchingEHPad(&MI)); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 251 | } |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 252 | } |
| 253 | } |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 254 | |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 255 | for (auto *Extract : ExtractInstrs) { |
| 256 | MachineBasicBlock *EHPad = getMatchingEHPad(Extract); |
| 257 | assert(EHPad && "No matching EH pad for extract_exception"); |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 258 | MachineInstr *Catch = &*EHPad->begin(); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 259 | if (Catch->getNextNode() != Extract) |
| 260 | EHPad->insert(Catch->getNextNode(), Extract->removeFromParent()); |
| 261 | |
| 262 | // - Before: |
| 263 | // ehpad: |
| 264 | // %exnref:except_ref = catch |
| 265 | // %exn:i32 = extract_exception |
| 266 | // ... use exn ... |
| 267 | // |
| 268 | // - After: |
| 269 | // ehpad: |
| 270 | // %exnref:except_ref = catch |
| 271 | // br_on_exn %thenbb, $__cpp_exception, %exnref |
| 272 | // br %elsebb |
| 273 | // elsebb: |
| 274 | // rethrow |
| 275 | // thenbb: |
| 276 | // %exn:i32 = extract_exception |
| 277 | // ... use exn ... |
Heejin Ahn | c739761 | 2019-03-05 11:11:34 +0000 | [diff] [blame^] | 278 | unsigned ExnReg = Catch->getOperand(0).getReg(); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 279 | auto *ThenMBB = MF.CreateMachineBasicBlock(); |
| 280 | auto *ElseMBB = MF.CreateMachineBasicBlock(); |
| 281 | MF.insert(std::next(MachineFunction::iterator(EHPad)), ElseMBB); |
| 282 | MF.insert(std::next(MachineFunction::iterator(ElseMBB)), ThenMBB); |
| 283 | ThenMBB->splice(ThenMBB->end(), EHPad, Extract, EHPad->end()); |
| 284 | ThenMBB->transferSuccessors(EHPad); |
| 285 | EHPad->addSuccessor(ThenMBB); |
| 286 | EHPad->addSuccessor(ElseMBB); |
| 287 | |
| 288 | DebugLoc DL = Extract->getDebugLoc(); |
| 289 | const char *CPPExnSymbol = MF.createExternalSymbolName("__cpp_exception"); |
| 290 | BuildMI(EHPad, DL, TII.get(WebAssembly::BR_ON_EXN)) |
| 291 | .addMBB(ThenMBB) |
| 292 | .addExternalSymbol(CPPExnSymbol, WebAssemblyII::MO_SYMBOL_EVENT) |
Heejin Ahn | c739761 | 2019-03-05 11:11:34 +0000 | [diff] [blame^] | 293 | .addReg(ExnReg); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 294 | BuildMI(EHPad, DL, TII.get(WebAssembly::BR)).addMBB(ElseMBB); |
| 295 | |
| 296 | // When this is a terminate pad with __clang_call_terminate() call, we don't |
| 297 | // rethrow it anymore and call __clang_call_terminate() with a nullptr |
| 298 | // argument, which will call std::terminate(). |
| 299 | // |
| 300 | // - Before: |
| 301 | // ehpad: |
| 302 | // %exnref:except_ref = catch |
| 303 | // %exn:i32 = extract_exception |
| 304 | // call @__clang_call_terminate(%exn) |
| 305 | // unreachable |
| 306 | // |
| 307 | // - After: |
| 308 | // ehpad: |
| 309 | // %exnref:except_ref = catch |
| 310 | // br_on_exn %thenbb, $__cpp_exception, %exnref |
| 311 | // br %elsebb |
| 312 | // elsebb: |
| 313 | // call @__clang_call_terminate(0) |
| 314 | // unreachable |
| 315 | // thenbb: |
| 316 | // %exn:i32 = extract_exception |
| 317 | // call @__clang_call_terminate(%exn) |
| 318 | // unreachable |
| 319 | if (TerminatePads.count(EHPad)) { |
| 320 | Function *ClangCallTerminateFn = |
| 321 | MF.getFunction().getParent()->getFunction( |
| 322 | WebAssembly::ClangCallTerminateFn); |
| 323 | assert(ClangCallTerminateFn && |
| 324 | "There is no __clang_call_terminate() function"); |
| 325 | BuildMI(ElseMBB, DL, TII.get(WebAssembly::CALL_VOID)) |
| 326 | .addGlobalAddress(ClangCallTerminateFn) |
| 327 | .addImm(0); |
| 328 | BuildMI(ElseMBB, DL, TII.get(WebAssembly::UNREACHABLE)); |
| 329 | |
| 330 | } else { |
| 331 | BuildMI(ElseMBB, DL, TII.get(WebAssembly::RETHROW)); |
| 332 | if (EHInfo->hasEHPadUnwindDest(EHPad)) |
Heejin Ahn | 195a62e | 2019-03-03 22:35:56 +0000 | [diff] [blame] | 333 | ElseMBB->addSuccessor(EHInfo->getEHPadUnwindDest(EHPad)); |
Heejin Ahn | d6f4878 | 2019-01-30 03:21:57 +0000 | [diff] [blame] | 334 | } |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 335 | } |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 336 | |
Heejin Ahn | 4934f76 | 2018-06-25 01:07:11 +0000 | [diff] [blame] | 337 | return true; |
| 338 | } |
Heejin Ahn | 0bb9865 | 2019-01-30 22:44:45 +0000 | [diff] [blame] | 339 | |
| 340 | // After the stack is unwound due to a thrown exception, the __stack_pointer |
| 341 | // global can point to an invalid address. This inserts instructions that |
| 342 | // restore __stack_pointer global. |
| 343 | bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { |
| 344 | const auto *FrameLowering = static_cast<const WebAssemblyFrameLowering *>( |
| 345 | MF.getSubtarget().getFrameLowering()); |
| 346 | if (!FrameLowering->needsPrologForEH(MF)) |
| 347 | return false; |
| 348 | bool Changed = false; |
| 349 | |
| 350 | for (auto &MBB : MF) { |
| 351 | if (!MBB.isEHPad()) |
| 352 | continue; |
| 353 | Changed = true; |
| 354 | |
| 355 | // Insert __stack_pointer restoring instructions at the beginning of each EH |
| 356 | // pad, after the catch instruction. Here it is safe to assume that SP32 |
| 357 | // holds the latest value of __stack_pointer, because the only exception for |
| 358 | // this case is when a function uses the red zone, but that only happens |
| 359 | // with leaf functions, and we don't restore __stack_pointer in leaf |
| 360 | // functions anyway. |
| 361 | auto InsertPos = MBB.begin(); |
| 362 | if (MBB.begin()->getOpcode() == WebAssembly::CATCH) |
| 363 | InsertPos++; |
| 364 | FrameLowering->writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPos, |
| 365 | MBB.begin()->getDebugLoc()); |
| 366 | } |
| 367 | return Changed; |
| 368 | } |