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//===----------------------------------------------------------------------===// 9/// 10/// \file 11/// WebAssembly SIMD operand code-gen constructs. 12/// 13//===----------------------------------------------------------------------===// 14 15// Instructions requiring HasSIMD128 and the simd128 prefix byte 16multiclass SIMD_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s, 17 list<dag> pattern_r, string asmstr_r = "", 18 string asmstr_s = "", bits<32> simdop = -1> { 19 defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s, 20 !or(0xfd00, !and(0xff, simdop))>, 21 Requires<[HasSIMD128]>; 22} 23 24defm "" : ARGUMENT<V128, v16i8>; 25defm "" : ARGUMENT<V128, v8i16>; 26defm "" : ARGUMENT<V128, v4i32>; 27defm "" : ARGUMENT<V128, v2i64>; 28defm "" : ARGUMENT<V128, v4f32>; 29defm "" : ARGUMENT<V128, v2f64>; 30 31// Constrained immediate argument types 32foreach SIZE = [8, 16] in 33def ImmI#SIZE : ImmLeaf<i32, 34 "return ((uint64_t)Imm & ((1UL << "#SIZE#") - 1)) == (uint64_t)Imm;" 35>; 36foreach SIZE = [2, 4, 8, 16, 32] in 37def LaneIdx#SIZE : ImmLeaf<i32, "return 0 <= Imm && Imm < "#SIZE#";">; 38 39//===----------------------------------------------------------------------===// 40// Constructing SIMD values 41//===----------------------------------------------------------------------===// 42 43// Constant: v128.const 44multiclass ConstVec<ValueType vec_t, dag ops, dag pat, string args> { 45 let isMoveImm = 1, isReMaterializable = 1 in 46 defm CONST_V128_#vec_t : SIMD_I<(outs V128:$dst), ops, (outs), ops, 47 [(set V128:$dst, (vec_t pat))], 48 "v128.const\t$dst, "#args, 49 "v128.const\t"#args, 0>; 50} 51 52defm "" : ConstVec<v16i8, 53 (ins vec_i8imm_op:$i0, vec_i8imm_op:$i1, 54 vec_i8imm_op:$i2, vec_i8imm_op:$i3, 55 vec_i8imm_op:$i4, vec_i8imm_op:$i5, 56 vec_i8imm_op:$i6, vec_i8imm_op:$i7, 57 vec_i8imm_op:$i8, vec_i8imm_op:$i9, 58 vec_i8imm_op:$iA, vec_i8imm_op:$iB, 59 vec_i8imm_op:$iC, vec_i8imm_op:$iD, 60 vec_i8imm_op:$iE, vec_i8imm_op:$iF), 61 (build_vector ImmI8:$i0, ImmI8:$i1, ImmI8:$i2, ImmI8:$i3, 62 ImmI8:$i4, ImmI8:$i5, ImmI8:$i6, ImmI8:$i7, 63 ImmI8:$i8, ImmI8:$i9, ImmI8:$iA, ImmI8:$iB, 64 ImmI8:$iC, ImmI8:$iD, ImmI8:$iE, ImmI8:$iF), 65 !strconcat("$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7, ", 66 "$i8, $i9, $iA, $iB, $iC, $iD, $iE, $iF")>; 67defm "" : ConstVec<v8i16, 68 (ins vec_i16imm_op:$i0, vec_i16imm_op:$i1, 69 vec_i16imm_op:$i2, vec_i16imm_op:$i3, 70 vec_i16imm_op:$i4, vec_i16imm_op:$i5, 71 vec_i16imm_op:$i6, vec_i16imm_op:$i7), 72 (build_vector 73 ImmI16:$i0, ImmI16:$i1, ImmI16:$i2, ImmI16:$i3, 74 ImmI16:$i4, ImmI16:$i5, ImmI16:$i6, ImmI16:$i7), 75 "$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7">; 76defm "" : ConstVec<v4i32, 77 (ins vec_i32imm_op:$i0, vec_i32imm_op:$i1, 78 vec_i32imm_op:$i2, vec_i32imm_op:$i3), 79 (build_vector (i32 imm:$i0), (i32 imm:$i1), 80 (i32 imm:$i2), (i32 imm:$i3)), 81 "$i0, $i1, $i2, $i3">; 82defm "" : ConstVec<v2i64, 83 (ins vec_i64imm_op:$i0, vec_i64imm_op:$i1), 84 (build_vector (i64 imm:$i0), (i64 imm:$i1)), 85 "$i0, $i1">; 86defm "" : ConstVec<v4f32, 87 (ins f32imm_op:$i0, f32imm_op:$i1, 88 f32imm_op:$i2, f32imm_op:$i3), 89 (build_vector (f32 fpimm:$i0), (f32 fpimm:$i1), 90 (f32 fpimm:$i2), (f32 fpimm:$i3)), 91 "$i0, $i1, $i2, $i3">; 92defm "" : ConstVec<v2f64, 93 (ins f64imm_op:$i0, f64imm_op:$i1), 94 (build_vector (f64 fpimm:$i0), (f64 fpimm:$i1)), 95 "$i0, $i1">; 96 97// Create vector with identical lanes: splat 98def splat2 : PatFrag<(ops node:$x), (build_vector node:$x, node:$x)>; 99def splat4 : PatFrag<(ops node:$x), (build_vector 100 node:$x, node:$x, node:$x, node:$x)>; 101def splat8 : PatFrag<(ops node:$x), (build_vector 102 node:$x, node:$x, node:$x, node:$x, 103 node:$x, node:$x, node:$x, node:$x)>; 104def splat16 : PatFrag<(ops node:$x), (build_vector 105 node:$x, node:$x, node:$x, node:$x, 106 node:$x, node:$x, node:$x, node:$x, 107 node:$x, node:$x, node:$x, node:$x, 108 node:$x, node:$x, node:$x, node:$x)>; 109 110multiclass Splat<ValueType vec_t, string vec, WebAssemblyRegClass reg_t, 111 PatFrag splat_pat, bits<32> simdop> { 112 // Prefer splats over v128.const for const splats (65 is lowest that works) 113 let AddedComplexity = 65 in 114 defm SPLAT_#vec_t : SIMD_I<(outs V128:$dst), (ins reg_t:$x), (outs), (ins), 115 [(set (vec_t V128:$dst), (splat_pat reg_t:$x))], 116 vec#".splat\t$dst, $x", vec#".splat", simdop>; 117} 118 119defm "" : Splat<v16i8, "i8x16", I32, splat16, 3>; 120defm "" : Splat<v8i16, "i16x8", I32, splat8, 4>; 121defm "" : Splat<v4i32, "i32x4", I32, splat4, 5>; 122defm "" : Splat<v2i64, "i64x2", I64, splat2, 6>; 123defm "" : Splat<v4f32, "f32x4", F32, splat4, 7>; 124defm "" : Splat<v2f64, "f64x2", F64, splat2, 8>; 125 126//===----------------------------------------------------------------------===// 127// Accessing lanes 128//===----------------------------------------------------------------------===// 129 130// Extract lane as a scalar: extract_lane / extract_lane_s / extract_lane_u 131multiclass ExtractLane<ValueType vec_t, string vec, ImmLeaf imm_t, 132 WebAssemblyRegClass reg_t, bits<32> simdop, 133 string suffix = "", SDNode extract = vector_extract> { 134 defm EXTRACT_LANE_#vec_t#suffix : 135 SIMD_I<(outs reg_t:$dst), (ins V128:$vec, vec_i8imm_op:$idx), 136 (outs), (ins vec_i8imm_op:$idx), 137 [(set reg_t:$dst, (extract (vec_t V128:$vec), (i32 imm_t:$idx)))], 138 vec#".extract_lane"#suffix#"\t$dst, $vec, $idx", 139 vec#".extract_lane"#suffix#"\t$idx", simdop>; 140} 141 142multiclass ExtractPat<ValueType lane_t, int mask> { 143 def _s : PatFrag<(ops node:$vec, node:$idx), 144 (i32 (sext_inreg 145 (i32 (vector_extract 146 node:$vec, 147 node:$idx 148 )), 149 lane_t 150 ))>; 151 def _u : PatFrag<(ops node:$vec, node:$idx), 152 (i32 (and 153 (i32 (vector_extract 154 node:$vec, 155 node:$idx 156 )), 157 (i32 mask) 158 ))>; 159} 160 161defm extract_i8x16 : ExtractPat<i8, 0xff>; 162defm extract_i16x8 : ExtractPat<i16, 0xffff>; 163 164multiclass ExtractLaneExtended<string sign, bits<32> baseInst> { 165 defm "" : ExtractLane<v16i8, "i8x16", LaneIdx16, I32, baseInst, sign, 166 !cast<PatFrag>("extract_i8x16"#sign)>; 167 defm "" : ExtractLane<v8i16, "i16x8", LaneIdx8, I32, !add(baseInst, 2), sign, 168 !cast<PatFrag>("extract_i16x8"#sign)>; 169} 170 171defm "" : ExtractLaneExtended<"_s", 9>; 172defm "" : ExtractLaneExtended<"_u", 10>; 173defm "" : ExtractLane<v4i32, "i32x4", LaneIdx4, I32, 13>; 174defm "" : ExtractLane<v2i64, "i64x2", LaneIdx2, I64, 14>; 175defm "" : ExtractLane<v4f32, "f32x4", LaneIdx4, F32, 15>; 176defm "" : ExtractLane<v2f64, "f64x2", LaneIdx2, F64, 16>; 177 178// Follow convention of making implicit expansions unsigned 179def : Pat<(i32 (vector_extract (v16i8 V128:$vec), (i32 LaneIdx16:$idx))), 180 (EXTRACT_LANE_v16i8_u V128:$vec, (i32 LaneIdx16:$idx))>; 181def : Pat<(i32 (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx))), 182 (EXTRACT_LANE_v8i16_u V128:$vec, (i32 LaneIdx8:$idx))>; 183 184// Replace lane value: replace_lane 185multiclass ReplaceLane<ValueType vec_t, string vec, ImmLeaf imm_t, 186 WebAssemblyRegClass reg_t, ValueType lane_t, 187 bits<32> simdop> { 188 defm REPLACE_LANE_#vec_t : 189 SIMD_I<(outs V128:$dst), (ins V128:$vec, vec_i8imm_op:$idx, reg_t:$x), 190 (outs), (ins vec_i8imm_op:$idx), 191 [(set V128:$dst, (vector_insert 192 (vec_t V128:$vec), (lane_t reg_t:$x), (i32 imm_t:$idx)))], 193 vec#".replace_lane\t$dst, $vec, $idx, $x", 194 vec#".replace_lane\t$idx", simdop>; 195} 196 197defm "" : ReplaceLane<v16i8, "i8x16", LaneIdx16, I32, i32, 17>; 198defm "" : ReplaceLane<v8i16, "i16x8", LaneIdx8, I32, i32, 18>; 199defm "" : ReplaceLane<v4i32, "i32x4", LaneIdx4, I32, i32, 19>; 200defm "" : ReplaceLane<v2i64, "i64x2", LaneIdx2, I64, i64, 20>; 201defm "" : ReplaceLane<v4f32, "f32x4", LaneIdx4, F32, f32, 21>; 202defm "" : ReplaceLane<v2f64, "f64x2", LaneIdx2, F64, f64, 22>; 203 204// Arbitrary other BUILD_VECTOR patterns 205def : Pat<(v16i8 (build_vector 206 (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3), 207 (i32 I32:$x4), (i32 I32:$x5), (i32 I32:$x6), (i32 I32:$x7), 208 (i32 I32:$x8), (i32 I32:$x9), (i32 I32:$x10), (i32 I32:$x11), 209 (i32 I32:$x12), (i32 I32:$x13), (i32 I32:$x14), (i32 I32:$x15) 210 )), 211 (v16i8 (REPLACE_LANE_v16i8 212 (v16i8 (REPLACE_LANE_v16i8 213 (v16i8 (REPLACE_LANE_v16i8 214 (v16i8 (REPLACE_LANE_v16i8 215 (v16i8 (REPLACE_LANE_v16i8 216 (v16i8 (REPLACE_LANE_v16i8 217 (v16i8 (REPLACE_LANE_v16i8 218 (v16i8 (REPLACE_LANE_v16i8 219 (v16i8 (REPLACE_LANE_v16i8 220 (v16i8 (REPLACE_LANE_v16i8 221 (v16i8 (REPLACE_LANE_v16i8 222 (v16i8 (REPLACE_LANE_v16i8 223 (v16i8 (REPLACE_LANE_v16i8 224 (v16i8 (REPLACE_LANE_v16i8 225 (v16i8 (REPLACE_LANE_v16i8 226 (v16i8 (SPLAT_v16i8 (i32 I32:$x0))), 227 1, I32:$x1 228 )), 229 2, I32:$x2 230 )), 231 3, I32:$x3 232 )), 233 4, I32:$x4 234 )), 235 5, I32:$x5 236 )), 237 6, I32:$x6 238 )), 239 7, I32:$x7 240 )), 241 8, I32:$x8 242 )), 243 9, I32:$x9 244 )), 245 10, I32:$x10 246 )), 247 11, I32:$x11 248 )), 249 12, I32:$x12 250 )), 251 13, I32:$x13 252 )), 253 14, I32:$x14 254 )), 255 15, I32:$x15 256 ))>; 257def : Pat<(v8i16 (build_vector 258 (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3), 259 (i32 I32:$x4), (i32 I32:$x5), (i32 I32:$x6), (i32 I32:$x7) 260 )), 261 (v8i16 (REPLACE_LANE_v8i16 262 (v8i16 (REPLACE_LANE_v8i16 263 (v8i16 (REPLACE_LANE_v8i16 264 (v8i16 (REPLACE_LANE_v8i16 265 (v8i16 (REPLACE_LANE_v8i16 266 (v8i16 (REPLACE_LANE_v8i16 267 (v8i16 (REPLACE_LANE_v8i16 268 (v8i16 (SPLAT_v8i16 (i32 I32:$x0))), 269 1, I32:$x1 270 )), 271 2, I32:$x2 272 )), 273 3, I32:$x3 274 )), 275 4, I32:$x4 276 )), 277 5, I32:$x5 278 )), 279 6, I32:$x6 280 )), 281 7, I32:$x7 282 ))>; 283def : Pat<(v4i32 (build_vector 284 (i32 I32:$x0), (i32 I32:$x1), (i32 I32:$x2), (i32 I32:$x3) 285 )), 286 (v4i32 (REPLACE_LANE_v4i32 287 (v4i32 (REPLACE_LANE_v4i32 288 (v4i32 (REPLACE_LANE_v4i32 289 (v4i32 (SPLAT_v4i32 (i32 I32:$x0))), 290 1, I32:$x1 291 )), 292 2, I32:$x2 293 )), 294 3, I32:$x3 295 ))>; 296def : Pat<(v2i64 (build_vector (i64 I64:$x0), (i64 I64:$x1))), 297 (v2i64 (REPLACE_LANE_v2i64 298 (v2i64 (SPLAT_v2i64 (i64 I64:$x0))), 1, I64:$x1))>; 299def : Pat<(v4f32 (build_vector 300 (f32 F32:$x0), (f32 F32:$x1), (f32 F32:$x2), (f32 F32:$x3) 301 )), 302 (v4f32 (REPLACE_LANE_v4f32 303 (v4f32 (REPLACE_LANE_v4f32 304 (v4f32 (REPLACE_LANE_v4f32 305 (v4f32 (SPLAT_v4f32 (f32 F32:$x0))), 306 1, F32:$x1 307 )), 308 2, F32:$x2 309 )), 310 3, F32:$x3 311 ))>; 312def : Pat<(v2f64 (build_vector (f64 F64:$x0), (f64 F64:$x1))), 313 (v2f64 (REPLACE_LANE_v2f64 314 (v2f64 (SPLAT_v2f64 (f64 F64:$x0))), 1, F64:$x1))>; 315 316// Shuffle lanes: shuffle 317defm SHUFFLE_v16i8 : 318 SIMD_I<(outs V128:$dst), 319 (ins V128:$x, V128:$y, 320 vec_i8imm_op:$m0, vec_i8imm_op:$m1, 321 vec_i8imm_op:$m2, vec_i8imm_op:$m3, 322 vec_i8imm_op:$m4, vec_i8imm_op:$m5, 323 vec_i8imm_op:$m6, vec_i8imm_op:$m7, 324 vec_i8imm_op:$m8, vec_i8imm_op:$m9, 325 vec_i8imm_op:$mA, vec_i8imm_op:$mB, 326 vec_i8imm_op:$mC, vec_i8imm_op:$mD, 327 vec_i8imm_op:$mE, vec_i8imm_op:$mF), 328 (outs), 329 (ins 330 vec_i8imm_op:$m0, vec_i8imm_op:$m1, 331 vec_i8imm_op:$m2, vec_i8imm_op:$m3, 332 vec_i8imm_op:$m4, vec_i8imm_op:$m5, 333 vec_i8imm_op:$m6, vec_i8imm_op:$m7, 334 vec_i8imm_op:$m8, vec_i8imm_op:$m9, 335 vec_i8imm_op:$mA, vec_i8imm_op:$mB, 336 vec_i8imm_op:$mC, vec_i8imm_op:$mD, 337 vec_i8imm_op:$mE, vec_i8imm_op:$mF), 338 [], 339 "v8x16.shuffle\t$dst, $x, $y, "# 340 "$m0, $m1, $m2, $m3, $m4, $m5, $m6, $m7, "# 341 "$m8, $m9, $mA, $mB, $mC, $mD, $mE, $mF", 342 "v8x16.shuffle\t"# 343 "$m0, $m1, $m2, $m3, $m4, $m5, $m6, $m7, "# 344 "$m8, $m9, $mA, $mB, $mC, $mD, $mE, $mF", 345 23>; 346 347// Shuffles after custom lowering 348def wasm_shuffle_t : SDTypeProfile<1, 18, []>; 349def wasm_shuffle : SDNode<"WebAssemblyISD::SHUFFLE", wasm_shuffle_t>; 350foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { 351def : Pat<(v16i8 (wasm_shuffle (vec_t V128:$x), (vec_t V128:$y), 352 (i32 LaneIdx32:$m0), (i32 LaneIdx32:$m1), 353 (i32 LaneIdx32:$m2), (i32 LaneIdx32:$m3), 354 (i32 LaneIdx32:$m4), (i32 LaneIdx32:$m5), 355 (i32 LaneIdx32:$m6), (i32 LaneIdx32:$m7), 356 (i32 LaneIdx32:$m8), (i32 LaneIdx32:$m9), 357 (i32 LaneIdx32:$mA), (i32 LaneIdx32:$mB), 358 (i32 LaneIdx32:$mC), (i32 LaneIdx32:$mD), 359 (i32 LaneIdx32:$mE), (i32 LaneIdx32:$mF))), 360 (v16i8 (SHUFFLE_v16i8 (vec_t V128:$x), (vec_t V128:$y), 361 (i32 LaneIdx32:$m0), (i32 LaneIdx32:$m1), 362 (i32 LaneIdx32:$m2), (i32 LaneIdx32:$m3), 363 (i32 LaneIdx32:$m4), (i32 LaneIdx32:$m5), 364 (i32 LaneIdx32:$m6), (i32 LaneIdx32:$m7), 365 (i32 LaneIdx32:$m8), (i32 LaneIdx32:$m9), 366 (i32 LaneIdx32:$mA), (i32 LaneIdx32:$mB), 367 (i32 LaneIdx32:$mC), (i32 LaneIdx32:$mD), 368 (i32 LaneIdx32:$mE), (i32 LaneIdx32:$mF)))>; 369} 370 371//===----------------------------------------------------------------------===// 372// Integer arithmetic 373//===----------------------------------------------------------------------===// 374 375multiclass SIMDBinary<ValueType vec_t, string vec, SDNode node, string name, 376 bits<32> simdop> { 377 defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), 378 (outs), (ins), 379 [(set (vec_t V128:$dst), 380 (node (vec_t V128:$lhs), (vec_t V128:$rhs)) 381 )], 382 vec#"."#name#"\t$dst, $lhs, $rhs", vec#"."#name, 383 simdop>; 384} 385 386multiclass SIMDBinaryIntNoI64x2<SDNode node, string name, bits<32> baseInst> { 387 defm "" : SIMDBinary<v16i8, "i8x16", node, name, baseInst>; 388 defm "" : SIMDBinary<v8i16, "i16x8", node, name, !add(baseInst, 1)>; 389 defm "" : SIMDBinary<v4i32, "i32x4", node, name, !add(baseInst, 2)>; 390} 391 392multiclass SIMDBinaryInt<SDNode node, string name, bits<32> baseInst> { 393 defm "" : SIMDBinaryIntNoI64x2<node, name, baseInst>; 394 defm "" : SIMDBinary<v2i64, "i64x2", node, name, !add(baseInst, 3)>; 395} 396 397// Integer vector negation 398def ivneg : PatFrag<(ops node:$in), (sub immAllZerosV, node:$in)>; 399 400// Integer addition: add 401let isCommutable = 1 in 402defm ADD : SIMDBinaryInt<add, "add", 24>; 403 404// Integer subtraction: sub 405defm SUB : SIMDBinaryInt<sub, "sub", 28>; 406 407// Integer multiplication: mul 408defm MUL : SIMDBinaryIntNoI64x2<mul, "mul", 32>; 409 410// Integer negation: neg 411multiclass SIMDNeg<ValueType vec_t, string vec, SDNode neg, bits<32> simdop> { 412 defm NEG_#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), 413 [(set (vec_t V128:$dst), 414 (vec_t (neg (vec_t V128:$vec))) 415 )], 416 vec#".neg\t$dst, $vec", vec#".neg", simdop>; 417} 418 419defm "" : SIMDNeg<v16i8, "i8x16", ivneg, 36>; 420defm "" : SIMDNeg<v8i16, "i16x8", ivneg, 37>; 421defm "" : SIMDNeg<v4i32, "i32x4", ivneg, 38>; 422defm "" : SIMDNeg<v2i64, "i64x2", ivneg, 39>; 423 424//===----------------------------------------------------------------------===// 425// Saturating integer arithmetic 426//===----------------------------------------------------------------------===// 427 428multiclass SIMDBinarySat<SDNode node, string name, bits<32> baseInst> { 429 defm "" : SIMDBinary<v16i8, "i8x16", node, name, baseInst>; 430 defm "" : SIMDBinary<v8i16, "i16x8", node, name, !add(baseInst, 2)>; 431} 432 433// Saturating integer addition: add_saturate_s / add_saturate_u 434let isCommutable = 1 in { 435defm ADD_SAT_S : 436 SIMDBinarySat<int_wasm_add_saturate_signed, "add_saturate_s", 40>; 437defm ADD_SAT_U : 438 SIMDBinarySat<int_wasm_add_saturate_unsigned, "add_saturate_u", 41>; 439} // isCommutable = 1 440 441// Saturating integer subtraction: sub_saturate_s / sub_saturate_u 442defm SUB_SAT_S : 443 SIMDBinarySat<int_wasm_sub_saturate_signed, "sub_saturate_s", 44>; 444defm SUB_SAT_U : 445 SIMDBinarySat<int_wasm_sub_saturate_unsigned, "sub_saturate_u", 45>; 446 447//===----------------------------------------------------------------------===// 448// Bit shifts 449//===----------------------------------------------------------------------===// 450 451multiclass SIMDShift<ValueType vec_t, string vec, SDNode node, dag shift_vec, 452 string name, bits<32> simdop> { 453 defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec, I32:$x), 454 (outs), (ins), 455 [(set (vec_t V128:$dst), 456 (node V128:$vec, (vec_t shift_vec)))], 457 vec#"."#name#"\t$dst, $vec, $x", vec#"."#name, simdop>; 458} 459 460multiclass SIMDShiftInt<SDNode node, string name, bits<32> baseInst, int skip> { 461 defm "" : SIMDShift<v16i8, "i8x16", node, (splat16 I32:$x), name, baseInst>; 462 defm "" : SIMDShift<v8i16, "i16x8", node, (splat8 I32:$x), name, 463 !add(baseInst, !if(skip, 2, 1))>; 464 defm "" : SIMDShift<v4i32, "i32x4", node, (splat4 I32:$x), name, 465 !add(baseInst, !if(skip, 4, 2))>; 466 defm "" : SIMDShift<v2i64, "i64x2", node, (splat2 (i64 (zext I32:$x))), 467 name, !add(baseInst, !if(skip, 6, 3))>; 468} 469 470// Left shift by scalar: shl 471defm SHL : SIMDShiftInt<shl, "shl", 48, 0>; 472 473// Right shift by scalar: shr_s / shr_u 474defm SHR_S : SIMDShiftInt<sra, "shr_s", 52, 1>; 475defm SHR_U : SIMDShiftInt<srl, "shr_u", 53, 1>; 476 477// Truncate i64 shift operands to i32s 478foreach shifts = [[shl, SHL_v2i64], [sra, SHR_S_v2i64], [srl, SHR_U_v2i64]] in 479def : Pat<(v2i64 (shifts[0] (v2i64 V128:$vec), (v2i64 (splat2 I64:$x)))), 480 (v2i64 (shifts[1] (v2i64 V128:$vec), (I32_WRAP_I64 I64:$x)))>; 481 482//===----------------------------------------------------------------------===// 483// Bitwise operations 484//===----------------------------------------------------------------------===// 485 486multiclass SIMDBitwise<SDNode node, string name, bits<32> simdop> { 487 defm "" : SIMDBinary<v16i8, "v128", node, name, simdop>; 488 defm "" : SIMDBinary<v8i16, "v128", node, name, simdop>; 489 defm "" : SIMDBinary<v4i32, "v128", node, name, simdop>; 490 defm "" : SIMDBinary<v2i64, "v128", node, name, simdop>; 491} 492 493// Bitwise logic: v128.and / v128.or / v128.xor 494let isCommutable = 1 in { 495defm AND : SIMDBitwise<and, "and", 60>; 496defm OR : SIMDBitwise<or, "or", 61>; 497defm XOR : SIMDBitwise<xor, "xor", 62>; 498} // isCommutable = 1 499 500// Bitwise logic: v128.not 501multiclass SIMDNot<ValueType vec_t> { 502 defm NOT_#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), 503 [(set (vec_t V128:$dst), (vec_t (vnot V128:$vec)))], 504 "v128.not\t$dst, $vec", "v128.not", 63>; 505} 506 507defm "" : SIMDNot<v16i8>; 508defm "" : SIMDNot<v8i16>; 509defm "" : SIMDNot<v4i32>; 510defm "" : SIMDNot<v2i64>; 511 512// Bitwise select: v128.bitselect 513multiclass Bitselect<ValueType vec_t> { 514 defm BITSELECT_#vec_t : 515 SIMD_I<(outs V128:$dst), (ins V128:$v1, V128:$v2, V128:$c), (outs), (ins), 516 [(set (vec_t V128:$dst), 517 (vec_t (int_wasm_bitselect 518 (vec_t V128:$c), (vec_t V128:$v1), (vec_t V128:$v2) 519 )) 520 )], 521 "v128.bitselect\t$dst, $v1, $v2, $c", "v128.bitselect", 64>; 522} 523 524foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in 525defm "" : Bitselect<vec_t>; 526 527// Bitselect is equivalent to (c & v1) | (~c & v2) 528foreach vec_t = [v16i8, v8i16, v4i32, v2i64] in 529 def : Pat<(vec_t (or (and (vec_t V128:$c), (vec_t V128:$v1)), 530 (and (vnot V128:$c), (vec_t V128:$v2)))), 531 (!cast<Instruction>("BITSELECT_"#vec_t) 532 V128:$v1, V128:$v2, V128:$c)>; 533 534//===----------------------------------------------------------------------===// 535// Boolean horizontal reductions 536//===----------------------------------------------------------------------===// 537 538multiclass SIMDReduceVec<ValueType vec_t, string vec, string name, SDNode op, 539 bits<32> simdop> { 540 defm _#vec_t : SIMD_I<(outs I32:$dst), (ins V128:$vec), (outs), (ins), 541 [(set I32:$dst, (i32 (op (vec_t V128:$vec))))], 542 vec#"."#name#"\t$dst, $vec", vec#"."#name, simdop>; 543} 544 545multiclass SIMDReduce<string name, SDNode op, bits<32> baseInst> { 546 defm "" : SIMDReduceVec<v16i8, "i8x16", name, op, baseInst>; 547 defm "" : SIMDReduceVec<v8i16, "i16x8", name, op, !add(baseInst, 1)>; 548 defm "" : SIMDReduceVec<v4i32, "i32x4", name, op, !add(baseInst, 2)>; 549 defm "" : SIMDReduceVec<v2i64, "i64x2", name, op, !add(baseInst, 3)>; 550} 551 552// Any lane true: any_true 553defm ANYTRUE : SIMDReduce<"any_true", int_wasm_anytrue, 65>; 554 555// All lanes true: all_true 556defm ALLTRUE : SIMDReduce<"all_true", int_wasm_alltrue, 69>; 557 558//===----------------------------------------------------------------------===// 559// Comparisons 560//===----------------------------------------------------------------------===// 561 562multiclass SIMDCondition<ValueType vec_t, ValueType out_t, string vec, 563 string name, CondCode cond, bits<32> simdop> { 564 defm _#vec_t : 565 SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), (outs), (ins), 566 [(set (out_t V128:$dst), 567 (setcc (vec_t V128:$lhs), (vec_t V128:$rhs), cond))], 568 vec#"."#name#"\t$dst, $lhs, $rhs", vec#"."#name, simdop>; 569} 570 571multiclass SIMDConditionInt<string name, CondCode cond, bits<32> baseInst, 572 int step = 1> { 573 defm "" : SIMDCondition<v16i8, v16i8, "i8x16", name, cond, baseInst>; 574 defm "" : SIMDCondition<v8i16, v8i16, "i16x8", name, cond, 575 !add(baseInst, step)>; 576 defm "" : SIMDCondition<v4i32, v4i32, "i32x4", name, cond, 577 !add(!add(baseInst, step), step)>; 578} 579 580multiclass SIMDConditionFP<string name, CondCode cond, bits<32> baseInst> { 581 defm "" : SIMDCondition<v4f32, v4i32, "f32x4", name, cond, baseInst>; 582 defm "" : SIMDCondition<v2f64, v2i64, "f64x2", name, cond, 583 !add(baseInst, 1)>; 584} 585 586// Equality: eq 587let isCommutable = 1 in { 588defm EQ : SIMDConditionInt<"eq", SETEQ, 73>; 589defm EQ : SIMDConditionFP<"eq", SETOEQ, 77>; 590} // isCommutable = 1 591 592// Non-equality: ne 593let isCommutable = 1 in { 594defm NE : SIMDConditionInt<"ne", SETNE, 79>; 595defm NE : SIMDConditionFP<"ne", SETUNE, 83>; 596} // isCommutable = 1 597 598// Less than: lt_s / lt_u / lt 599defm LT_S : SIMDConditionInt<"lt_s", SETLT, 85, 2>; 600defm LT_U : SIMDConditionInt<"lt_u", SETULT, 86, 2>; 601defm LT : SIMDConditionFP<"lt", SETOLT, 93>; 602 603// Less than or equal: le_s / le_u / le 604defm LE_S : SIMDConditionInt<"le_s", SETLE, 95, 2>; 605defm LE_U : SIMDConditionInt<"le_u", SETULE, 96, 2>; 606defm LE : SIMDConditionFP<"le", SETOLE, 103>; 607 608// Greater than: gt_s / gt_u / gt 609defm GT_S : SIMDConditionInt<"gt_s", SETGT, 105, 2>; 610defm GT_U : SIMDConditionInt<"gt_u", SETUGT, 106, 2>; 611defm GT : SIMDConditionFP<"gt", SETOGT, 113>; 612 613// Greater than or equal: ge_s / ge_u / ge 614defm GE_S : SIMDConditionInt<"ge_s", SETGE, 115, 2>; 615defm GE_U : SIMDConditionInt<"ge_u", SETUGE, 116, 2>; 616defm GE : SIMDConditionFP<"ge", SETOGE, 123>; 617 618// Lower float comparisons that don't care about NaN to standard WebAssembly 619// float comparisons. These instructions are generated in the target-independent 620// expansion of unordered comparisons and ordered ne. 621def : Pat<(v4i32 (seteq (v4f32 V128:$lhs), (v4f32 V128:$rhs))), 622 (v4i32 (EQ_v4f32 (v4f32 V128:$lhs), (v4f32 V128:$rhs)))>; 623def : Pat<(v4i32 (setne (v4f32 V128:$lhs), (v4f32 V128:$rhs))), 624 (v4i32 (NE_v4f32 (v4f32 V128:$lhs), (v4f32 V128:$rhs)))>; 625def : Pat<(v2i64 (seteq (v2f64 V128:$lhs), (v2f64 V128:$rhs))), 626 (v2i64 (EQ_v2f64 (v2f64 V128:$lhs), (v2f64 V128:$rhs)))>; 627def : Pat<(v2i64 (setne (v2f64 V128:$lhs), (v2f64 V128:$rhs))), 628 (v2i64 (NE_v2f64 (v2f64 V128:$lhs), (v2f64 V128:$rhs)))>; 629 630//===----------------------------------------------------------------------===// 631// Load and store 632//===----------------------------------------------------------------------===// 633 634// Load: v128.load 635multiclass SIMDLoad<ValueType vec_t> { 636 let mayLoad = 1 in 637 defm LOAD_#vec_t : 638 SIMD_I<(outs V128:$dst), (ins P2Align:$align, offset32_op:$off, I32:$addr), 639 (outs), (ins P2Align:$align, offset32_op:$off), [], 640 "v128.load\t$dst, ${off}(${addr})$align", 641 "v128.load\t$off$align", 1>; 642} 643 644foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { 645defm "" : SIMDLoad<vec_t>; 646 647// Def load and store patterns from WebAssemblyInstrMemory.td for vector types 648def : LoadPatNoOffset<vec_t, load, !cast<NI>("LOAD_"#vec_t)>; 649def : LoadPatImmOff<vec_t, load, regPlusImm, !cast<NI>("LOAD_"#vec_t)>; 650def : LoadPatImmOff<vec_t, load, or_is_add, !cast<NI>("LOAD_"#vec_t)>; 651def : LoadPatGlobalAddr<vec_t, load, !cast<NI>("LOAD_"#vec_t)>; 652def : LoadPatExternalSym<vec_t, load, !cast<NI>("LOAD_"#vec_t)>; 653def : LoadPatOffsetOnly<vec_t, load, !cast<NI>("LOAD_"#vec_t)>; 654def : LoadPatGlobalAddrOffOnly<vec_t, load, !cast<NI>("LOAD_"#vec_t)>; 655def : LoadPatExternSymOffOnly<vec_t, load, !cast<NI>("LOAD_"#vec_t)>; 656} 657 658// Store: v128.store 659multiclass SIMDStore<ValueType vec_t> { 660 let mayStore = 1 in 661 defm STORE_#vec_t : 662 SIMD_I<(outs), (ins P2Align:$align, offset32_op:$off, I32:$addr, V128:$vec), 663 (outs), (ins P2Align:$align, offset32_op:$off), [], 664 "v128.store\t${off}(${addr})$align, $vec", 665 "v128.store\t$off$align", 2>; 666} 667 668foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { 669defm "" : SIMDStore<vec_t>; 670 671// Def load and store patterns from WebAssemblyInstrMemory.td for vector types 672def : StorePatNoOffset<vec_t, store, !cast<NI>("STORE_"#vec_t)>; 673def : StorePatImmOff<vec_t, store, regPlusImm, !cast<NI>("STORE_"#vec_t)>; 674def : StorePatImmOff<vec_t, store, or_is_add, !cast<NI>("STORE_"#vec_t)>; 675def : StorePatGlobalAddr<vec_t, store, !cast<NI>("STORE_"#vec_t)>; 676def : StorePatExternalSym<vec_t, store, !cast<NI>("STORE_"#vec_t)>; 677def : StorePatOffsetOnly<vec_t, store, !cast<NI>("STORE_"#vec_t)>; 678def : StorePatGlobalAddrOffOnly<vec_t, store, !cast<NI>("STORE_"#vec_t)>; 679def : StorePatExternSymOffOnly<vec_t, store, !cast<NI>("STORE_"#vec_t)>; 680} 681 682//===----------------------------------------------------------------------===// 683// Floating-point sign bit operations 684//===----------------------------------------------------------------------===// 685 686// Negation: neg 687defm "" : SIMDNeg<v4f32, "f32x4", fneg, 125>; 688defm "" : SIMDNeg<v2f64, "f64x2", fneg, 126>; 689 690// Absolute value: abs 691multiclass SIMDAbs<ValueType vec_t, string vec, bits<32> simdop> { 692 defm ABS_#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), 693 [(set (vec_t V128:$dst), (vec_t (fabs V128:$vec)))], 694 vec#".abs\t$dst, $vec", vec#".abs", simdop>; 695} 696 697defm "" : SIMDAbs<v4f32, "f32x4", 127>; 698defm "" : SIMDAbs<v2f64, "f64x2", 128>; 699 700//===----------------------------------------------------------------------===// 701// Floating-point min and max 702//===----------------------------------------------------------------------===// 703 704multiclass SIMDBinaryFP<SDNode node, string name, bits<32> baseInst> { 705 defm "" : SIMDBinary<v4f32, "f32x4", node, name, baseInst>; 706 defm "" : SIMDBinary<v2f64, "f64x2", node, name, !add(baseInst, 1)>; 707} 708 709// NaN-propagating minimum: min 710defm MIN : SIMDBinaryFP<fminnan, "min", 129>; 711 712// NaN-propagating maximum: max 713defm MAX : SIMDBinaryFP<fmaxnan, "max", 131>; 714 715//===----------------------------------------------------------------------===// 716// Floating-point arithmetic 717//===----------------------------------------------------------------------===// 718 719// Addition: add 720let isCommutable = 1 in 721defm ADD : SIMDBinaryFP<fadd, "add", 133>; 722 723// Subtraction: sub 724defm SUB : SIMDBinaryFP<fsub, "sub", 135>; 725 726// Division: div 727defm DIV : SIMDBinaryFP<fdiv, "div", 137>; 728 729// Multiplication: mul 730let isCommutable = 1 in 731defm MUL : SIMDBinaryFP<fmul, "mul", 139>; 732 733// Square root: sqrt 734multiclass SIMDSqrt<ValueType vec_t, string vec, bits<32> simdop> { 735 defm SQRT_#vec_t : 736 SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), 737 [(set (vec_t V128:$dst), (vec_t (fsqrt V128:$vec)))], 738 vec#".sqrt\t$dst, $vec", vec#".sqrt", simdop>; 739} 740 741defm "" : SIMDSqrt<v4f32, "f32x4", 141>; 742defm "" : SIMDSqrt<v2f64, "f64x2", 142>; 743 744//===----------------------------------------------------------------------===// 745// Conversions 746//===----------------------------------------------------------------------===// 747 748multiclass SIMDConvert<ValueType vec_t, ValueType arg_t, SDNode op, 749 string name, bits<32> simdop> { 750 defm op#_#vec_t#_#arg_t : 751 SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), 752 [(set (vec_t V128:$dst), (vec_t (op (arg_t V128:$vec))))], 753 name#"\t$dst, $vec", name, simdop>; 754} 755 756// Integer to floating point: convert_s / convert_u 757defm "" : SIMDConvert<v4f32, v4i32, sint_to_fp, "f32x4.convert_s/i32x4", 143>; 758defm "" : SIMDConvert<v4f32, v4i32, uint_to_fp, "f32x4.convert_u/i32x4", 144>; 759defm "" : SIMDConvert<v2f64, v2i64, sint_to_fp, "f64x2.convert_s/i64x2", 145>; 760defm "" : SIMDConvert<v2f64, v2i64, uint_to_fp, "f64x2.convert_u/i64x2", 146>; 761 762// Floating point to integer with saturation: trunc_sat_s / trunc_sat_u 763defm "" : SIMDConvert<v4i32, v4f32, fp_to_sint, "i32x4.trunc_sat_s/f32x4", 147>; 764defm "" : SIMDConvert<v4i32, v4f32, fp_to_uint, "i32x4.trunc_sat_u/f32x4", 148>; 765defm "" : SIMDConvert<v2i64, v2f64, fp_to_sint, "i64x2.trunc_sat_s/f64x2", 149>; 766defm "" : SIMDConvert<v2i64, v2f64, fp_to_uint, "i64x2.trunc_sat_u/f64x2", 150>; 767 768// Lower llvm.wasm.trunc.saturate.* to saturating instructions 769def : Pat<(v4i32 (int_wasm_trunc_saturate_signed (v4f32 V128:$src))), 770 (fp_to_sint_v4i32_v4f32 (v4f32 V128:$src))>; 771def : Pat<(v4i32 (int_wasm_trunc_saturate_unsigned (v4f32 V128:$src))), 772 (fp_to_uint_v4i32_v4f32 (v4f32 V128:$src))>; 773def : Pat<(v2i64 (int_wasm_trunc_saturate_signed (v2f64 V128:$src))), 774 (fp_to_sint_v2i64_v2f64 (v2f64 V128:$src))>; 775def : Pat<(v2i64 (int_wasm_trunc_saturate_unsigned (v2f64 V128:$src))), 776 (fp_to_uint_v2i64_v2f64 (v2f64 V128:$src))>; 777 778// Bitcasts are nops 779// Matching bitcast t1 to t1 causes strange errors, so avoid repeating types 780foreach t1 = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in 781foreach t2 = !foldl( 782 []<ValueType>, [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], 783 acc, cur, !if(!eq(!cast<string>(t1), !cast<string>(cur)), 784 acc, !listconcat(acc, [cur]) 785 ) 786) in 787def : Pat<(t1 (bitconvert (t2 V128:$v))), (t1 V128:$v)>; 788