Skip to content
This repository has been archived by the owner on May 7, 2024. It is now read-only.

Commit

Permalink
Implement unordered FP comparisons correctly
Browse files Browse the repository at this point in the history
This implementation is not ideal, but it should reslove
riscv-collab/riscv-gnu-toolchain#195

@kito-cheng can you do the usual?  Thanks.
  • Loading branch information
aswaterman committed Nov 9, 2016
1 parent ee4d771 commit 2540fd6
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 40 deletions.
83 changes: 43 additions & 40 deletions gcc/config/riscv/riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1990,31 +1990,6 @@ riscv_zero_if_equal (rtx cmp0, rtx cmp1)
cmp0, cmp1, 0, 0, OPTAB_DIRECT);
}

/* Return false if we can easily emit code for the FP comparison specified
by *CODE. If not, set *CODE to its inverse and return true. */

static bool
riscv_reversed_fp_cond (enum rtx_code *code)
{
switch (*code)
{
case EQ:
case LT:
case LE:
case GT:
case GE:
case LTGT:
case ORDERED:
/* We know how to emit code for these cases... */
return false;

default:
/* ...but we must invert these and rely on the others. */
*code = reverse_condition_maybe_unordered (*code);
return true;
}
}

/* Convert a comparison into something that can be used in a branch or
conditional move. On entry, *OP0 and *OP1 are the values being
compared and *CODE is the code used to compare them.
Expand Down Expand Up @@ -2075,49 +2050,77 @@ riscv_emit_compare (enum rtx_code *code, rtx *op0, rtx *op1)
{
/* For FP comparisons, set an integer register with the result of the
comparison, then branch on it. */
rtx tmp0, tmp1, final_op;
rtx tmp0, tmp1;
enum rtx_code fp_code = *code;
*code = riscv_reversed_fp_cond (&fp_code) ? EQ : NE;
*code = NE;
*op1 = const0_rtx;

switch (fp_code)
{
case UNORDERED:
*code = EQ;
/* Fall through. */

case ORDERED:
/* a == a && b == b */
tmp0 = gen_reg_rtx (SImode);
riscv_emit_binary (EQ, tmp0, cmp_op0, cmp_op0);
tmp1 = gen_reg_rtx (SImode);
riscv_emit_binary (EQ, tmp1, cmp_op1, cmp_op1);
final_op = gen_reg_rtx (SImode);
riscv_emit_binary (AND, final_op, tmp0, tmp1);
*op0 = gen_reg_rtx (SImode);
riscv_emit_binary (AND, *op0, tmp0, tmp1);
break;

case UNEQ:
*code = EQ;
/* Fall through. */

case LTGT:
/* a < b || a > b */
/* ordered(a, b) != (a == b) */
tmp0 = gen_reg_rtx (SImode);
riscv_emit_binary (LT, tmp0, cmp_op0, cmp_op1);
riscv_emit_binary (EQ, tmp0, cmp_op0, cmp_op0);
tmp1 = gen_reg_rtx (SImode);
riscv_emit_binary (GT, tmp1, cmp_op0, cmp_op1);
final_op = gen_reg_rtx (SImode);
riscv_emit_binary (IOR, final_op, tmp0, tmp1);
riscv_emit_binary (EQ, tmp1, cmp_op1, cmp_op1);
*op0 = gen_reg_rtx (SImode);
riscv_emit_binary (AND, *op0, tmp0, tmp1);
*op1 = gen_reg_rtx (SImode);
riscv_emit_binary (EQ, *op1, cmp_op0, cmp_op1);
break;

#define UNORDERED_COMPARISON(CODE, CMP) \
case CODE: \
*code = EQ; \
*op0 = gen_reg_rtx (SImode); \
if (GET_MODE (cmp_op0) == SFmode) \
emit_insn (gen_f##CMP##_guardedsf4 (*op0, cmp_op0, cmp_op1)); \
else \
emit_insn (gen_f##CMP##_guardeddf4 (*op0, cmp_op0, cmp_op1)); \
break;

UNORDERED_COMPARISON(UNLT, ge)
UNORDERED_COMPARISON(UNLE, gt)
UNORDERED_COMPARISON(UNGT, le)
UNORDERED_COMPARISON(UNGE, lt)
#undef UNORDERED_COMPARISON

case NE:
fp_code = EQ;
*code = EQ;
/* Fall through. */

case EQ:
case LE:
case LT:
case GE:
case GT:
/* We have instructions for these cases. */
final_op = gen_reg_rtx (SImode);
riscv_emit_binary (fp_code, final_op, cmp_op0, cmp_op1);
*op0 = gen_reg_rtx (SImode);
riscv_emit_binary (fp_code, *op0, cmp_op0, cmp_op1);
break;

default:
gcc_unreachable ();
}

/* Compare the binary result against 0. */
*op0 = final_op;
*op1 = const0_rtx;
}
}

Expand Down
19 changes: 19 additions & 0 deletions gcc/config/riscv/riscv.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,9 @@
;; from the same template.
(define_code_iterator any_shift [ashift ashiftrt lshiftrt])

;; This code iterator supports emitting signaling FP comparisons.
(define_code_iterator fp_scmp [ge gt le lt])

;; This code iterator allows unsigned and signed division to be generated
;; from the same template.
(define_code_iterator any_div [div udiv])
Expand Down Expand Up @@ -349,6 +352,10 @@
(define_code_attr optab [(ashift "ashl")
(ashiftrt "ashr")
(lshiftrt "lshr")
(ge "ge")
(le "le")
(gt "gt")
(lt "lt")
(ior "ior")
(xor "xor")
(and "and")
Expand Down Expand Up @@ -1964,6 +1971,18 @@
[(set_attr "type" "fcmp")
(set_attr "mode" "<UNITMODE>")])

(define_insn "f<optab>_guarded<ANYF:mode>4"
[(set (match_operand:SI 0 "register_operand" "=r")
(fp_scmp:SI
(match_operand:ANYF 1 "register_operand" "f")
(match_operand:ANYF 2 "register_operand" "f")))
(clobber (match_scratch:SI 3 "=&r"))]
"TARGET_HARD_FLOAT"
"frflags\t%3\n\tf<optab>.<fmt>\t%0,%1,%2\n\tfsflags %3"
[(set_attr "type" "fcmp")
(set_attr "mode" "<UNITMODE>")
(set (attr "length") (const_int 12))])

(define_insn "*seq_zero_<GPR:mode><GPR2:mode>"
[(set (match_operand:GPR2 0 "register_operand" "=r")
(eq:GPR2 (match_operand:GPR 1 "register_operand" "r")
Expand Down

2 comments on commit 2540fd6

@kito-cheng
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No new fail :)

@aswaterman
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Please sign in to comment.