1600aee98SJF Bastien//===- WebAssemblyInstrControl.td-WebAssembly control-flow ------*- tablegen -*-
2600aee98SJF Bastien//
32946cd70SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth// See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6600aee98SJF Bastien//
7600aee98SJF Bastien//===----------------------------------------------------------------------===//
8600aee98SJF Bastien///
9600aee98SJF Bastien/// \file
105f8f34e4SAdrian Prantl/// WebAssembly control-flow code-gen constructs.
11600aee98SJF Bastien///
12600aee98SJF Bastien//===----------------------------------------------------------------------===//
13600aee98SJF Bastien
14950a13cfSDan Gohmanlet isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in {
15f0b165a7SDan Gohman// The condition operand is a boolean value which WebAssembly represents as i32.
1648dac310SWouter van Oortmerssendefm BR_IF : I<(outs), (ins bb_op:$dst, I32:$cond),
1748dac310SWouter van Oortmerssen               (outs), (ins bb_op:$dst),
18f0b165a7SDan Gohman               [(brcond I32:$cond, bb:$dst)],
1948dac310SWouter van Oortmerssen                "br_if   \t$dst, $cond", "br_if   \t$dst", 0x0d>;
20f0b165a7SDan Gohmanlet isCodeGenOnly = 1 in
2148dac310SWouter van Oortmerssendefm BR_UNLESS : I<(outs), (ins bb_op:$dst, I32:$cond),
2248dac310SWouter van Oortmerssen                   (outs), (ins bb_op:$dst), []>;
234367587fSHeejin Ahnlet isBarrier = 1 in
2448dac310SWouter van Oortmerssendefm BR   : NRI<(outs), (ins bb_op:$dst),
25af29bd4fSDan Gohman                [(br bb:$dst)],
26c968297bSDan Gohman                "br      \t$dst", 0x0c>;
27950a13cfSDan Gohman} // isBranch = 1, isTerminator = 1, hasCtrlDep = 1
28950a13cfSDan Gohman
29f0b165a7SDan Gohmandef : Pat<(brcond (i32 (setne I32:$cond, 0)), bb:$dst),
3006b49582SDan Gohman          (BR_IF bb_op:$dst, I32:$cond)>;
31f0b165a7SDan Gohmandef : Pat<(brcond (i32 (seteq I32:$cond, 0)), bb:$dst),
3206b49582SDan Gohman          (BR_UNLESS bb_op:$dst, I32:$cond)>;
3392e77714SSam Parkerdef : Pat<(brcond (i32 (xor bool_node:$cond, (i32 1))), bb:$dst),
3492e77714SSam Parker          (BR_UNLESS bb_op:$dst, I32:$cond)>;
35f0b165a7SDan Gohman
36d3c544aaSWouter van Oortmerssen// A list of branch targets enclosed in {} and separated by comma.
37d3c544aaSWouter van Oortmerssen// Used by br_table only.
38d3c544aaSWouter van Oortmerssendef BrListAsmOperand : AsmOperandClass { let Name = "BrList"; }
394367587fSHeejin Ahnlet OperandNamespace = "WebAssembly", OperandType = "OPERAND_BRLIST" in
40d3c544aaSWouter van Oortmerssendef brlist : Operand<i32> {
41d3c544aaSWouter van Oortmerssen  let ParserMatchClass = BrListAsmOperand;
42d3c544aaSWouter van Oortmerssen  let PrintMethod = "printBrList";
43d3c544aaSWouter van Oortmerssen}
44d3c544aaSWouter van Oortmerssen
45c5d01234SThomas Lively// Duplicating a BR_TABLE is almost never a good idea. In particular, it can
46c5d01234SThomas Lively// lead to some nasty irreducibility due to tail merging when the br_table is in
47c5d01234SThomas Lively// a loop.
48c5d01234SThomas Livelylet isTerminator = 1, hasCtrlDep = 1, isBarrier = 1, isNotDuplicable = 1 in {
49c5d01234SThomas Lively
508e2bac8eSHeejin Ahndefm BR_TABLE_I32 : I<(outs), (ins I32:$index, variable_ops),
518e2bac8eSHeejin Ahn                      (outs), (ins brlist:$brl),
528e2bac8eSHeejin Ahn                      [(WebAssemblybr_table I32:$index)],
538e2bac8eSHeejin Ahn                      "br_table \t$index", "br_table \t$brl",
548e2bac8eSHeejin Ahn                      0x0e>;
55c5d01234SThomas Lively// TODO: SelectionDAG's lowering insists on using a pointer as the index for
56c5d01234SThomas Lively// jump tables, so in practice we don't ever use BR_TABLE_I64 in wasm32 mode
57c5d01234SThomas Lively// currently.
588e2bac8eSHeejin Ahndefm BR_TABLE_I64 : I<(outs), (ins I64:$index, variable_ops),
598e2bac8eSHeejin Ahn                      (outs), (ins brlist:$brl),
608e2bac8eSHeejin Ahn                      [(WebAssemblybr_table I64:$index)],
618e2bac8eSHeejin Ahn                      "br_table \t$index", "br_table \t$brl",
628e2bac8eSHeejin Ahn                      0x0e>;
63c5d01234SThomas Lively} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1, isNotDuplicable = 1
64950a13cfSDan Gohman
6516c16827SSam Clegg// This is technically a control-flow instruction, since all it affects is the
6616c16827SSam Clegg// IP.
6748dac310SWouter van Oortmerssendefm NOP : NRI<(outs), (ins), [], "nop", 0x01>;
6816c16827SSam Clegg
69e4a8deeaSHeejin Ahn// Placemarkers to indicate the start or end of a block or loop scope.
70ac62b05dSHeejin Ahn// These use/clobber VALUE_STACK to prevent them from being moved into the
71ac62b05dSHeejin Ahn// middle of an expression tree.
72e040533eSDan Gohmanlet Uses = [VALUE_STACK], Defs = [VALUE_STACK] in {
7348dac310SWouter van Oortmerssendefm BLOCK : NRI<(outs), (ins Signature:$sig), [], "block   \t$sig", 0x02>;
7448dac310SWouter van Oortmerssendefm LOOP  : NRI<(outs), (ins Signature:$sig), [], "loop    \t$sig", 0x03>;
754becc585SDan Gohman
76f2276210SWouter van Oortmerssendefm IF : I<(outs), (ins Signature:$sig, I32:$cond),
77f2276210SWouter van Oortmerssen            (outs), (ins Signature:$sig),
78f2276210SWouter van Oortmerssen            [], "if    \t$sig, $cond", "if    \t$sig", 0x04>;
79f2276210SWouter van Oortmerssendefm ELSE : NRI<(outs), (ins), [], "else", 0x05>;
80f2276210SWouter van Oortmerssen
81f2276210SWouter van Oortmerssen// END_BLOCK, END_LOOP, END_IF and END_FUNCTION are represented with the same
82f2276210SWouter van Oortmerssen// opcode in wasm.
8348dac310SWouter van Oortmerssendefm END_BLOCK : NRI<(outs), (ins), [], "end_block", 0x0b>;
8448dac310SWouter van Oortmerssendefm END_LOOP  : NRI<(outs), (ins), [], "end_loop", 0x0b>;
85f2276210SWouter van Oortmerssendefm END_IF    : NRI<(outs), (ins), [], "end_if", 0x0b>;
861a91cb04SWouter van Oortmerssen// Generic instruction, for disassembler.
874367587fSHeejin Ahnlet IsCanonical = 1 in
881a91cb04SWouter van Oortmerssendefm END       : NRI<(outs), (ins), [], "end", 0x0b>;
89d934cb88SDan Gohmanlet isTerminator = 1, isBarrier = 1 in
9048dac310SWouter van Oortmerssendefm END_FUNCTION : NRI<(outs), (ins), [], "end_function", 0x0b>;
91e040533eSDan Gohman} // Uses = [VALUE_STACK], Defs = [VALUE_STACK]
92950a13cfSDan Gohman
9339bf39f3SDerek Schuff
94a07c08f7SThomas Livelylet hasCtrlDep = 1, isBarrier = 1 in {
95a07c08f7SThomas Livelylet isTerminator = 1 in {
96ffa143ceSDerek Schufflet isReturn = 1 in {
9739bf39f3SDerek Schuff
9800f9e5aaSThomas Livelydefm RETURN : I<(outs), (ins variable_ops), (outs), (ins),
9900f9e5aaSThomas Lively                [(WebAssemblyreturn)],
10000f9e5aaSThomas Lively                "return", "return", 0x0f>;
10100f9e5aaSThomas Lively// Equivalent to RETURN, for use at the end of a function when wasm
10200f9e5aaSThomas Lively// semantics return by falling off the end of the block.
103b7c2400fSDan Gohmanlet isCodeGenOnly = 1 in
10400f9e5aaSThomas Livelydefm FALLTHROUGH_RETURN : I<(outs), (ins variable_ops), (outs), (ins), []>;
10500f9e5aaSThomas Lively
106ffa143ceSDerek Schuff} // isReturn = 1
1079850e877SDan Gohman
1084252f300SDominic Chenlet IsCanonical = 1, isTrap = 1 in
10948dac310SWouter van Oortmerssendefm UNREACHABLE : NRI<(outs), (ins), [(trap)], "unreachable", 0x00>;
110a07c08f7SThomas Lively
111a07c08f7SThomas Lively} // isTerminator = 1
112a07c08f7SThomas Lively
113a07c08f7SThomas Lively// debugtrap explicitly returns despite trapping because it is supposed to just
114a07c08f7SThomas Lively// get the attention of the debugger. Unfortunately, because UNREACHABLE is a
115a07c08f7SThomas Lively// terminator, lowering debugtrap to UNREACHABLE can create an invalid
116a07c08f7SThomas Lively// MachineBasicBlock when there is additional code after it. Lower it to this
117a07c08f7SThomas Lively// non-terminator version instead.
118a07c08f7SThomas Lively// TODO: Actually execute the debugger statement when running on the Web
119a07c08f7SThomas Livelylet isTrap = 1 in
120a07c08f7SThomas Livelydefm DEBUG_UNREACHABLE : NRI<(outs), (ins), [(debugtrap)], "unreachable", 0x00>;
121a07c08f7SThomas Lively
122a07c08f7SThomas Lively} // hasCtrlDep = 1, isBarrier = 1
1239850e877SDan Gohman
124e4a8deeaSHeejin Ahn//===----------------------------------------------------------------------===//
125e4a8deeaSHeejin Ahn// Exception handling instructions
126e4a8deeaSHeejin Ahn//===----------------------------------------------------------------------===//
127e4a8deeaSHeejin Ahn
12847068a42SHeejin Ahnlet Predicates = [HasExceptionHandling] in {
12947068a42SHeejin Ahn
130e4a8deeaSHeejin Ahn// Throwing an exception: throw / rethrow
131e4a8deeaSHeejin Ahnlet isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
1321d891d44SHeejin Ahndefm THROW : I<(outs), (ins tag_op:$tag, variable_ops),
133*31a71a39SHeejin Ahn               (outs), (ins tag_op:$tag), [],
134d6f48786SHeejin Ahn               "throw   \t$tag", "throw   \t$tag", 0x08>;
1359e4eadebSHeejin Ahndefm RETHROW : NRI<(outs), (ins i32imm:$depth), [], "rethrow \t$depth", 0x09>;
136ffa143ceSDerek Schuff} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
13735f5f797SHeejin Ahn// The depth argument will be computed in CFGStackify. We set it to 0 here for
13835f5f797SHeejin Ahn// now.
1399e4eadebSHeejin Ahndef : Pat<(int_wasm_rethrow), (RETHROW 0)>;
140fb3e0594SDan Gohman
141e4a8deeaSHeejin Ahn// Region within which an exception is caught: try / end_try
142e4a8deeaSHeejin Ahnlet Uses = [VALUE_STACK], Defs = [VALUE_STACK] in {
14348dac310SWouter van Oortmerssendefm TRY     : NRI<(outs), (ins Signature:$sig), [], "try     \t$sig", 0x06>;
14448dac310SWouter van Oortmerssendefm END_TRY : NRI<(outs), (ins), [], "end_try", 0x0b>;
145e4a8deeaSHeejin Ahn} // Uses = [VALUE_STACK], Defs = [VALUE_STACK]
146e4a8deeaSHeejin Ahn
1479e4eadebSHeejin Ahn// Catching an exception: catch / catch_all
1489e4eadebSHeejin Ahnlet hasCtrlDep = 1, hasSideEffects = 1 in {
149*31a71a39SHeejin Ahnlet variadicOpsAreDefs = 1 in
150*31a71a39SHeejin Ahndefm CATCH : I<(outs), (ins tag_op:$tag, variable_ops),
151*31a71a39SHeejin Ahn               (outs), (ins tag_op:$tag), [],
152*31a71a39SHeejin Ahn               "catch",  "catch   \t$tag", 0x07>;
1537c594babSHeejin Ahndefm CATCH_ALL : NRI<(outs), (ins), [], "catch_all", 0x19>;
1549e4eadebSHeejin Ahn}
155d6f48786SHeejin Ahn
156ed41945fSHeejin Ahn// Delegating an exception: delegate
157ed41945fSHeejin Ahnlet isTerminator = 1, hasCtrlDep = 1, hasSideEffects = 1 in
158ed41945fSHeejin Ahndefm DELEGATE : NRI<(outs), (ins bb_op:$dst), [], "delegate \t $dst", 0x18>;
159ed41945fSHeejin Ahn
1605ef4d5f9SHeejin Ahn// Pseudo instructions: cleanupret / catchret
1615ef4d5f9SHeejin Ahnlet isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
162d6f48786SHeejin Ahn    isPseudo = 1, isEHScopeReturn = 1 in {
163d6f48786SHeejin Ahn  defm CLEANUPRET : NRI<(outs), (ins), [(cleanupret)], "cleanupret", 0>;
16448dac310SWouter van Oortmerssen  defm CATCHRET : NRI<(outs), (ins bb_op:$dst, bb_op:$from),
165d6f48786SHeejin Ahn                      [(catchret bb:$dst, bb:$from)], "catchret", 0>;
166d6f48786SHeejin Ahn} // isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
167d6f48786SHeejin Ahn  // isPseudo = 1, isEHScopeReturn = 1
1684367587fSHeejin Ahn} // Predicates = [HasExceptionHandling]
169