riscv64: Implement fcmp in ISLE (#5512)

Rework the compilation of fcmp in the riscv64 backend to be in ISLE, removing the need for the dedicated Fcmp instruction. This change is motivated by #5500, which showed that the riscv64 backend was generating branch instructions in the middle of a basic block.

We can't remove lower_br_fcmp quite yet as it's used in a few places in the emit module, but it's now no longer reachable from the ISLE lowerings.

Fixes #5500
This commit is contained in:
Trevor Elliott
2023-01-04 11:52:00 -08:00
committed by GitHub
parent d1920f5a2d
commit b2d5afdf83
7 changed files with 202 additions and 113 deletions

View File

@@ -107,6 +107,7 @@
(rs2 Reg)
(cc IntCC)
(trap_code TrapCode))
(TrapFf
(cc FloatCC)
(x Reg)
@@ -204,14 +205,6 @@
(x Reg)
(t0 WritableReg))
;; a float compare
(Fcmp
(cc FloatCC)
(rd WritableReg)
(rs1 Reg)
(rs2 Reg)
(ty Type))
;; select x or y base on condition
(Select
(dst VecWritableReg)
@@ -690,7 +683,6 @@
(Tso)
))
(type VecBranchTarget (primitive VecBranchTarget))
(type BoxCallInfo (primitive BoxCallInfo))
(type BoxCallIndInfo (primitive BoxCallIndInfo))
@@ -1880,9 +1872,6 @@
(decl lower_br_icmp (IntCC ValueRegs ValueRegs VecMachLabel Type) Unit)
(extern constructor lower_br_icmp lower_br_icmp)
(decl lower_br_fcmp (FloatCC Reg Reg VecMachLabel Type) Unit)
(extern constructor lower_br_fcmp lower_br_fcmp)
;; int scalar zero regs.
(decl int_zero_reg (Type) ValueRegs)
(extern constructor int_zero_reg int_zero_reg)
@@ -1935,7 +1924,9 @@
(rule 1
(lower_branch (brz (fcmp cc a @ (value_type ty) b) _ _) targets)
(lower_br_fcmp (floatcc_inverse cc) a b targets ty))
(let ((then BranchTarget (label_to_br_target (vec_label_get targets 0)))
(else BranchTarget (label_to_br_target (vec_label_get targets 1))))
(emit_side_effect (cond_br (emit_fcmp (floatcc_inverse cc) ty a b) then else))))
;;;;
(rule
@@ -1955,7 +1946,9 @@
(rule 1
(lower_branch (brnz (fcmp cc a @ (value_type ty) b) _ _) targets)
(lower_br_fcmp cc a b targets ty))
(let ((then BranchTarget (label_to_br_target (vec_label_get targets 0)))
(else BranchTarget (label_to_br_target (vec_label_get targets 1))))
(emit_side_effect (cond_br (emit_fcmp cc ty a b) then else))))
;;;
(decl lower_br_table (Reg VecMachLabel) Unit)
@@ -2194,3 +2187,159 @@
(decl sp_reg () PReg)
(extern constructor sp_reg sp_reg)
;;;; Helpers for floating point comparisons ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(decl not (Reg) Reg)
(rule (not x) (alu_rr_imm12 (AluOPRRI.Xori) x (imm_from_bits 1)))
(decl emit_or (Reg Reg) Reg)
(rule (emit_or x y) (alu_rrr (AluOPRRR.Or) x y))
(decl emit_and (Reg Reg) Reg)
(rule (emit_and x y) (alu_rrr (AluOPRRR.And) x y))
(decl is_not_nan (Type Reg) Reg)
(rule (is_not_nan ty a) (feq ty a a))
(decl feq (Type Reg Reg) Reg)
(rule (feq $F32 a b) (fpu_rrr (FpuOPRRR.FeqS) $I64 a b))
(rule (feq $F64 a b) (fpu_rrr (FpuOPRRR.FeqD) $I64 a b))
(decl flt (Type Reg Reg) Reg)
(rule (flt $F32 a b) (fpu_rrr (FpuOPRRR.FltS) $I64 a b))
(rule (flt $F64 a b) (fpu_rrr (FpuOPRRR.FltD) $I64 a b))
(decl fle (Type Reg Reg) Reg)
(rule (fle $F32 a b) (fpu_rrr (FpuOPRRR.FleS) $I64 a b))
(rule (fle $F64 a b) (fpu_rrr (FpuOPRRR.FleD) $I64 a b))
(decl fgt (Type Reg Reg) Reg)
(rule (fgt ty a b) (flt ty b a))
(decl fge (Type Reg Reg) Reg)
(rule (fge ty a b) (fle ty b a))
(decl ordered (Type Reg Reg) Reg)
(rule (ordered ty a b) (emit_and (is_not_nan ty a) (is_not_nan ty b)))
(type CmpResult (enum
(Result
(result Reg)
(invert bool))))
;; Wrapper for the common case when constructing comparison results. It assumes
;; that the result isn't negated.
(decl cmp_result (Reg) CmpResult)
(rule (cmp_result result) (CmpResult.Result result $false))
;; Wrapper for the case where it's more convenient to construct the negated
;; version of the comparison.
(decl cmp_result_invert (Reg) CmpResult)
(rule (cmp_result_invert result) (CmpResult.Result result $true))
;; Consume a CmpResult, producing a branch on its result.
(decl cond_br (CmpResult BranchTarget BranchTarget) SideEffectNoResult)
(rule (cond_br cmp then else)
(SideEffectNoResult.Inst
(MInst.CondBr then else (cmp_integer_compare cmp))))
;; Construct an IntegerCompare value.
(decl int_compare (IntCC Reg Reg) IntegerCompare)
(extern constructor int_compare int_compare)
;; Convert a comparison into a branch test.
(decl cmp_integer_compare (CmpResult) IntegerCompare)
(rule
(cmp_integer_compare (CmpResult.Result res $false))
(int_compare (IntCC.NotEqual) res (zero_reg)))
(rule
(cmp_integer_compare (CmpResult.Result res $true))
(int_compare (IntCC.Equal) res (zero_reg)))
;; Convert a comparison into a boolean value.
(decl cmp_value (CmpResult) Reg)
(rule (cmp_value (CmpResult.Result res $false)) res)
(rule (cmp_value (CmpResult.Result res $true)) (not res))
;; Compare two floating point numbers and return a zero/non-zero result.
(decl emit_fcmp (FloatCC Type Reg Reg) CmpResult)
;; a is not nan && b is not nan
(rule
(emit_fcmp (FloatCC.Ordered) ty a b)
(cmp_result (ordered ty a b)))
;; a is nan || b is nan
;; == !(a is not nan && b is not nan)
(rule
(emit_fcmp (FloatCC.Unordered) ty a b)
(cmp_result_invert (ordered ty a b)))
;; a == b
(rule
(emit_fcmp (FloatCC.Equal) ty a b)
(cmp_result (feq ty a b)))
;; a != b
;; == !(a == b)
(rule
(emit_fcmp (FloatCC.NotEqual) ty a b)
(cmp_result_invert (feq ty a b)))
;; a < b || a > b
(rule
(emit_fcmp (FloatCC.OrderedNotEqual) ty a b)
(cmp_result (emit_or (flt ty a b) (fgt ty a b))))
;; !(ordered a b) || a == b
(rule
(emit_fcmp (FloatCC.UnorderedOrEqual) ty a b)
(cmp_result (emit_or (not (ordered ty a b)) (feq ty a b))))
;; a < b
(rule
(emit_fcmp (FloatCC.LessThan) ty a b)
(cmp_result (flt ty a b)))
;; a <= b
(rule
(emit_fcmp (FloatCC.LessThanOrEqual) ty a b)
(cmp_result (fle ty a b)))
;; a > b
(rule
(emit_fcmp (FloatCC.GreaterThan) ty a b)
(cmp_result (fgt ty a b)))
;; a >= b
(rule
(emit_fcmp (FloatCC.GreaterThanOrEqual) ty a b)
(cmp_result (fge ty a b)))
;; !(ordered a b) || a < b
;; == !(ordered a b && a >= b)
(rule
(emit_fcmp (FloatCC.UnorderedOrLessThan) ty a b)
(cmp_result_invert (emit_and (ordered ty a b) (fge ty a b))))
;; !(ordered a b) || a <= b
;; == !(ordered a b && a > b)
(rule
(emit_fcmp (FloatCC.UnorderedOrLessThanOrEqual) ty a b)
(cmp_result_invert (emit_and (ordered ty a b) (fgt ty a b))))
;; !(ordered a b) || a > b
;; == !(ordered a b && a <= b)
(rule
(emit_fcmp (FloatCC.UnorderedOrGreaterThan) ty a b)
(cmp_result_invert (emit_and (ordered ty a b) (fle ty a b))))
;; !(ordered a b) || a >= b
;; == !(ordered a b && a < b)
(rule
(emit_fcmp (FloatCC.UnorderedOrGreaterThanOrEqual) ty a b)
(cmp_result_invert (emit_and (ordered ty a b) (flt ty a b))))