rs6000: Optimise SImode cstore on 64-bit
authorSegher Boessenkool <segher@kernel.crashing.org>
Wed, 2 Dec 2015 10:56:15 +0000 (11:56 +0100)
committerSegher Boessenkool <segher@gcc.gnu.org>
Wed, 2 Dec 2015 10:56:15 +0000 (11:56 +0100)
On 64-bit we can do comparisons of 32-bit values by extending those
values to 64-bit, subtracting them, and then getting the high bit of
the result.  For registers this is always cheaper than using the carry
bit sequence; and if the comparison involves a constant, this is cheaper
than the sequence we previously generated in half of the cases (and the
same cost in the other cases).

After this, the only sequence left that is using the mfcr insn is the
one doing signed comparison of Pmode registers.

From-SVN: r231165

gcc/ChangeLog
gcc/config/rs6000/rs6000.md

index 8eaac80b47d78aa371bb6122689412f6c35317e7..58c472868ed9c7d1b7d3ead40595cc72c57ca121 100644 (file)
@@ -1,3 +1,8 @@
+2015-12-02  Segher Boessenkool  <segher@kernel.crashing.org>
+
+       * config/rs6000/rs6000.md (cstore_si_as_di): New expander.
+       (cstore<mode>4): Use it.
+
 2015-12-02  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/68625
index a500d67efa9171734e93be576ba341cfc4f3d841..26b0962ae7d4c62a85121f17538497f3faa8cd1b 100644 (file)
   DONE;
 })
 
+(define_expand "cstore_si_as_di"
+  [(use (match_operator 1 "unsigned_comparison_operator"
+         [(match_operand:SI 2 "gpc_reg_operand")
+          (match_operand:SI 3 "reg_or_short_operand")]))
+   (clobber (match_operand:SI 0 "register_operand"))]
+  ""
+{
+  int uns_flag = unsigned_comparison_operator (operands[1], VOIDmode) ? 1 : 0;
+  enum rtx_code cond_code = signed_condition (GET_CODE (operands[1]));
+
+  rtx op1 = gen_reg_rtx (DImode);
+  rtx op2 = gen_reg_rtx (DImode);
+  convert_move (op1, operands[2], uns_flag);
+  convert_move (op2, operands[3], uns_flag);
+
+  if (cond_code == GT || cond_code == LE)
+    {
+      cond_code = swap_condition (cond_code);
+      std::swap (op1, op2);
+    }
+
+  rtx tmp = gen_reg_rtx (DImode);
+  rtx tmp2 = gen_reg_rtx (DImode);
+  emit_insn (gen_subdi3 (tmp, op1, op2));
+  emit_insn (gen_lshrdi3 (tmp2, tmp, GEN_INT (63)));
+
+  rtx tmp3;
+  switch (cond_code)
+    {
+    default:
+      gcc_unreachable ();
+    case LT:
+      tmp3 = tmp2;
+      break;
+    case GE:
+      tmp3 = gen_reg_rtx (DImode);
+      emit_insn (gen_xordi3 (tmp3, tmp2, const1_rtx));
+      break;
+    }
+
+  convert_move (operands[0], tmp3, 1);
+
+  DONE;
+})
+
 (define_expand "cstore<mode>4_signed_imm"
   [(use (match_operator 1 "signed_comparison_operator"
          [(match_operand:GPR 2 "gpc_reg_operand")
     emit_insn (gen_cstore<mode>4_unsigned (operands[0], operands[1],
                                           operands[2], operands[3]));
 
+  /* For comparisons smaller than Pmode we can cheaply do things in Pmode.  */
+  else if (<MODE>mode == SImode && Pmode == DImode)
+    emit_insn (gen_cstore_si_as_di (operands[0], operands[1],
+                                   operands[2], operands[3]));
+
   /* For signed comparisons against a constant, we can do some simple
      bit-twiddling.  */
   else if (signed_comparison_operator (operands[1], VOIDmode)