Index: lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp =================================================================== --- lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp +++ lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp @@ -91,6 +91,18 @@ return true; } +template +bool parseImmediate(MCInst &MI, uint64_t &Size, ArrayRef Bytes) { + if (Size + sizeof(T) > Bytes.size()) + return false; + T Val; + memcpy(&Val, Bytes.data() + Size, sizeof(T)); + support::endian::byte_swap(Val); + Size += sizeof(T); + MI.addOperand(MCOperand::createImm(static_cast(Val))); + return true; +} + template bool parseFPImmediate(MCInst &MI, uint64_t &Size, ArrayRef Bytes) { if (Size + sizeof(T) > Bytes.size()) @@ -169,6 +181,27 @@ return MCDisassembler::Fail; break; } + // Vector lane operands (not LEB encoded). + case WebAssembly::OPERAND_VEC_I8IMM: { + if (!parseImmediate(MI, Size, Bytes)) + return MCDisassembler::Fail; + break; + } + case WebAssembly::OPERAND_VEC_I16IMM: { + if (!parseImmediate(MI, Size, Bytes)) + return MCDisassembler::Fail; + break; + } + case WebAssembly::OPERAND_VEC_I32IMM: { + if (!parseImmediate(MI, Size, Bytes)) + return MCDisassembler::Fail; + break; + } + case WebAssembly::OPERAND_VEC_I64IMM: { + if (!parseImmediate(MI, Size, Bytes)) + return MCDisassembler::Fail; + break; + } case MCOI::OPERAND_REGISTER: { // These are NOT actually in the instruction stream, but MC is going to // expect operands to be present for them! Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -90,18 +90,35 @@ const MCOperandInfo &Info = Desc.OpInfo[i]; LLVM_DEBUG(dbgs() << "Encoding immediate: type=" << int(Info.OperandType) << "\n"); - if (Info.OperandType == WebAssembly::OPERAND_I32IMM) { - encodeSLEB128(int32_t(MO.getImm()), OS); - } else if (Info.OperandType == WebAssembly::OPERAND_OFFSET32) { - encodeULEB128(uint32_t(MO.getImm()), OS); - } else if (Info.OperandType == 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) { - OS << uint8_t(MO.getImm()); - } else { - encodeULEB128(uint64_t(MO.getImm()), OS); + switch (Info.OperandType) { + case WebAssembly::OPERAND_I32IMM: + encodeSLEB128(int32_t(MO.getImm()), OS); + break; + case WebAssembly::OPERAND_OFFSET32: + encodeULEB128(uint32_t(MO.getImm()), OS); + break; + case WebAssembly::OPERAND_I64IMM: + encodeSLEB128(int64_t(MO.getImm()), OS); + break; + case WebAssembly::OPERAND_SIGNATURE: + OS << uint8_t(MO.getImm()); + break; + case WebAssembly::OPERAND_VEC_I8IMM: + support::endian::write(OS, MO.getImm(), support::little); + break; + case WebAssembly::OPERAND_VEC_I16IMM: + support::endian::write(OS, MO.getImm(), support::little); + break; + case WebAssembly::OPERAND_VEC_I32IMM: + support::endian::write(OS, MO.getImm(), support::little); + break; + case WebAssembly::OPERAND_VEC_I64IMM: + support::endian::write(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 { assert(Desc.TSFlags == (WebAssemblyII::VariableOpIsImmediate | Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -59,6 +59,14 @@ 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. Index: lib/Target/WebAssembly/WebAssemblyInstrInfo.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -118,6 +118,18 @@ let OperandType = "OPERAND_F64IMM" in def f64imm_op : Operand; +let OperandType = "OPERAND_VEC_I8IMM" in +def vec_i8imm_op : Operand; + +let OperandType = "OPERAND_VEC_I16IMM" in +def vec_i16imm_op : Operand; + +let OperandType = "OPERAND_VEC_I32IMM" in +def vec_i32imm_op : Operand; + +let OperandType = "OPERAND_VEC_I64IMM" in +def vec_i64imm_op : Operand; + let OperandType = "OPERAND_FUNCTION32" in def function32_op : Operand; Index: lib/Target/WebAssembly/WebAssemblyInstrSIMD.td =================================================================== --- lib/Target/WebAssembly/WebAssemblyInstrSIMD.td +++ lib/Target/WebAssembly/WebAssemblyInstrSIMD.td @@ -12,18 +12,71 @@ /// //===----------------------------------------------------------------------===// -// immediate argument types -def ImmByte : ImmLeaf; +// constrained immediate argument types +foreach SIZE = [8, 16] in +def ImmI#SIZE : ImmLeaf; foreach SIZE = [2, 4, 8, 16, 32] in def LaneIdx#SIZE : ImmLeaf; +// const vectors +multiclass ConstVec { + 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; +defm "" : ConstVec; +defm "" : ConstVec; +defm "" : ConstVec; +defm "" : ConstVec; +defm "" : ConstVec; + // lane extraction multiclass ExtractLane 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>; @@ -73,8 +126,8 @@ multiclass ReplaceLane 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", Index: test/CodeGen/WebAssembly/simd.ll =================================================================== --- test/CodeGen/WebAssembly/simd.ll +++ test/CodeGen/WebAssembly/simd.ll @@ -10,6 +10,19 @@ ; ============================================================================== ; 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> +} + ; CHECK-LABEL: splat_v16i8: ; NO-SIMD128-NOT: i8x16 ; SIMD128: .param i32{{$}} @@ -73,6 +86,18 @@ ; ============================================================================== ; 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> +} + ; CHECK-LABEL: splat_v8i16: ; NO-SIMD128-NOT: i16x8 ; SIMD128: .param i32{{$}} @@ -135,6 +160,17 @@ ; ============================================================================== ; 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> +} + ; CHECK-LABEL: splat_v4i32: ; NO-SIMD128-NOT: i32x4 ; SIMD128: .param i32{{$}} @@ -173,6 +209,18 @@ ; ============================================================================== ; 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> +} + ; CHECK-LABEL: splat_v2i64: ; NO-SIMD128-NOT: i64x2 ; SIMD128-VM-NOT: i64x2 @@ -213,6 +261,19 @@ ; ============================================================================== ; 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> +} + ; CHECK-LABEL: splat_v4f32: ; NO-SIMD128-NOT: f32x4 ; SIMD128: .param f32{{$}} @@ -251,6 +312,17 @@ ; ============================================================================== ; 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> +} + ; CHECK-LABEL: splat_v2f64: ; NO-SIMD128-NOT: f64x2 ; SIMD128-VM-NOT: f64x2