diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td')
-rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td | 33 |
1 files changed, 25 insertions, 8 deletions
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td index 1afc9a8790dcd..171dd9a67beb5 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -40,21 +40,25 @@ def brlist : Operand<i32> { let PrintMethod = "printBrList"; } -// TODO: SelectionDAG's lowering insists on using a pointer as the index for -// jump tables, so in practice we don't ever use BR_TABLE_I64 in wasm32 mode -// currently. -let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in { +// Duplicating a BR_TABLE is almost never a good idea. In particular, it can +// lead to some nasty irreducibility due to tail merging when the br_table is in +// a loop. +let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1, isNotDuplicable = 1 in { + defm BR_TABLE_I32 : I<(outs), (ins I32:$index, variable_ops), (outs), (ins brlist:$brl), [(WebAssemblybr_table I32:$index)], "br_table \t$index", "br_table \t$brl", 0x0e>; +// TODO: SelectionDAG's lowering insists on using a pointer as the index for +// jump tables, so in practice we don't ever use BR_TABLE_I64 in wasm32 mode +// currently. defm BR_TABLE_I64 : I<(outs), (ins I64:$index, variable_ops), (outs), (ins brlist:$brl), [(WebAssemblybr_table I64:$index)], "br_table \t$index", "br_table \t$brl", 0x0e>; -} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 +} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1, isNotDuplicable = 1 // This is technically a control-flow instruction, since all it affects is the // IP. @@ -85,8 +89,8 @@ defm END_FUNCTION : NRI<(outs), (ins), [], "end_function", 0x0b>; } // Uses = [VALUE_STACK], Defs = [VALUE_STACK] -let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in { - +let hasCtrlDep = 1, isBarrier = 1 in { +let isTerminator = 1 in { let isReturn = 1 in { defm RETURN : I<(outs), (ins variable_ops), (outs), (ins), @@ -99,8 +103,21 @@ defm FALLTHROUGH_RETURN : I<(outs), (ins variable_ops), (outs), (ins), []>; } // isReturn = 1 +let isTrap = 1 in defm UNREACHABLE : NRI<(outs), (ins), [(trap)], "unreachable", 0x00>; -} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 + +} // isTerminator = 1 + +// debugtrap explicitly returns despite trapping because it is supposed to just +// get the attention of the debugger. Unfortunately, because UNREACHABLE is a +// terminator, lowering debugtrap to UNREACHABLE can create an invalid +// MachineBasicBlock when there is additional code after it. Lower it to this +// non-terminator version instead. +// TODO: Actually execute the debugger statement when running on the Web +let isTrap = 1 in +defm DEBUG_UNREACHABLE : NRI<(outs), (ins), [(debugtrap)], "unreachable", 0x00>; + +} // hasCtrlDep = 1, isBarrier = 1 //===----------------------------------------------------------------------===// // Exception handling instructions |