Vector bitcast support (AArch64 & Interpreter) (#4820)

* Vector bitcast support (AArch64 & Interpreter)

Implemented support for `bitcast` on vector values for AArch64 and the
interpreter.

Also corrected the verifier to ensure that the size, in bits, of the input and
output types match for a `bitcast`, per the docs.

Copyright (c) 2022 Arm Limited

* `I128` same-type bitcast support

Copyright (c) 2022 Arm Limited

* Directly return input for 64-bit GPR<=>GPR bitcast

Copyright (c) 2022 Arm Limited
This commit is contained in:
Damian Heaton
2022-09-21 17:20:28 +01:00
committed by GitHub
parent 05cbd667c7
commit e786bda002
15 changed files with 478 additions and 26 deletions

View File

@@ -3280,6 +3280,9 @@ pub(crate) fn define(
The input and output types must be storable to memory and of the same The input and output types must be storable to memory and of the same
size. A bitcast is equivalent to storing one type and loading the other size. A bitcast is equivalent to storing one type and loading the other
type from the same address. type from the same address.
For vector types, the lane types must also be the same size (see
`raw_bitcast` for changing the lane size).
"#, "#,
&formats.unary, &formats.unary,
) )

View File

@@ -1738,6 +1738,13 @@
(decl writable_zero_reg () WritableReg) (decl writable_zero_reg () WritableReg)
(extern constructor writable_zero_reg writable_zero_reg) (extern constructor writable_zero_reg writable_zero_reg)
;; Helper for emitting `MInst.Mov` instructions.
(decl mov (Reg Type) Reg)
(rule (mov src ty)
(let ((dst WritableReg (temp_writable_reg $I64))
(_ Unit (emit (MInst.Mov (operand_size ty) dst src))))
dst))
;; Helper for emitting `MInst.MovZ` instructions. ;; Helper for emitting `MInst.MovZ` instructions.
(decl movz (MoveWideConst OperandSize) Reg) (decl movz (MoveWideConst OperandSize) Reg)
(rule (movz imm size) (rule (movz imm size)
@@ -2093,6 +2100,17 @@
(_ Unit (emit (MInst.FpuRound op dst rn)))) (_ Unit (emit (MInst.FpuRound op dst rn))))
dst)) dst))
;; Helper for emitting `MInst.FpuMove64` and `MInst.FpuMove128` instructions.
(decl fpu_move (Type Reg) Reg)
(rule (fpu_move _ src)
(let ((dst WritableReg (temp_writable_reg $I8X16))
(_ Unit (emit (MInst.FpuMove128 dst src))))
dst))
(rule (fpu_move (fits_in_64 _) src)
(let ((dst WritableReg (temp_writable_reg $F64))
(_ Unit (emit (MInst.FpuMove64 dst src))))
dst))
;; Helper for emitting `MInst.MovToFpu` instructions. ;; Helper for emitting `MInst.MovToFpu` instructions.
(decl mov_to_fpu (Reg ScalarSize) Reg) (decl mov_to_fpu (Reg ScalarSize) Reg)
(rule (mov_to_fpu x size) (rule (mov_to_fpu x size)

View File

@@ -2209,17 +2209,26 @@
;;; Rules for `bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Rules for `bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(rule (lower (has_type $I32 (bitcast src @ (value_type $F32)))) ; SIMD&FP <=> SIMD&FP
(mov_from_vec src 0 (ScalarSize.Size32))) (rule (lower (has_type (ty_float_or_vec out_ty) (bitcast x @ (value_type (ty_float_or_vec _)))))
(fpu_move out_ty x))
(rule (lower (has_type $F32 (bitcast src @ (value_type $I32)))) ; GPR => SIMD&FP
(mov_to_fpu src (ScalarSize.Size32))) (rule (lower (has_type (ty_float_or_vec _) (bitcast x @ (value_type in_ty))))
(if (ty_int_bool_ref_scalar_64 in_ty))
(mov_to_fpu x (scalar_size in_ty)))
(rule (lower (has_type $I64 (bitcast src @ (value_type $F64)))) ; SIMD&FP => GPR
(mov_from_vec src 0 (ScalarSize.Size64))) (rule (lower (has_type out_ty (bitcast x @ (value_type (fits_in_64 (ty_float_or_vec _))))))
(if (ty_int_bool_ref_scalar_64 out_ty))
(mov_from_vec x 0 (scalar_size out_ty)))
(rule (lower (has_type $F64 (bitcast src @ (value_type $I64)))) ; GPR <=> GPR
(mov_to_fpu src (ScalarSize.Size64))) (rule (lower (has_type out_ty (bitcast x @ (value_type in_ty))))
(if (ty_int_bool_ref_scalar_64 out_ty))
(if (ty_int_bool_ref_scalar_64 in_ty))
x)
(rule (lower (has_type $I128 (bitcast x @ (value_type $I128)))) x)
;;; Rules for `raw_bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Rules for `raw_bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@@ -268,12 +268,7 @@ pub(crate) fn lower_insn_to_regs(
Opcode::IsNull | Opcode::IsInvalid => implemented_in_isle(ctx), Opcode::IsNull | Opcode::IsInvalid => implemented_in_isle(ctx),
Opcode::Copy => { Opcode::Copy => implemented_in_isle(ctx),
let rd = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let rn = put_input_in_reg(ctx, inputs[0], NarrowValueMode::None);
let ty = ctx.input_ty(insn, 0);
ctx.emit(Inst::gen_move(rd, rn, ty));
}
Opcode::Breduce | Opcode::Ireduce => implemented_in_isle(ctx), Opcode::Breduce | Opcode::Ireduce => implemented_in_isle(ctx),

View File

@@ -1096,15 +1096,26 @@ impl<'a> Verifier<'a> {
let typ = self.func.dfg.ctrl_typevar(inst); let typ = self.func.dfg.ctrl_typevar(inst);
let value_type = self.func.dfg.value_type(arg); let value_type = self.func.dfg.value_type(arg);
if typ.lane_bits() < value_type.lane_bits() { if typ.lane_bits() != value_type.lane_bits() {
errors.fatal(( errors.fatal((
inst, inst,
format!( format!(
"The bitcast argument {} doesn't fit in a type of {} bits", "The bitcast argument {} has a lane type of {} bits, which doesn't match an expected type of {} bits",
arg, arg,
value_type.lane_bits(),
typ.lane_bits() typ.lane_bits()
), ),
)) ))
} else if typ.bits() != value_type.bits() {
errors.fatal((
inst,
format!(
"The bitcast argument {} has a type of {} bits, which doesn't match an expected type of {} bits",
arg,
value_type.bits(),
typ.bits()
),
))
} else { } else {
Ok(()) Ok(())
} }

View File

@@ -0,0 +1,26 @@
test run
target aarch64
; the interpreter, x86_64, and s390x do not support bitcasting to/from
; references
function %bitcast_ir64(i64) -> b1 {
block0(v0: i64):
v1 = bitcast.r64 v0
v2 = is_null v1
return v2
}
; run: %bitcast_ir64(0) == true
; run: %bitcast_ir64(18446744073709551615) == false
; run: %bitcast_ir64(-1) == false
; run: %bitcast_ir64(127) == false
function %bitcast_ri64(i64) -> i64 {
block0(v0: i64):
v1 = bitcast.r64 v0
v2 = bitcast.i64 v1
return v2
}
; run: %bitcast_ri64(0) == 0
; run: %bitcast_ri64(18446744073709551615) == 18446744073709551615
; run: %bitcast_ri64(-1) == -1
; run: %bitcast_ri64(127) == 127

View File

@@ -0,0 +1,69 @@
test interpret
test run
target aarch64
; x86_64 and s390x do not support bitcasting to the same type as the input.
function %bitcast_i8(i8) -> i8 {
block0(v0: i8):
v1 = bitcast.i8 v0
return v1
}
; run: %bitcast_i8(0) == 0
; run: %bitcast_i8(42) == 42
; run: %bitcast_i8(255) == 255
function %bitcast_i16(i16) -> i16 {
block0(v0: i16):
v1 = bitcast.i16 v0
return v1
}
; run: %bitcast_i16(0) == 0
; run: %bitcast_i16(42) == 42
; run: %bitcast_i16(65535) == 65535
function %bitcast_i32(i32) -> i32 {
block0(v0: i32):
v1 = bitcast.i32 v0
return v1
}
; run: %bitcast_i32(0) == 0
; run: %bitcast_i32(42) == 42
; run: %bitcast_i32(4294967295) == 4294967295
function %bitcast_i64(i64) -> i64 {
block0(v0: i64):
v1 = bitcast.i64 v0
return v1
}
; run: %bitcast_i64(0) == 0
; run: %bitcast_i64(42) == 42
; run: %bitcast_i64(18446744073709551615) == 18446744073709551615
function %bitcast_i128(i128) -> i128 {
block0(v0: i128):
v1 = bitcast.i128 v0
return v1
}
; run: %bitcast_i128(0) == 0
; run: %bitcast_i128(42) == 42
; run: %bitcast_i128(200000000000000000000) == 200000000000000000000
function %bitcast_f32(f32) -> f32 {
block0(v0: f32):
v1 = bitcast.f32 v0
return v1
}
; run: %bitcast_f32(0x0.0) == 0x0.0
; run: %bitcast_f32(0x1.0) == 0x1.0
; run: %bitcast_f32(-0x1.0) == -0x1.0
; run: %bitcast_f32(NaN) == NaN
function %bitcast_f64(f64) -> f64 {
block0(v0: f64):
v1 = bitcast.f64 v0
return v1
}
; run: %bitcast_f64(0x0.0) == 0x0.0
; run: %bitcast_f64(0x1.0) == 0x1.0
; run: %bitcast_f64(-0x1.0) == -0x1.0
; run: %bitcast_f64(NaN) == NaN

View File

@@ -0,0 +1,45 @@
test interpret
test run
target aarch64
target x86_64
target s390x
function %bitcast_if32(i32) -> f32 {
block0(v0: i32):
v1 = bitcast.f32 v0
return v1
}
; run: %bitcast_if32(0) == 0x0.0
; run: %bitcast_if32(4294967295) == -NaN:0x3fffff
; run: %bitcast_if32(-1) == -NaN:0x3fffff
; run: %bitcast_if32(127) == 0x0.0000fep-126
function %bitcast_fi32(f32) -> i32 {
block0(v0: f32):
v1 = bitcast.i32 v0
return v1
}
; run: %bitcast_fi32(0x0.0) == 0
; run: %bitcast_fi32(-NaN:0x3fffff) == 4294967295
; run: %bitcast_fi32(-NaN:0x3fffff) == -1
; run: %bitcast_fi32(0x0.0000fep-126) == 127
function %bitcast_if64(i64) -> f64 {
block0(v0: i64):
v1 = bitcast.f64 v0
return v1
}
; run: %bitcast_if64(0) == 0x0.0
; run: %bitcast_if64(18446744073709551615) == -NaN:0x7ffffffffffff
; run: %bitcast_if64(-1) == -NaN:0x7ffffffffffff
; run: %bitcast_if64(127) == 0x0.000000000007fp-1022
function %bitcast_fi64(f64) -> i64 {
block0(v0: f64):
v1 = bitcast.i64 v0
return v1
}
; run: %bitcast_fi64(0x0.0) == 0
; run: %bitcast_fi64(-NaN:0x7ffffffffffff) == 18446744073709551615
; run: %bitcast_fi64(-NaN:0x7ffffffffffff) == -1
; run: %bitcast_fi64(0x0.000000000007fp-1022) == 127

View File

@@ -0,0 +1,121 @@
test interpret
test run
target aarch64
target s390x
; x86_64 regards this as an unused opcode.
function %copy_i8(i8) -> i8 {
block0(v0: i8):
v1 = copy v0
return v1
}
; run: %copy_i8(0) == 0
; run: %copy_i8(255) == 255
; run: %copy_i8(-1) == -1
; run: %copy_i8(127) == 127
function %copy_i16(i16) -> i16 {
block0(v0: i16):
v1 = copy v0
return v1
}
; run: %copy_i16(0) == 0
; run: %copy_i16(65535) == 65535
; run: %copy_i16(-1) == -1
; run: %copy_i16(127) == 127
function %copy_i32(i32) -> i32 {
block0(v0: i32):
v1 = copy v0
return v1
}
; run: %copy_i32(0) == 0
; run: %copy_i32(4294967295) == 4294967295
; run: %copy_i32(-1) == -1
; run: %copy_i32(127) == 127
function %copy_i64(i64) -> i64 {
block0(v0: i64):
v1 = copy v0
return v1
}
; run: %copy_i64(0) == 0
; run: %copy_i64(18446744073709551615) == 18446744073709551615
; run: %copy_i64(-1) == -1
; run: %copy_i64(127) == 127
function %copy_b1(b1) -> b1 {
block0(v0: b1):
v1 = copy v0
return v1
}
; run: %copy_b1(false) == false
; run: %copy_b1(true) == true
function %copy_b8(b8) -> b8 {
block0(v0: b8):
v1 = copy v0
return v1
}
; run: %copy_b8(false) == false
; run: %copy_b8(true) == true
function %copy_b16(b16) -> b16 {
block0(v0: b16):
v1 = copy v0
return v1
}
; run: %copy_b16(false) == false
; run: %copy_b16(true) == true
function %copy_b32(b32) -> b32 {
block0(v0: b32):
v1 = copy v0
return v1
}
; run: %copy_b32(false) == false
; run: %copy_b32(true) == true
function %copy_b64(b64) -> b64 {
block0(v0: b64):
v1 = copy v0
return v1
}
; run: %copy_b64(false) == false
; run: %copy_b64(true) == true
function %copy_f32(f32) -> f32 {
block0(v0: f32):
v1 = copy v0
return v1
}
; run: %copy_f32(0x1.0) == 0x1.0
; run: %copy_f32(0x1.0p10) == 0x1.0p10
; run: %copy_f32(0x0.0) == 0x0.0
; run: %copy_f32(-0x0.0) == -0x0.0
; run: %copy_f32(+Inf) == +Inf
; run: %copy_f32(-Inf) == -Inf
; run: %copy_f32(0x1.000002p-23) == 0x1.000002p-23
; run: %copy_f32(0x1.fffffep127) == 0x1.fffffep127
; run: %copy_f32(0x1.000000p-126) == 0x1.000000p-126
; run: %copy_f32(0x0.800002p-126) == 0x0.800002p-126
; run: %copy_f32(-0x0.800000p-126) == -0x0.800000p-126
function %copy_f64(f64) -> f64 {
block0(v0: f64):
v1 = copy v0
return v1
}
; run: %copy_f64(0x2.0) == 0x2.0
; run: %copy_f64(0x1.0p11) == 0x1.0p11
; run: %copy_f64(0x0.0) == 0x0.0
; run: %copy_f64(-0x0.0) == -0x0.0
; run: %copy_f64(+Inf) == +Inf
; run: %copy_f64(-Inf) == -Inf
; run: %copy_f64(0x1.0000000000002p-52) == 0x1.0000000000002p-52
; run: %copy_f64(0x1.fffffffffffffp1023) == 0x1.fffffffffffffp1023
; run: %copy_f64(0x1.0000000000000p-1022) == 0x1.0000000000000p-1022
; run: %copy_f64(0x0.8000000000002p-1022) == 0x0.8000000000002p-1022
; run: %copy_f64(-0x0.8000000000000p-1022) == -0x0.8000000000000p-1022

View File

@@ -0,0 +1,50 @@
test interpret
test run
target aarch64
; x86_64 and s390x do not support vector bitcasts.
function %bitcast_if32x2(i32x2) -> f32x2 {
block0(v0: i32x2):
v1 = bitcast.f32x2 v0
return v1
}
; run: %bitcast_if32x2([0 4294967295]) == [0x0.0 -NaN:0x3fffff]
; run: %bitcast_if32x2([-1 127]) == [-NaN:0x3fffff 0x0.0000fep-126]
function %bitcast_fi32x2(f32x2) -> i32x2 {
block0(v0: f32x2):
v1 = bitcast.i32x2 v0
return v1
}
; run: %bitcast_fi32x2([0x0.0 -NaN:0x3fffff]) == [0 4294967295]
; run: %bitcast_fi32x2([-NaN:0x3fffff 0x0.0000fep-126]) == [-1 127]
function %bitcast_if32x4(i32x4) -> f32x4 {
block0(v0: i32x4):
v1 = bitcast.f32x4 v0
return v1
}
; run: %bitcast_if32x4([0 4294967295 -1 127]) == [0x0.0 -NaN:0x3fffff -NaN:0x3fffff 0x0.0000fep-126]
function %bitcast_fi32x4(f32x4) -> i32x4 {
block0(v0: f32x4):
v1 = bitcast.i32x4 v0
return v1
}
; run: %bitcast_fi32x4([0x0.0 -NaN:0x3fffff -NaN:0x3fffff 0x0.0000fep-126]) == [0 4294967295 -1 127]
function %bitcast_if64x2(i64x2) -> f64x2 {
block0(v0: i64x2):
v1 = bitcast.f64x2 v0
return v1
}
; run: %bitcast_if64x2([0 18446744073709551615]) == [0x0.0 -NaN:0x7ffffffffffff]
; run: %bitcast_if64x2([-1 127]) == [-NaN:0x7ffffffffffff 0x0.000000000007fp-1022]
function %bitcast_fi64x2(f64x2) -> i64x2 {
block0(v0: f64x2):
v1 = bitcast.i64x2 v0
return v1
}
; run: %bitcast_fi64x2([0x0.0 -NaN:0x7ffffffffffff]) == [0 18446744073709551615]
; run: %bitcast_fi64x2([-NaN:0x7ffffffffffff 0x0.000000000007fp-1022]) == [-1 127]

View File

@@ -0,0 +1,40 @@
test interpret
test run
target aarch64
; x86_64 regards this as an unused opcode.
; s390x does not support 64-bit vectors.
function %copy_i8x8(i8x8) -> i8x8 {
block0(v0: i8x8):
v1 = copy v0
return v1
}
; run: %copy_i8x8([0 0 255 255 -1 -1 127 128]) == [0 0 255 255 -1 -1 127 128]
function %copy_i16x4(i16x4) -> i16x4 {
block0(v0: i16x4):
v1 = copy v0
return v1
}
; run: %copy_i16x4([0 65535 -1 127]) == [0 65535 -1 127]
function %copy_i32x2(i32x2) -> i32x2 {
block0(v0: i32x2):
v1 = copy v0
return v1
}
; run: %copy_i32x2([0 4294967295]) == [0 4294967295]
; run: %copy_i32x2([-1 127]) == [-1 127]
function %copy_f32x2(f32x2) -> f32x2 {
block0(v0: f32x2):
v1 = copy v0
return v1
}
; run: %copy_f32x2([0x1.0 0x1.0p10]) == [0x1.0 0x1.0p10]
; run: %copy_f32x2([0x0.0 -0x0.0]) == [0x0.0 -0x0.0]
; run: %copy_f32x2([+Inf -Inf]) == [+Inf -Inf]
; run: %copy_f32x2([0x1.000002p-23 0x1.fffffep127]) == [0x1.000002p-23 0x1.fffffep127]
; run: %copy_f32x2([0x1.000000p-126 0x0.800002p-126]) == [0x1.000000p-126 0x0.800002p-126]
; run: %copy_f32x2([-0x0.800000p-126 -0x0.800000p-126]) == [-0x0.800000p-126 -0x0.800000p-126]

View File

@@ -0,0 +1,57 @@
test interpret
test run
target aarch64
target s390x
; x86_64 regards this as an unused opcode.
function %copy_i8x16(i8x16) -> i8x16 {
block0(v0: i8x16):
v1 = copy v0
return v1
}
; run: %copy_i8x16([0 0 255 255 -1 -1 127 128 0 0 255 255 -1 -1 127 128]) == [0 0 255 255 -1 -1 127 128 0 0 255 255 -1 -1 127 128]
function %copy_i16x8(i16x8) -> i16x8 {
block0(v0: i16x8):
v1 = copy v0
return v1
}
; run: %copy_i16x8([0 65535 -1 127 0 65535 -1 128]) == [0 65535 -1 127 0 65535 -1 128]
function %copy_i32x4(i32x4) -> i32x4 {
block0(v0: i32x4):
v1 = copy v0
return v1
}
; run: %copy_i32x4([0 4294967295 -1 127]) == [0 4294967295 -1 127]
function %copy_i64x2(i64x2) -> i64x2 {
block0(v0: i64x2):
v1 = copy v0
return v1
}
; run: %copy_i64x2([0 18446744073709551615]) == [0 18446744073709551615]
; run: %copy_i64x2([-1 127]) == [-1 127]
function %copy_f32x4(f32x4) -> f32x4 {
block0(v0: f32x4):
v1 = copy v0
return v1
}
; run: %copy_f32x4([0x1.0 0x1.0p10 0x0.0 -0x0.0]) == [0x1.0 0x1.0p10 0x0.0 -0x0.0]
; run: %copy_f32x4([+Inf -Inf 0x1.000002p-23 0x1.fffffep127]) == [+Inf -Inf 0x1.000002p-23 0x1.fffffep127]
; run: %copy_f32x4([0x1.000000p-126 0x0.800002p-126 -0x0.800000p-126 -0x0.800000p-126]) == [0x1.000000p-126 0x0.800002p-126 -0x0.800000p-126 -0x0.800000p-126]
function %copy_f64x2(f64x2) -> f64x2 {
block0(v0: f64x2):
v1 = copy v0
return v1
}
; run: %copy_f64x2([0x2.0 0x1.0p11]) == [0x2.0 0x1.0p11]
; run: %copy_f64x2([0x0.0 -0x0.0]) == [0x0.0 -0x0.0]
; run: %copy_f64x2([+Inf -Inf]) == [+Inf -Inf]
; run: %copy_f64x2([0x1.0000000000002p-52 0x1.fffffffffffffp1023]) == [0x1.0000000000002p-52 0x1.fffffffffffffp1023]
; run: %copy_f64x2([0x1.0000000000000p-1022 0x0.8000000000002p-1022]) == [0x1.0000000000000p-1022 0x0.8000000000002p-1022]
; run: %copy_f64x2([-0x0.8000000000000p-1022 -0x0.8000000000000p-1022]) == [-0x0.8000000000000p-1022 -0x0.8000000000000p-1022]

View File

@@ -1,23 +1,23 @@
test verifier test verifier
; bitcast between two types of equal size if ok ; bitcast between two types of equal size is ok
function %valid_bitcast1(i32) -> f32 { ; Ok function %valid_bitcast1(i32) -> f32 { ; Ok
block0(v0: i32): block0(v0: i32):
v1 = bitcast.f32 v0 v1 = bitcast.f32 v0
return v1 return v1
} }
; bitcast to a type larger than the operand is ok ; bitcast to a type larger than the operand is not ok
function %valid_bitcast2(i32) -> i64 { ; Ok function %valid_bitcast2(i32) -> i64 {
block0(v0: i32): block0(v0: i32):
v1 = bitcast.i64 v0 v1 = bitcast.i64 v0 ; error: The bitcast argument v0 has a lane type of 32 bits, which doesn't match an expected type of 64 bits
return v1 return v1
} }
; bitcast to a smaller type is not ok ; bitcast to a smaller type is not ok
function %bad_bitcast(i64) -> i32 { function %bad_bitcast(i64) -> i32 {
block0(v0: i64): block0(v0: i64):
v1 = bitcast.i32 v0 ; error: The bitcast argument v0 doesn't fit in a type of 32 bits v1 = bitcast.i32 v0 ; error: The bitcast argument v0 has a lane type of 64 bits, which doesn't match an expected type of 32 bits
return v1 return v1
} }

View File

@@ -956,10 +956,18 @@ where
| Opcode::RawBitcast | Opcode::RawBitcast
| Opcode::ScalarToVector | Opcode::ScalarToVector
| Opcode::Breduce | Opcode::Breduce
| Opcode::Bextend => assign(Value::convert( | Opcode::Bextend => {
arg(0)?, let input_ty = inst_context.type_of(inst_context.args()[0]).unwrap();
ValueConversionKind::Exact(ctrl_ty), let arg0 = extractlanes(&arg(0)?, input_ty)?;
)?),
assign(vectorizelanes(
&arg0
.into_iter()
.map(|x| V::convert(x, ValueConversionKind::Exact(ctrl_ty.lane_type())))
.collect::<ValueResult<SimdVec<V>>>()?,
ctrl_ty,
)?)
}
Opcode::Ireduce => assign(Value::convert( Opcode::Ireduce => assign(Value::convert(
arg(0)?, arg(0)?,
ValueConversionKind::Truncate(ctrl_ty), ValueConversionKind::Truncate(ctrl_ty),

View File

@@ -326,7 +326,7 @@ impl Value for DataValue {
}; };
DataValue::int(val, t)? DataValue::int(val, t)?
} }
(dv, t) if t.is_int() && dv.ty() == t => dv, (dv, t) if (t.is_int() || t.is_float()) && dv.ty() == t => dv,
(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind), (dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
}, },
ValueConversionKind::Truncate(ty) => { ValueConversionKind::Truncate(ty) => {