LLVM  15.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"
22 #include "llvm/MC/MCAsmInfo.h"
23 #include "llvm/Support/Debug.h"
25 using namespace llvm;
26 
27 #define DEBUG_TYPE "wasm-late-eh-prepare"
28 
29 namespace {
30 class WebAssemblyLateEHPrepare final : public MachineFunctionPass {
31  StringRef getPassName() const override {
32  return "WebAssembly Late Prepare Exception";
33  }
34 
35  bool runOnMachineFunction(MachineFunction &MF) override;
36  bool removeUnreachableEHPads(MachineFunction &MF);
37  void recordCatchRetBBs(MachineFunction &MF);
38  bool hoistCatches(MachineFunction &MF);
39  bool addCatchAlls(MachineFunction &MF);
40  bool replaceFuncletReturns(MachineFunction &MF);
41  bool removeUnnecessaryUnreachables(MachineFunction &MF);
42  bool restoreStackPointer(MachineFunction &MF);
43 
44  MachineBasicBlock *getMatchingEHPad(MachineInstr *MI);
46 
47 public:
48  static char ID; // Pass identification, replacement for typeid
49  WebAssemblyLateEHPrepare() : MachineFunctionPass(ID) {}
50 };
51 } // end anonymous namespace
52 
54 INITIALIZE_PASS(WebAssemblyLateEHPrepare, DEBUG_TYPE,
55  "WebAssembly Late Exception Preparation", false, false)
56 
58  return new WebAssemblyLateEHPrepare();
59 }
60 
61 // Returns the nearest EH pad that dominates this instruction. This does not use
62 // dominator analysis; it just does BFS on its predecessors until arriving at an
63 // EH pad. This assumes valid EH scopes so the first EH pad it arrives in all
64 // possible search paths should be the same.
65 // Returns nullptr in case it does not find any EH pad in the search, or finds
66 // multiple different EH pads.
68 WebAssemblyLateEHPrepare::getMatchingEHPad(MachineInstr *MI) {
69  MachineFunction *MF = MI->getParent()->getParent();
72  WL.push_back(MI->getParent());
73  MachineBasicBlock *EHPad = nullptr;
74  while (!WL.empty()) {
76  if (Visited.count(MBB))
77  continue;
78  Visited.insert(MBB);
79  if (MBB->isEHPad()) {
80  if (EHPad && EHPad != MBB)
81  return nullptr;
82  EHPad = MBB;
83  continue;
84  }
85  if (MBB == &MF->front())
86  return nullptr;
87  for (auto *Pred : MBB->predecessors())
88  if (!CatchRetBBs.count(Pred)) // We don't go into child scopes
89  WL.push_back(Pred);
90  }
91  return EHPad;
92 }
93 
94 // Erase the specified BBs if the BB does not have any remaining predecessors,
95 // and also all its dead children.
96 template <typename Container>
97 static void eraseDeadBBsAndChildren(const Container &MBBs) {
98  SmallVector<MachineBasicBlock *, 8> WL(MBBs.begin(), MBBs.end());
100  while (!WL.empty()) {
102  if (Deleted.count(MBB) || !MBB->pred_empty())
103  continue;
105  WL.append(MBB->succ_begin(), MBB->succ_end());
106  for (auto *Succ : Succs)
107  MBB->removeSuccessor(Succ);
108  // To prevent deleting the same BB multiple times, which can happen when
109  // 'MBBs' contain both a parent and a child
110  Deleted.insert(MBB);
111  MBB->eraseFromParent();
112  }
113 }
114 
115 bool WebAssemblyLateEHPrepare::runOnMachineFunction(MachineFunction &MF) {
116  LLVM_DEBUG(dbgs() << "********** Late EH Prepare **********\n"
117  "********** Function: "
118  << MF.getName() << '\n');
119 
122  return false;
123 
124  bool Changed = false;
125  if (MF.getFunction().hasPersonalityFn()) {
126  Changed |= removeUnreachableEHPads(MF);
127  recordCatchRetBBs(MF);
128  Changed |= hoistCatches(MF);
129  Changed |= addCatchAlls(MF);
130  Changed |= replaceFuncletReturns(MF);
131  }
132  Changed |= removeUnnecessaryUnreachables(MF);
133  if (MF.getFunction().hasPersonalityFn())
134  Changed |= restoreStackPointer(MF);
135  return Changed;
136 }
137 
138 // Remove unreachable EH pads and its children. If they remain, CFG
139 // stackification can be tricky.
140 bool WebAssemblyLateEHPrepare::removeUnreachableEHPads(MachineFunction &MF) {
142  for (auto &MBB : MF)
143  if (MBB.isEHPad() && MBB.pred_empty())
144  ToDelete.push_back(&MBB);
145  eraseDeadBBsAndChildren(ToDelete);
146  return !ToDelete.empty();
147 }
148 
149 // Record which BB ends with catchret instruction, because this will be replaced
150 // with 'br's later. This set of catchret BBs is necessary in 'getMatchingEHPad'
151 // function.
152 void WebAssemblyLateEHPrepare::recordCatchRetBBs(MachineFunction &MF) {
153  CatchRetBBs.clear();
154  for (auto &MBB : MF) {
155  auto Pos = MBB.getFirstTerminator();
156  if (Pos == MBB.end())
157  continue;
158  MachineInstr *TI = &*Pos;
159  if (TI->getOpcode() == WebAssembly::CATCHRET)
160  CatchRetBBs.insert(&MBB);
161  }
162 }
163 
164 // Hoist catch instructions to the beginning of their matching EH pad BBs in
165 // case,
166 // (1) catch instruction is not the first instruction in EH pad.
167 // ehpad:
168 // some_other_instruction
169 // ...
170 // %exn = catch 0
171 // (2) catch instruction is in a non-EH pad BB. For example,
172 // ehpad:
173 // br bb0
174 // bb0:
175 // %exn = catch 0
176 bool WebAssemblyLateEHPrepare::hoistCatches(MachineFunction &MF) {
177  bool Changed = false;
179  for (auto &MBB : MF)
180  for (auto &MI : MBB)
181  if (WebAssembly::isCatch(MI.getOpcode()))
182  Catches.push_back(&MI);
183 
184  for (auto *Catch : Catches) {
185  MachineBasicBlock *EHPad = getMatchingEHPad(Catch);
186  assert(EHPad && "No matching EH pad for catch");
187  auto InsertPos = EHPad->begin();
188  // Skip EH_LABELs in the beginning of an EH pad if present. We don't use
189  // these labels at the moment, but other targets also seem to have an
190  // EH_LABEL instruction in the beginning of an EH pad.
191  while (InsertPos != EHPad->end() && InsertPos->isEHLabel())
192  InsertPos++;
193  if (InsertPos == Catch)
194  continue;
195  Changed = true;
196  EHPad->insert(InsertPos, Catch->removeFromParent());
197  }
198  return Changed;
199 }
200 
201 // Add catch_all to beginning of cleanup pads.
202 bool WebAssemblyLateEHPrepare::addCatchAlls(MachineFunction &MF) {
203  bool Changed = false;
204  const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
205 
206  for (auto &MBB : MF) {
207  if (!MBB.isEHPad())
208  continue;
209  auto InsertPos = MBB.begin();
210  // Skip EH_LABELs in the beginning of an EH pad if present.
211  while (InsertPos != MBB.end() && InsertPos->isEHLabel())
212  InsertPos++;
213  // This runs after hoistCatches(), so we assume that if there is a catch,
214  // that should be the first non-EH-label instruction in an EH pad.
215  if (InsertPos == MBB.end() ||
216  !WebAssembly::isCatch(InsertPos->getOpcode())) {
217  Changed = true;
218  BuildMI(MBB, InsertPos,
219  InsertPos == MBB.end() ? DebugLoc() : InsertPos->getDebugLoc(),
220  TII.get(WebAssembly::CATCH_ALL));
221  }
222  }
223  return Changed;
224 }
225 
226 // Replace pseudo-instructions catchret and cleanupret with br and rethrow
227 // respectively.
228 bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) {
229  bool Changed = false;
230  const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
231 
232  for (auto &MBB : MF) {
233  auto Pos = MBB.getFirstTerminator();
234  if (Pos == MBB.end())
235  continue;
236  MachineInstr *TI = &*Pos;
237 
238  switch (TI->getOpcode()) {
239  case WebAssembly::CATCHRET: {
240  // Replace a catchret with a branch
241  MachineBasicBlock *TBB = TI->getOperand(0).getMBB();
242  if (!MBB.isLayoutSuccessor(TBB))
243  BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::BR))
244  .addMBB(TBB);
245  TI->eraseFromParent();
246  Changed = true;
247  break;
248  }
250  // Replace a cleanupret with a rethrow. For C++ support, currently
251  // rethrow's immediate argument is always 0 (= the latest exception).
252  BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW))
253  .addImm(0);
254  TI->eraseFromParent();
255  Changed = true;
256  break;
257  }
258  }
259  }
260  return Changed;
261 }
262 
263 // Remove unnecessary unreachables after a throw or rethrow.
264 bool WebAssemblyLateEHPrepare::removeUnnecessaryUnreachables(
265  MachineFunction &MF) {
266  bool Changed = false;
267  for (auto &MBB : MF) {
268  for (auto &MI : MBB) {
269  if (MI.getOpcode() != WebAssembly::THROW &&
270  MI.getOpcode() != WebAssembly::RETHROW)
271  continue;
272  Changed = true;
273 
274  // The instruction after the throw should be an unreachable or a branch to
275  // another BB that should eventually lead to an unreachable. Delete it
276  // because throw itself is a terminator, and also delete successors if
277  // any.
278  MBB.erase(std::next(MI.getIterator()), MBB.end());
280  for (auto *Succ : Succs)
281  if (!Succ->isEHPad())
282  MBB.removeSuccessor(Succ);
284  }
285  }
286 
287  return Changed;
288 }
289 
290 // After the stack is unwound due to a thrown exception, the __stack_pointer
291 // global can point to an invalid address. This inserts instructions that
292 // restore __stack_pointer global.
293 bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) {
294  const auto *FrameLowering = static_cast<const WebAssemblyFrameLowering *>(
296  if (!FrameLowering->needsPrologForEH(MF))
297  return false;
298  bool Changed = false;
299 
300  for (auto &MBB : MF) {
301  if (!MBB.isEHPad())
302  continue;
303  Changed = true;
304 
305  // Insert __stack_pointer restoring instructions at the beginning of each EH
306  // pad, after the catch instruction. Here it is safe to assume that SP32
307  // holds the latest value of __stack_pointer, because the only exception for
308  // this case is when a function uses the red zone, but that only happens
309  // with leaf functions, and we don't restore __stack_pointer in leaf
310  // functions anyway.
311  auto InsertPos = MBB.begin();
312  // Skip EH_LABELs in the beginning of an EH pad if present.
313  while (InsertPos != MBB.end() && InsertPos->isEHLabel())
314  InsertPos++;
315  assert(InsertPos != MBB.end() &&
316  WebAssembly::isCatch(InsertPos->getOpcode()) &&
317  "catch/catch_all should be present in every EH pad at this point");
318  ++InsertPos; // Skip the catch instruction
319  FrameLowering->writeSPToGlobal(FrameLowering->getSPReg(MF), MF, MBB,
320  InsertPos, MBB.begin()->getDebugLoc());
321  }
322  return Changed;
323 }
MI
IRTranslator LLVM IR MI
Definition: IRTranslator.cpp:104
llvm::MachineInstrBuilder::addImm
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Definition: MachineInstrBuilder.h:131
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
WebAssembly.h
llvm::WebAssembly::isCatch
bool isCatch(unsigned Opc)
Definition: WebAssemblyMCTargetDesc.h:406
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:1185
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:54
llvm::SmallPtrSet
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
Definition: SmallPtrSet.h:450
llvm::SmallVectorImpl::pop_back_val
LLVM_NODISCARD T pop_back_val()
Definition: SmallVector.h:654
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
eraseDeadBBsAndChildren
static void eraseDeadBBsAndChildren(const Container &MBBs)
Definition: WebAssemblyLateEHPrepare.cpp:97
llvm::MachineBasicBlock::erase
instr_iterator erase(instr_iterator I)
Remove an instruction from the instruction list and delete it.
Definition: MachineBasicBlock.cpp:1295
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:834
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:667
llvm::MachineBasicBlock::succ_end
succ_iterator succ_end()
Definition: MachineBasicBlock.h:343
llvm::ISD::CATCHRET
@ CATCHRET
CATCHRET - Represents a return from a catch block funclet.
Definition: ISDOpcodes.h:1037
llvm::MachineInstr::getOperand
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:501
llvm::MachineBasicBlock::eraseFromParent
void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
Definition: MachineBasicBlock.cpp:1328
DEBUG_TYPE
#define DEBUG_TYPE
Definition: WebAssemblyLateEHPrepare.cpp:27
TII
const HexagonInstrInfo * TII
Definition: HexagonCopyToCombine.cpp:127
llvm::ExceptionHandling::Wasm
@ Wasm
WebAssembly Exception Handling.
llvm::Function::hasPersonalityFn
bool hasPersonalityFn() const
Check whether this function has a personality function.
Definition: Function.h:777
SmallPtrSet.h
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
llvm::MachineBasicBlock
Definition: MachineBasicBlock.h:94
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:640
llvm::MachineInstr::getDebugLoc
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
Definition: MachineInstr.h:420
llvm::MachineInstr
Representation of each machine instruction.
Definition: MachineInstr.h:66
llvm::ISD::CLEANUPRET
@ CLEANUPRET
CLEANUPRET - Represents a return from a cleanup block funclet.
Definition: ISDOpcodes.h:1041
MachineFunctionPass.h
llvm::MachineFunction::getName
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
Definition: MachineFunction.cpp:567
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::MachineBasicBlock::succ_begin
succ_iterator succ_begin()
Definition: MachineBasicBlock.h:341
llvm::MachineBasicBlock::predecessors
iterator_range< pred_iterator > predecessors()
Definition: MachineBasicBlock.h:358
llvm::MachineBasicBlock::pred_empty
bool pred_empty() const
Definition: MachineBasicBlock.h:340
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:383
llvm::MachineFunction
Definition: MachineFunction.h:241
llvm::MachineBasicBlock::getFirstTerminator
iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
Definition: MachineBasicBlock.cpp:238
llvm::TargetMachine::getMCAsmInfo
const MCAsmInfo * getMCAsmInfo() const
Return target specific asm information.
Definition: TargetMachine.h:205
llvm::MachineOperand::getMBB
MachineBasicBlock * getMBB() const
Definition: MachineOperand.h:561
MCAsmInfo.h
llvm::MachineBasicBlock::successors
iterator_range< succ_iterator > successors()
Definition: MachineBasicBlock.h:364
llvm::MachineBasicBlock::isEHPad
bool isEHPad() const
Returns true if the block is a landing pad.
Definition: MachineBasicBlock.h:548
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:491
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:606
llvm::TargetSubtargetInfo::getFrameLowering
virtual const TargetFrameLowering * getFrameLowering() const
Definition: TargetSubtargetInfo.h:94
llvm::MachineFunction::getTarget
const LLVMTargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
Definition: MachineFunction.h:636
llvm::MachineBasicBlock::removeSuccessor
void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
Definition: MachineBasicBlock.cpp:785
llvm::ISD::BR
@ BR
Control flow instructions. These all have token chains.
Definition: ISDOpcodes.h:975
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:1308
WasmEHFuncInfo.h
WebAssemblySubtarget.h
llvm::SmallVectorImpl::clear
void clear()
Definition: SmallVector.h:591
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:913
llvm::ClrHandlerType::Catch
@ Catch
llvm::MCAsmInfo::getExceptionHandlingType
ExceptionHandling getExceptionHandlingType() const
Definition: MCAsmInfo.h:777
llvm::MachineBasicBlock::begin
iterator begin()
Definition: MachineBasicBlock.h:277
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:308
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:650
Debug.h
llvm::MachineBasicBlock::end
iterator end()
Definition: MachineBasicBlock.h:279
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:365
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:37