From efe7f5ede0b3276f3f43daca46410bb7978221fb Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Tue, 22 Dec 2020 20:06:12 -0800 Subject: [PATCH] [WebAssembly][NFC] Refactor SIMD load/store tablegen defs Introduce `Vec` records, each bundling all information related to a single SIMD lane interpretation. This lets TableGen definitions take a single Vec parameter from which they can extract information rather than taking multiple redundant parameters. This commit refactors all of the SIMD load and store instruction definitions to use the new `Vec`s. Subsequent commits will similarly refactor additional instruction definitions. Differential Revision: https://reviews.llvm.org/D93660 --- .../MCTargetDesc/WebAssemblyMCTargetDesc.h | 32 +-- .../lib/Target/WebAssembly/WebAssemblyInstrSIMD.td | 290 ++++++++++++--------- 2 files changed, 190 insertions(+), 132 deletions(-) diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h index 4bc77aa..6c819f3 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -195,8 +195,8 @@ inline unsigned GetDefaultP2AlignAny(unsigned Opc) { WASM_LOAD_STORE(ATOMIC_RMW8_U_CMPXCHG_I32) WASM_LOAD_STORE(ATOMIC_RMW8_U_CMPXCHG_I64) WASM_LOAD_STORE(LOAD8_SPLAT) - WASM_LOAD_STORE(LOAD_LANE_v16i8) - WASM_LOAD_STORE(STORE_LANE_v16i8) + WASM_LOAD_STORE(LOAD_LANE_I8x16) + WASM_LOAD_STORE(STORE_LANE_I8x16) return 0; WASM_LOAD_STORE(LOAD16_S_I32) WASM_LOAD_STORE(LOAD16_U_I32) @@ -223,8 +223,8 @@ inline unsigned GetDefaultP2AlignAny(unsigned Opc) { WASM_LOAD_STORE(ATOMIC_RMW16_U_CMPXCHG_I32) WASM_LOAD_STORE(ATOMIC_RMW16_U_CMPXCHG_I64) WASM_LOAD_STORE(LOAD16_SPLAT) - WASM_LOAD_STORE(LOAD_LANE_v8i16) - WASM_LOAD_STORE(STORE_LANE_v8i16) + WASM_LOAD_STORE(LOAD_LANE_I16x8) + WASM_LOAD_STORE(STORE_LANE_I16x8) return 1; WASM_LOAD_STORE(LOAD_I32) WASM_LOAD_STORE(LOAD_F32) @@ -254,9 +254,9 @@ inline unsigned GetDefaultP2AlignAny(unsigned Opc) { WASM_LOAD_STORE(MEMORY_ATOMIC_NOTIFY) WASM_LOAD_STORE(MEMORY_ATOMIC_WAIT32) WASM_LOAD_STORE(LOAD32_SPLAT) - WASM_LOAD_STORE(LOAD_ZERO_v4i32) - WASM_LOAD_STORE(LOAD_LANE_v4i32) - WASM_LOAD_STORE(STORE_LANE_v4i32) + WASM_LOAD_STORE(LOAD_ZERO_I32x4) + WASM_LOAD_STORE(LOAD_LANE_I32x4) + WASM_LOAD_STORE(STORE_LANE_I32x4) return 2; WASM_LOAD_STORE(LOAD_I64) WASM_LOAD_STORE(LOAD_F64) @@ -273,15 +273,15 @@ inline unsigned GetDefaultP2AlignAny(unsigned Opc) { WASM_LOAD_STORE(ATOMIC_RMW_CMPXCHG_I64) WASM_LOAD_STORE(MEMORY_ATOMIC_WAIT64) WASM_LOAD_STORE(LOAD64_SPLAT) - WASM_LOAD_STORE(LOAD_EXTEND_S_v8i16) - WASM_LOAD_STORE(LOAD_EXTEND_U_v8i16) - WASM_LOAD_STORE(LOAD_EXTEND_S_v4i32) - WASM_LOAD_STORE(LOAD_EXTEND_U_v4i32) - WASM_LOAD_STORE(LOAD_EXTEND_S_v2i64) - WASM_LOAD_STORE(LOAD_EXTEND_U_v2i64) - WASM_LOAD_STORE(LOAD_ZERO_v2i64) - WASM_LOAD_STORE(LOAD_LANE_v2i64) - WASM_LOAD_STORE(STORE_LANE_v2i64) + WASM_LOAD_STORE(LOAD_EXTEND_S_I16x8) + WASM_LOAD_STORE(LOAD_EXTEND_U_I16x8) + WASM_LOAD_STORE(LOAD_EXTEND_S_I32x4) + WASM_LOAD_STORE(LOAD_EXTEND_U_I32x4) + WASM_LOAD_STORE(LOAD_EXTEND_S_I64x2) + WASM_LOAD_STORE(LOAD_EXTEND_U_I64x2) + WASM_LOAD_STORE(LOAD_ZERO_I64x2) + WASM_LOAD_STORE(LOAD_LANE_I64x2) + WASM_LOAD_STORE(STORE_LANE_I64x2) return 3; WASM_LOAD_STORE(LOAD_V128) WASM_LOAD_STORE(STORE_V128) diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td index e48bbae..df4de49 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -37,6 +37,75 @@ def ImmI#SIZE : ImmLeaf; +class Vec { + ValueType vt; + ValueType lane_vt; + WebAssemblyRegClass lane_rc; + int lane_bits; + ImmLeaf lane_idx; + string prefix; + Vec split; +} + +def I8x16 : Vec { + let vt = v16i8; + let lane_vt = i32; + let lane_rc = I32; + let lane_bits = 8; + let lane_idx = LaneIdx16; + let prefix = "i8x16"; +} + +def I16x8 : Vec { + let vt = v8i16; + let lane_vt = i32; + let lane_rc = I32; + let lane_bits = 16; + let lane_idx = LaneIdx8; + let prefix = "i16x8"; + let split = I8x16; +} + +def I32x4 : Vec { + let vt = v4i32; + let lane_vt = i32; + let lane_rc = I32; + let lane_bits = 32; + let lane_idx = LaneIdx4; + let prefix = "i32x4"; + let split = I16x8; +} + +def I64x2 : Vec { + let vt = v2i64; + let lane_vt = i64; + let lane_rc = I64; + let lane_bits = 64; + let lane_idx = LaneIdx2; + let prefix = "i64x2"; + let split = I32x4; +} + +def F32x4 : Vec { + let vt = v4f32; + let lane_vt = f32; + let lane_rc = F32; + let lane_bits = 32; + let lane_idx = LaneIdx4; + let prefix = "f32x4"; +} + +def F64x2 : Vec { + let vt = v2f64; + let lane_vt = f64; + let lane_rc = F64; + let lane_bits = 64; + let lane_idx = LaneIdx2; + let prefix = "f64x2"; +} + +defvar AllVecs = [I8x16, I16x8, I32x4, I64x2, F32x4, F64x2]; + //===----------------------------------------------------------------------===// // Load and store //===----------------------------------------------------------------------===// @@ -56,12 +125,12 @@ defm LOAD_V128_A64 : } // Def load patterns from WebAssemblyInstrMemory.td for vector types -foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { -defm : LoadPatNoOffset; -defm : LoadPatImmOff; -defm : LoadPatImmOff; -defm : LoadPatOffsetOnly; -defm : LoadPatGlobalAddrOffOnly; +foreach vec = AllVecs in { +defm : LoadPatNoOffset; +defm : LoadPatImmOff; +defm : LoadPatImmOff; +defm : LoadPatOffsetOnly; +defm : LoadPatGlobalAddrOffOnly; } // v128.loadX_splat @@ -94,87 +163,75 @@ def wasm_load_splat : SDNode<"WebAssemblyISD::LOAD_SPLAT", wasm_load_splat_t, [SDNPHasChain, SDNPMayLoad, SDNPMemOperand]>; def load_splat : PatFrag<(ops node:$addr), (wasm_load_splat node:$addr)>; -foreach args = [["v16i8", "8"], ["v8i16", "16"], ["v4i32", "32"], - ["v2i64", "64"], ["v4f32", "32"], ["v2f64", "64"]] in { -defm : LoadPatNoOffset(args[0]), - load_splat, - "LOAD"#args[1]#"_SPLAT">; -defm : LoadPatImmOff(args[0]), - load_splat, - regPlusImm, - "LOAD"#args[1]#"_SPLAT">; -defm : LoadPatImmOff(args[0]), - load_splat, - or_is_add, - "LOAD"#args[1]#"_SPLAT">; -defm : LoadPatOffsetOnly(args[0]), - load_splat, - "LOAD"#args[1]#"_SPLAT">; -defm : LoadPatGlobalAddrOffOnly(args[0]), - load_splat, - "LOAD"#args[1]#"_SPLAT">; +foreach vec = AllVecs in { +defvar inst = "LOAD"#vec.lane_bits#"_SPLAT"; +defm : LoadPatNoOffset; +defm : LoadPatImmOff; +defm : LoadPatImmOff; +defm : LoadPatOffsetOnly; +defm : LoadPatGlobalAddrOffOnly; } // Load and extend -multiclass SIMDLoadExtend simdop> { +multiclass SIMDLoadExtend simdop> { + defvar signed = vec.prefix#".load"#loadPat#"_s"; + defvar unsigned = vec.prefix#".load"#loadPat#"_u"; let mayLoad = 1, UseNamedOperandTable = 1 in { - defm LOAD_EXTEND_S_#vec_t#_A32 : + defm LOAD_EXTEND_S_#vec#_A32 : SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr), (outs), (ins P2Align:$p2align, offset32_op:$off), [], - name#"_s\t$dst, ${off}(${addr})$p2align", - name#"_s\t$off$p2align", simdop>; - defm LOAD_EXTEND_U_#vec_t#_A32 : + signed#"\t$dst, ${off}(${addr})$p2align", + signed#"\t$off$p2align", simdop>; + defm LOAD_EXTEND_U_#vec#_A32 : SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr), (outs), (ins P2Align:$p2align, offset32_op:$off), [], - name#"_u\t$dst, ${off}(${addr})$p2align", - name#"_u\t$off$p2align", !add(simdop, 1)>; - defm LOAD_EXTEND_S_#vec_t#_A64 : + unsigned#"\t$dst, ${off}(${addr})$p2align", + unsigned#"\t$off$p2align", !add(simdop, 1)>; + defm LOAD_EXTEND_S_#vec#_A64 : SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr), (outs), (ins P2Align:$p2align, offset64_op:$off), [], - name#"_s\t$dst, ${off}(${addr})$p2align", - name#"_s\t$off$p2align", simdop>; - defm LOAD_EXTEND_U_#vec_t#_A64 : + signed#"\t$dst, ${off}(${addr})$p2align", + signed#"\t$off$p2align", simdop>; + defm LOAD_EXTEND_U_#vec#_A64 : SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr), (outs), (ins P2Align:$p2align, offset64_op:$off), [], - name#"_u\t$dst, ${off}(${addr})$p2align", - name#"_u\t$off$p2align", !add(simdop, 1)>; + unsigned#"\t$dst, ${off}(${addr})$p2align", + unsigned#"\t$off$p2align", !add(simdop, 1)>; } } -defm "" : SIMDLoadExtend; -defm "" : SIMDLoadExtend; -defm "" : SIMDLoadExtend; - -foreach types = [[v8i16, i8], [v4i32, i16], [v2i64, i32]] in -foreach exts = [["sextloadv", "_S"], - ["zextloadv", "_U"], - ["extloadv", "_U"]] in { -defm : LoadPatNoOffset(exts[0]#types[1]), - "LOAD_EXTEND"#exts[1]#"_"#types[0]>; -defm : LoadPatImmOff(exts[0]#types[1]), regPlusImm, - "LOAD_EXTEND"#exts[1]#"_"#types[0]>; -defm : LoadPatImmOff(exts[0]#types[1]), or_is_add, - "LOAD_EXTEND"#exts[1]#"_"#types[0]>; -defm : LoadPatOffsetOnly(exts[0]#types[1]), - "LOAD_EXTEND"#exts[1]#"_"#types[0]>; -defm : LoadPatGlobalAddrOffOnly(exts[0]#types[1]), - "LOAD_EXTEND"#exts[1]#"_"#types[0]>; +defm "" : SIMDLoadExtend; +defm "" : SIMDLoadExtend; +defm "" : SIMDLoadExtend; + +foreach vec = [I16x8, I32x4, I64x2] in +foreach exts = [["sextloadvi", "_S"], + ["zextloadvi", "_U"], + ["extloadvi", "_U"]] in { +defvar loadpat = !cast(exts[0]#vec.split.lane_bits); +defvar inst = "LOAD_EXTEND"#exts[1]#"_"#vec; +defm : LoadPatNoOffset; +defm : LoadPatImmOff; +defm : LoadPatImmOff; +defm : LoadPatOffsetOnly; +defm : LoadPatGlobalAddrOffOnly; } // Load lane into zero vector -multiclass SIMDLoadZero simdop> { +multiclass SIMDLoadZero simdop> { + defvar name = "v128.load"#vec.lane_bits#"_zero"; let mayLoad = 1, UseNamedOperandTable = 1 in { - defm LOAD_ZERO_#vec_t#_A32 : + defm LOAD_ZERO_#vec#_A32 : SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset32_op:$off, I32:$addr), (outs), (ins P2Align:$p2align, offset32_op:$off), [], name#"\t$dst, ${off}(${addr})$p2align", name#"\t$off$p2align", simdop>; - defm LOAD_ZERO_#vec_t#_A64 : + defm LOAD_ZERO_#vec#_A64 : SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset64_op:$off, I64:$addr), (outs), (ins P2Align:$p2align, offset64_op:$off), [], @@ -185,35 +242,31 @@ multiclass SIMDLoadZero simdop> { // TODO: Also support v4f32 and v2f64 once the instructions are merged // to the proposal -defm "" : SIMDLoadZero; -defm "" : SIMDLoadZero; - -defm : LoadPatNoOffset; -defm : LoadPatNoOffset; - -defm : LoadPatImmOff; -defm : LoadPatImmOff; - -defm : LoadPatImmOff; -defm : LoadPatImmOff; - -defm : LoadPatOffsetOnly; -defm : LoadPatOffsetOnly; - -defm : LoadPatGlobalAddrOffOnly; -defm : LoadPatGlobalAddrOffOnly; +defm "" : SIMDLoadZero; +defm "" : SIMDLoadZero; + +foreach vec = [I32x4, I64x2] in { +defvar loadpat = !cast("int_wasm_load"#vec.lane_bits#"_zero"); +defvar inst = "LOAD_ZERO_"#vec; +defm : LoadPatNoOffset; +defm : LoadPatImmOff; +defm : LoadPatImmOff; +defm : LoadPatOffsetOnly; +defm : LoadPatGlobalAddrOffOnly; +} // Load lane -multiclass SIMDLoadLane simdop> { +multiclass SIMDLoadLane simdop> { + defvar name = "v128.load"#vec.lane_bits#"_lane"; let mayLoad = 1, UseNamedOperandTable = 1 in { - defm LOAD_LANE_#vec_t#_A32 : + defm LOAD_LANE_#vec#_A32 : SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset32_op:$off, vec_i8imm_op:$idx, I32:$addr, V128:$vec), (outs), (ins P2Align:$p2align, offset32_op:$off, vec_i8imm_op:$idx), [], name#"\t$dst, ${off}(${addr})$p2align, $vec, $idx", name#"\t$off$p2align, $idx", simdop>; - defm LOAD_LANE_#vec_t#_A64 : + defm LOAD_LANE_#vec#_A64 : SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset64_op:$off, vec_i8imm_op:$idx, I64:$addr, V128:$vec), @@ -225,25 +278,29 @@ multiclass SIMDLoadLane simdop> { // TODO: Also support v4f32 and v2f64 once the instructions are merged // to the proposal -defm "" : SIMDLoadLane; -defm "" : SIMDLoadLane; -defm "" : SIMDLoadLane; -defm "" : SIMDLoadLane; +defm "" : SIMDLoadLane; +defm "" : SIMDLoadLane; +defm "" : SIMDLoadLane; +defm "" : SIMDLoadLane; // Select loads with no constant offset. -multiclass LoadLanePatNoOffset { - def : Pat<(ty (kind (i32 I32:$addr), (ty V128:$vec), (i32 lane_imm_t:$idx))), - (!cast("LOAD_LANE_"#ty#"_A32") 0, 0, imm:$idx, I32:$addr, V128:$vec)>, +multiclass LoadLanePatNoOffset { + defvar load_lane_a32 = !cast("LOAD_LANE_"#vec#"_A32"); + defvar load_lane_a64 = !cast("LOAD_LANE_"#vec#"_A64"); + def : Pat<(vec.vt (kind (i32 I32:$addr), + (vec.vt V128:$vec), (i32 vec.lane_idx:$idx))), + (load_lane_a32 0, 0, imm:$idx, I32:$addr, V128:$vec)>, Requires<[HasAddr32]>; - def : Pat<(ty (kind (i64 I64:$addr), (ty V128:$vec), (i32 lane_imm_t:$idx))), - (!cast("LOAD_LANE_"#ty#"_A64") 0, 0, imm:$idx, I64:$addr, V128:$vec)>, + def : Pat<(vec.vt (kind (i64 I64:$addr), + (vec.vt V128:$vec), (i32 vec.lane_idx:$idx))), + (load_lane_a64 0, 0, imm:$idx, I64:$addr, V128:$vec)>, Requires<[HasAddr64]>; } -defm : LoadLanePatNoOffset; -defm : LoadLanePatNoOffset; -defm : LoadLanePatNoOffset; -defm : LoadLanePatNoOffset; +defm : LoadLanePatNoOffset; +defm : LoadLanePatNoOffset; +defm : LoadLanePatNoOffset; +defm : LoadLanePatNoOffset; // TODO: Also support the other load patterns for load_lane once the instructions // are merged to the proposal. @@ -263,25 +320,26 @@ defm STORE_V128_A64 : } // Def store patterns from WebAssemblyInstrMemory.td for vector types -foreach vec_t = [v16i8, v8i16, v4i32, v2i64, v4f32, v2f64] in { -defm : StorePatNoOffset; -defm : StorePatImmOff; -defm : StorePatImmOff; -defm : StorePatOffsetOnly; -defm : StorePatGlobalAddrOffOnly; +foreach vec = AllVecs in { +defm : StorePatNoOffset; +defm : StorePatImmOff; +defm : StorePatImmOff; +defm : StorePatOffsetOnly; +defm : StorePatGlobalAddrOffOnly; } // Store lane -multiclass SIMDStoreLane simdop> { +multiclass SIMDStoreLane simdop> { + defvar name = "v128.store"#vec.lane_bits#"_lane"; let mayStore = 1, UseNamedOperandTable = 1 in { - defm STORE_LANE_#vec_t#_A32 : + defm STORE_LANE_#vec#_A32 : SIMD_I<(outs), (ins P2Align:$p2align, offset32_op:$off, vec_i8imm_op:$idx, I32:$addr, V128:$vec), (outs), (ins P2Align:$p2align, offset32_op:$off, vec_i8imm_op:$idx), [], name#"\t${off}(${addr})$p2align, $vec, $idx", name#"\t$off$p2align, $idx", simdop>; - defm STORE_LANE_#vec_t#_A64 : + defm STORE_LANE_#vec#_A64 : SIMD_I<(outs V128:$dst), (ins P2Align:$p2align, offset64_op:$off, vec_i8imm_op:$idx, I64:$addr, V128:$vec), @@ -293,27 +351,27 @@ multiclass SIMDStoreLane simdop> { // TODO: Also support v4f32 and v2f64 once the instructions are merged // to the proposal -defm "" : SIMDStoreLane; -defm "" : SIMDStoreLane; -defm "" : SIMDStoreLane; -defm "" : SIMDStoreLane; +defm "" : SIMDStoreLane; +defm "" : SIMDStoreLane; +defm "" : SIMDStoreLane; +defm "" : SIMDStoreLane; // Select stores with no constant offset. -multiclass StoreLanePatNoOffset { - def : Pat<(kind (i32 I32:$addr), (ty V128:$vec), (i32 lane_imm_t:$idx)), - (!cast("STORE_LANE_"#ty#"_A32") - 0, 0, imm:$idx, I32:$addr, ty:$vec)>, +multiclass StoreLanePatNoOffset { + def : Pat<(kind (i32 I32:$addr), (vec.vt V128:$vec), (i32 vec.lane_idx:$idx)), + (!cast("STORE_LANE_"#vec#"_A32") + 0, 0, imm:$idx, I32:$addr, vec.vt:$vec)>, Requires<[HasAddr32]>; - def : Pat<(kind (i64 I64:$addr), (ty V128:$vec), (i32 lane_imm_t:$idx)), - (!cast("STORE_LANE_"#ty#"_A64") - 0, 0, imm:$idx, I64:$addr, ty:$vec)>, + def : Pat<(kind (i64 I64:$addr), (vec.vt V128:$vec), (i32 vec.lane_idx:$idx)), + (!cast("STORE_LANE_"#vec#"_A64") + 0, 0, imm:$idx, I64:$addr, vec.vt:$vec)>, Requires<[HasAddr64]>; } -defm : StoreLanePatNoOffset; -defm : StoreLanePatNoOffset; -defm : StoreLanePatNoOffset; -defm : StoreLanePatNoOffset; +defm : StoreLanePatNoOffset; +defm : StoreLanePatNoOffset; +defm : StoreLanePatNoOffset; +defm : StoreLanePatNoOffset; // TODO: Also support the other store patterns for store_lane once the // instructions are merged to the proposal. -- 2.7.4