diff --git a/cranelift/codegen/src/isa/aarch64/inst.isle b/cranelift/codegen/src/isa/aarch64/inst.isle index 68dd824634..a24620ee40 100644 --- a/cranelift/codegen/src/isa/aarch64/inst.isle +++ b/cranelift/codegen/src/isa/aarch64/inst.isle @@ -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) diff --git a/cranelift/codegen/src/isa/aarch64/lower.isle b/cranelift/codegen/src/isa/aarch64/lower.isle index 464cf6f7aa..2900c67b99 100644 --- a/cranelift/codegen/src/isa/aarch64/lower.isle +++ b/cranelift/codegen/src/isa/aarch64/lower.isle @@ -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))) diff --git a/cranelift/codegen/src/isa/riscv64/inst.isle b/cranelift/codegen/src/isa/riscv64/inst.isle index 69ae36a904..7720facf54 100644 --- a/cranelift/codegen/src/isa/riscv64/inst.isle +++ b/cranelift/codegen/src/isa/riscv64/inst.isle @@ -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) diff --git a/cranelift/codegen/src/isa/riscv64/lower.isle b/cranelift/codegen/src/isa/riscv64/lower.isle index a24f05fc13..62f3b03acc 100644 --- a/cranelift/codegen/src/isa/riscv64/lower.isle +++ b/cranelift/codegen/src/isa/riscv64/lower.isle @@ -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` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/cranelift/codegen/src/isa/x64/inst.isle b/cranelift/codegen/src/isa/x64/inst.isle index da70f52409..e9b0b4ea45 100644 --- a/cranelift/codegen/src/isa/x64/inst.isle +++ b/cranelift/codegen/src/isa/x64/inst.isle @@ -2917,6 +2917,14 @@ (size OperandSize (operand_size_of_type_32_64 ty)) (_ 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) diff --git a/cranelift/codegen/src/isa/x64/lower.isle b/cranelift/codegen/src/isa/x64/lower.isle index 0c2267225e..5ff32deb1e 100644 --- a/cranelift/codegen/src/isa/x64/lower.isle +++ b/cranelift/codegen/src/isa/x64/lower.isle @@ -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))) diff --git a/cranelift/filetests/filetests/runtests/i128-ineg.clif b/cranelift/filetests/filetests/runtests/i128-ineg.clif new file mode 100644 index 0000000000..4e50093c1c --- /dev/null +++ b/cranelift/filetests/filetests/runtests/i128-ineg.clif @@ -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 diff --git a/cranelift/filetests/filetests/runtests/ineg.clif b/cranelift/filetests/filetests/runtests/ineg.clif new file mode 100644 index 0000000000..00f1574d14 --- /dev/null +++ b/cranelift/filetests/filetests/runtests/ineg.clif @@ -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 diff --git a/cranelift/fuzzgen/src/function_generator.rs b/cranelift/fuzzgen/src/function_generator.rs index 88e0f62efc..825b73c02c 100644 --- a/cranelift/fuzzgen/src/function_generator.rs +++ b/cranelift/fuzzgen/src/function_generator.rs @@ -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: