aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/rs6000/rs6000.md
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rs6000/rs6000.md')
-rw-r--r--gcc/config/rs6000/rs6000.md119
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"