2015-09-17 00:51:30 +08:00
|
|
|
//===-- WebAssemblyCFGStackify.cpp - CFG Stackification -------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2015-09-17 00:51:30 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
///
|
|
|
|
/// \file
|
2018-05-01 23:54:18 +08:00
|
|
|
/// This file implements a CFG stacking pass.
|
2015-09-17 00:51:30 +08:00
|
|
|
///
|
2018-08-17 07:50:59 +08:00
|
|
|
/// This pass inserts BLOCK, LOOP, and TRY markers to mark the start of scopes,
|
|
|
|
/// since scope boundaries serve as the labels for WebAssembly's control
|
|
|
|
/// transfers.
|
2015-09-17 00:51:30 +08:00
|
|
|
///
|
|
|
|
/// This is sufficient to convert arbitrary CFGs into a form that works on
|
|
|
|
/// WebAssembly, provided that all loops are single-entry.
|
|
|
|
///
|
2018-08-17 07:50:59 +08:00
|
|
|
/// In case we use exceptions, this pass also fixes mismatches in unwind
|
|
|
|
/// destinations created during transforming CFG into wasm structured format.
|
|
|
|
///
|
2015-09-17 00:51:30 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-06 19:49:48 +08:00
|
|
|
#include "WebAssembly.h"
|
2018-08-17 07:50:59 +08:00
|
|
|
#include "WebAssemblyExceptionInfo.h"
|
2016-01-30 13:01:06 +08:00
|
|
|
#include "WebAssemblyMachineFunctionInfo.h"
|
2015-09-17 00:51:30 +08:00
|
|
|
#include "WebAssemblySubtarget.h"
|
2016-10-25 03:49:43 +08:00
|
|
|
#include "WebAssemblyUtilities.h"
|
2019-03-30 19:04:48 +08:00
|
|
|
#include "llvm/ADT/Statistic.h"
|
2015-11-24 00:19:56 +08:00
|
|
|
#include "llvm/CodeGen/MachineDominators.h"
|
2015-09-17 00:51:30 +08:00
|
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
2018-08-17 07:50:59 +08:00
|
|
|
#include "llvm/MC/MCAsmInfo.h"
|
2015-09-17 00:51:30 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "wasm-cfg-stackify"
|
|
|
|
|
2019-03-30 19:04:48 +08:00
|
|
|
STATISTIC(NumUnwindMismatches, "Number of EH pad unwind mismatches found");
|
|
|
|
|
2015-09-17 00:51:30 +08:00
|
|
|
namespace {
|
|
|
|
class WebAssemblyCFGStackify final : public MachineFunctionPass {
|
2016-10-01 10:56:57 +08:00
|
|
|
StringRef getPassName() const override { return "WebAssembly CFG Stackify"; }
|
2015-09-17 00:51:30 +08:00
|
|
|
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
2015-11-24 00:19:56 +08:00
|
|
|
AU.addRequired<MachineDominatorTree>();
|
2015-09-17 00:51:30 +08:00
|
|
|
AU.addRequired<MachineLoopInfo>();
|
2018-08-17 07:50:59 +08:00
|
|
|
AU.addRequired<WebAssemblyExceptionInfo>();
|
2015-09-17 00:51:30 +08:00
|
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override;
|
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
// For each block whose label represents the end of a scope, record the block
|
|
|
|
// which holds the beginning of the scope. This will allow us to quickly skip
|
|
|
|
// over scoped regions when walking blocks.
|
|
|
|
SmallVector<MachineBasicBlock *, 8> ScopeTops;
|
|
|
|
|
2019-03-30 19:04:48 +08:00
|
|
|
// Placing markers.
|
2018-08-17 07:50:59 +08:00
|
|
|
void placeMarkers(MachineFunction &MF);
|
|
|
|
void placeBlockMarker(MachineBasicBlock &MBB);
|
|
|
|
void placeLoopMarker(MachineBasicBlock &MBB);
|
|
|
|
void placeTryMarker(MachineBasicBlock &MBB);
|
2019-02-27 08:50:53 +08:00
|
|
|
void removeUnnecessaryInstrs(MachineFunction &MF);
|
2019-03-30 19:04:48 +08:00
|
|
|
bool fixUnwindMismatches(MachineFunction &MF);
|
2018-08-17 07:50:59 +08:00
|
|
|
void rewriteDepthImmediates(MachineFunction &MF);
|
|
|
|
void fixEndsAtEndOfFunction(MachineFunction &MF);
|
|
|
|
|
|
|
|
// For each BLOCK|LOOP|TRY, the corresponding END_(BLOCK|LOOP|TRY).
|
|
|
|
DenseMap<const MachineInstr *, MachineInstr *> BeginToEnd;
|
|
|
|
// For each END_(BLOCK|LOOP|TRY), the corresponding BLOCK|LOOP|TRY.
|
|
|
|
DenseMap<const MachineInstr *, MachineInstr *> EndToBegin;
|
|
|
|
// <TRY marker, EH pad> map
|
|
|
|
DenseMap<const MachineInstr *, MachineBasicBlock *> TryToEHPad;
|
|
|
|
// <EH pad, TRY marker> map
|
|
|
|
DenseMap<const MachineBasicBlock *, MachineInstr *> EHPadToTry;
|
|
|
|
|
2019-03-30 19:04:48 +08:00
|
|
|
// There can be an appendix block at the end of each function, shared for:
|
|
|
|
// - creating a correct signature for fallthrough returns
|
|
|
|
// - target for rethrows that need to unwind to the caller, but are trapped
|
|
|
|
// inside another try/catch
|
|
|
|
MachineBasicBlock *AppendixBB = nullptr;
|
|
|
|
MachineBasicBlock *getAppendixBlock(MachineFunction &MF) {
|
|
|
|
if (!AppendixBB) {
|
|
|
|
AppendixBB = MF.CreateMachineBasicBlock();
|
|
|
|
// Give it a fake predecessor so that AsmPrinter prints its label.
|
|
|
|
AppendixBB->addSuccessor(AppendixBB);
|
|
|
|
MF.push_back(AppendixBB);
|
|
|
|
}
|
|
|
|
return AppendixBB;
|
|
|
|
}
|
|
|
|
|
2019-02-27 08:50:53 +08:00
|
|
|
// Helper functions to register / unregister scope information created by
|
|
|
|
// marker instructions.
|
2018-08-17 07:50:59 +08:00
|
|
|
void registerScope(MachineInstr *Begin, MachineInstr *End);
|
|
|
|
void registerTryScope(MachineInstr *Begin, MachineInstr *End,
|
|
|
|
MachineBasicBlock *EHPad);
|
2019-02-27 08:50:53 +08:00
|
|
|
void unregisterScope(MachineInstr *Begin);
|
2018-08-17 07:50:59 +08:00
|
|
|
|
2015-09-17 00:51:30 +08:00
|
|
|
public:
|
|
|
|
static char ID; // Pass identification, replacement for typeid
|
|
|
|
WebAssemblyCFGStackify() : MachineFunctionPass(ID) {}
|
2018-08-17 07:50:59 +08:00
|
|
|
~WebAssemblyCFGStackify() override { releaseMemory(); }
|
|
|
|
void releaseMemory() override;
|
2015-09-17 00:51:30 +08:00
|
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
|
|
|
|
char WebAssemblyCFGStackify::ID = 0;
|
2018-03-31 04:36:58 +08:00
|
|
|
INITIALIZE_PASS(WebAssemblyCFGStackify, DEBUG_TYPE,
|
2019-03-30 19:04:48 +08:00
|
|
|
"Insert BLOCK/LOOP/TRY markers for WebAssembly scopes", false,
|
2018-09-05 09:27:38 +08:00
|
|
|
false)
|
2018-03-31 04:36:58 +08:00
|
|
|
|
2015-09-17 00:51:30 +08:00
|
|
|
FunctionPass *llvm::createWebAssemblyCFGStackify() {
|
|
|
|
return new WebAssemblyCFGStackify();
|
|
|
|
}
|
|
|
|
|
2015-12-17 03:06:41 +08:00
|
|
|
/// Test whether Pred has any terminators explicitly branching to MBB, as
|
|
|
|
/// opposed to falling through. Note that it's possible (eg. in unoptimized
|
|
|
|
/// code) for a branch instruction to both branch to a block and fallthrough
|
|
|
|
/// to it, so we check the actual branch operands to see if there are any
|
|
|
|
/// explicit mentions.
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
static bool explicitlyBranchesTo(MachineBasicBlock *Pred,
|
2016-01-08 09:06:00 +08:00
|
|
|
MachineBasicBlock *MBB) {
|
2015-12-17 03:06:41 +08:00
|
|
|
for (MachineInstr &MI : Pred->terminators())
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
for (MachineOperand &MO : MI.explicit_operands())
|
|
|
|
if (MO.isMBB() && MO.getMBB() == MBB)
|
|
|
|
return true;
|
2015-12-17 03:06:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
// Returns an iterator to the earliest position possible within the MBB,
|
|
|
|
// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
|
|
|
|
// contains instructions that should go before the marker, and AfterSet contains
|
|
|
|
// ones that should go after the marker. In this function, AfterSet is only
|
|
|
|
// used for sanity checking.
|
|
|
|
static MachineBasicBlock::iterator
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
getEarliestInsertPos(MachineBasicBlock *MBB,
|
2018-08-17 07:50:59 +08:00
|
|
|
const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
|
|
|
|
const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
|
|
|
|
auto InsertPos = MBB->end();
|
|
|
|
while (InsertPos != MBB->begin()) {
|
|
|
|
if (BeforeSet.count(&*std::prev(InsertPos))) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// Sanity check
|
|
|
|
for (auto Pos = InsertPos, E = MBB->begin(); Pos != E; --Pos)
|
|
|
|
assert(!AfterSet.count(&*std::prev(Pos)));
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
--InsertPos;
|
|
|
|
}
|
|
|
|
return InsertPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Returns an iterator to the latest position possible within the MBB,
|
|
|
|
// satisfying the restrictions given by BeforeSet and AfterSet. BeforeSet
|
|
|
|
// contains instructions that should go before the marker, and AfterSet contains
|
|
|
|
// ones that should go after the marker. In this function, BeforeSet is only
|
|
|
|
// used for sanity checking.
|
|
|
|
static MachineBasicBlock::iterator
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
getLatestInsertPos(MachineBasicBlock *MBB,
|
2018-08-17 07:50:59 +08:00
|
|
|
const SmallPtrSet<const MachineInstr *, 4> &BeforeSet,
|
|
|
|
const SmallPtrSet<const MachineInstr *, 4> &AfterSet) {
|
|
|
|
auto InsertPos = MBB->begin();
|
|
|
|
while (InsertPos != MBB->end()) {
|
|
|
|
if (AfterSet.count(&*InsertPos)) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// Sanity check
|
|
|
|
for (auto Pos = InsertPos, E = MBB->end(); Pos != E; ++Pos)
|
|
|
|
assert(!BeforeSet.count(&*Pos));
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++InsertPos;
|
|
|
|
}
|
|
|
|
return InsertPos;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebAssemblyCFGStackify::registerScope(MachineInstr *Begin,
|
|
|
|
MachineInstr *End) {
|
|
|
|
BeginToEnd[Begin] = End;
|
|
|
|
EndToBegin[End] = Begin;
|
|
|
|
}
|
|
|
|
|
|
|
|
void WebAssemblyCFGStackify::registerTryScope(MachineInstr *Begin,
|
|
|
|
MachineInstr *End,
|
|
|
|
MachineBasicBlock *EHPad) {
|
|
|
|
registerScope(Begin, End);
|
|
|
|
TryToEHPad[Begin] = EHPad;
|
|
|
|
EHPadToTry[EHPad] = Begin;
|
|
|
|
}
|
|
|
|
|
2019-02-27 08:50:53 +08:00
|
|
|
void WebAssemblyCFGStackify::unregisterScope(MachineInstr *Begin) {
|
|
|
|
assert(BeginToEnd.count(Begin));
|
|
|
|
MachineInstr *End = BeginToEnd[Begin];
|
|
|
|
assert(EndToBegin.count(End));
|
|
|
|
BeginToEnd.erase(Begin);
|
|
|
|
EndToBegin.erase(End);
|
|
|
|
MachineBasicBlock *EHPad = TryToEHPad.lookup(Begin);
|
|
|
|
if (EHPad) {
|
|
|
|
assert(EHPadToTry.count(EHPad));
|
|
|
|
TryToEHPad.erase(Begin);
|
|
|
|
EHPadToTry.erase(EHPad);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-24 00:19:56 +08:00
|
|
|
/// Insert a BLOCK marker for branches to MBB (if needed).
|
2019-03-30 19:04:48 +08:00
|
|
|
// TODO Consider a more generalized way of handling block (and also loop and
|
|
|
|
// try) signatures when we implement the multi-value proposal later.
|
2018-08-17 07:50:59 +08:00
|
|
|
void WebAssemblyCFGStackify::placeBlockMarker(MachineBasicBlock &MBB) {
|
2019-03-27 01:15:55 +08:00
|
|
|
assert(!MBB.isEHPad());
|
2018-08-17 07:50:59 +08:00
|
|
|
MachineFunction &MF = *MBB.getParent();
|
|
|
|
auto &MDT = getAnalysis<MachineDominatorTree>();
|
|
|
|
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
|
|
|
|
const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
|
|
|
|
|
2015-12-15 06:51:54 +08:00
|
|
|
// First compute the nearest common dominator of all forward non-fallthrough
|
|
|
|
// predecessors so that we minimize the time that the BLOCK is on the stack,
|
|
|
|
// which reduces overall stack height.
|
2015-11-24 00:19:56 +08:00
|
|
|
MachineBasicBlock *Header = nullptr;
|
|
|
|
bool IsBranchedTo = false;
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
bool IsBrOnExn = false;
|
|
|
|
MachineInstr *BrOnExn = nullptr;
|
2015-11-24 00:19:56 +08:00
|
|
|
int MBBNumber = MBB.getNumber();
|
2018-08-17 07:50:59 +08:00
|
|
|
for (MachineBasicBlock *Pred : MBB.predecessors()) {
|
2015-11-24 00:19:56 +08:00
|
|
|
if (Pred->getNumber() < MBBNumber) {
|
|
|
|
Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
if (explicitlyBranchesTo(Pred, &MBB)) {
|
2015-11-24 00:19:56 +08:00
|
|
|
IsBranchedTo = true;
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
if (Pred->getFirstTerminator()->getOpcode() == WebAssembly::BR_ON_EXN) {
|
|
|
|
IsBrOnExn = true;
|
|
|
|
assert(!BrOnExn && "There should be only one br_on_exn per block");
|
|
|
|
BrOnExn = &*Pred->getFirstTerminator();
|
|
|
|
}
|
|
|
|
}
|
2015-09-17 00:51:30 +08:00
|
|
|
}
|
2018-08-17 07:50:59 +08:00
|
|
|
}
|
2015-11-24 00:19:56 +08:00
|
|
|
if (!Header)
|
|
|
|
return;
|
|
|
|
if (!IsBranchedTo)
|
|
|
|
return;
|
|
|
|
|
2015-12-15 06:51:54 +08:00
|
|
|
assert(&MBB != &MF.front() && "Header blocks shouldn't have predecessors");
|
2019-03-06 05:05:09 +08:00
|
|
|
MachineBasicBlock *LayoutPred = MBB.getPrevNode();
|
2015-12-15 06:51:54 +08:00
|
|
|
|
|
|
|
// If the nearest common dominator is inside a more deeply nested context,
|
|
|
|
// walk out to the nearest scope which isn't more deeply nested.
|
|
|
|
for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
|
|
|
|
if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
|
|
|
|
if (ScopeTop->getNumber() > Header->getNumber()) {
|
|
|
|
// Skip over an intervening scope.
|
2019-03-06 05:05:09 +08:00
|
|
|
I = std::next(ScopeTop->getIterator());
|
2015-12-15 06:51:54 +08:00
|
|
|
} else {
|
|
|
|
// We found a scope level at an appropriate depth.
|
|
|
|
Header = ScopeTop;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decide where in Header to put the BLOCK.
|
2018-08-17 07:50:59 +08:00
|
|
|
|
|
|
|
// Instructions that should go before the BLOCK.
|
|
|
|
SmallPtrSet<const MachineInstr *, 4> BeforeSet;
|
|
|
|
// Instructions that should go after the BLOCK.
|
|
|
|
SmallPtrSet<const MachineInstr *, 4> AfterSet;
|
|
|
|
for (const auto &MI : *Header) {
|
2019-03-27 01:15:55 +08:00
|
|
|
// If there is a previously placed LOOP marker and the bottom block of the
|
|
|
|
// loop is above MBB, it should be after the BLOCK, because the loop is
|
|
|
|
// nested in this BLOCK. Otherwise it should be before the BLOCK.
|
|
|
|
if (MI.getOpcode() == WebAssembly::LOOP) {
|
|
|
|
auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode();
|
|
|
|
if (MBB.getNumber() > LoopBottom->getNumber())
|
2018-08-17 07:50:59 +08:00
|
|
|
AfterSet.insert(&MI);
|
|
|
|
#ifndef NDEBUG
|
|
|
|
else
|
|
|
|
BeforeSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-03-27 01:15:55 +08:00
|
|
|
// All previously inserted BLOCK/TRY markers should be after the BLOCK
|
|
|
|
// because they are all nested blocks.
|
|
|
|
if (MI.getOpcode() == WebAssembly::BLOCK ||
|
|
|
|
MI.getOpcode() == WebAssembly::TRY)
|
2018-08-17 07:50:59 +08:00
|
|
|
AfterSet.insert(&MI);
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// All END_(BLOCK|LOOP|TRY) markers should be before the BLOCK.
|
|
|
|
if (MI.getOpcode() == WebAssembly::END_BLOCK ||
|
|
|
|
MI.getOpcode() == WebAssembly::END_LOOP ||
|
|
|
|
MI.getOpcode() == WebAssembly::END_TRY)
|
|
|
|
BeforeSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Terminators should go after the BLOCK.
|
|
|
|
if (MI.isTerminator())
|
|
|
|
AfterSet.insert(&MI);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Local expression tree should go after the BLOCK.
|
|
|
|
for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
|
|
|
|
--I) {
|
2018-10-05 07:31:00 +08:00
|
|
|
if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
|
|
|
|
continue;
|
2018-08-17 07:50:59 +08:00
|
|
|
if (WebAssembly::isChild(*std::prev(I), MFI))
|
|
|
|
AfterSet.insert(&*std::prev(I));
|
|
|
|
else
|
|
|
|
break;
|
2015-09-17 00:51:30 +08:00
|
|
|
}
|
|
|
|
|
2015-12-15 06:51:54 +08:00
|
|
|
// Add the BLOCK.
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
|
2019-07-16 06:49:25 +08:00
|
|
|
// 'br_on_exn' extracts exnref object and pushes variable number of values
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
// depending on its tag. For C++ exception, its a single i32 value, and the
|
|
|
|
// generated code will be in the form of:
|
|
|
|
// block i32
|
|
|
|
// br_on_exn 0, $__cpp_exception
|
|
|
|
// rethrow
|
|
|
|
// end_block
|
|
|
|
WebAssembly::ExprType ReturnType = WebAssembly::ExprType::Void;
|
|
|
|
if (IsBrOnExn) {
|
|
|
|
const char *TagName = BrOnExn->getOperand(1).getSymbolName();
|
|
|
|
if (std::strcmp(TagName, "__cpp_exception") != 0)
|
|
|
|
llvm_unreachable("Only C++ exception is supported");
|
|
|
|
ReturnType = WebAssembly::ExprType::I32;
|
|
|
|
}
|
|
|
|
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet);
|
2018-04-14 08:12:12 +08:00
|
|
|
MachineInstr *Begin =
|
|
|
|
BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
|
|
|
|
TII.get(WebAssembly::BLOCK))
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
.addImm(int64_t(ReturnType));
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
// Decide where in Header to put the END_BLOCK.
|
|
|
|
BeforeSet.clear();
|
|
|
|
AfterSet.clear();
|
|
|
|
for (auto &MI : MBB) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
// END_BLOCK should precede existing LOOP and TRY markers.
|
|
|
|
if (MI.getOpcode() == WebAssembly::LOOP ||
|
|
|
|
MI.getOpcode() == WebAssembly::TRY)
|
|
|
|
AfterSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// If there is a previously placed END_LOOP marker and the header of the
|
|
|
|
// loop is above this block's header, the END_LOOP should be placed after
|
|
|
|
// the BLOCK, because the loop contains this block. Otherwise the END_LOOP
|
|
|
|
// should be placed before the BLOCK. The same for END_TRY.
|
|
|
|
if (MI.getOpcode() == WebAssembly::END_LOOP ||
|
|
|
|
MI.getOpcode() == WebAssembly::END_TRY) {
|
|
|
|
if (EndToBegin[&MI]->getParent()->getNumber() >= Header->getNumber())
|
|
|
|
BeforeSet.insert(&MI);
|
|
|
|
#ifndef NDEBUG
|
|
|
|
else
|
|
|
|
AfterSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
// Mark the end of the block.
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet);
|
2018-03-16 06:06:51 +08:00
|
|
|
MachineInstr *End = BuildMI(MBB, InsertPos, MBB.findPrevDebugLoc(InsertPos),
|
2016-10-07 06:29:32 +08:00
|
|
|
TII.get(WebAssembly::END_BLOCK));
|
2018-08-17 07:50:59 +08:00
|
|
|
registerScope(Begin, End);
|
2015-12-15 06:51:54 +08:00
|
|
|
|
|
|
|
// Track the farthest-spanning scope that ends at this point.
|
|
|
|
int Number = MBB.getNumber();
|
|
|
|
if (!ScopeTops[Number] ||
|
|
|
|
ScopeTops[Number]->getNumber() > Header->getNumber())
|
|
|
|
ScopeTops[Number] = Header;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Insert a LOOP marker for a loop starting at MBB (if it's a loop header).
|
2018-08-17 07:50:59 +08:00
|
|
|
void WebAssemblyCFGStackify::placeLoopMarker(MachineBasicBlock &MBB) {
|
|
|
|
MachineFunction &MF = *MBB.getParent();
|
|
|
|
const auto &MLI = getAnalysis<MachineLoopInfo>();
|
|
|
|
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
|
|
|
|
|
2015-12-15 06:51:54 +08:00
|
|
|
MachineLoop *Loop = MLI.getLoopFor(&MBB);
|
|
|
|
if (!Loop || Loop->getHeader() != &MBB)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// The operand of a LOOP is the first block after the loop. If the loop is the
|
|
|
|
// bottom of the function, insert a dummy block at the end.
|
2018-06-19 08:32:03 +08:00
|
|
|
MachineBasicBlock *Bottom = WebAssembly::getBottom(Loop);
|
2019-03-06 05:05:09 +08:00
|
|
|
auto Iter = std::next(Bottom->getIterator());
|
2015-12-15 06:51:54 +08:00
|
|
|
if (Iter == MF.end()) {
|
2019-03-30 19:04:48 +08:00
|
|
|
getAppendixBlock(MF);
|
2019-03-06 05:05:09 +08:00
|
|
|
Iter = std::next(Bottom->getIterator());
|
2015-12-15 06:51:54 +08:00
|
|
|
}
|
|
|
|
MachineBasicBlock *AfterLoop = &*Iter;
|
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
// Decide where in Header to put the LOOP.
|
|
|
|
SmallPtrSet<const MachineInstr *, 4> BeforeSet;
|
|
|
|
SmallPtrSet<const MachineInstr *, 4> AfterSet;
|
|
|
|
for (const auto &MI : MBB) {
|
|
|
|
// LOOP marker should be after any existing loop that ends here. Otherwise
|
|
|
|
// we assume the instruction belongs to the loop.
|
|
|
|
if (MI.getOpcode() == WebAssembly::END_LOOP)
|
|
|
|
BeforeSet.insert(&MI);
|
|
|
|
#ifndef NDEBUG
|
|
|
|
else
|
|
|
|
AfterSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark the beginning of the loop.
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
auto InsertPos = getEarliestInsertPos(&MBB, BeforeSet, AfterSet);
|
2018-03-16 06:06:51 +08:00
|
|
|
MachineInstr *Begin = BuildMI(MBB, InsertPos, MBB.findDebugLoc(InsertPos),
|
2016-10-07 06:29:32 +08:00
|
|
|
TII.get(WebAssembly::LOOP))
|
2018-03-16 06:06:51 +08:00
|
|
|
.addImm(int64_t(WebAssembly::ExprType::Void));
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
// Decide where in Header to put the END_LOOP.
|
|
|
|
BeforeSet.clear();
|
|
|
|
AfterSet.clear();
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (const auto &MI : MBB)
|
|
|
|
// Existing END_LOOP markers belong to parent loops of this loop
|
|
|
|
if (MI.getOpcode() == WebAssembly::END_LOOP)
|
|
|
|
AfterSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Mark the end of the loop (using arbitrary debug location that branched to
|
|
|
|
// the loop end as its location).
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
InsertPos = getEarliestInsertPos(AfterLoop, BeforeSet, AfterSet);
|
2019-03-30 03:36:51 +08:00
|
|
|
DebugLoc EndDL = AfterLoop->pred_empty()
|
|
|
|
? DebugLoc()
|
|
|
|
: (*AfterLoop->pred_rbegin())->findBranchDebugLoc();
|
2018-08-17 07:50:59 +08:00
|
|
|
MachineInstr *End =
|
|
|
|
BuildMI(*AfterLoop, InsertPos, EndDL, TII.get(WebAssembly::END_LOOP));
|
|
|
|
registerScope(Begin, End);
|
2015-12-15 06:51:54 +08:00
|
|
|
|
|
|
|
assert((!ScopeTops[AfterLoop->getNumber()] ||
|
|
|
|
ScopeTops[AfterLoop->getNumber()]->getNumber() < MBB.getNumber()) &&
|
2016-02-17 00:22:41 +08:00
|
|
|
"With block sorting the outermost loop for a block should be first.");
|
2015-12-15 06:51:54 +08:00
|
|
|
if (!ScopeTops[AfterLoop->getNumber()])
|
|
|
|
ScopeTops[AfterLoop->getNumber()] = &MBB;
|
2015-09-17 00:51:30 +08:00
|
|
|
}
|
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
void WebAssemblyCFGStackify::placeTryMarker(MachineBasicBlock &MBB) {
|
2019-03-27 01:15:55 +08:00
|
|
|
assert(MBB.isEHPad());
|
2018-08-17 07:50:59 +08:00
|
|
|
MachineFunction &MF = *MBB.getParent();
|
|
|
|
auto &MDT = getAnalysis<MachineDominatorTree>();
|
|
|
|
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
|
|
|
|
const auto &WEI = getAnalysis<WebAssemblyExceptionInfo>();
|
|
|
|
const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
|
|
|
|
|
|
|
|
// Compute the nearest common dominator of all unwind predecessors
|
|
|
|
MachineBasicBlock *Header = nullptr;
|
|
|
|
int MBBNumber = MBB.getNumber();
|
|
|
|
for (auto *Pred : MBB.predecessors()) {
|
|
|
|
if (Pred->getNumber() < MBBNumber) {
|
|
|
|
Header = Header ? MDT.findNearestCommonDominator(Header, Pred) : Pred;
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
assert(!explicitlyBranchesTo(Pred, &MBB) &&
|
2018-08-17 07:50:59 +08:00
|
|
|
"Explicit branch to an EH pad!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!Header)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// If this try is at the bottom of the function, insert a dummy block at the
|
|
|
|
// end.
|
|
|
|
WebAssemblyException *WE = WEI.getExceptionFor(&MBB);
|
|
|
|
assert(WE);
|
|
|
|
MachineBasicBlock *Bottom = WebAssembly::getBottom(WE);
|
|
|
|
|
2019-03-06 05:05:09 +08:00
|
|
|
auto Iter = std::next(Bottom->getIterator());
|
2018-08-17 07:50:59 +08:00
|
|
|
if (Iter == MF.end()) {
|
2019-03-30 19:04:48 +08:00
|
|
|
getAppendixBlock(MF);
|
2019-03-06 05:05:09 +08:00
|
|
|
Iter = std::next(Bottom->getIterator());
|
2018-08-17 07:50:59 +08:00
|
|
|
}
|
2019-02-24 16:30:06 +08:00
|
|
|
MachineBasicBlock *Cont = &*Iter;
|
2018-08-17 07:50:59 +08:00
|
|
|
|
2019-02-24 16:30:06 +08:00
|
|
|
assert(Cont != &MF.front());
|
2019-03-06 05:05:09 +08:00
|
|
|
MachineBasicBlock *LayoutPred = Cont->getPrevNode();
|
2018-08-17 07:50:59 +08:00
|
|
|
|
|
|
|
// If the nearest common dominator is inside a more deeply nested context,
|
|
|
|
// walk out to the nearest scope which isn't more deeply nested.
|
|
|
|
for (MachineFunction::iterator I(LayoutPred), E(Header); I != E; --I) {
|
|
|
|
if (MachineBasicBlock *ScopeTop = ScopeTops[I->getNumber()]) {
|
|
|
|
if (ScopeTop->getNumber() > Header->getNumber()) {
|
|
|
|
// Skip over an intervening scope.
|
2019-03-06 05:05:09 +08:00
|
|
|
I = std::next(ScopeTop->getIterator());
|
2018-08-17 07:50:59 +08:00
|
|
|
} else {
|
|
|
|
// We found a scope level at an appropriate depth.
|
|
|
|
Header = ScopeTop;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decide where in Header to put the TRY.
|
|
|
|
|
2019-03-27 01:15:55 +08:00
|
|
|
// Instructions that should go before the TRY.
|
2018-08-17 07:50:59 +08:00
|
|
|
SmallPtrSet<const MachineInstr *, 4> BeforeSet;
|
2019-03-27 01:15:55 +08:00
|
|
|
// Instructions that should go after the TRY.
|
2018-08-17 07:50:59 +08:00
|
|
|
SmallPtrSet<const MachineInstr *, 4> AfterSet;
|
|
|
|
for (const auto &MI : *Header) {
|
2019-03-27 01:15:55 +08:00
|
|
|
// If there is a previously placed LOOP marker and the bottom block of the
|
|
|
|
// loop is above MBB, it should be after the TRY, because the loop is nested
|
|
|
|
// in this TRY. Otherwise it should be before the TRY.
|
2018-08-17 07:50:59 +08:00
|
|
|
if (MI.getOpcode() == WebAssembly::LOOP) {
|
2019-03-27 01:15:55 +08:00
|
|
|
auto *LoopBottom = BeginToEnd[&MI]->getParent()->getPrevNode();
|
|
|
|
if (MBB.getNumber() > LoopBottom->getNumber())
|
2018-08-17 07:50:59 +08:00
|
|
|
AfterSet.insert(&MI);
|
|
|
|
#ifndef NDEBUG
|
|
|
|
else
|
|
|
|
BeforeSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-03-27 01:15:55 +08:00
|
|
|
// All previously inserted BLOCK/TRY markers should be after the TRY because
|
|
|
|
// they are all nested trys.
|
|
|
|
if (MI.getOpcode() == WebAssembly::BLOCK ||
|
|
|
|
MI.getOpcode() == WebAssembly::TRY)
|
2018-08-17 07:50:59 +08:00
|
|
|
AfterSet.insert(&MI);
|
|
|
|
|
|
|
|
#ifndef NDEBUG
|
2019-03-27 01:15:55 +08:00
|
|
|
// All END_(BLOCK/LOOP/TRY) markers should be before the TRY.
|
|
|
|
if (MI.getOpcode() == WebAssembly::END_BLOCK ||
|
|
|
|
MI.getOpcode() == WebAssembly::END_LOOP ||
|
2018-08-17 07:50:59 +08:00
|
|
|
MI.getOpcode() == WebAssembly::END_TRY)
|
|
|
|
BeforeSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Terminators should go after the TRY.
|
|
|
|
if (MI.isTerminator())
|
|
|
|
AfterSet.insert(&MI);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Local expression tree should go after the TRY.
|
|
|
|
for (auto I = Header->getFirstTerminator(), E = Header->begin(); I != E;
|
|
|
|
--I) {
|
2018-10-05 07:31:00 +08:00
|
|
|
if (std::prev(I)->isDebugInstr() || std::prev(I)->isPosition())
|
|
|
|
continue;
|
2018-08-17 07:50:59 +08:00
|
|
|
if (WebAssembly::isChild(*std::prev(I), MFI))
|
|
|
|
AfterSet.insert(&*std::prev(I));
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If Header unwinds to MBB (= Header contains 'invoke'), the try block should
|
|
|
|
// contain the call within it. So the call should go after the TRY. The
|
|
|
|
// exception is when the header's terminator is a rethrow instruction, in
|
|
|
|
// which case that instruction, not a call instruction before it, is gonna
|
|
|
|
// throw.
|
|
|
|
if (MBB.isPredecessor(Header)) {
|
|
|
|
auto TermPos = Header->getFirstTerminator();
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
if (TermPos == Header->end() ||
|
|
|
|
TermPos->getOpcode() != WebAssembly::RETHROW) {
|
2018-08-17 07:50:59 +08:00
|
|
|
for (const auto &MI : reverse(*Header)) {
|
|
|
|
if (MI.isCall()) {
|
|
|
|
AfterSet.insert(&MI);
|
[WebAssembly] Place 'try' and 'catch' correctly wrt EH_LABELs
Summary:
After instruction selection phase, possibly-throwing calls, which were
previously invoke, are wrapped in `EH_LABEL` instructions. For example:
```
EH_LABEL <mcsymbol .Ltmp0>
CALL_VOID @foo ...
EH_LABEL <mcsymbol .Ltmp1>
```
`EH_LABEL` is placed also in the beginning of EH pads:
```
bb.1 (landing-pad):
EH_LABEL <mcsymbol .Ltmp2>
...
```
And we'd like to maintian this relationship, so when we place a `try`,
```
TRY ...
EH_LABEL <mcsymbol .Ltmp0>
CALL_VOID @foo ...
EH_LABEL <mcsymbol .Ltmp1>
```
When we place a `catch`,
```
bb.1 (landing-pad):
EH_LABEL <mcsymbol .Ltmp2>
%0:except_ref = CATCH ...
...
```
Previously we didn't treat EH_LABELs specially, so `try` was placed
right before a call, and `catch` was placed in the beginning of an EH
pad.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D58914
llvm-svn: 355996
2019-03-13 08:37:31 +08:00
|
|
|
// Possibly throwing calls are usually wrapped by EH_LABEL
|
|
|
|
// instructions. We don't want to split them and the call.
|
|
|
|
if (MI.getIterator() != Header->begin() &&
|
|
|
|
std::prev(MI.getIterator())->isEHLabel())
|
|
|
|
AfterSet.insert(&*std::prev(MI.getIterator()));
|
2018-08-17 07:50:59 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add the TRY.
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
auto InsertPos = getLatestInsertPos(Header, BeforeSet, AfterSet);
|
2018-08-17 07:50:59 +08:00
|
|
|
MachineInstr *Begin =
|
|
|
|
BuildMI(*Header, InsertPos, Header->findDebugLoc(InsertPos),
|
|
|
|
TII.get(WebAssembly::TRY))
|
|
|
|
.addImm(int64_t(WebAssembly::ExprType::Void));
|
|
|
|
|
|
|
|
// Decide where in Header to put the END_TRY.
|
|
|
|
BeforeSet.clear();
|
|
|
|
AfterSet.clear();
|
2019-02-24 16:30:06 +08:00
|
|
|
for (const auto &MI : *Cont) {
|
2018-08-17 07:50:59 +08:00
|
|
|
#ifndef NDEBUG
|
2019-03-27 01:15:55 +08:00
|
|
|
// END_TRY should precede existing LOOP and BLOCK markers.
|
|
|
|
if (MI.getOpcode() == WebAssembly::LOOP ||
|
|
|
|
MI.getOpcode() == WebAssembly::BLOCK)
|
2018-08-17 07:50:59 +08:00
|
|
|
AfterSet.insert(&MI);
|
|
|
|
|
|
|
|
// All END_TRY markers placed earlier belong to exceptions that contains
|
|
|
|
// this one.
|
|
|
|
if (MI.getOpcode() == WebAssembly::END_TRY)
|
|
|
|
AfterSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// If there is a previously placed END_LOOP marker and its header is after
|
|
|
|
// where TRY marker is, this loop is contained within the 'catch' part, so
|
|
|
|
// the END_TRY marker should go after that. Otherwise, the whole try-catch
|
|
|
|
// is contained within this loop, so the END_TRY should go before that.
|
|
|
|
if (MI.getOpcode() == WebAssembly::END_LOOP) {
|
2019-03-27 01:29:55 +08:00
|
|
|
// For a LOOP to be after TRY, LOOP's BB should be after TRY's BB; if they
|
|
|
|
// are in the same BB, LOOP is always before TRY.
|
|
|
|
if (EndToBegin[&MI]->getParent()->getNumber() > Header->getNumber())
|
2018-08-17 07:50:59 +08:00
|
|
|
BeforeSet.insert(&MI);
|
|
|
|
#ifndef NDEBUG
|
|
|
|
else
|
|
|
|
AfterSet.insert(&MI);
|
|
|
|
#endif
|
|
|
|
}
|
2019-03-27 01:15:55 +08:00
|
|
|
|
|
|
|
// It is not possible for an END_BLOCK to be already in this block.
|
2018-08-17 07:50:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Mark the end of the TRY.
|
2019-02-24 16:30:06 +08:00
|
|
|
InsertPos = getEarliestInsertPos(Cont, BeforeSet, AfterSet);
|
2018-08-17 07:50:59 +08:00
|
|
|
MachineInstr *End =
|
2019-02-24 16:30:06 +08:00
|
|
|
BuildMI(*Cont, InsertPos, Bottom->findBranchDebugLoc(),
|
2018-08-17 07:50:59 +08:00
|
|
|
TII.get(WebAssembly::END_TRY));
|
|
|
|
registerTryScope(Begin, End, &MBB);
|
|
|
|
|
2019-02-27 09:35:14 +08:00
|
|
|
// Track the farthest-spanning scope that ends at this point. We create two
|
|
|
|
// mappings: (BB with 'end_try' -> BB with 'try') and (BB with 'catch' -> BB
|
|
|
|
// with 'try'). We need to create 'catch' -> 'try' mapping here too because
|
|
|
|
// markers should not span across 'catch'. For example, this should not
|
|
|
|
// happen:
|
|
|
|
//
|
|
|
|
// try
|
|
|
|
// block --| (X)
|
|
|
|
// catch |
|
|
|
|
// end_block --|
|
|
|
|
// end_try
|
|
|
|
for (int Number : {Cont->getNumber(), MBB.getNumber()}) {
|
|
|
|
if (!ScopeTops[Number] ||
|
|
|
|
ScopeTops[Number]->getNumber() > Header->getNumber())
|
|
|
|
ScopeTops[Number] = Header;
|
|
|
|
}
|
2018-08-17 07:50:59 +08:00
|
|
|
}
|
|
|
|
|
2019-02-27 08:50:53 +08:00
|
|
|
void WebAssemblyCFGStackify::removeUnnecessaryInstrs(MachineFunction &MF) {
|
|
|
|
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
|
|
|
|
|
|
|
|
// When there is an unconditional branch right before a catch instruction and
|
|
|
|
// it branches to the end of end_try marker, we don't need the branch, because
|
|
|
|
// it there is no exception, the control flow transfers to that point anyway.
|
|
|
|
// bb0:
|
|
|
|
// try
|
|
|
|
// ...
|
|
|
|
// br bb2 <- Not necessary
|
|
|
|
// bb1:
|
|
|
|
// catch
|
|
|
|
// ...
|
|
|
|
// bb2:
|
|
|
|
// end
|
|
|
|
for (auto &MBB : MF) {
|
|
|
|
if (!MBB.isEHPad())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
|
|
|
|
SmallVector<MachineOperand, 4> Cond;
|
2019-03-06 05:05:09 +08:00
|
|
|
MachineBasicBlock *EHPadLayoutPred = MBB.getPrevNode();
|
2019-02-27 08:50:53 +08:00
|
|
|
MachineBasicBlock *Cont = BeginToEnd[EHPadToTry[&MBB]]->getParent();
|
|
|
|
bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond);
|
|
|
|
if (Analyzable && ((Cond.empty() && TBB && TBB == Cont) ||
|
|
|
|
(!Cond.empty() && FBB && FBB == Cont)))
|
|
|
|
TII.removeBranch(*EHPadLayoutPred);
|
|
|
|
}
|
|
|
|
|
|
|
|
// When there are block / end_block markers that overlap with try / end_try
|
|
|
|
// markers, and the block and try markers' return types are the same, the
|
|
|
|
// block /end_block markers are not necessary, because try / end_try markers
|
|
|
|
// also can serve as boundaries for branches.
|
|
|
|
// block <- Not necessary
|
|
|
|
// try
|
|
|
|
// ...
|
|
|
|
// catch
|
|
|
|
// ...
|
|
|
|
// end
|
|
|
|
// end <- Not necessary
|
|
|
|
SmallVector<MachineInstr *, 32> ToDelete;
|
|
|
|
for (auto &MBB : MF) {
|
|
|
|
for (auto &MI : MBB) {
|
|
|
|
if (MI.getOpcode() != WebAssembly::TRY)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
MachineInstr *Try = &MI, *EndTry = BeginToEnd[Try];
|
|
|
|
MachineBasicBlock *TryBB = Try->getParent();
|
|
|
|
MachineBasicBlock *Cont = EndTry->getParent();
|
|
|
|
int64_t RetType = Try->getOperand(0).getImm();
|
2019-03-06 05:05:09 +08:00
|
|
|
for (auto B = Try->getIterator(), E = std::next(EndTry->getIterator());
|
2019-02-27 08:50:53 +08:00
|
|
|
B != TryBB->begin() && E != Cont->end() &&
|
|
|
|
std::prev(B)->getOpcode() == WebAssembly::BLOCK &&
|
|
|
|
E->getOpcode() == WebAssembly::END_BLOCK &&
|
|
|
|
std::prev(B)->getOperand(0).getImm() == RetType;
|
|
|
|
--B, ++E) {
|
|
|
|
ToDelete.push_back(&*std::prev(B));
|
|
|
|
ToDelete.push_back(&*E);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto *MI : ToDelete) {
|
|
|
|
if (MI->getOpcode() == WebAssembly::BLOCK)
|
|
|
|
unregisterScope(MI);
|
|
|
|
MI->eraseFromParent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-30 19:04:48 +08:00
|
|
|
bool WebAssemblyCFGStackify::fixUnwindMismatches(MachineFunction &MF) {
|
|
|
|
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
|
|
|
|
MachineRegisterInfo &MRI = MF.getRegInfo();
|
|
|
|
|
|
|
|
// Linearizing the control flow by placing TRY / END_TRY markers can create
|
|
|
|
// mismatches in unwind destinations. There are two kinds of mismatches we
|
|
|
|
// try to solve here.
|
|
|
|
|
|
|
|
// 1. When an instruction may throw, but the EH pad it will unwind to can be
|
|
|
|
// different from the original CFG.
|
|
|
|
//
|
|
|
|
// Example: we have the following CFG:
|
|
|
|
// bb0:
|
|
|
|
// call @foo (if it throws, unwind to bb2)
|
|
|
|
// bb1:
|
|
|
|
// call @bar (if it throws, unwind to bb3)
|
|
|
|
// bb2 (ehpad):
|
|
|
|
// catch
|
|
|
|
// ...
|
|
|
|
// bb3 (ehpad)
|
|
|
|
// catch
|
|
|
|
// handler body
|
|
|
|
//
|
|
|
|
// And the CFG is sorted in this order. Then after placing TRY markers, it
|
|
|
|
// will look like: (BB markers are omitted)
|
|
|
|
// try $label1
|
|
|
|
// try
|
|
|
|
// call @foo
|
|
|
|
// call @bar (if it throws, unwind to bb3)
|
|
|
|
// catch <- ehpad (bb2)
|
|
|
|
// ...
|
|
|
|
// end_try
|
|
|
|
// catch <- ehpad (bb3)
|
|
|
|
// handler body
|
|
|
|
// end_try
|
|
|
|
//
|
|
|
|
// Now if bar() throws, it is going to end up ip in bb2, not bb3, where it
|
|
|
|
// is supposed to end up. We solve this problem by
|
|
|
|
// a. Split the target unwind EH pad (here bb3) so that the handler body is
|
|
|
|
// right after 'end_try', which means we extract the handler body out of
|
|
|
|
// the catch block. We do this because this handler body should be
|
|
|
|
// somewhere branch-eable from the inner scope.
|
|
|
|
// b. Wrap the call that has an incorrect unwind destination ('call @bar'
|
|
|
|
// here) with a nested try/catch/end_try scope, and within the new catch
|
|
|
|
// block, branches to the handler body.
|
|
|
|
// c. Place a branch after the newly inserted nested end_try so it can bypass
|
|
|
|
// the handler body, which is now outside of a catch block.
|
|
|
|
//
|
|
|
|
// The result will like as follows. (new: a) means this instruction is newly
|
|
|
|
// created in the process of doing 'a' above.
|
|
|
|
//
|
|
|
|
// block $label0 (new: placeBlockMarker)
|
|
|
|
// try $label1
|
|
|
|
// try
|
|
|
|
// call @foo
|
|
|
|
// try (new: b)
|
|
|
|
// call @bar
|
|
|
|
// catch (new: b)
|
|
|
|
// local.set n / drop (new: b)
|
|
|
|
// br $label1 (new: b)
|
|
|
|
// end_try (new: b)
|
|
|
|
// catch <- ehpad (bb2)
|
|
|
|
// end_try
|
|
|
|
// br $label0 (new: c)
|
|
|
|
// catch <- ehpad (bb3)
|
|
|
|
// end_try (hoisted: a)
|
|
|
|
// handler body
|
|
|
|
// end_block (new: placeBlockMarker)
|
|
|
|
//
|
|
|
|
// Note that the new wrapping block/end_block will be generated later in
|
|
|
|
// placeBlockMarker.
|
|
|
|
//
|
2019-07-16 06:49:25 +08:00
|
|
|
// TODO Currently local.set and local.gets are generated to move exnref value
|
|
|
|
// created by catches. That's because we don't support yielding values from a
|
|
|
|
// block in LLVM machine IR yet, even though it is supported by wasm. Delete
|
|
|
|
// unnecessary local.get/local.sets once yielding values from a block is
|
|
|
|
// supported. The full EH spec requires multi-value support to do this, but
|
2019-03-30 19:04:48 +08:00
|
|
|
// for C++ we don't yet need it because we only throw a single i32.
|
|
|
|
//
|
|
|
|
// ---
|
|
|
|
// 2. The same as 1, but in this case an instruction unwinds to a caller
|
|
|
|
// function and not another EH pad.
|
|
|
|
//
|
|
|
|
// Example: we have the following CFG:
|
|
|
|
// bb0:
|
|
|
|
// call @foo (if it throws, unwind to bb2)
|
|
|
|
// bb1:
|
|
|
|
// call @bar (if it throws, unwind to caller)
|
|
|
|
// bb2 (ehpad):
|
|
|
|
// catch
|
|
|
|
// ...
|
|
|
|
//
|
|
|
|
// And the CFG is sorted in this order. Then after placing TRY markers, it
|
|
|
|
// will look like:
|
|
|
|
// try
|
|
|
|
// call @foo
|
|
|
|
// call @bar (if it throws, unwind to caller)
|
|
|
|
// catch <- ehpad (bb2)
|
|
|
|
// ...
|
|
|
|
// end_try
|
|
|
|
//
|
|
|
|
// Now if bar() throws, it is going to end up ip in bb2, when it is supposed
|
|
|
|
// throw up to the caller.
|
|
|
|
// We solve this problem by
|
|
|
|
// a. Create a new 'appendix' BB at the end of the function and put a single
|
|
|
|
// 'rethrow' instruction (+ local.get) in there.
|
|
|
|
// b. Wrap the call that has an incorrect unwind destination ('call @bar'
|
|
|
|
// here) with a nested try/catch/end_try scope, and within the new catch
|
|
|
|
// block, branches to the new appendix block.
|
|
|
|
//
|
|
|
|
// block $label0 (new: placeBlockMarker)
|
|
|
|
// try
|
|
|
|
// call @foo
|
|
|
|
// try (new: b)
|
|
|
|
// call @bar
|
|
|
|
// catch (new: b)
|
|
|
|
// local.set n (new: b)
|
|
|
|
// br $label0 (new: b)
|
|
|
|
// end_try (new: b)
|
|
|
|
// catch <- ehpad (bb2)
|
|
|
|
// ...
|
|
|
|
// end_try
|
|
|
|
// ...
|
|
|
|
// end_block (new: placeBlockMarker)
|
|
|
|
// local.get n (new: a) <- appendix block
|
|
|
|
// rethrow (new: a)
|
|
|
|
//
|
|
|
|
// In case there are multiple calls in a BB that may throw to the caller, they
|
|
|
|
// can be wrapped together in one nested try scope. (In 1, this couldn't
|
|
|
|
// happen, because may-throwing instruction there had an unwind destination,
|
|
|
|
// i.e., it was an invoke before, and there could be only one invoke within a
|
|
|
|
// BB.)
|
|
|
|
|
|
|
|
SmallVector<const MachineBasicBlock *, 8> EHPadStack;
|
|
|
|
// Range of intructions to be wrapped in a new nested try/catch
|
|
|
|
using TryRange = std::pair<MachineInstr *, MachineInstr *>;
|
|
|
|
// In original CFG, <unwind destionation BB, a vector of try ranges>
|
|
|
|
DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> UnwindDestToTryRanges;
|
|
|
|
// In new CFG, <destination to branch to, a vector of try ranges>
|
|
|
|
DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> BrDestToTryRanges;
|
2019-07-16 06:49:25 +08:00
|
|
|
// In new CFG, <destination to branch to, register containing exnref>
|
2019-03-30 19:04:48 +08:00
|
|
|
DenseMap<MachineBasicBlock *, unsigned> BrDestToExnReg;
|
|
|
|
|
|
|
|
// Gather possibly throwing calls (i.e., previously invokes) whose current
|
|
|
|
// unwind destination is not the same as the original CFG.
|
|
|
|
for (auto &MBB : reverse(MF)) {
|
|
|
|
bool SeenThrowableInstInBB = false;
|
|
|
|
for (auto &MI : reverse(MBB)) {
|
|
|
|
if (MI.getOpcode() == WebAssembly::TRY)
|
|
|
|
EHPadStack.pop_back();
|
|
|
|
else if (MI.getOpcode() == WebAssembly::CATCH)
|
|
|
|
EHPadStack.push_back(MI.getParent());
|
|
|
|
|
|
|
|
// In this loop we only gather calls that have an EH pad to unwind. So
|
|
|
|
// there will be at most 1 such call (= invoke) in a BB, so after we've
|
|
|
|
// seen one, we can skip the rest of BB. Also if MBB has no EH pad
|
|
|
|
// successor or MI does not throw, this is not an invoke.
|
|
|
|
if (SeenThrowableInstInBB || !MBB.hasEHPadSuccessor() ||
|
|
|
|
!WebAssembly::mayThrow(MI))
|
|
|
|
continue;
|
|
|
|
SeenThrowableInstInBB = true;
|
|
|
|
|
|
|
|
// If the EH pad on the stack top is where this instruction should unwind
|
|
|
|
// next, we're good.
|
|
|
|
MachineBasicBlock *UnwindDest = nullptr;
|
|
|
|
for (auto *Succ : MBB.successors()) {
|
|
|
|
if (Succ->isEHPad()) {
|
|
|
|
UnwindDest = Succ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (EHPadStack.back() == UnwindDest)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If not, record the range.
|
|
|
|
UnwindDestToTryRanges[UnwindDest].push_back(TryRange(&MI, &MI));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(EHPadStack.empty());
|
|
|
|
|
|
|
|
// Gather possibly throwing calls that are supposed to unwind up to the caller
|
|
|
|
// if they throw, but currently unwind to an incorrect destination. Unlike the
|
|
|
|
// loop above, there can be multiple calls within a BB that unwind to the
|
|
|
|
// caller, which we should group together in a range.
|
|
|
|
bool NeedAppendixBlock = false;
|
|
|
|
for (auto &MBB : reverse(MF)) {
|
|
|
|
MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr; // inclusive
|
|
|
|
for (auto &MI : reverse(MBB)) {
|
|
|
|
if (MI.getOpcode() == WebAssembly::TRY)
|
|
|
|
EHPadStack.pop_back();
|
|
|
|
else if (MI.getOpcode() == WebAssembly::CATCH)
|
|
|
|
EHPadStack.push_back(MI.getParent());
|
|
|
|
|
|
|
|
// If MBB has an EH pad successor, this inst does not unwind to caller.
|
|
|
|
if (MBB.hasEHPadSuccessor())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// We wrap up the current range when we see a marker even if we haven't
|
|
|
|
// finished a BB.
|
2019-07-13 06:08:25 +08:00
|
|
|
if (RangeEnd && WebAssembly::isMarker(MI.getOpcode())) {
|
2019-03-30 19:04:48 +08:00
|
|
|
NeedAppendixBlock = true;
|
|
|
|
// Record the range. nullptr here means the unwind destination is the
|
|
|
|
// caller.
|
|
|
|
UnwindDestToTryRanges[nullptr].push_back(
|
|
|
|
TryRange(RangeBegin, RangeEnd));
|
|
|
|
RangeBegin = RangeEnd = nullptr; // Reset range pointers
|
|
|
|
}
|
|
|
|
|
|
|
|
// If EHPadStack is empty, that means it is correctly unwind to caller if
|
|
|
|
// it throws, so we're good. If MI does not throw, we're good too.
|
|
|
|
if (EHPadStack.empty() || !WebAssembly::mayThrow(MI))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// We found an instruction that unwinds to the caller but currently has an
|
|
|
|
// incorrect unwind destination. Create a new range or increment the
|
|
|
|
// currently existing range.
|
|
|
|
if (!RangeEnd)
|
|
|
|
RangeBegin = RangeEnd = &MI;
|
|
|
|
else
|
|
|
|
RangeBegin = &MI;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RangeEnd) {
|
|
|
|
NeedAppendixBlock = true;
|
|
|
|
// Record the range. nullptr here means the unwind destination is the
|
|
|
|
// caller.
|
|
|
|
UnwindDestToTryRanges[nullptr].push_back(TryRange(RangeBegin, RangeEnd));
|
|
|
|
RangeBegin = RangeEnd = nullptr; // Reset range pointers
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(EHPadStack.empty());
|
|
|
|
// We don't have any unwind destination mismatches to resolve.
|
|
|
|
if (UnwindDestToTryRanges.empty())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// If we found instructions that should unwind to the caller but currently
|
|
|
|
// have incorrect unwind destination, we create an appendix block at the end
|
|
|
|
// of the function with a local.get and a rethrow instruction.
|
|
|
|
if (NeedAppendixBlock) {
|
|
|
|
auto *AppendixBB = getAppendixBlock(MF);
|
[webassembly] Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Reviewers: aheejin
Subscribers: jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision for whole review: https://reviews.llvm.org/D65962
llvm-svn: 368627
2019-08-13 06:40:45 +08:00
|
|
|
Register ExnReg = MRI.createVirtualRegister(&WebAssembly::EXNREFRegClass);
|
2019-03-30 19:04:48 +08:00
|
|
|
BuildMI(AppendixBB, DebugLoc(), TII.get(WebAssembly::RETHROW))
|
|
|
|
.addReg(ExnReg);
|
|
|
|
// These instruction ranges should branch to this appendix BB.
|
|
|
|
for (auto Range : UnwindDestToTryRanges[nullptr])
|
|
|
|
BrDestToTryRanges[AppendixBB].push_back(Range);
|
|
|
|
BrDestToExnReg[AppendixBB] = ExnReg;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We loop through unwind destination EH pads that are targeted from some
|
|
|
|
// inner scopes. Because these EH pads are destination of more than one scope
|
|
|
|
// now, we split them so that the handler body is after 'end_try'.
|
|
|
|
// - Before
|
|
|
|
// ehpad:
|
|
|
|
// catch
|
|
|
|
// local.set n / drop
|
|
|
|
// handler body
|
|
|
|
// ...
|
|
|
|
// cont:
|
|
|
|
// end_try
|
|
|
|
//
|
|
|
|
// - After
|
|
|
|
// ehpad:
|
|
|
|
// catch
|
|
|
|
// local.set n / drop
|
|
|
|
// brdest: (new)
|
|
|
|
// end_try (hoisted from 'cont' BB)
|
|
|
|
// handler body (taken from 'ehpad')
|
|
|
|
// ...
|
|
|
|
// cont:
|
|
|
|
for (auto &P : UnwindDestToTryRanges) {
|
|
|
|
NumUnwindMismatches++;
|
|
|
|
|
|
|
|
// This means the destination is the appendix BB, which was separately
|
|
|
|
// handled above.
|
|
|
|
if (!P.first)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
MachineBasicBlock *EHPad = P.first;
|
|
|
|
|
|
|
|
// Find 'catch' and 'local.set' or 'drop' instruction that follows the
|
|
|
|
// 'catch'. If -wasm-disable-explicit-locals is not set, 'catch' should be
|
|
|
|
// always followed by either 'local.set' or a 'drop', because 'br_on_exn' is
|
|
|
|
// generated after 'catch' in LateEHPrepare and we don't support blocks
|
|
|
|
// taking values yet.
|
|
|
|
MachineInstr *Catch = nullptr;
|
|
|
|
unsigned ExnReg = 0;
|
|
|
|
for (auto &MI : *EHPad) {
|
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
case WebAssembly::CATCH:
|
|
|
|
Catch = &MI;
|
|
|
|
ExnReg = Catch->getOperand(0).getReg();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(Catch && "EH pad does not have a catch");
|
|
|
|
assert(ExnReg != 0 && "Invalid register");
|
|
|
|
|
|
|
|
auto SplitPos = std::next(Catch->getIterator());
|
|
|
|
|
|
|
|
// Create a new BB that's gonna be the destination for branches from the
|
|
|
|
// inner mismatched scope.
|
|
|
|
MachineInstr *BeginTry = EHPadToTry[EHPad];
|
|
|
|
MachineInstr *EndTry = BeginToEnd[BeginTry];
|
|
|
|
MachineBasicBlock *Cont = EndTry->getParent();
|
|
|
|
auto *BrDest = MF.CreateMachineBasicBlock();
|
|
|
|
MF.insert(std::next(EHPad->getIterator()), BrDest);
|
|
|
|
// Hoist up the existing 'end_try'.
|
|
|
|
BrDest->insert(BrDest->end(), EndTry->removeFromParent());
|
|
|
|
// Take out the handler body from EH pad to the new branch destination BB.
|
|
|
|
BrDest->splice(BrDest->end(), EHPad, SplitPos, EHPad->end());
|
|
|
|
// Fix predecessor-successor relationship.
|
|
|
|
BrDest->transferSuccessors(EHPad);
|
|
|
|
EHPad->addSuccessor(BrDest);
|
|
|
|
|
|
|
|
// All try ranges that were supposed to unwind to this EH pad now have to
|
|
|
|
// branch to this new branch dest BB.
|
|
|
|
for (auto Range : UnwindDestToTryRanges[EHPad])
|
|
|
|
BrDestToTryRanges[BrDest].push_back(Range);
|
|
|
|
BrDestToExnReg[BrDest] = ExnReg;
|
|
|
|
|
|
|
|
// In case we fall through to the continuation BB after the catch block, we
|
|
|
|
// now have to add a branch to it.
|
|
|
|
// - Before
|
|
|
|
// try
|
|
|
|
// ...
|
|
|
|
// (falls through to 'cont')
|
|
|
|
// catch
|
|
|
|
// handler body
|
|
|
|
// end
|
|
|
|
// <-- cont
|
|
|
|
//
|
|
|
|
// - After
|
|
|
|
// try
|
|
|
|
// ...
|
|
|
|
// br %cont (new)
|
|
|
|
// catch
|
|
|
|
// end
|
|
|
|
// handler body
|
|
|
|
// <-- cont
|
|
|
|
MachineBasicBlock *EHPadLayoutPred = &*std::prev(EHPad->getIterator());
|
|
|
|
MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
|
|
|
|
SmallVector<MachineOperand, 4> Cond;
|
|
|
|
bool Analyzable = !TII.analyzeBranch(*EHPadLayoutPred, TBB, FBB, Cond);
|
|
|
|
if (Analyzable && !TBB && !FBB) {
|
|
|
|
DebugLoc DL = EHPadLayoutPred->empty()
|
|
|
|
? DebugLoc()
|
|
|
|
: EHPadLayoutPred->rbegin()->getDebugLoc();
|
|
|
|
BuildMI(EHPadLayoutPred, DL, TII.get(WebAssembly::BR)).addMBB(Cont);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// For possibly throwing calls whose unwind destinations are currently
|
|
|
|
// incorrect because of CFG linearization, we wrap them with a nested
|
|
|
|
// try/catch/end_try, and within the new catch block, we branch to the correct
|
|
|
|
// handler.
|
|
|
|
// - Before
|
|
|
|
// mbb:
|
|
|
|
// call @foo <- Unwind destination mismatch!
|
|
|
|
// ehpad:
|
|
|
|
// ...
|
|
|
|
//
|
|
|
|
// - After
|
|
|
|
// mbb:
|
|
|
|
// try (new)
|
|
|
|
// call @foo
|
|
|
|
// nested-ehpad: (new)
|
|
|
|
// catch (new)
|
|
|
|
// local.set n / drop (new)
|
|
|
|
// br %brdest (new)
|
|
|
|
// nested-end: (new)
|
|
|
|
// end_try (new)
|
|
|
|
// ehpad:
|
|
|
|
// ...
|
|
|
|
for (auto &P : BrDestToTryRanges) {
|
|
|
|
MachineBasicBlock *BrDest = P.first;
|
|
|
|
auto &TryRanges = P.second;
|
|
|
|
unsigned ExnReg = BrDestToExnReg[BrDest];
|
|
|
|
|
|
|
|
for (auto Range : TryRanges) {
|
|
|
|
MachineInstr *RangeBegin = nullptr, *RangeEnd = nullptr;
|
|
|
|
std::tie(RangeBegin, RangeEnd) = Range;
|
|
|
|
auto *MBB = RangeBegin->getParent();
|
|
|
|
|
|
|
|
// Include possible EH_LABELs in the range
|
|
|
|
if (RangeBegin->getIterator() != MBB->begin() &&
|
|
|
|
std::prev(RangeBegin->getIterator())->isEHLabel())
|
|
|
|
RangeBegin = &*std::prev(RangeBegin->getIterator());
|
|
|
|
if (std::next(RangeEnd->getIterator()) != MBB->end() &&
|
|
|
|
std::next(RangeEnd->getIterator())->isEHLabel())
|
|
|
|
RangeEnd = &*std::next(RangeEnd->getIterator());
|
|
|
|
|
|
|
|
MachineBasicBlock *EHPad = nullptr;
|
|
|
|
for (auto *Succ : MBB->successors()) {
|
|
|
|
if (Succ->isEHPad()) {
|
|
|
|
EHPad = Succ;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the nested try instruction.
|
|
|
|
MachineInstr *NestedTry =
|
|
|
|
BuildMI(*MBB, *RangeBegin, RangeBegin->getDebugLoc(),
|
|
|
|
TII.get(WebAssembly::TRY))
|
|
|
|
.addImm(int64_t(WebAssembly::ExprType::Void));
|
|
|
|
|
|
|
|
// Create the nested EH pad and fill instructions in.
|
|
|
|
MachineBasicBlock *NestedEHPad = MF.CreateMachineBasicBlock();
|
|
|
|
MF.insert(std::next(MBB->getIterator()), NestedEHPad);
|
|
|
|
NestedEHPad->setIsEHPad();
|
|
|
|
NestedEHPad->setIsEHScopeEntry();
|
|
|
|
BuildMI(NestedEHPad, RangeEnd->getDebugLoc(), TII.get(WebAssembly::CATCH),
|
|
|
|
ExnReg);
|
|
|
|
BuildMI(NestedEHPad, RangeEnd->getDebugLoc(), TII.get(WebAssembly::BR))
|
|
|
|
.addMBB(BrDest);
|
|
|
|
|
|
|
|
// Create the nested continuation BB and end_try instruction.
|
|
|
|
MachineBasicBlock *NestedCont = MF.CreateMachineBasicBlock();
|
|
|
|
MF.insert(std::next(NestedEHPad->getIterator()), NestedCont);
|
|
|
|
MachineInstr *NestedEndTry =
|
|
|
|
BuildMI(*NestedCont, NestedCont->begin(), RangeEnd->getDebugLoc(),
|
|
|
|
TII.get(WebAssembly::END_TRY));
|
|
|
|
// In case MBB has more instructions after the try range, move them to the
|
|
|
|
// new nested continuation BB.
|
|
|
|
NestedCont->splice(NestedCont->end(), MBB,
|
|
|
|
std::next(RangeEnd->getIterator()), MBB->end());
|
|
|
|
registerTryScope(NestedTry, NestedEndTry, NestedEHPad);
|
|
|
|
|
|
|
|
// Fix predecessor-successor relationship.
|
|
|
|
NestedCont->transferSuccessors(MBB);
|
|
|
|
if (EHPad)
|
|
|
|
NestedCont->removeSuccessor(EHPad);
|
|
|
|
MBB->addSuccessor(NestedEHPad);
|
|
|
|
MBB->addSuccessor(NestedCont);
|
|
|
|
NestedEHPad->addSuccessor(BrDest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Renumber BBs and recalculate ScopeTop info because new BBs might have been
|
|
|
|
// created and inserted above.
|
|
|
|
MF.RenumberBlocks();
|
|
|
|
ScopeTops.clear();
|
|
|
|
ScopeTops.resize(MF.getNumBlockIDs());
|
|
|
|
for (auto &MBB : reverse(MF)) {
|
|
|
|
for (auto &MI : reverse(MBB)) {
|
|
|
|
if (ScopeTops[MBB.getNumber()])
|
|
|
|
break;
|
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
case WebAssembly::END_BLOCK:
|
|
|
|
case WebAssembly::END_LOOP:
|
|
|
|
case WebAssembly::END_TRY:
|
|
|
|
ScopeTops[MBB.getNumber()] = EndToBegin[&MI]->getParent();
|
|
|
|
break;
|
|
|
|
case WebAssembly::CATCH:
|
|
|
|
ScopeTops[MBB.getNumber()] = EHPadToTry[&MBB]->getParent();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Recompute the dominator tree.
|
|
|
|
getAnalysis<MachineDominatorTree>().runOnMachineFunction(MF);
|
|
|
|
|
|
|
|
// Place block markers for newly added branches.
|
|
|
|
SmallVector <MachineBasicBlock *, 8> BrDests;
|
|
|
|
for (auto &P : BrDestToTryRanges)
|
|
|
|
BrDests.push_back(P.first);
|
|
|
|
llvm::sort(BrDests,
|
|
|
|
[&](const MachineBasicBlock *A, const MachineBasicBlock *B) {
|
|
|
|
auto ANum = A->getNumber();
|
|
|
|
auto BNum = B->getNumber();
|
|
|
|
return ANum < BNum;
|
|
|
|
});
|
|
|
|
for (auto *Dest : BrDests)
|
|
|
|
placeBlockMarker(*Dest);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
static unsigned
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
getDepth(const SmallVectorImpl<const MachineBasicBlock *> &Stack,
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
const MachineBasicBlock *MBB) {
|
|
|
|
unsigned Depth = 0;
|
|
|
|
for (auto X : reverse(Stack)) {
|
|
|
|
if (X == MBB)
|
|
|
|
break;
|
|
|
|
++Depth;
|
|
|
|
}
|
|
|
|
assert(Depth < Stack.size() && "Branch destination should be in scope");
|
|
|
|
return Depth;
|
|
|
|
}
|
|
|
|
|
2016-10-07 06:29:32 +08:00
|
|
|
/// In normal assembly languages, when the end of a function is unreachable,
|
|
|
|
/// because the function ends in an infinite loop or a noreturn call or similar,
|
|
|
|
/// it isn't necessary to worry about the function return type at the end of
|
|
|
|
/// the function, because it's never reached. However, in WebAssembly, blocks
|
|
|
|
/// that end at the function end need to have a return type signature that
|
|
|
|
/// matches the function signature, even though it's unreachable. This function
|
|
|
|
/// checks for such cases and fixes up the signatures.
|
2018-08-17 07:50:59 +08:00
|
|
|
void WebAssemblyCFGStackify::fixEndsAtEndOfFunction(MachineFunction &MF) {
|
|
|
|
const auto &MFI = *MF.getInfo<WebAssemblyFunctionInfo>();
|
2016-10-07 06:29:32 +08:00
|
|
|
assert(MFI.getResults().size() <= 1);
|
|
|
|
|
|
|
|
if (MFI.getResults().empty())
|
|
|
|
return;
|
|
|
|
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
WebAssembly::ExprType RetType;
|
2016-10-07 06:29:32 +08:00
|
|
|
switch (MFI.getResults().front().SimpleTy) {
|
2018-09-05 09:27:38 +08:00
|
|
|
case MVT::i32:
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
RetType = WebAssembly::ExprType::I32;
|
2018-09-05 09:27:38 +08:00
|
|
|
break;
|
|
|
|
case MVT::i64:
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
RetType = WebAssembly::ExprType::I64;
|
2018-09-05 09:27:38 +08:00
|
|
|
break;
|
|
|
|
case MVT::f32:
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
RetType = WebAssembly::ExprType::F32;
|
2018-09-05 09:27:38 +08:00
|
|
|
break;
|
|
|
|
case MVT::f64:
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
RetType = WebAssembly::ExprType::F64;
|
2018-09-05 09:27:38 +08:00
|
|
|
break;
|
2018-08-07 07:16:50 +08:00
|
|
|
case MVT::v16i8:
|
|
|
|
case MVT::v8i16:
|
|
|
|
case MVT::v4i32:
|
2018-08-08 05:24:01 +08:00
|
|
|
case MVT::v2i64:
|
2018-08-07 07:16:50 +08:00
|
|
|
case MVT::v4f32:
|
2018-08-08 05:24:01 +08:00
|
|
|
case MVT::v2f64:
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
RetType = WebAssembly::ExprType::V128;
|
2018-08-07 07:16:50 +08:00
|
|
|
break;
|
2019-07-16 06:49:25 +08:00
|
|
|
case MVT::exnref:
|
|
|
|
RetType = WebAssembly::ExprType::Exnref;
|
2018-09-05 09:27:38 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unexpected return type");
|
2016-10-07 06:29:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (MachineBasicBlock &MBB : reverse(MF)) {
|
|
|
|
for (MachineInstr &MI : reverse(MBB)) {
|
2018-05-09 10:42:00 +08:00
|
|
|
if (MI.isPosition() || MI.isDebugInstr())
|
2016-10-07 06:29:32 +08:00
|
|
|
continue;
|
|
|
|
if (MI.getOpcode() == WebAssembly::END_BLOCK) {
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType));
|
2016-10-07 06:29:32 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (MI.getOpcode() == WebAssembly::END_LOOP) {
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
EndToBegin[&MI]->getOperand(0).setImm(int32_t(RetType));
|
2016-10-07 06:29:32 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Something other than an `end`. We're done.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-25 07:18:00 +08:00
|
|
|
// WebAssembly functions end with an end instruction, as if the function body
|
|
|
|
// were a block.
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
static void appendEndToFunction(MachineFunction &MF,
|
2018-09-05 09:27:38 +08:00
|
|
|
const WebAssemblyInstrInfo &TII) {
|
2018-03-16 06:06:51 +08:00
|
|
|
BuildMI(MF.back(), MF.back().end(),
|
|
|
|
MF.back().findPrevDebugLoc(MF.back().end()),
|
2017-02-25 07:18:00 +08:00
|
|
|
TII.get(WebAssembly::END_FUNCTION));
|
|
|
|
}
|
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
/// Insert LOOP/TRY/BLOCK markers at appropriate places.
|
|
|
|
void WebAssemblyCFGStackify::placeMarkers(MachineFunction &MF) {
|
|
|
|
// We allocate one more than the number of blocks in the function to
|
|
|
|
// accommodate for the possible fake block we may insert at the end.
|
|
|
|
ScopeTops.resize(MF.getNumBlockIDs() + 1);
|
|
|
|
// Place the LOOP for MBB if MBB is the header of a loop.
|
|
|
|
for (auto &MBB : MF)
|
|
|
|
placeLoopMarker(MBB);
|
2019-03-27 01:15:55 +08:00
|
|
|
|
[WebAssembly] Exception handling: Switch to the new proposal
Summary:
This switches the EH implementation to the new proposal:
https://github.com/WebAssembly/exception-handling/blob/master/proposals/Exceptions.md
(The previous proposal was
https://github.com/WebAssembly/exception-handling/blob/master/proposals/old/Exceptions.md)
- Instruction changes
- Now we have one single `catch` instruction that returns a except_ref
value
- `throw` now can take variable number of operations
- `rethrow` does not have 'depth' argument anymore
- `br_on_exn` queries an except_ref to see if it matches the tag and
branches to the given label if true.
- `extract_exception` is a pseudo instruction that simulates popping
values from wasm stack. This is to make `br_on_exn`, a very special
instruction, work: `br_on_exn` puts values onto the stack only if it
is taken, and the # of values can vay depending on the tag.
- Now there's only one `catch` per `try`, this patch removes all special
handling for terminate pad with a call to `__clang_call_terminate`.
Before it was the only case there are two catch clauses (a normal
`catch` and `catch_all` per `try`).
- Make `rethrow` act as a terminator like `throw`. This splits BB after
`rethrow` in WasmEHPrepare, and deletes an unnecessary `unreachable`
after `rethrow` in LateEHPrepare.
- Now we stop at all catchpads (because we add wasm `catch` instruction
that catches all exceptions), this creates new
`findWasmUnwindDestinations` function in SelectionDAGBuilder.
- Now we use `br_on_exn` instrution to figure out if an except_ref
matches the current tag or not, LateEHPrepare generates this sequence
for catch pads:
```
catch
block i32
br_on_exn $__cpp_exception
end_block
extract_exception
```
- Branch analysis for `br_on_exn` in WebAssemblyInstrInfo
- Other various misc. changes to switch to the new proposal.
Reviewers: dschuff
Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits
Differential Revision: https://reviews.llvm.org/D57134
llvm-svn: 352598
2019-01-30 11:21:57 +08:00
|
|
|
const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
|
2019-03-27 01:15:55 +08:00
|
|
|
for (auto &MBB : MF) {
|
|
|
|
if (MBB.isEHPad()) {
|
|
|
|
// Place the TRY for MBB if MBB is the EH pad of an exception.
|
|
|
|
if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
|
|
|
|
MF.getFunction().hasPersonalityFn())
|
|
|
|
placeTryMarker(MBB);
|
|
|
|
} else {
|
|
|
|
// Place the BLOCK for MBB if MBB is branched to from above.
|
|
|
|
placeBlockMarker(MBB);
|
|
|
|
}
|
|
|
|
}
|
2019-03-30 19:04:48 +08:00
|
|
|
// Fix mismatches in unwind destinations induced by linearizing the code.
|
|
|
|
fixUnwindMismatches(MF);
|
2018-08-17 07:50:59 +08:00
|
|
|
}
|
2015-09-17 00:51:30 +08:00
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
// Now rewrite references to basic blocks to be depth immediates.
|
|
|
|
SmallVector<const MachineBasicBlock *, 8> Stack;
|
|
|
|
for (auto &MBB : reverse(MF)) {
|
2018-08-17 07:50:59 +08:00
|
|
|
for (auto I = MBB.rbegin(), E = MBB.rend(); I != E; ++I) {
|
|
|
|
MachineInstr &MI = *I;
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
case WebAssembly::BLOCK:
|
2018-08-17 07:50:59 +08:00
|
|
|
case WebAssembly::TRY:
|
|
|
|
assert(ScopeTops[Stack.back()->getNumber()]->getNumber() <=
|
|
|
|
MBB.getNumber() &&
|
|
|
|
"Block/try marker should be balanced");
|
|
|
|
Stack.pop_back();
|
|
|
|
break;
|
|
|
|
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
case WebAssembly::LOOP:
|
|
|
|
assert(Stack.back() == &MBB && "Loop top should be balanced");
|
|
|
|
Stack.pop_back();
|
|
|
|
break;
|
2018-08-17 07:50:59 +08:00
|
|
|
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
case WebAssembly::END_BLOCK:
|
2018-08-17 07:50:59 +08:00
|
|
|
case WebAssembly::END_TRY:
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
Stack.push_back(&MBB);
|
|
|
|
break;
|
2018-08-17 07:50:59 +08:00
|
|
|
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
case WebAssembly::END_LOOP:
|
2018-08-17 07:50:59 +08:00
|
|
|
Stack.push_back(EndToBegin[&MI]->getParent());
|
|
|
|
break;
|
|
|
|
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
default:
|
|
|
|
if (MI.isTerminator()) {
|
|
|
|
// Rewrite MBB operands to be depth immediates.
|
|
|
|
SmallVector<MachineOperand, 4> Ops(MI.operands());
|
|
|
|
while (MI.getNumOperands() > 0)
|
|
|
|
MI.RemoveOperand(MI.getNumOperands() - 1);
|
|
|
|
for (auto MO : Ops) {
|
|
|
|
if (MO.isMBB())
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
MO = MachineOperand::CreateImm(getDepth(Stack, MO.getMBB()));
|
[WebAssembly] Make CFG stackification independent of basic-block labels.
This patch changes the way labels are referenced. Instead of referencing the
basic-block label name (eg. .LBB0_0), instructions now just have an immediate
which indicates the depth in the control-flow stack to find a label to jump to.
This makes them much closer to what we expect to have in the binary encoding,
and avoids the problem of basic-block label names not being explicit in the
binary encoding.
Also, it terminates blocks and loops with end_block and end_loop instructions,
rather than basic-block label names, for similar reasons.
This will also fix problems where two constructs appear to have the same label,
because we no longer explicitly use labels, so consumers that need labels will
presumably create their own labels, and presumably they won't reuse labels
when they do.
This patch does make the code a little more awkward to read; as a partial
mitigation, this patch also introduces comments showing where the labels are,
and comments on each branch showing where it's branching to.
llvm-svn: 257505
2016-01-13 03:14:46 +08:00
|
|
|
MI.addOperand(MF, MO);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(Stack.empty() && "Control flow should be balanced");
|
2018-08-17 07:50:59 +08:00
|
|
|
}
|
2016-10-07 06:29:32 +08:00
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
void WebAssemblyCFGStackify::releaseMemory() {
|
|
|
|
ScopeTops.clear();
|
|
|
|
BeginToEnd.clear();
|
|
|
|
EndToBegin.clear();
|
|
|
|
TryToEHPad.clear();
|
|
|
|
EHPadToTry.clear();
|
2019-03-30 19:04:48 +08:00
|
|
|
AppendixBB = nullptr;
|
2015-11-24 00:19:56 +08:00
|
|
|
}
|
|
|
|
|
2015-09-17 00:51:30 +08:00
|
|
|
bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n"
|
|
|
|
"********** Function: "
|
|
|
|
<< MF.getName() << '\n');
|
2019-02-27 08:50:53 +08:00
|
|
|
const MCAsmInfo *MCAI = MF.getTarget().getMCAsmInfo();
|
2015-09-17 00:51:30 +08:00
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
releaseMemory();
|
|
|
|
|
2016-10-04 06:43:53 +08:00
|
|
|
// Liveness is not tracked for VALUE_STACK physreg.
|
2016-01-14 01:10:28 +08:00
|
|
|
MF.getRegInfo().invalidateLiveness();
|
2015-09-17 00:51:30 +08:00
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
// Place the BLOCK/LOOP/TRY markers to indicate the beginnings of scopes.
|
|
|
|
placeMarkers(MF);
|
|
|
|
|
2019-03-30 19:04:48 +08:00
|
|
|
// Remove unnecessary instructions possibly introduced by try/end_trys.
|
2019-02-27 08:50:53 +08:00
|
|
|
if (MCAI->getExceptionHandlingType() == ExceptionHandling::Wasm &&
|
|
|
|
MF.getFunction().hasPersonalityFn())
|
|
|
|
removeUnnecessaryInstrs(MF);
|
|
|
|
|
2018-08-17 07:50:59 +08:00
|
|
|
// Convert MBB operands in terminators to relative depth immediates.
|
|
|
|
rewriteDepthImmediates(MF);
|
|
|
|
|
|
|
|
// Fix up block/loop/try signatures at the end of the function to conform to
|
|
|
|
// WebAssembly's rules.
|
|
|
|
fixEndsAtEndOfFunction(MF);
|
|
|
|
|
|
|
|
// Add an end instruction at the end of the function body.
|
|
|
|
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
|
|
|
|
if (!MF.getSubtarget<WebAssemblySubtarget>()
|
|
|
|
.getTargetTriple()
|
|
|
|
.isOSBinFormatELF())
|
[WebAssembly] clang-tidy (NFC)
Summary:
This patch fixes clang-tidy warnings on wasm-only files.
The list of checks used is:
`-*,clang-diagnostic-*,llvm-*,misc-*,-misc-unused-parameters,readability-identifier-naming,modernize-*`
(LLVM's default .clang-tidy list is the same except it does not have
`modernize-*`. But I've seen in multiple CLs in LLVM the modernize style
was recommended and code was fixed based on the style, so I added it as
well.)
The common fixes are:
- Variable names start with an uppercase letter
- Function names start with a lowercase letter
- Use `auto` when you use casts so the type is evident
- Use inline initialization for class member variables
- Use `= default` for empty constructors / destructors
- Use `using` in place of `typedef`
Reviewers: sbc100, tlively, aardappel
Subscribers: dschuff, sunfish, jgravelle-google, yurydelendik, kripken, MatzeB, mgorny, rupprecht, llvm-commits
Differential Revision: https://reviews.llvm.org/D57500
llvm-svn: 353075
2019-02-05 03:13:39 +08:00
|
|
|
appendEndToFunction(MF, TII);
|
2015-11-24 00:19:56 +08:00
|
|
|
|
2019-03-27 01:46:14 +08:00
|
|
|
MF.getInfo<WebAssemblyFunctionInfo>()->setCFGStackified();
|
2015-09-17 00:51:30 +08:00
|
|
|
return true;
|
|
|
|
}
|