1// WebAssemblyInstrSIMD.td - WebAssembly SIMD codegen support -*- tablegen -*-// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8/// 9/// \file 10/// WebAssembly SIMD operand code-gen constructs. 11/// 12//===----------------------------------------------------------------------===// 13 14// Instructions requiring HasSIMD128 and the simd128 prefix byte 15multiclass SIMD_I<dag oops_r, dag iops_r, dag oops_s, dag iops_s, 16 list<dag> pattern_r, string asmstr_r = "", 17 string asmstr_s = "", bits<32> simdop = -1> { 18 defm "" : I<oops_r, iops_r, oops_s, iops_s, pattern_r, asmstr_r, asmstr_s, 19 !or(0xfd00, !and(0xff, simdop))>, 20 Requires<[HasSIMD128]>; 21} 22 23defm "" : ARGUMENT<V128, v16i8>; 24defm "" : ARGUMENT<V128, v8i16>; 25defm "" : ARGUMENT<V128, v4i32>; 26defm "" : ARGUMENT<V128, v2i64>; 27defm "" : ARGUMENT<V128, v4f32>; 28defm "" : ARGUMENT<V128, v2f64>; 29 30// Constrained immediate argument types 31foreach SIZE = [8, 16] in 32def ImmI#SIZE : ImmLeaf<i32, 33 "return -(1 << ("#SIZE#" - 1)) <= Imm && Imm < (1 << ("#SIZE#" - 1));" 34>; 35foreach SIZE = [2, 4, 8, 16, 32] in 36def LaneIdx#SIZE : ImmLeaf<i32, "return 0 <= Imm && Imm < "#SIZE#";">; 37 38//===----------------------------------------------------------------------===// 39// Load and store 40//===----------------------------------------------------------------------===// 41 42// Load: v128.load 43let mayLoad = 1, UseNamedOperandTable = 1 in { 44defm LOAD_V128_A32 : 45 SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr), 46 (outs), (ins P2Align:$p2align, offset32_op:$off), [], 47 "v128.load\t$dst, ${off}(${addr})$p2align", 48 "v128.load\t$off$p2align", 0>; 49defm LOAD_V128_A64 : 50 SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr), 51 (outs), (ins P2Align:$p2align, offset64_op:$off), [], 52 "v128.load\t$dst, ${off}(${addr})$p2align", 53 "v128.load\t$off$p2align", 0>; 54} 55 56// Def load and store patterns from WebAssemblyInstrMemory.td for vector types 57foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { 58defm : LoadPatNoOffset<vec_t, load, "LOAD_V128">; 59defm : LoadPatImmOff<vec_t, load, regPlusImm, "LOAD_V128">; 60defm : LoadPatImmOff<vec_t, load, or_is_add, "LOAD_V128">; 61defm : LoadPatOffsetOnly<vec_t, load, "LOAD_V128">; 62defm : LoadPatGlobalAddrOffOnly<vec_t, load, "LOAD_V128">; 63} 64 65// vNxM.load_splat 66multiclass SIMDLoadSplat<string vec, bits<32> simdop> { 67 let mayLoad = 1, UseNamedOperandTable = 1 in { 68 defm LOAD_SPLAT_#vec#_A32 : 69 SIMD_I<(outs V128:$dst), 70 (ins P2Align:$p2align, offset32_op:$off, I32:$addr), 71 (outs), 72 (ins P2Align:$p2align, offset32_op:$off), [], 73 vec#".load_splat\t$dst, ${off}(${addr})$p2align", 74 vec#".load_splat\t$off$p2align", simdop>; 75 defm LOAD_SPLAT_#vec#_A64 : 76 SIMD_I<(outs V128:$dst), 77 (ins P2Align:$p2align, offset64_op:$off, I64:$addr), 78 (outs), 79 (ins P2Align:$p2align, offset64_op:$off), [], 80 vec#".load_splat\t$dst, ${off}(${addr})$p2align", 81 vec#".load_splat\t$off$p2align", simdop>; 82 } 83} 84 85defm "" : SIMDLoadSplat<"v8x16", 7>; 86defm "" : SIMDLoadSplat<"v16x8", 8>; 87defm "" : SIMDLoadSplat<"v32x4", 9>; 88defm "" : SIMDLoadSplat<"v64x2", 10>; 89 90def wasm_load_splat_t : SDTypeProfile<1, 1, [SDTCisPtrTy<1>]>; 91def wasm_load_splat : SDNode<"WebAssemblyISD::LOAD_SPLAT", wasm_load_splat_t, 92 [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; 93def load_splat : PatFrag<(ops node:$addr), (wasm_load_splat node:$addr)>; 94 95foreach args = [["v16i8", "v8x16"], ["v8i16", "v16x8"], ["v4i32", "v32x4"], 96 ["v2i64", "v64x2"], ["v4f32", "v32x4"], ["v2f64", "v64x2"]] in { 97defm : LoadPatNoOffset<!cast<ValueType>(args[0]), 98 load_splat, 99 "LOAD_SPLAT_"#args[1]>; 100defm : LoadPatImmOff<!cast<ValueType>(args[0]), 101 load_splat, 102 regPlusImm, 103 "LOAD_SPLAT_"#args[1]>; 104defm : LoadPatImmOff<!cast<ValueType>(args[0]), 105 load_splat, 106 or_is_add, 107 "LOAD_SPLAT_"#args[1]>; 108defm : LoadPatOffsetOnly<!cast<ValueType>(args[0]), 109 load_splat, 110 "LOAD_SPLAT_"#args[1]>; 111defm : LoadPatGlobalAddrOffOnly<!cast<ValueType>(args[0]), 112 load_splat, 113 "LOAD_SPLAT_"#args[1]>; 114} 115 116// Load and extend 117multiclass SIMDLoadExtend<ValueType vec_t, string name, bits<32> simdop> { 118 let mayLoad = 1, UseNamedOperandTable = 1 in { 119 defm LOAD_EXTEND_S_#vec_t#_A32 : 120 SIMD_I<(outs V128:$dst), 121 (ins P2Align:$p2align, offset32_op:$off, I32:$addr), 122 (outs), (ins P2Align:$p2align, offset32_op:$off), [], 123 name#"_s\t$dst, ${off}(${addr})$p2align", 124 name#"_s\t$off$p2align", simdop>; 125 defm LOAD_EXTEND_U_#vec_t#_A32 : 126 SIMD_I<(outs V128:$dst), 127 (ins P2Align:$p2align, offset32_op:$off, I32:$addr), 128 (outs), (ins P2Align:$p2align, offset32_op:$off), [], 129 name#"_u\t$dst, ${off}(${addr})$p2align", 130 name#"_u\t$off$p2align", !add(simdop, 1)>; 131 defm LOAD_EXTEND_S_#vec_t#_A64 : 132 SIMD_I<(outs V128:$dst), 133 (ins P2Align:$p2align, offset64_op:$off, I64:$addr), 134 (outs), (ins P2Align:$p2align, offset64_op:$off), [], 135 name#"_s\t$dst, ${off}(${addr})$p2align", 136 name#"_s\t$off$p2align", simdop>; 137 defm LOAD_EXTEND_U_#vec_t#_A64 : 138 SIMD_I<(outs V128:$dst), 139 (ins P2Align:$p2align, offset64_op:$off, I64:$addr), 140 (outs), (ins P2Align:$p2align, offset64_op:$off), [], 141 name#"_u\t$dst, ${off}(${addr})$p2align", 142 name#"_u\t$off$p2align", !add(simdop, 1)>; 143 } 144} 145 146defm "" : SIMDLoadExtend<v8i16, "i16x8.load8x8", 1>; 147defm "" : SIMDLoadExtend<v4i32, "i32x4.load16x4", 3>; 148defm "" : SIMDLoadExtend<v2i64, "i64x2.load32x2", 5>; 149 150foreach types = [[v8i16, i8], [v4i32, i16], [v2i64, i32]] in 151foreach exts = [["sextloadv", "_S"], 152 ["zextloadv", "_U"], 153 ["extloadv", "_U"]] in { 154defm : LoadPatNoOffset<types[0], !cast<PatFrag>(exts[0]#types[1]), 155 "LOAD_EXTEND"#exts[1]#"_"#types[0]>; 156defm : LoadPatImmOff<types[0], !cast<PatFrag>(exts[0]#types[1]), regPlusImm, 157 "LOAD_EXTEND"#exts[1]#"_"#types[0]>; 158defm : LoadPatImmOff<types[0], !cast<PatFrag>(exts[0]#types[1]), or_is_add, 159 "LOAD_EXTEND"#exts[1]#"_"#types[0]>; 160defm : LoadPatOffsetOnly<types[0], !cast<PatFrag>(exts[0]#types[1]), 161 "LOAD_EXTEND"#exts[1]#"_"#types[0]>; 162defm : LoadPatGlobalAddrOffOnly<types[0], !cast<PatFrag>(exts[0]#types[1]), 163 "LOAD_EXTEND"#exts[1]#"_"#types[0]>; 164} 165 166 167// Store: v128.store 168let mayStore = 1, UseNamedOperandTable = 1 in { 169defm STORE_V128_A32 : 170 SIMD_I<(outs), (ins P2Align:$p2align, offset32_op:$off, I32:$addr, V128:$vec), 171 (outs), (ins P2Align:$p2align, offset32_op:$off), [], 172 "v128.store\t${off}(${addr})$p2align, $vec", 173 "v128.store\t$off$p2align", 11>; 174defm STORE_V128_A64 : 175 SIMD_I<(outs), (ins P2Align:$p2align, offset64_op:$off, I64:$addr, V128:$vec), 176 (outs), (ins P2Align:$p2align, offset64_op:$off), [], 177 "v128.store\t${off}(${addr})$p2align, $vec", 178 "v128.store\t$off$p2align", 11>; 179} 180foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { 181// Def load and store patterns from WebAssemblyInstrMemory.td for vector types 182defm : StorePatNoOffset<vec_t, store, "STORE_V128">; 183defm : StorePatImmOff<vec_t, store, regPlusImm, "STORE_V128">; 184defm : StorePatImmOff<vec_t, store, or_is_add, "STORE_V128">; 185defm : StorePatOffsetOnly<vec_t, store, "STORE_V128">; 186defm : StorePatGlobalAddrOffOnly<vec_t, store, "STORE_V128">; 187} 188 189//===----------------------------------------------------------------------===// 190// Constructing SIMD values 191//===----------------------------------------------------------------------===// 192 193// Constant: v128.const 194multiclass ConstVec<ValueType vec_t, dag ops, dag pat, string args> { 195 let isMoveImm = 1, isReMaterializable = 1, 196 Predicates = [HasUnimplementedSIMD128] in 197 defm CONST_V128_#vec_t : SIMD_I<(outs V128:$dst), ops, (outs), ops, 198 [(set V128:$dst, (vec_t pat))], 199 "v128.const\t$dst, "#args, 200 "v128.const\t"#args, 12>; 201} 202 203defm "" : ConstVec<v16i8, 204 (ins vec_i8imm_op:$i0, vec_i8imm_op:$i1, 205 vec_i8imm_op:$i2, vec_i8imm_op:$i3, 206 vec_i8imm_op:$i4, vec_i8imm_op:$i5, 207 vec_i8imm_op:$i6, vec_i8imm_op:$i7, 208 vec_i8imm_op:$i8, vec_i8imm_op:$i9, 209 vec_i8imm_op:$iA, vec_i8imm_op:$iB, 210 vec_i8imm_op:$iC, vec_i8imm_op:$iD, 211 vec_i8imm_op:$iE, vec_i8imm_op:$iF), 212 (build_vector ImmI8:$i0, ImmI8:$i1, ImmI8:$i2, ImmI8:$i3, 213 ImmI8:$i4, ImmI8:$i5, ImmI8:$i6, ImmI8:$i7, 214 ImmI8:$i8, ImmI8:$i9, ImmI8:$iA, ImmI8:$iB, 215 ImmI8:$iC, ImmI8:$iD, ImmI8:$iE, ImmI8:$iF), 216 !strconcat("$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7, ", 217 "$i8, $i9, $iA, $iB, $iC, $iD, $iE, $iF")>; 218defm "" : ConstVec<v8i16, 219 (ins vec_i16imm_op:$i0, vec_i16imm_op:$i1, 220 vec_i16imm_op:$i2, vec_i16imm_op:$i3, 221 vec_i16imm_op:$i4, vec_i16imm_op:$i5, 222 vec_i16imm_op:$i6, vec_i16imm_op:$i7), 223 (build_vector 224 ImmI16:$i0, ImmI16:$i1, ImmI16:$i2, ImmI16:$i3, 225 ImmI16:$i4, ImmI16:$i5, ImmI16:$i6, ImmI16:$i7), 226 "$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7">; 227let IsCanonical = 1 in 228defm "" : ConstVec<v4i32, 229 (ins vec_i32imm_op:$i0, vec_i32imm_op:$i1, 230 vec_i32imm_op:$i2, vec_i32imm_op:$i3), 231 (build_vector (i32 imm:$i0), (i32 imm:$i1), 232 (i32 imm:$i2), (i32 imm:$i3)), 233 "$i0, $i1, $i2, $i3">; 234defm "" : ConstVec<v2i64, 235 (ins vec_i64imm_op:$i0, vec_i64imm_op:$i1), 236 (build_vector (i64 imm:$i0), (i64 imm:$i1)), 237 "$i0, $i1">; 238defm "" : ConstVec<v4f32, 239 (ins f32imm_op:$i0, f32imm_op:$i1, 240 f32imm_op:$i2, f32imm_op:$i3), 241 (build_vector (f32 fpimm:$i0), (f32 fpimm:$i1), 242 (f32 fpimm:$i2), (f32 fpimm:$i3)), 243 "$i0, $i1, $i2, $i3">; 244defm "" : ConstVec<v2f64, 245 (ins f64imm_op:$i0, f64imm_op:$i1), 246 (build_vector (f64 fpimm:$i0), (f64 fpimm:$i1)), 247 "$i0, $i1">; 248 249// Shuffle lanes: shuffle 250defm SHUFFLE : 251 SIMD_I<(outs V128:$dst), 252 (ins V128:$x, V128:$y, 253 vec_i8imm_op:$m0, vec_i8imm_op:$m1, 254 vec_i8imm_op:$m2, vec_i8imm_op:$m3, 255 vec_i8imm_op:$m4, vec_i8imm_op:$m5, 256 vec_i8imm_op:$m6, vec_i8imm_op:$m7, 257 vec_i8imm_op:$m8, vec_i8imm_op:$m9, 258 vec_i8imm_op:$mA, vec_i8imm_op:$mB, 259 vec_i8imm_op:$mC, vec_i8imm_op:$mD, 260 vec_i8imm_op:$mE, vec_i8imm_op:$mF), 261 (outs), 262 (ins 263 vec_i8imm_op:$m0, vec_i8imm_op:$m1, 264 vec_i8imm_op:$m2, vec_i8imm_op:$m3, 265 vec_i8imm_op:$m4, vec_i8imm_op:$m5, 266 vec_i8imm_op:$m6, vec_i8imm_op:$m7, 267 vec_i8imm_op:$m8, vec_i8imm_op:$m9, 268 vec_i8imm_op:$mA, vec_i8imm_op:$mB, 269 vec_i8imm_op:$mC, vec_i8imm_op:$mD, 270 vec_i8imm_op:$mE, vec_i8imm_op:$mF), 271 [], 272 "v8x16.shuffle\t$dst, $x, $y, "# 273 "$m0, $m1, $m2, $m3, $m4, $m5, $m6, $m7, "# 274 "$m8, $m9, $mA, $mB, $mC, $mD, $mE, $mF", 275 "v8x16.shuffle\t"# 276 "$m0, $m1, $m2, $m3, $m4, $m5, $m6, $m7, "# 277 "$m8, $m9, $mA, $mB, $mC, $mD, $mE, $mF", 278 13>; 279 280// Shuffles after custom lowering 281def wasm_shuffle_t : SDTypeProfile<1, 18, []>; 282def wasm_shuffle : SDNode<"WebAssemblyISD::SHUFFLE", wasm_shuffle_t>; 283foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { 284def : Pat<(vec_t (wasm_shuffle (vec_t V128:$x), (vec_t V128:$y), 285 (i32 LaneIdx32:$m0), (i32 LaneIdx32:$m1), 286 (i32 LaneIdx32:$m2), (i32 LaneIdx32:$m3), 287 (i32 LaneIdx32:$m4), (i32 LaneIdx32:$m5), 288 (i32 LaneIdx32:$m6), (i32 LaneIdx32:$m7), 289 (i32 LaneIdx32:$m8), (i32 LaneIdx32:$m9), 290 (i32 LaneIdx32:$mA), (i32 LaneIdx32:$mB), 291 (i32 LaneIdx32:$mC), (i32 LaneIdx32:$mD), 292 (i32 LaneIdx32:$mE), (i32 LaneIdx32:$mF))), 293 (vec_t (SHUFFLE (vec_t V128:$x), (vec_t V128:$y), 294 (i32 LaneIdx32:$m0), (i32 LaneIdx32:$m1), 295 (i32 LaneIdx32:$m2), (i32 LaneIdx32:$m3), 296 (i32 LaneIdx32:$m4), (i32 LaneIdx32:$m5), 297 (i32 LaneIdx32:$m6), (i32 LaneIdx32:$m7), 298 (i32 LaneIdx32:$m8), (i32 LaneIdx32:$m9), 299 (i32 LaneIdx32:$mA), (i32 LaneIdx32:$mB), 300 (i32 LaneIdx32:$mC), (i32 LaneIdx32:$mD), 301 (i32 LaneIdx32:$mE), (i32 LaneIdx32:$mF)))>; 302} 303 304// Swizzle lanes: v8x16.swizzle 305def wasm_swizzle_t : SDTypeProfile<1, 2, []>; 306def wasm_swizzle : SDNode<"WebAssemblyISD::SWIZZLE", wasm_swizzle_t>; 307defm SWIZZLE : 308 SIMD_I<(outs V128:$dst), (ins V128:$src, V128:$mask), (outs), (ins), 309 [(set (v16i8 V128:$dst), 310 (wasm_swizzle (v16i8 V128:$src), (v16i8 V128:$mask)))], 311 "v8x16.swizzle\t$dst, $src, $mask", "v8x16.swizzle", 14>; 312 313def : Pat<(int_wasm_swizzle (v16i8 V128:$src), (v16i8 V128:$mask)), 314 (SWIZZLE V128:$src, V128:$mask)>; 315 316// Create vector with identical lanes: splat 317def splat2 : PatFrag<(ops node:$x), (build_vector node:$x, node:$x)>; 318def splat4 : PatFrag<(ops node:$x), (build_vector 319 node:$x, node:$x, node:$x, node:$x)>; 320def splat8 : PatFrag<(ops node:$x), (build_vector 321 node:$x, node:$x, node:$x, node:$x, 322 node:$x, node:$x, node:$x, node:$x)>; 323def splat16 : PatFrag<(ops node:$x), (build_vector 324 node:$x, node:$x, node:$x, node:$x, 325 node:$x, node:$x, node:$x, node:$x, 326 node:$x, node:$x, node:$x, node:$x, 327 node:$x, node:$x, node:$x, node:$x)>; 328 329multiclass Splat<ValueType vec_t, string vec, WebAssemblyRegClass reg_t, 330 PatFrag splat_pat, bits<32> simdop> { 331 // Prefer splats over v128.const for const splats (65 is lowest that works) 332 let AddedComplexity = 65 in 333 defm SPLAT_#vec_t : SIMD_I<(outs V128:$dst), (ins reg_t:$x), (outs), (ins), 334 [(set (vec_t V128:$dst), (splat_pat reg_t:$x))], 335 vec#".splat\t$dst, $x", vec#".splat", simdop>; 336} 337 338defm "" : Splat<v16i8, "i8x16", I32, splat16, 15>; 339defm "" : Splat<v8i16, "i16x8", I32, splat8, 16>; 340defm "" : Splat<v4i32, "i32x4", I32, splat4, 17>; 341defm "" : Splat<v2i64, "i64x2", I64, splat2, 18>; 342defm "" : Splat<v4f32, "f32x4", F32, splat4, 19>; 343defm "" : Splat<v2f64, "f64x2", F64, splat2, 20>; 344 345// scalar_to_vector leaves high lanes undefined, so can be a splat 346class ScalarSplatPat<ValueType vec_t, ValueType lane_t, 347 WebAssemblyRegClass reg_t> : 348 Pat<(vec_t (scalar_to_vector (lane_t reg_t:$x))), 349 (!cast<Instruction>("SPLAT_"#vec_t) reg_t:$x)>; 350 351def : ScalarSplatPat<v16i8, i32, I32>; 352def : ScalarSplatPat<v8i16, i32, I32>; 353def : ScalarSplatPat<v4i32, i32, I32>; 354def : ScalarSplatPat<v2i64, i64, I64>; 355def : ScalarSplatPat<v4f32, f32, F32>; 356def : ScalarSplatPat<v2f64, f64, F64>; 357 358//===----------------------------------------------------------------------===// 359// Accessing lanes 360//===----------------------------------------------------------------------===// 361 362// Extract lane as a scalar: extract_lane / extract_lane_s / extract_lane_u 363multiclass ExtractLane<ValueType vec_t, string vec, WebAssemblyRegClass reg_t, 364 bits<32> simdop, string suffix = ""> { 365 defm EXTRACT_LANE_#vec_t#suffix : 366 SIMD_I<(outs reg_t:$dst), (ins V128:$vec, vec_i8imm_op:$idx), 367 (outs), (ins vec_i8imm_op:$idx), [], 368 vec#".extract_lane"#suffix#"\t$dst, $vec, $idx", 369 vec#".extract_lane"#suffix#"\t$idx", simdop>; 370} 371 372defm "" : ExtractLane<v16i8, "i8x16", I32, 21, "_s">; 373defm "" : ExtractLane<v16i8, "i8x16", I32, 22, "_u">; 374defm "" : ExtractLane<v8i16, "i16x8", I32, 24, "_s">; 375defm "" : ExtractLane<v8i16, "i16x8", I32, 25, "_u">; 376defm "" : ExtractLane<v4i32, "i32x4", I32, 27>; 377defm "" : ExtractLane<v2i64, "i64x2", I64, 29>; 378defm "" : ExtractLane<v4f32, "f32x4", F32, 31>; 379defm "" : ExtractLane<v2f64, "f64x2", F64, 33>; 380 381def : Pat<(vector_extract (v16i8 V128:$vec), (i32 LaneIdx16:$idx)), 382 (EXTRACT_LANE_v16i8_u V128:$vec, imm:$idx)>; 383def : Pat<(vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx)), 384 (EXTRACT_LANE_v8i16_u V128:$vec, imm:$idx)>; 385def : Pat<(vector_extract (v4i32 V128:$vec), (i32 LaneIdx4:$idx)), 386 (EXTRACT_LANE_v4i32 V128:$vec, imm:$idx)>; 387def : Pat<(vector_extract (v4f32 V128:$vec), (i32 LaneIdx4:$idx)), 388 (EXTRACT_LANE_v4f32 V128:$vec, imm:$idx)>; 389def : Pat<(vector_extract (v2i64 V128:$vec), (i32 LaneIdx2:$idx)), 390 (EXTRACT_LANE_v2i64 V128:$vec, imm:$idx)>; 391def : Pat<(vector_extract (v2f64 V128:$vec), (i32 LaneIdx2:$idx)), 392 (EXTRACT_LANE_v2f64 V128:$vec, imm:$idx)>; 393 394def : Pat< 395 (sext_inreg (vector_extract (v16i8 V128:$vec), (i32 LaneIdx16:$idx)), i8), 396 (EXTRACT_LANE_v16i8_s V128:$vec, imm:$idx)>; 397def : Pat< 398 (and (vector_extract (v16i8 V128:$vec), (i32 LaneIdx16:$idx)), (i32 0xff)), 399 (EXTRACT_LANE_v16i8_u V128:$vec, imm:$idx)>; 400def : Pat< 401 (sext_inreg (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx)), i16), 402 (EXTRACT_LANE_v8i16_s V128:$vec, imm:$idx)>; 403def : Pat< 404 (and (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx)), (i32 0xffff)), 405 (EXTRACT_LANE_v8i16_u V128:$vec, imm:$idx)>; 406 407// Replace lane value: replace_lane 408multiclass ReplaceLane<ValueType vec_t, string vec, ImmLeaf imm_t, 409 WebAssemblyRegClass reg_t, ValueType lane_t, 410 bits<32> simdop> { 411 defm REPLACE_LANE_#vec_t : 412 SIMD_I<(outs V128:$dst), (ins V128:$vec, vec_i8imm_op:$idx, reg_t:$x), 413 (outs), (ins vec_i8imm_op:$idx), 414 [(set V128:$dst, (vector_insert 415 (vec_t V128:$vec), (lane_t reg_t:$x), (i32 imm_t:$idx)))], 416 vec#".replace_lane\t$dst, $vec, $idx, $x", 417 vec#".replace_lane\t$idx", simdop>; 418} 419 420defm "" : ReplaceLane<v16i8, "i8x16", LaneIdx16, I32, i32, 23>; 421defm "" : ReplaceLane<v8i16, "i16x8", LaneIdx8, I32, i32, 26>; 422defm "" : ReplaceLane<v4i32, "i32x4", LaneIdx4, I32, i32, 28>; 423defm "" : ReplaceLane<v2i64, "i64x2", LaneIdx2, I64, i64, 30>; 424defm "" : ReplaceLane<v4f32, "f32x4", LaneIdx4, F32, f32, 32>; 425defm "" : ReplaceLane<v2f64, "f64x2", LaneIdx2, F64, f64, 34>; 426 427// Lower undef lane indices to zero 428def : Pat<(vector_insert (v16i8 V128:$vec), I32:$x, undef), 429 (REPLACE_LANE_v16i8 V128:$vec, 0, I32:$x)>; 430def : Pat<(vector_insert (v8i16 V128:$vec), I32:$x, undef), 431 (REPLACE_LANE_v8i16 V128:$vec, 0, I32:$x)>; 432def : Pat<(vector_insert (v4i32 V128:$vec), I32:$x, undef), 433 (REPLACE_LANE_v4i32 V128:$vec, 0, I32:$x)>; 434def : Pat<(vector_insert (v2i64 V128:$vec), I64:$x, undef), 435 (REPLACE_LANE_v2i64 V128:$vec, 0, I64:$x)>; 436def : Pat<(vector_insert (v4f32 V128:$vec), F32:$x, undef), 437 (REPLACE_LANE_v4f32 V128:$vec, 0, F32:$x)>; 438def : Pat<(vector_insert (v2f64 V128:$vec), F64:$x, undef), 439 (REPLACE_LANE_v2f64 V128:$vec, 0, F64:$x)>; 440 441//===----------------------------------------------------------------------===// 442// Comparisons 443//===----------------------------------------------------------------------===// 444 445multiclass SIMDCondition<ValueType vec_t, ValueType out_t, string vec, 446 string name, CondCode cond, bits<32> simdop> { 447 defm _#vec_t : 448 SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), (outs), (ins), 449 [(set (out_t V128:$dst), 450 (setcc (vec_t V128:$lhs), (vec_t V128:$rhs), cond) 451 )], 452 vec#"."#name#"\t$dst, $lhs, $rhs", vec#"."#name, simdop>; 453} 454 455multiclass SIMDConditionInt<string name, CondCode cond, bits<32> baseInst> { 456 defm "" : SIMDCondition<v16i8, v16i8, "i8x16", name, cond, baseInst>; 457 defm "" : SIMDCondition<v8i16, v8i16, "i16x8", name, cond, 458 !add(baseInst, 10)>; 459 defm "" : SIMDCondition<v4i32, v4i32, "i32x4", name, cond, 460 !add(baseInst, 20)>; 461} 462 463multiclass SIMDConditionFP<string name, CondCode cond, bits<32> baseInst> { 464 defm "" : SIMDCondition<v4f32, v4i32, "f32x4", name, cond, baseInst>; 465 defm "" : SIMDCondition<v2f64, v2i64, "f64x2", name, cond, 466 !add(baseInst, 6)>; 467} 468 469// Equality: eq 470let isCommutable = 1 in { 471defm EQ : SIMDConditionInt<"eq", SETEQ, 35>; 472defm EQ : SIMDConditionFP<"eq", SETOEQ, 65>; 473} // isCommutable = 1 474 475// Non-equality: ne 476let isCommutable = 1 in { 477defm NE : SIMDConditionInt<"ne", SETNE, 36>; 478defm NE : SIMDConditionFP<"ne", SETUNE, 66>; 479} // isCommutable = 1 480 481// Less than: lt_s / lt_u / lt 482defm LT_S : SIMDConditionInt<"lt_s", SETLT, 37>; 483defm LT_U : SIMDConditionInt<"lt_u", SETULT, 38>; 484defm LT : SIMDConditionFP<"lt", SETOLT, 67>; 485 486// Greater than: gt_s / gt_u / gt 487defm GT_S : SIMDConditionInt<"gt_s", SETGT, 39>; 488defm GT_U : SIMDConditionInt<"gt_u", SETUGT, 40>; 489defm GT : SIMDConditionFP<"gt", SETOGT, 68>; 490 491// Less than or equal: le_s / le_u / le 492defm LE_S : SIMDConditionInt<"le_s", SETLE, 41>; 493defm LE_U : SIMDConditionInt<"le_u", SETULE, 42>; 494defm LE : SIMDConditionFP<"le", SETOLE, 69>; 495 496// Greater than or equal: ge_s / ge_u / ge 497defm GE_S : SIMDConditionInt<"ge_s", SETGE, 43>; 498defm GE_U : SIMDConditionInt<"ge_u", SETUGE, 44>; 499defm GE : SIMDConditionFP<"ge", SETOGE, 70>; 500 501// Lower float comparisons that don't care about NaN to standard WebAssembly 502// float comparisons. These instructions are generated with nnan and in the 503// target-independent expansion of unordered comparisons and ordered ne. 504foreach nodes = [[seteq, EQ_v4f32], [setne, NE_v4f32], [setlt, LT_v4f32], 505 [setgt, GT_v4f32], [setle, LE_v4f32], [setge, GE_v4f32]] in 506def : Pat<(v4i32 (nodes[0] (v4f32 V128:$lhs), (v4f32 V128:$rhs))), 507 (v4i32 (nodes[1] (v4f32 V128:$lhs), (v4f32 V128:$rhs)))>; 508 509foreach nodes = [[seteq, EQ_v2f64], [setne, NE_v2f64], [setlt, LT_v2f64], 510 [setgt, GT_v2f64], [setle, LE_v2f64], [setge, GE_v2f64]] in 511def : Pat<(v2i64 (nodes[0] (v2f64 V128:$lhs), (v2f64 V128:$rhs))), 512 (v2i64 (nodes[1] (v2f64 V128:$lhs), (v2f64 V128:$rhs)))>; 513 514 515//===----------------------------------------------------------------------===// 516// Bitwise operations 517//===----------------------------------------------------------------------===// 518 519multiclass SIMDBinary<ValueType vec_t, string vec, SDNode node, string name, 520 bits<32> simdop> { 521 defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), 522 (outs), (ins), 523 [(set (vec_t V128:$dst), 524 (node (vec_t V128:$lhs), (vec_t V128:$rhs)) 525 )], 526 vec#"."#name#"\t$dst, $lhs, $rhs", vec#"."#name, 527 simdop>; 528} 529 530multiclass SIMDBitwise<SDNode node, string name, bits<32> simdop> { 531 defm "" : SIMDBinary<v16i8, "v128", node, name, simdop>; 532 defm "" : SIMDBinary<v8i16, "v128", node, name, simdop>; 533 defm "" : SIMDBinary<v4i32, "v128", node, name, simdop>; 534 defm "" : SIMDBinary<v2i64, "v128", node, name, simdop>; 535} 536 537multiclass SIMDUnary<ValueType vec_t, string vec, SDNode node, string name, 538 bits<32> simdop> { 539 defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), 540 [(set (vec_t V128:$dst), 541 (vec_t (node (vec_t V128:$vec))) 542 )], 543 vec#"."#name#"\t$dst, $vec", vec#"."#name, simdop>; 544} 545 546// Bitwise logic: v128.not 547foreach vec_t = [v16i8, v8i16, v4i32, v2i64] in 548defm NOT: SIMDUnary<vec_t, "v128", vnot, "not", 77>; 549 550// Bitwise logic: v128.and / v128.or / v128.xor 551let isCommutable = 1 in { 552defm AND : SIMDBitwise<and, "and", 78>; 553defm OR : SIMDBitwise<or, "or", 80>; 554defm XOR : SIMDBitwise<xor, "xor", 81>; 555} // isCommutable = 1 556 557// Bitwise logic: v128.andnot 558def andnot : PatFrag<(ops node:$left, node:$right), (and $left, (vnot $right))>; 559defm ANDNOT : SIMDBitwise<andnot, "andnot", 79>; 560 561// Bitwise select: v128.bitselect 562foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in 563 defm BITSELECT_#vec_t : 564 SIMD_I<(outs V128:$dst), (ins V128:$v1, V128:$v2, V128:$c), (outs), (ins), 565 [(set (vec_t V128:$dst), 566 (vec_t (int_wasm_bitselect 567 (vec_t V128:$v1), (vec_t V128:$v2), (vec_t V128:$c) 568 )) 569 )], 570 "v128.bitselect\t$dst, $v1, $v2, $c", "v128.bitselect", 82>; 571 572// Bitselect is equivalent to (c & v1) | (~c & v2) 573foreach vec_t = [v16i8, v8i16, v4i32, v2i64] in 574 def : Pat<(vec_t (or (and (vec_t V128:$c), (vec_t V128:$v1)), 575 (and (vnot V128:$c), (vec_t V128:$v2)))), 576 (!cast<Instruction>("BITSELECT_"#vec_t) 577 V128:$v1, V128:$v2, V128:$c)>; 578 579//===----------------------------------------------------------------------===// 580// Integer unary arithmetic 581//===----------------------------------------------------------------------===// 582 583multiclass SIMDUnaryInt<SDNode node, string name, bits<32> baseInst> { 584 defm "" : SIMDUnary<v16i8, "i8x16", node, name, baseInst>; 585 defm "" : SIMDUnary<v8i16, "i16x8", node, name, !add(baseInst, 32)>; 586 defm "" : SIMDUnary<v4i32, "i32x4", node, name, !add(baseInst, 64)>; 587 defm "" : SIMDUnary<v2i64, "i64x2", node, name, !add(baseInst, 96)>; 588} 589 590multiclass SIMDReduceVec<ValueType vec_t, string vec, SDNode op, string name, 591 bits<32> simdop> { 592 defm _#vec_t : SIMD_I<(outs I32:$dst), (ins V128:$vec), (outs), (ins), 593 [(set I32:$dst, (i32 (op (vec_t V128:$vec))))], 594 vec#"."#name#"\t$dst, $vec", vec#"."#name, simdop>; 595} 596 597multiclass SIMDReduce<SDNode op, string name, bits<32> baseInst> { 598 defm "" : SIMDReduceVec<v16i8, "i8x16", op, name, baseInst>; 599 defm "" : SIMDReduceVec<v8i16, "i16x8", op, name, !add(baseInst, 32)>; 600 defm "" : SIMDReduceVec<v4i32, "i32x4", op, name, !add(baseInst, 64)>; 601 defm "" : SIMDReduceVec<v2i64, "i64x2", op, name, !add(baseInst, 96)>; 602} 603 604// Integer vector negation 605def ivneg : PatFrag<(ops node:$in), (sub immAllZerosV, node:$in)>; 606 607// Integer absolute value: abs 608defm ABS : SIMDUnaryInt<abs, "abs", 96>; 609 610// Integer negation: neg 611defm NEG : SIMDUnaryInt<ivneg, "neg", 97>; 612 613// Any lane true: any_true 614defm ANYTRUE : SIMDReduce<int_wasm_anytrue, "any_true", 98>; 615 616// All lanes true: all_true 617defm ALLTRUE : SIMDReduce<int_wasm_alltrue, "all_true", 99>; 618 619// Reductions already return 0 or 1, so and 1, setne 0, and seteq 1 620// can be folded out 621foreach reduction = 622 [["int_wasm_anytrue", "ANYTRUE"], ["int_wasm_alltrue", "ALLTRUE"]] in 623foreach ty = [v16i8, v8i16, v4i32, v2i64] in { 624def : Pat<(i32 (and 625 (i32 (!cast<Intrinsic>(reduction[0]) (ty V128:$x))), 626 (i32 1) 627 )), 628 (i32 (!cast<NI>(reduction[1]#"_"#ty) (ty V128:$x)))>; 629def : Pat<(i32 (setne 630 (i32 (!cast<Intrinsic>(reduction[0]) (ty V128:$x))), 631 (i32 0) 632 )), 633 (i32 (!cast<NI>(reduction[1]#"_"#ty) (ty V128:$x)))>; 634def : Pat<(i32 (seteq 635 (i32 (!cast<Intrinsic>(reduction[0]) (ty V128:$x))), 636 (i32 1) 637 )), 638 (i32 (!cast<NI>(reduction[1]#"_"#ty) (ty V128:$x)))>; 639} 640 641multiclass SIMDBitmask<ValueType vec_t, string vec, bits<32> simdop> { 642 defm _#vec_t : SIMD_I<(outs I32:$dst), (ins V128:$vec), (outs), (ins), 643 [(set I32:$dst, 644 (i32 (int_wasm_bitmask (vec_t V128:$vec))) 645 )], 646 vec#".bitmask\t$dst, $vec", vec#".bitmask", simdop>; 647} 648 649defm BITMASK : SIMDBitmask<v16i8, "i8x16", 100>; 650defm BITMASK : SIMDBitmask<v8i16, "i16x8", 132>; 651defm BITMASK : SIMDBitmask<v4i32, "i32x4", 164>; 652 653//===----------------------------------------------------------------------===// 654// Bit shifts 655//===----------------------------------------------------------------------===// 656 657multiclass SIMDShift<ValueType vec_t, string vec, SDNode node, dag shift_vec, 658 string name, bits<32> simdop> { 659 defm _#vec_t : SIMD_I<(outs V128:$dst), (ins V128:$vec, I32:$x), 660 (outs), (ins), 661 [(set (vec_t V128:$dst), 662 (node V128:$vec, (vec_t shift_vec)))], 663 vec#"."#name#"\t$dst, $vec, $x", vec#"."#name, simdop>; 664} 665 666multiclass SIMDShiftInt<SDNode node, string name, bits<32> baseInst> { 667 defm "" : SIMDShift<v16i8, "i8x16", node, (splat16 I32:$x), name, baseInst>; 668 defm "" : SIMDShift<v8i16, "i16x8", node, (splat8 I32:$x), name, 669 !add(baseInst, 32)>; 670 defm "" : SIMDShift<v4i32, "i32x4", node, (splat4 I32:$x), name, 671 !add(baseInst, 64)>; 672 defm "" : SIMDShift<v2i64, "i64x2", node, (splat2 (i64 (zext I32:$x))), 673 name, !add(baseInst, 96)>; 674} 675 676// Left shift by scalar: shl 677defm SHL : SIMDShiftInt<shl, "shl", 107>; 678 679// Right shift by scalar: shr_s / shr_u 680defm SHR_S : SIMDShiftInt<sra, "shr_s", 108>; 681defm SHR_U : SIMDShiftInt<srl, "shr_u", 109>; 682 683// Truncate i64 shift operands to i32s, except if they are already i32s 684foreach shifts = [[shl, SHL_v2i64], [sra, SHR_S_v2i64], [srl, SHR_U_v2i64]] in { 685def : Pat<(v2i64 (shifts[0] 686 (v2i64 V128:$vec), 687 (v2i64 (splat2 (i64 (sext I32:$x)))) 688 )), 689 (v2i64 (shifts[1] (v2i64 V128:$vec), (i32 I32:$x)))>; 690def : Pat<(v2i64 (shifts[0] (v2i64 V128:$vec), (v2i64 (splat2 I64:$x)))), 691 (v2i64 (shifts[1] (v2i64 V128:$vec), (I32_WRAP_I64 I64:$x)))>; 692} 693 694// 2xi64 shifts with constant shift amounts are custom lowered to avoid wrapping 695def wasm_shift_t : SDTypeProfile<1, 2, 696 [SDTCisVec<0>, SDTCisSameAs<0, 1>, SDTCisVT<2, i32>] 697>; 698def wasm_shl : SDNode<"WebAssemblyISD::VEC_SHL", wasm_shift_t>; 699def wasm_shr_s : SDNode<"WebAssemblyISD::VEC_SHR_S", wasm_shift_t>; 700def wasm_shr_u : SDNode<"WebAssemblyISD::VEC_SHR_U", wasm_shift_t>; 701foreach shifts = [[wasm_shl, SHL_v2i64], 702 [wasm_shr_s, SHR_S_v2i64], 703 [wasm_shr_u, SHR_U_v2i64]] in 704def : Pat<(v2i64 (shifts[0] (v2i64 V128:$vec), I32:$x)), 705 (v2i64 (shifts[1] (v2i64 V128:$vec), I32:$x))>; 706 707//===----------------------------------------------------------------------===// 708// Integer binary arithmetic 709//===----------------------------------------------------------------------===// 710 711multiclass SIMDBinaryIntNoI8x16<SDNode node, string name, bits<32> baseInst> { 712 defm "" : SIMDBinary<v8i16, "i16x8", node, name, !add(baseInst, 32)>; 713 defm "" : SIMDBinary<v4i32, "i32x4", node, name, !add(baseInst, 64)>; 714 defm "" : SIMDBinary<v2i64, "i64x2", node, name, !add(baseInst, 96)>; 715} 716 717multiclass SIMDBinaryIntSmall<SDNode node, string name, bits<32> baseInst> { 718 defm "" : SIMDBinary<v16i8, "i8x16", node, name, baseInst>; 719 defm "" : SIMDBinary<v8i16, "i16x8", node, name, !add(baseInst, 32)>; 720} 721 722multiclass SIMDBinaryIntNoI64x2<SDNode node, string name, bits<32> baseInst> { 723 defm "" : SIMDBinaryIntSmall<node, name, baseInst>; 724 defm "" : SIMDBinary<v4i32, "i32x4", node, name, !add(baseInst, 64)>; 725} 726 727multiclass SIMDBinaryInt<SDNode node, string name, bits<32> baseInst> { 728 defm "" : SIMDBinaryIntNoI64x2<node, name, baseInst>; 729 defm "" : SIMDBinary<v2i64, "i64x2", node, name, !add(baseInst, 96)>; 730} 731 732// Integer addition: add / add_saturate_s / add_saturate_u 733let isCommutable = 1 in { 734defm ADD : SIMDBinaryInt<add, "add", 110>; 735defm ADD_SAT_S : SIMDBinaryIntSmall<saddsat, "add_saturate_s", 111>; 736defm ADD_SAT_U : SIMDBinaryIntSmall<uaddsat, "add_saturate_u", 112>; 737} // isCommutable = 1 738 739// Integer subtraction: sub / sub_saturate_s / sub_saturate_u 740defm SUB : SIMDBinaryInt<sub, "sub", 113>; 741defm SUB_SAT_S : 742 SIMDBinaryIntSmall<int_wasm_sub_saturate_signed, "sub_saturate_s", 114>; 743defm SUB_SAT_U : 744 SIMDBinaryIntSmall<int_wasm_sub_saturate_unsigned, "sub_saturate_u", 115>; 745 746// Integer multiplication: mul 747let isCommutable = 1 in 748defm MUL : SIMDBinaryIntNoI8x16<mul, "mul", 117>; 749 750// Integer min_s / min_u / max_s / max_u 751let isCommutable = 1 in { 752defm MIN_S : SIMDBinaryIntNoI64x2<smin, "min_s", 118>; 753defm MIN_U : SIMDBinaryIntNoI64x2<umin, "min_u", 119>; 754defm MAX_S : SIMDBinaryIntNoI64x2<smax, "max_s", 120>; 755defm MAX_U : SIMDBinaryIntNoI64x2<umax, "max_u", 121>; 756} // isCommutable = 1 757 758// Integer unsigned rounding average: avgr_u 759let isCommutable = 1 in { 760defm AVGR_U : SIMDBinary<v16i8, "i8x16", int_wasm_avgr_unsigned, "avgr_u", 123>; 761defm AVGR_U : SIMDBinary<v8i16, "i16x8", int_wasm_avgr_unsigned, "avgr_u", 155>; 762} 763 764def add_nuw : PatFrag<(ops node:$lhs, node:$rhs), 765 (add node:$lhs, node:$rhs), 766 "return N->getFlags().hasNoUnsignedWrap();">; 767 768foreach nodes = [[v16i8, splat16], [v8i16, splat8]] in 769def : Pat<(srl 770 (add_nuw 771 (add_nuw (nodes[0] V128:$lhs), (nodes[0] V128:$rhs)), 772 (nodes[1] (i32 1)) 773 ), 774 (nodes[0] (nodes[1] (i32 1))) 775 ), 776 (!cast<NI>("AVGR_U_"#nodes[0]) V128:$lhs, V128:$rhs)>; 777 778// Widening dot product: i32x4.dot_i16x8_s 779let isCommutable = 1 in 780defm DOT : SIMD_I<(outs V128:$dst), (ins V128:$lhs, V128:$rhs), (outs), (ins), 781 [(set V128:$dst, (int_wasm_dot V128:$lhs, V128:$rhs))], 782 "i32x4.dot_i16x8_s\t$dst, $lhs, $rhs", "i32x4.dot_i16x8_s", 783 180>; 784 785//===----------------------------------------------------------------------===// 786// Floating-point unary arithmetic 787//===----------------------------------------------------------------------===// 788 789multiclass SIMDUnaryFP<SDNode node, string name, bits<32> baseInst> { 790 defm "" : SIMDUnary<v4f32, "f32x4", node, name, baseInst>; 791 defm "" : SIMDUnary<v2f64, "f64x2", node, name, !add(baseInst, 12)>; 792} 793 794// Absolute value: abs 795defm ABS : SIMDUnaryFP<fabs, "abs", 224>; 796 797// Negation: neg 798defm NEG : SIMDUnaryFP<fneg, "neg", 225>; 799 800// Square root: sqrt 801defm SQRT : SIMDUnaryFP<fsqrt, "sqrt", 227>; 802 803// Rounding: ceil, floor, trunc, nearest 804defm CEIL : SIMDUnary<v4f32, "f32x4", int_wasm_ceil, "ceil", 216>; 805defm FLOOR : SIMDUnary<v4f32, "f32x4", int_wasm_floor, "floor", 217>; 806defm TRUNC: SIMDUnary<v4f32, "f32x4", int_wasm_trunc, "trunc", 218>; 807defm NEAREST: SIMDUnary<v4f32, "f32x4", int_wasm_nearest, "nearest", 219>; 808defm CEIL : SIMDUnary<v2f64, "f64x2", int_wasm_ceil, "ceil", 220>; 809defm FLOOR : SIMDUnary<v2f64, "f64x2", int_wasm_floor, "floor", 221>; 810defm TRUNC: SIMDUnary<v2f64, "f64x2", int_wasm_trunc, "trunc", 222>; 811defm NEAREST: SIMDUnary<v2f64, "f64x2", int_wasm_nearest, "nearest", 223>; 812 813//===----------------------------------------------------------------------===// 814// Floating-point binary arithmetic 815//===----------------------------------------------------------------------===// 816 817multiclass SIMDBinaryFP<SDNode node, string name, bits<32> baseInst> { 818 defm "" : SIMDBinary<v4f32, "f32x4", node, name, baseInst>; 819 defm "" : SIMDBinary<v2f64, "f64x2", node, name, !add(baseInst, 12)>; 820} 821 822// Addition: add 823let isCommutable = 1 in 824defm ADD : SIMDBinaryFP<fadd, "add", 228>; 825 826// Subtraction: sub 827defm SUB : SIMDBinaryFP<fsub, "sub", 229>; 828 829// Multiplication: mul 830let isCommutable = 1 in 831defm MUL : SIMDBinaryFP<fmul, "mul", 230>; 832 833// Division: div 834defm DIV : SIMDBinaryFP<fdiv, "div", 231>; 835 836// NaN-propagating minimum: min 837defm MIN : SIMDBinaryFP<fminimum, "min", 232>; 838 839// NaN-propagating maximum: max 840defm MAX : SIMDBinaryFP<fmaximum, "max", 233>; 841 842// Pseudo-minimum: pmin 843defm PMIN : SIMDBinaryFP<int_wasm_pmin, "pmin", 234>; 844 845// Pseudo-maximum: pmax 846defm PMAX : SIMDBinaryFP<int_wasm_pmax, "pmax", 235>; 847 848//===----------------------------------------------------------------------===// 849// Conversions 850//===----------------------------------------------------------------------===// 851 852multiclass SIMDConvert<ValueType vec_t, ValueType arg_t, SDNode op, 853 string name, bits<32> simdop> { 854 defm op#_#vec_t#_#arg_t : 855 SIMD_I<(outs V128:$dst), (ins V128:$vec), (outs), (ins), 856 [(set (vec_t V128:$dst), (vec_t (op (arg_t V128:$vec))))], 857 name#"\t$dst, $vec", name, simdop>; 858} 859 860// Floating point to integer with saturation: trunc_sat 861defm "" : SIMDConvert<v4i32, v4f32, fp_to_sint, "i32x4.trunc_sat_f32x4_s", 248>; 862defm "" : SIMDConvert<v4i32, v4f32, fp_to_uint, "i32x4.trunc_sat_f32x4_u", 249>; 863 864// Integer to floating point: convert 865defm "" : SIMDConvert<v4f32, v4i32, sint_to_fp, "f32x4.convert_i32x4_s", 250>; 866defm "" : SIMDConvert<v4f32, v4i32, uint_to_fp, "f32x4.convert_i32x4_u", 251>; 867 868// Widening operations 869multiclass SIMDWiden<ValueType vec_t, string vec, ValueType arg_t, string arg, 870 bits<32> baseInst> { 871 defm "" : SIMDConvert<vec_t, arg_t, int_wasm_widen_low_signed, 872 vec#".widen_low_"#arg#"_s", baseInst>; 873 defm "" : SIMDConvert<vec_t, arg_t, int_wasm_widen_high_signed, 874 vec#".widen_high_"#arg#"_s", !add(baseInst, 1)>; 875 defm "" : SIMDConvert<vec_t, arg_t, int_wasm_widen_low_unsigned, 876 vec#".widen_low_"#arg#"_u", !add(baseInst, 2)>; 877 defm "" : SIMDConvert<vec_t, arg_t, int_wasm_widen_high_unsigned, 878 vec#".widen_high_"#arg#"_u", !add(baseInst, 3)>; 879} 880 881defm "" : SIMDWiden<v8i16, "i16x8", v16i8, "i8x16", 135>; 882defm "" : SIMDWiden<v4i32, "i32x4", v8i16, "i16x8", 167>; 883 884// Narrowing operations 885multiclass SIMDNarrow<ValueType vec_t, string vec, ValueType arg_t, string arg, 886 bits<32> baseInst> { 887 defm NARROW_S_#vec_t : 888 SIMD_I<(outs V128:$dst), (ins V128:$low, V128:$high), (outs), (ins), 889 [(set (vec_t V128:$dst), (vec_t (int_wasm_narrow_signed 890 (arg_t V128:$low), (arg_t V128:$high))))], 891 vec#".narrow_"#arg#"_s\t$dst, $low, $high", vec#".narrow_"#arg#"_s", 892 baseInst>; 893 defm NARROW_U_#vec_t : 894 SIMD_I<(outs V128:$dst), (ins V128:$low, V128:$high), (outs), (ins), 895 [(set (vec_t V128:$dst), (vec_t (int_wasm_narrow_unsigned 896 (arg_t V128:$low), (arg_t V128:$high))))], 897 vec#".narrow_"#arg#"_u\t$dst, $low, $high", vec#".narrow_"#arg#"_u", 898 !add(baseInst, 1)>; 899} 900 901defm "" : SIMDNarrow<v16i8, "i8x16", v8i16, "i16x8", 101>; 902defm "" : SIMDNarrow<v8i16, "i16x8", v4i32, "i32x4", 133>; 903 904// Lower llvm.wasm.trunc.saturate.* to saturating instructions 905def : Pat<(v4i32 (int_wasm_trunc_saturate_signed (v4f32 V128:$src))), 906 (fp_to_sint_v4i32_v4f32 (v4f32 V128:$src))>; 907def : Pat<(v4i32 (int_wasm_trunc_saturate_unsigned (v4f32 V128:$src))), 908 (fp_to_uint_v4i32_v4f32 (v4f32 V128:$src))>; 909 910// Bitcasts are nops 911// Matching bitcast t1 to t1 causes strange errors, so avoid repeating types 912foreach t1 = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in 913foreach t2 = !foldl( 914 []<ValueType>, [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64], 915 acc, cur, !if(!eq(!cast<string>(t1), !cast<string>(cur)), 916 acc, !listconcat(acc, [cur]) 917 ) 918) in 919def : Pat<(t1 (bitconvert (t2 V128:$v))), (t1 V128:$v)>; 920 921//===----------------------------------------------------------------------===// 922// Quasi-Fused Multiply- Add and Subtract (QFMA/QFMS) 923//===----------------------------------------------------------------------===// 924 925multiclass SIMDQFM<ValueType vec_t, string vec, bits<32> baseInst> { 926 defm QFMA_#vec_t : 927 SIMD_I<(outs V128:$dst), (ins V128:$a, V128:$b, V128:$c), 928 (outs), (ins), 929 [(set (vec_t V128:$dst), 930 (int_wasm_qfma (vec_t V128:$a), (vec_t V128:$b), (vec_t V128:$c)))], 931 vec#".qfma\t$dst, $a, $b, $c", vec#".qfma", baseInst>; 932 defm QFMS_#vec_t : 933 SIMD_I<(outs V128:$dst), (ins V128:$a, V128:$b, V128:$c), 934 (outs), (ins), 935 [(set (vec_t V128:$dst), 936 (int_wasm_qfms (vec_t V128:$a), (vec_t V128:$b), (vec_t V128:$c)))], 937 vec#".qfms\t$dst, $a, $b, $c", vec#".qfms", !add(baseInst, 1)>; 938} 939 940defm "" : SIMDQFM<v4f32, "f32x4", 252>; 941defm "" : SIMDQFM<v2f64, "f64x2", 254>; 942