cranelift: Implement ineg.i128 for everyone (#5129)
* cranelift: Add `ineg` runtests * aarch64: Implement `ineg.i128` * x64: Implement `ineg.i128` * riscv: Implement `ineg.i128` * fuzzgen: Enable `ineg.i128`
This commit is contained in:
@@ -1731,6 +1731,13 @@
|
||||
(decl writable_zero_reg () WritableReg)
|
||||
(extern constructor writable_zero_reg writable_zero_reg)
|
||||
|
||||
(decl value_regs_zero () ValueRegs)
|
||||
(rule (value_regs_zero)
|
||||
(value_regs
|
||||
(imm $I64 (ImmExtend.Zero) 0)
|
||||
(imm $I64 (ImmExtend.Zero) 0)))
|
||||
|
||||
|
||||
;; Helper for emitting `MInst.Mov` instructions.
|
||||
(decl mov (Reg Type) Reg)
|
||||
(rule (mov src ty)
|
||||
@@ -2286,6 +2293,24 @@
|
||||
(decl sub_vec (Reg Reg VectorSize) Reg)
|
||||
(rule (sub_vec x y size) (vec_rrr (VecALUOp.Sub) x y size))
|
||||
|
||||
(decl sub_i128 (ValueRegs ValueRegs) ValueRegs)
|
||||
(rule (sub_i128 x y)
|
||||
(let
|
||||
;; Get the high/low registers for `x`.
|
||||
((x_regs ValueRegs x)
|
||||
(x_lo Reg (value_regs_get x_regs 0))
|
||||
(x_hi Reg (value_regs_get x_regs 1))
|
||||
|
||||
;; Get the high/low registers for `y`.
|
||||
(y_regs ValueRegs y)
|
||||
(y_lo Reg (value_regs_get y_regs 0))
|
||||
(y_hi Reg (value_regs_get y_regs 1)))
|
||||
;; the actual subtraction is `subs` followed by `sbc` which comprises
|
||||
;; the low/high bits of the result
|
||||
(with_flags
|
||||
(sub_with_flags_paired $I64 x_lo y_lo)
|
||||
(sbc_paired $I64 x_hi y_hi))))
|
||||
|
||||
;; Helpers for generating `madd` instructions.
|
||||
|
||||
(decl madd (Type Reg Reg Reg) Reg)
|
||||
|
||||
@@ -540,21 +540,7 @@
|
||||
|
||||
;; `i128`
|
||||
(rule -1 (lower (has_type $I128 (isub x y)))
|
||||
(let
|
||||
;; Get the high/low registers for `x`.
|
||||
((x_regs ValueRegs x)
|
||||
(x_lo Reg (value_regs_get x_regs 0))
|
||||
(x_hi Reg (value_regs_get x_regs 1))
|
||||
|
||||
;; Get the high/low registers for `y`.
|
||||
(y_regs ValueRegs y)
|
||||
(y_lo Reg (value_regs_get y_regs 0))
|
||||
(y_hi Reg (value_regs_get y_regs 1)))
|
||||
;; the actual subtraction is `subs` followed by `sbc` which comprises
|
||||
;; the low/high bits of the result
|
||||
(with_flags
|
||||
(sub_with_flags_paired $I64 x_lo y_lo)
|
||||
(sbc_paired $I64 x_hi y_hi))))
|
||||
(sub_i128 x y))
|
||||
|
||||
;;;; Rules for `uadd_sat` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
@@ -582,6 +568,10 @@
|
||||
(rule 1 (lower (has_type (fits_in_64 ty) (ineg x)))
|
||||
(sub ty (zero_reg) x))
|
||||
|
||||
;; `i128`
|
||||
(rule 2 (lower (has_type $I128 (ineg x)))
|
||||
(sub_i128 (value_regs_zero) x))
|
||||
|
||||
;; vectors.
|
||||
(rule (lower (has_type (ty_vec128 ty) (ineg x)))
|
||||
(neg x (vector_size ty)))
|
||||
|
||||
@@ -703,6 +703,10 @@
|
||||
(decl zero_reg () Reg)
|
||||
(extern constructor zero_reg zero_reg)
|
||||
|
||||
(decl value_regs_zero () ValueRegs)
|
||||
(rule (value_regs_zero)
|
||||
(value_regs (imm $I64 0) (imm $I64 0)))
|
||||
|
||||
(decl gen_float_round (FloatRoundOP Reg Type) Reg)
|
||||
(rule
|
||||
(gen_float_round op rs ty)
|
||||
|
||||
@@ -71,9 +71,11 @@
|
||||
;;;; Rules for `ineg` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; `i64` and smaller.
|
||||
(rule (lower (has_type (fits_in_64 ty) (ineg x)))
|
||||
(rule 1 (lower (has_type (fits_in_64 ty) (ineg x)))
|
||||
(alu_rrr (AluOPRRR.Sub) (zero_reg) x))
|
||||
|
||||
(rule 2 (lower (has_type $I128 (ineg x)))
|
||||
(i128_sub (value_regs_zero) x))
|
||||
|
||||
;;;; Rules for `imul` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
@@ -2918,6 +2918,14 @@
|
||||
(_ Unit (emit (MInst.Neg size src dst))))
|
||||
dst))
|
||||
|
||||
;; Helper for creating `neg` instructions whose flags are also used.
|
||||
(decl x64_neg_paired (Type Gpr) ProducesFlags)
|
||||
(rule (x64_neg_paired ty src)
|
||||
(let ((dst WritableGpr (temp_writable_gpr))
|
||||
(size OperandSize (operand_size_of_type_32_64 ty))
|
||||
(inst MInst (MInst.Neg size src dst)))
|
||||
(ProducesFlags.ProducesFlagsReturnsResultWithConsumer inst dst)))
|
||||
|
||||
(decl x64_lea (SyntheticAmode) Gpr)
|
||||
(rule (x64_lea addr)
|
||||
(let ((dst WritableGpr (temp_writable_gpr))
|
||||
|
||||
@@ -777,6 +777,15 @@
|
||||
(rule -1 (lower (has_type (fits_in_64 ty) (ineg x)))
|
||||
(x64_neg ty x))
|
||||
|
||||
(rule -2 (lower (has_type $I128 (ineg x)))
|
||||
;; Get the high/low registers for `x`.
|
||||
(let ((regs ValueRegs x)
|
||||
(lo Gpr (value_regs_get_gpr regs 0))
|
||||
(hi Gpr (value_regs_get_gpr regs 1)))
|
||||
;; Do a neg followed by an sub-with-borrow.
|
||||
(with_flags (x64_neg_paired $I64 lo)
|
||||
(x64_sbb_paired $I64 (imm $I64 0) hi))))
|
||||
|
||||
;; SSE.
|
||||
|
||||
(rule (lower (has_type $I8X16 (ineg x)))
|
||||
|
||||
19
cranelift/filetests/filetests/runtests/i128-ineg.clif
Normal file
19
cranelift/filetests/filetests/runtests/i128-ineg.clif
Normal file
@@ -0,0 +1,19 @@
|
||||
test interpret
|
||||
test run
|
||||
set enable_llvm_abi_extensions=true
|
||||
target aarch64
|
||||
target s390x
|
||||
target x86_64
|
||||
target riscv64
|
||||
|
||||
function %ineg_i128(i128) -> i128 {
|
||||
block0(v0: i128):
|
||||
v1 = ineg.i128 v0
|
||||
return v1
|
||||
}
|
||||
; run: %ineg_i128(0) == 0
|
||||
; run: %ineg_i128(1) == -1
|
||||
; run: %ineg_i128(-1) == 1
|
||||
; run: %ineg_i128(2) == -2
|
||||
; run: %ineg_i128(0x80000000_00000000_00000000_00000000) == 0x80000000_00000000_00000000_00000000
|
||||
; run: %ineg_i128(0x7fffffff_ffffffff_ffffffff_ffffffff) == 0x80000000_00000000_00000000_00000001
|
||||
54
cranelift/filetests/filetests/runtests/ineg.clif
Normal file
54
cranelift/filetests/filetests/runtests/ineg.clif
Normal file
@@ -0,0 +1,54 @@
|
||||
test interpret
|
||||
test run
|
||||
target aarch64
|
||||
target s390x
|
||||
target x86_64
|
||||
target riscv64
|
||||
|
||||
function %ineg_i8(i8) -> i8 {
|
||||
block0(v0: i8):
|
||||
v1 = ineg.i8 v0
|
||||
return v1
|
||||
}
|
||||
; run: %ineg_i8(0) == 0
|
||||
; run: %ineg_i8(1) == -1
|
||||
; run: %ineg_i8(-1) == 1
|
||||
; run: %ineg_i8(2) == -2
|
||||
; run: %ineg_i8(0x80) == 0x80
|
||||
; run: %ineg_i8(0x7f) == 0x81
|
||||
|
||||
function %ineg_i16(i16) -> i16 {
|
||||
block0(v0: i16):
|
||||
v1 = ineg.i16 v0
|
||||
return v1
|
||||
}
|
||||
; run: %ineg_i16(0) == 0
|
||||
; run: %ineg_i16(1) == -1
|
||||
; run: %ineg_i16(-1) == 1
|
||||
; run: %ineg_i16(2) == -2
|
||||
; run: %ineg_i16(0x8000) == 0x8000
|
||||
; run: %ineg_i16(0x7fff) == 0x8001
|
||||
|
||||
function %ineg_i32(i32) -> i32 {
|
||||
block0(v0: i32):
|
||||
v1 = ineg.i32 v0
|
||||
return v1
|
||||
}
|
||||
; run: %ineg_i32(0) == 0
|
||||
; run: %ineg_i32(1) == -1
|
||||
; run: %ineg_i32(-1) == 1
|
||||
; run: %ineg_i32(2) == -2
|
||||
; run: %ineg_i32(0x80000000) == 0x80000000
|
||||
; run: %ineg_i32(0x7fffffff) == 0x80000001
|
||||
|
||||
function %ineg_i64(i64) -> i64 {
|
||||
block0(v0: i64):
|
||||
v1 = ineg.i64 v0
|
||||
return v1
|
||||
}
|
||||
; run: %ineg_i64(0) == 0
|
||||
; run: %ineg_i64(1) == -1
|
||||
; run: %ineg_i64(-1) == 1
|
||||
; run: %ineg_i64(2) == -2
|
||||
; run: %ineg_i64(0x80000000_00000000) == 0x80000000_00000000
|
||||
; run: %ineg_i64(0x7fffffff_ffffffff) == 0x80000000_00000001
|
||||
@@ -282,10 +282,6 @@ const OPCODE_SIGNATURES: &'static [(
|
||||
(Opcode::Ineg, &[I16, I16], &[I16], insert_opcode),
|
||||
(Opcode::Ineg, &[I32, I32], &[I32], insert_opcode),
|
||||
(Opcode::Ineg, &[I64, I64], &[I64], insert_opcode),
|
||||
// ineg.i128 not implemented in some backends:
|
||||
// x64: https://github.com/bytecodealliance/wasmtime/issues/5105
|
||||
// aarch64: https://github.com/bytecodealliance/wasmtime/issues/5108
|
||||
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
|
||||
(Opcode::Ineg, &[I128, I128], &[I128], insert_opcode),
|
||||
// Imin
|
||||
// imin not implemented in some backends:
|
||||
|
||||
Reference in New Issue
Block a user