forked from OSchip/llvm-project
[WebAssembly] Update InstPrinter support for EH
- Updates InstPrinter to handle `catch_all`. - Makes `rethrow` condition an early exit from the function to make the rest simpler. - Unify label and catch counters. They don't need to be counted separately and this will help `delegate` instruction later. - Removes `LastSeenEHInst` field. This was first introduced to handle when there are more than one `catch` blocks per `try`, but this was not implemented correctly and not being used at the moment anyway. - Reenables all tests in cfg-stackify-eh.ll that don't deal with unwind destination mismatches, which will be handled in a later CL. Reviewed By: dschuff, tlively, aardappel Differential Revision: https://reviews.llvm.org/D94043
This commit is contained in:
parent
bb0e621387
commit
0d8dfbb42a
|
@ -94,19 +94,18 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
|||
case WebAssembly::LOOP_S:
|
||||
printAnnotation(OS, "label" + utostr(ControlFlowCounter) + ':');
|
||||
ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, true));
|
||||
break;
|
||||
return;
|
||||
|
||||
case WebAssembly::BLOCK:
|
||||
case WebAssembly::BLOCK_S:
|
||||
ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
|
||||
break;
|
||||
return;
|
||||
|
||||
case WebAssembly::TRY:
|
||||
case WebAssembly::TRY_S:
|
||||
ControlFlowStack.push_back(std::make_pair(ControlFlowCounter++, false));
|
||||
EHPadStack.push_back(EHPadStackCounter++);
|
||||
LastSeenEHInst = TRY;
|
||||
break;
|
||||
ControlFlowStack.push_back(std::make_pair(ControlFlowCounter, false));
|
||||
EHPadStack.push_back(ControlFlowCounter++);
|
||||
return;
|
||||
|
||||
case WebAssembly::END_LOOP:
|
||||
case WebAssembly::END_LOOP_S:
|
||||
|
@ -115,7 +114,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
|||
} else {
|
||||
ControlFlowStack.pop_back();
|
||||
}
|
||||
break;
|
||||
return;
|
||||
|
||||
case WebAssembly::END_BLOCK:
|
||||
case WebAssembly::END_BLOCK_S:
|
||||
|
@ -125,7 +124,7 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
|||
printAnnotation(
|
||||
OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
|
||||
}
|
||||
break;
|
||||
return;
|
||||
|
||||
case WebAssembly::END_TRY:
|
||||
case WebAssembly::END_TRY_S:
|
||||
|
@ -134,60 +133,60 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
|
|||
} else {
|
||||
printAnnotation(
|
||||
OS, "label" + utostr(ControlFlowStack.pop_back_val().first) + ':');
|
||||
LastSeenEHInst = END_TRY;
|
||||
}
|
||||
break;
|
||||
return;
|
||||
|
||||
case WebAssembly::CATCH:
|
||||
case WebAssembly::CATCH_S:
|
||||
case WebAssembly::CATCH_ALL:
|
||||
case WebAssembly::CATCH_ALL_S:
|
||||
if (EHPadStack.empty()) {
|
||||
printAnnotation(OS, "try-catch mismatch!");
|
||||
} else {
|
||||
printAnnotation(OS, "catch" + utostr(EHPadStack.pop_back_val()) + ':');
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
|
||||
// Annotate any control flow label references.
|
||||
|
||||
// rethrow instruction does not take any depth argument and rethrows to the
|
||||
// nearest enclosing catch scope, if any. If there's no enclosing catch
|
||||
// scope, it throws up to the caller.
|
||||
if (Opc == WebAssembly::RETHROW || Opc == WebAssembly::RETHROW_S) {
|
||||
case WebAssembly::RETHROW:
|
||||
case WebAssembly::RETHROW_S:
|
||||
// 'rethrow' rethrows to the nearest enclosing catch scope, if any. If
|
||||
// there's no enclosing catch scope, it throws up to the caller.
|
||||
if (EHPadStack.empty()) {
|
||||
printAnnotation(OS, "to caller");
|
||||
} else {
|
||||
printAnnotation(OS, "down to catch" + utostr(EHPadStack.back()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
unsigned NumFixedOperands = Desc.NumOperands;
|
||||
SmallSet<uint64_t, 8> Printed;
|
||||
for (unsigned I = 0, E = MI->getNumOperands(); I < E; ++I) {
|
||||
// See if this operand denotes a basic block target.
|
||||
if (I < NumFixedOperands) {
|
||||
// A non-variable_ops operand, check its type.
|
||||
if (Desc.OpInfo[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
|
||||
continue;
|
||||
} else {
|
||||
// A variable_ops operand, which currently can be immediates (used in
|
||||
// br_table) which are basic block targets, or for call instructions
|
||||
// when using -wasm-keep-registers (in which case they are registers,
|
||||
// and should not be processed).
|
||||
if (!MI->getOperand(I).isImm())
|
||||
continue;
|
||||
}
|
||||
uint64_t Depth = MI->getOperand(I).getImm();
|
||||
if (!Printed.insert(Depth).second)
|
||||
// Annotate any control flow label references.
|
||||
|
||||
unsigned NumFixedOperands = Desc.NumOperands;
|
||||
SmallSet<uint64_t, 8> Printed;
|
||||
for (unsigned I = 0, E = MI->getNumOperands(); I < E; ++I) {
|
||||
// See if this operand denotes a basic block target.
|
||||
if (I < NumFixedOperands) {
|
||||
// A non-variable_ops operand, check its type.
|
||||
if (Desc.OpInfo[I].OperandType != WebAssembly::OPERAND_BASIC_BLOCK)
|
||||
continue;
|
||||
if (Depth >= ControlFlowStack.size()) {
|
||||
printAnnotation(OS, "Invalid depth argument!");
|
||||
} else {
|
||||
const auto &Pair = ControlFlowStack.rbegin()[Depth];
|
||||
printAnnotation(OS, utostr(Depth) + ": " +
|
||||
(Pair.second ? "up" : "down") + " to label" +
|
||||
utostr(Pair.first));
|
||||
}
|
||||
} else {
|
||||
// A variable_ops operand, which currently can be immediates (used in
|
||||
// br_table) which are basic block targets, or for call instructions
|
||||
// when using -wasm-keep-registers (in which case they are registers,
|
||||
// and should not be processed).
|
||||
if (!MI->getOperand(I).isImm())
|
||||
continue;
|
||||
}
|
||||
uint64_t Depth = MI->getOperand(I).getImm();
|
||||
if (!Printed.insert(Depth).second)
|
||||
continue;
|
||||
if (Depth >= ControlFlowStack.size()) {
|
||||
printAnnotation(OS, "Invalid depth argument!");
|
||||
} else {
|
||||
const auto &Pair = ControlFlowStack.rbegin()[Depth];
|
||||
printAnnotation(OS, utostr(Depth) + ": " +
|
||||
(Pair.second ? "up" : "down") + " to label" +
|
||||
utostr(Pair.first));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,13 +25,9 @@ class MCSubtargetInfo;
|
|||
|
||||
class WebAssemblyInstPrinter final : public MCInstPrinter {
|
||||
uint64_t ControlFlowCounter = 0;
|
||||
uint64_t EHPadStackCounter = 0;
|
||||
SmallVector<std::pair<uint64_t, bool>, 4> ControlFlowStack;
|
||||
SmallVector<uint64_t, 4> EHPadStack;
|
||||
|
||||
enum EHInstKind { TRY, CATCH, END_TRY };
|
||||
EHInstKind LastSeenEHInst = END_TRY;
|
||||
|
||||
public:
|
||||
WebAssemblyInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
|
||||
const MCRegisterInfo &MRI);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
; REQUIRES: asserts
|
||||
; TODO Reenable disabled lines after updating the backend to the new spec
|
||||
; R UN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling | FileCheck %s
|
||||
; RUN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling | FileCheck %s
|
||||
; RUN: llc < %s -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling
|
||||
; R UN: llc < %s -O0 -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -verify-machineinstrs -exception-model=wasm -mattr=+exception-handling | FileCheck %s --check-prefix=NOOPT
|
||||
; RUN: llc < %s -O0 -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -verify-machineinstrs -exception-model=wasm -mattr=+exception-handling | FileCheck %s --check-prefix=NOOPT
|
||||
; R UN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling -wasm-disable-ehpad-sort | FileCheck %s --check-prefix=NOSORT
|
||||
; R UN: llc < %s -disable-wasm-fallthrough-return-opt -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling -wasm-disable-ehpad-sort | FileCheck %s --check-prefix=NOSORT-LOCALS
|
||||
; R UN: llc < %s -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -disable-block-placement -verify-machineinstrs -fast-isel=false -machine-sink-split-probability-threshold=0 -cgp-freq-ratio-to-skip-merge=1000 -exception-model=wasm -mattr=+exception-handling -wasm-disable-ehpad-sort -stats 2>&1 | FileCheck %s --check-prefix=NOSORT-STAT
|
||||
|
@ -43,7 +43,7 @@ target triple = "wasm32-unknown-unknown"
|
|||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: br 1 # 1: down to label[[L1]]
|
||||
; CHECK: end_block # label[[L2]]:
|
||||
; CHECK: rethrow {{.*}} # to caller
|
||||
; CHECK: rethrow 0 # to caller
|
||||
; CHECK: end_try # label[[L1]]:
|
||||
define void @test0() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
|
||||
entry:
|
||||
|
@ -118,19 +118,19 @@ try.cont: ; preds = %catch, %catch2, %en
|
|||
; CHECK: br 2 # 2: down to label[[L3:[0-9]+]]
|
||||
; CHECK: catch
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: rethrow {{.*}} # down to catch[[C0:[0-9]+]]
|
||||
; CHECK: rethrow 0 # down to catch[[C0:[0-9]+]]
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block # label[[L2]]:
|
||||
; CHECK: rethrow {{.*}} # down to catch[[C0]]
|
||||
; CHECK: catch {{.*}} # catch[[C0]]:
|
||||
; CHECK: rethrow 0 # down to catch[[C0]]
|
||||
; CHECK: catch_all # catch[[C0]]:
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: rethrow {{.*}} # to caller
|
||||
; CHECK: rethrow 0 # to caller
|
||||
; CHECK: end_try # label[[L3]]:
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: br 2 # 2: down to label[[L1]]
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block # label[[L0]]:
|
||||
; CHECK: rethrow {{.*}} # to caller
|
||||
; CHECK: rethrow 0 # to caller
|
||||
; CHECK: end_block # label[[L1]]:
|
||||
; CHECK: call __cxa_end_catch
|
||||
; CHECK: end_try
|
||||
|
@ -237,7 +237,7 @@ unreachable: ; preds = %rethrow5
|
|||
; CHECK: call __clang_call_terminate
|
||||
; CHECK: unreachable
|
||||
; CHECK: end_try
|
||||
; CHECK: rethrow {{.*}} # to caller
|
||||
; CHECK: rethrow 0 # to caller
|
||||
; CHECK: end_try
|
||||
; CHECK: end_block # label[[L1]]:
|
||||
; CHECK: call __cxa_end_catch
|
||||
|
@ -658,7 +658,7 @@ try.cont: ; preds = %catch.start
|
|||
; NOSORT: br_on_exn 0, {{.*}} # 0: down to label[[L2:[0-9]+]]
|
||||
; --- Nested try/catch/end_try starts
|
||||
; NOSORT: try
|
||||
; NOSORT: rethrow {{.*}} # down to catch[[C0:[0-9]+]]
|
||||
; NOSORT: rethrow 0 # down to catch[[C0:[0-9]+]]
|
||||
; NOSORT: catch $[[REG1:[0-9]+]]= # catch[[C0]]:
|
||||
; NOSORT: br 5 # 5: down to label[[L3:[0-9]+]]
|
||||
; NOSORT: end_try
|
||||
|
|
|
@ -24,8 +24,7 @@ test_annotation:
|
|||
block
|
||||
try
|
||||
br 0
|
||||
catch __cpp_exception
|
||||
local.set 0
|
||||
catch_all
|
||||
end_try
|
||||
end_block
|
||||
rethrow 0
|
||||
|
@ -45,13 +44,12 @@ test_annotation:
|
|||
# CHECK-NEXT: end_loop
|
||||
# CHECK-NEXT: end_block # label1:
|
||||
# CHECK-NEXT: try
|
||||
# CHECK-NEXT: rethrow 0 # down to catch1
|
||||
# CHECK-NEXT: catch __cpp_exception # catch1:
|
||||
# CHECK-NEXT: rethrow 0 # down to catch3
|
||||
# CHECK-NEXT: catch __cpp_exception # catch3:
|
||||
# CHECK-NEXT: block
|
||||
# CHECK-NEXT: try
|
||||
# CHECK-NEXT: br 0 # 0: down to label5
|
||||
# CHECK-NEXT: catch __cpp_exception # catch2:
|
||||
# CHECK-NEXT: local.set 0
|
||||
# CHECK-NEXT: catch_all # catch5:
|
||||
# CHECK-NEXT: end_try # label5:
|
||||
# CHECK-NEXT: end_block # label4:
|
||||
# CHECK-NEXT: rethrow 0 # to caller
|
||||
|
|
Loading…
Reference in New Issue