blob: 6b30f31ab1d72d612b4c374c82f6f7b2aa0fb40b [file] [log] [blame]
Dan Gohman950a13c2015-09-16 16:51:30 +00001//===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dan Gohman950a13c2015-09-16 16:51:30 +00006//
7//===----------------------------------------------------------------------===//
8///
9/// \file
Adrian Prantl5f8f34e42018-05-01 15:54:18 +000010/// This file implements a CFG stacking pass.
Dan Gohman950a13c2015-09-16 16:51:30 +000011///
Heejin Ahne76fa9e2018-08-16 23:50:59 +000012/// This pass inserts BLOCK, LOOP, and TRY markers to mark the start of scopes,
13/// since scope boundaries serve as the labels for WebAssembly's control
14/// transfers.
Dan Gohman950a13c2015-09-16 16:51:30 +000015///
16/// This is sufficient to convert arbitrary CFGs into a form that works on
17/// WebAssembly, provided that all loops are single-entry.
18///
Heejin Ahne76fa9e2018-08-16 23:50:59 +000019/// In case we use exceptions, this pass also fixes mismatches in unwind
20/// destinations created during transforming CFG into wasm structured format.
21///
Dan Gohman950a13c2015-09-16 16:51:30 +000022//===----------------------------------------------------------------------===//
23
Dan Gohman950a13c2015-09-16 16:51:30 +000024#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000025#include "WebAssembly.h"
Heejin Ahne76fa9e2018-08-16 23:50:59 +000026#include "WebAssemblyExceptionInfo.h"
Dan Gohmaned0f1132016-01-30 05:01:06 +000027#include "WebAssemblyMachineFunctionInfo.h"
Dan Gohman950a13c2015-09-16 16:51:30 +000028#include "WebAssemblySubtarget.h"
Dan Gohman4fc4e422016-10-24 19:49:43 +000029#include "WebAssemblyUtilities.h"
Dan Gohman32807932015-11-23 16:19:56 +000030#include "llvm/CodeGen/MachineDominators.h"
Dan Gohman950a13c2015-09-16 16:51:30 +000031#include "llvm/CodeGen/MachineFunction.h"
32#include "llvm/CodeGen/MachineInstrBuilder.h"
33#include "llvm/CodeGen/MachineLoopInfo.h"
Derek Schuff9c3bf312016-01-13 17:10:28 +000034#include "llvm/CodeGen/MachineRegisterInfo.h"
Dan Gohman950a13c2015-09-16 16:51:30 +000035#include "llvm/CodeGen/Passes.h"
Heejin Ahne76fa9e2018-08-16 23:50:59 +000036#include "llvm/CodeGen/WasmEHFuncInfo.h"
37#include "llvm/MC/MCAsmInfo.h"
Dan Gohman950a13c2015-09-16 16:51:30 +000038#include "llvm/Support/Debug.h"
39#include "llvm/Support/raw_ostream.h"
40using namespace llvm;
41
42#define DEBUG_TYPE "wasm-cfg-stackify"
43
44namespace {
45class WebAssemblyCFGStackify final : public MachineFunctionPass {
Mehdi Amini117296c2016-10-01 02:56:57 +000046 StringRef getPassName() const override { return "WebAssembly CFG Stackify"; }
Dan Gohman950a13c2015-09-16 16:51:30 +000047
48 void getAnalysisUsage(AnalysisUsage &AU) const override {
Dan Gohman32807932015-11-23 16:19:56 +000049 AU.addRequired<MachineDominatorTree>();
Dan Gohman950a13c2015-09-16 16:51:30 +000050 AU.addRequired<MachineLoopInfo>();
Heejin Ahne76fa9e2018-08-16 23:50:59 +000051 AU.addRequired<WebAssemblyExceptionInfo>();
Dan Gohman950a13c2015-09-16 16:51:30 +000052 MachineFunctionPass::getAnalysisUsage(AU);
53 }
54
55 bool runOnMachineFunction(MachineFunction &MF) override;
56
Heejin Ahne76fa9e2018-08-16 23:50:59 +000057 // For each block whose label represents the end of a scope, record the block
58 // which holds the beginning of the scope. This will allow us to quickly skip
59 // over scoped regions when walking blocks.
60 SmallVector<MachineBasicBlock *, 8> ScopeTops;
61
62 void placeMarkers(MachineFunction &MF);
63 void placeBlockMarker(MachineBasicBlock &MBB);
64 void placeLoopMarker(MachineBasicBlock &MBB);
65 void placeTryMarker(MachineBasicBlock &MBB);
66 void rewriteDepthImmediates(MachineFunction &MF);
67 void fixEndsAtEndOfFunction(MachineFunction &MF);
68
69 // For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY).
70 DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd;
71 // For each END_(BLOCK|LOOP|TRY), the corresponding BLOCK|LOOP|TRY.
72 DenseMap<const MachineInstr *, MachineInstr *> EndToBegin;
73 // <TRY marker, EH pad> map
74 DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad;
75 // <EH pad, TRY marker> map
76 DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry;
77 // <LOOP|TRY marker, Loop/exception bottom BB> map
78 DenseMap<const MachineInstr *, MachineBasicBlock *> BeginToBottom;
79
Heejin Ahnd2fd7092018-12-07 21:31:14 +000080 // Helper functions to register scope information created by marker
81 // instructions.
Heejin Ahne76fa9e2018-08-16 23:50:59 +000082 void registerScope(MachineInstr *Begin, MachineInstr *End);
83 void registerTryScope(MachineInstr *Begin, MachineInstr *End,
84 MachineBasicBlock *EHPad);
Heejin Ahne76fa9e2018-08-16 23:50:59 +000085
86 MachineBasicBlock *getBottom(const MachineInstr *Begin);
87
Dan Gohman950a13c2015-09-16 16:51:30 +000088public:
89 static char ID; // Pass identification, replacement for typeid
90 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {}
Heejin Ahne76fa9e2018-08-16 23:50:59 +000091 ~WebAssemblyCFGStackify() override { releaseMemory(); }
92 void releaseMemory() override;
Dan Gohman950a13c2015-09-16 16:51:30 +000093};
94} // end anonymous namespace
95
96char WebAssemblyCFGStackify::ID = 0;
Jacob Gravelle40926452018-03-30 20:36:58 +000097INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE,
Heejin Ahnf208f632018-09-05 01:27:38 +000098 "Insert BLOCK and LOOP markers for WebAssembly scopes", false,
99 false)
Jacob Gravelle40926452018-03-30 20:36:58 +0000100
Dan Gohman950a13c2015-09-16 16:51:30 +0000101FunctionPass *llvm::createWebAssemblyCFGStackify() {
102 return new WebAssemblyCFGStackify();
103}
104
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000105/// Test whether Pred has any terminators explicitly branching to MBB, as
106/// opposed to falling through. Note that it's possible (eg. in unoptimized
107/// code) for a branch instruction to both branch to a block and fallthrough
108/// to it, so we check the actual branch operands to see if there are any
109/// explicit mentions.
Dan Gohman35e4a282016-01-08 01:06:00 +0000110static bool ExplicitlyBranchesTo(MachineBasicBlock *Pred,
111 MachineBasicBlock *MBB) {
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000112 for (MachineInstr &MI : Pred->terminators())
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000113 // Even if a rethrow takes a BB argument, it is not a branch
114 if (!WebAssembly::isRethrow(MI))
115 for (MachineOperand &MO : MI.explicit_operands())
116 if (MO.isMBB() && MO.getMBB() == MBB)
117 return true;
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000118 return false;
119}
120
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000121// Returns an iterator to the earliest position possible within the MBB,
122// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
123// contains instructions that should go before the marker, and AfterSet contains
124// ones that should go after the marker. In this function, AfterSet is only
125// used for sanity checking.
126static MachineBasicBlock::iterator
127GetEarliestInsertPos(MachineBasicBlock *MBB,
128 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
129 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
130 auto InsertPos = MBB->end();
131 while (InsertPos != MBB->begin()) {
132 if (BeforeSet.count(&*std::prev(InsertPos))) {
133#ifndef NDEBUG
134 // Sanity check
135 for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos)
136 assert(!AfterSet.count(&*std::prev(Pos)));
137#endif
138 break;
139 }
140 --InsertPos;
141 }
142 return InsertPos;
143}
144
145// Returns an iterator to the latest position possible within the MBB,
146// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
147// contains instructions that should go before the marker, and AfterSet contains
148// ones that should go after the marker. In this function, BeforeSet is only
149// used for sanity checking.
150static MachineBasicBlock::iterator
151GetLatestInsertPos(MachineBasicBlock *MBB,
152 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
153 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
154 auto InsertPos = MBB->begin();
155 while (InsertPos != MBB->end()) {
156 if (AfterSet.count(&*InsertPos)) {
157#ifndef NDEBUG
158 // Sanity check
159 for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos)
160 assert(!BeforeSet.count(&*Pos));
161#endif
162 break;
163 }
164 ++InsertPos;
165 }
166 return InsertPos;
167}
168
169void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin,
170 MachineInstr *End) {
171 BeginToEnd[Begin] = End;
172 EndToBegin[End] = Begin;
173}
174
175void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin,
176 MachineInstr *End,
177 MachineBasicBlock *EHPad) {
178 registerScope(Begin, End);
179 TryToEHPad[Begin] = EHPad;
180 EHPadToTry[EHPad] = Begin;
181}
182
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000183// Given a LOOP/TRY marker, returns its bottom BB. Use cached information if any
184// to prevent recomputation.
185MachineBasicBlock *
186WebAssemblyCFGStackify::getBottom(const MachineInstr *Begin) {
187 const auto &MLI = getAnalysis<MachineLoopInfo>();
188 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
189 if (BeginToBottom.count(Begin))
190 return BeginToBottom[Begin];
191 if (Begin->getOpcode() == WebAssembly::LOOP) {
192 MachineLoop *L = MLI.getLoopFor(Begin->getParent());
193 assert(L);
194 BeginToBottom[Begin] = WebAssembly::getBottom(L);
195 } else if (Begin->getOpcode() == WebAssembly::TRY) {
196 WebAssemblyException *WE = WEI.getExceptionFor(TryToEHPad[Begin]);
197 assert(WE);
198 BeginToBottom[Begin] = WebAssembly::getBottom(WE);
199 } else
200 assert(false);
201 return BeginToBottom[Begin];
202}
203
Dan Gohman32807932015-11-23 16:19:56 +0000204/// Insert a BLOCK marker for branches to MBB (if needed).
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000205void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) {
206 // This should have been handled in placeTryMarker.
207 if (MBB.isEHPad())
208 return;
209
210 MachineFunction &MF = *MBB.getParent();
211 auto &MDT = getAnalysis<MachineDominatorTree>();
212 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
213 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
214
Dan Gohman8fe7e862015-12-14 22:51:54 +0000215 // First compute the nearest common dominator of all forward non-fallthrough
216 // predecessors so that we minimize the time that the BLOCK is on the stack,
217 // which reduces overall stack height.
Dan Gohman32807932015-11-23 16:19:56 +0000218 MachineBasicBlock *Header = nullptr;
219 bool IsBranchedTo = false;
220 int MBBNumber = MBB.getNumber();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000221 for (MachineBasicBlock *Pred : MBB.predecessors()) {
Dan Gohman32807932015-11-23 16:19:56 +0000222 if (Pred->getNumber() < MBBNumber) {
223 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000224 if (ExplicitlyBranchesTo(Pred, &MBB))
Dan Gohman32807932015-11-23 16:19:56 +0000225 IsBranchedTo = true;
226 }
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000227 }
Dan Gohman32807932015-11-23 16:19:56 +0000228 if (!Header)
229 return;
230 if (!IsBranchedTo)
Dan Gohman950a13c2015-09-16 16:51:30 +0000231 return;
232
Dan Gohman8fe7e862015-12-14 22:51:54 +0000233 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors");
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000234 MachineBasicBlock *LayoutPred = &*std::prev(MachineFunction::iterator(&MBB));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000235
236 // If the nearest common dominator is inside a more deeply nested context,
237 // walk out to the nearest scope which isn't more deeply nested.
238 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
239 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
240 if (ScopeTop->getNumber() > Header->getNumber()) {
241 // Skip over an intervening scope.
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000242 I = std::next(MachineFunction::iterator(ScopeTop));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000243 } else {
244 // We found a scope level at an appropriate depth.
245 Header = ScopeTop;
246 break;
247 }
248 }
249 }
250
Dan Gohman8fe7e862015-12-14 22:51:54 +0000251 // Decide where in Header to put the BLOCK.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000252
253 // Instructions that should go before the BLOCK.
254 SmallPtrSet<const MachineInstr *, 4> BeforeSet;
255 // Instructions that should go after the BLOCK.
256 SmallPtrSet<const MachineInstr *, 4> AfterSet;
257 for (const auto &MI : *Header) {
258 // If there is a previously placed LOOP/TRY marker and the bottom block of
259 // the loop/exception is above MBB, it should be after the BLOCK, because
260 // the loop/exception is nested in this block. Otherwise it should be before
261 // the BLOCK.
262 if (MI.getOpcode() == WebAssembly::LOOP ||
263 MI.getOpcode() == WebAssembly::TRY) {
264 if (MBB.getNumber() > getBottom(&MI)->getNumber())
265 AfterSet.insert(&MI);
266#ifndef NDEBUG
267 else
268 BeforeSet.insert(&MI);
269#endif
270 }
271
272 // All previously inserted BLOCK markers should be after the BLOCK because
273 // they are all nested blocks.
274 if (MI.getOpcode() == WebAssembly::BLOCK)
275 AfterSet.insert(&MI);
276
277#ifndef NDEBUG
278 // All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK.
279 if (MI.getOpcode() == WebAssembly::END_BLOCK ||
280 MI.getOpcode() == WebAssembly::END_LOOP ||
281 MI.getOpcode() == WebAssembly::END_TRY)
282 BeforeSet.insert(&MI);
283#endif
284
285 // Terminators should go after the BLOCK.
286 if (MI.isTerminator())
287 AfterSet.insert(&MI);
288 }
289
290 // Local expression tree should go after the BLOCK.
291 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
292 --I) {
Yury Delendik409b4392018-10-04 23:31:00 +0000293 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
294 continue;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000295 if (WebAssembly::isChild(*std::prev(I), MFI))
296 AfterSet.insert(&*std::prev(I));
297 else
298 break;
Dan Gohman950a13c2015-09-16 16:51:30 +0000299 }
300
Dan Gohman8fe7e862015-12-14 22:51:54 +0000301 // Add the BLOCK.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000302 auto InsertPos = GetLatestInsertPos(Header, BeforeSet, AfterSet);
Heejin Ahn92401cc2018-04-14 00:12:12 +0000303 MachineInstr *Begin =
304 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
305 TII.get(WebAssembly::BLOCK))
306 .addImm(int64_t(WebAssembly::ExprType::Void));
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000307
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000308 // Decide where in Header to put the END_BLOCK.
309 BeforeSet.clear();
310 AfterSet.clear();
311 for (auto &MI : MBB) {
312#ifndef NDEBUG
313 // END_BLOCK should precede existing LOOP and TRY markers.
314 if (MI.getOpcode() == WebAssembly::LOOP ||
315 MI.getOpcode() == WebAssembly::TRY)
316 AfterSet.insert(&MI);
317#endif
318
319 // If there is a previously placed END_LOOP marker and the header of the
320 // loop is above this block's header, the END_LOOP should be placed after
321 // the BLOCK, because the loop contains this block. Otherwise the END_LOOP
322 // should be placed before the BLOCK. The same for END_TRY.
323 if (MI.getOpcode() == WebAssembly::END_LOOP ||
324 MI.getOpcode() == WebAssembly::END_TRY) {
325 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber())
326 BeforeSet.insert(&MI);
327#ifndef NDEBUG
328 else
329 AfterSet.insert(&MI);
330#endif
331 }
332 }
333
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000334 // Mark the end of the block.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000335 InsertPos = GetEarliestInsertPos(&MBB, BeforeSet, AfterSet);
Derek Schuff10b31352018-03-15 22:06:51 +0000336 MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos),
Dan Gohman2726b882016-10-06 22:29:32 +0000337 TII.get(WebAssembly::END_BLOCK));
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000338 registerScope(Begin, End);
Dan Gohman8fe7e862015-12-14 22:51:54 +0000339
340 // Track the farthest-spanning scope that ends at this point.
341 int Number = MBB.getNumber();
342 if (!ScopeTops[Number] ||
343 ScopeTops[Number]->getNumber() > Header->getNumber())
344 ScopeTops[Number] = Header;
345}
346
347/// Insert a LOOP marker for a loop starting at MBB (if it's a loop header).
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000348void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) {
349 MachineFunction &MF = *MBB.getParent();
350 const auto &MLI = getAnalysis<MachineLoopInfo>();
351 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
352
Dan Gohman8fe7e862015-12-14 22:51:54 +0000353 MachineLoop *Loop = MLI.getLoopFor(&MBB);
354 if (!Loop || Loop->getHeader() != &MBB)
355 return;
356
357 // The operand of a LOOP is the first block after the loop. If the loop is the
358 // bottom of the function, insert a dummy block at the end.
Heejin Ahn817811ca2018-06-19 00:32:03 +0000359 MachineBasicBlock *Bottom = WebAssembly::getBottom(Loop);
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000360 auto Iter = std::next(MachineFunction::iterator(Bottom));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000361 if (Iter == MF.end()) {
362 MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
363 // Give it a fake predecessor so that AsmPrinter prints its label.
364 Label->addSuccessor(Label);
365 MF.push_back(Label);
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000366 Iter = std::next(MachineFunction::iterator(Bottom));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000367 }
368 MachineBasicBlock *AfterLoop = &*Iter;
Dan Gohman8fe7e862015-12-14 22:51:54 +0000369
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000370 // Decide where in Header to put the LOOP.
371 SmallPtrSet<const MachineInstr *, 4> BeforeSet;
372 SmallPtrSet<const MachineInstr *, 4> AfterSet;
373 for (const auto &MI : MBB) {
374 // LOOP marker should be after any existing loop that ends here. Otherwise
375 // we assume the instruction belongs to the loop.
376 if (MI.getOpcode() == WebAssembly::END_LOOP)
377 BeforeSet.insert(&MI);
378#ifndef NDEBUG
379 else
380 AfterSet.insert(&MI);
381#endif
382 }
383
384 // Mark the beginning of the loop.
385 auto InsertPos = GetEarliestInsertPos(&MBB, BeforeSet, AfterSet);
Derek Schuff10b31352018-03-15 22:06:51 +0000386 MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos),
Dan Gohman2726b882016-10-06 22:29:32 +0000387 TII.get(WebAssembly::LOOP))
Derek Schuff10b31352018-03-15 22:06:51 +0000388 .addImm(int64_t(WebAssembly::ExprType::Void));
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000389
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000390 // Decide where in Header to put the END_LOOP.
391 BeforeSet.clear();
392 AfterSet.clear();
393#ifndef NDEBUG
394 for (const auto &MI : MBB)
395 // Existing END_LOOP markers belong to parent loops of this loop
396 if (MI.getOpcode() == WebAssembly::END_LOOP)
397 AfterSet.insert(&MI);
398#endif
399
400 // Mark the end of the loop (using arbitrary debug location that branched to
401 // the loop end as its location).
402 InsertPos = GetEarliestInsertPos(AfterLoop, BeforeSet, AfterSet);
Derek Schuff10b31352018-03-15 22:06:51 +0000403 DebugLoc EndDL = (*AfterLoop->pred_rbegin())->findBranchDebugLoc();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000404 MachineInstr *End =
405 BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP));
406 registerScope(Begin, End);
Dan Gohman8fe7e862015-12-14 22:51:54 +0000407
408 assert((!ScopeTops[AfterLoop->getNumber()] ||
409 ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&
Dan Gohman442bfce2016-02-16 16:22:41 +0000410 "With block sorting the outermost loop for a block should be first.");
Dan Gohman8fe7e862015-12-14 22:51:54 +0000411 if (!ScopeTops[AfterLoop->getNumber()])
412 ScopeTops[AfterLoop->getNumber()] = &MBB;
Dan Gohman950a13c2015-09-16 16:51:30 +0000413}
414
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000415void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) {
416 if (!MBB.isEHPad())
417 return;
418
419 // catch_all terminate pad is grouped together with catch terminate pad and
420 // does not need a separate TRY and END_TRY marker.
421 if (WebAssembly::isCatchAllTerminatePad(MBB))
422 return;
423
424 MachineFunction &MF = *MBB.getParent();
425 auto &MDT = getAnalysis<MachineDominatorTree>();
426 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
427 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
428 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
429
430 // Compute the nearest common dominator of all unwind predecessors
431 MachineBasicBlock *Header = nullptr;
432 int MBBNumber = MBB.getNumber();
433 for (auto *Pred : MBB.predecessors()) {
434 if (Pred->getNumber() < MBBNumber) {
435 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
436 assert(!ExplicitlyBranchesTo(Pred, &MBB) &&
437 "Explicit branch to an EH pad!");
438 }
439 }
440 if (!Header)
441 return;
442
443 // If this try is at the bottom of the function, insert a dummy block at the
444 // end.
445 WebAssemblyException *WE = WEI.getExceptionFor(&MBB);
446 assert(WE);
447 MachineBasicBlock *Bottom = WebAssembly::getBottom(WE);
448
449 auto Iter = std::next(MachineFunction::iterator(Bottom));
450 if (Iter == MF.end()) {
451 MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
452 // Give it a fake predecessor so that AsmPrinter prints its label.
453 Label->addSuccessor(Label);
454 MF.push_back(Label);
455 Iter = std::next(MachineFunction::iterator(Bottom));
456 }
457 MachineBasicBlock *AfterTry = &*Iter;
458
459 assert(AfterTry != &MF.front());
460 MachineBasicBlock *LayoutPred =
461 &*std::prev(MachineFunction::iterator(AfterTry));
462
463 // If the nearest common dominator is inside a more deeply nested context,
464 // walk out to the nearest scope which isn't more deeply nested.
465 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
466 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
467 if (ScopeTop->getNumber() > Header->getNumber()) {
468 // Skip over an intervening scope.
469 I = std::next(MachineFunction::iterator(ScopeTop));
470 } else {
471 // We found a scope level at an appropriate depth.
472 Header = ScopeTop;
473 break;
474 }
475 }
476 }
477
478 // Decide where in Header to put the TRY.
479
480 // Instructions that should go before the BLOCK.
481 SmallPtrSet<const MachineInstr *, 4> BeforeSet;
482 // Instructions that should go after the BLOCK.
483 SmallPtrSet<const MachineInstr *, 4> AfterSet;
484 for (const auto &MI : *Header) {
485 // If there is a previously placed LOOP marker and the bottom block of
486 // the loop is above MBB, the LOOP should be after the TRY, because the
487 // loop is nested in this try. Otherwise it should be before the TRY.
488 if (MI.getOpcode() == WebAssembly::LOOP) {
489 if (MBB.getNumber() > Bottom->getNumber())
490 AfterSet.insert(&MI);
491#ifndef NDEBUG
492 else
493 BeforeSet.insert(&MI);
494#endif
495 }
496
497 // All previously inserted TRY markers should be after the TRY because they
498 // are all nested trys.
499 if (MI.getOpcode() == WebAssembly::TRY)
500 AfterSet.insert(&MI);
501
502#ifndef NDEBUG
503 // All END_(LOOP/TRY) markers should be before the TRY.
504 if (MI.getOpcode() == WebAssembly::END_LOOP ||
505 MI.getOpcode() == WebAssembly::END_TRY)
506 BeforeSet.insert(&MI);
507#endif
508
509 // Terminators should go after the TRY.
510 if (MI.isTerminator())
511 AfterSet.insert(&MI);
512 }
513
514 // Local expression tree should go after the TRY.
515 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
516 --I) {
Yury Delendik409b4392018-10-04 23:31:00 +0000517 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
518 continue;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000519 if (WebAssembly::isChild(*std::prev(I), MFI))
520 AfterSet.insert(&*std::prev(I));
521 else
522 break;
523 }
524
525 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should
526 // contain the call within it. So the call should go after the TRY. The
527 // exception is when the header's terminator is a rethrow instruction, in
528 // which case that instruction, not a call instruction before it, is gonna
529 // throw.
530 if (MBB.isPredecessor(Header)) {
531 auto TermPos = Header->getFirstTerminator();
532 if (TermPos == Header->end() || !WebAssembly::isRethrow(*TermPos)) {
533 for (const auto &MI : reverse(*Header)) {
534 if (MI.isCall()) {
535 AfterSet.insert(&MI);
536 break;
537 }
538 }
539 }
540 }
541
542 // Add the TRY.
543 auto InsertPos = GetLatestInsertPos(Header, BeforeSet, AfterSet);
544 MachineInstr *Begin =
545 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
546 TII.get(WebAssembly::TRY))
547 .addImm(int64_t(WebAssembly::ExprType::Void));
548
549 // Decide where in Header to put the END_TRY.
550 BeforeSet.clear();
551 AfterSet.clear();
552 for (const auto &MI : *AfterTry) {
553#ifndef NDEBUG
554 // END_TRY should precede existing LOOP markers.
555 if (MI.getOpcode() == WebAssembly::LOOP)
556 AfterSet.insert(&MI);
557
558 // All END_TRY markers placed earlier belong to exceptions that contains
559 // this one.
560 if (MI.getOpcode() == WebAssembly::END_TRY)
561 AfterSet.insert(&MI);
562#endif
563
564 // If there is a previously placed END_LOOP marker and its header is after
565 // where TRY marker is, this loop is contained within the 'catch' part, so
566 // the END_TRY marker should go after that. Otherwise, the whole try-catch
567 // is contained within this loop, so the END_TRY should go before that.
568 if (MI.getOpcode() == WebAssembly::END_LOOP) {
569 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber())
570 BeforeSet.insert(&MI);
571#ifndef NDEBUG
572 else
573 AfterSet.insert(&MI);
574#endif
575 }
576 }
577
578 // Mark the end of the TRY.
579 InsertPos = GetEarliestInsertPos(AfterTry, BeforeSet, AfterSet);
580 MachineInstr *End =
581 BuildMI(*AfterTry, InsertPos, Bottom->findBranchDebugLoc(),
582 TII.get(WebAssembly::END_TRY));
583 registerTryScope(Begin, End, &MBB);
584
585 // Track the farthest-spanning scope that ends at this point.
586 int Number = AfterTry->getNumber();
587 if (!ScopeTops[Number] ||
588 ScopeTops[Number]->getNumber() > Header->getNumber())
589 ScopeTops[Number] = Header;
590}
591
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000592static unsigned
593GetDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
594 const MachineBasicBlock *MBB) {
595 unsigned Depth = 0;
596 for (auto X : reverse(Stack)) {
597 if (X == MBB)
598 break;
599 ++Depth;
600 }
601 assert(Depth < Stack.size() && "Branch destination should be in scope");
602 return Depth;
603}
604
Dan Gohman2726b882016-10-06 22:29:32 +0000605/// In normal assembly languages, when the end of a function is unreachable,
606/// because the function ends in an infinite loop or a noreturn call or similar,
607/// it isn't necessary to worry about the function return type at the end of
608/// the function, because it's never reached. However, in WebAssembly, blocks
609/// that end at the function end need to have a return type signature that
610/// matches the function signature, even though it's unreachable. This function
611/// checks for such cases and fixes up the signatures.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000612void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) {
613 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
Dan Gohman2726b882016-10-06 22:29:32 +0000614 assert(MFI.getResults().size() <= 1);
615
616 if (MFI.getResults().empty())
617 return;
618
619 WebAssembly::ExprType retType;
620 switch (MFI.getResults().front().SimpleTy) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000621 case MVT::i32:
622 retType = WebAssembly::ExprType::I32;
623 break;
624 case MVT::i64:
625 retType = WebAssembly::ExprType::I64;
626 break;
627 case MVT::f32:
628 retType = WebAssembly::ExprType::F32;
629 break;
630 case MVT::f64:
631 retType = WebAssembly::ExprType::F64;
632 break;
Derek Schuff2c783852018-08-06 23:16:50 +0000633 case MVT::v16i8:
634 case MVT::v8i16:
635 case MVT::v4i32:
Derek Schuff51ed1312018-08-07 21:24:01 +0000636 case MVT::v2i64:
Derek Schuff2c783852018-08-06 23:16:50 +0000637 case MVT::v4f32:
Derek Schuff51ed1312018-08-07 21:24:01 +0000638 case MVT::v2f64:
Derek Schuff2c783852018-08-06 23:16:50 +0000639 retType = WebAssembly::ExprType::V128;
640 break;
Heejin Ahnf208f632018-09-05 01:27:38 +0000641 case MVT::ExceptRef:
642 retType = WebAssembly::ExprType::ExceptRef;
643 break;
644 default:
645 llvm_unreachable("unexpected return type");
Dan Gohman2726b882016-10-06 22:29:32 +0000646 }
647
648 for (MachineBasicBlock &MBB : reverse(MF)) {
649 for (MachineInstr &MI : reverse(MBB)) {
Shiva Chen801bf7e2018-05-09 02:42:00 +0000650 if (MI.isPosition() || MI.isDebugInstr())
Dan Gohman2726b882016-10-06 22:29:32 +0000651 continue;
652 if (MI.getOpcode() == WebAssembly::END_BLOCK) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000653 EndToBegin[&MI]->getOperand(0).setImm(int32_t(retType));
Dan Gohman2726b882016-10-06 22:29:32 +0000654 continue;
655 }
656 if (MI.getOpcode() == WebAssembly::END_LOOP) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000657 EndToBegin[&MI]->getOperand(0).setImm(int32_t(retType));
Dan Gohman2726b882016-10-06 22:29:32 +0000658 continue;
659 }
660 // Something other than an `end`. We're done.
661 return;
662 }
663 }
664}
665
Dan Gohmand934cb82017-02-24 23:18:00 +0000666// WebAssembly functions end with an end instruction, as if the function body
667// were a block.
Heejin Ahnf208f632018-09-05 01:27:38 +0000668static void AppendEndToFunction(MachineFunction &MF,
669 const WebAssemblyInstrInfo &TII) {
Derek Schuff10b31352018-03-15 22:06:51 +0000670 BuildMI(MF.back(), MF.back().end(),
671 MF.back().findPrevDebugLoc(MF.back().end()),
Dan Gohmand934cb82017-02-24 23:18:00 +0000672 TII.get(WebAssembly::END_FUNCTION));
673}
674
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000675/// Insert LOOP/TRY/BLOCK markers at appropriate places.
676void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
677 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
678 // We allocate one more than the number of blocks in the function to
679 // accommodate for the possible fake block we may insert at the end.
680 ScopeTops.resize(MF.getNumBlockIDs() + 1);
681 // Place the LOOP for MBB if MBB is the header of a loop.
682 for (auto &MBB : MF)
683 placeLoopMarker(MBB);
684 // Place the TRY for MBB if MBB is the EH pad of an exception.
685 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
686 MF.getFunction().hasPersonalityFn())
687 for (auto &MBB : MF)
688 placeTryMarker(MBB);
689 // Place the BLOCK for MBB if MBB is branched to from above.
690 for (auto &MBB : MF)
691 placeBlockMarker(MBB);
692}
Dan Gohman8fe7e862015-12-14 22:51:54 +0000693
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000694void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
695 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000696 // Now rewrite references to basic blocks to be depth immediates.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000697 // We need two stacks: one for normal scopes and the other for EH pad scopes.
698 // EH pad stack is used to rewrite depths in rethrow instructions.
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000699 SmallVector<const MachineBasicBlock *, 8> Stack;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000700 SmallVector<const MachineBasicBlock *, 8> EHPadStack;
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000701 for (auto &MBB : reverse(MF)) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000702 for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) {
703 MachineInstr &MI = *I;
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000704 switch (MI.getOpcode()) {
705 case WebAssembly::BLOCK:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000706 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <=
707 MBB.getNumber() &&
708 "Block/try should be balanced");
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000709 Stack.pop_back();
710 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000711
712 case WebAssembly::TRY:
713 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <=
714 MBB.getNumber() &&
715 "Block/try marker should be balanced");
716 Stack.pop_back();
717 EHPadStack.pop_back();
718 break;
719
720 case WebAssembly::CATCH_I32:
721 case WebAssembly::CATCH_I64:
722 case WebAssembly::CATCH_ALL:
Heejin Ahn5b023e02018-11-02 18:38:52 +0000723 // Currently the only case there are more than one catch for a try is
724 // for catch terminate pad, in the form of
725 // try
726 // catch
727 // call @__clang_call_terminate
728 // unreachable
729 // catch_all
730 // call @std::terminate
731 // unreachable
732 // end
733 // So we shouldn't push the current BB for the second catch_all block
734 // here.
735 if (!WebAssembly::isCatchAllTerminatePad(MBB))
736 EHPadStack.push_back(&MBB);
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000737 break;
738
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000739 case WebAssembly::LOOP:
740 assert(Stack.back() == &MBB && "Loop top should be balanced");
741 Stack.pop_back();
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000742 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000743
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000744 case WebAssembly::END_BLOCK:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000745 case WebAssembly::END_TRY:
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000746 Stack.push_back(&MBB);
747 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000748
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000749 case WebAssembly::END_LOOP:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000750 Stack.push_back(EndToBegin[&MI]->getParent());
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000751 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000752
753 case WebAssembly::RETHROW: {
754 // Rewrite MBB operands to be depth immediates.
755 unsigned EHPadDepth = GetDepth(EHPadStack, MI.getOperand(0).getMBB());
756 MI.RemoveOperand(0);
757 MI.addOperand(MF, MachineOperand::CreateImm(EHPadDepth));
758 break;
759 }
760
761 case WebAssembly::RETHROW_TO_CALLER: {
762 MachineInstr *Rethrow =
763 BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(WebAssembly::RETHROW))
Heejin Ahnac764aa2018-10-24 23:31:24 +0000764 .addImm(EHPadStack.size());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000765 MI.eraseFromParent();
766 I = MachineBasicBlock::reverse_iterator(Rethrow);
767 break;
768 }
769
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000770 default:
771 if (MI.isTerminator()) {
772 // Rewrite MBB operands to be depth immediates.
773 SmallVector<MachineOperand, 4> Ops(MI.operands());
774 while (MI.getNumOperands() > 0)
775 MI.RemoveOperand(MI.getNumOperands() - 1);
776 for (auto MO : Ops) {
777 if (MO.isMBB())
778 MO = MachineOperand::CreateImm(GetDepth(Stack, MO.getMBB()));
779 MI.addOperand(MF, MO);
780 }
781 }
782 break;
783 }
784 }
785 }
786 assert(Stack.empty() && "Control flow should be balanced");
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000787}
Dan Gohman2726b882016-10-06 22:29:32 +0000788
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000789void WebAssemblyCFGStackify::releaseMemory() {
790 ScopeTops.clear();
791 BeginToEnd.clear();
792 EndToBegin.clear();
793 TryToEHPad.clear();
794 EHPadToTry.clear();
795 BeginToBottom.clear();
Dan Gohman32807932015-11-23 16:19:56 +0000796}
Dan Gohman32807932015-11-23 16:19:56 +0000797
Dan Gohman950a13c2015-09-16 16:51:30 +0000798bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000799 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n"
800 "********** Function: "
801 << MF.getName() << '\n');
Dan Gohman950a13c2015-09-16 16:51:30 +0000802
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000803 releaseMemory();
804
Dan Gohmane0405332016-10-03 22:43:53 +0000805 // Liveness is not tracked for VALUE_STACK physreg.
Derek Schuff9c3bf312016-01-13 17:10:28 +0000806 MF.getRegInfo().invalidateLiveness();
Dan Gohman950a13c2015-09-16 16:51:30 +0000807
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000808 // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes.
809 placeMarkers(MF);
810
811 // Convert MBB operands in terminators to relative depth immediates.
812 rewriteDepthImmediates(MF);
813
814 // Fix up block/loop/try signatures at the end of the function to conform to
815 // WebAssembly's rules.
816 fixEndsAtEndOfFunction(MF);
817
818 // Add an end instruction at the end of the function body.
819 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
820 if (!MF.getSubtarget<WebAssemblySubtarget>()
821 .getTargetTriple()
822 .isOSBinFormatELF())
823 AppendEndToFunction(MF, TII);
Dan Gohman32807932015-11-23 16:19:56 +0000824
Dan Gohman950a13c2015-09-16 16:51:30 +0000825 return true;
826}