[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:
Heejin Ahn 2020-12-27 01:10:53 -08:00
parent bb0e621387
commit 0d8dfbb42a
4 changed files with 58 additions and 65 deletions

View File

@ -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));
}
}
}

View File

@ -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);

View File

@ -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

View File

@ -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