blob: 1efd34f8319e8e37e3693542e4fd41d6eba021df [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);
67 void rewriteDepthImmediates(MachineFunction &MF);
68 void fixEndsAtEndOfFunction(MachineFunction &MF);
69
70 // For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY).
71 DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd;
72 // For each END_(BLOCK|LOOP|TRY), the corresponding BLOCK|LOOP|TRY.
73 DenseMap<const MachineInstr *, MachineInstr *> EndToBegin;
74 // <TRY marker, EH pad> map
75 DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad;
76 // <EH pad, TRY marker> map
77 DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry;
Heejin Ahne76fa9e2018-08-16 23:50:59 +000078
Heejin Ahnd2fd7092018-12-07 21:31:14 +000079 // Helper functions to register scope information created by marker
80 // instructions.
Heejin Ahne76fa9e2018-08-16 23:50:59 +000081 void registerScope(MachineInstr *Begin, MachineInstr *End);
82 void registerTryScope(MachineInstr *Begin, MachineInstr *End,
83 MachineBasicBlock *EHPad);
Heejin Ahne76fa9e2018-08-16 23:50:59 +000084
Dan Gohman950a13c2015-09-16 16:51:30 +000085public:
86 static char ID; // Pass identification, replacement for typeid
87 WebAssemblyCFGStackify() : MachineFunctionPass(ID) {}
Heejin Ahne76fa9e2018-08-16 23:50:59 +000088 ~WebAssemblyCFGStackify() override { releaseMemory(); }
89 void releaseMemory() override;
Dan Gohman950a13c2015-09-16 16:51:30 +000090};
91} // end anonymous namespace
92
93char WebAssemblyCFGStackify::ID = 0;
Jacob Gravelle40926452018-03-30 20:36:58 +000094INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE,
Heejin Ahnf208f632018-09-05 01:27:38 +000095 "Insert BLOCK and LOOP markers for WebAssembly scopes", false,
96 false)
Jacob Gravelle40926452018-03-30 20:36:58 +000097
Dan Gohman950a13c2015-09-16 16:51:30 +000098FunctionPass *llvm::createWebAssemblyCFGStackify() {
99 return new WebAssemblyCFGStackify();
100}
101
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000102/// Test whether Pred has any terminators explicitly branching to MBB, as
103/// opposed to falling through. Note that it's possible (eg. in unoptimized
104/// code) for a branch instruction to both branch to a block and fallthrough
105/// to it, so we check the actual branch operands to see if there are any
106/// explicit mentions.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000107static bool explicitlyBranchesTo(MachineBasicBlock *Pred,
Dan Gohman35e4a282016-01-08 01:06:00 +0000108 MachineBasicBlock *MBB) {
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000109 for (MachineInstr &MI : Pred->terminators())
Heejin Ahnd6f48782019-01-30 03:21:57 +0000110 for (MachineOperand &MO : MI.explicit_operands())
111 if (MO.isMBB() && MO.getMBB() == MBB)
112 return true;
Dan Gohmanb3aa1ec2015-12-16 19:06:41 +0000113 return false;
114}
115
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000116// Returns an iterator to the earliest position possible within the MBB,
117// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
118// contains instructions that should go before the marker, and AfterSet contains
119// ones that should go after the marker. In this function, AfterSet is only
120// used for sanity checking.
121static MachineBasicBlock::iterator
Heejin Ahn18c56a02019-02-04 19:13:39 +0000122getEarliestInsertPos(MachineBasicBlock *MBB,
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000123 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
124 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
125 auto InsertPos = MBB->end();
126 while (InsertPos != MBB->begin()) {
127 if (BeforeSet.count(&*std::prev(InsertPos))) {
128#ifndef NDEBUG
129 // Sanity check
130 for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos)
131 assert(!AfterSet.count(&*std::prev(Pos)));
132#endif
133 break;
134 }
135 --InsertPos;
136 }
137 return InsertPos;
138}
139
140// Returns an iterator to the latest position possible within the MBB,
141// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
142// contains instructions that should go before the marker, and AfterSet contains
143// ones that should go after the marker. In this function, BeforeSet is only
144// used for sanity checking.
145static MachineBasicBlock::iterator
Heejin Ahn18c56a02019-02-04 19:13:39 +0000146getLatestInsertPos(MachineBasicBlock *MBB,
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000147 const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
148 const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
149 auto InsertPos = MBB->begin();
150 while (InsertPos != MBB->end()) {
151 if (AfterSet.count(&*InsertPos)) {
152#ifndef NDEBUG
153 // Sanity check
154 for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos)
155 assert(!BeforeSet.count(&*Pos));
156#endif
157 break;
158 }
159 ++InsertPos;
160 }
161 return InsertPos;
162}
163
164void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin,
165 MachineInstr *End) {
166 BeginToEnd[Begin] = End;
167 EndToBegin[End] = Begin;
168}
169
170void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin,
171 MachineInstr *End,
172 MachineBasicBlock *EHPad) {
173 registerScope(Begin, End);
174 TryToEHPad[Begin] = EHPad;
175 EHPadToTry[EHPad] = Begin;
176}
177
Dan Gohman32807932015-11-23 16:19:56 +0000178/// Insert a BLOCK marker for branches to MBB (if needed).
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000179void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) {
180 // This should have been handled in placeTryMarker.
181 if (MBB.isEHPad())
182 return;
183
184 MachineFunction &MF = *MBB.getParent();
185 auto &MDT = getAnalysis<MachineDominatorTree>();
186 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
187 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
188
Dan Gohman8fe7e862015-12-14 22:51:54 +0000189 // First compute the nearest common dominator of all forward non-fallthrough
190 // predecessors so that we minimize the time that the BLOCK is on the stack,
191 // which reduces overall stack height.
Dan Gohman32807932015-11-23 16:19:56 +0000192 MachineBasicBlock *Header = nullptr;
193 bool IsBranchedTo = false;
Heejin Ahnd6f48782019-01-30 03:21:57 +0000194 bool IsBrOnExn = false;
195 MachineInstr *BrOnExn = nullptr;
Dan Gohman32807932015-11-23 16:19:56 +0000196 int MBBNumber = MBB.getNumber();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000197 for (MachineBasicBlock *Pred : MBB.predecessors()) {
Dan Gohman32807932015-11-23 16:19:56 +0000198 if (Pred->getNumber() < MBBNumber) {
199 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
Heejin Ahn18c56a02019-02-04 19:13:39 +0000200 if (explicitlyBranchesTo(Pred, &MBB)) {
Dan Gohman32807932015-11-23 16:19:56 +0000201 IsBranchedTo = true;
Heejin Ahnd6f48782019-01-30 03:21:57 +0000202 if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) {
203 IsBrOnExn = true;
204 assert(!BrOnExn && "There should be only one br_on_exn per block");
205 BrOnExn = &*Pred->getFirstTerminator();
206 }
207 }
Dan Gohman32807932015-11-23 16:19:56 +0000208 }
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000209 }
Dan Gohman32807932015-11-23 16:19:56 +0000210 if (!Header)
211 return;
212 if (!IsBranchedTo)
Dan Gohman950a13c2015-09-16 16:51:30 +0000213 return;
214
Dan Gohman8fe7e862015-12-14 22:51:54 +0000215 assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors");
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000216 MachineBasicBlock *LayoutPred = &*std::prev(MachineFunction::iterator(&MBB));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000217
218 // If the nearest common dominator is inside a more deeply nested context,
219 // walk out to the nearest scope which isn't more deeply nested.
220 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
221 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
222 if (ScopeTop->getNumber() > Header->getNumber()) {
223 // Skip over an intervening scope.
Benjamin Krameref0a45a2016-09-05 12:06:47 +0000224 I = std::next(MachineFunction::iterator(ScopeTop));
Dan Gohman8fe7e862015-12-14 22:51:54 +0000225 } else {
226 // We found a scope level at an appropriate depth.
227 Header = ScopeTop;
228 break;
229 }
230 }
231 }
232
Dan Gohman8fe7e862015-12-14 22:51:54 +0000233 // Decide where in Header to put the BLOCK.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000234
235 // Instructions that should go before the BLOCK.
236 SmallPtrSet<const MachineInstr *, 4> BeforeSet;
237 // Instructions that should go after the BLOCK.
238 SmallPtrSet<const MachineInstr *, 4> AfterSet;
239 for (const auto &MI : *Header) {
240 // If there is a previously placed LOOP/TRY marker and the bottom block of
241 // the loop/exception is above MBB, it should be after the BLOCK, because
242 // the loop/exception is nested in this block. Otherwise it should be before
243 // the BLOCK.
244 if (MI.getOpcode() == WebAssembly::LOOP ||
245 MI.getOpcode() == WebAssembly::TRY) {
Heejin Ahn85631d82019-02-22 07:19:30 +0000246 auto *BottomBB =
247 &*std::prev(MachineFunction::iterator(BeginToEnd[&MI]->getParent()));
248 if (MBB.getNumber() > BottomBB->getNumber())
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000249 AfterSet.insert(&MI);
250#ifndef NDEBUG
251 else
252 BeforeSet.insert(&MI);
253#endif
254 }
255
256 // All previously inserted BLOCK markers should be after the BLOCK because
257 // they are all nested blocks.
258 if (MI.getOpcode() == WebAssembly::BLOCK)
259 AfterSet.insert(&MI);
260
261#ifndef NDEBUG
262 // All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK.
263 if (MI.getOpcode() == WebAssembly::END_BLOCK ||
264 MI.getOpcode() == WebAssembly::END_LOOP ||
265 MI.getOpcode() == WebAssembly::END_TRY)
266 BeforeSet.insert(&MI);
267#endif
268
269 // Terminators should go after the BLOCK.
270 if (MI.isTerminator())
271 AfterSet.insert(&MI);
272 }
273
274 // Local expression tree should go after the BLOCK.
275 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
276 --I) {
Yury Delendik409b4392018-10-04 23:31:00 +0000277 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
278 continue;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000279 if (WebAssembly::isChild(*std::prev(I), MFI))
280 AfterSet.insert(&*std::prev(I));
281 else
282 break;
Dan Gohman950a13c2015-09-16 16:51:30 +0000283 }
284
Dan Gohman8fe7e862015-12-14 22:51:54 +0000285 // Add the BLOCK.
Heejin Ahnd6f48782019-01-30 03:21:57 +0000286
287 // 'br_on_exn' extracts except_ref object and pushes variable number of values
288 // depending on its tag. For C++ exception, its a single i32 value, and the
289 // generated code will be in the form of:
290 // block i32
291 // br_on_exn 0, $__cpp_exception
292 // rethrow
293 // end_block
294 WebAssembly::ExprType ReturnType = WebAssembly::ExprType::Void;
295 if (IsBrOnExn) {
296 const char *TagName = BrOnExn->getOperand(1).getSymbolName();
297 if (std::strcmp(TagName, "__cpp_exception") != 0)
298 llvm_unreachable("Only C++ exception is supported");
299 ReturnType = WebAssembly::ExprType::I32;
300 }
301
Heejin Ahn18c56a02019-02-04 19:13:39 +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))
Heejin Ahnd6f48782019-01-30 03:21:57 +0000306 .addImm(int64_t(ReturnType));
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 Ahn18c56a02019-02-04 19:13:39 +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.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000385 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).
Heejin Ahn18c56a02019-02-04 19:13:39 +0000402 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
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000419 MachineFunction &MF = *MBB.getParent();
420 auto &MDT = getAnalysis<MachineDominatorTree>();
421 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
422 const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
423 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
424
425 // Compute the nearest common dominator of all unwind predecessors
426 MachineBasicBlock *Header = nullptr;
427 int MBBNumber = MBB.getNumber();
428 for (auto *Pred : MBB.predecessors()) {
429 if (Pred->getNumber() < MBBNumber) {
430 Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
Heejin Ahn18c56a02019-02-04 19:13:39 +0000431 assert(!explicitlyBranchesTo(Pred, &MBB) &&
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000432 "Explicit branch to an EH pad!");
433 }
434 }
435 if (!Header)
436 return;
437
438 // If this try is at the bottom of the function, insert a dummy block at the
439 // end.
440 WebAssemblyException *WE = WEI.getExceptionFor(&MBB);
441 assert(WE);
442 MachineBasicBlock *Bottom = WebAssembly::getBottom(WE);
443
444 auto Iter = std::next(MachineFunction::iterator(Bottom));
445 if (Iter == MF.end()) {
446 MachineBasicBlock *Label = MF.CreateMachineBasicBlock();
447 // Give it a fake predecessor so that AsmPrinter prints its label.
448 Label->addSuccessor(Label);
449 MF.push_back(Label);
450 Iter = std::next(MachineFunction::iterator(Bottom));
451 }
Heejin Ahn20cf0742019-02-24 08:30:06 +0000452 MachineBasicBlock *Cont = &*Iter;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000453
Heejin Ahn20cf0742019-02-24 08:30:06 +0000454 assert(Cont != &MF.front());
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000455 MachineBasicBlock *LayoutPred =
Heejin Ahn20cf0742019-02-24 08:30:06 +0000456 &*std::prev(MachineFunction::iterator(Cont));
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000457
458 // If the nearest common dominator is inside a more deeply nested context,
459 // walk out to the nearest scope which isn't more deeply nested.
460 for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
461 if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
462 if (ScopeTop->getNumber() > Header->getNumber()) {
463 // Skip over an intervening scope.
464 I = std::next(MachineFunction::iterator(ScopeTop));
465 } else {
466 // We found a scope level at an appropriate depth.
467 Header = ScopeTop;
468 break;
469 }
470 }
471 }
472
473 // Decide where in Header to put the TRY.
474
475 // Instructions that should go before the BLOCK.
476 SmallPtrSet<const MachineInstr *, 4> BeforeSet;
477 // Instructions that should go after the BLOCK.
478 SmallPtrSet<const MachineInstr *, 4> AfterSet;
479 for (const auto &MI : *Header) {
480 // If there is a previously placed LOOP marker and the bottom block of
481 // the loop is above MBB, the LOOP should be after the TRY, because the
482 // loop is nested in this try. Otherwise it should be before the TRY.
483 if (MI.getOpcode() == WebAssembly::LOOP) {
484 if (MBB.getNumber() > Bottom->getNumber())
485 AfterSet.insert(&MI);
486#ifndef NDEBUG
487 else
488 BeforeSet.insert(&MI);
489#endif
490 }
491
492 // All previously inserted TRY markers should be after the TRY because they
493 // are all nested trys.
494 if (MI.getOpcode() == WebAssembly::TRY)
495 AfterSet.insert(&MI);
496
497#ifndef NDEBUG
498 // All END_(LOOP/TRY) markers should be before the TRY.
499 if (MI.getOpcode() == WebAssembly::END_LOOP ||
500 MI.getOpcode() == WebAssembly::END_TRY)
501 BeforeSet.insert(&MI);
502#endif
503
504 // Terminators should go after the TRY.
505 if (MI.isTerminator())
506 AfterSet.insert(&MI);
507 }
508
509 // Local expression tree should go after the TRY.
510 for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
511 --I) {
Yury Delendik409b4392018-10-04 23:31:00 +0000512 if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
513 continue;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000514 if (WebAssembly::isChild(*std::prev(I), MFI))
515 AfterSet.insert(&*std::prev(I));
516 else
517 break;
518 }
519
520 // If Header unwinds to MBB (= Header contains 'invoke'), the try block should
521 // contain the call within it. So the call should go after the TRY. The
522 // exception is when the header's terminator is a rethrow instruction, in
523 // which case that instruction, not a call instruction before it, is gonna
524 // throw.
525 if (MBB.isPredecessor(Header)) {
526 auto TermPos = Header->getFirstTerminator();
Heejin Ahnd6f48782019-01-30 03:21:57 +0000527 if (TermPos == Header->end() ||
528 TermPos->getOpcode() != WebAssembly::RETHROW) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000529 for (const auto &MI : reverse(*Header)) {
530 if (MI.isCall()) {
531 AfterSet.insert(&MI);
532 break;
533 }
534 }
535 }
536 }
537
538 // Add the TRY.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000539 auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet);
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000540 MachineInstr *Begin =
541 BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
542 TII.get(WebAssembly::TRY))
543 .addImm(int64_t(WebAssembly::ExprType::Void));
544
545 // Decide where in Header to put the END_TRY.
546 BeforeSet.clear();
547 AfterSet.clear();
Heejin Ahn20cf0742019-02-24 08:30:06 +0000548 for (const auto &MI : *Cont) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000549#ifndef NDEBUG
550 // END_TRY should precede existing LOOP markers.
551 if (MI.getOpcode() == WebAssembly::LOOP)
552 AfterSet.insert(&MI);
553
554 // All END_TRY markers placed earlier belong to exceptions that contains
555 // this one.
556 if (MI.getOpcode() == WebAssembly::END_TRY)
557 AfterSet.insert(&MI);
558#endif
559
560 // If there is a previously placed END_LOOP marker and its header is after
561 // where TRY marker is, this loop is contained within the 'catch' part, so
562 // the END_TRY marker should go after that. Otherwise, the whole try-catch
563 // is contained within this loop, so the END_TRY should go before that.
564 if (MI.getOpcode() == WebAssembly::END_LOOP) {
565 if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber())
566 BeforeSet.insert(&MI);
567#ifndef NDEBUG
568 else
569 AfterSet.insert(&MI);
570#endif
571 }
572 }
573
574 // Mark the end of the TRY.
Heejin Ahn20cf0742019-02-24 08:30:06 +0000575 InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet);
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000576 MachineInstr *End =
Heejin Ahn20cf0742019-02-24 08:30:06 +0000577 BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(),
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000578 TII.get(WebAssembly::END_TRY));
579 registerTryScope(Begin, End, &MBB);
580
581 // Track the farthest-spanning scope that ends at this point.
Heejin Ahn20cf0742019-02-24 08:30:06 +0000582 int Number = Cont->getNumber();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000583 if (!ScopeTops[Number] ||
584 ScopeTops[Number]->getNumber() > Header->getNumber())
585 ScopeTops[Number] = Header;
586}
587
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000588static unsigned
Heejin Ahn18c56a02019-02-04 19:13:39 +0000589getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000590 const MachineBasicBlock *MBB) {
591 unsigned Depth = 0;
592 for (auto X : reverse(Stack)) {
593 if (X == MBB)
594 break;
595 ++Depth;
596 }
597 assert(Depth < Stack.size() && "Branch destination should be in scope");
598 return Depth;
599}
600
Dan Gohman2726b882016-10-06 22:29:32 +0000601/// In normal assembly languages, when the end of a function is unreachable,
602/// because the function ends in an infinite loop or a noreturn call or similar,
603/// it isn't necessary to worry about the function return type at the end of
604/// the function, because it's never reached. However, in WebAssembly, blocks
605/// that end at the function end need to have a return type signature that
606/// matches the function signature, even though it's unreachable. This function
607/// checks for such cases and fixes up the signatures.
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000608void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) {
609 const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
Dan Gohman2726b882016-10-06 22:29:32 +0000610 assert(MFI.getResults().size() <= 1);
611
612 if (MFI.getResults().empty())
613 return;
614
Heejin Ahn18c56a02019-02-04 19:13:39 +0000615 WebAssembly::ExprType RetType;
Dan Gohman2726b882016-10-06 22:29:32 +0000616 switch (MFI.getResults().front().SimpleTy) {
Heejin Ahnf208f632018-09-05 01:27:38 +0000617 case MVT::i32:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000618 RetType = WebAssembly::ExprType::I32;
Heejin Ahnf208f632018-09-05 01:27:38 +0000619 break;
620 case MVT::i64:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000621 RetType = WebAssembly::ExprType::I64;
Heejin Ahnf208f632018-09-05 01:27:38 +0000622 break;
623 case MVT::f32:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000624 RetType = WebAssembly::ExprType::F32;
Heejin Ahnf208f632018-09-05 01:27:38 +0000625 break;
626 case MVT::f64:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000627 RetType = WebAssembly::ExprType::F64;
Heejin Ahnf208f632018-09-05 01:27:38 +0000628 break;
Derek Schuff2c783852018-08-06 23:16:50 +0000629 case MVT::v16i8:
630 case MVT::v8i16:
631 case MVT::v4i32:
Derek Schuff51ed1312018-08-07 21:24:01 +0000632 case MVT::v2i64:
Derek Schuff2c783852018-08-06 23:16:50 +0000633 case MVT::v4f32:
Derek Schuff51ed1312018-08-07 21:24:01 +0000634 case MVT::v2f64:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000635 RetType = WebAssembly::ExprType::V128;
Derek Schuff2c783852018-08-06 23:16:50 +0000636 break;
Heejin Ahnf208f632018-09-05 01:27:38 +0000637 case MVT::ExceptRef:
Heejin Ahn18c56a02019-02-04 19:13:39 +0000638 RetType = WebAssembly::ExprType::ExceptRef;
Heejin Ahnf208f632018-09-05 01:27:38 +0000639 break;
640 default:
641 llvm_unreachable("unexpected return type");
Dan Gohman2726b882016-10-06 22:29:32 +0000642 }
643
644 for (MachineBasicBlock &MBB : reverse(MF)) {
645 for (MachineInstr &MI : reverse(MBB)) {
Shiva Chen801bf7e2018-05-09 02:42:00 +0000646 if (MI.isPosition() || MI.isDebugInstr())
Dan Gohman2726b882016-10-06 22:29:32 +0000647 continue;
648 if (MI.getOpcode() == WebAssembly::END_BLOCK) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000649 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType));
Dan Gohman2726b882016-10-06 22:29:32 +0000650 continue;
651 }
652 if (MI.getOpcode() == WebAssembly::END_LOOP) {
Heejin Ahn18c56a02019-02-04 19:13:39 +0000653 EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType));
Dan Gohman2726b882016-10-06 22:29:32 +0000654 continue;
655 }
656 // Something other than an `end`. We're done.
657 return;
658 }
659 }
660}
661
Dan Gohmand934cb82017-02-24 23:18:00 +0000662// WebAssembly functions end with an end instruction, as if the function body
663// were a block.
Heejin Ahn18c56a02019-02-04 19:13:39 +0000664static void appendEndToFunction(MachineFunction &MF,
Heejin Ahnf208f632018-09-05 01:27:38 +0000665 const WebAssemblyInstrInfo &TII) {
Derek Schuff10b31352018-03-15 22:06:51 +0000666 BuildMI(MF.back(), MF.back().end(),
667 MF.back().findPrevDebugLoc(MF.back().end()),
Dan Gohmand934cb82017-02-24 23:18:00 +0000668 TII.get(WebAssembly::END_FUNCTION));
669}
670
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000671/// Insert LOOP/TRY/BLOCK markers at appropriate places.
672void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000673 // We allocate one more than the number of blocks in the function to
674 // accommodate for the possible fake block we may insert at the end.
675 ScopeTops.resize(MF.getNumBlockIDs() + 1);
676 // Place the LOOP for MBB if MBB is the header of a loop.
677 for (auto &MBB : MF)
678 placeLoopMarker(MBB);
679 // Place the TRY for MBB if MBB is the EH pad of an exception.
Heejin Ahnd6f48782019-01-30 03:21:57 +0000680 const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000681 if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
682 MF.getFunction().hasPersonalityFn())
683 for (auto &MBB : MF)
684 placeTryMarker(MBB);
685 // Place the BLOCK for MBB if MBB is branched to from above.
686 for (auto &MBB : MF)
687 placeBlockMarker(MBB);
688}
Dan Gohman8fe7e862015-12-14 22:51:54 +0000689
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000690void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000691 // Now rewrite references to basic blocks to be depth immediates.
692 SmallVector<const MachineBasicBlock *, 8> Stack;
693 for (auto &MBB : reverse(MF)) {
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000694 for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) {
695 MachineInstr &MI = *I;
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000696 switch (MI.getOpcode()) {
697 case WebAssembly::BLOCK:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000698 case WebAssembly::TRY:
699 assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <=
700 MBB.getNumber() &&
701 "Block/try marker should be balanced");
702 Stack.pop_back();
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000703 break;
704
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000705 case WebAssembly::LOOP:
706 assert(Stack.back() == &MBB && "Loop top should be balanced");
707 Stack.pop_back();
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000708 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000709
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000710 case WebAssembly::END_BLOCK:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000711 case WebAssembly::END_TRY:
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000712 Stack.push_back(&MBB);
713 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000714
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000715 case WebAssembly::END_LOOP:
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000716 Stack.push_back(EndToBegin[&MI]->getParent());
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000717 break;
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000718
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000719 default:
720 if (MI.isTerminator()) {
721 // Rewrite MBB operands to be depth immediates.
722 SmallVector<MachineOperand, 4> Ops(MI.operands());
723 while (MI.getNumOperands() > 0)
724 MI.RemoveOperand(MI.getNumOperands() - 1);
725 for (auto MO : Ops) {
726 if (MO.isMBB())
Heejin Ahn18c56a02019-02-04 19:13:39 +0000727 MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB()));
Dan Gohman1d68e80f2016-01-12 19:14:46 +0000728 MI.addOperand(MF, MO);
729 }
730 }
731 break;
732 }
733 }
734 }
735 assert(Stack.empty() && "Control flow should be balanced");
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000736}
Dan Gohman2726b882016-10-06 22:29:32 +0000737
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000738void WebAssemblyCFGStackify::releaseMemory() {
739 ScopeTops.clear();
740 BeginToEnd.clear();
741 EndToBegin.clear();
742 TryToEHPad.clear();
743 EHPadToTry.clear();
Dan Gohman32807932015-11-23 16:19:56 +0000744}
Dan Gohman32807932015-11-23 16:19:56 +0000745
Dan Gohman950a13c2015-09-16 16:51:30 +0000746bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000747 LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n"
748 "********** Function: "
749 << MF.getName() << '\n');
Dan Gohman950a13c2015-09-16 16:51:30 +0000750
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000751 releaseMemory();
752
Dan Gohmane0405332016-10-03 22:43:53 +0000753 // Liveness is not tracked for VALUE_STACK physreg.
Derek Schuff9c3bf312016-01-13 17:10:28 +0000754 MF.getRegInfo().invalidateLiveness();
Dan Gohman950a13c2015-09-16 16:51:30 +0000755
Heejin Ahne76fa9e2018-08-16 23:50:59 +0000756 // Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes.
757 placeMarkers(MF);
758
759 // Convert MBB operands in terminators to relative depth immediates.
760 rewriteDepthImmediates(MF);
761
762 // Fix up block/loop/try signatures at the end of the function to conform to
763 // WebAssembly's rules.
764 fixEndsAtEndOfFunction(MF);
765
766 // Add an end instruction at the end of the function body.
767 const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
768 if (!MF.getSubtarget<WebAssemblySubtarget>()
769 .getTargetTriple()
770 .isOSBinFormatELF())
Heejin Ahn18c56a02019-02-04 19:13:39 +0000771 appendEndToFunction(MF, TII);
Dan Gohman32807932015-11-23 16:19:56 +0000772
Dan Gohman950a13c2015-09-16 16:51:30 +0000773 return true;
774}