From 95c2f8c0503858335d0b6875bba8ef142ca4e6b5 Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Wed, 9 Nov 2016 15:25:53 -0800 Subject: [PATCH] Implement unordered FP comparisons correctly This implementation is not ideal, but it should reslove https://github.com/riscv/riscv-gnu-toolchain/issues/195 @kito-cheng can you do the usual? Thanks. --- gcc/config/riscv/riscv.c | 83 ++++++++++++++++++++------------------- gcc/config/riscv/riscv.md | 19 +++++++++ 2 files changed, 62 insertions(+), 40 deletions(-) diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 08907079afae..e378eb1bba58 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -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. @@ -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; } } diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 43612ca172a0..f149909f9916 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -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]) @@ -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") @@ -1964,6 +1971,18 @@ [(set_attr "type" "fcmp") (set_attr "mode" "")]) +(define_insn "f_guarded4" + [(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.\t%0,%1,%2\n\tfsflags %3" + [(set_attr "type" "fcmp") + (set_attr "mode" "") + (set (attr "length") (const_int 12))]) + (define_insn "*seq_zero_" [(set (match_operand:GPR2 0 "register_operand" "=r") (eq:GPR2 (match_operand:GPR 1 "register_operand" "r")