X64: port the rest of icmp to ISLE (#4254)

Finish migrating icmp to ISLE for x64
This commit is contained in:
Trevor Elliott
2022-06-13 16:34:11 -07:00
committed by GitHub
parent 43d4f0b93b
commit 7e0bb465d0
5 changed files with 121 additions and 74 deletions

View File

@@ -1271,6 +1271,26 @@
(decl lo_gpr (Value) Gpr)
(rule (lo_gpr regs) (gpr_new (lo_reg regs)))
;;;; Helpers for Working With Integer Comparison Codes ;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; An extractor that fails if the two arguments are equal. The first argument is
;; returned when it does not match the second.
(decl pure intcc_neq (IntCC IntCC) IntCC)
(extern constructor intcc_neq intcc_neq)
;; This is a direct import of `IntCC::without_equal`.
;; Get the corresponding IntCC with the equal component removed.
;; For conditions without a zero component, this is a no-op.
(decl intcc_without_eq (IntCC) IntCC)
(extern constructor intcc_without_eq intcc_without_eq)
;; This is a direct import of `IntCC::unsigned`.
;; Get the corresponding IntCC with the signed component removed.
;; For conditions without a signed component, this is a no-op.
(decl intcc_unsigned (IntCC) IntCC)
(extern constructor intcc_unsigned intcc_unsigned)
;;;; Helpers for Getting Particular Physical Registers ;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; These should only be used for legalization purposes, when we can't otherwise

View File

@@ -1459,6 +1459,7 @@
;; unset).
(rule (lower (icmp (IntCC.Equal) a @ (value_type (ty_vec128 ty)) b))
(x64_pcmpeq ty a b))
;; To lower a not-equals comparison, we perform an equality comparison
;; (PCMPEQ*) and then invert the bits (PXOR with all 1s).
(rule (lower (icmp (IntCC.NotEqual) a @ (value_type (ty_vec128 ty)) b))
@@ -1553,6 +1554,30 @@
(cmp Reg (x64_or $I64 cmp_lo cmp_hi)))
(with_flags (x64_test (OperandSize.Size64) (RegMemImm.Imm 1) cmp) (x64_setcc (CC.NZ)))))
;; Result = (a_hi <> b_hi) ||
;; (a_hi == b_hi && a_lo <> b_lo)
(rule (lower (icmp cc a @ (value_type $I128) b))
(if (intcc_neq cc (IntCC.Equal)))
(if (intcc_neq cc (IntCC.NotEqual)))
(let ((a_lo Gpr (value_regs_get_gpr a 0))
(a_hi Gpr (value_regs_get_gpr a 1))
(b_lo Gpr (value_regs_get_gpr b 0))
(b_hi Gpr (value_regs_get_gpr b 1))
(cmp_hi ValueRegs (with_flags (x64_cmp (OperandSize.Size64) b_hi a_hi)
(consumes_flags_concat
(x64_setcc (intcc_without_eq cc))
(x64_setcc (CC.Z)))))
(cc_hi Reg (value_regs_get cmp_hi 0))
(eq_hi Reg (value_regs_get cmp_hi 1))
(cmp_lo Reg (with_flags_reg (x64_cmp (OperandSize.Size64) b_lo a_lo)
(x64_setcc (intcc_unsigned cc))))
(res_lo Reg (x64_and $I64 eq_hi cmp_lo))
(res Reg (x64_or $I64 cc_hi res_lo)))
(x64_and $I64 res (RegMemImm.Imm 1))))
;;;; Rules for `fcmp` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; CLIF's `fcmp` instruction always operates on XMM registers--both scalar and

View File

@@ -903,16 +903,7 @@ fn lower_insn_to_regs<C: LowerCtx<I = Inst>>(
| Opcode::FmaxPseudo => implemented_in_isle(ctx),
Opcode::Icmp => {
let condcode = ctx.data(insn).cond_code().unwrap();
let dst = get_output_reg(ctx, outputs[0]).only_reg().unwrap();
let ty = ctx.input_ty(insn, 0);
if ty == types::I128 && condcode != IntCC::Equal && condcode != IntCC::NotEqual {
let condcode = emit_cmp(ctx, insn, condcode);
let cc = CC::from_intcc(condcode);
ctx.emit(Inst::setcc(cc, dst));
} else {
implemented_in_isle(ctx);
}
implemented_in_isle(ctx);
}
Opcode::Fcmp => {

View File

@@ -511,6 +511,25 @@ where
}
}
#[inline]
fn intcc_neq(&mut self, x: &IntCC, y: &IntCC) -> Option<IntCC> {
if x != y {
Some(*x)
} else {
None
}
}
#[inline]
fn intcc_without_eq(&mut self, x: &IntCC) -> IntCC {
x.without_equal()
}
#[inline]
fn intcc_unsigned(&mut self, x: &IntCC) -> IntCC {
x.unsigned()
}
#[inline]
fn intcc_to_cc(&mut self, intcc: &IntCC) -> CC {
CC::from_intcc(*intcc)