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 u9: copy %r25,%r28 copy %r26,%r29 extru %r26,2,3,%r21 zdep %r25,28,29,%r19 zdep %r26,28,29,%r20 or %r21,%r19,%r19 add %r29,%r20,%r29 addc %r28,%r19,%r28 bv,n %r0(%r2) and with this patch now requires only 7: u9: copy %r25,%r28 copy %r26,%r29 shd %r26,%r25,29,%r19 zdep %r26,28,29,%r20 add %r29,%r20,%r29 addc %r28,%r19,%r28 bv,n %r0(%r2) This improvement is a first step towards getting synth_mult to behave sanely on hppa (PR middle-end/87256). Unfortunately, it's been a long while since I've had access to a hppa system, so apart from building a cross-compiler and looking at the assembler it generates, this patch is completely untested. I was wondering whether Dave or Jeff (or someone else with access to real hardware) might "spin" this patch for me? 2020-08-21 Roger Sayle <ro...@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. Thanks in advance, Roger -- Roger Sayle NextMove Software Cambridge, UK
diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md index 6350c68..e7b7635 100644 --- a/gcc/config/pa/pa.md +++ b/gcc/config/pa/pa.md @@ -6416,9 +6416,32 @@ [(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_highpart (SImode, src), + GEN_INT (32-shift), + gen_lowpart (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); @@ -6705,6 +6728,15 @@ [(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")