LLVM  14.0.0git
WebAssemblyLateEHPrepare.cpp
Go to the documentation of this file.
1 //=== WebAssemblyLateEHPrepare.cpp - WebAssembly Exception Preparation -===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// \brief Does various transformations for exception handling.
11 ///
12 //===----------------------------------------------------------------------===//
13 
16 #include "WebAssembly.h"
17 #include "WebAssemblySubtarget.h"
18 #include "llvm/ADT/SmallPtrSet.h"
21 #include "llvm/MC/MCAsmInfo.h"
22 #include "llvm/Support/Debug.h"
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "wasm-late-eh-prepare"
27 
28 namespace {
29 class WebAssemblyLateEHPrepare final : public MachineFunctionPass {
30  StringRef getPassName() const override {
31  return "WebAssembly Late Prepare Exception";
32  }
33 
34  bool runOnMachineFunction(MachineFunction &MF) override;
35  bool removeUnreachableEHPads(MachineFunction &MF);
36  void recordCatchRetBBs(MachineFunction &MF);
37  bool hoistCatches(MachineFunction &MF);
38  bool addCatchAlls(MachineFunction &MF);
39  bool replaceFuncletReturns(MachineFunction &MF);
40  bool removeUnnecessaryUnreachables(MachineFunction &MF);
41  bool restoreStackPointer(MachineFunction &MF);
42 
43  MachineBasicBlock *getMatchingEHPad(MachineInstr *MI);
45 
46 public:
47  static char ID; // Pass identification, replacement for typeid
48  WebAssemblyLateEHPrepare() : MachineFunctionPass(ID) {}
49 };
50 } // end anonymous namespace
51 
53 INITIALIZE_PASS(WebAssemblyLateEHPrepare, DEBUG_TYPE,
54  "WebAssembly Late Exception Preparation", false, false)
55 
57  return new WebAssemblyLateEHPrepare();
58 }
59 
60 // Returns the nearest EH pad that dominates this instruction. This does not use
61 // dominator analysis; it just does BFS on its predecessors until arriving at an
62 // EH pad. This assumes valid EH scopes so the first EH pad it arrives in all
63 // possible search paths should be the same.
64 // Returns nullptr in case it does not find any EH pad in the search, or finds
65 // multiple different EH pads.
67 WebAssemblyLateEHPrepare::getMatchingEHPad(MachineInstr *MI) {
68  MachineFunction *MF = MI->getParent()->getParent();
71  WL.push_back(MI->getParent());
72  MachineBasicBlock *EHPad = nullptr;
73  while (!WL.empty()) {
75  if (Visited.count(MBB))
76  continue;
77  Visited.insert(MBB);
78  if (MBB->isEHPad()) {
79  if (EHPad && EHPad != MBB)
80  return nullptr;
81  EHPad = MBB;
82  continue;
83  }
84  if (MBB == &MF->front())
85  return nullptr;
86  for (auto *Pred : MBB->predecessors())
87  if (!CatchRetBBs.count(Pred)) // We don't go into child scopes
88  WL.push_back(Pred);
89  }
90  return EHPad;
91 }
92 
93 // Erase the specified BBs if the BB does not have any remaining predecessors,
94 // and also all its dead children.
95 template <typename Container>
96 static void eraseDeadBBsAndChildren(const Container &MBBs) {
97  SmallVector<MachineBasicBlock *, 8> WL(MBBs.begin(), MBBs.end());
99  while (!WL.empty()) {
101  if (Deleted.count(MBB) || !MBB->pred_empty())
102  continue;
104  WL.append(MBB->succ_begin(), MBB->succ_end());
105  for (auto *Succ : Succs)
106  MBB->removeSuccessor(Succ);
107  // To prevent deleting the same BB multiple times, which can happen when
108  // 'MBBs' contain both a parent and a child
109  Deleted.insert(MBB);
110  MBB->eraseFromParent();
111  }
112 }
113 
114 bool WebAssemblyLateEHPrepare::runOnMachineFunction(MachineFunction &MF) {
115  LLVM_DEBUG(dbgs() << "********** Late EH Prepare **********\n"
116  "********** Function: "
117  << MF.getName() << '\n');
118 
121  return false;
122 
123  bool Changed = false;
124  if (MF.getFunction().hasPersonalityFn()) {
125  Changed |= removeUnreachableEHPads(MF);
126  recordCatchRetBBs(MF);
127  Changed |= hoistCatches(MF);
128  Changed |= addCatchAlls(MF);
129  Changed |= replaceFuncletReturns(MF);
130  }
131  Changed |= removeUnnecessaryUnreachables(MF);
132  if (MF.getFunction().hasPersonalityFn())
133  Changed |= restoreStackPointer(MF);
134  return Changed;
135 }
136 
137 // Remove unreachable EH pads and its children. If they remain, CFG
138 // stackification can be tricky.
139 bool WebAssemblyLateEHPrepare::removeUnreachableEHPads(MachineFunction &MF) {
141  for (auto &MBB : MF)
142  if (MBB.isEHPad() && MBB.pred_empty())
143  ToDelete.push_back(&MBB);
144  eraseDeadBBsAndChildren(ToDelete);
145  return !ToDelete.empty();
146 }
147 
148 // Record which BB ends with catchret instruction, because this will be replaced
149 // with 'br's later. This set of catchret BBs is necessary in 'getMatchingEHPad'
150 // function.
151 void WebAssemblyLateEHPrepare::recordCatchRetBBs(MachineFunction &MF) {
152  CatchRetBBs.clear();
153  for (auto &MBB : MF) {
154  auto Pos = MBB.getFirstTerminator();
155  if (Pos == MBB.end())
156  continue;
157  MachineInstr *TI = &*Pos;
158  if (TI->getOpcode() == WebAssembly::CATCHRET)
159  CatchRetBBs.insert(&MBB);
160  }
161 }
162 
163 // Hoist catch instructions to the beginning of their matching EH pad BBs in
164 // case,
165 // (1) catch instruction is not the first instruction in EH pad.
166 // ehpad:
167 // some_other_instruction
168 // ...
169 // %exn = catch 0
170 // (2) catch instruction is in a non-EH pad BB. For example,
171 // ehpad:
172 // br bb0
173 // bb0:
174 // %exn = catch 0
175 bool WebAssemblyLateEHPrepare::hoistCatches(MachineFunction &MF) {
176  bool Changed = false;
178  for (auto &MBB : MF)
179  for (auto &MI : MBB)
180  if (WebAssembly::isCatch(MI.getOpcode()))
181  Catches.push_back(&MI);
182 
183  for (auto *Catch : Catches) {
184  MachineBasicBlock *EHPad = getMatchingEHPad(Catch);
185  assert(EHPad && "No matching EH pad for catch");
186  auto InsertPos = EHPad->begin();
187  // Skip EH_LABELs in the beginning of an EH pad if present. We don't use
188  // these labels at the moment, but other targets also seem to have an
189  // EH_LABEL instruction in the beginning of an EH pad.
190  while (InsertPos != EHPad->end() && InsertPos->isEHLabel())
191  InsertPos++;
192  if (InsertPos == Catch)
193  continue;
194  Changed = true;
195  EHPad->insert(InsertPos, Catch->removeFromParent());
196  }
197  return Changed;
198 }
199 
200 // Add catch_all to beginning of cleanup pads.
201 bool WebAssemblyLateEHPrepare::addCatchAlls(MachineFunction &MF) {
202  bool Changed = false;
203  const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
204 
205  for (auto &MBB : MF) {
206  if (!MBB.isEHPad())
207  continue;
208  auto InsertPos = MBB.begin();
209  // Skip EH_LABELs in the beginning of an EH pad if present.
210  while (InsertPos != MBB.end() && InsertPos->isEHLabel())
211  InsertPos++;
212  // This runs after hoistCatches(), so we assume that if there is a catch,
213  // that should be the first non-EH-label instruction in an EH pad.
214  if (InsertPos == MBB.end() ||
215  !WebAssembly::isCatch(InsertPos->getOpcode())) {
216  Changed = true;
217  BuildMI(MBB, InsertPos,
218  InsertPos == MBB.end() ? DebugLoc() : InsertPos->getDebugLoc(),
219  TII.get(WebAssembly::CATCH_ALL));
220  }
221  }
222  return Changed;
223 }
224 
225 // Replace pseudo-instructions catchret and cleanupret with br and rethrow
226 // respectively.
227 bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) {
228  bool Changed = false;
229  const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
230 
231  for (auto &MBB : MF) {
232  auto Pos = MBB.getFirstTerminator();
233  if (Pos == MBB.end())
234  continue;
235  MachineInstr *TI = &*Pos;
236 
237  switch (TI->getOpcode()) {
238  case WebAssembly::CATCHRET: {
239  // Replace a catchret with a branch
240  MachineBasicBlock *TBB = TI->getOperand(0).getMBB();
241  if (!MBB.isLayoutSuccessor(TBB))
242  BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::BR))
243  .addMBB(TBB);
244  TI->eraseFromParent();
245  Changed = true;
246  break;
247  }
249  // Replace a cleanupret with a rethrow. For C++ support, currently
250  // rethrow's immediate argument is always 0 (= the latest exception).
251  BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW))
252  .addImm(0);
253  TI->eraseFromParent();
254  Changed = true;
255  break;
256  }
257  }
258  }
259  return Changed;
260 }
261 
262 // Remove unnecessary unreachables after a throw or rethrow.
263 bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables(
264  MachineFunction &MF) {
265  bool Changed = false;
266  for (auto &MBB : MF) {
267  for (auto &MI : MBB) {
268  if (MI.getOpcode() != WebAssembly::THROW &&
269  MI.getOpcode() != WebAssembly::RETHROW)
270  continue;
271  Changed = true;
272 
273  // The instruction after the throw should be an unreachable or a branch to
274  // another BB that should eventually lead to an unreachable. Delete it
275  // because throw itself is a terminator, and also delete successors if
276  // any.
277  MBB.erase(std::next(MI.getIterator()), MBB.end());
279  for (auto *Succ : Succs)
280  if (!Succ->isEHPad())
281  MBB.removeSuccessor(Succ);
283  }
284  }
285 
286  return Changed;
287 }
288 
289 // After the stack is unwound due to a thrown exception, the __stack_pointer
290 // global can point to an invalid address. This inserts instructions that
291 // restore __stack_pointer global.
292 bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) {
293  const auto *FrameLowering = static_cast<const WebAssemblyFrameLowering *>(
295  if (!FrameLowering->needsPrologForEH(MF))
296  return false;
297  bool Changed = false;
298 
299  for (auto &MBB : MF) {
300  if (!MBB.isEHPad())
301  continue;
302  Changed = true;
303 
304  // Insert __stack_pointer restoring instructions at the beginning of each EH
305  // pad, after the catch instruction. Here it is safe to assume that SP32
306  // holds the latest value of __stack_pointer, because the only exception for
307  // this case is when a function uses the red zone, but that only happens
308  // with leaf functions, and we don't restore __stack_pointer in leaf
309  // functions anyway.
310  auto InsertPos = MBB.begin();
311  // Skip EH_LABELs in the beginning of an EH pad if present.
312  while (InsertPos != MBB.end() && InsertPos->isEHLabel())
313  InsertPos++;
314  assert(InsertPos != MBB.end() &&
315  WebAssembly::isCatch(InsertPos->getOpcode()) &&
316  "catch/catch_all should be present in every EH pad at this point");
317  ++InsertPos; // Skip the catch instruction
318  FrameLowering->writeSPToGlobal(FrameLowering->getSPReg(MF), MF, MBB,
319  InsertPos, MBB.begin()->getDebugLoc());
320  }
321  return Changed;
322 }
MI
IRTranslator LLVM IR MI
Definition: IRTranslator.cpp:105
llvm::MachineInstrBuilder::addImm
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Definition: MachineInstrBuilder.h:131
llvm
This file implements support for optimizing divisions by a constant.
Definition: AllocatorList.h:23
WebAssembly.h
llvm::WebAssembly::isCatch
bool isCatch(unsigned Opc)
Definition: WebAssemblyMCTargetDesc.h:409
llvm::WebAssemblyFrameLowering
Definition: WebAssemblyFrameLowering.h:22
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1168
llvm::MachineFunctionPass
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
Definition: MachineFunctionPass.h:30
INITIALIZE_PASS
INITIALIZE_PASS(WebAssemblyLateEHPrepare, DEBUG_TYPE, "WebAssembly Late Exception Preparation", false, false) FunctionPass *llvm
Definition: WebAssemblyLateEHPrepare.cpp:53
llvm::SmallPtrSet
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:449
llvm::SmallVectorImpl::pop_back_val
LLVM_NODISCARD T pop_back_val()
Definition: SmallVector.h:635
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
eraseDeadBBsAndChildren
static void eraseDeadBBsAndChildren(const Container &MBBs)
Definition: WebAssemblyLateEHPrepare.cpp:96
llvm::MachineBasicBlock::erase
instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
Definition: MachineBasicBlock.cpp:1304
llvm::dbgs
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
LoopDeletionResult::Deleted
@ Deleted
llvm::MachineFunction::front
const MachineBasicBlock & front() const
Definition: MachineFunction.h:824
TargetMachine.h
llvm::MachineInstrBuilder::addMBB
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
Definition: MachineInstrBuilder.h:146
llvm::SmallVectorImpl::append
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:648
llvm::MachineBasicBlock::succ_end
succ_iterator succ_end()
Definition: MachineBasicBlock.h:334
llvm::ISD::CATCHRET
@ CATCHRET
CATCHRET - Represents a return from a catch block funclet.
Definition: ISDOpcodes.h:999
llvm::MachineInstr::getOperand
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:499
llvm::MachineBasicBlock::eraseFromParent
void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
Definition: MachineBasicBlock.cpp:1337
DEBUG_TYPE
#define DEBUG_TYPE
Definition: WebAssemblyLateEHPrepare.cpp:26
TII
const HexagonInstrInfo * TII
Definition: HexagonCopyToCombine.cpp:129
llvm::ExceptionHandling::Wasm
@ Wasm
WebAssembly Exception Handling.
llvm::Function::hasPersonalityFn
bool hasPersonalityFn() const
Check whether this function has a personality function.
Definition: Function.h:786
SmallPtrSet.h
llvm::MachineBasicBlock
Definition: MachineBasicBlock.h:95
WebAssemblyUtilities.h
WebAssemblyMCTargetDesc.h
llvm::MachineFunction::getSubtarget
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Definition: MachineFunction.h:630
llvm::MachineInstr::getDebugLoc
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
Definition: MachineInstr.h:418
llvm::MachineInstr
Representation of each machine instruction.
Definition: MachineInstr.h:64
llvm::ISD::CLEANUPRET
@ CLEANUPRET
CLEANUPRET - Represents a return from a cleanup block funclet.
Definition: ISDOpcodes.h:1003
llvm::MachineFunction::getName
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Definition: MachineFunction.cpp:542
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::MachineBasicBlock::succ_begin
succ_iterator succ_begin()
Definition: MachineBasicBlock.h:332
llvm::MachineBasicBlock::predecessors
iterator_range< pred_iterator > predecessors()
Definition: MachineBasicBlock.h:349
llvm::MachineBasicBlock::pred_empty
bool pred_empty() const
Definition: MachineBasicBlock.h:331
llvm::SmallPtrSetImpl::count
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
Definition: SmallPtrSet.h:382
llvm::MachineFunction
Definition: MachineFunction.h:234
llvm::MachineBasicBlock::getFirstTerminator
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
Definition: MachineBasicBlock.cpp:242
llvm::TargetMachine::getMCAsmInfo
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
Definition: TargetMachine.h:207
llvm::MachineOperand::getMBB
MachineBasicBlock * getMBB() const
Definition: MachineOperand.h:552
MCAsmInfo.h
llvm::MachineBasicBlock::successors
iterator_range< succ_iterator > successors()
Definition: MachineBasicBlock.h:355
llvm::MachineBasicBlock::isEHPad
bool isEHPad() const
Returns true if the block is a landing pad.
Definition: MachineBasicBlock.h:526
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm::MachineInstr::getOpcode
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:489
llvm::WebAssemblySubtarget
Definition: WebAssemblySubtarget.h:35
MBB
MachineBasicBlock & MBB
Definition: AArch64SLSHardening.cpp:74
llvm::MachineFunction::getFunction
Function & getFunction()
Return the LLVM function that this machine code represents.
Definition: MachineFunction.h:596
llvm::TargetSubtargetInfo::getFrameLowering
virtual const TargetFrameLowering * getFrameLowering() const
Definition: TargetSubtargetInfo.h:93
llvm::MachineFunction::getTarget
const LLVMTargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Definition: MachineFunction.h:626
llvm::MachineBasicBlock::removeSuccessor
void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
Definition: MachineBasicBlock.cpp:789
llvm::ISD::BR
@ BR
Control flow instructions. These all have token chains.
Definition: ISDOpcodes.h:937
llvm::MachineBasicBlock::insert
instr_iterator insert(instr_iterator I, MachineInstr *M)
Insert MI into the instruction list before I, possibly inside a bundle.
Definition: MachineBasicBlock.cpp:1317
WasmEHFuncInfo.h
WebAssemblySubtarget.h
llvm::SmallVectorImpl::clear
void clear()
Definition: SmallVector.h:585
llvm::MachineBasicBlock::isLayoutSuccessor
bool isLayoutSuccessor(const MachineBasicBlock *MBB) const
Return true if the specified MBB will be emitted immediately after this block, such that if this bloc...
Definition: MachineBasicBlock.cpp:917
llvm::ClrHandlerType::Catch
@ Catch
llvm::MCAsmInfo::getExceptionHandlingType
ExceptionHandling getExceptionHandlingType() const
Definition: MCAsmInfo.h:762
llvm::MachineBasicBlock::begin
iterator begin()
Definition: MachineBasicBlock.h:268
MachineInstrBuilder.h
llvm::BuildMI
MachineInstrBuilder BuildMI(MachineFunction &MF, const DebugLoc &DL, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
Definition: MachineInstrBuilder.h:328
llvm::FunctionPass
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:298
llvm::DebugLoc
A debug info location.
Definition: DebugLoc.h:33
llvm::createWebAssemblyLateEHPrepare
FunctionPass * createWebAssemblyLateEHPrepare()
llvm::MachineInstr::eraseFromParent
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
Definition: MachineInstr.cpp:680
Debug.h
llvm::MachineBasicBlock::end
iterator end()
Definition: MachineBasicBlock.h:270
llvm::SmallPtrSetImpl::insert
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:364
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:37