Skip to content

Commit

Permalink
[WebAssembly] v128.const
Browse files Browse the repository at this point in the history
Summary:
This CL implements v128.const for each vector type. New operand types
are added to ensure the vector contents can be serialized without LEB
encoding. Tests are added for instruction selection, encoding,
assembly and disassembly.

Reviewers: aheejin, dschuff, aardappel

Subscribers: sbc100, jgravelle-google, sunfish, llvm-commits

Differential Revision: https://reviews.llvm.org/D50873

llvm-svn: 340336
  • Loading branch information
tlively committed Aug 21, 2018
1 parent 61aaa35 commit 2244292
Show file tree
Hide file tree
Showing 9 changed files with 229 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ static unsigned MVTToWasmReg(MVT::SimpleValueType Type) {
case MVT::v16i8: return WebAssembly::V128_0;
case MVT::v8i16: return WebAssembly::V128_0;
case MVT::v4i32: return WebAssembly::V128_0;
case MVT::v2i64: return WebAssembly::V128_0;
case MVT::v4f32: return WebAssembly::V128_0;
case MVT::v2f64: return WebAssembly::V128_0;
default: return MVT::INVALID_SIMPLE_VALUE_TYPE;
}
}
Expand Down Expand Up @@ -194,6 +196,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
const MCInstrInfo &mii, const MCTargetOptions &Options)
: MCTargetAsmParser(Options, sti, mii), Parser(Parser),
Lexer(Parser.getLexer()), LastLabel(nullptr) {
setAvailableFeatures(ComputeAvailableFeatures(sti.getFeatureBits()));
}

#define GET_ASSEMBLER_HEADER
Expand Down Expand Up @@ -232,7 +235,13 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
.Case("i8x16", MVT::v16i8)
.Case("i16x8", MVT::v8i16)
.Case("i32x4", MVT::v4i32)
.Case("i64x2", MVT::v2i64)
.Case("f32x4", MVT::v4f32)
.Case("f64x2", MVT::v2f64)
// arbitrarily chosen vector type to associate with "v128"
// FIXME: should these be EVTs to avoid this arbitrary hack? Do we want
// to accept more specific SIMD register types?
.Case("v128", MVT::v16i8)
.Default(MVT::INVALID_SIMPLE_VALUE_TYPE);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,18 @@ static bool parseLEBImmediate(MCInst &MI, uint64_t &Size,
}

template <typename T>
bool parseFPImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes) {
if (Size + sizeof(T) > Bytes.size())
return false;
T Val;
memcpy(&Val, Bytes.data() + Size, sizeof(T));
support::endian::byte_swap<T, support::endianness::little>(Val);
Size += sizeof(T);
MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
if (std::is_floating_point<T>::value) {
MI.addOperand(MCOperand::createFPImm(static_cast<double>(Val)));
} else {
MI.addOperand(MCOperand::createImm(static_cast<int64_t>(Val)));
}
return true;
}

Expand Down Expand Up @@ -160,12 +164,33 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
}
// FP operands.
case WebAssembly::OPERAND_F32IMM: {
if (!parseFPImmediate<float>(MI, Size, Bytes))
if (!parseImmediate<float>(MI, Size, Bytes))
return MCDisassembler::Fail;
break;
}
case WebAssembly::OPERAND_F64IMM: {
if (!parseFPImmediate<double>(MI, Size, Bytes))
if (!parseImmediate<double>(MI, Size, Bytes))
return MCDisassembler::Fail;
break;
}
// Vector lane operands (not LEB encoded).
case WebAssembly::OPERAND_VEC_I8IMM: {
if (!parseImmediate<uint8_t>(MI, Size, Bytes))
return MCDisassembler::Fail;
break;
}
case WebAssembly::OPERAND_VEC_I16IMM: {
if (!parseImmediate<uint16_t>(MI, Size, Bytes))
return MCDisassembler::Fail;
break;
}
case WebAssembly::OPERAND_VEC_I32IMM: {
if (!parseImmediate<uint32_t>(MI, Size, Bytes))
return MCDisassembler::Fail;
break;
}
case WebAssembly::OPERAND_VEC_I64IMM: {
if (!parseImmediate<uint64_t>(MI, Size, Bytes))
return MCDisassembler::Fail;
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,34 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
const MCOperandInfo &Info = Desc.OpInfo[i];
LLVM_DEBUG(dbgs() << "Encoding immediate: type="
<< int(Info.OperandType) << "\n");
if (Info.OperandType == WebAssembly::OPERAND_I32IMM) {
switch (Info.OperandType) {
case WebAssembly::OPERAND_I32IMM:
encodeSLEB128(int32_t(MO.getImm()), OS);
} else if (Info.OperandType == WebAssembly::OPERAND_OFFSET32) {
break;
case WebAssembly::OPERAND_OFFSET32:
encodeULEB128(uint32_t(MO.getImm()), OS);
} else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
break;
case WebAssembly::OPERAND_I64IMM:
encodeSLEB128(int64_t(MO.getImm()), OS);
} else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) {
llvm_unreachable("wasm globals should only be accessed symbolicly");
} else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) {
break;
case WebAssembly::OPERAND_SIGNATURE:
OS << uint8_t(MO.getImm());
} else {
break;
case WebAssembly::OPERAND_VEC_I8IMM:
support::endian::write<uint8_t>(OS, MO.getImm(), support::little);
break;
case WebAssembly::OPERAND_VEC_I16IMM:
support::endian::write<uint16_t>(OS, MO.getImm(), support::little);
break;
case WebAssembly::OPERAND_VEC_I32IMM:
support::endian::write<uint32_t>(OS, MO.getImm(), support::little);
break;
case WebAssembly::OPERAND_VEC_I64IMM:
support::endian::write<uint64_t>(OS, MO.getImm(), support::little);
break;
case WebAssembly::OPERAND_GLOBAL:
llvm_unreachable("wasm globals should only be accessed symbolicly");
default:
encodeULEB128(uint64_t(MO.getImm()), OS);
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ enum OperandType {
OPERAND_F32IMM,
/// 64-bit floating-point immediates.
OPERAND_F64IMM,
/// 8-bit vector lane immediate
OPERAND_VEC_I8IMM,
/// 16-bit vector lane immediate
OPERAND_VEC_I16IMM,
/// 32-bit vector lane immediate
OPERAND_VEC_I32IMM,
/// 64-bit vector lane immediate
OPERAND_VEC_I64IMM,
/// 32-bit unsigned function indices.
OPERAND_FUNCTION32,
/// 32-bit unsigned memory offsets.
Expand Down
12 changes: 12 additions & 0 deletions llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,18 @@ def f32imm_op : Operand<f32>;
let OperandType = "OPERAND_F64IMM" in
def f64imm_op : Operand<f64>;

let OperandType = "OPERAND_VEC_I8IMM" in
def vec_i8imm_op : Operand<i32>;

let OperandType = "OPERAND_VEC_I16IMM" in
def vec_i16imm_op : Operand<i32>;

let OperandType = "OPERAND_VEC_I32IMM" in
def vec_i32imm_op : Operand<i32>;

let OperandType = "OPERAND_VEC_I64IMM" in
def vec_i64imm_op : Operand<i64>;

let OperandType = "OPERAND_FUNCTION32" in
def function32_op : Operand<i32>;

Expand Down
65 changes: 59 additions & 6 deletions llvm/lib/Target/WebAssembly/WebAssemblyInstrSIMD.td
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,71 @@
///
//===----------------------------------------------------------------------===//

// immediate argument types
def ImmByte : ImmLeaf<i32, [{ return 0 <= Imm && Imm < 256; }]>;
// constrained immediate argument types
foreach SIZE = [8, 16] in
def ImmI#SIZE : ImmLeaf<i32, "return (Imm & ((1UL << "#SIZE#") - 1)) == Imm;">;
foreach SIZE = [2, 4, 8, 16, 32] in
def LaneIdx#SIZE : ImmLeaf<i32, "return 0 <= Imm && Imm < "#SIZE#";">;

// const vectors
multiclass ConstVec<ValueType vec_t, dag ops, dag pat, string args> {
defm CONST_V128_#vec_t : SIMD_I<(outs V128:$dst), ops, (outs), ops,
[(set V128:$dst, (vec_t pat))],
"v128.const\t$dst, "#args,
"v128.const\t"#args, 0>;
}
defm "" : ConstVec<v16i8,
(ins vec_i8imm_op:$i0, vec_i8imm_op:$i1,
vec_i8imm_op:$i2, vec_i8imm_op:$i3,
vec_i8imm_op:$i4, vec_i8imm_op:$i5,
vec_i8imm_op:$i6, vec_i8imm_op:$i7,
vec_i8imm_op:$i8, vec_i8imm_op:$i9,
vec_i8imm_op:$iA, vec_i8imm_op:$iB,
vec_i8imm_op:$iC, vec_i8imm_op:$iD,
vec_i8imm_op:$iE, vec_i8imm_op:$iF),
(build_vector ImmI8:$i0, ImmI8:$i1, ImmI8:$i2, ImmI8:$i3,
ImmI8:$i4, ImmI8:$i5, ImmI8:$i6, ImmI8:$i7,
ImmI8:$i8, ImmI8:$i9, ImmI8:$iA, ImmI8:$iB,
ImmI8:$iC, ImmI8:$iD, ImmI8:$iE, ImmI8:$iF),
!strconcat("$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7, ",
"$i8, $i9, $iA, $iB, $iC, $iD, $iE, $iF")>;
defm "" : ConstVec<v8i16,
(ins vec_i16imm_op:$i0, vec_i16imm_op:$i1,
vec_i16imm_op:$i2, vec_i16imm_op:$i3,
vec_i16imm_op:$i4, vec_i16imm_op:$i5,
vec_i16imm_op:$i6, vec_i16imm_op:$i7),
(build_vector
ImmI16:$i0, ImmI16:$i1, ImmI16:$i2, ImmI16:$i3,
ImmI16:$i4, ImmI16:$i5, ImmI16:$i6, ImmI16:$i7),
"$i0, $i1, $i2, $i3, $i4, $i5, $i6, $i7">;
defm "" : ConstVec<v4i32,
(ins vec_i32imm_op:$i0, vec_i32imm_op:$i1,
vec_i32imm_op:$i2, vec_i32imm_op:$i3),
(build_vector (i32 imm:$i0), (i32 imm:$i1),
(i32 imm:$i2), (i32 imm:$i3)),
"$i0, $i1, $i2, $i3">;
defm "" : ConstVec<v2i64,
(ins vec_i64imm_op:$i0, vec_i64imm_op:$i1),
(build_vector (i64 imm:$i0), (i64 imm:$i1)),
"$i0, $i1">;
defm "" : ConstVec<v4f32,
(ins f32imm_op:$i0, f32imm_op:$i1,
f32imm_op:$i2, f32imm_op:$i3),
(build_vector (f32 fpimm:$i0), (f32 fpimm:$i1),
(f32 fpimm:$i2), (f32 fpimm:$i3)),
"$i0, $i1, $i2, $i3">;
defm "" : ConstVec<v2f64,
(ins f64imm_op:$i0, f64imm_op:$i1),
(build_vector (f64 fpimm:$i0), (f64 fpimm:$i1)),
"$i0, $i1">;

// lane extraction
multiclass ExtractLane<ValueType vec_t, string vec, ImmLeaf imm_t,
WebAssemblyRegClass reg_t, bits<32> simdop,
string suffix = "", SDNode extract = vector_extract> {
defm EXTRACT_LANE_#vec_t#suffix :
SIMD_I<(outs reg_t:$dst), (ins V128:$vec, I32:$idx),
(outs), (ins I32:$idx),
SIMD_I<(outs reg_t:$dst), (ins V128:$vec, i32imm_op:$idx),
(outs), (ins i32imm_op:$idx),
[(set reg_t:$dst, (extract (vec_t V128:$vec), (i32 imm_t:$idx)))],
vec#".extract_lane"#suffix#"\t$dst, $vec, $idx",
vec#".extract_lane"#suffix#"\t$idx", simdop>;
Expand Down Expand Up @@ -73,8 +126,8 @@ def : Pat<(i32 (vector_extract (v8i16 V128:$vec), (i32 LaneIdx8:$idx))),
multiclass ReplaceLane<ValueType vec_t, string vec, WebAssemblyRegClass reg_t,
ValueType lane_t, ImmLeaf imm_t, bits<32> simdop> {
defm REPLACE_LANE_#vec_t :
SIMD_I<(outs V128:$dst), (ins V128:$vec, I32:$idx, reg_t:$x),
(outs), (ins I32:$idx),
SIMD_I<(outs V128:$dst), (ins V128:$vec, i32imm_op:$idx, reg_t:$x),
(outs), (ins i32imm_op:$idx),
[(set V128:$dst, (vector_insert
(vec_t V128:$vec), (lane_t reg_t:$x), (i32 imm_t:$idx)))],
vec#".replace_lane\t$dst, $vec, $idx, $x",
Expand Down
72 changes: 72 additions & 0 deletions llvm/test/CodeGen/WebAssembly/simd.ll
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ target triple = "wasm32-unknown-unknown"
; ==============================================================================
; 16 x i8
; ==============================================================================
; CHECK-LABEL: const_v16i8:
; NO-SIMD128-NOT: i8x16
; SIMD128: .result v128{{$}}
; SIMD128: v128.const $push0=,
; SIMD128-SAME: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
; SIMD128-SAME: # encoding: [0xfd,0x00,
; SIMD128-SAME: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
; SIMD128-SAME: 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f]{{$}}
define <16 x i8> @const_v16i8() {
ret <16 x i8> <i8 00, i8 01, i8 02, i8 03, i8 04, i8 05, i8 06, i8 07,
i8 08, i8 09, i8 10, i8 11, i8 12, i8 13, i8 14, i8 15>
}

; CHECK-LABEL: splat_v16i8:
; NO-SIMD128-NOT: i8x16
; SIMD128: .param i32{{$}}
Expand Down Expand Up @@ -73,6 +86,18 @@ define <16 x i8> @replace_v16i8(<16 x i8> %v, i8 %x) {
; ==============================================================================
; 8 x i16
; ==============================================================================
; CHECK-LABEL: const_v8i16:
; NO-SIMD128-NOT: i16x8
; SIMD128: .result v128{{$}}
; SIMD128: v128.const $push0=, 256, 770, 1284, 1798, 2312, 2826, 3340, 3854
; SIMD128-SAME: # encoding: [0xfd,0x00,
; SIMD128-SAME: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
; SIMD128-SAME: 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f]{{$}}
define <8 x i16> @const_v8i16() {
ret <8 x i16> <i16 256, i16 770, i16 1284, i16 1798,
i16 2312, i16 2826, i16 3340, i16 3854>
}

; CHECK-LABEL: splat_v8i16:
; NO-SIMD128-NOT: i16x8
; SIMD128: .param i32{{$}}
Expand Down Expand Up @@ -135,6 +160,17 @@ define <8 x i16> @replace_v8i16(<8 x i16> %v, i16 %x) {
; ==============================================================================
; 4 x i32
; ==============================================================================
; CHECK-LABEL: const_v4i32:
; NO-SIMD128-NOT: i32x4
; SIMD128: .result v128{{$}}
; SIMD128: v128.const $push0=, 50462976, 117835012, 185207048, 252579084
; SIMD128-SAME: # encoding: [0xfd,0x00,
; SIMD128-SAME: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
; SIMD128-SAME: 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f]{{$}}
define <4 x i32> @const_v4i32() {
ret <4 x i32> <i32 50462976, i32 117835012, i32 185207048, i32 252579084>
}

; CHECK-LABEL: splat_v4i32:
; NO-SIMD128-NOT: i32x4
; SIMD128: .param i32{{$}}
Expand Down Expand Up @@ -173,6 +209,18 @@ define <4 x i32> @replace_v4i32(<4 x i32> %v, i32 %x) {
; ==============================================================================
; 2 x i64
; ==============================================================================
; CHECK-LABEL: const_v2i64:
; NO-SIMD128-NOT: i64x2
; SIMD128-VM-NOT: i64x2
; SIMD128: .result v128{{$}}
; SIMD128: v128.const $push0=, 506097522914230528, 1084818905618843912
; SIMD128-SAME: # encoding: [0xfd,0x00,
; SIMD128-SAME: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
; SIMD128-SAME: 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f]{{$}}
define <2 x i64> @const_v2i64() {
ret <2 x i64> <i64 506097522914230528, i64 1084818905618843912>
}

; CHECK-LABEL: splat_v2i64:
; NO-SIMD128-NOT: i64x2
; SIMD128-VM-NOT: i64x2
Expand Down Expand Up @@ -213,6 +261,19 @@ define <2 x i64> @replace_v2i64(<2 x i64> %v, i64 %x) {
; ==============================================================================
; 4 x f32
; ==============================================================================
; CHECK-LABEL: const_v4f32:
; NO-SIMD128-NOT: f32x4
; SIMD128: .result v128{{$}}
; SIMD128: v128.const $push0=,
; SIMD128-SAME: 0x1.0402p-121, 0x1.0c0a08p-113, 0x1.14121p-105, 0x1.1c1a18p-97
; SIMD128-SAME: # encoding: [0xfd,0x00,
; SIMD128-SAME: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
; SIMD128-SAME: 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f]{{$}}
define <4 x float> @const_v4f32() {
ret <4 x float> <float 0x3860402000000000, float 0x38e0c0a080000000,
float 0x3961412100000000, float 0x39e1c1a180000000>
}

; CHECK-LABEL: splat_v4f32:
; NO-SIMD128-NOT: f32x4
; SIMD128: .param f32{{$}}
Expand Down Expand Up @@ -251,6 +312,17 @@ define <4 x float> @replace_v4f32(<4 x float> %v, float %x) {
; ==============================================================================
; 2 x f64
; ==============================================================================
; CHECK-LABEL: const_v2f64:
; NO-SIMD128-NOT: f64x2
; SIMD128: .result v128{{$}}
; SIMD128: v128.const $push0=, 0x1.60504030201p-911, 0x1.e0d0c0b0a0908p-783
; SIMD128-SAME: # encoding: [0xfd,0x00,
; SIMD128-SAME: 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
; SIMD128-SAME: 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f]{{$}}
define <2 x double> @const_v2f64() {
ret <2 x double> <double 0x0706050403020100, double 0x0F0E0D0C0B0A0908>
}

; CHECK-LABEL: splat_v2f64:
; NO-SIMD128-NOT: f64x2
; SIMD128-VM-NOT: f64x2
Expand Down
4 changes: 4 additions & 0 deletions llvm/test/MC/Disassembler/WebAssembly/wasm.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,7 @@
# Prefix byte example:
# CHECK: i64.trunc_u:sat/f64
0xFC 0x07

# v128.const is arbitrarily disassembled as v2f64
# CHECK: v128.const 0x1.60504030201p-911, 0x1.e0d0c0b0a0908p-783
0xFD 0x00 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F

0 comments on commit 2244292

Please sign in to comment.