blob: 7a7838adb9747ea77ccc37544d03d23379d9854c [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"
Heejin Ahnd6f48782019-01-30 03:21:57 +000040#include <cstring>
Dan Gohman950a13c2015-09-16 16:51:30 +000041using namespace llvm;
42
43#define DEBUG_TYPE "wasm-cfg-stackify"
44
45namespace {
46class WebAssemblyCFGStackify final : public MachineFunctionPass {
Mehdi Amini117296c2016-10-01 02:56:57 +000047 StringRef getPassName() const override { return "WebAssembly CFG Stackify"; }
Dan Gohman950a13c2015-09-16 16:51:30 +000048
49 void getAnalysisUsage(AnalysisUsage &AU) const override {
Dan Gohman32807932015-11-23 16:19:56 +000050 AU.addRequired<MachineDominatorTree>();
Dan Gohman950a13c2015-09-16 16:51:30 +000051 AU.addRequired<MachineLoopInfo>();
Heejin Ahne76fa9e2018-08-16 23:50:59 +000052 AU.addRequired<WebAssemblyExceptionInfo>();
Dan Gohman950a13c2015-09-16 16:51:30 +000053 MachineFunctionPass::getAnalysisUsage(AU);
54 }
55
56 bool runOnMachineFunction(MachineFunction &MF) override;
57
Heejin Ahne76fa9e2018-08-16 23:50:59 +000058 // For each block whose label represents the end of a scope, record the block
59 // which holds the beginning of the scope. This will allow us to quickly skip
60 // over scoped regions when walking blocks.
61 SmallVector<MachineBasicBlock *, 8> ScopeTops;
62
63 void placeMarkers(MachineFunction &MF);
64 void placeBlockMarker(MachineBasicBlock &MBB);
65 void placeLoopMarker(MachineBasicBlock &MBB);
66 void placeTryMarker(MachineBasicBlock &MBB);
Heejin Ahncf699b42019-02-27 00:50:53 +000067 void removeUnnecessaryInstrs(MachineFunction &MF);
Heejin Ahne76fa9e2018-08-16 23:50:59 +000068 void rewriteDepthImmediates(MachineFunction &MF);
69 void fixEndsAtEndOfFunction(MachineFunction &MF);
70
71 // For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY).
72 DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd;
73 // For each END_(BLOCK|LOOP|TRY), the corresponding BLOCK|LOOP|TRY.
74 DenseMap<const MachineInstr *, MachineInstr *> EndToBegin;
75 // <TRY marker, EH pad> map
76 DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad;
77 // <EH pad, TRY marker> map
78 DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry;
Heejin Ahne76fa9e2018-08-16 23:50:59 +000079
Heejin Ahncf699b42019-02-27 00:50:53 +000080 // Helper functions to register / unregister scope information created by
81 // marker 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 Ahncf699b42019-02-27 00:50:53 +000085 void unregisterScope(MachineInstr *Begin);
Heejin Ahne76fa9e2018-08-16 23:50:59 +000086
Dan Gohman950a13c2015-09-16 16:51:30 +000087public:
88 static char ID; // Pass identification, replacement for typeid
89 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {}
Heejin Ahne76fa9e2018-08-16 23:50:59 +000090 ~WebAssemblyCFGStackify() override { releaseMemory(); }
91 void releaseMemory() override;
Dan Gohman950a13c2015-09-16 16:51:30 +000092};
93} // end anonymous namespace
94
95char WebAssemblyCFGStackify::ID = 0;
Jacob Gravelle40926452018-03-30 20:36:58 +000096INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE,
Heejin Ahnf208f632018-09-05 01:27:38 +000097 "Insert BLOCK and LOOP markers for WebAssembly scopes", false,
98 false)
Jacob Gravelle40926452018-03-30 20:36:58 +000099
Dan Gohman950a13c2015-09-16 16:51:30 +0000100FunctionPass *llvm::createWebAssemblyCFGStackify() {
101 return new WebAssemblyCFGStackify();
102}
103
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000104/// Test whether Pred has any terminators explicitly branching to MBB, as
105/// opposed to falling through. Note that it's possible (eg. in unoptimized
106/// code) for a branch instruction to both branch to a block and fallthrough
107/// to it, so we check the actual branch operands to see if there are any
108/// explicit mentions.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000109static bool explicitlyBranchesTo(MachineBasicBlock *Pred,
Dan Gohman35e4a282016-01-08 01:06:00 +0000110 MachineBasicBlock *MBB) {
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000111 for (MachineInstr &MI : Pred->terminators())
Heejin Ahnd6f48782019-01-30 03:21:57 +0000112 for (MachineOperand &MO : MI.explicit_operands())
113 if (MO.isMBB() && MO.getMBB() == MBB)
114 return true;
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000115 return false;
116}
117
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000118// Returns an iterator to the earliest position possible within the MBB,
119// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
120// contains instructions that should go before the marker, and AfterSet contains
121// ones that should go after the marker. In this function, AfterSet is only
122// used for sanity checking.
123static MachineBasicBlock::iterator
Heejin Ahn18c56a02019-02-04 19:13:39 +0000124getEarliestInsertPos(MachineBasicBlock *MBB,
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000125 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
126 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
127 auto InsertPos = MBB->end();
128 while (InsertPos != MBB->begin()) {
129 if (BeforeSet.count(&*std::prev(InsertPos))) {
130#ifndef NDEBUG
131 // Sanity check
132 for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos)
133 assert(!AfterSet.count(&*std::prev(Pos)));
134#endif
135 break;
136 }
137 --InsertPos;
138 }
139 return InsertPos;
140}
141
142// Returns an iterator to the latest position possible within the MBB,
143// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
144// contains instructions that should go before the marker, and AfterSet contains
145// ones that should go after the marker. In this function, BeforeSet is only
146// used for sanity checking.
147static MachineBasicBlock::iterator
Heejin Ahn18c56a02019-02-04 19:13:39 +0000148getLatestInsertPos(MachineBasicBlock *MBB,
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000149 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
150 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
151 auto InsertPos = MBB->begin();
152 while (InsertPos != MBB->end()) {
153 if (AfterSet.count(&*InsertPos)) {
154#ifndef NDEBUG
155 // Sanity check
156 for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos)
157 assert(!BeforeSet.count(&*Pos));
158#endif
159 break;
160 }
161 ++InsertPos;
162 }
163 return InsertPos;
164}
165
166void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin,
167 MachineInstr *End) {
168 BeginToEnd[Begin] = End;
169 EndToBegin[End] = Begin;
170}
171
172void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin,
173 MachineInstr *End,
174 MachineBasicBlock *EHPad) {
175 registerScope(Begin, End);
176 TryToEHPad[Begin] = EHPad;
177 EHPadToTry[EHPad] = Begin;
178}
179
Heejin Ahncf699b42019-02-27 00:50:53 +0000180void WebAssemblyCFGStackify::unregisterScope(MachineInstr *Begin) {
181 assert(BeginToEnd.count(Begin));
182 MachineInstr *End = BeginToEnd[Begin];
183 assert(EndToBegin.count(End));
184 BeginToEnd.erase(Begin);
185 EndToBegin.erase(End);
186 MachineBasicBlock *EHPad = TryToEHPad.lookup(Begin);
187 if (EHPad) {
188 assert(EHPadToTry.count(EHPad));
189 TryToEHPad.erase(Begin);
190 EHPadToTry.erase(EHPad);
191 }
192}
193
Dan Gohman32807932015-11-23 16:19:56 +0000194/// Insert a BLOCK marker for branches to MBB (if needed).
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000195void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) {
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000196 assert(!MBB.isEHPad());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000197 MachineFunction &MF = *MBB.getParent();
198 auto &MDT = getAnalysis<MachineDominatorTree>();
199 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
200 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
201
Dan Gohman8fe7e862015-12-14 22:51:54 +0000202 // First compute the nearest common dominator of all forward non-fallthrough
203 // predecessors so that we minimize the time that the BLOCK is on the stack,
204 // which reduces overall stack height.
Dan Gohman32807932015-11-23 16:19:56 +0000205 MachineBasicBlock *Header = nullptr;
206 bool IsBranchedTo = false;
Heejin Ahnd6f48782019-01-30 03:21:57 +0000207 bool IsBrOnExn = false;
208 MachineInstr *BrOnExn = nullptr;
Dan Gohman32807932015-11-23 16:19:56 +0000209 int MBBNumber = MBB.getNumber();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000210 for (MachineBasicBlock *Pred : MBB.predecessors()) {
Dan Gohman32807932015-11-23 16:19:56 +0000211 if (Pred->getNumber() < MBBNumber) {
212 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
Heejin Ahn18c56a02019-02-04 19:13:39 +0000213 if (explicitlyBranchesTo(Pred, &MBB)) {
Dan Gohman32807932015-11-23 16:19:56 +0000214 IsBranchedTo = true;
Heejin Ahnd6f48782019-01-30 03:21:57 +0000215 if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) {
216 IsBrOnExn = true;
217 assert(!BrOnExn && "There should be only one br_on_exn per block");
218 BrOnExn = &*Pred->getFirstTerminator();
219 }
220 }
Dan Gohman32807932015-11-23 16:19:56 +0000221 }
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000222 }
Dan Gohman32807932015-11-23 16:19:56 +0000223 if (!Header)
224 return;
225 if (!IsBranchedTo)
Dan Gohman950a13c2015-09-16 16:51:30 +0000226 return;
227
Dan Gohman8fe7e862015-12-14 22:51:54 +0000228 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors");
Heejin Ahn5c644c92019-03-05 21:05:09 +0000229 MachineBasicBlock *LayoutPred = MBB.getPrevNode();
Dan Gohman8fe7e862015-12-14 22:51:54 +0000230
231 // If the nearest common dominator is inside a more deeply nested context,
232 // walk out to the nearest scope which isn't more deeply nested.
233 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
234 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
235 if (ScopeTop->getNumber() > Header->getNumber()) {
236 // Skip over an intervening scope.
Heejin Ahn5c644c92019-03-05 21:05:09 +0000237 I = std::next(ScopeTop->getIterator());
Dan Gohman8fe7e862015-12-14 22:51:54 +0000238 } else {
239 // We found a scope level at an appropriate depth.
240 Header = ScopeTop;
241 break;
242 }
243 }
244 }
245
Dan Gohman8fe7e862015-12-14 22:51:54 +0000246 // Decide where in Header to put the BLOCK.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000247
248 // Instructions that should go before the BLOCK.
249 SmallPtrSet<const MachineInstr *, 4> BeforeSet;
250 // Instructions that should go after the BLOCK.
251 SmallPtrSet<const MachineInstr *, 4> AfterSet;
252 for (const auto &MI : *Header) {
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000253 // If there is a previously placed LOOP marker and the bottom block of the
254 // loop is above MBB, it should be after the BLOCK, because the loop is
255 // nested in this BLOCK. Otherwise it should be before the BLOCK.
256 if (MI.getOpcode() == WebAssembly::LOOP) {
257 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode();
258 if (MBB.getNumber() > LoopBottom->getNumber())
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000259 AfterSet.insert(&MI);
260#ifndef NDEBUG
261 else
262 BeforeSet.insert(&MI);
263#endif
264 }
265
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000266 // All previously inserted BLOCK/TRY markers should be after the BLOCK
267 // because they are all nested blocks.
268 if (MI.getOpcode() == WebAssembly::BLOCK ||
269 MI.getOpcode() == WebAssembly::TRY)
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000270 AfterSet.insert(&MI);
271
272#ifndef NDEBUG
273 // All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK.
274 if (MI.getOpcode() == WebAssembly::END_BLOCK ||
275 MI.getOpcode() == WebAssembly::END_LOOP ||
276 MI.getOpcode() == WebAssembly::END_TRY)
277 BeforeSet.insert(&MI);
278#endif
279
280 // Terminators should go after the BLOCK.
281 if (MI.isTerminator())
282 AfterSet.insert(&MI);
283 }
284
285 // Local expression tree should go after the BLOCK.
286 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
287 --I) {
Yury Delendik409b4392018-10-04 23:31:00 +0000288 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
289 continue;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000290 if (WebAssembly::isChild(*std::prev(I), MFI))
291 AfterSet.insert(&*std::prev(I));
292 else
293 break;
Dan Gohman950a13c2015-09-16 16:51:30 +0000294 }
295
Dan Gohman8fe7e862015-12-14 22:51:54 +0000296 // Add the BLOCK.
Heejin Ahnd6f48782019-01-30 03:21:57 +0000297
298 // 'br_on_exn' extracts except_ref object and pushes variable number of values
299 // depending on its tag. For C++ exception, its a single i32 value, and the
300 // generated code will be in the form of:
301 // block i32
302 // br_on_exn 0, $__cpp_exception
303 // rethrow
304 // end_block
305 WebAssembly::ExprType ReturnType = WebAssembly::ExprType::Void;
306 if (IsBrOnExn) {
307 const char *TagName = BrOnExn->getOperand(1).getSymbolName();
308 if (std::strcmp(TagName, "__cpp_exception") != 0)
309 llvm_unreachable("Only C++ exception is supported");
310 ReturnType = WebAssembly::ExprType::I32;
311 }
312
Heejin Ahn18c56a02019-02-04 19:13:39 +0000313 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet);
Heejin Ahn92401cc2018-04-14 00:12:12 +0000314 MachineInstr *Begin =
315 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
316 TII.get(WebAssembly::BLOCK))
Heejin Ahnd6f48782019-01-30 03:21:57 +0000317 .addImm(int64_t(ReturnType));
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000318
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000319 // Decide where in Header to put the END_BLOCK.
320 BeforeSet.clear();
321 AfterSet.clear();
322 for (auto &MI : MBB) {
323#ifndef NDEBUG
324 // END_BLOCK should precede existing LOOP and TRY markers.
325 if (MI.getOpcode() == WebAssembly::LOOP ||
326 MI.getOpcode() == WebAssembly::TRY)
327 AfterSet.insert(&MI);
328#endif
329
330 // If there is a previously placed END_LOOP marker and the header of the
331 // loop is above this block's header, the END_LOOP should be placed after
332 // the BLOCK, because the loop contains this block. Otherwise the END_LOOP
333 // should be placed before the BLOCK. The same for END_TRY.
334 if (MI.getOpcode() == WebAssembly::END_LOOP ||
335 MI.getOpcode() == WebAssembly::END_TRY) {
336 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber())
337 BeforeSet.insert(&MI);
338#ifndef NDEBUG
339 else
340 AfterSet.insert(&MI);
341#endif
342 }
343 }
344
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000345 // Mark the end of the block.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000346 InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet);
Derek Schuff10b31352018-03-15 22:06:51 +0000347 MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos),
Dan Gohman2726b882016-10-06 22:29:32 +0000348 TII.get(WebAssembly::END_BLOCK));
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000349 registerScope(Begin, End);
Dan Gohman8fe7e862015-12-14 22:51:54 +0000350
351 // Track the farthest-spanning scope that ends at this point.
352 int Number = MBB.getNumber();
353 if (!ScopeTops[Number] ||
354 ScopeTops[Number]->getNumber() > Header->getNumber())
355 ScopeTops[Number] = Header;
356}
357
358/// Insert a LOOP marker for a loop starting at MBB (if it's a loop header).
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000359void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) {
360 MachineFunction &MF = *MBB.getParent();
361 const auto &MLI = getAnalysis<MachineLoopInfo>();
362 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
363
Dan Gohman8fe7e862015-12-14 22:51:54 +0000364 MachineLoop *Loop = MLI.getLoopFor(&MBB);
365 if (!Loop || Loop->getHeader() != &MBB)
366 return;
367
368 // The operand of a LOOP is the first block after the loop. If the loop is the
369 // bottom of the function, insert a dummy block at the end.
Heejin Ahn817811ca2018-06-19 00:32:03 +0000370 MachineBasicBlock *Bottom = WebAssembly::getBottom(Loop);
Heejin Ahn5c644c92019-03-05 21:05:09 +0000371 auto Iter = std::next(Bottom->getIterator());
Dan Gohman8fe7e862015-12-14 22:51:54 +0000372 if (Iter == MF.end()) {
373 MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
374 // Give it a fake predecessor so that AsmPrinter prints its label.
375 Label->addSuccessor(Label);
376 MF.push_back(Label);
Heejin Ahn5c644c92019-03-05 21:05:09 +0000377 Iter = std::next(Bottom->getIterator());
Dan Gohman8fe7e862015-12-14 22:51:54 +0000378 }
379 MachineBasicBlock *AfterLoop = &*Iter;
Dan Gohman8fe7e862015-12-14 22:51:54 +0000380
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000381 // Decide where in Header to put the LOOP.
382 SmallPtrSet<const MachineInstr *, 4> BeforeSet;
383 SmallPtrSet<const MachineInstr *, 4> AfterSet;
384 for (const auto &MI : MBB) {
385 // LOOP marker should be after any existing loop that ends here. Otherwise
386 // we assume the instruction belongs to the loop.
387 if (MI.getOpcode() == WebAssembly::END_LOOP)
388 BeforeSet.insert(&MI);
389#ifndef NDEBUG
390 else
391 AfterSet.insert(&MI);
392#endif
393 }
394
395 // Mark the beginning of the loop.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000396 auto InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet);
Derek Schuff10b31352018-03-15 22:06:51 +0000397 MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos),
Dan Gohman2726b882016-10-06 22:29:32 +0000398 TII.get(WebAssembly::LOOP))
Derek Schuff10b31352018-03-15 22:06:51 +0000399 .addImm(int64_t(WebAssembly::ExprType::Void));
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000400
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000401 // Decide where in Header to put the END_LOOP.
402 BeforeSet.clear();
403 AfterSet.clear();
404#ifndef NDEBUG
405 for (const auto &MI : MBB)
406 // Existing END_LOOP markers belong to parent loops of this loop
407 if (MI.getOpcode() == WebAssembly::END_LOOP)
408 AfterSet.insert(&MI);
409#endif
410
411 // Mark the end of the loop (using arbitrary debug location that branched to
412 // the loop end as its location).
Heejin Ahn18c56a02019-02-04 19:13:39 +0000413 InsertPos = getEarliestInsertPos(AfterLoop, BeforeSet, AfterSet);
Derek Schuff10b31352018-03-15 22:06:51 +0000414 DebugLoc EndDL = (*AfterLoop->pred_rbegin())->findBranchDebugLoc();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000415 MachineInstr *End =
416 BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP));
417 registerScope(Begin, End);
Dan Gohman8fe7e862015-12-14 22:51:54 +0000418
419 assert((!ScopeTops[AfterLoop->getNumber()] ||
420 ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&
Dan Gohman442bfce2016-02-16 16:22:41 +0000421 "With block sorting the outermost loop for a block should be first.");
Dan Gohman8fe7e862015-12-14 22:51:54 +0000422 if (!ScopeTops[AfterLoop->getNumber()])
423 ScopeTops[AfterLoop->getNumber()] = &MBB;
Dan Gohman950a13c2015-09-16 16:51:30 +0000424}
425
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000426void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) {
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000427 assert(MBB.isEHPad());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000428 MachineFunction &MF = *MBB.getParent();
429 auto &MDT = getAnalysis<MachineDominatorTree>();
430 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
431 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
432 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
433
434 // Compute the nearest common dominator of all unwind predecessors
435 MachineBasicBlock *Header = nullptr;
436 int MBBNumber = MBB.getNumber();
437 for (auto *Pred : MBB.predecessors()) {
438 if (Pred->getNumber() < MBBNumber) {
439 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
Heejin Ahn18c56a02019-02-04 19:13:39 +0000440 assert(!explicitlyBranchesTo(Pred, &MBB) &&
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000441 "Explicit branch to an EH pad!");
442 }
443 }
444 if (!Header)
445 return;
446
447 // If this try is at the bottom of the function, insert a dummy block at the
448 // end.
449 WebAssemblyException *WE = WEI.getExceptionFor(&MBB);
450 assert(WE);
451 MachineBasicBlock *Bottom = WebAssembly::getBottom(WE);
452
Heejin Ahn5c644c92019-03-05 21:05:09 +0000453 auto Iter = std::next(Bottom->getIterator());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000454 if (Iter == MF.end()) {
455 MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
456 // Give it a fake predecessor so that AsmPrinter prints its label.
457 Label->addSuccessor(Label);
458 MF.push_back(Label);
Heejin Ahn5c644c92019-03-05 21:05:09 +0000459 Iter = std::next(Bottom->getIterator());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000460 }
Heejin Ahn20cf0742019-02-24 08:30:06 +0000461 MachineBasicBlock *Cont = &*Iter;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000462
Heejin Ahn20cf0742019-02-24 08:30:06 +0000463 assert(Cont != &MF.front());
Heejin Ahn5c644c92019-03-05 21:05:09 +0000464 MachineBasicBlock *LayoutPred = Cont->getPrevNode();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000465
466 // If the nearest common dominator is inside a more deeply nested context,
467 // walk out to the nearest scope which isn't more deeply nested.
468 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
469 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
470 if (ScopeTop->getNumber() > Header->getNumber()) {
471 // Skip over an intervening scope.
Heejin Ahn5c644c92019-03-05 21:05:09 +0000472 I = std::next(ScopeTop->getIterator());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000473 } else {
474 // We found a scope level at an appropriate depth.
475 Header = ScopeTop;
476 break;
477 }
478 }
479 }
480
481 // Decide where in Header to put the TRY.
482
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000483 // Instructions that should go before the TRY.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000484 SmallPtrSet<const MachineInstr *, 4> BeforeSet;
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000485 // Instructions that should go after the TRY.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000486 SmallPtrSet<const MachineInstr *, 4> AfterSet;
487 for (const auto &MI : *Header) {
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000488 // If there is a previously placed LOOP marker and the bottom block of the
489 // loop is above MBB, it should be after the TRY, because the loop is nested
490 // in this TRY. Otherwise it should be before the TRY.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000491 if (MI.getOpcode() == WebAssembly::LOOP) {
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000492 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode();
493 if (MBB.getNumber() > LoopBottom->getNumber())
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000494 AfterSet.insert(&MI);
495#ifndef NDEBUG
496 else
497 BeforeSet.insert(&MI);
498#endif
499 }
500
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000501 // All previously inserted BLOCK/TRY markers should be after the TRY because
502 // they are all nested trys.
503 if (MI.getOpcode() == WebAssembly::BLOCK ||
504 MI.getOpcode() == WebAssembly::TRY)
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000505 AfterSet.insert(&MI);
506
507#ifndef NDEBUG
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000508 // All END_(BLOCK/LOOP/TRY) markers should be before the TRY.
509 if (MI.getOpcode() == WebAssembly::END_BLOCK ||
510 MI.getOpcode() == WebAssembly::END_LOOP ||
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000511 MI.getOpcode() == WebAssembly::END_TRY)
512 BeforeSet.insert(&MI);
513#endif
514
515 // Terminators should go after the TRY.
516 if (MI.isTerminator())
517 AfterSet.insert(&MI);
518 }
519
520 // Local expression tree should go after the TRY.
521 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
522 --I) {
Yury Delendik409b4392018-10-04 23:31:00 +0000523 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
524 continue;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000525 if (WebAssembly::isChild(*std::prev(I), MFI))
526 AfterSet.insert(&*std::prev(I));
527 else
528 break;
529 }
530
531 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should
532 // contain the call within it. So the call should go after the TRY. The
533 // exception is when the header's terminator is a rethrow instruction, in
534 // which case that instruction, not a call instruction before it, is gonna
535 // throw.
536 if (MBB.isPredecessor(Header)) {
537 auto TermPos = Header->getFirstTerminator();
Heejin Ahnd6f48782019-01-30 03:21:57 +0000538 if (TermPos == Header->end() ||
539 TermPos->getOpcode() != WebAssembly::RETHROW) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000540 for (const auto &MI : reverse(*Header)) {
541 if (MI.isCall()) {
542 AfterSet.insert(&MI);
Heejin Ahn8b49b6b2019-03-13 00:37:31 +0000543 // Possibly throwing calls are usually wrapped by EH_LABEL
544 // instructions. We don't want to split them and the call.
545 if (MI.getIterator() != Header->begin() &&
546 std::prev(MI.getIterator())->isEHLabel())
547 AfterSet.insert(&*std::prev(MI.getIterator()));
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000548 break;
549 }
550 }
551 }
552 }
553
554 // Add the TRY.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000555 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet);
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000556 MachineInstr *Begin =
557 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
558 TII.get(WebAssembly::TRY))
559 .addImm(int64_t(WebAssembly::ExprType::Void));
560
561 // Decide where in Header to put the END_TRY.
562 BeforeSet.clear();
563 AfterSet.clear();
Heejin Ahn20cf0742019-02-24 08:30:06 +0000564 for (const auto &MI : *Cont) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000565#ifndef NDEBUG
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000566 // END_TRY should precede existing LOOP and BLOCK markers.
567 if (MI.getOpcode() == WebAssembly::LOOP ||
568 MI.getOpcode() == WebAssembly::BLOCK)
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000569 AfterSet.insert(&MI);
570
571 // All END_TRY markers placed earlier belong to exceptions that contains
572 // this one.
573 if (MI.getOpcode() == WebAssembly::END_TRY)
574 AfterSet.insert(&MI);
575#endif
576
577 // If there is a previously placed END_LOOP marker and its header is after
578 // where TRY marker is, this loop is contained within the 'catch' part, so
579 // the END_TRY marker should go after that. Otherwise, the whole try-catch
580 // is contained within this loop, so the END_TRY should go before that.
581 if (MI.getOpcode() == WebAssembly::END_LOOP) {
Heejin Ahn222718f2019-03-26 17:29:55 +0000582 // For a LOOP to be after TRY, LOOP's BB should be after TRY's BB; if they
583 // are in the same BB, LOOP is always before TRY.
584 if (EndToBegin[&MI]->getParent()->getNumber() > Header->getNumber())
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000585 BeforeSet.insert(&MI);
586#ifndef NDEBUG
587 else
588 AfterSet.insert(&MI);
589#endif
590 }
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000591
592 // It is not possible for an END_BLOCK to be already in this block.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000593 }
594
595 // Mark the end of the TRY.
Heejin Ahn20cf0742019-02-24 08:30:06 +0000596 InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet);
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000597 MachineInstr *End =
Heejin Ahn20cf0742019-02-24 08:30:06 +0000598 BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(),
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000599 TII.get(WebAssembly::END_TRY));
600 registerTryScope(Begin, End, &MBB);
601
Heejin Ahn82da1ff2019-02-27 01:35:14 +0000602 // Track the farthest-spanning scope that ends at this point. We create two
603 // mappings: (BB with 'end_try' -> BB with 'try') and (BB with 'catch' -> BB
604 // with 'try'). We need to create 'catch' -> 'try' mapping here too because
605 // markers should not span across 'catch'. For example, this should not
606 // happen:
607 //
608 // try
609 // block --| (X)
610 // catch |
611 // end_block --|
612 // end_try
613 for (int Number : {Cont->getNumber(), MBB.getNumber()}) {
614 if (!ScopeTops[Number] ||
615 ScopeTops[Number]->getNumber() > Header->getNumber())
616 ScopeTops[Number] = Header;
617 }
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000618}
619
Heejin Ahncf699b42019-02-27 00:50:53 +0000620void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) {
621 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
622
623 // When there is an unconditional branch right before a catch instruction and
624 // it branches to the end of end_try marker, we don't need the branch, because
625 // it there is no exception, the control flow transfers to that point anyway.
626 // bb0:
627 // try
628 // ...
629 // br bb2 <- Not necessary
630 // bb1:
631 // catch
632 // ...
633 // bb2:
634 // end
635 for (auto &MBB : MF) {
636 if (!MBB.isEHPad())
637 continue;
638
639 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
640 SmallVector<MachineOperand, 4> Cond;
Heejin Ahn5c644c92019-03-05 21:05:09 +0000641 MachineBasicBlock *EHPadLayoutPred = MBB.getPrevNode();
Heejin Ahncf699b42019-02-27 00:50:53 +0000642 MachineBasicBlock *Cont = BeginToEnd[EHPadToTry[&MBB]]->getParent();
643 bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond);
644 if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) ||
645 (!Cond.empty() && FBB && FBB == Cont)))
646 TII.removeBranch(*EHPadLayoutPred);
647 }
648
649 // When there are block / end_block markers that overlap with try / end_try
650 // markers, and the block and try markers' return types are the same, the
651 // block /end_block markers are not necessary, because try / end_try markers
652 // also can serve as boundaries for branches.
653 // block <- Not necessary
654 // try
655 // ...
656 // catch
657 // ...
658 // end
659 // end <- Not necessary
660 SmallVector<MachineInstr *, 32> ToDelete;
661 for (auto &MBB : MF) {
662 for (auto &MI : MBB) {
663 if (MI.getOpcode() != WebAssembly::TRY)
664 continue;
665
666 MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try];
667 MachineBasicBlock *TryBB = Try->getParent();
668 MachineBasicBlock *Cont = EndTry->getParent();
669 int64_t RetType = Try->getOperand(0).getImm();
Heejin Ahn5c644c92019-03-05 21:05:09 +0000670 for (auto B = Try->getIterator(), E = std::next(EndTry->getIterator());
Heejin Ahncf699b42019-02-27 00:50:53 +0000671 B != TryBB->begin() && E != Cont->end() &&
672 std::prev(B)->getOpcode() == WebAssembly::BLOCK &&
673 E->getOpcode() == WebAssembly::END_BLOCK &&
674 std::prev(B)->getOperand(0).getImm() == RetType;
675 --B, ++E) {
676 ToDelete.push_back(&*std::prev(B));
677 ToDelete.push_back(&*E);
678 }
679 }
680 }
681 for (auto *MI : ToDelete) {
682 if (MI->getOpcode() == WebAssembly::BLOCK)
683 unregisterScope(MI);
684 MI->eraseFromParent();
685 }
686}
687
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000688static unsigned
Heejin Ahn18c56a02019-02-04 19:13:39 +0000689getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000690 const MachineBasicBlock *MBB) {
691 unsigned Depth = 0;
692 for (auto X : reverse(Stack)) {
693 if (X == MBB)
694 break;
695 ++Depth;
696 }
697 assert(Depth < Stack.size() && "Branch destination should be in scope");
698 return Depth;
699}
700
Dan Gohman2726b882016-10-06 22:29:32 +0000701/// In normal assembly languages, when the end of a function is unreachable,
702/// because the function ends in an infinite loop or a noreturn call or similar,
703/// it isn't necessary to worry about the function return type at the end of
704/// the function, because it's never reached. However, in WebAssembly, blocks
705/// that end at the function end need to have a return type signature that
706/// matches the function signature, even though it's unreachable. This function
707/// checks for such cases and fixes up the signatures.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000708void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) {
709 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
Dan Gohman2726b882016-10-06 22:29:32 +0000710 assert(MFI.getResults().size() <= 1);
711
712 if (MFI.getResults().empty())
713 return;
714
Heejin Ahn18c56a02019-02-04 19:13:39 +0000715 WebAssembly::ExprType RetType;
Dan Gohman2726b882016-10-06 22:29:32 +0000716 switch (MFI.getResults().front().SimpleTy) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000717 case MVT::i32:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000718 RetType = WebAssembly::ExprType::I32;
Heejin Ahnf208f632018-09-05 01:27:38 +0000719 break;
720 case MVT::i64:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000721 RetType = WebAssembly::ExprType::I64;
Heejin Ahnf208f632018-09-05 01:27:38 +0000722 break;
723 case MVT::f32:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000724 RetType = WebAssembly::ExprType::F32;
Heejin Ahnf208f632018-09-05 01:27:38 +0000725 break;
726 case MVT::f64:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000727 RetType = WebAssembly::ExprType::F64;
Heejin Ahnf208f632018-09-05 01:27:38 +0000728 break;
Derek Schuff2c783852018-08-06 23:16:50 +0000729 case MVT::v16i8:
730 case MVT::v8i16:
731 case MVT::v4i32:
Derek Schuff51ed1312018-08-07 21:24:01 +0000732 case MVT::v2i64:
Derek Schuff2c783852018-08-06 23:16:50 +0000733 case MVT::v4f32:
Derek Schuff51ed1312018-08-07 21:24:01 +0000734 case MVT::v2f64:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000735 RetType = WebAssembly::ExprType::V128;
Derek Schuff2c783852018-08-06 23:16:50 +0000736 break;
Heejin Ahnf208f632018-09-05 01:27:38 +0000737 case MVT::ExceptRef:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000738 RetType = WebAssembly::ExprType::ExceptRef;
Heejin Ahnf208f632018-09-05 01:27:38 +0000739 break;
740 default:
741 llvm_unreachable("unexpected return type");
Dan Gohman2726b882016-10-06 22:29:32 +0000742 }
743
744 for (MachineBasicBlock &MBB : reverse(MF)) {
745 for (MachineInstr &MI : reverse(MBB)) {
Shiva Chen801bf7e2018-05-09 02:42:00 +0000746 if (MI.isPosition() || MI.isDebugInstr())
Dan Gohman2726b882016-10-06 22:29:32 +0000747 continue;
748 if (MI.getOpcode() == WebAssembly::END_BLOCK) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000749 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType));
Dan Gohman2726b882016-10-06 22:29:32 +0000750 continue;
751 }
752 if (MI.getOpcode() == WebAssembly::END_LOOP) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000753 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType));
Dan Gohman2726b882016-10-06 22:29:32 +0000754 continue;
755 }
756 // Something other than an `end`. We're done.
757 return;
758 }
759 }
760}
761
Dan Gohmand934cb82017-02-24 23:18:00 +0000762// WebAssembly functions end with an end instruction, as if the function body
763// were a block.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000764static void appendEndToFunction(MachineFunction &MF,
Heejin Ahnf208f632018-09-05 01:27:38 +0000765 const WebAssemblyInstrInfo &TII) {
Derek Schuff10b31352018-03-15 22:06:51 +0000766 BuildMI(MF.back(), MF.back().end(),
767 MF.back().findPrevDebugLoc(MF.back().end()),
Dan Gohmand934cb82017-02-24 23:18:00 +0000768 TII.get(WebAssembly::END_FUNCTION));
769}
770
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000771/// Insert LOOP/TRY/BLOCK markers at appropriate places.
772void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000773 // We allocate one more than the number of blocks in the function to
774 // accommodate for the possible fake block we may insert at the end.
775 ScopeTops.resize(MF.getNumBlockIDs() + 1);
776 // Place the LOOP for MBB if MBB is the header of a loop.
777 for (auto &MBB : MF)
778 placeLoopMarker(MBB);
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000779
Heejin Ahnd6f48782019-01-30 03:21:57 +0000780 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000781 for (auto &MBB : MF) {
782 if (MBB.isEHPad()) {
783 // Place the TRY for MBB if MBB is the EH pad of an exception.
784 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
785 MF.getFunction().hasPersonalityFn())
786 placeTryMarker(MBB);
787 } else {
788 // Place the BLOCK for MBB if MBB is branched to from above.
789 placeBlockMarker(MBB);
790 }
791 }
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000792}
Dan Gohman8fe7e862015-12-14 22:51:54 +0000793
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000794void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000795 // Now rewrite references to basic blocks to be depth immediates.
796 SmallVector<const MachineBasicBlock *, 8> Stack;
797 for (auto &MBB : reverse(MF)) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000798 for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) {
799 MachineInstr &MI = *I;
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000800 switch (MI.getOpcode()) {
801 case WebAssembly::BLOCK:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000802 case WebAssembly::TRY:
803 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <=
804 MBB.getNumber() &&
805 "Block/try marker should be balanced");
806 Stack.pop_back();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000807 break;
808
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000809 case WebAssembly::LOOP:
810 assert(Stack.back() == &MBB && "Loop top should be balanced");
811 Stack.pop_back();
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000812 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000813
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000814 case WebAssembly::END_BLOCK:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000815 case WebAssembly::END_TRY:
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000816 Stack.push_back(&MBB);
817 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000818
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000819 case WebAssembly::END_LOOP:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000820 Stack.push_back(EndToBegin[&MI]->getParent());
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000821 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000822
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000823 default:
824 if (MI.isTerminator()) {
825 // Rewrite MBB operands to be depth immediates.
826 SmallVector<MachineOperand, 4> Ops(MI.operands());
827 while (MI.getNumOperands() > 0)
828 MI.RemoveOperand(MI.getNumOperands() - 1);
829 for (auto MO : Ops) {
830 if (MO.isMBB())
Heejin Ahn18c56a02019-02-04 19:13:39 +0000831 MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB()));
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000832 MI.addOperand(MF, MO);
833 }
834 }
835 break;
836 }
837 }
838 }
839 assert(Stack.empty() && "Control flow should be balanced");
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000840}
Dan Gohman2726b882016-10-06 22:29:32 +0000841
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000842void WebAssemblyCFGStackify::releaseMemory() {
843 ScopeTops.clear();
844 BeginToEnd.clear();
845 EndToBegin.clear();
846 TryToEHPad.clear();
847 EHPadToTry.clear();
Dan Gohman32807932015-11-23 16:19:56 +0000848}
Dan Gohman32807932015-11-23 16:19:56 +0000849
Dan Gohman950a13c2015-09-16 16:51:30 +0000850bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000851 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n"
852 "********** Function: "
853 << MF.getName() << '\n');
Heejin Ahncf699b42019-02-27 00:50:53 +0000854 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
Dan Gohman950a13c2015-09-16 16:51:30 +0000855
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000856 releaseMemory();
857
Dan Gohmane0405332016-10-03 22:43:53 +0000858 // Liveness is not tracked for VALUE_STACK physreg.
Derek Schuff9c3bf312016-01-13 17:10:28 +0000859 MF.getRegInfo().invalidateLiveness();
Dan Gohman950a13c2015-09-16 16:51:30 +0000860
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000861 // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes.
862 placeMarkers(MF);
863
Heejin Ahncf699b42019-02-27 00:50:53 +0000864 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
865 MF.getFunction().hasPersonalityFn())
866 // Remove unnecessary instructions.
867 removeUnnecessaryInstrs(MF);
868
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000869 // Convert MBB operands in terminators to relative depth immediates.
870 rewriteDepthImmediates(MF);
871
872 // Fix up block/loop/try signatures at the end of the function to conform to
873 // WebAssembly's rules.
874 fixEndsAtEndOfFunction(MF);
875
876 // Add an end instruction at the end of the function body.
877 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
878 if (!MF.getSubtarget<WebAssemblySubtarget>()
879 .getTargetTriple()
880 .isOSBinFormatELF())
Heejin Ahn18c56a02019-02-04 19:13:39 +0000881 appendEndToFunction(MF, TII);
Dan Gohman32807932015-11-23 16:19:56 +0000882
Dan Gohman950a13c2015-09-16 16:51:30 +0000883 return true;
884}