This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
sCOND update for FP comparisons
- From: Geoffrey Keating <gkeating at apple dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 3 May 2003 14:00:57 -0700 (PDT)
- Subject: sCOND update for FP comparisons
This patch does the following:
1. Fix a bug where
(set (reg:SI xxx) (unge:SI (reg:CCFP yyy) (const_int 0)))
caused incorrect code generation. The pattern actually doesn't
exist in the machine, so the rewrite just prevents it from being
generated & recognized. This was a latent bug triggered by
rs6000-iselslowmath.patch.
2. It makes the condition code complement operation a separate insn,
rather than using %D, so it can be scheduled and in
future combined with other condition code logical operations (this
doesn't work now, because the required instructions aren't in the
md file and possibly because combine doesn't know how to generate
them if they did exist).
3. It makes the sCOND patterns actually work and actually be generated
in all cases for FP operations. I know this is not really the best
thing in general, but I think a complete solution will want to
generate CR moves or branches depending on the processor in use
and the certainty of prediction of the branch, and you can't
do that if CR moves don't work to start with.
Bootstrapped & tested on powerpc-darwin.
--
- Geoffrey Keating <geoffk@apple.com>
===File ~/patches/rs6000-sccfp.patch========================
2003-05-03 Geoffrey Keating <geoffk@apple.com>
* config/rs6000/rs6000.c (scc_comparison_operator): Make equivalent
to branch_positive_comparison_operator.
(ccr_bit): Check that sCOND conditions are actually a positive bit.
(print_operand): Remove %D substitution.
(rs6000_emit_sCOND): Generate complement operation to ensure that
sCOND input is a positive bit.
* config/rs6000/rs6000.md: Rearrange sCOND templates to be in the
same order as bCOND, and add the missing ones. Remove the %D
substitutions from the scc patterns.
Index: config/rs6000/rs6000.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.c,v
retrieving revision 1.466
diff -u -p -u -p -r1.466 rs6000.c
--- config/rs6000/rs6000.c 2 May 2003 18:36:50 -0000 1.466
+++ config/rs6000/rs6000.c 3 May 2003 20:44:04 -0000
@@ -7049,34 +7049,15 @@ branch_positive_comparison_operator (op,
|| code == UNORDERED);
}
-/* Return 1 if OP is a comparison operation that is valid for an scc insn.
- We check the opcode against the mode of the CC value and disallow EQ or
- NE comparisons for integers. */
+/* Return 1 if OP is a comparison operation that is valid for an scc
+ insn: it must be a positive comparison. */
int
scc_comparison_operator (op, mode)
rtx op;
enum machine_mode mode;
{
- enum rtx_code code = GET_CODE (op);
- enum machine_mode cc_mode;
-
- if (GET_MODE (op) != mode && mode != VOIDmode)
- return 0;
-
- if (GET_RTX_CLASS (code) != '<')
- return 0;
-
- cc_mode = GET_MODE (XEXP (op, 0));
- if (GET_MODE_CLASS (cc_mode) != MODE_CC)
- return 0;
-
- validate_condition_mode (code, cc_mode);
-
- if (code == NE && cc_mode != CCFPmode)
- return 0;
-
- return 1;
+ return branch_positive_comparison_operator (op, mode);
}
int
@@ -7501,6 +7482,12 @@ ccr_bit (op, scc_p)
validate_condition_mode (code, cc_mode);
+ /* When generating a sCOND operation, only positive conditions are
+ allowed. */
+ if (scc_p && code != EQ && code != GT && code != LT && code != UNORDERED
+ && code != GTU && code != LTU)
+ abort ();
+
switch (code)
{
case NE:
@@ -7697,42 +7684,6 @@ print_operand (file, x, code)
/* %c is output_addr_const if a CONSTANT_ADDRESS_P, otherwise
output_operand. */
- case 'D':
- /* There used to be a comment for 'C' reading "This is an
- optional cror needed for certain floating-point
- comparisons. Otherwise write nothing." */
-
- /* Similar, except that this is for an scc, so we must be able to
- encode the test in a single bit that is one. We do the above
- for any LE, GE, GEU, or LEU and invert the bit for NE. */
- if (GET_CODE (x) == LE || GET_CODE (x) == GE
- || GET_CODE (x) == LEU || GET_CODE (x) == GEU)
- {
- int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO);
-
- fprintf (file, "cror %d,%d,%d\n\t", base_bit + 3,
- base_bit + 2,
- base_bit + (GET_CODE (x) == GE || GET_CODE (x) == GEU));
- }
-
- else if (GET_CODE (x) == NE)
- {
- int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO);
-
- fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 3,
- base_bit + 2, base_bit + 2);
- }
- else if (TARGET_E500 && !TARGET_FPRS && TARGET_HARD_FLOAT
- && GET_CODE (x) == EQ
- && GET_MODE (XEXP (x, 0)) == CCFPmode)
- {
- int base_bit = 4 * (REGNO (XEXP (x, 0)) - CR0_REGNO);
-
- fprintf (file, "crnor %d,%d,%d\n\t", base_bit + 1,
- base_bit + 1, base_bit + 1);
- }
- return;
-
case 'E':
/* X is a CR register. Print the number of the EQ bit of the CR */
if (GET_CODE (x) != REG || ! CR_REGNO_P (REGNO (x)))
@@ -8686,8 +8637,28 @@ rs6000_emit_sCOND (code, result)
{
rtx condition_rtx;
enum machine_mode op_mode;
+ enum rtx_code cond_code;
condition_rtx = rs6000_generate_compare (code);
+ cond_code = GET_CODE (condition_rtx);
+
+ if (cond_code == NE
+ || cond_code == GE || cond_code == LE
+ || cond_code == GEU || cond_code == LEU
+ || cond_code == ORDERED || cond_code == UNGE || cond_code == UNLE)
+ {
+ rtx not_result = gen_reg_rtx (CCEQmode);
+ rtx not_op, rev_cond_rtx;
+ enum machine_mode cc_mode;
+
+ cc_mode = GET_MODE (XEXP (condition_rtx, 0));
+
+ rev_cond_rtx = gen_rtx (rs6000_reverse_condition (cc_mode, cond_code),
+ SImode, XEXP (condition_rtx, 0), const0_rtx);
+ not_op = gen_rtx_COMPARE (CCEQmode, rev_cond_rtx, const0_rtx);
+ emit_insn (gen_rtx_SET (VOIDmode, not_result, not_op));
+ condition_rtx = gen_rtx_EQ (VOIDmode, not_result, const0_rtx);
+ }
op_mode = GET_MODE (rs6000_compare_op0);
if (op_mode == VOIDmode)
Index: config/rs6000/rs6000.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/rs6000/rs6000.md,v
retrieving revision 1.251
diff -u -p -u -p -r1.251 rs6000.md
--- config/rs6000/rs6000.md 2 May 2003 14:49:51 -0000 1.251
+++ config/rs6000/rs6000.md 3 May 2003 20:44:05 -0000
@@ -10919,8 +10919,8 @@
DONE;
}")
-;; A > 0 is best done using the portable sequence, so fail in that case.
-(define_expand "sgt"
+;; A >= 0 is best done the portable way for A an integer.
+(define_expand "sge"
[(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
""
"
@@ -10929,26 +10929,26 @@
&& (! TARGET_POWER || rs6000_compare_op1 == const0_rtx))
FAIL;
- rs6000_emit_sCOND (GT, operands[0]);
+ rs6000_emit_sCOND (GE, operands[0]);
DONE;
}")
-;; A < 0 is best done in the portable way for A an integer.
-(define_expand "slt"
+;; A > 0 is best done using the portable sequence, so fail in that case.
+(define_expand "sgt"
[(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
""
"
{
- if (! rs6000_compare_fp_p
+ if (! rs6000_compare_fp_p
&& (! TARGET_POWER || rs6000_compare_op1 == const0_rtx))
FAIL;
- rs6000_emit_sCOND (LT, operands[0]);
+ rs6000_emit_sCOND (GT, operands[0]);
DONE;
}")
-;; A >= 0 is best done the portable way for A an integer.
-(define_expand "sge"
+;; A <= 0 is best done the portable way for A an integer.
+(define_expand "sle"
[(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
""
"
@@ -10957,43 +10957,84 @@
&& (! TARGET_POWER || rs6000_compare_op1 == const0_rtx))
FAIL;
- rs6000_emit_sCOND (GE, operands[0]);
+ rs6000_emit_sCOND (LE, operands[0]);
DONE;
}")
-;; A <= 0 is best done the portable way for A an integer.
-(define_expand "sle"
+;; A < 0 is best done in the portable way for A an integer.
+(define_expand "slt"
[(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
""
"
{
- if (! rs6000_compare_fp_p
+ if (! rs6000_compare_fp_p
&& (! TARGET_POWER || rs6000_compare_op1 == const0_rtx))
FAIL;
- rs6000_emit_sCOND (LE, operands[0]);
+ rs6000_emit_sCOND (LT, operands[0]);
DONE;
}")
+(define_expand "sgeu"
+ [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+ ""
+ "{ rs6000_emit_sCOND (GEU, operands[0]); DONE; }")
+
(define_expand "sgtu"
[(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
""
"{ rs6000_emit_sCOND (GTU, operands[0]); DONE; }")
+(define_expand "sleu"
+ [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+ ""
+ "{ rs6000_emit_sCOND (LEU, operands[0]); DONE; }")
+
(define_expand "sltu"
[(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
""
"{ rs6000_emit_sCOND (LTU, operands[0]); DONE; }")
-(define_expand "sgeu"
+(define_expand "sunordered"
[(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
""
- "{ rs6000_emit_sCOND (GEU, operands[0]); DONE; }")
+ "{ rs6000_emit_sCOND (UNORDERED, operands[0]); DONE; }")
-(define_expand "sleu"
+(define_expand "sordered"
[(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
""
- "{ rs6000_emit_sCOND (LEU, operands[0]); DONE; }")
+ "{ rs6000_emit_sCOND (ORDERED, operands[0]); DONE; }")
+
+(define_expand "suneq"
+ [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+ ""
+ "{ rs6000_emit_sCOND (UNEQ, operands[0]); DONE; }")
+
+(define_expand "sunge"
+ [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+ ""
+ "{ rs6000_emit_sCOND (UNGE, operands[0]); DONE; }")
+
+(define_expand "sungt"
+ [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+ ""
+ "{ rs6000_emit_sCOND (UNGT, operands[0]); DONE; }")
+
+(define_expand "sunle"
+ [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+ ""
+ "{ rs6000_emit_sCOND (UNLE, operands[0]); DONE; }")
+
+(define_expand "sunlt"
+ [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+ ""
+ "{ rs6000_emit_sCOND (UNLT, operands[0]); DONE; }")
+
+(define_expand "sltgt"
+ [(clobber (match_operand:SI 0 "gpc_reg_operand" ""))]
+ ""
+ "{ rs6000_emit_sCOND (LTGT, operands[0]); DONE; }")
+
;; Here are the actual compare insns.
(define_insn "*cmpsi_internal1"
@@ -11141,7 +11182,7 @@
[(match_operand 2 "cc_reg_operand" "y")
(const_int 0)]))]
""
- "%D1mfcr %0\;{rlinm|rlwinm} %0,%0,%J1,1"
+ "mfcr %0\;{rlinm|rlwinm} %0,%0,%J1,1"
[(set_attr "type" "mfcr")
(set_attr "length" "12")])
@@ -11150,7 +11191,7 @@
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(unspec:SI [(match_operand 1 "cc_reg_operand" "y")] UNSPEC_MV_CR_OV))]
"TARGET_ISEL"
- "%D1mfcr %0\;{rlinm|rlwinm} %0,%0,%t1,1"
+ "mfcr %0\;{rlinm|rlwinm} %0,%0,%t1,1"
[(set_attr "type" "mfcr")
(set_attr "length" "12")])
@@ -11160,7 +11201,7 @@
[(match_operand 2 "cc_reg_operand" "y")
(const_int 0)]))]
"TARGET_POWERPC64"
- "%D1mfcr %0\;{rlinm|rlwinm} %0,%0,%J1,1"
+ "mfcr %0\;{rlinm|rlwinm} %0,%0,%J1,1"
[(set_attr "type" "mfcr")
(set_attr "length" "12")])
@@ -11174,7 +11215,7 @@
(match_op_dup 1 [(match_dup 2) (const_int 0)]))]
"! TARGET_POWERPC64"
"@
- %D1mfcr %3\;{rlinm.|rlwinm.} %3,%3,%J1,1
+ mfcr %3\;{rlinm.|rlwinm.} %3,%3,%J1,1
#"
[(set_attr "type" "delayed_compare")
(set_attr "length" "12,16")])
@@ -11216,7 +11257,7 @@
operands[4] = GEN_INT (count);
operands[5] = GEN_INT (put_bit);
- return \"%D1mfcr %0\;{rlinm|rlwinm} %0,%0,%4,%5,%5\";
+ return \"mfcr %0\;{rlinm|rlwinm} %0,%0,%4,%5,%5\";
}"
[(set_attr "type" "mfcr")
(set_attr "length" "12")])
@@ -11251,7 +11292,7 @@
operands[5] = GEN_INT (count);
operands[6] = GEN_INT (put_bit);
- return \"%D1mfcr %4\;{rlinm.|rlwinm.} %4,%4,%5,%6,%6\";
+ return \"mfcr %4\;{rlinm.|rlwinm.} %4,%4,%5,%6,%6\";
}"
[(set_attr "type" "delayed_compare")
(set_attr "length" "12,16")])
@@ -11289,7 +11330,7 @@
[(match_operand 5 "cc_reg_operand" "y")
(const_int 0)]))]
"REGNO (operands[2]) != REGNO (operands[5])"
- "%D1%D4mfcr %3\;{rlinm|rlwinm} %0,%3,%J1,1\;{rlinm|rlwinm} %3,%3,%J4,1"
+ "mfcr %3\;{rlinm|rlwinm} %0,%3,%J1,1\;{rlinm|rlwinm} %3,%3,%J4,1"
[(set_attr "type" "mfcr")
(set_attr "length" "20")])
@@ -11303,7 +11344,7 @@
[(match_operand 5 "cc_reg_operand" "y")
(const_int 0)]))]
"TARGET_POWERPC64 && REGNO (operands[2]) != REGNO (operands[5])"
- "%D1%D4mfcr %3\;{rlinm|rlwinm} %0,%3,%J1,1\;{rlinm|rlwinm} %3,%3,%J4,1"
+ "mfcr %3\;{rlinm|rlwinm} %0,%3,%J1,1\;{rlinm|rlwinm} %3,%3,%J4,1"
[(set_attr "type" "mfcr")
(set_attr "length" "20")])
============================================================