From 0706bd283b07b4a35fc3b3b9781688a5b2944f28 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Tue, 14 Aug 2018 18:53:27 +0000 Subject: [PATCH] [WebAssembly] SIMD extract_lane Implement instruction selection for all versions of the extract_lane instruction. Use explicit sext/zext to differentiate between extract_lane_s and extract_lane_u for applicable types, otherwise default to extract_lane_u. Reviewers: aheejin Subscribers: sunfish, jgravelle-google, sbc100, llvm-commits Differential Revision: https://reviews.llvm.org/D50597 Patch by Thomas Lively (tlively) llvm-svn: 339707 --- .../WebAssembly/WebAssemblyInstrSIMD.td | 66 +++++++- test/CodeGen/WebAssembly/simd.ll | 142 ++++++++++++++++++ 2 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 test/CodeGen/WebAssembly/simd.ll diff --git a/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td b/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td index 5ff0ecba034..1c0090ebba1 100644 --- a/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ b/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -12,19 +12,79 @@ /// //===----------------------------------------------------------------------===// -let Defs = [ARGUMENTS] in { +// Immediate argument types +def ImmByte : ImmLeaf; +foreach SIZE = [2, 4, 8, 16, 32] in +def LaneIdx#SIZE : ImmLeaf; +// lane extraction +multiclass ExtractLane simdop, + SDNode extract = vector_extract> { + defm "" : SIMD_I<(outs reg_t:$dst), (ins V128:$vec, I32:$idx), + (outs), (ins I32:$idx), + [(set reg_t:$dst, + (extract (vec_t V128:$vec), (i32 imm_t:$idx)))], + name#"\t$dst, $vec, $idx", name#"\t$idx", simdop>; +} +multiclass ExtractPat { + def _s : PatFrag<(ops node:$vec, node:$idx), + (i32 (sext_inreg + (i32 (vector_extract + node:$vec, + node:$idx + )), + lane_t + ))>; + def _u : PatFrag<(ops node:$vec, node:$idx), + (i32 (and + (i32 (vector_extract + node:$vec, + node:$idx + )), + (i32 mask) + ))>; +} +defm extract_i8x16 : ExtractPat; +defm extract_i16x8 : ExtractPat; +multiclass ExtractLaneExtended baseInst> { + defm _I8x16 : ExtractLane("extract_i8x16"#sign)>; + defm _I16x8 : ExtractLane("extract_i16x8"#sign)>; +} + +let Defs = [ARGUMENTS] in { +defm EXTRACT_LANE_S : ExtractLaneExtended<"_s", 9>; +defm EXTRACT_LANE_U : ExtractLaneExtended<"_u", 10>; +defm EXTRACT_LANE_I32x4 : + ExtractLane; +defm EXTRACT_LANE_I64x2 : + ExtractLane; +defm EXTRACT_LANE_F32x4 : + ExtractLane; +defm EXTRACT_LANE_F64x2 : + ExtractLane; +} // Defs = [ARGUMENTS] + +// follow convention of making implicit expansions unsigned +def : Pat<(i32 (vector_extract (v16i8 V128:$vec), (i32 LaneIdx16:$idx))), + (EXTRACT_LANE_U_I8x16 V128:$vec, (i32 LaneIdx16:$idx))>; +def : Pat<(i32 (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx))), + (EXTRACT_LANE_U_I16x8 V128:$vec, (i32 LaneIdx8:$idx))>; + +// arithmetic +let Defs = [ARGUMENTS] in { let isCommutable = 1 in defm ADD : SIMDBinaryInt; defm SUB : SIMDBinaryInt; let isCommutable = 1 in defm MUL : SIMDBinaryInt; - let isCommutable = 1 in defm ADD : SIMDBinaryFP; defm SUB : SIMDBinaryFP; defm DIV : SIMDBinaryFP; let isCommutable = 1 in defm MUL : SIMDBinaryFP; - } // Defs = [ARGUMENTS] diff --git a/test/CodeGen/WebAssembly/simd.ll b/test/CodeGen/WebAssembly/simd.ll new file mode 100644 index 00000000000..af585dd7066 --- /dev/null +++ b/test/CodeGen/WebAssembly/simd.ll @@ -0,0 +1,142 @@ +; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -wasm-enable-unimplemented-simd -mattr=+simd128,+sign-ext | FileCheck %s --check-prefixes CHECK,SIMD128 +; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=+simd128,+sign-ext | FileCheck %s --check-prefixes CHECK,SIMD128-VM +; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -disable-wasm-explicit-locals -mattr=-simd128,+sign-ext | FileCheck %s --check-prefixes CHECK,NO-SIMD128 + +; Test that basic SIMD128 vector manipulation operations assemble as expected. + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +; ============================================================================== +; 16 x i8 +; ============================================================================== +; CHECK-LABEL: extract_v16i8_s:{{$}} +; NO-SIMD128-NOT: i8x16 +; SIMD128: .param v128{{$}} +; SIMD128: .result i32{{$}} +; SIMD128: i8x16.extract_lane_s $push0=, $0, 13{{$}} +; SIMD128: return $pop0{{$}} +define i32 @extract_v16i8_s(<16 x i8> %v) { + %elem = extractelement <16 x i8> %v, i8 13 + %a = sext i8 %elem to i32 + ret i32 %a +} + +; CHECK-LABEL: extract_v16i8_u:{{$}} +; NO-SIMD128-NOT: i8x16 +; SIMD128: .param v128{{$}} +; SIMD128: .result i32{{$}} +; SIMD128: i8x16.extract_lane_u $push0=, $0, 13{{$}} +; SIMD128: return $pop0{{$}} +define i32 @extract_v16i8_u(<16 x i8> %v) { + %elem = extractelement <16 x i8> %v, i8 13 + %a = zext i8 %elem to i32 + ret i32 %a +} + +; CHECK-LABEL: extract_v16i8:{{$}} +; NO-SIMD128-NOT: i8x16 +; SIMD128: .param v128{{$}} +; SIMD128: .result i32{{$}} +; SIMD128: i8x16.extract_lane_u $push0=, $0, 13{{$}} +; SIMD128: return $pop0{{$}} +define i8 @extract_v16i8(<16 x i8> %v) { + %elem = extractelement <16 x i8> %v, i8 13 + ret i8 %elem +} + +; ============================================================================== +; 8 x i16 +; ============================================================================== +; CHECK-LABEL: extract_v8i16_s:{{$}} +; NO-SIMD128-NOT: i16x8 +; SIMD128: .param v128{{$}} +; SIMD128: .result i32{{$}} +; SIMD128: i16x8.extract_lane_s $push0=, $0, 5{{$}} +; SIMD128: return $pop0{{$}} +define i32 @extract_v8i16_s(<8 x i16> %v) { + %elem = extractelement <8 x i16> %v, i16 5 + %a = sext i16 %elem to i32 + ret i32 %a +} + +; CHECK-LABEL: extract_v8i16_u:{{$}} +; NO-SIMD128-NOT: i16x8 +; SIMD128: .param v128{{$}} +; SIMD128: .result i32{{$}} +; SIMD128: i16x8.extract_lane_u $push0=, $0, 5{{$}} +; SIMD128: return $pop0{{$}} +define i32 @extract_v8i16_u(<8 x i16> %v) { + %elem = extractelement <8 x i16> %v, i16 5 + %a = zext i16 %elem to i32 + ret i32 %a +} + +; CHECK-LABEL: extract_v8i16:{{$}} +; NO-SIMD128-NOT: i16x8 +; SIMD128: .param v128{{$}} +; SIMD128: .result i32{{$}} +; SIMD128: i16x8.extract_lane_u $push0=, $0, 5{{$}} +; SIMD128: return $pop0{{$}} +define i16 @extract_v8i16(<8 x i16> %v) { + %elem = extractelement <8 x i16> %v, i16 5 + ret i16 %elem +} + +; ============================================================================== +; 4 x i32 +; ============================================================================== +; CHECK-LABEL: extract_v4i32:{{$}} +; NO-SIMD128-NOT: i32x4 +; SIMD128: .param v128{{$}} +; SIMD128: .result i32{{$}} +; SIMD128: i32x4.extract_lane $push0=, $0, 3{{$}} +; SIMD128: return $pop0{{$}} +define i32 @extract_v4i32(<4 x i32> %v) { + %elem = extractelement <4 x i32> %v, i32 3 + ret i32 %elem +} + +; ============================================================================== +; 2 x i64 +; ============================================================================== +; CHECK-LABEL: extract_v2i64:{{$}} +; NO-SIMD128-NOT: i64x2 +; SIMD128-VM-NOT: i64x2 +; SIMD128: .param v128{{$}} +; SIMD128: .result i64{{$}} +; SIMD128: i64x2.extract_lane $push0=, $0, 1{{$}} +; SIMD128: return $pop0{{$}} +define i64 @extract_v2i64(<2 x i64> %v) { + %elem = extractelement <2 x i64> %v, i64 1 + ret i64 %elem +} + +; ============================================================================== +; 4 x f32 +; ============================================================================== +; CHECK-LABEL: extract_v4f32:{{$}} +; NO-SIMD128-NOT: f32x4 +; SIMD128: .param v128{{$}} +; SIMD128: .result f32{{$}} +; SIMD128: f32x4.extract_lane $push0=, $0, 3{{$}} +; SIMD128: return $pop0{{$}} +define float @extract_v4f32(<4 x float> %v) { + %elem = extractelement <4 x float> %v, i32 3 + ret float %elem +} + +; ============================================================================== +; 2 x f64 +; ============================================================================== +; CHECK-LABEL: extract_v2f64:{{$}} +; NO-SIMD128-NOT: f64x2 +; SIMD128-VM-NOT: f64x2 +; SIMD128: .param v128{{$}} +; SIMD128: .result f64{{$}} +; SIMD128: f64x2.extract_lane $push0=, $0, 1{{$}} +; SIMD128: return $pop0{{$}} +define double @extract_v2f64(<2 x double> %v) { + %elem = extractelement <2 x double> %v, i32 1 + ret double %elem +}