Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrFormats.td =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrFormats.td +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrFormats.td @@ -58,12 +58,3 @@ bits<32> inst = -1> { defm "": I; } - -// Instructions requiring HasSIMD128 and the simd128 prefix byte -multiclass SIMD_I pattern_r, string asmstr_r = "", - string asmstr_s = "", bits<32> simdop = -1> { - defm "" : I, - Requires<[HasSIMD128]>; -} Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -169,24 +169,11 @@ (outs), (ins i32imm:$argno), [(set vt:$res, (WebAssemblyargument timm:$argno))]>; } -multiclass SIMD_ARGUMENT { - let hasSideEffects = 1, Uses = [ARGUMENTS], isCodeGenOnly = 1 in - defm ARGUMENT_#vt : SIMD_I<(outs V128:$res), (ins i32imm:$argno), - (outs), (ins i32imm:$argno), - [(set (vt V128:$res), - (WebAssemblyargument timm:$argno))]>; -} defm "": ARGUMENT; defm "": ARGUMENT; defm "": ARGUMENT; defm "": ARGUMENT; defm "": ARGUMENT; -defm "": SIMD_ARGUMENT; -defm "": SIMD_ARGUMENT; -defm "": SIMD_ARGUMENT; -defm "": SIMD_ARGUMENT; -defm "": SIMD_ARGUMENT; -defm "": SIMD_ARGUMENT; let Defs = [ARGUMENTS] in { Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -12,30 +12,41 @@ /// //===----------------------------------------------------------------------===// -// constrained immediate argument types +// Instructions requiring HasSIMD128 and the simd128 prefix byte +multiclass SIMD_I pattern_r, string asmstr_r = "", + string asmstr_s = "", bits<32> simdop = -1> { + defm "" : I, + Requires<[HasSIMD128]>; +} + +multiclass SIMD_ARGUMENT { + let hasSideEffects = 1, Uses = [ARGUMENTS], isCodeGenOnly = 1 in + defm ARGUMENT_#vt : SIMD_I<(outs V128:$res), (ins i32imm:$argno), + (outs), (ins i32imm:$argno), + [(set (vt V128:$res), + (WebAssemblyargument timm:$argno))]>; +} + +defm "": SIMD_ARGUMENT; +defm "": SIMD_ARGUMENT; +defm "": SIMD_ARGUMENT; +defm "": SIMD_ARGUMENT; +defm "": SIMD_ARGUMENT; +defm "": SIMD_ARGUMENT; + +// Constrained immediate argument types foreach SIZE = [8, 16] in def ImmI#SIZE : ImmLeaf; foreach SIZE = [2, 4, 8, 16, 32] in def LaneIdx#SIZE : ImmLeaf; -// Custom nodes for custom operations -def wasm_shuffle_t : SDTypeProfile<1, 18, []>; -def wasm_saturate_t : SDTypeProfile<1, 2, - [SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>] ->; -def wasm_bitselect_t : SDTypeProfile<1, 3, - [SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>] ->; -def wasm_reduce_t : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVec<1>]>; -def wasm_shuffle : SDNode<"WebAssemblyISD::SHUFFLE", wasm_shuffle_t>; -def wasm_add_sat_s : SDNode<"WebAssemblyISD::ADD_SAT_S", wasm_saturate_t>; -def wasm_add_sat_u : SDNode<"WebAssemblyISD::ADD_SAT_U", wasm_saturate_t>; -def wasm_sub_sat_s : SDNode<"WebAssemblyISD::SUB_SAT_S", wasm_saturate_t>; -def wasm_sub_sat_u : SDNode<"WebAssemblyISD::SUB_SAT_U", wasm_saturate_t>; -def wasm_bitselect : SDNode<"WebAssemblyISD::BITSELECT", wasm_bitselect_t>; -def wasm_anytrue : SDNode<"WebAssemblyISD::ANYTRUE", wasm_reduce_t>; -def wasm_alltrue : SDNode<"WebAssemblyISD::ALLTRUE", wasm_reduce_t>; +//===----------------------------------------------------------------------===// +// Constructing SIMD values +//===----------------------------------------------------------------------===// +// Constant: v128.const multiclass ConstVec { let isMoveImm = 1, isReMaterializable = 1 in defm CONST_V128_#vec_t : SIMD_I<(outs V128:$dst), ops, (outs), ops, @@ -43,22 +54,88 @@ "v128.const\t$dst, "#args, "v128.const\t"#args, 0>; } -multiclass SIMDLoad { - let mayLoad = 1 in - defm LOAD_#vec_t : - SIMD_I<(outs V128:$dst), (ins P2Align:$align, offset32_op:$off, I32:$addr), - (outs), (ins P2Align:$align, offset32_op:$off), [], - "v128.load\t$dst, ${off}(${addr})$align", - "v128.load\t$off$align", 1>; -} -multiclass SIMDStore { - let mayStore = 1 in - defm STORE_#vec_t : - SIMD_I<(outs), (ins P2Align:$align, offset32_op:$off, I32:$addr, V128:$vec), - (outs), (ins P2Align:$align, offset32_op:$off), [], - "v128.store\t${off}(${addr})$align, $vec", - "v128.store\t$off$align", 2>; + +let Defs = [ARGUMENTS] in { +defm "" : ConstVec; +defm "" : ConstVec; +defm "" : ConstVec; +defm "" : ConstVec; +defm "" : ConstVec; +defm "" : ConstVec; +} // Defs = [ARGUMENTS] + +// Create vector with identical lanes: splat +def splat2 : PatFrag<(ops node:$x), (build_vector node:$x, node:$x)>; +def splat4 : PatFrag<(ops node:$x), (build_vector + node:$x, node:$x, node:$x, node:$x)>; +def splat8 : PatFrag<(ops node:$x), (build_vector + node:$x, node:$x, node:$x, node:$x, + node:$x, node:$x, node:$x, node:$x)>; +def splat16 : PatFrag<(ops node:$x), (build_vector + node:$x, node:$x, node:$x, node:$x, + node:$x, node:$x, node:$x, node:$x, + node:$x, node:$x, node:$x, node:$x, + node:$x, node:$x, node:$x, node:$x)>; + +multiclass Splat simdop> { + // Prefer splats over v128.const for const splats (65 is lowest that works) + let AddedComplexity = 65 in + defm SPLAT_#vec_t : SIMD_I<(outs V128:$dst), (ins reg_t:$x), (outs), (ins), + [(set (vec_t V128:$dst), (splat_pat reg_t:$x))], + vec#".splat\t$dst, $x", vec#".splat", simdop>; } + +defm "" : Splat; +defm "" : Splat; +defm "" : Splat; +defm "" : Splat; +defm "" : Splat; +defm "" : Splat; + +//===----------------------------------------------------------------------===// +// Accessing lanes +//===----------------------------------------------------------------------===// + +// Extract lane as a scalar: extract_lane / extract_lane_s / extract_lane_u multiclass ExtractLane simdop, string suffix = "", SDNode extract = vector_extract> { @@ -69,6 +146,7 @@ vec#".extract_lane"#suffix#"\t$dst, $vec, $idx", vec#".extract_lane"#suffix#"\t$idx", simdop>; } + multiclass ExtractPat { def _s : PatFrag<(ops node:$vec, node:$idx), (i32 (sext_inreg @@ -87,14 +165,31 @@ (i32 mask) ))>; } + defm extract_i8x16 : ExtractPat; defm extract_i16x8 : ExtractPat; + multiclass ExtractLaneExtended baseInst> { defm "" : ExtractLane("extract_i8x16"#sign)>; defm "" : ExtractLane("extract_i16x8"#sign)>; } + +defm "" : ExtractLaneExtended<"_s", 9>; +defm "" : ExtractLaneExtended<"_u", 10>; +defm "" : ExtractLane; +defm "" : ExtractLane; +defm "" : ExtractLane; +defm "" : ExtractLane; + +// Follow convention of making implicit expansions unsigned +def : Pat<(i32 (vector_extract (v16i8 V128:$vec), (i32 LaneIdx16:$idx))), + (EXTRACT_LANE_v16i8_u V128:$vec, (i32 LaneIdx16:$idx))>; +def : Pat<(i32 (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx))), + (EXTRACT_LANE_v8i16_u V128:$vec, (i32 LaneIdx8:$idx))>; + +// Replace lane value: replace_lane multiclass ReplaceLane simdop> { @@ -106,227 +201,6 @@ vec#".replace_lane\t$dst, $vec, $idx, $x", vec#".replace_lane\t$idx", simdop>; } -def splat2 : PatFrag<(ops node:$x), (build_vector node:$x, node:$x)>; -def splat4 : PatFrag<(ops node:$x), (build_vector - node:$x, node:$x, node:$x, node:$x)>; -def splat8 : PatFrag<(ops node:$x), (build_vector - node:$x, node:$x, node:$x, node:$x, - node:$x, node:$x, node:$x, node:$x)>; -def splat16 : PatFrag<(ops node:$x), (build_vector - node:$x, node:$x, node:$x, node:$x, - node:$x, node:$x, node:$x, node:$x, - node:$x, node:$x, node:$x, node:$x, - node:$x, node:$x, node:$x, node:$x)>; -multiclass Splat simdop> { - // Prefer splats over v128.const for const splats (65 is lowest that works) - let AddedComplexity = 65 in - defm SPLAT_#vec_t : SIMD_I<(outs V128:$dst), (ins reg_t:$x), (outs), (ins), - [(set (vec_t V128:$dst), (splat_pat reg_t:$x))], - vec#".splat\t$dst, $x", vec#".splat", simdop>; -} -multiclass SIMDBinary simdop> { - defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), - (outs), (ins), - [(set (vec_t V128:$dst), (node V128:$lhs, V128:$rhs))], - vec#"."#name#"\t$dst, $lhs, $rhs", vec#"."#name, - simdop>; -} -multiclass SIMDBinaryIntNoI64x2 baseInst> { - defm "" : SIMDBinary; - defm "" : SIMDBinary; - defm "" : SIMDBinary; -} -multiclass SIMDBinaryInt baseInst> { - defm "" : SIMDBinaryIntNoI64x2; - defm "" : SIMDBinary; -} -multiclass SIMDBinaryFP baseInst> { - defm "" : SIMDBinary; - defm "" : SIMDBinary; -} -multiclass SIMDBinarySat baseInst> { - defm "" : SIMDBinary; - defm "" : SIMDBinary; -} -multiclass SIMDShift simdop> { - defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec, I32:$x), - (outs), (ins), - [(set (vec_t V128:$dst), - (node V128:$vec, (vec_t shift_vec)))], - vec#"."#name#"\t$dst, $vec, $x", vec#"."#name, simdop>; -} -multiclass SIMDShiftInt baseInst, int skip> { - defm "" : SIMDShift; - defm "" : SIMDShift; - defm "" : SIMDShift; - defm "" : SIMDShift; -} -multiclass SIMDBitwise simdop> { - defm "" : SIMDBinary; - defm "" : SIMDBinary; - defm "" : SIMDBinary; - defm "" : SIMDBinary; -} -multiclass SIMDNeg simdop> { - defm NEG_#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), - (outs), (ins), - [(set - (vec_t V128:$dst), - (vec_t (node - (vec_t (splat_pat lane)), - (vec_t V128:$vec) - )) - )], - vec#".neg\t$dst, $vec", vec#".neg", simdop>; -} -multiclass SIMDNegInt simdop> { - defm "" : SIMDNeg; -} -def fpimm0 : FPImmLeaf; -multiclass SIMDNegFP simdop> { - defm "" : SIMDNeg; -} -multiclass SIMDNot { - defm NOT_#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), - (outs), (ins), - [(set - (vec_t V128:$dst), - (vec_t (xor - (vec_t V128:$vec), - (vec_t (splat_pat (lane_t -1))) - )) - )], - "v128.not\t$dst, $vec", "v128.not", 63>; -} -multiclass Bitselect { - defm BITSELECT_#vec_t : - SIMD_I<(outs V128:$dst), (ins V128:$v1, V128:$v2, V128:$c), (outs), (ins), - [(set (vec_t V128:$dst), - (vec_t (wasm_bitselect - (vec_t V128:$c), (vec_t V128:$v1), (vec_t V128:$v2) - )) - )], - "v128.bitselect\t$dst, $v1, $v2, $c", "v128.bitselect", 64>; -} -multiclass SIMDReduceVec simdop> { - defm _#vec_t : SIMD_I<(outs I32:$dst), (ins V128:$vec), (outs), (ins), - [(set I32:$dst, (i32 (op (vec_t V128:$vec))))], - vec#"."#name#"\t$dst, $vec", vec#"."#name, simdop>; -} -multiclass SIMDReduce baseInst> { - defm "" : SIMDReduceVec; - defm "" : SIMDReduceVec; - defm "" : SIMDReduceVec; - defm "" : SIMDReduceVec; -} -multiclass SIMDCondition simdop> { - defm _#vec_t : - SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), (outs), (ins), - [(set (out_t V128:$dst), - (setcc (vec_t V128:$lhs), (vec_t V128:$rhs), cond))], - vec#"."#name#"\t$dst, $lhs, $rhs", vec#"."#name, simdop>; -} -multiclass SIMDConditionInt baseInst, - int step = 1> { - defm "" : SIMDCondition; - defm "" : SIMDCondition; - defm "" : SIMDCondition; -} -multiclass SIMDConditionFP baseInst> { - defm "" : SIMDCondition; - defm "" : SIMDCondition; -} -multiclass SIMDAbs simdop> { - defm ABS_#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), - [(set (vec_t V128:$dst), (vec_t (fabs V128:$vec)))], - vec#".abs\t$dst, $vec", vec#".abs", simdop>; -} -multiclass SIMDSqrt simdop> { - defm SQRT_#vec_t : - SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), - [(set (vec_t V128:$dst), (vec_t (fsqrt V128:$vec)))], - vec#".sqrt\t$dst, $vec", vec#".sqrt", simdop>; -} -multiclass SIMDConvert simdop> { - defm op#_#vec_t#_#arg_t : - SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), - [(set (vec_t V128:$dst), (vec_t (op (arg_t V128:$vec))))], - name#"\t$dst, $vec", name, simdop>; -} - -let Defs = [ARGUMENTS] in { -defm "" : ConstVec; -defm "" : ConstVec; -defm "" : ConstVec; -defm "" : ConstVec; -defm "" : ConstVec; -defm "" : ConstVec; - -foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { -defm "" : SIMDLoad; -defm "" : SIMDStore; -} - -defm "" : ExtractLaneExtended<"_s", 9>; -defm "" : ExtractLaneExtended<"_u", 10>; -defm "" : ExtractLane; -defm "" : ExtractLane; -defm "" : ExtractLane; -defm "" : ExtractLane; defm "" : ReplaceLane; defm "" : ReplaceLane; @@ -335,13 +209,119 @@ defm "" : ReplaceLane; defm "" : ReplaceLane; -defm "" : Splat; -defm "" : Splat; -defm "" : Splat; -defm "" : Splat; -defm "" : Splat; -defm "" : Splat; +// Arbitrary other BUILD_VECTOR patterns +def : Pat<(v16i8 (build_vector + (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3), + (i32 I32:$x4), (i32 I32:$x5), (i32 I32:$x6), (i32 I32:$x7), + (i32 I32:$x8), (i32 I32:$x9), (i32 I32:$x10), (i32 I32:$x11), + (i32 I32:$x12), (i32 I32:$x13), (i32 I32:$x14), (i32 I32:$x15) + )), + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (REPLACE_LANE_v16i8 + (v16i8 (SPLAT_v16i8 (i32 I32:$x0))), + 1, I32:$x1 + )), + 2, I32:$x2 + )), + 3, I32:$x3 + )), + 4, I32:$x4 + )), + 5, I32:$x5 + )), + 6, I32:$x6 + )), + 7, I32:$x7 + )), + 8, I32:$x8 + )), + 9, I32:$x9 + )), + 10, I32:$x10 + )), + 11, I32:$x11 + )), + 12, I32:$x12 + )), + 13, I32:$x13 + )), + 14, I32:$x14 + )), + 15, I32:$x15 + ))>; +def : Pat<(v8i16 (build_vector + (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3), + (i32 I32:$x4), (i32 I32:$x5), (i32 I32:$x6), (i32 I32:$x7) + )), + (v8i16 (REPLACE_LANE_v8i16 + (v8i16 (REPLACE_LANE_v8i16 + (v8i16 (REPLACE_LANE_v8i16 + (v8i16 (REPLACE_LANE_v8i16 + (v8i16 (REPLACE_LANE_v8i16 + (v8i16 (REPLACE_LANE_v8i16 + (v8i16 (REPLACE_LANE_v8i16 + (v8i16 (SPLAT_v8i16 (i32 I32:$x0))), + 1, I32:$x1 + )), + 2, I32:$x2 + )), + 3, I32:$x3 + )), + 4, I32:$x4 + )), + 5, I32:$x5 + )), + 6, I32:$x6 + )), + 7, I32:$x7 + ))>; +def : Pat<(v4i32 (build_vector + (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3) + )), + (v4i32 (REPLACE_LANE_v4i32 + (v4i32 (REPLACE_LANE_v4i32 + (v4i32 (REPLACE_LANE_v4i32 + (v4i32 (SPLAT_v4i32 (i32 I32:$x0))), + 1, I32:$x1 + )), + 2, I32:$x2 + )), + 3, I32:$x3 + ))>; +def : Pat<(v2i64 (build_vector (i64 I64:$x0), (i64 I64:$x1))), + (v2i64 (REPLACE_LANE_v2i64 + (v2i64 (SPLAT_v2i64 (i64 I64:$x0))), 1, I64:$x1))>; +def : Pat<(v4f32 (build_vector + (f32 F32:$x0), (f32 F32:$x1), (f32 F32:$x2), (f32 F32:$x3) + )), + (v4f32 (REPLACE_LANE_v4f32 + (v4f32 (REPLACE_LANE_v4f32 + (v4f32 (REPLACE_LANE_v4f32 + (v4f32 (SPLAT_v4f32 (f32 F32:$x0))), + 1, F32:$x1 + )), + 2, F32:$x2 + )), + 3, F32:$x3 + ))>; +def : Pat<(v2f64 (build_vector (f64 F64:$x0), (f64 F64:$x1))), + (v2f64 (REPLACE_LANE_v2f64 + (v2f64 (SPLAT_v2f64 (f64 F64:$x0))), 1, F64:$x1))>; +// Shuffle lanes: shuffle defm SHUFFLE_v16i8 : SIMD_I<(outs V128:$dst), (ins V128:$x, V128:$y, @@ -372,89 +352,333 @@ "$m8, $m9, $mA, $mB, $mC, $mD, $mE, $mF", 23>; -let isCommutable = 1 in { -defm ADD : SIMDBinaryInt; -defm ADD : SIMDBinaryFP; -defm MUL : SIMDBinaryIntNoI64x2; -defm MUL : SIMDBinaryFP; -defm ADD_SAT_S : SIMDBinarySat; -defm ADD_SAT_U : SIMDBinarySat; -} // isCommutable = 1 +// Shuffles after custom lowering +def wasm_shuffle_t : SDTypeProfile<1, 18, []>; +def wasm_shuffle : SDNode<"WebAssemblyISD::SHUFFLE", wasm_shuffle_t>; +foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { +def : Pat<(v16i8 (wasm_shuffle (vec_t V128:$x), (vec_t V128:$y), + (i32 LaneIdx32:$m0), (i32 LaneIdx32:$m1), + (i32 LaneIdx32:$m2), (i32 LaneIdx32:$m3), + (i32 LaneIdx32:$m4), (i32 LaneIdx32:$m5), + (i32 LaneIdx32:$m6), (i32 LaneIdx32:$m7), + (i32 LaneIdx32:$m8), (i32 LaneIdx32:$m9), + (i32 LaneIdx32:$mA), (i32 LaneIdx32:$mB), + (i32 LaneIdx32:$mC), (i32 LaneIdx32:$mD), + (i32 LaneIdx32:$mE), (i32 LaneIdx32:$mF))), + (v16i8 (SHUFFLE_v16i8 (vec_t V128:$x), (vec_t V128:$y), + (i32 LaneIdx32:$m0), (i32 LaneIdx32:$m1), + (i32 LaneIdx32:$m2), (i32 LaneIdx32:$m3), + (i32 LaneIdx32:$m4), (i32 LaneIdx32:$m5), + (i32 LaneIdx32:$m6), (i32 LaneIdx32:$m7), + (i32 LaneIdx32:$m8), (i32 LaneIdx32:$m9), + (i32 LaneIdx32:$mA), (i32 LaneIdx32:$mB), + (i32 LaneIdx32:$mC), (i32 LaneIdx32:$mD), + (i32 LaneIdx32:$mE), (i32 LaneIdx32:$mF)))>; +} -defm SUB : SIMDBinaryInt; -defm SUB : SIMDBinaryFP; -defm SUB_SAT_S : SIMDBinarySat; -defm SUB_SAT_U : SIMDBinarySat; -defm DIV : SIMDBinaryFP; +//===----------------------------------------------------------------------===// +// Integer arithmetic +//===----------------------------------------------------------------------===// -defm "" : SIMDNegInt; -defm "" : SIMDNegInt; -defm "" : SIMDNegInt; -defm "" : SIMDNegInt; -defm "" : SIMDNegFP; -defm "" : SIMDNegFP; +multiclass SIMDBinary simdop> { + defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), + (outs), (ins), + [(set (vec_t V128:$dst), (node V128:$lhs, V128:$rhs))], + vec#"."#name#"\t$dst, $lhs, $rhs", vec#"."#name, + simdop>; +} -defm SHL : SIMDShiftInt; -defm SHR_S : SIMDShiftInt; -defm SHR_U : SIMDShiftInt; +multiclass SIMDBinaryIntNoI64x2 baseInst> { + defm "" : SIMDBinary; + defm "" : SIMDBinary; + defm "" : SIMDBinary; +} + +multiclass SIMDBinaryInt baseInst> { + defm "" : SIMDBinaryIntNoI64x2; + defm "" : SIMDBinary; +} + +// Integer addition: add +let isCommutable = 1 in +defm ADD : SIMDBinaryInt; + +// Integer subtraction: sub +defm SUB : SIMDBinaryInt; + +// Integer multiplication: mul +defm MUL : SIMDBinaryIntNoI64x2; + +// Integer negation: neg +multiclass SIMDNeg simdop> { + defm NEG_#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), + (outs), (ins), + [(set + (vec_t V128:$dst), + (vec_t (node + (vec_t (splat_pat lane)), + (vec_t V128:$vec) + )) + )], + vec#".neg\t$dst, $vec", vec#".neg", simdop>; +} +multiclass SIMDNegInt simdop> { + defm "" : SIMDNeg; +} + +defm "" : SIMDNegInt; +defm "" : SIMDNegInt; +defm "" : SIMDNegInt; +defm "" : SIMDNegInt; + +//===----------------------------------------------------------------------===// +// Saturating integer arithmetic +//===----------------------------------------------------------------------===// + +multiclass SIMDBinarySat baseInst> { + defm "" : SIMDBinary; + defm "" : SIMDBinary; +} + +def wasm_saturate_t : SDTypeProfile<1, 2, + [SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>] +>; +def wasm_add_sat_s : SDNode<"WebAssemblyISD::ADD_SAT_S", wasm_saturate_t>; +def wasm_add_sat_u : SDNode<"WebAssemblyISD::ADD_SAT_U", wasm_saturate_t>; +def wasm_sub_sat_s : SDNode<"WebAssemblyISD::SUB_SAT_S", wasm_saturate_t>; +def wasm_sub_sat_u : SDNode<"WebAssemblyISD::SUB_SAT_U", wasm_saturate_t>; + +// Saturating integer addition: add_saturate_s / add_saturate_u +let isCommutable = 1 in { +defm ADD_SAT_S : SIMDBinarySat; +defm ADD_SAT_U : SIMDBinarySat; +} // isCommutable = 1 + +// Saturating integer subtraction: sub_saturate_s / sub_saturate_u +defm SUB_SAT_S : SIMDBinarySat; +defm SUB_SAT_U : SIMDBinarySat; + +//===----------------------------------------------------------------------===// +// Bit shifts +//===----------------------------------------------------------------------===// + +multiclass SIMDShift simdop> { + defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec, I32:$x), + (outs), (ins), + [(set (vec_t V128:$dst), + (node V128:$vec, (vec_t shift_vec)))], + vec#"."#name#"\t$dst, $vec, $x", vec#"."#name, simdop>; +} + +multiclass SIMDShiftInt baseInst, int skip> { + defm "" : SIMDShift; + defm "" : SIMDShift; + defm "" : SIMDShift; + defm "" : SIMDShift; +} + +// Left shift by scalar: shl +defm SHL : SIMDShiftInt; + +// Right shift by scalar: shr_s / shr_u +defm SHR_S : SIMDShiftInt; +defm SHR_U : SIMDShiftInt; + +// Truncate i64 shift operands to i32s +foreach shifts = [[shl, SHL_v2i64], [sra, SHR_S_v2i64], [srl, SHR_U_v2i64]] in +def : Pat<(v2i64 (shifts[0] (v2i64 V128:$vec), (v2i64 (splat2 I64:$x)))), + (v2i64 (shifts[1] (v2i64 V128:$vec), (I32_WRAP_I64 I64:$x)))>; + +//===----------------------------------------------------------------------===// +// Bitwise operations +//===----------------------------------------------------------------------===// + +multiclass SIMDBitwise simdop> { + defm "" : SIMDBinary; + defm "" : SIMDBinary; + defm "" : SIMDBinary; + defm "" : SIMDBinary; +} + +// Bitwise logic: v128.and / v128.or / v128.xor let isCommutable = 1 in { defm AND : SIMDBitwise; defm OR : SIMDBitwise; defm XOR : SIMDBitwise; } // isCommutable = 1 +// Bitwise logic: v128.not +multiclass SIMDNot { + defm NOT_#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), + (outs), (ins), + [(set + (vec_t V128:$dst), + (vec_t (xor + (vec_t V128:$vec), + (vec_t (splat_pat (lane_t -1))) + )) + )], + "v128.not\t$dst, $vec", "v128.not", 63>; +} + defm "" : SIMDNot; defm "" : SIMDNot; defm "" : SIMDNot; defm "" : SIMDNot; +// Bitwise select: v128.bitselect +def wasm_bitselect_t : SDTypeProfile<1, 3, + [SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>] +>; +def wasm_bitselect : SDNode<"WebAssemblyISD::BITSELECT", wasm_bitselect_t>; + +multiclass Bitselect { + defm BITSELECT_#vec_t : + SIMD_I<(outs V128:$dst), (ins V128:$v1, V128:$v2, V128:$c), (outs), (ins), + [(set (vec_t V128:$dst), + (vec_t (wasm_bitselect + (vec_t V128:$c), (vec_t V128:$v1), (vec_t V128:$v2) + )) + )], + "v128.bitselect\t$dst, $v1, $v2, $c", "v128.bitselect", 64>; +} + foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in defm "" : Bitselect; +// Bitselect is equivalent to (c & v1) | (~c & v2) +foreach vec_t = [v16i8, v8i16, v4i32, v2i64] in + def : Pat<(vec_t (or (and (vec_t V128:$c), (vec_t V128:$v1)), + (and (vnot V128:$c), (vec_t V128:$v2)))), + (!cast("BITSELECT_"#vec_t) + V128:$v1, V128:$v2, V128:$c)>; + +//===----------------------------------------------------------------------===// +// Boolean horizontal reductions +//===----------------------------------------------------------------------===// + +multiclass SIMDReduceVec simdop> { + defm _#vec_t : SIMD_I<(outs I32:$dst), (ins V128:$vec), (outs), (ins), + [(set I32:$dst, (i32 (op (vec_t V128:$vec))))], + vec#"."#name#"\t$dst, $vec", vec#"."#name, simdop>; +} + +multiclass SIMDReduce baseInst> { + defm "" : SIMDReduceVec; + defm "" : SIMDReduceVec; + defm "" : SIMDReduceVec; + defm "" : SIMDReduceVec; +} + +def wasm_reduce_t : SDTypeProfile<1, 1, [SDTCisVT<0, i32>, SDTCisVec<1>]>; + +// Any lane true: any_true +def wasm_anytrue : SDNode<"WebAssemblyISD::ANYTRUE", wasm_reduce_t>; defm ANYTRUE : SIMDReduce<"any_true", wasm_anytrue, 65>; + +// All lanes true: all_true +def wasm_alltrue : SDNode<"WebAssemblyISD::ALLTRUE", wasm_reduce_t>; defm ALLTRUE : SIMDReduce<"all_true", wasm_alltrue, 69>; +//===----------------------------------------------------------------------===// +// Comparisons +//===----------------------------------------------------------------------===// + +multiclass SIMDCondition simdop> { + defm _#vec_t : + SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), (outs), (ins), + [(set (out_t V128:$dst), + (setcc (vec_t V128:$lhs), (vec_t V128:$rhs), cond))], + vec#"."#name#"\t$dst, $lhs, $rhs", vec#"."#name, simdop>; +} + +multiclass SIMDConditionInt baseInst, + int step = 1> { + defm "" : SIMDCondition; + defm "" : SIMDCondition; + defm "" : SIMDCondition; +} + +multiclass SIMDConditionFP baseInst> { + defm "" : SIMDCondition; + defm "" : SIMDCondition; +} + +// Equality: eq let isCommutable = 1 in { defm EQ : SIMDConditionInt<"eq", SETEQ, 73>; defm EQ : SIMDConditionFP<"eq", SETOEQ, 77>; +} // isCommutable = 1 + +// Non-equality: ne +let isCommutable = 1 in { defm NE : SIMDConditionInt<"ne", SETNE, 79>; defm NE : SIMDConditionFP<"ne", SETUNE, 83>; } // isCommutable = 1 +// Less than: lt_s / lt_u / lt defm LT_S : SIMDConditionInt<"lt_s", SETLT, 85, 2>; defm LT_U : SIMDConditionInt<"lt_u", SETULT, 86, 2>; defm LT : SIMDConditionFP<"lt", SETOLT, 93>; + +// Less than or equal: le_s / le_u / le defm LE_S : SIMDConditionInt<"le_s", SETLE, 95, 2>; defm LE_U : SIMDConditionInt<"le_u", SETULE, 96, 2>; defm LE : SIMDConditionFP<"le", SETOLE, 103>; + +// Greater than: gt_s / gt_u / gt defm GT_S : SIMDConditionInt<"gt_s", SETGT, 105, 2>; defm GT_U : SIMDConditionInt<"gt_u", SETUGT, 106, 2>; defm GT : SIMDConditionFP<"gt", SETOGT, 113>; + +// Greater than or equal: ge_s / ge_u / ge defm GE_S : SIMDConditionInt<"ge_s", SETGE, 115, 2>; defm GE_U : SIMDConditionInt<"ge_u", SETUGE, 116, 2>; defm GE : SIMDConditionFP<"ge", SETOGE, 123>; -defm "" : SIMDAbs; -defm "" : SIMDAbs; - -defm "" : SIMDSqrt; -defm "" : SIMDSqrt; +// Lower float comparisons that don't care about NaN to standard WebAssembly +// float comparisons. These instructions are generated in the target-independent +// expansion of unordered comparisons and ordered ne. +def : Pat<(v4i32 (seteq (v4f32 V128:$lhs), (v4f32 V128:$rhs))), + (v4i32 (EQ_v4f32 (v4f32 V128:$lhs), (v4f32 V128:$rhs)))>; +def : Pat<(v4i32 (setne (v4f32 V128:$lhs), (v4f32 V128:$rhs))), + (v4i32 (NE_v4f32 (v4f32 V128:$lhs), (v4f32 V128:$rhs)))>; +def : Pat<(v2i64 (seteq (v2f64 V128:$lhs), (v2f64 V128:$rhs))), + (v2i64 (EQ_v2f64 (v2f64 V128:$lhs), (v2f64 V128:$rhs)))>; +def : Pat<(v2i64 (setne (v2f64 V128:$lhs), (v2f64 V128:$rhs))), + (v2i64 (NE_v2f64 (v2f64 V128:$lhs), (v2f64 V128:$rhs)))>; -defm "" : SIMDConvert; -defm "" : SIMDConvert; -defm "" : SIMDConvert; -defm "" : SIMDConvert; -defm "" : SIMDConvert; -defm "" : SIMDConvert; -defm "" : SIMDConvert; -defm "" : SIMDConvert; +//===----------------------------------------------------------------------===// +// Load and store +//===----------------------------------------------------------------------===// -} // Defs = [ARGUMENTS] +// Load: v128.load +multiclass SIMDLoad { + let mayLoad = 1 in + defm LOAD_#vec_t : + SIMD_I<(outs V128:$dst), (ins P2Align:$align, offset32_op:$off, I32:$addr), + (outs), (ins P2Align:$align, offset32_op:$off), [], + "v128.load\t$dst, ${off}(${addr})$align", + "v128.load\t$off$align", 1>; +} -// Def load and store patterns from WebAssemblyInstrMemory.td for vector types foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { +defm "" : SIMDLoad; +// Def load and store patterns from WebAssemblyInstrMemory.td for vector types def : LoadPatNoOffset("LOAD_"#vec_t)>; def : LoadPatImmOff("LOAD_"#vec_t)>; def : LoadPatImmOff("LOAD_"#vec_t)>; @@ -463,7 +687,22 @@ def : LoadPatOffsetOnly("LOAD_"#vec_t)>; def : LoadPatGlobalAddrOffOnly("LOAD_"#vec_t)>; def : LoadPatExternSymOffOnly("LOAD_"#vec_t)>; +} + +// Store: v128.store +multiclass SIMDStore { + let mayStore = 1 in + defm STORE_#vec_t : + SIMD_I<(outs), (ins P2Align:$align, offset32_op:$off, I32:$addr, V128:$vec), + (outs), (ins P2Align:$align, offset32_op:$off), [], + "v128.store\t${off}(${addr})$align, $vec", + "v128.store\t$off$align", 2>; +} +foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { +defm "" : SIMDStore; + +// Def load and store patterns from WebAssemblyInstrMemory.td for vector types def : StorePatNoOffset("STORE_"#vec_t)>; def : StorePatImmOff("STORE_"#vec_t)>; def : StorePatImmOff("STORE_"#vec_t)>; @@ -472,34 +711,100 @@ def : StorePatOffsetOnly("STORE_"#vec_t)>; def : StorePatGlobalAddrOffOnly("STORE_"#vec_t)>; def : StorePatExternSymOffOnly("STORE_"#vec_t)>; +} + +//===----------------------------------------------------------------------===// +// Floating-point sign bit operations +//===----------------------------------------------------------------------===// +// Negation: neg +def fpimm0 : FPImmLeaf; +multiclass SIMDNegFP simdop> { + defm "" : SIMDNeg; } -// Bitselect is equivalent to (c & v1) | (~c & v2) -foreach vec_t = [v16i8, v8i16, v4i32, v2i64] in - def : Pat<(vec_t (or (and (vec_t V128:$c), (vec_t V128:$v1)), - (and (vnot V128:$c), (vec_t V128:$v2)))), - (!cast("BITSELECT_"#vec_t) - V128:$v1, V128:$v2, V128:$c)>; +defm "" : SIMDNegFP; +defm "" : SIMDNegFP; -// Lower float comparisons that don't care about NaN to standard -// WebAssembly float comparisons. These instructions are generated in -// the target-independent expansion of unordered comparisons and -// ordered ne. -def : Pat<(v4i32 (seteq (v4f32 V128:$lhs), (v4f32 V128:$rhs))), - (v4i32 (EQ_v4f32 (v4f32 V128:$lhs), (v4f32 V128:$rhs)))>; -def : Pat<(v4i32 (setne (v4f32 V128:$lhs), (v4f32 V128:$rhs))), - (v4i32 (NE_v4f32 (v4f32 V128:$lhs), (v4f32 V128:$rhs)))>; -def : Pat<(v2i64 (seteq (v2f64 V128:$lhs), (v2f64 V128:$rhs))), - (v2i64 (EQ_v2f64 (v2f64 V128:$lhs), (v2f64 V128:$rhs)))>; -def : Pat<(v2i64 (setne (v2f64 V128:$lhs), (v2f64 V128:$rhs))), - (v2i64 (NE_v2f64 (v2f64 V128:$lhs), (v2f64 V128:$rhs)))>; +// Absolute value: abs +multiclass SIMDAbs simdop> { + defm ABS_#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), + [(set (vec_t V128:$dst), (vec_t (fabs V128:$vec)))], + vec#".abs\t$dst, $vec", vec#".abs", simdop>; +} -// follow convention of making implicit expansions unsigned -def : Pat<(i32 (vector_extract (v16i8 V128:$vec), (i32 LaneIdx16:$idx))), - (EXTRACT_LANE_v16i8_u V128:$vec, (i32 LaneIdx16:$idx))>; -def : Pat<(i32 (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx))), - (EXTRACT_LANE_v8i16_u V128:$vec, (i32 LaneIdx8:$idx))>; +defm "" : SIMDAbs; +defm "" : SIMDAbs; + +//===----------------------------------------------------------------------===// +// Floating-point min and max +//===----------------------------------------------------------------------===// + +// NaN-propagating minimum: min +// TODO + +// NaN-propagating maximum: max +// TODO + +//===----------------------------------------------------------------------===// +// Floating-point arithmetic +//===----------------------------------------------------------------------===// + +multiclass SIMDBinaryFP baseInst> { + defm "" : SIMDBinary; + defm "" : SIMDBinary; +} + +// Addition: add +let isCommutable = 1 in +defm ADD : SIMDBinaryFP; + +// Subtraction: sub +defm SUB : SIMDBinaryFP; + +// Division: div +defm DIV : SIMDBinaryFP; + +// Multiplication: mul +let isCommutable = 1 in +defm MUL : SIMDBinaryFP; + +// Square root: sqrt +multiclass SIMDSqrt simdop> { + defm SQRT_#vec_t : + SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), + [(set (vec_t V128:$dst), (vec_t (fsqrt V128:$vec)))], + vec#".sqrt\t$dst, $vec", vec#".sqrt", simdop>; +} + +defm "" : SIMDSqrt; +defm "" : SIMDSqrt; + +//===----------------------------------------------------------------------===// +// Conversions +//===----------------------------------------------------------------------===// + +multiclass SIMDConvert simdop> { + defm op#_#vec_t#_#arg_t : + SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), + [(set (vec_t V128:$dst), (vec_t (op (arg_t V128:$vec))))], + name#"\t$dst, $vec", name, simdop>; +} + +// Integer to floating point +defm "" : SIMDConvert; +defm "" : SIMDConvert; +defm "" : SIMDConvert; +defm "" : SIMDConvert; + +// Floating point to integer with saturation +defm "" : SIMDConvert; +defm "" : SIMDConvert; +defm "" : SIMDConvert; +defm "" : SIMDConvert; // Bitcasts are nops // Matching bitcast t1 to t1 causes strange errors, so avoid repeating types @@ -511,142 +816,3 @@ ) ) in def : Pat<(t1 (bitconvert (t2 V128:$v))), (t1 V128:$v)>; - -// Truncate i64 shift operands to i32s -foreach shifts = [[shl, SHL_v2i64], [sra, SHR_S_v2i64], [srl, SHR_U_v2i64]] in -def : Pat<(v2i64 (shifts[0] (v2i64 V128:$vec), (v2i64 (splat2 I64:$x)))), - (v2i64 (shifts[1] (v2i64 V128:$vec), (I32_WRAP_I64 I64:$x)))>; - -// Shuffles after custom lowering -foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { -def : Pat<(v16i8 (wasm_shuffle (vec_t V128:$x), (vec_t V128:$y), - (i32 LaneIdx32:$m0), (i32 LaneIdx32:$m1), - (i32 LaneIdx32:$m2), (i32 LaneIdx32:$m3), - (i32 LaneIdx32:$m4), (i32 LaneIdx32:$m5), - (i32 LaneIdx32:$m6), (i32 LaneIdx32:$m7), - (i32 LaneIdx32:$m8), (i32 LaneIdx32:$m9), - (i32 LaneIdx32:$mA), (i32 LaneIdx32:$mB), - (i32 LaneIdx32:$mC), (i32 LaneIdx32:$mD), - (i32 LaneIdx32:$mE), (i32 LaneIdx32:$mF))), - (v16i8 (SHUFFLE_v16i8 (vec_t V128:$x), (vec_t V128:$y), - (i32 LaneIdx32:$m0), (i32 LaneIdx32:$m1), - (i32 LaneIdx32:$m2), (i32 LaneIdx32:$m3), - (i32 LaneIdx32:$m4), (i32 LaneIdx32:$m5), - (i32 LaneIdx32:$m6), (i32 LaneIdx32:$m7), - (i32 LaneIdx32:$m8), (i32 LaneIdx32:$m9), - (i32 LaneIdx32:$mA), (i32 LaneIdx32:$mB), - (i32 LaneIdx32:$mC), (i32 LaneIdx32:$mD), - (i32 LaneIdx32:$mE), (i32 LaneIdx32:$mF)))>; -} - -// arbitrary other BUILD_VECTOR patterns -def : Pat<(v16i8 (build_vector - (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3), - (i32 I32:$x4), (i32 I32:$x5), (i32 I32:$x6), (i32 I32:$x7), - (i32 I32:$x8), (i32 I32:$x9), (i32 I32:$x10), (i32 I32:$x11), - (i32 I32:$x12), (i32 I32:$x13), (i32 I32:$x14), (i32 I32:$x15) - )), - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (REPLACE_LANE_v16i8 - (v16i8 (SPLAT_v16i8 (i32 I32:$x0))), - 1, I32:$x1 - )), - 2, I32:$x2 - )), - 3, I32:$x3 - )), - 4, I32:$x4 - )), - 5, I32:$x5 - )), - 6, I32:$x6 - )), - 7, I32:$x7 - )), - 8, I32:$x8 - )), - 9, I32:$x9 - )), - 10, I32:$x10 - )), - 11, I32:$x11 - )), - 12, I32:$x12 - )), - 13, I32:$x13 - )), - 14, I32:$x14 - )), - 15, I32:$x15 - ))>; -def : Pat<(v8i16 (build_vector - (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3), - (i32 I32:$x4), (i32 I32:$x5), (i32 I32:$x6), (i32 I32:$x7) - )), - (v8i16 (REPLACE_LANE_v8i16 - (v8i16 (REPLACE_LANE_v8i16 - (v8i16 (REPLACE_LANE_v8i16 - (v8i16 (REPLACE_LANE_v8i16 - (v8i16 (REPLACE_LANE_v8i16 - (v8i16 (REPLACE_LANE_v8i16 - (v8i16 (REPLACE_LANE_v8i16 - (v8i16 (SPLAT_v8i16 (i32 I32:$x0))), - 1, I32:$x1 - )), - 2, I32:$x2 - )), - 3, I32:$x3 - )), - 4, I32:$x4 - )), - 5, I32:$x5 - )), - 6, I32:$x6 - )), - 7, I32:$x7 - ))>; -def : Pat<(v4i32 (build_vector - (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3) - )), - (v4i32 (REPLACE_LANE_v4i32 - (v4i32 (REPLACE_LANE_v4i32 - (v4i32 (REPLACE_LANE_v4i32 - (v4i32 (SPLAT_v4i32 (i32 I32:$x0))), - 1, I32:$x1 - )), - 2, I32:$x2 - )), - 3, I32:$x3 - ))>; -def : Pat<(v2i64 (build_vector (i64 I64:$x0), (i64 I64:$x1))), - (v2i64 (REPLACE_LANE_v2i64 - (v2i64 (SPLAT_v2i64 (i64 I64:$x0))), 1, I64:$x1))>; -def : Pat<(v4f32 (build_vector - (f32 F32:$x0), (f32 F32:$x1), (f32 F32:$x2), (f32 F32:$x3) - )), - (v4f32 (REPLACE_LANE_v4f32 - (v4f32 (REPLACE_LANE_v4f32 - (v4f32 (REPLACE_LANE_v4f32 - (v4f32 (SPLAT_v4f32 (f32 F32:$x0))), - 1, F32:$x1 - )), - 2, F32:$x2 - )), - 3, F32:$x3 - ))>; -def : Pat<(v2f64 (build_vector (f64 F64:$x0), (f64 F64:$x1))), - (v2f64 (REPLACE_LANE_v2f64 - (v2f64 (SPLAT_v2f64 (f64 F64:$x0))), 1, F64:$x1))>;