Patchwork [rs6000] inform combine about extra isel alternatives

login
register
mail settings
Submitter Nathan Froyd
Date Oct. 12, 2010, 6:04 p.m.
Message ID <20101012180448.GB24720@nightcrawler>
Download mbox | patch
Permalink /patch/67604/
State New
Headers show

Comments

Nathan Froyd - Oct. 12, 2010, 6:04 p.m.
My patch to permit isel to accommodate a constant 0 operand:

http://gcc.gnu.org/ml/gcc-patches/2010-07/msg01298.html

has one small problem: patterns with comparisons that isel can't handle
are assumed to be invalid.  They were permitted before the patch, but
not afterwards.  However, they are still useful for combine's purposes.

This patch introduces two patterns for combine's purposes; a new
predicate is needed to constrain the comparison appropriately.  The
tweak to output_isel is necessary to reverse the sense of the condition
before outputting the assembly.  (The PUT_CODE there is gross, but such
a construct was used prior to my July patch.)  Finally, the addition of
NE to rs6000_rtx_costs is to ensure that we think:

(if_then_else (ne (compare (reg:CC N) 0)) ... ...)

as just as cheap as the EQ variant.  Otherwise, combine will probably
reject the NE version as being too expensive (0 will be considered as
COST_N_INSNS(2) or more).

A typical example of what we gain as a result looks like:

-       rlwinm 9,9,0,31,31
        srwi 10,3,1
        xori 11,4,16386
        srwi 11,11,1
        ori 11,11,32768
        srwi 4,4,1
-       cmpwi 7,9,1
-       isel 0,11,4,30
+       andi. 0,9,1
+       isel 0,4,11,2

The rlwinm+cmpwi has been replaced in favor of andi..  This assembly is
faster and equivalent to what 4.5 generates.

Testing on powerpc-linux-gnu in progress.  OK to commit?

-Nathan

	* config/rs6000/predicates.md (scc_rev_comparison_operator): New.
	* config/rs6000/rs6000.md (*isel_reversed_signed_<mode>): New.
	(*isel_reversed_unsigned_<mode>): New.
	* config/rs6000/rs6000.c (output_isel): Accept GE/GEU/LE/LEU/NE
	as valid comparisons and adjust operands and output appropriately.
	(rs6000_rtx_costs) <CONST_INT>: Accept NE as a cost-0 outer_code.
David Edelsohn - Oct. 12, 2010, 6:51 p.m.
>        * config/rs6000/predicates.md (scc_rev_comparison_operator): New.
>        * config/rs6000/rs6000.md (*isel_reversed_signed_<mode>): New.
>        (*isel_reversed_unsigned_<mode>): New.
>        * config/rs6000/rs6000.c (output_isel): Accept GE/GEU/LE/LEU/NE
>        as valid comparisons and adjust operands and output appropriately.
>        (rs6000_rtx_costs) <CONST_INT>: Accept NE as a cost-0 outer_code.

Okay.

Thanks, David

Patch

Index: config/rs6000/predicates.md
===================================================================
--- config/rs6000/predicates.md	(revision 165389)
+++ config/rs6000/predicates.md	(working copy)
@@ -903,6 +903,12 @@  (define_predicate "scc_comparison_operat
   (and (match_operand 0 "branch_comparison_operator")
        (match_code "eq,lt,gt,ltu,gtu,unordered")))
 
+;; Return 1 if OP is a comparison operation whose inverse would be valid for
+;; an SCC insn.
+(define_predicate "scc_rev_comparison_operator"
+  (and (match_operand 0 "branch_comparison_operator")
+       (match_code "ne,le,ge,leu,geu,ordered")))
+
 ;; Return 1 if OP is a comparison operation that is valid for a branch
 ;; insn, which is true if the corresponding bit in the CC register is set.
 (define_predicate "branch_positive_comparison_operator"
Index: config/rs6000/rs6000.c
===================================================================
--- config/rs6000/rs6000.c	(revision 165389)
+++ config/rs6000/rs6000.c	(working copy)
@@ -17159,7 +17159,13 @@  output_isel (rtx *operands)
 
   code = GET_CODE (operands[1]);
 
-  gcc_assert (!(code == GE || code == GEU || code == LE || code == LEU || code == NE));
+  if (code == GE || code == GEU || code == LE || code == LEU || code == NE)
+    {
+      gcc_assert (GET_CODE (operands[2]) == REG
+		  && GET_CODE (operands[3]) == REG);
+      PUT_CODE (operands[1], reverse_condition (code));
+      return "isel %0,%3,%2,%j1";
+    }
 
   return "isel %0,%2,%3,%j1";
 }
@@ -25731,7 +25737,7 @@  rs6000_rtx_costs (rtx x, int code, int o
 	  || (outer_code == COMPARE
 	      && (satisfies_constraint_I (x)
 		  || satisfies_constraint_K (x)))
-	  || (outer_code == EQ
+	  || ((outer_code == EQ || outer_code == NE)
 	      && (satisfies_constraint_I (x)
 		  || satisfies_constraint_K (x)
 		  || (mode == SImode
Index: config/rs6000/rs6000.md
===================================================================
--- config/rs6000/rs6000.md	(revision 165389)
+++ config/rs6000/rs6000.md	(working copy)
@@ -6126,6 +6126,38 @@  (define_insn "isel_unsigned_<mode>"
   [(set_attr "type" "isel")
    (set_attr "length" "4")])
 
+;; These patterns can be useful for combine; they let combine know that
+;; isel can handle reversed comparisons so long as the operands are
+;; registers.
+
+(define_insn "*isel_reversed_signed_<mode>"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+	(if_then_else:GPR
+	 (match_operator 1 "scc_rev_comparison_operator"
+			 [(match_operand:CC 4 "cc_reg_operand" "y")
+			  (const_int 0)])
+	 (match_operand:GPR 2 "gpc_reg_operand" "b")
+	 (match_operand:GPR 3 "gpc_reg_operand" "b")))]
+  "TARGET_ISEL<sel>"
+  "*
+{ return output_isel (operands); }"
+  [(set_attr "type" "isel")
+   (set_attr "length" "4")])
+
+(define_insn "*isel_reversed_unsigned_<mode>"
+  [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+	(if_then_else:GPR
+	 (match_operator 1 "scc_rev_comparison_operator"
+			 [(match_operand:CCUNS 4 "cc_reg_operand" "y")
+			  (const_int 0)])
+	 (match_operand:GPR 2 "gpc_reg_operand" "b")
+	 (match_operand:GPR 3 "gpc_reg_operand" "b")))]
+  "TARGET_ISEL<sel>"
+  "*
+{ return output_isel (operands); }"
+  [(set_attr "type" "isel")
+   (set_attr "length" "4")])
+
 (define_expand "movsfcc"
    [(set (match_operand:SF 0 "gpc_reg_operand" "")
 	 (if_then_else:SF (match_operand 1 "comparison_operator" "")