Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -109,38 +109,68 @@ inline unsigned GetDefaultP2Align(unsigned Opcode) { switch (Opcode) { case WebAssembly::LOAD8_S_I32: + case WebAssembly::LOAD8_S_I32_S: case WebAssembly::LOAD8_U_I32: + case WebAssembly::LOAD8_U_I32_S: case WebAssembly::LOAD8_S_I64: + case WebAssembly::LOAD8_S_I64_S: case WebAssembly::LOAD8_U_I64: + case WebAssembly::LOAD8_U_I64_S: case WebAssembly::ATOMIC_LOAD8_U_I32: + case WebAssembly::ATOMIC_LOAD8_U_I32_S: case WebAssembly::ATOMIC_LOAD8_U_I64: + case WebAssembly::ATOMIC_LOAD8_U_I64_S: case WebAssembly::STORE8_I32: + case WebAssembly::STORE8_I32_S: case WebAssembly::STORE8_I64: + case WebAssembly::STORE8_I64_S: return 0; case WebAssembly::LOAD16_S_I32: + case WebAssembly::LOAD16_S_I32_S: case WebAssembly::LOAD16_U_I32: + case WebAssembly::LOAD16_U_I32_S: case WebAssembly::LOAD16_S_I64: + case WebAssembly::LOAD16_S_I64_S: case WebAssembly::LOAD16_U_I64: + case WebAssembly::LOAD16_U_I64_S: case WebAssembly::ATOMIC_LOAD16_U_I32: + case WebAssembly::ATOMIC_LOAD16_U_I32_S: case WebAssembly::ATOMIC_LOAD16_U_I64: + case WebAssembly::ATOMIC_LOAD16_U_I64_S: case WebAssembly::STORE16_I32: + case WebAssembly::STORE16_I32_S: case WebAssembly::STORE16_I64: + case WebAssembly::STORE16_I64_S: return 1; case WebAssembly::LOAD_I32: + case WebAssembly::LOAD_I32_S: case WebAssembly::LOAD_F32: + case WebAssembly::LOAD_F32_S: case WebAssembly::STORE_I32: + case WebAssembly::STORE_I32_S: case WebAssembly::STORE_F32: + case WebAssembly::STORE_F32_S: case WebAssembly::LOAD32_S_I64: + case WebAssembly::LOAD32_S_I64_S: case WebAssembly::LOAD32_U_I64: + case WebAssembly::LOAD32_U_I64_S: case WebAssembly::STORE32_I64: + case WebAssembly::STORE32_I64_S: case WebAssembly::ATOMIC_LOAD_I32: + case WebAssembly::ATOMIC_LOAD_I32_S: case WebAssembly::ATOMIC_LOAD32_U_I64: + case WebAssembly::ATOMIC_LOAD32_U_I64_S: return 2; case WebAssembly::LOAD_I64: + case WebAssembly::LOAD_I64_S: case WebAssembly::LOAD_F64: + case WebAssembly::LOAD_F64_S: case WebAssembly::STORE_I64: + case WebAssembly::STORE_I64_S: case WebAssembly::STORE_F64: + case WebAssembly::STORE_F64_S: case WebAssembly::ATOMIC_LOAD_I64: + case WebAssembly::ATOMIC_LOAD_I64_S: return 3; default: llvm_unreachable("Only loads and stores have p2align values"); Index: lib/Target/WebAssembly/WebAssemblyInstrAtomics.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrAtomics.td +++ lib/Target/WebAssembly/WebAssemblyInstrAtomics.td @@ -17,8 +17,8 @@ //===----------------------------------------------------------------------===// let Defs = [ARGUMENTS] in { -def ATOMIC_LOAD_I32 : WebAssemblyLoad; -def ATOMIC_LOAD_I64 : WebAssemblyLoad; +defm ATOMIC_LOAD_I32 : WebAssemblyLoad; +defm ATOMIC_LOAD_I64 : WebAssemblyLoad; } // Defs = [ARGUMENTS] // Select loads with no constant offset. @@ -56,11 +56,11 @@ // Extending loads. Note that there are only zero-extending atomic loads, no // sign-extending loads. let Defs = [ARGUMENTS] in { -def ATOMIC_LOAD8_U_I32 : WebAssemblyLoad; -def ATOMIC_LOAD16_U_I32 : WebAssemblyLoad; -def ATOMIC_LOAD8_U_I64 : WebAssemblyLoad; -def ATOMIC_LOAD16_U_I64 : WebAssemblyLoad; -def ATOMIC_LOAD32_U_I64 : WebAssemblyLoad; +defm ATOMIC_LOAD8_U_I32 : WebAssemblyLoad; +defm ATOMIC_LOAD16_U_I32 : WebAssemblyLoad; +defm ATOMIC_LOAD8_U_I64 : WebAssemblyLoad; +defm ATOMIC_LOAD16_U_I64 : WebAssemblyLoad; +defm ATOMIC_LOAD32_U_I64 : WebAssemblyLoad; } // Defs = [ARGUMENTS] // Fragments for exending loads. These are different from regular loads because Index: lib/Target/WebAssembly/WebAssemblyInstrCall.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -13,57 +13,72 @@ //===----------------------------------------------------------------------===// // TODO: addr64: These currently assume the callee address is 32-bit. +// FIXME: add $type to first call_indirect asmstr (and maybe $flags) let Defs = [ARGUMENTS] in { // Call sequence markers. These have an immediate which represents the amount of // stack space to allocate or free, which is used for varargs lowering. let Uses = [SP32, SP64], Defs = [SP32, SP64], isCodeGenOnly = 1 in { -def ADJCALLSTACKDOWN : I<(outs), (ins i32imm:$amt, i32imm:$amt2), - [(WebAssemblycallseq_start timm:$amt, timm:$amt2)]>; -def ADJCALLSTACKUP : I<(outs), (ins i32imm:$amt, i32imm:$amt2), - [(WebAssemblycallseq_end timm:$amt, timm:$amt2)]>; +defm ADJCALLSTACKDOWN : NRI<(outs), (ins i32imm:$amt, i32imm:$amt2), + [(WebAssemblycallseq_start timm:$amt, timm:$amt2)]>; +defm ADJCALLSTACKUP : NRI<(outs), (ins i32imm:$amt, i32imm:$amt2), + [(WebAssemblycallseq_end timm:$amt, timm:$amt2)]>; } // isCodeGenOnly = 1 multiclass CALL { - def CALL_#vt : I<(outs vt:$dst), (ins function32_op:$callee, variable_ops), - [(set vt:$dst, (WebAssemblycall1 (i32 imm:$callee)))], - !strconcat(prefix, "call\t$dst, $callee"), - 0x10>; + defm CALL_#vt : I<(outs vt:$dst), (ins function32_op:$callee, variable_ops), + (outs), (ins function32_op:$callee), + [(set vt:$dst, (WebAssemblycall1 (i32 imm:$callee)))], + !strconcat(prefix, "call\t$dst, $callee"), + !strconcat(prefix, "call\t$callee"), + 0x10>; let isCodeGenOnly = 1 in { - def PCALL_INDIRECT_#vt : I<(outs vt:$dst), (ins I32:$callee, variable_ops), - [(set vt:$dst, (WebAssemblycall1 I32:$callee))], - "PSEUDO CALL INDIRECT\t$callee">; + defm PCALL_INDIRECT_#vt : I<(outs vt:$dst), (ins I32:$callee, variable_ops), + (outs), (ins I32:$callee), + [(set vt:$dst, (WebAssemblycall1 I32:$callee))], + "PSEUDO CALL INDIRECT\t$callee", + "PSEUDO CALL INDIRECT\t$callee">; } // isCodeGenOnly = 1 - def CALL_INDIRECT_#vt : I<(outs vt:$dst), - (ins TypeIndex:$type, i32imm:$flags, variable_ops), - [], - !strconcat(prefix, "call_indirect\t$dst"), - 0x11>; + defm CALL_INDIRECT_#vt : I<(outs vt:$dst), + (ins TypeIndex:$type, i32imm:$flags, variable_ops), + (outs), (ins TypeIndex:$type, i32imm:$flags), + [], + !strconcat(prefix, "call_indirect\t$dst"), + !strconcat(prefix, "call_indirect\t$type"), + 0x11>; } multiclass SIMD_CALL { - def CALL_#vt : SIMD_I<(outs V128:$dst), (ins function32_op:$callee, variable_ops), + defm CALL_#vt : SIMD_I<(outs V128:$dst), (ins function32_op:$callee, + variable_ops), + (outs), (ins function32_op:$callee), [(set (vt V128:$dst), - (WebAssemblycall1 (i32 imm:$callee)))], + (WebAssemblycall1 (i32 imm:$callee)))], !strconcat(prefix, "call\t$dst, $callee"), + !strconcat(prefix, "call\t$callee"), 0x10>; let isCodeGenOnly = 1 in { - def PCALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst), - (ins I32:$callee, variable_ops), - [(set (vt V128:$dst), - (WebAssemblycall1 I32:$callee))], - "PSEUDO CALL INDIRECT\t$callee">; + defm PCALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst), + (ins I32:$callee, variable_ops), + (outs), (ins I32:$callee), + [(set (vt V128:$dst), + (WebAssemblycall1 I32:$callee))], + "PSEUDO CALL INDIRECT\t$callee", + "PSEUDO CALL INDIRECT\t$callee">; } // isCodeGenOnly = 1 - def CALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst), + defm CALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst), (ins TypeIndex:$type, i32imm:$flags, - variable_ops), + variable_ops), + (outs), (ins TypeIndex:$type, i32imm:$flags), [], - !strconcat(prefix, "call_indirect\t$dst"), + !strconcat(prefix, + "call_indirect\t$dst"), + !strconcat(prefix, "call_indirect\t$type"), 0x11>; } @@ -78,20 +93,26 @@ defm "" : SIMD_CALL; defm "" : SIMD_CALL; - def CALL_VOID : I<(outs), (ins function32_op:$callee, variable_ops), - [(WebAssemblycall0 (i32 imm:$callee))], - "call \t$callee", 0x10>; + defm CALL_VOID : I<(outs), (ins function32_op:$callee, variable_ops), + (outs), (ins function32_op:$callee), + [(WebAssemblycall0 (i32 imm:$callee))], + "call \t$callee", "call\t$callee", 0x10>; let isCodeGenOnly = 1 in { - def PCALL_INDIRECT_VOID : I<(outs), (ins I32:$callee, variable_ops), - [(WebAssemblycall0 I32:$callee)], - "PSEUDO CALL INDIRECT\t$callee">; + defm PCALL_INDIRECT_VOID : I<(outs), (ins I32:$callee, variable_ops), + (outs), (ins I32:$callee), + [(WebAssemblycall0 I32:$callee)], + "PSEUDO CALL INDIRECT\t$callee", + "PSEUDO CALL INDIRECT\t$callee">; } // isCodeGenOnly = 1 - def CALL_INDIRECT_VOID : I<(outs), - (ins TypeIndex:$type, i32imm:$flags, variable_ops), - [], - "call_indirect\t", 0x11>; + defm CALL_INDIRECT_VOID : I<(outs), + (ins TypeIndex:$type, i32imm:$flags, + variable_ops), + (outs), (ins TypeIndex:$type, i32imm:$flags), + [], + "call_indirect\t", "call_indirect\t$type", + 0x11>; } // Uses = [SP32,SP64], isCall = 1 } // Defs = [ARGUMENTS] Index: lib/Target/WebAssembly/WebAssemblyInstrControl.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -16,15 +16,17 @@ let isBranch = 1, isTerminator = 1, hasCtrlDep = 1 in { // The condition operand is a boolean value which WebAssembly represents as i32. -def BR_IF : I<(outs), (ins bb_op:$dst, I32:$cond), - [(brcond I32:$cond, bb:$dst)], - "br_if \t$dst, $cond", 0x0d>; +defm BR_IF : I<(outs), (ins bb_op:$dst, I32:$cond), + (outs), (ins bb_op:$dst), + [(brcond I32:$cond, bb:$dst)], + "br_if \t$dst, $cond", "br_if \t$dst", 0x0d>; let isCodeGenOnly = 1 in -def BR_UNLESS : I<(outs), (ins bb_op:$dst, I32:$cond), []>; +defm BR_UNLESS : I<(outs), (ins bb_op:$dst, I32:$cond), + (outs), (ins bb_op:$dst), []>; let isBarrier = 1 in { -def BR : I<(outs), (ins bb_op:$dst), - [(br bb:$dst)], - "br \t$dst", 0x0c>; +defm BR : NRI<(outs), (ins bb_op:$dst), + [(br bb:$dst)], + "br \t$dst", 0x0c>; } // isBarrier = 1 } // isBranch = 1, isTerminator = 1, hasCtrlDep = 1 @@ -42,16 +44,30 @@ // currently. // Set TSFlags{0} to 1 to indicate that the variable_ops are immediates. // Set TSFlags{1} to 1 to indicate that the immediates represent labels. +// FIXME: this can't inherit from I<> since there is no way to inherit from a +// multiclass and still have the let statements. let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in { -def BR_TABLE_I32 : I<(outs), (ins I32:$index, variable_ops), - [(WebAssemblybr_table I32:$index)], - "br_table \t$index", 0x0e> { +def BR_TABLE_I32 : NI<(outs), (ins I32:$index, variable_ops), + [(WebAssemblybr_table I32:$index)], 0, + "br_table \t$index", 0x0e> { let TSFlags{0} = 1; let TSFlags{1} = 1; } -def BR_TABLE_I64 : I<(outs), (ins I64:$index, variable_ops), - [(WebAssemblybr_table I64:$index)], - "br_table \t$index"> { +def BR_TABLE_I32_S : NI<(outs), (ins I32:$index), + [], 1, + "br_table \t$index", 0x0e> { + let TSFlags{0} = 1; + let TSFlags{1} = 1; +} +def BR_TABLE_I64 : NI<(outs), (ins I64:$index, variable_ops), + [(WebAssemblybr_table I64:$index)], 0, + "br_table \t$index"> { + let TSFlags{0} = 1; + let TSFlags{1} = 1; +} +def BR_TABLE_I64_S : NI<(outs), (ins I64:$index), + [], 1, + "br_table \t$index"> { let TSFlags{0} = 1; let TSFlags{1} = 1; } @@ -59,40 +75,42 @@ // This is technically a control-flow instruction, since all it affects is the // IP. -def NOP : I<(outs), (ins), [], "nop", 0x01>; +defm NOP : NRI<(outs), (ins), [], "nop", 0x01>; // Placemarkers to indicate the start or end of a block or loop scope. // These use/clobber VALUE_STACK to prevent them from being moved into the // middle of an expression tree. let Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { -def BLOCK : I<(outs), (ins Signature:$sig), [], "block \t$sig", 0x02>; -def LOOP : I<(outs), (ins Signature:$sig), [], "loop \t$sig", 0x03>; +defm BLOCK : NRI<(outs), (ins Signature:$sig), [], "block \t$sig", 0x02>; +defm LOOP : NRI<(outs), (ins Signature:$sig), [], "loop \t$sig", 0x03>; // END_BLOCK, END_LOOP, and END_FUNCTION are represented with the same opcode in // wasm. -def END_BLOCK : I<(outs), (ins), [], "end_block", 0x0b>; -def END_LOOP : I<(outs), (ins), [], "end_loop", 0x0b>; +defm END_BLOCK : NRI<(outs), (ins), [], "end_block", 0x0b>; +defm END_LOOP : NRI<(outs), (ins), [], "end_loop", 0x0b>; let isTerminator = 1, isBarrier = 1 in -def END_FUNCTION : I<(outs), (ins), [], "end_function", 0x0b>; +defm END_FUNCTION : NRI<(outs), (ins), [], "end_function", 0x0b>; } // Uses = [VALUE_STACK], Defs = [VALUE_STACK] multiclass RETURN { - def RETURN_#vt : I<(outs), (ins vt:$val), [(WebAssemblyreturn vt:$val)], - "return \t$val", 0x0f>; + defm RETURN_#vt : I<(outs), (ins vt:$val), (outs), (ins), + [(WebAssemblyreturn vt:$val)], + "return \t$val", "return", 0x0f>; // Equivalent to RETURN_#vt, for use at the end of a function when wasm // semantics return by falling off the end of the block. let isCodeGenOnly = 1 in - def FALLTHROUGH_RETURN_#vt : I<(outs), (ins vt:$val), []>; + defm FALLTHROUGH_RETURN_#vt : I<(outs), (ins vt:$val), (outs), (ins), []>; } multiclass SIMD_RETURN { - def RETURN_#vt : SIMD_I<(outs), (ins V128:$val), - [(WebAssemblyreturn (vt V128:$val))], - "return \t$val", 0x0f>; + defm RETURN_#vt : SIMD_I<(outs), (ins V128:$val), (outs), (ins), + [(WebAssemblyreturn (vt V128:$val))], + "return \t$val", "return", 0x0f>; // Equivalent to RETURN_#vt, for use at the end of a function when wasm // semantics return by falling off the end of the block. let isCodeGenOnly = 1 in - def FALLTHROUGH_RETURN_#vt : SIMD_I<(outs), (ins V128:$val), []>; + defm FALLTHROUGH_RETURN_#vt : SIMD_I<(outs), (ins V128:$val), (outs), (ins), + []>; } let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in { @@ -108,14 +126,14 @@ defm "": SIMD_RETURN; defm "": SIMD_RETURN; - def RETURN_VOID : I<(outs), (ins), [(WebAssemblyreturn)], "return", 0x0f>; + defm RETURN_VOID : NRI<(outs), (ins), [(WebAssemblyreturn)], "return", 0x0f>; // This is to RETURN_VOID what FALLTHROUGH_RETURN_#vt is to RETURN_#vt. let isCodeGenOnly = 1 in - def FALLTHROUGH_RETURN_VOID : I<(outs), (ins), []>; + defm FALLTHROUGH_RETURN_VOID : NRI<(outs), (ins), []>; } // isReturn = 1 -def UNREACHABLE : I<(outs), (ins), [(trap)], "unreachable", 0x00>; +defm UNREACHABLE : NRI<(outs), (ins), [(trap)], "unreachable", 0x00>; } // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 //===----------------------------------------------------------------------===// @@ -124,31 +142,37 @@ // Throwing an exception: throw / rethrow let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in { -def THROW_I32 : I<(outs), (ins i32imm:$tag, I32:$val), - [(int_wasm_throw imm:$tag, I32:$val)], "throw \t$tag, $val", - 0x08>; -def THROW_I64 : I<(outs), (ins i32imm:$tag, I64:$val), - [(int_wasm_throw imm:$tag, I64:$val)], "throw \t$tag, $val", - 0x08>; -def RETHROW : I<(outs), (ins i32imm:$rel_depth), [], "rethrow \t$rel_depth", - 0x09>; +defm THROW_I32 : I<(outs), (ins i32imm:$tag, I32:$val), + (outs), (ins i32imm:$tag), + [(int_wasm_throw imm:$tag, I32:$val)], + "throw \t$tag, $val", "throw \t$tag", + 0x08>; +defm THROW_I64 : I<(outs), (ins i32imm:$tag, I64:$val), + (outs), (ins i32imm:$tag), + [(int_wasm_throw imm:$tag, I64:$val)], + "throw \t$tag, $val", "throw \t$tag", + 0x08>; +defm RETHROW : NRI<(outs), (ins i32imm:$rel_depth), [], "rethrow \t$rel_depth", + 0x09>; } // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 // Region within which an exception is caught: try / end_try let Uses = [VALUE_STACK], Defs = [VALUE_STACK] in { -def TRY : I<(outs), (ins Signature:$sig), [], "try \t$sig", 0x06>; -def END_TRY : I<(outs), (ins), [], "end_try", 0x0b>; +defm TRY : NRI<(outs), (ins Signature:$sig), [], "try \t$sig", 0x06>; +defm END_TRY : NRI<(outs), (ins), [], "end_try", 0x0b>; } // Uses = [VALUE_STACK], Defs = [VALUE_STACK] // Catching an exception: catch / catch_all let hasCtrlDep = 1 in { -def CATCH_I32 : I<(outs I32:$dst), (ins i32imm:$tag), - [(set I32:$dst, (int_wasm_catch imm:$tag))], - "i32.catch \t$dst, $tag", 0x07>; -def CATCH_I64 : I<(outs I64:$dst), (ins i32imm:$tag), - [(set I64:$dst, (int_wasm_catch imm:$tag))], - "i64.catch \t$dst, $tag", 0x07>; -def CATCH_ALL : I<(outs), (ins), [], "catch_all", 0x05>; +defm CATCH_I32 : I<(outs I32:$dst), (ins i32imm:$tag), + (outs), (ins i32imm:$tag), + [(set I32:$dst, (int_wasm_catch imm:$tag))], + "i32.catch \t$dst, $tag", "i32.catch \t$tag", 0x07>; +defm CATCH_I64 : I<(outs I64:$dst), (ins i32imm:$tag), + (outs), (ins i32imm:$tag), + [(set I64:$dst, (int_wasm_catch imm:$tag))], + "i64.catch \t$dst, $tag", "i64.catch \t$tag", 0x07>; +defm CATCH_ALL : NRI<(outs), (ins), [], "catch_all", 0x05>; } // Pseudo instructions: cleanupret / catchret @@ -156,8 +180,8 @@ // in X86 is necessary for computing funclet membership. let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1, isCodeGenOnly = 1, isReturn = 1 in { - def CLEANUPRET : I<(outs), (ins), [(cleanupret)], "", 0>; - def CATCHRET : I<(outs), (ins bb_op:$dst, bb_op:$from), + defm CLEANUPRET : NRI<(outs), (ins), [(cleanupret)], "", 0>; + defm CATCHRET : NRI<(outs), (ins bb_op:$dst, bb_op:$from), [(catchret bb:$dst, bb:$from)], "", 0>; } Index: lib/Target/WebAssembly/WebAssemblyInstrConv.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrConv.td +++ lib/Target/WebAssembly/WebAssemblyInstrConv.td @@ -15,33 +15,40 @@ let Defs = [ARGUMENTS] in { -def I32_WRAP_I64 : I<(outs I32:$dst), (ins I64:$src), +defm I32_WRAP_I64 : I<(outs I32:$dst), (ins I64:$src), (outs), (ins), [(set I32:$dst, (trunc I64:$src))], - "i32.wrap/i64\t$dst, $src", 0xa7>; + "i32.wrap/i64\t$dst, $src", "i32.wrap/i64", 0xa7>; -def I64_EXTEND_S_I32 : I<(outs I64:$dst), (ins I32:$src), +defm I64_EXTEND_S_I32 : I<(outs I64:$dst), (ins I32:$src), (outs), (ins), [(set I64:$dst, (sext I32:$src))], - "i64.extend_s/i32\t$dst, $src", 0xac>; -def I64_EXTEND_U_I32 : I<(outs I64:$dst), (ins I32:$src), - [(set I64:$dst, (zext I32:$src))], - "i64.extend_u/i32\t$dst, $src", 0xad>; + "i64.extend_s/i32\t$dst, $src", "i64.extend_s/i32", + 0xac>; +defm I64_EXTEND_U_I32 : I<(outs I64:$dst), (ins I32:$src), (outs), (ins), + [(set I64:$dst, (zext I32:$src))], + "i64.extend_u/i32\t$dst, $src", "i64.extend_u/i32", + 0xad>; let Predicates = [HasSignExt] in { -def I32_EXTEND8_S_I32 : I<(outs I32:$dst), (ins I32:$src), - [(set I32:$dst, (sext_inreg I32:$src, i8))], - "i32.extend8_s\t$dst, $src", 0xc0>; -def I32_EXTEND16_S_I32 : I<(outs I32:$dst), (ins I32:$src), - [(set I32:$dst, (sext_inreg I32:$src, i16))], - "i32.extend16_s\t$dst, $src", 0xc1>; -def I64_EXTEND8_S_I64 : I<(outs I64:$dst), (ins I64:$src), - [(set I64:$dst, (sext_inreg I64:$src, i8))], - "i64.extend8_s\t$dst, $src", 0xc2>; -def I64_EXTEND16_S_I64 : I<(outs I64:$dst), (ins I64:$src), - [(set I64:$dst, (sext_inreg I64:$src, i16))], - "i64.extend16_s\t$dst, $src", 0xc3>; -def I64_EXTEND32_S_I64 : I<(outs I64:$dst), (ins I64:$src), - [(set I64:$dst, (sext_inreg I64:$src, i32))], - "i64.extend32_s\t$dst, $src", 0xc4>; +defm I32_EXTEND8_S_I32 : I<(outs I32:$dst), (ins I32:$src), (outs), (ins), + [(set I32:$dst, (sext_inreg I32:$src, i8))], + "i32.extend8_s\t$dst, $src", "i32.extend8_s", + 0xc0>; +defm I32_EXTEND16_S_I32 : I<(outs I32:$dst), (ins I32:$src), (outs), (ins), + [(set I32:$dst, (sext_inreg I32:$src, i16))], + "i32.extend16_s\t$dst, $src", "i32.extend16_s", + 0xc1>; +defm I64_EXTEND8_S_I64 : I<(outs I64:$dst), (ins I64:$src), (outs), (ins), + [(set I64:$dst, (sext_inreg I64:$src, i8))], + "i64.extend8_s\t$dst, $src", "i64.extend8_s", + 0xc2>; +defm I64_EXTEND16_S_I64 : I<(outs I64:$dst), (ins I64:$src), (outs), (ins), + [(set I64:$dst, (sext_inreg I64:$src, i16))], + "i64.extend16_s\t$dst, $src", "i64.extend16_s", + 0xc3>; +defm I64_EXTEND32_S_I64 : I<(outs I64:$dst), (ins I64:$src), (outs), (ins), + [(set I64:$dst, (sext_inreg I64:$src, i32))], + "i64.extend32_s\t$dst, $src", "i64.extend32_s", + 0xc4>; } // Predicates = [HasSignExt] } // defs = [ARGUMENTS] @@ -55,131 +62,161 @@ // Conversion from floating point to integer instructions which don't trap on // overflow or invalid. -def I32_TRUNC_S_SAT_F32 : I<(outs I32:$dst), (ins F32:$src), - [(set I32:$dst, (fp_to_sint F32:$src))], - "i32.trunc_s:sat/f32\t$dst, $src", 0xfc00>, - Requires<[HasNontrappingFPToInt]>; -def I32_TRUNC_U_SAT_F32 : I<(outs I32:$dst), (ins F32:$src), - [(set I32:$dst, (fp_to_uint F32:$src))], - "i32.trunc_u:sat/f32\t$dst, $src", 0xfc01>, - Requires<[HasNontrappingFPToInt]>; -def I64_TRUNC_S_SAT_F32 : I<(outs I64:$dst), (ins F32:$src), - [(set I64:$dst, (fp_to_sint F32:$src))], - "i64.trunc_s:sat/f32\t$dst, $src", 0xfc04>, - Requires<[HasNontrappingFPToInt]>; -def I64_TRUNC_U_SAT_F32 : I<(outs I64:$dst), (ins F32:$src), - [(set I64:$dst, (fp_to_uint F32:$src))], - "i64.trunc_u:sat/f32\t$dst, $src", 0xfc05>, - Requires<[HasNontrappingFPToInt]>; -def I32_TRUNC_S_SAT_F64 : I<(outs I32:$dst), (ins F64:$src), - [(set I32:$dst, (fp_to_sint F64:$src))], - "i32.trunc_s:sat/f64\t$dst, $src", 0xfc02>, - Requires<[HasNontrappingFPToInt]>; -def I32_TRUNC_U_SAT_F64 : I<(outs I32:$dst), (ins F64:$src), - [(set I32:$dst, (fp_to_uint F64:$src))], - "i32.trunc_u:sat/f64\t$dst, $src", 0xfc03>, - Requires<[HasNontrappingFPToInt]>; -def I64_TRUNC_S_SAT_F64 : I<(outs I64:$dst), (ins F64:$src), - [(set I64:$dst, (fp_to_sint F64:$src))], - "i64.trunc_s:sat/f64\t$dst, $src", 0xfc06>, - Requires<[HasNontrappingFPToInt]>; -def I64_TRUNC_U_SAT_F64 : I<(outs I64:$dst), (ins F64:$src), - [(set I64:$dst, (fp_to_uint F64:$src))], - "i64.trunc_u:sat/f64\t$dst, $src", 0xfc07>, - Requires<[HasNontrappingFPToInt]>; +defm I32_TRUNC_S_SAT_F32 : I<(outs I32:$dst), (ins F32:$src), (outs), (ins), + [(set I32:$dst, (fp_to_sint F32:$src))], + "i32.trunc_s:sat/f32\t$dst, $src", + "i32.trunc_s:sat/f32", 0xfc00>, + Requires<[HasNontrappingFPToInt]>; +defm I32_TRUNC_U_SAT_F32 : I<(outs I32:$dst), (ins F32:$src), (outs), (ins), + [(set I32:$dst, (fp_to_uint F32:$src))], + "i32.trunc_u:sat/f32\t$dst, $src", + "i32.trunc_u:sat/f32", 0xfc01>, + Requires<[HasNontrappingFPToInt]>; +defm I64_TRUNC_S_SAT_F32 : I<(outs I64:$dst), (ins F32:$src), (outs), (ins), + [(set I64:$dst, (fp_to_sint F32:$src))], + "i64.trunc_s:sat/f32\t$dst, $src", + "i64.trunc_s:sat/f32", 0xfc04>, + Requires<[HasNontrappingFPToInt]>; +defm I64_TRUNC_U_SAT_F32 : I<(outs I64:$dst), (ins F32:$src), (outs), (ins), + [(set I64:$dst, (fp_to_uint F32:$src))], + "i64.trunc_u:sat/f32\t$dst, $src", + "i64.trunc_u:sat/f32", 0xfc05>, + Requires<[HasNontrappingFPToInt]>; +defm I32_TRUNC_S_SAT_F64 : I<(outs I32:$dst), (ins F64:$src), (outs), (ins), + [(set I32:$dst, (fp_to_sint F64:$src))], + "i32.trunc_s:sat/f64\t$dst, $src", + "i32.trunc_s:sat/f64", 0xfc02>, + Requires<[HasNontrappingFPToInt]>; +defm I32_TRUNC_U_SAT_F64 : I<(outs I32:$dst), (ins F64:$src), (outs), (ins), + [(set I32:$dst, (fp_to_uint F64:$src))], + "i32.trunc_u:sat/f64\t$dst, $src", + "i32.trunc_u:sat/f64", 0xfc03>, + Requires<[HasNontrappingFPToInt]>; +defm I64_TRUNC_S_SAT_F64 : I<(outs I64:$dst), (ins F64:$src), (outs), (ins), + [(set I64:$dst, (fp_to_sint F64:$src))], + "i64.trunc_s:sat/f64\t$dst, $src", + "i64.trunc_s:sat/f64", 0xfc06>, + Requires<[HasNontrappingFPToInt]>; +defm I64_TRUNC_U_SAT_F64 : I<(outs I64:$dst), (ins F64:$src), (outs), (ins), + [(set I64:$dst, (fp_to_uint F64:$src))], + "i64.trunc_u:sat/f64\t$dst, $src", + "i64.trunc_u:sat/f64", 0xfc07>, + Requires<[HasNontrappingFPToInt]>; // Conversion from floating point to integer pseudo-instructions which don't // trap on overflow or invalid. let usesCustomInserter = 1, isCodeGenOnly = 1 in { -def FP_TO_SINT_I32_F32 : I<(outs I32:$dst), (ins F32:$src), - [(set I32:$dst, (fp_to_sint F32:$src))], "", 0>, - Requires<[NotHasNontrappingFPToInt]>; -def FP_TO_UINT_I32_F32 : I<(outs I32:$dst), (ins F32:$src), - [(set I32:$dst, (fp_to_uint F32:$src))], "", 0>, - Requires<[NotHasNontrappingFPToInt]>; -def FP_TO_SINT_I64_F32 : I<(outs I64:$dst), (ins F32:$src), - [(set I64:$dst, (fp_to_sint F32:$src))], "", 0>, - Requires<[NotHasNontrappingFPToInt]>; -def FP_TO_UINT_I64_F32 : I<(outs I64:$dst), (ins F32:$src), - [(set I64:$dst, (fp_to_uint F32:$src))], "", 0>, - Requires<[NotHasNontrappingFPToInt]>; -def FP_TO_SINT_I32_F64 : I<(outs I32:$dst), (ins F64:$src), - [(set I32:$dst, (fp_to_sint F64:$src))], "", 0>, - Requires<[NotHasNontrappingFPToInt]>; -def FP_TO_UINT_I32_F64 : I<(outs I32:$dst), (ins F64:$src), - [(set I32:$dst, (fp_to_uint F64:$src))], "", 0>, - Requires<[NotHasNontrappingFPToInt]>; -def FP_TO_SINT_I64_F64 : I<(outs I64:$dst), (ins F64:$src), - [(set I64:$dst, (fp_to_sint F64:$src))], "", 0>, - Requires<[NotHasNontrappingFPToInt]>; -def FP_TO_UINT_I64_F64 : I<(outs I64:$dst), (ins F64:$src), - [(set I64:$dst, (fp_to_uint F64:$src))], "", 0>, - Requires<[NotHasNontrappingFPToInt]>; +defm FP_TO_SINT_I32_F32 : I<(outs I32:$dst), (ins F32:$src), (outs), (ins), + [(set I32:$dst, (fp_to_sint F32:$src))], "", "", 0>, + Requires<[NotHasNontrappingFPToInt]>; +defm FP_TO_UINT_I32_F32 : I<(outs I32:$dst), (ins F32:$src), (outs), (ins), + [(set I32:$dst, (fp_to_uint F32:$src))], "", "", 0>, + Requires<[NotHasNontrappingFPToInt]>; +defm FP_TO_SINT_I64_F32 : I<(outs I64:$dst), (ins F32:$src), (outs), (ins), + [(set I64:$dst, (fp_to_sint F32:$src))], "", "", 0>, + Requires<[NotHasNontrappingFPToInt]>; +defm FP_TO_UINT_I64_F32 : I<(outs I64:$dst), (ins F32:$src), (outs), (ins), + [(set I64:$dst, (fp_to_uint F32:$src))], "", "", 0>, + Requires<[NotHasNontrappingFPToInt]>; +defm FP_TO_SINT_I32_F64 : I<(outs I32:$dst), (ins F64:$src), (outs), (ins), + [(set I32:$dst, (fp_to_sint F64:$src))], "", "", 0>, + Requires<[NotHasNontrappingFPToInt]>; +defm FP_TO_UINT_I32_F64 : I<(outs I32:$dst), (ins F64:$src), (outs), (ins), + [(set I32:$dst, (fp_to_uint F64:$src))], "", "", 0>, + Requires<[NotHasNontrappingFPToInt]>; +defm FP_TO_SINT_I64_F64 : I<(outs I64:$dst), (ins F64:$src), (outs), (ins), + [(set I64:$dst, (fp_to_sint F64:$src))], "", "", 0>, + Requires<[NotHasNontrappingFPToInt]>; +defm FP_TO_UINT_I64_F64 : I<(outs I64:$dst), (ins F64:$src), (outs), (ins), + [(set I64:$dst, (fp_to_uint F64:$src))], "", "", 0>, + Requires<[NotHasNontrappingFPToInt]>; } // usesCustomInserter, isCodeGenOnly = 1 // Conversion from floating point to integer traps on overflow and invalid. let hasSideEffects = 1 in { -def I32_TRUNC_S_F32 : I<(outs I32:$dst), (ins F32:$src), - [], "i32.trunc_s/f32\t$dst, $src", 0xa8>; -def I32_TRUNC_U_F32 : I<(outs I32:$dst), (ins F32:$src), - [], "i32.trunc_u/f32\t$dst, $src", 0xa9>; -def I64_TRUNC_S_F32 : I<(outs I64:$dst), (ins F32:$src), - [], "i64.trunc_s/f32\t$dst, $src", 0xae>; -def I64_TRUNC_U_F32 : I<(outs I64:$dst), (ins F32:$src), - [], "i64.trunc_u/f32\t$dst, $src", 0xaf>; -def I32_TRUNC_S_F64 : I<(outs I32:$dst), (ins F64:$src), - [], "i32.trunc_s/f64\t$dst, $src", 0xaa>; -def I32_TRUNC_U_F64 : I<(outs I32:$dst), (ins F64:$src), - [], "i32.trunc_u/f64\t$dst, $src", 0xab>; -def I64_TRUNC_S_F64 : I<(outs I64:$dst), (ins F64:$src), - [], "i64.trunc_s/f64\t$dst, $src", 0xb0>; -def I64_TRUNC_U_F64 : I<(outs I64:$dst), (ins F64:$src), - [], "i64.trunc_u/f64\t$dst, $src", 0xb1>; +defm I32_TRUNC_S_F32 : I<(outs I32:$dst), (ins F32:$src), (outs), (ins), + [], "i32.trunc_s/f32\t$dst, $src", "i32.trunc_s/f32", + 0xa8>; +defm I32_TRUNC_U_F32 : I<(outs I32:$dst), (ins F32:$src), (outs), (ins), + [], "i32.trunc_u/f32\t$dst, $src", "i32.trunc_u/f32", + 0xa9>; +defm I64_TRUNC_S_F32 : I<(outs I64:$dst), (ins F32:$src), (outs), (ins), + [], "i64.trunc_s/f32\t$dst, $src", "i64.trunc_s/f32", + 0xae>; +defm I64_TRUNC_U_F32 : I<(outs I64:$dst), (ins F32:$src), (outs), (ins), + [], "i64.trunc_u/f32\t$dst, $src", "i64.trunc_u/f32", + 0xaf>; +defm I32_TRUNC_S_F64 : I<(outs I32:$dst), (ins F64:$src), (outs), (ins), + [], "i32.trunc_s/f64\t$dst, $src", "i32.trunc_s/f64", + 0xaa>; +defm I32_TRUNC_U_F64 : I<(outs I32:$dst), (ins F64:$src), (outs), (ins), + [], "i32.trunc_u/f64\t$dst, $src", "i32.trunc_u/f64", + 0xab>; +defm I64_TRUNC_S_F64 : I<(outs I64:$dst), (ins F64:$src), (outs), (ins), + [], "i64.trunc_s/f64\t$dst, $src", "i64.trunc_s/f64", + 0xb0>; +defm I64_TRUNC_U_F64 : I<(outs I64:$dst), (ins F64:$src), (outs), (ins), + [], "i64.trunc_u/f64\t$dst, $src", "i64.trunc_u/f64", + 0xb1>; } // hasSideEffects = 1 -def F32_CONVERT_S_I32 : I<(outs F32:$dst), (ins I32:$src), - [(set F32:$dst, (sint_to_fp I32:$src))], - "f32.convert_s/i32\t$dst, $src", 0xb2>; -def F32_CONVERT_U_I32 : I<(outs F32:$dst), (ins I32:$src), - [(set F32:$dst, (uint_to_fp I32:$src))], - "f32.convert_u/i32\t$dst, $src", 0xb3>; -def F64_CONVERT_S_I32 : I<(outs F64:$dst), (ins I32:$src), - [(set F64:$dst, (sint_to_fp I32:$src))], - "f64.convert_s/i32\t$dst, $src", 0xb7>; -def F64_CONVERT_U_I32 : I<(outs F64:$dst), (ins I32:$src), - [(set F64:$dst, (uint_to_fp I32:$src))], - "f64.convert_u/i32\t$dst, $src", 0xb8>; -def F32_CONVERT_S_I64 : I<(outs F32:$dst), (ins I64:$src), - [(set F32:$dst, (sint_to_fp I64:$src))], - "f32.convert_s/i64\t$dst, $src", 0xb4>; -def F32_CONVERT_U_I64 : I<(outs F32:$dst), (ins I64:$src), - [(set F32:$dst, (uint_to_fp I64:$src))], - "f32.convert_u/i64\t$dst, $src", 0xb5>; -def F64_CONVERT_S_I64 : I<(outs F64:$dst), (ins I64:$src), - [(set F64:$dst, (sint_to_fp I64:$src))], - "f64.convert_s/i64\t$dst, $src", 0xb9>; -def F64_CONVERT_U_I64 : I<(outs F64:$dst), (ins I64:$src), - [(set F64:$dst, (uint_to_fp I64:$src))], - "f64.convert_u/i64\t$dst, $src", 0xba>; +defm F32_CONVERT_S_I32 : I<(outs F32:$dst), (ins I32:$src), (outs), (ins), + [(set F32:$dst, (sint_to_fp I32:$src))], + "f32.convert_s/i32\t$dst, $src", "f32.convert_s/i32", + 0xb2>; +defm F32_CONVERT_U_I32 : I<(outs F32:$dst), (ins I32:$src), (outs), (ins), + [(set F32:$dst, (uint_to_fp I32:$src))], + "f32.convert_u/i32\t$dst, $src", "f32.convert_u/i32", + 0xb3>; +defm F64_CONVERT_S_I32 : I<(outs F64:$dst), (ins I32:$src), (outs), (ins), + [(set F64:$dst, (sint_to_fp I32:$src))], + "f64.convert_s/i32\t$dst, $src", "f64.convert_s/i32", + 0xb7>; +defm F64_CONVERT_U_I32 : I<(outs F64:$dst), (ins I32:$src), (outs), (ins), + [(set F64:$dst, (uint_to_fp I32:$src))], + "f64.convert_u/i32\t$dst, $src", "f64.convert_u/i32", + 0xb8>; +defm F32_CONVERT_S_I64 : I<(outs F32:$dst), (ins I64:$src), (outs), (ins), + [(set F32:$dst, (sint_to_fp I64:$src))], + "f32.convert_s/i64\t$dst, $src", "f32.convert_s/i64", + 0xb4>; +defm F32_CONVERT_U_I64 : I<(outs F32:$dst), (ins I64:$src), (outs), (ins), + [(set F32:$dst, (uint_to_fp I64:$src))], + "f32.convert_u/i64\t$dst, $src", "f32.convert_u/i64", + 0xb5>; +defm F64_CONVERT_S_I64 : I<(outs F64:$dst), (ins I64:$src), (outs), (ins), + [(set F64:$dst, (sint_to_fp I64:$src))], + "f64.convert_s/i64\t$dst, $src", "f64.convert_s/i64", + 0xb9>; +defm F64_CONVERT_U_I64 : I<(outs F64:$dst), (ins I64:$src), (outs), (ins), + [(set F64:$dst, (uint_to_fp I64:$src))], + "f64.convert_u/i64\t$dst, $src", "f64.convert_u/i64", + 0xba>; -def F64_PROMOTE_F32 : I<(outs F64:$dst), (ins F32:$src), - [(set F64:$dst, (fpextend F32:$src))], - "f64.promote/f32\t$dst, $src", 0xbb>; -def F32_DEMOTE_F64 : I<(outs F32:$dst), (ins F64:$src), - [(set F32:$dst, (fpround F64:$src))], - "f32.demote/f64\t$dst, $src", 0xb6>; +defm F64_PROMOTE_F32 : I<(outs F64:$dst), (ins F32:$src), (outs), (ins), + [(set F64:$dst, (fpextend F32:$src))], + "f64.promote/f32\t$dst, $src", "f64.promote/f32", + 0xbb>; +defm F32_DEMOTE_F64 : I<(outs F32:$dst), (ins F64:$src), (outs), (ins), + [(set F32:$dst, (fpround F64:$src))], + "f32.demote/f64\t$dst, $src", "f32.demote/f64", + 0xb6>; -def I32_REINTERPRET_F32 : I<(outs I32:$dst), (ins F32:$src), - [(set I32:$dst, (bitconvert F32:$src))], - "i32.reinterpret/f32\t$dst, $src", 0xbc>; -def F32_REINTERPRET_I32 : I<(outs F32:$dst), (ins I32:$src), - [(set F32:$dst, (bitconvert I32:$src))], - "f32.reinterpret/i32\t$dst, $src", 0xbe>; -def I64_REINTERPRET_F64 : I<(outs I64:$dst), (ins F64:$src), - [(set I64:$dst, (bitconvert F64:$src))], - "i64.reinterpret/f64\t$dst, $src", 0xbd>; -def F64_REINTERPRET_I64 : I<(outs F64:$dst), (ins I64:$src), - [(set F64:$dst, (bitconvert I64:$src))], - "f64.reinterpret/i64\t$dst, $src", 0xbf>; +defm I32_REINTERPRET_F32 : I<(outs I32:$dst), (ins F32:$src), (outs), (ins), + [(set I32:$dst, (bitconvert F32:$src))], + "i32.reinterpret/f32\t$dst, $src", + "i32.reinterpret/f32", 0xbc>; +defm F32_REINTERPRET_I32 : I<(outs F32:$dst), (ins I32:$src), (outs), (ins), + [(set F32:$dst, (bitconvert I32:$src))], + "f32.reinterpret/i32\t$dst, $src", + "f32.reinterpret/i32", 0xbe>; +defm I64_REINTERPRET_F64 : I<(outs I64:$dst), (ins F64:$src), (outs), (ins), + [(set I64:$dst, (bitconvert F64:$src))], + "i64.reinterpret/f64\t$dst, $src", + "i64.reinterpret/f64", 0xbd>; +defm F64_REINTERPRET_I64 : I<(outs F64:$dst), (ins I64:$src), (outs), (ins), + [(set F64:$dst, (bitconvert I64:$src))], + "f64.reinterpret/i64\t$dst, $src", + "f64.reinterpret/i64", 0xbf>; } // Defs = [ARGUMENTS] Index: lib/Target/WebAssembly/WebAssemblyInstrExceptRef.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrExceptRef.td +++ lib/Target/WebAssembly/WebAssemblyInstrExceptRef.td @@ -14,12 +14,14 @@ let Defs = [ARGUMENTS] in { -def SELECT_EXCEPT_REF : I<(outs EXCEPT_REF:$dst), - (ins EXCEPT_REF:$lhs, EXCEPT_REF:$rhs, I32:$cond), - [(set EXCEPT_REF:$dst, - (select I32:$cond, EXCEPT_REF:$lhs, - EXCEPT_REF:$rhs))], - "except_ref.select\t$dst, $lhs, $rhs, $cond", 0x1b>; +defm SELECT_EXCEPT_REF : I<(outs EXCEPT_REF:$dst), + (ins EXCEPT_REF:$lhs, EXCEPT_REF:$rhs, I32:$cond), + (outs), (ins), + [(set EXCEPT_REF:$dst, + (select I32:$cond, EXCEPT_REF:$lhs, + EXCEPT_REF:$rhs))], + "except_ref.select\t$dst, $lhs, $rhs, $cond", + "except_ref.select", 0x1b>; } // Defs = [ARGUMENTS] Index: lib/Target/WebAssembly/WebAssemblyInstrFloat.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrFloat.td +++ lib/Target/WebAssembly/WebAssemblyInstrFloat.td @@ -77,12 +77,14 @@ let Defs = [ARGUMENTS] in { -def SELECT_F32 : I<(outs F32:$dst), (ins F32:$lhs, F32:$rhs, I32:$cond), - [(set F32:$dst, (select I32:$cond, F32:$lhs, F32:$rhs))], - "f32.select\t$dst, $lhs, $rhs, $cond", 0x1b>; -def SELECT_F64 : I<(outs F64:$dst), (ins F64:$lhs, F64:$rhs, I32:$cond), - [(set F64:$dst, (select I32:$cond, F64:$lhs, F64:$rhs))], - "f64.select\t$dst, $lhs, $rhs, $cond", 0x1b>; +defm SELECT_F32 : I<(outs F32:$dst), (ins F32:$lhs, F32:$rhs, I32:$cond), + (outs), (ins), + [(set F32:$dst, (select I32:$cond, F32:$lhs, F32:$rhs))], + "f32.select\t$dst, $lhs, $rhs, $cond", "f32.select", 0x1b>; +defm SELECT_F64 : I<(outs F64:$dst), (ins F64:$lhs, F64:$rhs, I32:$cond), + (outs), (ins), + [(set F64:$dst, (select I32:$cond, F64:$lhs, F64:$rhs))], + "f64.select\t$dst, $lhs, $rhs, $cond", "f64.select", 0x1b>; } // Defs = [ARGUMENTS] Index: lib/Target/WebAssembly/WebAssemblyInstrFormats.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrFormats.td +++ lib/Target/WebAssembly/WebAssemblyInstrFormats.td @@ -13,94 +13,155 @@ //===----------------------------------------------------------------------===// // WebAssembly Instruction Format. -class WebAssemblyInst inst, string asmstr> : Instruction { +// We instantiate 2 of these for every actual instruction (register based +// and stack based), see below. +class WebAssemblyInst inst, string asmstr, bit stack> : Instruction { field bits<32> Inst = inst; // Instruction encoding. + field bit StackBased = stack; let Namespace = "WebAssembly"; let Pattern = []; let AsmString = asmstr; } -// Normal instructions. -class I pattern, string asmstr = "", bits<32> inst = -1> - : WebAssemblyInst { +// Normal instructions. Default instantiation of a WebAssemblyInst. +class NI pattern, bit stack, string asmstr = "", + bits<32> inst = -1> + : WebAssemblyInst { dag OutOperandList = oops; dag InOperandList = iops; let Pattern = pattern; } -class SIMD_I pattern, - string asmstr = "", bits<32> inst = -1> - : I, Requires<[HasSIMD128]>; +// Generates both register and stack based versions of one actual instruction. +// We have 2 sets of operands (oops & iops) for the register and stack +// based version of this instruction, as well as the corresponding asmstr. +// The register versions have virtual-register operands which correspond to wasm +// locals or stack locations. Each use and def of the register corresponds to an +// implicit get_local / set_local or access of stack operands in wasm. These +// instructions are used for ISel and all MI passes. The stack versions of the +// instructions do not have register operands (they implicitly operate on the +// stack), and get_locals and set_locals are explicit. The register instructions +// are converted to their corresponding stack instructions before lowering to +// MC. +// Every instruction should want to be based on this multi-class to guarantee +// there is always an equivalent pair of instructions. +multiclass I pattern_r, string asmstr_r = "", string asmstr_s = "", + bits<32> inst = -1> { + def "" : NI; + def _S : NI; +} + +// For instructions that have no register ops, so both sets are the same. +multiclass NRI pattern, string asmstr = "", + bits<32> inst = -1> { + defm "": I; +} -class ATOMIC_I pattern, - string asmstr = "", bits<32> inst = -1> - : I, Requires<[HasAtomics]>; +multiclass SIMD_I pattern_r, string asmstr_r = "", + string asmstr_s = "", bits<32> inst = -1> { + defm "" : I, + Requires<[HasSIMD128]>; +} + +multiclass ATOMIC_I pattern_r, string asmstr_r = "", + string asmstr_s = "", bits<32> inst = -1> { + defm "" : I, + Requires<[HasAtomics]>; +} // Unary and binary instructions, for the local types that WebAssembly supports. -multiclass UnaryInt i32Inst, bits<32> i64Inst> { - def _I32 : I<(outs I32:$dst), (ins I32:$src), - [(set I32:$dst, (node I32:$src))], - !strconcat("i32.", !strconcat(name, "\t$dst, $src")), i32Inst>; - def _I64 : I<(outs I64:$dst), (ins I64:$src), - [(set I64:$dst, (node I64:$src))], - !strconcat("i64.", !strconcat(name, "\t$dst, $src")), i64Inst>; +multiclass UnaryInt i32Inst, + bits<32> i64Inst> { + defm _I32 : I<(outs I32:$dst), (ins I32:$src), (outs), (ins), + [(set I32:$dst, (node I32:$src))], + !strconcat("i32.", !strconcat(name, "\t$dst, $src")), + !strconcat("i32.", name), i32Inst>; + defm _I64 : I<(outs I64:$dst), (ins I64:$src), (outs), (ins), + [(set I64:$dst, (node I64:$src))], + !strconcat("i64.", !strconcat(name, "\t$dst, $src")), + !strconcat("i64.", name), i64Inst>; } -multiclass BinaryInt i32Inst, bits<32> i64Inst> { - def _I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs), - [(set I32:$dst, (node I32:$lhs, I32:$rhs))], - !strconcat("i32.", !strconcat(name, "\t$dst, $lhs, $rhs")), i32Inst>; - def _I64 : I<(outs I64:$dst), (ins I64:$lhs, I64:$rhs), - [(set I64:$dst, (node I64:$lhs, I64:$rhs))], - !strconcat("i64.", !strconcat(name, "\t$dst, $lhs, $rhs")), i64Inst>; +multiclass BinaryInt i32Inst, + bits<32> i64Inst> { + defm _I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs), (outs), (ins), + [(set I32:$dst, (node I32:$lhs, I32:$rhs))], + !strconcat("i32.", !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("i32.", name), i32Inst>; + defm _I64 : I<(outs I64:$dst), (ins I64:$lhs, I64:$rhs), (outs), (ins), + [(set I64:$dst, (node I64:$lhs, I64:$rhs))], + !strconcat("i64.", !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("i64.", name), i64Inst>; } -multiclass UnaryFP f32Inst, bits<32> f64Inst> { - def _F32 : I<(outs F32:$dst), (ins F32:$src), - [(set F32:$dst, (node F32:$src))], - !strconcat("f32.", !strconcat(name, "\t$dst, $src")), f32Inst>; - def _F64 : I<(outs F64:$dst), (ins F64:$src), - [(set F64:$dst, (node F64:$src))], - !strconcat("f64.", !strconcat(name, "\t$dst, $src")), f64Inst>; +multiclass UnaryFP f32Inst, + bits<32> f64Inst> { + defm _F32 : I<(outs F32:$dst), (ins F32:$src), (outs), (ins), + [(set F32:$dst, (node F32:$src))], + !strconcat("f32.", !strconcat(name, "\t$dst, $src")), + !strconcat("f32.", name), f32Inst>; + defm _F64 : I<(outs F64:$dst), (ins F64:$src), (outs), (ins), + [(set F64:$dst, (node F64:$src))], + !strconcat("f64.", !strconcat(name, "\t$dst, $src")), + !strconcat("f64.", name), f64Inst>; } -multiclass BinaryFP f32Inst, bits<32> f64Inst> { - def _F32 : I<(outs F32:$dst), (ins F32:$lhs, F32:$rhs), - [(set F32:$dst, (node F32:$lhs, F32:$rhs))], - !strconcat("f32.", !strconcat(name, "\t$dst, $lhs, $rhs")), f32Inst>; - def _F64 : I<(outs F64:$dst), (ins F64:$lhs, F64:$rhs), - [(set F64:$dst, (node F64:$lhs, F64:$rhs))], - !strconcat("f64.", !strconcat(name, "\t$dst, $lhs, $rhs")), f64Inst>; +multiclass BinaryFP f32Inst, + bits<32> f64Inst> { + defm _F32 : I<(outs F32:$dst), (ins F32:$lhs, F32:$rhs), (outs), (ins), + [(set F32:$dst, (node F32:$lhs, F32:$rhs))], + !strconcat("f32.", !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("f32.", name), f32Inst>; + defm _F64 : I<(outs F64:$dst), (ins F64:$lhs, F64:$rhs), (outs), (ins), + [(set F64:$dst, (node F64:$lhs, F64:$rhs))], + !strconcat("f64.", !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("f64.", name), f64Inst>; } multiclass SIMDBinary { - def _I8x16 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), - [(set (v16i8 V128:$dst), (node V128:$lhs, V128:$rhs))], - !strconcat("i8x16.", !strconcat(name, "\t$dst, $lhs, $rhs"))>; - def _I16x8 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), - [(set (v8i16 V128:$dst), (node V128:$lhs, V128:$rhs))], - !strconcat("i16x8.", !strconcat(name, "\t$dst, $lhs, $rhs"))>; - def _I32x4 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), - [(set (v4i32 V128:$dst), (node V128:$lhs, V128:$rhs))], - !strconcat("i32x4.", !strconcat(name, "\t$dst, $lhs, $rhs"))>; - def _F32x4 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), - [(set (v4f32 V128:$dst), (fnode V128:$lhs, V128:$rhs))], - !strconcat("f32x4.", !strconcat(name, "\t$dst, $lhs, $rhs"))>; - + defm _I8x16 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), + (outs), (ins), + [(set (v16i8 V128:$dst), (node V128:$lhs, V128:$rhs))], + !strconcat("i8x16.", + !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("i8x16.", name)>; + defm _I16x8 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), + (outs), (ins), + [(set (v8i16 V128:$dst), (node V128:$lhs, V128:$rhs))], + !strconcat("i16x8.", + !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("i16x8.", name)>; + defm _I32x4 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), + (outs), (ins), + [(set (v4i32 V128:$dst), (node V128:$lhs, V128:$rhs))], + !strconcat("i32x4.", + !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("i32x4.", name)>; + defm _F32x4 : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), + (outs), (ins), + [(set (v4f32 V128:$dst), (fnode V128:$lhs, V128:$rhs))], + !strconcat("f32x4.", + !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("f32x4.", name)>; } multiclass ComparisonInt i32Inst, bits<32> i64Inst> { - def _I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs), - [(set I32:$dst, (setcc I32:$lhs, I32:$rhs, cond))], - !strconcat("i32.", !strconcat(name, "\t$dst, $lhs, $rhs")), - i32Inst>; - def _I64 : I<(outs I32:$dst), (ins I64:$lhs, I64:$rhs), - [(set I32:$dst, (setcc I64:$lhs, I64:$rhs, cond))], - !strconcat("i64.", !strconcat(name, "\t$dst, $lhs, $rhs")), - i64Inst>; + defm _I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs), (outs), (ins), + [(set I32:$dst, (setcc I32:$lhs, I32:$rhs, cond))], + !strconcat("i32.", !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("i32.", name), i32Inst>; + defm _I64 : I<(outs I32:$dst), (ins I64:$lhs, I64:$rhs), (outs), (ins), + [(set I32:$dst, (setcc I64:$lhs, I64:$rhs, cond))], + !strconcat("i64.", !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("i64.", name), i64Inst>; } multiclass ComparisonFP f32Inst, bits<32> f64Inst> { - def _F32 : I<(outs I32:$dst), (ins F32:$lhs, F32:$rhs), - [(set I32:$dst, (setcc F32:$lhs, F32:$rhs, cond))], - !strconcat("f32.", !strconcat(name, "\t$dst, $lhs, $rhs")), - f32Inst>; - def _F64 : I<(outs I32:$dst), (ins F64:$lhs, F64:$rhs), - [(set I32:$dst, (setcc F64:$lhs, F64:$rhs, cond))], - !strconcat("f64.", !strconcat(name, "\t$dst, $lhs, $rhs")), - f64Inst>; + defm _F32 : I<(outs I32:$dst), (ins F32:$lhs, F32:$rhs), (outs), (ins), + [(set I32:$dst, (setcc F32:$lhs, F32:$rhs, cond))], + !strconcat("f32.", !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("f32.", name), f32Inst>; + defm _F64 : I<(outs I32:$dst), (ins F64:$lhs, F64:$rhs), (outs), (ins), + [(set I32:$dst, (setcc F64:$lhs, F64:$rhs, cond))], + !strconcat("f64.", !strconcat(name, "\t$dst, $lhs, $rhs")), + !strconcat("f64.", name), f64Inst>; } Index: lib/Target/WebAssembly/WebAssemblyInstrInfo.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -153,13 +153,15 @@ multiclass ARGUMENT { let hasSideEffects = 1, Uses = [ARGUMENTS], isCodeGenOnly = 1 in - def ARGUMENT_#vt : I<(outs vt:$res), (ins i32imm:$argno), - [(set vt:$res, (WebAssemblyargument timm:$argno))]>; + defm ARGUMENT_#vt : I<(outs vt:$res), (ins i32imm:$argno), + (outs), (ins i32imm:$argno), + [(set vt:$res, (WebAssemblyargument timm:$argno))]>; } multiclass SIMD_ARGUMENT { let hasSideEffects = 1, Uses = [ARGUMENTS], isCodeGenOnly = 1 in - def ARGUMENT_#vt : SIMD_I<(outs V128:$res), (ins i32imm:$argno), - [(set (vt V128:$res), + defm ARGUMENT_#vt : SIMD_I<(outs V128:$res), (ins i32imm:$argno), + (outs), (ins i32imm:$argno), + [(set (vt V128:$res), (WebAssemblyargument timm:$argno))]>; } defm "": ARGUMENT; @@ -184,47 +186,56 @@ // and set_local. COPYs are eliminated (and replaced with // get_local/set_local) in the ExplicitLocals pass. let isAsCheapAsAMove = 1, isCodeGenOnly = 1 in - def COPY_#vt : I<(outs vt:$res), (ins vt:$src), [], "copy_local\t$res, $src">; + defm COPY_#vt : I<(outs vt:$res), (ins vt:$src), (outs), (ins), [], + "copy_local\t$res, $src", "copy_local">; // TEE is similar to COPY, but writes two copies of its result. Typically // this would be used to stackify one result and write the other result to a // local. let isAsCheapAsAMove = 1, isCodeGenOnly = 1 in - def TEE_#vt : I<(outs vt:$res, vt:$also), (ins vt:$src), [], - "tee_local\t$res, $also, $src">; + defm TEE_#vt : I<(outs vt:$res, vt:$also), (ins vt:$src), (outs), (ins), [], + "tee_local\t$res, $also, $src", "tee_local">; // This is the actual get_local instruction in wasm. These are made explicit // by the ExplicitLocals pass. It has mayLoad because it reads from a wasm // local, which is a side effect not otherwise modeled in LLVM. let mayLoad = 1, isAsCheapAsAMove = 1 in - def GET_LOCAL_#vt : I<(outs vt:$res), (ins local_op:$local), [], - "get_local\t$res, $local", 0x20>; + defm GET_LOCAL_#vt : I<(outs vt:$res), (ins local_op:$local), + (outs), (ins local_op:$local), [], + "get_local\t$res, $local", "get_local\t$local", 0x20>; // This is the actual set_local instruction in wasm. These are made explicit // by the ExplicitLocals pass. It has mayStore because it writes to a wasm // local, which is a side effect not otherwise modeled in LLVM. let mayStore = 1, isAsCheapAsAMove = 1 in - def SET_LOCAL_#vt : I<(outs), (ins local_op:$local, vt:$src), [], - "set_local\t$local, $src", 0x21>; + defm SET_LOCAL_#vt : I<(outs), (ins local_op:$local, vt:$src), + (outs), (ins local_op:$local), [], + "set_local\t$local, $src", "set_local\t$local", 0x21>; // This is the actual tee_local instruction in wasm. TEEs are turned into // TEE_LOCALs by the ExplicitLocals pass. It has mayStore for the same reason // as SET_LOCAL. let mayStore = 1, isAsCheapAsAMove = 1 in - def TEE_LOCAL_#vt : I<(outs vt:$res), (ins local_op:$local, vt:$src), [], - "tee_local\t$res, $local, $src", 0x22>; + defm TEE_LOCAL_#vt : I<(outs vt:$res), (ins local_op:$local, vt:$src), + (outs), (ins local_op:$local), [], + "tee_local\t$res, $local, $src", "tee_local\t$local", + 0x22>; // Unused values must be dropped in some contexts. - def DROP_#vt : I<(outs), (ins vt:$src), [], - "drop\t$src", 0x1a>; + defm DROP_#vt : I<(outs), (ins vt:$src), (outs), (ins), [], + "drop\t$src", "drop", 0x1a>; let mayLoad = 1 in - def GET_GLOBAL_#vt : I<(outs vt:$res), (ins global_op:$local), [], - "get_global\t$res, $local", 0x23>; + defm GET_GLOBAL_#vt : I<(outs vt:$res), (ins global_op:$local), + (outs), (ins global_op:$local), [], + "get_global\t$res, $local", "get_global\t$local", + 0x23>; let mayStore = 1 in - def SET_GLOBAL_#vt : I<(outs), (ins global_op:$local, vt:$src), [], - "set_global\t$local, $src", 0x24>; + defm SET_GLOBAL_#vt : I<(outs), (ins global_op:$local, vt:$src), + (outs), (ins global_op:$local), [], + "set_global\t$local, $src", "set_global\t$local", + 0x24>; } // hasSideEffects = 0 } @@ -236,18 +247,22 @@ defm "" : LOCAL, Requires<[HasExceptionHandling]>; let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1 in { -def CONST_I32 : I<(outs I32:$res), (ins i32imm_op:$imm), - [(set I32:$res, imm:$imm)], - "i32.const\t$res, $imm", 0x41>; -def CONST_I64 : I<(outs I64:$res), (ins i64imm_op:$imm), - [(set I64:$res, imm:$imm)], - "i64.const\t$res, $imm", 0x42>; -def CONST_F32 : I<(outs F32:$res), (ins f32imm_op:$imm), - [(set F32:$res, fpimm:$imm)], - "f32.const\t$res, $imm", 0x43>; -def CONST_F64 : I<(outs F64:$res), (ins f64imm_op:$imm), - [(set F64:$res, fpimm:$imm)], - "f64.const\t$res, $imm", 0x44>; +defm CONST_I32 : I<(outs I32:$res), (ins i32imm_op:$imm), + (outs), (ins i32imm_op:$imm), + [(set I32:$res, imm:$imm)], + "i32.const\t$res, $imm", "i32.const\t$imm", 0x41>; +defm CONST_I64 : I<(outs I64:$res), (ins i64imm_op:$imm), + (outs), (ins i64imm_op:$imm), + [(set I64:$res, imm:$imm)], + "i64.const\t$res, $imm", "i64.const\t$imm", 0x42>; +defm CONST_F32 : I<(outs F32:$res), (ins f32imm_op:$imm), + (outs), (ins f32imm_op:$imm), + [(set F32:$res, fpimm:$imm)], + "f32.const\t$res, $imm", "f32.const\t$imm", 0x43>; +defm CONST_F64 : I<(outs F64:$res), (ins f64imm_op:$imm), + (outs), (ins f64imm_op:$imm), + [(set F64:$res, fpimm:$imm)], + "f64.const\t$res, $imm", "f64.const\t$imm", 0x44>; } // isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1 } // Defs = [ARGUMENTS] Index: lib/Target/WebAssembly/WebAssemblyInstrInteger.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrInteger.td +++ lib/Target/WebAssembly/WebAssemblyInstrInteger.td @@ -56,12 +56,12 @@ defm CTZ : UnaryInt; defm POPCNT : UnaryInt; -def EQZ_I32 : I<(outs I32:$dst), (ins I32:$src), - [(set I32:$dst, (setcc I32:$src, 0, SETEQ))], - "i32.eqz \t$dst, $src", 0x45>; -def EQZ_I64 : I<(outs I32:$dst), (ins I64:$src), - [(set I32:$dst, (setcc I64:$src, 0, SETEQ))], - "i64.eqz \t$dst, $src", 0x50>; +defm EQZ_I32 : I<(outs I32:$dst), (ins I32:$src), (outs), (ins), + [(set I32:$dst, (setcc I32:$src, 0, SETEQ))], + "i32.eqz \t$dst, $src", "i32.eqz", 0x45>; +defm EQZ_I64 : I<(outs I32:$dst), (ins I64:$src), (outs), (ins), + [(set I32:$dst, (setcc I64:$src, 0, SETEQ))], + "i64.eqz \t$dst, $src", "i64.eqz", 0x50>; } // Defs = [ARGUMENTS] @@ -73,12 +73,14 @@ let Defs = [ARGUMENTS] in { -def SELECT_I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs, I32:$cond), - [(set I32:$dst, (select I32:$cond, I32:$lhs, I32:$rhs))], - "i32.select\t$dst, $lhs, $rhs, $cond", 0x1b>; -def SELECT_I64 : I<(outs I64:$dst), (ins I64:$lhs, I64:$rhs, I32:$cond), - [(set I64:$dst, (select I32:$cond, I64:$lhs, I64:$rhs))], - "i64.select\t$dst, $lhs, $rhs, $cond", 0x1b>; +defm SELECT_I32 : I<(outs I32:$dst), (ins I32:$lhs, I32:$rhs, I32:$cond), + (outs), (ins), + [(set I32:$dst, (select I32:$cond, I32:$lhs, I32:$rhs))], + "i32.select\t$dst, $lhs, $rhs, $cond", "i32.select", 0x1b>; +defm SELECT_I64 : I<(outs I64:$dst), (ins I64:$lhs, I64:$rhs, I32:$cond), + (outs), (ins), + [(set I64:$dst, (select I32:$cond, I64:$lhs, I64:$rhs))], + "i64.select\t$dst, $lhs, $rhs, $cond", "i64.select", 0x1b>; } // Defs = [ARGUMENTS] Index: lib/Target/WebAssembly/WebAssemblyInstrMemory.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrMemory.td +++ lib/Target/WebAssembly/WebAssemblyInstrMemory.td @@ -56,23 +56,26 @@ let Defs = [ARGUMENTS] in { // Defines atomic and non-atomic loads, regular and extending. -class WebAssemblyLoad : - I<(outs rc:$dst), - (ins P2Align:$p2align, offset32_op:$off, I32:$addr), - [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"), Opcode>; +multiclass WebAssemblyLoad { + defm "": I<(outs rc:$dst), + (ins P2Align:$p2align, offset32_op:$off, I32:$addr), + (outs), (ins P2Align:$p2align, offset32_op:$off), + [], !strconcat(Name, "\t$dst, ${off}(${addr})${p2align}"), + !strconcat(Name, "\t${off}, ${p2align}"), Opcode>; +} // Basic load. // FIXME: When we can break syntax compatibility, reorder the fields in the // asmstrings to match the binary encoding. -def LOAD_I32 : WebAssemblyLoad; -def LOAD_I64 : WebAssemblyLoad; -def LOAD_F32 : WebAssemblyLoad; -def LOAD_F64 : WebAssemblyLoad; +defm LOAD_I32 : WebAssemblyLoad; +defm LOAD_I64 : WebAssemblyLoad; +defm LOAD_F32 : WebAssemblyLoad; +defm LOAD_F64 : WebAssemblyLoad; } // Defs = [ARGUMENTS] // Select loads with no constant offset. -class LoadPatNoOffset : +class LoadPatNoOffset : Pat<(ty (node I32:$addr)), (inst 0, 0, $addr)>; def : LoadPatNoOffset; @@ -84,7 +87,7 @@ // Select loads with a constant offset. // Pattern with address + immediate offset -class LoadPatImmOff : +class LoadPatImmOff : Pat<(ty (loadkind (operand I32:$addr, imm:$off))), (inst 0, imm:$off, $addr)>; @@ -97,7 +100,7 @@ def : LoadPatImmOff; def : LoadPatImmOff; -class LoadPatGlobalAddr : +class LoadPatGlobalAddr : Pat<(ty (loadkind (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off)))), (inst 0, tglobaladdr:$off, $addr)>; @@ -106,7 +109,7 @@ def : LoadPatGlobalAddr; def : LoadPatGlobalAddr; -class LoadPatExternalSym : +class LoadPatExternalSym : Pat<(ty (loadkind (add I32:$addr, (WebAssemblywrapper texternalsym:$off)))), (inst 0, texternalsym:$off, $addr)>; def : LoadPatExternalSym; @@ -116,7 +119,7 @@ // Select loads with just a constant offset. -class LoadPatOffsetOnly : +class LoadPatOffsetOnly : Pat<(ty (loadkind imm:$off)), (inst 0, imm:$off, (CONST_I32 0))>; def : LoadPatOffsetOnly; @@ -124,7 +127,7 @@ def : LoadPatOffsetOnly; def : LoadPatOffsetOnly; -class LoadPatGlobalAddrOffOnly : +class LoadPatGlobalAddrOffOnly : Pat<(ty (loadkind (WebAssemblywrapper tglobaladdr:$off))), (inst 0, tglobaladdr:$off, (CONST_I32 0))>; @@ -133,7 +136,7 @@ def : LoadPatGlobalAddrOffOnly; def : LoadPatGlobalAddrOffOnly; -class LoadPatExternSymOffOnly : +class LoadPatExternSymOffOnly : Pat<(ty (loadkind (WebAssemblywrapper texternalsym:$off))), (inst 0, texternalsym:$off, (CONST_I32 0))>; def : LoadPatExternSymOffOnly; @@ -144,16 +147,16 @@ let Defs = [ARGUMENTS] in { // Extending load. -def LOAD8_S_I32 : WebAssemblyLoad; -def LOAD8_U_I32 : WebAssemblyLoad; -def LOAD16_S_I32 : WebAssemblyLoad; -def LOAD16_U_I32 : WebAssemblyLoad; -def LOAD8_S_I64 : WebAssemblyLoad; -def LOAD8_U_I64 : WebAssemblyLoad; -def LOAD16_S_I64 : WebAssemblyLoad; -def LOAD16_U_I64 : WebAssemblyLoad; -def LOAD32_S_I64 : WebAssemblyLoad; -def LOAD32_U_I64 : WebAssemblyLoad; +defm LOAD8_S_I32 : WebAssemblyLoad; +defm LOAD8_U_I32 : WebAssemblyLoad; +defm LOAD16_S_I32 : WebAssemblyLoad; +defm LOAD16_U_I32 : WebAssemblyLoad; +defm LOAD8_S_I64 : WebAssemblyLoad; +defm LOAD8_U_I64 : WebAssemblyLoad; +defm LOAD16_S_I64 : WebAssemblyLoad; +defm LOAD16_U_I64 : WebAssemblyLoad; +defm LOAD32_S_I64 : WebAssemblyLoad; +defm LOAD32_U_I64 : WebAssemblyLoad; } // Defs = [ARGUMENTS] @@ -304,20 +307,25 @@ let Defs = [ARGUMENTS] in { // Defines atomic and non-atomic stores, regular and truncating -class WebAssemblyStore : - I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val), [], - !strconcat(Name, "\t${off}(${addr})${p2align}, $val"), Opcode>; +multiclass WebAssemblyStore { + defm "" : I<(outs), + (ins P2Align:$p2align, offset32_op:$off, I32:$addr, rc:$val), + (outs), + (ins P2Align:$p2align, offset32_op:$off), [], + !strconcat(Name, "\t${off}(${addr})${p2align}, $val"), + !strconcat(Name, "\t${off}, ${p2align}"), Opcode>; +} // Basic store. // Note: WebAssembly inverts SelectionDAG's usual operand order. -def STORE_I32 : WebAssemblyStore; -def STORE_I64 : WebAssemblyStore; -def STORE_F32 : WebAssemblyStore; -def STORE_F64 : WebAssemblyStore; +defm STORE_I32 : WebAssemblyStore; +defm STORE_I64 : WebAssemblyStore; +defm STORE_F32 : WebAssemblyStore; +defm STORE_F64 : WebAssemblyStore; } // Defs = [ARGUMENTS] // Select stores with no constant offset. -class StorePatNoOffset : +class StorePatNoOffset : Pat<(node ty:$val, I32:$addr), (inst 0, 0, $addr, $val)>; def : StorePatNoOffset; @@ -326,7 +334,7 @@ def : StorePatNoOffset; // Select stores with a constant offset. -class StorePatImmOff : +class StorePatImmOff : Pat<(storekind ty:$val, (operand I32:$addr, imm:$off)), (inst 0, imm:$off, $addr, ty:$val)>; @@ -339,7 +347,7 @@ def : StorePatImmOff; def : StorePatImmOff; -class StorePatGlobalAddr : +class StorePatGlobalAddr : Pat<(storekind ty:$val, (regPlusGA I32:$addr, (WebAssemblywrapper tglobaladdr:$off))), (inst 0, tglobaladdr:$off, I32:$addr, ty:$val)>; @@ -348,7 +356,7 @@ def : StorePatGlobalAddr; def : StorePatGlobalAddr; -class StorePatExternalSym : +class StorePatExternalSym : Pat<(storekind ty:$val, (add I32:$addr, (WebAssemblywrapper texternalsym:$off))), (inst 0, texternalsym:$off, I32:$addr, ty:$val)>; @@ -358,7 +366,7 @@ def : StorePatExternalSym; // Select stores with just a constant offset. -class StorePatOffsetOnly : +class StorePatOffsetOnly : Pat<(storekind ty:$val, imm:$off), (inst 0, imm:$off, (CONST_I32 0), ty:$val)>; def : StorePatOffsetOnly; @@ -366,7 +374,7 @@ def : StorePatOffsetOnly; def : StorePatOffsetOnly; -class StorePatGlobalAddrOffOnly : +class StorePatGlobalAddrOffOnly : Pat<(storekind ty:$val, (WebAssemblywrapper tglobaladdr:$off)), (inst 0, tglobaladdr:$off, (CONST_I32 0), ty:$val)>; def : StorePatGlobalAddrOffOnly; @@ -374,7 +382,7 @@ def : StorePatGlobalAddrOffOnly; def : StorePatGlobalAddrOffOnly; -class StorePatExternSymOffOnly : +class StorePatExternSymOffOnly : Pat<(storekind ty:$val, (WebAssemblywrapper texternalsym:$off)), (inst 0, texternalsym:$off, (CONST_I32 0), ty:$val)>; def : StorePatExternSymOffOnly; @@ -386,11 +394,11 @@ let Defs = [ARGUMENTS] in { // Truncating store. -def STORE8_I32 : WebAssemblyStore; -def STORE16_I32 : WebAssemblyStore; -def STORE8_I64 : WebAssemblyStore; -def STORE16_I64 : WebAssemblyStore; -def STORE32_I64 : WebAssemblyStore; +defm STORE8_I32 : WebAssemblyStore; +defm STORE16_I32 : WebAssemblyStore; +defm STORE8_I64 : WebAssemblyStore; +defm STORE16_I64 : WebAssemblyStore; +defm STORE32_I64 : WebAssemblyStore; } // Defs = [ARGUMENTS] @@ -444,34 +452,47 @@ let Defs = [ARGUMENTS] in { // Current memory size. -def MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags), - [(set I32:$dst, (int_wasm_memory_size (i32 imm:$flags)))], - "memory.size\t$dst, $flags", 0x3f>, - Requires<[HasAddr32]>; -def MEM_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags), - [(set I32:$dst, (int_wasm_mem_size (i32 imm:$flags)))], - "mem.size\t$dst, $flags", 0x3f>, - Requires<[HasAddr32]>; -def CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags), - [], - "current_memory\t$dst", 0x3f>, - Requires<[HasAddr32]>; +defm MEMORY_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags), + (outs), (ins i32imm:$flags), + [(set I32:$dst, + (int_wasm_memory_size (i32 imm:$flags)))], + "memory.size\t$dst, $flags", "memory.size\t$flags", + 0x3f>, + Requires<[HasAddr32]>; +defm MEM_SIZE_I32 : I<(outs I32:$dst), (ins i32imm:$flags), + (outs), (ins i32imm:$flags), + [(set I32:$dst, (int_wasm_mem_size (i32 imm:$flags)))], + "mem.size\t$dst, $flags", "mem.size\t$flags", 0x3f>, + Requires<[HasAddr32]>; +defm CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags), + (outs), (ins i32imm:$flags), + [], + "current_memory\t$dst", + "current_memory\t$flags", 0x3f>, + Requires<[HasAddr32]>; // Grow memory. -def MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), - [(set I32:$dst, - (int_wasm_memory_grow (i32 imm:$flags), I32:$delta))], - "memory.grow\t$dst, $flags, $delta", 0x3f>, - Requires<[HasAddr32]>; -def MEM_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), - [(set I32:$dst, - (int_wasm_mem_grow (i32 imm:$flags), I32:$delta))], - "mem.grow\t$dst, $flags, $delta", 0x3f>, - Requires<[HasAddr32]>; -def GROW_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), - [], - "grow_memory\t$dst, $delta", 0x40>, - Requires<[HasAddr32]>; +defm MEMORY_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), + (outs), (ins i32imm:$flags, I32:$delta), + [(set I32:$dst, + (int_wasm_memory_grow (i32 imm:$flags), + I32:$delta))], + "memory.grow\t$dst, $flags, $delta", + "memory.grow\t$flags, $delta", 0x3f>, + Requires<[HasAddr32]>; +defm MEM_GROW_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), + (outs), (ins i32imm:$flags), + [(set I32:$dst, + (int_wasm_mem_grow (i32 imm:$flags), I32:$delta))], + "mem.grow\t$dst, $flags, $delta", "mem.grow\t$flags", + 0x3f>, + Requires<[HasAddr32]>; +defm GROW_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), + (outs), (ins i32imm:$flags), + [], + "grow_memory\t$dst, $delta", "grow_memory\t$flags", + 0x40>, + Requires<[HasAddr32]>; } // Defs = [ARGUMENTS] Index: test/MC/Disassembler/WebAssembly/wasm.txt =================================================================== --- test/MC/Disassembler/WebAssembly/wasm.txt +++ test/MC/Disassembler/WebAssembly/wasm.txt @@ -5,14 +5,14 @@ # CHECK: nop 0x01 -# CHECK: i32.add $0=, $0, $0 -# NOTE: registers are meaningless, as there is no context for what they are. +# CHECK: i32.add 0x6a -# CHECK: i64.const $0=, -1 +# CHECK: i64.const -1 0x42 0x7F -# CHECK: i64.load32_u $0=, 16($0):p2align=1 +# CHECK: i64.load32_u 16, :p2align=1 +# FIXME: fix p2align output in WebAssemblyInstPrinter 0x35 0x01 0x10 # CHECK: block @@ -25,9 +25,9 @@ # FIXME: WebAssemblyInstPrinter does not print immediates. 0x11 0x80 0x01 0x00 -# CHECK: get_local $0=, 128 +# CHECK: get_local 128 0x20 0x80 0x01 # Prefix byte example: -# CHECK: i64.trunc_u:sat/f64 $0=, $0 +# CHECK: i64.trunc_u:sat/f64 0xFC 0x07