hppa: Improve expansion of ashldi3 when !TARGET_64BIT
authorRoger Sayle <roger@nextmovesoftware.com>
Tue, 25 Aug 2020 17:57:55 +0000 (18:57 +0100)
committerRoger Sayle <roger@nextmovesoftware.com>
Tue, 25 Aug 2020 17:57:55 +0000 (18:57 +0100)
This patch improves the code generated on PA-RISC for DImode
(double word) left shifts by small constants (1-31).  This target
has a very cool shd instruction that can be recognized by combine
for simple shifts, but relying on combine is fragile for more
complicated functions.  This patch tweaks pa.md's ashldi3 expander,
to form the optimal two instruction shd/zdep sequence at RTL
expansion time.

As an example of the benefits of this approach, the simple function
unsigned long long u9(unsigned long long x) { return x*9; }
currently generates 9 instructions and with this patch now requires
only 7.

2020-08-25  Roger Sayle  <roger@nextmovesoftware.com>

* config/pa/pa.md (ashldi3): Additionally, on !TARGET_64BIT
generate a two instruction shd/zdep sequence when shifting
registers by suitable constants.
(shd_internal): New define_expand to provide gen_shd_internal.

gcc/config/pa/pa.md

index 6350c685a59b71dbc83b0527169e5e18bdb578b5..713ff175445cccb4ebe9a517c1164d8412028d59 100644 (file)
   [(set (match_operand:DI 0 "register_operand" "")
        (ashift:DI (match_operand:DI 1 "lhs_lshift_operand" "")
                   (match_operand:DI 2 "arith32_operand" "")))]
-  "TARGET_64BIT"
+  ""
   "
 {
+  if (!TARGET_64BIT)
+    {
+      if (REG_P (operands[0]) && GET_CODE (operands[2]) == CONST_INT)
+       {
+         unsigned HOST_WIDE_INT shift = UINTVAL (operands[2]);
+         if (shift >= 1 && shift <= 31)
+           {
+             rtx dst = operands[0];
+             rtx src = force_reg (DImode, operands[1]);
+             emit_insn (gen_shd_internal (gen_highpart (SImode, dst),
+                                          gen_lowpart (SImode, src),
+                                          GEN_INT (32-shift),
+                                          gen_highpart (SImode, src),
+                                          GEN_INT (shift)));
+             emit_insn (gen_ashlsi3 (gen_lowpart (SImode, dst),
+                                     gen_lowpart (SImode, src),
+                                     GEN_INT (shift)));
+             DONE;
+           }
+       }
+      /* Fallback to using optabs.c's expand_doubleword_shift.  */
+      FAIL;
+    }
   if (GET_CODE (operands[2]) != CONST_INT)
     {
       rtx temp = gen_reg_rtx (DImode);
   [(set_attr "type" "shift")
    (set_attr "length" "4")])
 
+(define_expand "shd_internal"
+  [(set (match_operand:SI 0 "register_operand")
+       (ior:SI
+         (lshiftrt:SI (match_operand:SI 1 "register_operand")
+                      (match_operand:SI 2 "const_int_operand"))
+         (ashift:SI (match_operand:SI 3 "register_operand")
+                    (match_operand:SI 4 "const_int_operand"))))]
+  "")
+
 (define_insn ""
   [(set (match_operand:SI 0 "register_operand" "=r")
        (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "r")