diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.md')
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 119 |
1 files changed, 69 insertions, 50 deletions
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index 6cf3b17e20b..5c7a4caf10b 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -4606,12 +4606,19 @@ { if (FLOAT128_IEEE_P (<MODE>mode)) { + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp = gen_reg_rtx (DImode); + rtx dest_di = gen_lowpart (DImode, dest); + if (<MODE>mode == KFmode) - emit_insn (gen_signbitkf2_dm (operands[0], operands[1])); + emit_insn (gen_signbitkf2_dm (tmp, src)); else if (<MODE>mode == TFmode) - emit_insn (gen_signbittf2_dm (operands[0], operands[1])); + emit_insn (gen_signbittf2_dm (tmp, src)); else gcc_unreachable (); + + emit_insn (gen_lshrdi3 (dest_di, tmp, GEN_INT (63))); DONE; } operands[2] = gen_reg_rtx (DFmode); @@ -4632,6 +4639,66 @@ } }) +;; Optimize IEEE 128-bit signbit on 64-bit systems with direct move to avoid +;; multiple direct moves. If we used a SUBREG:DI of the Floa128 type, the +;; register allocator would typically move the entire _Float128 item to GPRs (2 +;; instructions on ISA 3.0, 3-4 instructions on ISA 2.07). +;; +;; After register allocation, if the _Float128 had originally been in GPRs, the +;; split allows the post reload phases to eliminate the move, and do the shift +;; directly with the register that contains the signbit. +(define_insn_and_split "signbit<mode>2_dm" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (unspec:DI [(match_operand:SIGNBIT 1 "gpc_reg_operand" "wa,r")] + UNSPEC_SIGNBIT))] + "TARGET_POWERPC64 && TARGET_DIRECT_MOVE" + "@ + mfvsrd %0,%x1 + #" + "&& reload_completed && int_reg_operand (operands[1], <MODE>mode)" + [(set (match_dup 0) + (match_dup 2))] +{ + operands[2] = gen_highpart (DImode, operands[1]); +} + [(set_attr "type" "mftgpr,*")]) + +;; Optimize IEEE 128-bit signbit on to avoid loading the value into a vector +;; register and then doing a direct move if the value comes from memory. On +;; little endian, we have to load the 2nd double-word to get the sign bit. +(define_insn_and_split "*signbit<mode>2_dm_mem" + [(set (match_operand:DI 0 "gpc_reg_operand" "=b") + (unspec:DI [(match_operand:SIGNBIT 1 "memory_operand" "m")] + UNSPEC_SIGNBIT))] + "TARGET_POWERPC64 && TARGET_DIRECT_MOVE" + "#" + "&& 1" + [(set (match_dup 0) + (match_dup 2))] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx addr = XEXP (src, 0); + + if (WORDS_BIG_ENDIAN) + operands[2] = adjust_address (src, DImode, 0); + + else if (REG_P (addr) || SUBREG_P (addr)) + operands[2] = adjust_address (src, DImode, 8); + + else if (GET_CODE (addr) == PLUS && REG_P (XEXP (addr, 0)) + && CONST_INT_P (XEXP (addr, 1)) && mem_operand_gpr (src, DImode)) + operands[2] = adjust_address (src, DImode, 8); + + else + { + rtx tmp = can_create_pseudo_p () ? gen_reg_rtx (DImode) : dest; + emit_insn (gen_rtx_SET (tmp, addr)); + operands[2] = change_address (src, DImode, + gen_rtx_PLUS (DImode, tmp, GEN_INT (8))); + } +}) + (define_expand "copysign<mode>3" [(set (match_dup 3) (abs:SFDF (match_operand:SFDF 1 "gpc_reg_operand" ""))) @@ -4661,54 +4728,6 @@ operands[5] = CONST0_RTX (<MODE>mode); }) -;; Optimize signbit on 64-bit systems with direct move to avoid doing the store -;; and load. -(define_insn_and_split "signbit<mode>2_dm" - [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r") - (unspec:SI - [(match_operand:SIGNBIT 1 "input_operand" "wa,m,r")] - UNSPEC_SIGNBIT))] - "TARGET_POWERPC64 && TARGET_DIRECT_MOVE" - "#" - "&& reload_completed" - [(const_int 0)] -{ - rs6000_split_signbit (operands[0], operands[1]); - DONE; -} - [(set_attr "length" "8,8,4") - (set_attr "type" "mftgpr,load,integer")]) - -(define_insn_and_split "*signbit<mode>2_dm_<su>ext" - [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r") - (any_extend:DI - (unspec:SI - [(match_operand:SIGNBIT 1 "input_operand" "wa,m,r")] - UNSPEC_SIGNBIT)))] - "TARGET_POWERPC64 && TARGET_DIRECT_MOVE" - "#" - "&& reload_completed" - [(const_int 0)] -{ - rs6000_split_signbit (operands[0], operands[1]); - DONE; -} - [(set_attr "length" "8,8,4") - (set_attr "type" "mftgpr,load,integer")]) - -;; MODES_TIEABLE_P doesn't allow DImode to be tied with the various floating -;; point types, which makes normal SUBREG's problematical. Instead use a -;; special pattern to avoid using a normal movdi. -(define_insn "signbit<mode>2_dm2" - [(set (match_operand:DI 0 "gpc_reg_operand" "=r") - (unspec:DI [(match_operand:SIGNBIT 1 "gpc_reg_operand" "wa") - (const_int 0)] - UNSPEC_SIGNBIT))] - "TARGET_POWERPC64 && TARGET_DIRECT_MOVE" - "mfvsrd %0,%x1" - [(set_attr "type" "mftgpr")]) - - ;; Use an unspec rather providing an if-then-else in RTL, to prevent the ;; compiler from optimizing -0.0 (define_insn "copysign<mode>3_fcpsgn" |