Dan Gohman | 10e730a | 2015-06-29 23:51:55 +0000 | [diff] [blame] | 1 | // WebAssemblyInstrSIMD.td - WebAssembly SIMD codegen support -*- tablegen -*-// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
JF Bastien | 5ca0bac | 2015-07-10 18:23:10 +0000 | [diff] [blame] | 9 | /// |
| 10 | /// \file |
Adrian Prantl | 5f8f34e4 | 2018-05-01 15:54:18 +0000 | [diff] [blame] | 11 | /// WebAssembly SIMD operand code-gen constructs. |
JF Bastien | 5ca0bac | 2015-07-10 18:23:10 +0000 | [diff] [blame] | 12 | /// |
Dan Gohman | 10e730a | 2015-06-29 23:51:55 +0000 | [diff] [blame] | 13 | //===----------------------------------------------------------------------===// |
| 14 | |
Thomas Lively | 2244292 | 2018-08-21 21:03:18 +0000 | [diff] [blame^] | 15 | // constrained immediate argument types |
| 16 | foreach SIZE = [8, 16] in |
| 17 | def ImmI#SIZE : ImmLeaf<i32, "return (Imm & ((1UL << "#SIZE#") - 1)) == Imm;">; |
Heejin Ahn | a0fd9c3 | 2018-08-14 18:53:27 +0000 | [diff] [blame] | 18 | foreach SIZE = [2, 4, 8, 16, 32] in |
| 19 | def LaneIdx#SIZE : ImmLeaf<i32, "return 0 <= Imm && Imm < "#SIZE#";">; |
Derek Schuff | 51ed131 | 2018-08-07 21:24:01 +0000 | [diff] [blame] | 20 | |
Thomas Lively | 2244292 | 2018-08-21 21:03:18 +0000 | [diff] [blame^] | 21 | // const vectors |
| 22 | multiclass ConstVec<ValueType vec_t, dag ops, dag pat, string args> { |
| 23 | defm CONST_V128_#vec_t : SIMD_I<(outs V128:$dst), ops, (outs), ops, |
| 24 | [(set V128:$dst, (vec_t pat))], |
| 25 | "v128.const\t$dst, "#args, |
| 26 | "v128.const\t"#args, 0>; |
| 27 | } |
| 28 | defm "" : ConstVec<v16i8, |
| 29 | (ins vec_i8imm_op:$i0, vec_i8imm_op:$i1, |
| 30 | vec_i8imm_op:$i2, vec_i8imm_op:$i3, |
| 31 | vec_i8imm_op:$i4, vec_i8imm_op:$i5, |
| 32 | vec_i8imm_op:$i6, vec_i8imm_op:$i7, |
| 33 | vec_i8imm_op:$i8, vec_i8imm_op:$i9, |
| 34 | vec_i8imm_op:$iA, vec_i8imm_op:$iB, |
| 35 | vec_i8imm_op:$iC, vec_i8imm_op:$iD, |
| 36 | vec_i8imm_op:$iE, vec_i8imm_op:$iF), |
| 37 | (build_vector ImmI8:$i0, ImmI8:$i1, ImmI8:$i2, ImmI8:$i3, |
| 38 | ImmI8:$i4, ImmI8:$i5, ImmI8:$i6, ImmI8:$i7, |
| 39 | ImmI8:$i8, ImmI8:$i9, ImmI8:$iA, ImmI8:$iB, |
| 40 | ImmI8:$iC, ImmI8:$iD, ImmI8:$iE, ImmI8:$iF), |
| 41 | !strconcat("$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7, ", |
| 42 | "$i8, $i9, $iA, $iB, $iC, $iD, $iE, $iF")>; |
| 43 | defm "" : ConstVec<v8i16, |
| 44 | (ins vec_i16imm_op:$i0, vec_i16imm_op:$i1, |
| 45 | vec_i16imm_op:$i2, vec_i16imm_op:$i3, |
| 46 | vec_i16imm_op:$i4, vec_i16imm_op:$i5, |
| 47 | vec_i16imm_op:$i6, vec_i16imm_op:$i7), |
| 48 | (build_vector |
| 49 | ImmI16:$i0, ImmI16:$i1, ImmI16:$i2, ImmI16:$i3, |
| 50 | ImmI16:$i4, ImmI16:$i5, ImmI16:$i6, ImmI16:$i7), |
| 51 | "$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7">; |
| 52 | defm "" : ConstVec<v4i32, |
| 53 | (ins vec_i32imm_op:$i0, vec_i32imm_op:$i1, |
| 54 | vec_i32imm_op:$i2, vec_i32imm_op:$i3), |
| 55 | (build_vector (i32 imm:$i0), (i32 imm:$i1), |
| 56 | (i32 imm:$i2), (i32 imm:$i3)), |
| 57 | "$i0, $i1, $i2, $i3">; |
| 58 | defm "" : ConstVec<v2i64, |
| 59 | (ins vec_i64imm_op:$i0, vec_i64imm_op:$i1), |
| 60 | (build_vector (i64 imm:$i0), (i64 imm:$i1)), |
| 61 | "$i0, $i1">; |
| 62 | defm "" : ConstVec<v4f32, |
| 63 | (ins f32imm_op:$i0, f32imm_op:$i1, |
| 64 | f32imm_op:$i2, f32imm_op:$i3), |
| 65 | (build_vector (f32 fpimm:$i0), (f32 fpimm:$i1), |
| 66 | (f32 fpimm:$i2), (f32 fpimm:$i3)), |
| 67 | "$i0, $i1, $i2, $i3">; |
| 68 | defm "" : ConstVec<v2f64, |
| 69 | (ins f64imm_op:$i0, f64imm_op:$i1), |
| 70 | (build_vector (f64 fpimm:$i0), (f64 fpimm:$i1)), |
| 71 | "$i0, $i1">; |
| 72 | |
Heejin Ahn | a0fd9c3 | 2018-08-14 18:53:27 +0000 | [diff] [blame] | 73 | // lane extraction |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 74 | multiclass ExtractLane<ValueType vec_t, string vec, ImmLeaf imm_t, |
| 75 | WebAssemblyRegClass reg_t, bits<32> simdop, |
| 76 | string suffix = "", SDNode extract = vector_extract> { |
| 77 | defm EXTRACT_LANE_#vec_t#suffix : |
Thomas Lively | 2244292 | 2018-08-21 21:03:18 +0000 | [diff] [blame^] | 78 | SIMD_I<(outs reg_t:$dst), (ins V128:$vec, i32imm_op:$idx), |
| 79 | (outs), (ins i32imm_op:$idx), |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 80 | [(set reg_t:$dst, (extract (vec_t V128:$vec), (i32 imm_t:$idx)))], |
| 81 | vec#".extract_lane"#suffix#"\t$dst, $vec, $idx", |
| 82 | vec#".extract_lane"#suffix#"\t$idx", simdop>; |
Heejin Ahn | a0fd9c3 | 2018-08-14 18:53:27 +0000 | [diff] [blame] | 83 | } |
| 84 | multiclass ExtractPat<ValueType lane_t, int mask> { |
| 85 | def _s : PatFrag<(ops node:$vec, node:$idx), |
| 86 | (i32 (sext_inreg |
| 87 | (i32 (vector_extract |
| 88 | node:$vec, |
| 89 | node:$idx |
| 90 | )), |
| 91 | lane_t |
| 92 | ))>; |
| 93 | def _u : PatFrag<(ops node:$vec, node:$idx), |
| 94 | (i32 (and |
| 95 | (i32 (vector_extract |
| 96 | node:$vec, |
| 97 | node:$idx |
| 98 | )), |
| 99 | (i32 mask) |
| 100 | ))>; |
| 101 | } |
| 102 | defm extract_i8x16 : ExtractPat<i8, 0xff>; |
| 103 | defm extract_i16x8 : ExtractPat<i16, 0xffff>; |
| 104 | multiclass ExtractLaneExtended<string sign, bits<32> baseInst> { |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 105 | defm "" : ExtractLane<v16i8, "i8x16", LaneIdx16, I32, baseInst, sign, |
| 106 | !cast<PatFrag>("extract_i8x16"#sign)>; |
| 107 | defm "" : ExtractLane<v8i16, "i16x8", LaneIdx8, I32, !add(baseInst, 2), sign, |
| 108 | !cast<PatFrag>("extract_i16x8"#sign)>; |
Heejin Ahn | a0fd9c3 | 2018-08-14 18:53:27 +0000 | [diff] [blame] | 109 | } |
Heejin Ahn | a0fd9c3 | 2018-08-14 18:53:27 +0000 | [diff] [blame] | 110 | let Defs = [ARGUMENTS] in { |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 111 | defm "" : ExtractLaneExtended<"_s", 9>; |
| 112 | defm "" : ExtractLaneExtended<"_u", 10>; |
| 113 | defm "" : ExtractLane<v4i32, "i32x4", LaneIdx4, I32, 13>; |
| 114 | defm "" : ExtractLane<v2i64, "i64x2", LaneIdx2, I64, 14>; |
| 115 | defm "" : ExtractLane<v4f32, "f32x4", LaneIdx4, F32, 15>; |
| 116 | defm "" : ExtractLane<v2f64, "f64x2", LaneIdx2, F64, 16>; |
Heejin Ahn | a0fd9c3 | 2018-08-14 18:53:27 +0000 | [diff] [blame] | 117 | } // Defs = [ARGUMENTS] |
| 118 | |
| 119 | // follow convention of making implicit expansions unsigned |
| 120 | def : Pat<(i32 (vector_extract (v16i8 V128:$vec), (i32 LaneIdx16:$idx))), |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 121 | (EXTRACT_LANE_v16i8_u V128:$vec, (i32 LaneIdx16:$idx))>; |
Heejin Ahn | a0fd9c3 | 2018-08-14 18:53:27 +0000 | [diff] [blame] | 122 | def : Pat<(i32 (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx))), |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 123 | (EXTRACT_LANE_v8i16_u V128:$vec, (i32 LaneIdx8:$idx))>; |
Heejin Ahn | a0fd9c3 | 2018-08-14 18:53:27 +0000 | [diff] [blame] | 124 | |
Derek Schuff | 82812fb | 2018-08-15 16:18:51 +0000 | [diff] [blame] | 125 | // lane replacement |
| 126 | multiclass ReplaceLane<ValueType vec_t, string vec, WebAssemblyRegClass reg_t, |
| 127 | ValueType lane_t, ImmLeaf imm_t, bits<32> simdop> { |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 128 | defm REPLACE_LANE_#vec_t : |
Thomas Lively | 2244292 | 2018-08-21 21:03:18 +0000 | [diff] [blame^] | 129 | SIMD_I<(outs V128:$dst), (ins V128:$vec, i32imm_op:$idx, reg_t:$x), |
| 130 | (outs), (ins i32imm_op:$idx), |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 131 | [(set V128:$dst, (vector_insert |
| 132 | (vec_t V128:$vec), (lane_t reg_t:$x), (i32 imm_t:$idx)))], |
| 133 | vec#".replace_lane\t$dst, $vec, $idx, $x", |
| 134 | vec#".replace_lane\t$idx", simdop>; |
Derek Schuff | 82812fb | 2018-08-15 16:18:51 +0000 | [diff] [blame] | 135 | } |
| 136 | let Defs = [ARGUMENTS] in { |
| 137 | defm "" : ReplaceLane<v16i8, "i8x16", I32, i32, LaneIdx16, 17>; |
| 138 | defm "" : ReplaceLane<v8i16, "i16x8", I32, i32, LaneIdx8, 18>; |
| 139 | defm "" : ReplaceLane<v4i32, "i32x4", I32, i32, LaneIdx4, 19>; |
| 140 | defm "" : ReplaceLane<v2i64, "i64x2", I64, i64, LaneIdx2, 20>; |
| 141 | defm "" : ReplaceLane<v4f32, "f32x4", F32, f32, LaneIdx4, 21>; |
| 142 | defm "" : ReplaceLane<v2f64, "f64x2", F64, f64, LaneIdx2, 22>; |
| 143 | } // Defs = [ARGUMENTS] |
Derek Schuff | 4ec8bca | 2018-08-15 00:30:27 +0000 | [diff] [blame] | 144 | |
| 145 | // splats |
| 146 | def splat2 : PatFrag<(ops node:$x), (build_vector node:$x, node:$x)>; |
| 147 | def splat4 : PatFrag<(ops node:$x), (build_vector |
| 148 | node:$x, node:$x, node:$x, node:$x)>; |
| 149 | def splat8 : PatFrag<(ops node:$x), (build_vector |
| 150 | node:$x, node:$x, node:$x, node:$x, |
| 151 | node:$x, node:$x, node:$x, node:$x)>; |
| 152 | def splat16 : PatFrag<(ops node:$x), (build_vector |
| 153 | node:$x, node:$x, node:$x, node:$x, |
| 154 | node:$x, node:$x, node:$x, node:$x, |
| 155 | node:$x, node:$x, node:$x, node:$x, |
| 156 | node:$x, node:$x, node:$x, node:$x)>; |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 157 | multiclass Splat<ValueType vec_t, string vec, WebAssemblyRegClass reg_t, |
Derek Schuff | 4ec8bca | 2018-08-15 00:30:27 +0000 | [diff] [blame] | 158 | PatFrag splat_pat, bits<32> simdop> { |
| 159 | defm SPLAT_#vec_t : SIMD_I<(outs V128:$dst), (ins reg_t:$x), (outs), (ins), |
| 160 | [(set (vec_t V128:$dst), (splat_pat reg_t:$x))], |
Thomas Lively | 5222cb6 | 2018-08-15 18:15:18 +0000 | [diff] [blame] | 161 | vec#".splat\t$dst, $x", vec#".splat", simdop>; |
Derek Schuff | 4ec8bca | 2018-08-15 00:30:27 +0000 | [diff] [blame] | 162 | } |
| 163 | let Defs = [ARGUMENTS] in { |
| 164 | defm "" : Splat<v16i8, "i8x16", I32, splat16, 3>; |
| 165 | defm "" : Splat<v8i16, "i16x8", I32, splat8, 4>; |
| 166 | defm "" : Splat<v4i32, "i32x4", I32, splat4, 5>; |
| 167 | defm "" : Splat<v2i64, "i64x2", I64, splat2, 6>; |
| 168 | defm "" : Splat<v4f32, "f32x4", F32, splat4, 7>; |
| 169 | defm "" : Splat<v2f64, "f64x2", F64, splat2, 8>; |
Derek Schuff | 82812fb | 2018-08-15 16:18:51 +0000 | [diff] [blame] | 170 | } // Defs = [ARGUMENTS] |
Derek Schuff | 4ec8bca | 2018-08-15 00:30:27 +0000 | [diff] [blame] | 171 | |
Heejin Ahn | a0fd9c3 | 2018-08-14 18:53:27 +0000 | [diff] [blame] | 172 | // arithmetic |
| 173 | let Defs = [ARGUMENTS] in { |
Derek Schuff | 51ed131 | 2018-08-07 21:24:01 +0000 | [diff] [blame] | 174 | let isCommutable = 1 in |
| 175 | defm ADD : SIMDBinaryInt<add, "add ", 24>; |
| 176 | defm SUB : SIMDBinaryInt<sub, "sub ", 28>; |
| 177 | let isCommutable = 1 in |
| 178 | defm MUL : SIMDBinaryInt<mul, "mul ", 32>; |
Derek Schuff | 51ed131 | 2018-08-07 21:24:01 +0000 | [diff] [blame] | 179 | let isCommutable = 1 in |
| 180 | defm ADD : SIMDBinaryFP<fadd, "add ", 122>; |
| 181 | defm SUB : SIMDBinaryFP<fsub, "sub ", 124>; |
| 182 | defm DIV : SIMDBinaryFP<fdiv, "div ", 126>; |
| 183 | let isCommutable = 1 in |
| 184 | defm MUL : SIMDBinaryFP<fmul, "mul ", 128>; |
Derek Schuff | 51ed131 | 2018-08-07 21:24:01 +0000 | [diff] [blame] | 185 | } // Defs = [ARGUMENTS] |