blob: b64aa3023bb395b0b84df1981864e3961bb49aee [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);
Heejin Ahn67f74ac2019-03-29 19:36:51 +0000414 DebugLoc EndDL = AfterLoop->pred_empty()
415 ? DebugLoc()
416 : (*AfterLoop->pred_rbegin())->findBranchDebugLoc();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000417 MachineInstr *End =
418 BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP));
419 registerScope(Begin, End);
Dan Gohman8fe7e862015-12-14 22:51:54 +0000420
421 assert((!ScopeTops[AfterLoop->getNumber()] ||
422 ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&
Dan Gohman442bfce2016-02-16 16:22:41 +0000423 "With block sorting the outermost loop for a block should be first.");
Dan Gohman8fe7e862015-12-14 22:51:54 +0000424 if (!ScopeTops[AfterLoop->getNumber()])
425 ScopeTops[AfterLoop->getNumber()] = &MBB;
Dan Gohman950a13c2015-09-16 16:51:30 +0000426}
427
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000428void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) {
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000429 assert(MBB.isEHPad());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000430 MachineFunction &MF = *MBB.getParent();
431 auto &MDT = getAnalysis<MachineDominatorTree>();
432 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
433 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
434 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
435
436 // Compute the nearest common dominator of all unwind predecessors
437 MachineBasicBlock *Header = nullptr;
438 int MBBNumber = MBB.getNumber();
439 for (auto *Pred : MBB.predecessors()) {
440 if (Pred->getNumber() < MBBNumber) {
441 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
Heejin Ahn18c56a02019-02-04 19:13:39 +0000442 assert(!explicitlyBranchesTo(Pred, &MBB) &&
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000443 "Explicit branch to an EH pad!");
444 }
445 }
446 if (!Header)
447 return;
448
449 // If this try is at the bottom of the function, insert a dummy block at the
450 // end.
451 WebAssemblyException *WE = WEI.getExceptionFor(&MBB);
452 assert(WE);
453 MachineBasicBlock *Bottom = WebAssembly::getBottom(WE);
454
Heejin Ahn5c644c92019-03-05 21:05:09 +0000455 auto Iter = std::next(Bottom->getIterator());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000456 if (Iter == MF.end()) {
457 MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
458 // Give it a fake predecessor so that AsmPrinter prints its label.
459 Label->addSuccessor(Label);
460 MF.push_back(Label);
Heejin Ahn5c644c92019-03-05 21:05:09 +0000461 Iter = std::next(Bottom->getIterator());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000462 }
Heejin Ahn20cf0742019-02-24 08:30:06 +0000463 MachineBasicBlock *Cont = &*Iter;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000464
Heejin Ahn20cf0742019-02-24 08:30:06 +0000465 assert(Cont != &MF.front());
Heejin Ahn5c644c92019-03-05 21:05:09 +0000466 MachineBasicBlock *LayoutPred = Cont->getPrevNode();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000467
468 // If the nearest common dominator is inside a more deeply nested context,
469 // walk out to the nearest scope which isn't more deeply nested.
470 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
471 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
472 if (ScopeTop->getNumber() > Header->getNumber()) {
473 // Skip over an intervening scope.
Heejin Ahn5c644c92019-03-05 21:05:09 +0000474 I = std::next(ScopeTop->getIterator());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000475 } else {
476 // We found a scope level at an appropriate depth.
477 Header = ScopeTop;
478 break;
479 }
480 }
481 }
482
483 // Decide where in Header to put the TRY.
484
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000485 // Instructions that should go before the TRY.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000486 SmallPtrSet<const MachineInstr *, 4> BeforeSet;
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000487 // Instructions that should go after the TRY.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000488 SmallPtrSet<const MachineInstr *, 4> AfterSet;
489 for (const auto &MI : *Header) {
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000490 // If there is a previously placed LOOP marker and the bottom block of the
491 // loop is above MBB, it should be after the TRY, because the loop is nested
492 // in this TRY. Otherwise it should be before the TRY.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000493 if (MI.getOpcode() == WebAssembly::LOOP) {
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000494 auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode();
495 if (MBB.getNumber() > LoopBottom->getNumber())
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000496 AfterSet.insert(&MI);
497#ifndef NDEBUG
498 else
499 BeforeSet.insert(&MI);
500#endif
501 }
502
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000503 // All previously inserted BLOCK/TRY markers should be after the TRY because
504 // they are all nested trys.
505 if (MI.getOpcode() == WebAssembly::BLOCK ||
506 MI.getOpcode() == WebAssembly::TRY)
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000507 AfterSet.insert(&MI);
508
509#ifndef NDEBUG
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000510 // All END_(BLOCK/LOOP/TRY) markers should be before the TRY.
511 if (MI.getOpcode() == WebAssembly::END_BLOCK ||
512 MI.getOpcode() == WebAssembly::END_LOOP ||
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000513 MI.getOpcode() == WebAssembly::END_TRY)
514 BeforeSet.insert(&MI);
515#endif
516
517 // Terminators should go after the TRY.
518 if (MI.isTerminator())
519 AfterSet.insert(&MI);
520 }
521
522 // Local expression tree should go after the TRY.
523 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
524 --I) {
Yury Delendik409b4392018-10-04 23:31:00 +0000525 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
526 continue;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000527 if (WebAssembly::isChild(*std::prev(I), MFI))
528 AfterSet.insert(&*std::prev(I));
529 else
530 break;
531 }
532
533 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should
534 // contain the call within it. So the call should go after the TRY. The
535 // exception is when the header's terminator is a rethrow instruction, in
536 // which case that instruction, not a call instruction before it, is gonna
537 // throw.
538 if (MBB.isPredecessor(Header)) {
539 auto TermPos = Header->getFirstTerminator();
Heejin Ahnd6f48782019-01-30 03:21:57 +0000540 if (TermPos == Header->end() ||
541 TermPos->getOpcode() != WebAssembly::RETHROW) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000542 for (const auto &MI : reverse(*Header)) {
543 if (MI.isCall()) {
544 AfterSet.insert(&MI);
Heejin Ahn8b49b6b2019-03-13 00:37:31 +0000545 // Possibly throwing calls are usually wrapped by EH_LABEL
546 // instructions. We don't want to split them and the call.
547 if (MI.getIterator() != Header->begin() &&
548 std::prev(MI.getIterator())->isEHLabel())
549 AfterSet.insert(&*std::prev(MI.getIterator()));
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000550 break;
551 }
552 }
553 }
554 }
555
556 // Add the TRY.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000557 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet);
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000558 MachineInstr *Begin =
559 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
560 TII.get(WebAssembly::TRY))
561 .addImm(int64_t(WebAssembly::ExprType::Void));
562
563 // Decide where in Header to put the END_TRY.
564 BeforeSet.clear();
565 AfterSet.clear();
Heejin Ahn20cf0742019-02-24 08:30:06 +0000566 for (const auto &MI : *Cont) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000567#ifndef NDEBUG
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000568 // END_TRY should precede existing LOOP and BLOCK markers.
569 if (MI.getOpcode() == WebAssembly::LOOP ||
570 MI.getOpcode() == WebAssembly::BLOCK)
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000571 AfterSet.insert(&MI);
572
573 // All END_TRY markers placed earlier belong to exceptions that contains
574 // this one.
575 if (MI.getOpcode() == WebAssembly::END_TRY)
576 AfterSet.insert(&MI);
577#endif
578
579 // If there is a previously placed END_LOOP marker and its header is after
580 // where TRY marker is, this loop is contained within the 'catch' part, so
581 // the END_TRY marker should go after that. Otherwise, the whole try-catch
582 // is contained within this loop, so the END_TRY should go before that.
583 if (MI.getOpcode() == WebAssembly::END_LOOP) {
Heejin Ahn222718f2019-03-26 17:29:55 +0000584 // For a LOOP to be after TRY, LOOP's BB should be after TRY's BB; if they
585 // are in the same BB, LOOP is always before TRY.
586 if (EndToBegin[&MI]->getParent()->getNumber() > Header->getNumber())
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000587 BeforeSet.insert(&MI);
588#ifndef NDEBUG
589 else
590 AfterSet.insert(&MI);
591#endif
592 }
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000593
594 // It is not possible for an END_BLOCK to be already in this block.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000595 }
596
597 // Mark the end of the TRY.
Heejin Ahn20cf0742019-02-24 08:30:06 +0000598 InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet);
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000599 MachineInstr *End =
Heejin Ahn20cf0742019-02-24 08:30:06 +0000600 BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(),
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000601 TII.get(WebAssembly::END_TRY));
602 registerTryScope(Begin, End, &MBB);
603
Heejin Ahn82da1ff2019-02-27 01:35:14 +0000604 // Track the farthest-spanning scope that ends at this point. We create two
605 // mappings: (BB with 'end_try' -> BB with 'try') and (BB with 'catch' -> BB
606 // with 'try'). We need to create 'catch' -> 'try' mapping here too because
607 // markers should not span across 'catch'. For example, this should not
608 // happen:
609 //
610 // try
611 // block --| (X)
612 // catch |
613 // end_block --|
614 // end_try
615 for (int Number : {Cont->getNumber(), MBB.getNumber()}) {
616 if (!ScopeTops[Number] ||
617 ScopeTops[Number]->getNumber() > Header->getNumber())
618 ScopeTops[Number] = Header;
619 }
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000620}
621
Heejin Ahncf699b42019-02-27 00:50:53 +0000622void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) {
623 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
624
625 // When there is an unconditional branch right before a catch instruction and
626 // it branches to the end of end_try marker, we don't need the branch, because
627 // it there is no exception, the control flow transfers to that point anyway.
628 // bb0:
629 // try
630 // ...
631 // br bb2 <- Not necessary
632 // bb1:
633 // catch
634 // ...
635 // bb2:
636 // end
637 for (auto &MBB : MF) {
638 if (!MBB.isEHPad())
639 continue;
640
641 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
642 SmallVector<MachineOperand, 4> Cond;
Heejin Ahn5c644c92019-03-05 21:05:09 +0000643 MachineBasicBlock *EHPadLayoutPred = MBB.getPrevNode();
Heejin Ahncf699b42019-02-27 00:50:53 +0000644 MachineBasicBlock *Cont = BeginToEnd[EHPadToTry[&MBB]]->getParent();
645 bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond);
646 if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) ||
647 (!Cond.empty() && FBB && FBB == Cont)))
648 TII.removeBranch(*EHPadLayoutPred);
649 }
650
651 // When there are block / end_block markers that overlap with try / end_try
652 // markers, and the block and try markers' return types are the same, the
653 // block /end_block markers are not necessary, because try / end_try markers
654 // also can serve as boundaries for branches.
655 // block <- Not necessary
656 // try
657 // ...
658 // catch
659 // ...
660 // end
661 // end <- Not necessary
662 SmallVector<MachineInstr *, 32> ToDelete;
663 for (auto &MBB : MF) {
664 for (auto &MI : MBB) {
665 if (MI.getOpcode() != WebAssembly::TRY)
666 continue;
667
668 MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try];
669 MachineBasicBlock *TryBB = Try->getParent();
670 MachineBasicBlock *Cont = EndTry->getParent();
671 int64_t RetType = Try->getOperand(0).getImm();
Heejin Ahn5c644c92019-03-05 21:05:09 +0000672 for (auto B = Try->getIterator(), E = std::next(EndTry->getIterator());
Heejin Ahncf699b42019-02-27 00:50:53 +0000673 B != TryBB->begin() && E != Cont->end() &&
674 std::prev(B)->getOpcode() == WebAssembly::BLOCK &&
675 E->getOpcode() == WebAssembly::END_BLOCK &&
676 std::prev(B)->getOperand(0).getImm() == RetType;
677 --B, ++E) {
678 ToDelete.push_back(&*std::prev(B));
679 ToDelete.push_back(&*E);
680 }
681 }
682 }
683 for (auto *MI : ToDelete) {
684 if (MI->getOpcode() == WebAssembly::BLOCK)
685 unregisterScope(MI);
686 MI->eraseFromParent();
687 }
688}
689
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000690static unsigned
Heejin Ahn18c56a02019-02-04 19:13:39 +0000691getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000692 const MachineBasicBlock *MBB) {
693 unsigned Depth = 0;
694 for (auto X : reverse(Stack)) {
695 if (X == MBB)
696 break;
697 ++Depth;
698 }
699 assert(Depth < Stack.size() && "Branch destination should be in scope");
700 return Depth;
701}
702
Dan Gohman2726b882016-10-06 22:29:32 +0000703/// In normal assembly languages, when the end of a function is unreachable,
704/// because the function ends in an infinite loop or a noreturn call or similar,
705/// it isn't necessary to worry about the function return type at the end of
706/// the function, because it's never reached. However, in WebAssembly, blocks
707/// that end at the function end need to have a return type signature that
708/// matches the function signature, even though it's unreachable. This function
709/// checks for such cases and fixes up the signatures.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000710void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) {
711 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
Dan Gohman2726b882016-10-06 22:29:32 +0000712 assert(MFI.getResults().size() <= 1);
713
714 if (MFI.getResults().empty())
715 return;
716
Heejin Ahn18c56a02019-02-04 19:13:39 +0000717 WebAssembly::ExprType RetType;
Dan Gohman2726b882016-10-06 22:29:32 +0000718 switch (MFI.getResults().front().SimpleTy) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000719 case MVT::i32:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000720 RetType = WebAssembly::ExprType::I32;
Heejin Ahnf208f632018-09-05 01:27:38 +0000721 break;
722 case MVT::i64:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000723 RetType = WebAssembly::ExprType::I64;
Heejin Ahnf208f632018-09-05 01:27:38 +0000724 break;
725 case MVT::f32:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000726 RetType = WebAssembly::ExprType::F32;
Heejin Ahnf208f632018-09-05 01:27:38 +0000727 break;
728 case MVT::f64:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000729 RetType = WebAssembly::ExprType::F64;
Heejin Ahnf208f632018-09-05 01:27:38 +0000730 break;
Derek Schuff2c783852018-08-06 23:16:50 +0000731 case MVT::v16i8:
732 case MVT::v8i16:
733 case MVT::v4i32:
Derek Schuff51ed1312018-08-07 21:24:01 +0000734 case MVT::v2i64:
Derek Schuff2c783852018-08-06 23:16:50 +0000735 case MVT::v4f32:
Derek Schuff51ed1312018-08-07 21:24:01 +0000736 case MVT::v2f64:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000737 RetType = WebAssembly::ExprType::V128;
Derek Schuff2c783852018-08-06 23:16:50 +0000738 break;
Heejin Ahnf208f632018-09-05 01:27:38 +0000739 case MVT::ExceptRef:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000740 RetType = WebAssembly::ExprType::ExceptRef;
Heejin Ahnf208f632018-09-05 01:27:38 +0000741 break;
742 default:
743 llvm_unreachable("unexpected return type");
Dan Gohman2726b882016-10-06 22:29:32 +0000744 }
745
746 for (MachineBasicBlock &MBB : reverse(MF)) {
747 for (MachineInstr &MI : reverse(MBB)) {
Shiva Chen801bf7e2018-05-09 02:42:00 +0000748 if (MI.isPosition() || MI.isDebugInstr())
Dan Gohman2726b882016-10-06 22:29:32 +0000749 continue;
750 if (MI.getOpcode() == WebAssembly::END_BLOCK) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000751 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType));
Dan Gohman2726b882016-10-06 22:29:32 +0000752 continue;
753 }
754 if (MI.getOpcode() == WebAssembly::END_LOOP) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000755 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType));
Dan Gohman2726b882016-10-06 22:29:32 +0000756 continue;
757 }
758 // Something other than an `end`. We're done.
759 return;
760 }
761 }
762}
763
Dan Gohmand934cb82017-02-24 23:18:00 +0000764// WebAssembly functions end with an end instruction, as if the function body
765// were a block.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000766static void appendEndToFunction(MachineFunction &MF,
Heejin Ahnf208f632018-09-05 01:27:38 +0000767 const WebAssemblyInstrInfo &TII) {
Derek Schuff10b31352018-03-15 22:06:51 +0000768 BuildMI(MF.back(), MF.back().end(),
769 MF.back().findPrevDebugLoc(MF.back().end()),
Dan Gohmand934cb82017-02-24 23:18:00 +0000770 TII.get(WebAssembly::END_FUNCTION));
771}
772
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000773/// Insert LOOP/TRY/BLOCK markers at appropriate places.
774void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000775 // We allocate one more than the number of blocks in the function to
776 // accommodate for the possible fake block we may insert at the end.
777 ScopeTops.resize(MF.getNumBlockIDs() + 1);
778 // Place the LOOP for MBB if MBB is the header of a loop.
779 for (auto &MBB : MF)
780 placeLoopMarker(MBB);
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000781
Heejin Ahnd6f48782019-01-30 03:21:57 +0000782 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
Heejin Ahn44a5a4b2019-03-26 17:15:55 +0000783 for (auto &MBB : MF) {
784 if (MBB.isEHPad()) {
785 // Place the TRY for MBB if MBB is the EH pad of an exception.
786 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
787 MF.getFunction().hasPersonalityFn())
788 placeTryMarker(MBB);
789 } else {
790 // Place the BLOCK for MBB if MBB is branched to from above.
791 placeBlockMarker(MBB);
792 }
793 }
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000794}
Dan Gohman8fe7e862015-12-14 22:51:54 +0000795
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000796void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000797 // Now rewrite references to basic blocks to be depth immediates.
798 SmallVector<const MachineBasicBlock *, 8> Stack;
799 for (auto &MBB : reverse(MF)) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000800 for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) {
801 MachineInstr &MI = *I;
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000802 switch (MI.getOpcode()) {
803 case WebAssembly::BLOCK:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000804 case WebAssembly::TRY:
805 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <=
806 MBB.getNumber() &&
807 "Block/try marker should be balanced");
808 Stack.pop_back();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000809 break;
810
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000811 case WebAssembly::LOOP:
812 assert(Stack.back() == &MBB && "Loop top should be balanced");
813 Stack.pop_back();
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000814 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000815
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000816 case WebAssembly::END_BLOCK:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000817 case WebAssembly::END_TRY:
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000818 Stack.push_back(&MBB);
819 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000820
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000821 case WebAssembly::END_LOOP:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000822 Stack.push_back(EndToBegin[&MI]->getParent());
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000823 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000824
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000825 default:
826 if (MI.isTerminator()) {
827 // Rewrite MBB operands to be depth immediates.
828 SmallVector<MachineOperand, 4> Ops(MI.operands());
829 while (MI.getNumOperands() > 0)
830 MI.RemoveOperand(MI.getNumOperands() - 1);
831 for (auto MO : Ops) {
832 if (MO.isMBB())
Heejin Ahn18c56a02019-02-04 19:13:39 +0000833 MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB()));
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000834 MI.addOperand(MF, MO);
835 }
836 }
837 break;
838 }
839 }
840 }
841 assert(Stack.empty() && "Control flow should be balanced");
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000842}
Dan Gohman2726b882016-10-06 22:29:32 +0000843
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000844void WebAssemblyCFGStackify::releaseMemory() {
845 ScopeTops.clear();
846 BeginToEnd.clear();
847 EndToBegin.clear();
848 TryToEHPad.clear();
849 EHPadToTry.clear();
Dan Gohman32807932015-11-23 16:19:56 +0000850}
Dan Gohman32807932015-11-23 16:19:56 +0000851
Dan Gohman950a13c2015-09-16 16:51:30 +0000852bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000853 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n"
854 "********** Function: "
855 << MF.getName() << '\n');
Heejin Ahncf699b42019-02-27 00:50:53 +0000856 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
Dan Gohman950a13c2015-09-16 16:51:30 +0000857
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000858 releaseMemory();
859
Dan Gohmane0405332016-10-03 22:43:53 +0000860 // Liveness is not tracked for VALUE_STACK physreg.
Derek Schuff9c3bf312016-01-13 17:10:28 +0000861 MF.getRegInfo().invalidateLiveness();
Dan Gohman950a13c2015-09-16 16:51:30 +0000862
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000863 // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes.
864 placeMarkers(MF);
865
Heejin Ahncf699b42019-02-27 00:50:53 +0000866 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
867 MF.getFunction().hasPersonalityFn())
868 // Remove unnecessary instructions.
869 removeUnnecessaryInstrs(MF);
870
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000871 // Convert MBB operands in terminators to relative depth immediates.
872 rewriteDepthImmediates(MF);
873
874 // Fix up block/loop/try signatures at the end of the function to conform to
875 // WebAssembly's rules.
876 fixEndsAtEndOfFunction(MF);
877
878 // Add an end instruction at the end of the function body.
879 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
880 if (!MF.getSubtarget<WebAssemblySubtarget>()
881 .getTargetTriple()
882 .isOSBinFormatELF())
Heejin Ahn18c56a02019-02-04 19:13:39 +0000883 appendEndToFunction(MF, TII);
Dan Gohman32807932015-11-23 16:19:56 +0000884
Heejin Ahn1aaa4812019-03-26 17:46:14 +0000885 MF.getInfo<WebAssemblyFunctionInfo>()->setCFGStackified();
Dan Gohman950a13c2015-09-16 16:51:30 +0000886 return true;
887}