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.md408
1 files changed, 279 insertions, 129 deletions
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index c3ff213832e..12ee4dce506 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -1,6 +1,6 @@
;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler
;; Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-;; 1999, 2000, 2001 Free Software Foundation, Inc.
+;; 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
;; This file is part of GNU CC.
@@ -32,6 +32,8 @@
;; 8 movsi_got
;; 9/v eh_reg_restore
;; 10 fctiwz
+;; 15 load_macho_picbase
+;; 16 macho_correct_pic
;; 19 movesi_from_cr
;; 20 movesi_to_cr
@@ -3613,7 +3615,7 @@
#"
[(set_attr "type" "compare")
(set_attr "length" "4,8")])
-
+
(define_split
[(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "")
(compare:CC
@@ -3633,7 +3635,7 @@
(compare:CC (match_dup 0)
(const_int 0)))]
"")
-
+
;; Rotate and shift insns, in all their variants. These support shifts,
;; field inserts and extracts, and various combinations thereof.
(define_expand "insv"
@@ -3821,7 +3823,7 @@
if (which_alternative == 1)
return \"#\";
- /* If the bitfield being tested fits in the upper or lower half of a
+ /* If the bit-field being tested fits in the upper or lower half of a
word, it is possible to use andiu. or andil. to test it. This is
useful because the condition register set-use delay is smaller for
andi[ul]. than for rlinm. This doesn't work when the starting bit
@@ -3880,14 +3882,12 @@
if (which_alternative == 1)
return \"#\";
- if ((start > 0 && start + size <= 16) || start >= 16)
+ /* Since we are using the output value, we can't ignore any need for
+ a shift. The bit-field must end at the LSB. */
+ if (start >= 16 && start + size == 32)
{
- operands[3] = GEN_INT (((1 << (16 - (start & 15)))
- - (1 << (16 - (start & 15) - size))));
- if (start < 16)
- return \"{andiu.|andis.} %0,%1,%3\";
- else
- return \"{andil.|andi.} %0,%1,%3\";
+ operands[3] = GEN_INT ((1 << size) - 1);
+ return \"{andil.|andi.} %0,%1,%3\";
}
if (start + size >= 32)
@@ -5892,13 +5892,30 @@
"fctidz %0,%1"
[(set_attr "type" "fp")])
-;; This only is safe if rounding mode set appropriately.
-(define_insn_and_split "floatdisf2"
+(define_expand "floatdisf2"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (float:SF (match_operand:DI 1 "gpc_reg_operand" "")))]
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+ "
+{
+ if (!flag_unsafe_math_optimizations)
+ {
+ rtx label = gen_label_rtx ();
+ emit_insn (gen_floatdisf2_internal2 (operands[1], label));
+ emit_label (label);
+ }
+ emit_insn (gen_floatdisf2_internal1 (operands[0], operands[1]));
+ DONE;
+}")
+
+;; This is not IEEE compliant if rounding mode is "round to nearest".
+;; If the DI->DF conversion is inexact, then it's possible to suffer
+;; from double rounding.
+(define_insn_and_split "floatdisf2_internal1"
[(set (match_operand:SF 0 "gpc_reg_operand" "=f")
(float:SF (match_operand:DI 1 "gpc_reg_operand" "*f")))
(clobber (match_scratch:DF 2 "=f"))]
- "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
- && flag_unsafe_math_optimizations"
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
"#"
"&& reload_completed"
[(set (match_dup 2)
@@ -5906,6 +5923,37 @@
(set (match_dup 0)
(float_truncate:SF (match_dup 2)))]
"")
+
+;; Twiddles bits to avoid double rounding.
+;; Bits that might be trucated when converting to DFmode are replaced
+;; by a bit that won't be lost at that stage, but is below the SFmode
+;; rounding position.
+(define_expand "floatdisf2_internal2"
+ [(parallel [(set (match_dup 4)
+ (compare:CC (and:DI (match_operand:DI 0 "" "")
+ (const_int 2047))
+ (const_int 0)))
+ (set (match_dup 2) (and:DI (match_dup 0) (const_int 2047)))
+ (clobber (match_scratch:CC 7 ""))])
+ (set (match_dup 3) (ashiftrt:DI (match_dup 0) (const_int 53)))
+ (set (match_dup 3) (plus:DI (match_dup 3) (const_int 1)))
+ (set (pc) (if_then_else (eq (match_dup 4) (const_int 0))
+ (label_ref (match_operand:DI 1 "" ""))
+ (pc)))
+ (set (match_dup 5) (compare:CCUNS (match_dup 3) (const_int 2)))
+ (set (pc) (if_then_else (ltu (match_dup 5) (const_int 0))
+ (label_ref (match_dup 1))
+ (pc)))
+ (set (match_dup 0) (xor:DI (match_dup 0) (match_dup 2)))
+ (set (match_dup 0) (ior:DI (match_dup 0) (const_int 2048)))]
+ "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS"
+ "
+{
+ operands[2] = gen_reg_rtx (DImode);
+ operands[3] = gen_reg_rtx (DImode);
+ operands[4] = gen_reg_rtx (CCmode);
+ operands[5] = gen_reg_rtx (CCUNSmode);
+}")
;; Define the DImode operations that can be done in a small number
;; of instructions. The & constraints are to prevent the register
@@ -8301,8 +8349,8 @@
"")
(define_insn "*movcc_internal1"
- [(set (match_operand:CC 0 "nonimmediate_operand" "=y,x,y,r,r,r,r,m")
- (match_operand:CC 1 "nonimmediate_operand" "y,r,r,x,y,r,m,r"))]
+ [(set (match_operand:CC 0 "nonimmediate_operand" "=y,x,y,r,r,r,cl,q,r,r,m")
+ (match_operand:CC 1 "nonimmediate_operand" "y,r,r,x,y,r,r,r,h,m,r"))]
"register_operand (operands[0], CCmode)
|| register_operand (operands[1], CCmode)"
"@
@@ -8312,10 +8360,13 @@
mfcr %0
mfcr %0\;{rlinm|rlwinm} %0,%0,%f1,0xf0000000
mr %0,%1
+ mt%0 %1
+ mt%0 %1
+ mf%1 %0
{l%U1%X1|lwz%U1%X1} %0,%1
{st%U0%U1|stw%U0%U1} %1,%0"
- [(set_attr "type" "cr_logical,cr_logical,cr_logical,cr_logical,cr_logical,*,load,store")
- (set_attr "length" "*,*,12,*,8,*,*,*")])
+ [(set_attr "type" "cr_logical,cr_logical,cr_logical,cr_logical,cr_logical,*,*,mtjmpr,*,load,store")
+ (set_attr "length" "4,4,12,4,8,4,4,4,4,4,4")])
;; For floating-point, we normally deal with the floating-point registers
;; unless -msoft-float is used. The sole exception is that parameter passing
@@ -8354,8 +8405,8 @@
}")
(define_insn "*movsf_hardfloat"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=!r,!r,m,f,f,m,!r,!r")
- (match_operand:SF 1 "input_operand" "r,m,r,f,m,f,G,Fn"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=!r,!r,m,f,f,m,!cl,!q,!r,!r,!r")
+ (match_operand:SF 1 "input_operand" "r,m,r,f,m,f,r,r,h,G,Fn"))]
"(gpc_reg_operand (operands[0], SFmode)
|| gpc_reg_operand (operands[1], SFmode))
&& (TARGET_HARD_FLOAT && TARGET_FPRS)"
@@ -8366,19 +8417,25 @@
fmr %0,%1
lfs%U1%X1 %0,%1
stfs%U0%X0 %1,%0
+ mt%0 %1
+ mt%0 %1
+ mf%1 %0
#
#"
- [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*")
- (set_attr "length" "4,4,4,4,4,4,4,8")])
+ [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,mtjmpr,*,*,*")
+ (set_attr "length" "4,4,4,4,4,4,4,4,4,4,8")])
(define_insn "*movsf_softfloat"
- [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,r")
- (match_operand:SF 1 "input_operand" "r,m,r,I,L,R,G,Fn"))]
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,cl,q,r,r,m,r,r,r,r,r")
+ (match_operand:SF 1 "input_operand" "r,r,r,h,m,r,I,L,R,G,Fn"))]
"(gpc_reg_operand (operands[0], SFmode)
|| gpc_reg_operand (operands[1], SFmode))
&& (TARGET_SOFT_FLOAT || !TARGET_FPRS)"
"@
mr %0,%1
+ mt%0 %1
+ mt%0 %1
+ mf%1 %0
{l%U1%X1|lwz%U1%X1} %0,%1
{st%U0%X0|stw%U0%X0} %1,%0
{lil|li} %0,%1
@@ -8386,8 +8443,8 @@
{cal|la} %0,%a1
#
#"
- [(set_attr "type" "*,load,store,*,*,*,*,*")
- (set_attr "length" "4,4,4,4,4,4,4,8")])
+ [(set_attr "type" "*,mtjmpr,*,*,load,store,*,*,*,*,*")
+ (set_attr "length" "4,4,4,4,4,4,4,4,4,4,8")])
(define_expand "movdf"
@@ -8460,7 +8517,9 @@
int endian = (WORDS_BIG_ENDIAN == 0);
long l[2];
REAL_VALUE_TYPE rv;
+#if HOST_BITS_PER_WIDE_INT >= 64
HOST_WIDE_INT val;
+#endif
REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
REAL_VALUE_TO_TARGET_DOUBLE (rv, l);
@@ -8468,10 +8527,10 @@
operands[2] = gen_lowpart (DImode, operands[0]);
/* HIGHPART is lower memory address when WORDS_BIG_ENDIAN. */
#if HOST_BITS_PER_WIDE_INT >= 64
- val = ((HOST_WIDE_INT)(unsigned long)l[endian] << 32 |
- ((HOST_WIDE_INT)(unsigned long)l[1 - endian]));
+ val = ((HOST_WIDE_INT)(unsigned long)l[endian] << 32
+ | ((HOST_WIDE_INT)(unsigned long)l[1 - endian]));
- operands[3] = immed_double_const (val, -(val < 0), DImode);
+ operands[3] = gen_int_mode (val, DImode);
#else
operands[3] = immed_double_const (l[1 - endian], l[endian], DImode);
#endif
@@ -8484,8 +8543,8 @@
;; The "??" is a kludge until we can figure out a more reasonable way
;; of handling these non-offsettable values.
(define_insn "*movdf_hardfloat32"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,m,!r,!r,!r,f,f,m")
- (match_operand:DF 1 "input_operand" "r,m,r,G,H,F,f,m,f"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,m,f,f,m,!r,!r,!r")
+ (match_operand:DF 1 "input_operand" "r,m,r,f,m,f,G,H,F"))]
"! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
&& (gpc_reg_operand (operands[0], DFmode)
|| gpc_reg_operand (operands[1], DFmode))"
@@ -8562,19 +8621,19 @@
return \"\";
}
case 3:
+ return \"fmr %0,%1\";
case 4:
+ return \"lfd%U1%X1 %0,%1\";
case 5:
- return \"#\";
+ return \"stfd%U0%X0 %1,%0\";
case 6:
- return \"fmr %0,%1\";
case 7:
- return \"lfd%U1%X1 %0,%1\";
case 8:
- return \"stfd%U0%X0 %1,%0\";
+ return \"#\";
}
}"
- [(set_attr "type" "*,load,store,*,*,*,fp,fpload,fpstore")
- (set_attr "length" "8,16,16,8,12,16,*,*,*")])
+ [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*,*")
+ (set_attr "length" "8,16,16,4,4,4,8,12,16")])
(define_insn "*movdf_softfloat32"
[(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,r,r,r")
@@ -8618,8 +8677,8 @@
(set_attr "length" "8,8,8,8,12,16")])
(define_insn "*movdf_hardfloat64"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,m,!r,!r,!r,f,f,m")
- (match_operand:DF 1 "input_operand" "r,m,r,G,H,F,f,m,f"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,m,f,f,m,!cl,!r,!r,!r,!r")
+ (match_operand:DF 1 "input_operand" "r,m,r,f,m,f,r,h,G,H,F"))]
"TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS
&& (gpc_reg_operand (operands[0], DFmode)
|| gpc_reg_operand (operands[1], DFmode))"
@@ -8627,30 +8686,34 @@
mr %0,%1
ld%U1%X1 %0,%1
std%U0%X0 %1,%0
- #
- #
- #
fmr %0,%1
lfd%U1%X1 %0,%1
- stfd%U0%X0 %1,%0"
- [(set_attr "type" "*,load,store,*,*,*,fp,fpload,fpstore")
- (set_attr "length" "4,4,4,8,12,16,4,4,4")])
+ stfd%U0%X0 %1,%0
+ mt%0 %1
+ mf%1 %0
+ #
+ #
+ #"
+ [(set_attr "type" "*,load,store,fp,fpload,fpstore,mtjmpr,*,*,*,*")
+ (set_attr "length" "4,4,4,4,4,4,4,4,8,12,16")])
(define_insn "*movdf_softfloat64"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,r,r,r")
- (match_operand:DF 1 "input_operand" "r,m,r,G,H,F"))]
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,cl,r,r,m,r,r,r")
+ (match_operand:DF 1 "input_operand" "r,r,h,m,r,G,H,F"))]
"TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || !TARGET_FPRS)
&& (gpc_reg_operand (operands[0], DFmode)
|| gpc_reg_operand (operands[1], DFmode))"
"@
mr %0,%1
+ mt%0 %1
+ mf%1 %0
ld%U1%X1 %0,%1
std%U0%X0 %1,%0
#
#
#"
- [(set_attr "type" "*,load,store,*,*,*")
- (set_attr "length" "*,*,*,8,12,16")])
+ [(set_attr "type" "*,*,*,load,store,*,*,*")
+ (set_attr "length" "4,4,4,4,4,8,12,16")])
(define_expand "movtf"
[(set (match_operand:TF 0 "general_operand" "")
@@ -8681,9 +8744,9 @@
else
return \"fmr %0,%1\;fmr %L0,%L1\";
case 1:
- return \"lfd %0,%1\;lfd %L0,%L1\";
+ return \"lfd %0,%1\;lfd %L0,%Y1\";
case 2:
- return \"stfd %1,%0\;stfd %L1,%L0\";
+ return \"stfd %1,%0\;stfd %L1,%Y0\";
case 3:
case 4:
case 5:
@@ -8695,45 +8758,100 @@
(define_split
[(set (match_operand:TF 0 "gpc_reg_operand" "")
- (match_operand:TF 1 "const_double_operand" ""))]
- "DEFAULT_ABI == ABI_AIX && TARGET_HARD_FLOAT && TARGET_FPRS
- && TARGET_LONG_DOUBLE_128"
- [(set (match_dup 3) (match_dup 1))
- (set (match_dup 0)
- (float_extend:TF (match_dup 3)))]
+ (match_operand:TF 1 "easy_fp_constant" ""))]
+ "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
+ && TARGET_HARD_FLOAT && TARGET_FPRS && ! TARGET_POWERPC64
+ && TARGET_LONG_DOUBLE_128 && reload_completed
+ && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
+ || (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (SUBREG_REG (operands[0])) <= 31))"
+ [(set (match_dup 2) (match_dup 6))
+ (set (match_dup 3) (match_dup 7))
+ (set (match_dup 4) (match_dup 8))
+ (set (match_dup 5) (match_dup 9))]
"
{
- operands[2] = operand_subword (operands[1], 0, 0, DFmode);
- operands[3] = gen_reg_rtx (DFmode);
+ long l[4];
+ REAL_VALUE_TYPE rv;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, l);
+
+ operands[2] = operand_subword (operands[0], 0, 0, TFmode);
+ operands[3] = operand_subword (operands[0], 1, 0, TFmode);
+ operands[4] = operand_subword (operands[0], 2, 0, TFmode);
+ operands[5] = operand_subword (operands[0], 3, 0, TFmode);
+ operands[6] = gen_int_mode (l[0], SImode);
+ operands[7] = gen_int_mode (l[1], SImode);
+ operands[8] = gen_int_mode (l[2], SImode);
+ operands[9] = gen_int_mode (l[3], SImode);
}")
-(define_insn_and_split "extenddftf2"
+(define_split
+ [(set (match_operand:TF 0 "gpc_reg_operand" "")
+ (match_operand:TF 1 "easy_fp_constant" ""))]
+ "(DEFAULT_ABI == ABI_AIX || DEFAULT_ABI == ABI_DARWIN)
+ && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_POWERPC64
+ && TARGET_LONG_DOUBLE_128 && reload_completed
+ && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31)
+ || (GET_CODE (operands[0]) == SUBREG
+ && GET_CODE (SUBREG_REG (operands[0])) == REG
+ && REGNO (SUBREG_REG (operands[0])) <= 31))"
+ [(set (match_dup 2) (match_dup 4))
+ (set (match_dup 3) (match_dup 5))]
+ "
+{
+ long l[4];
+ REAL_VALUE_TYPE rv;
+ HOST_WIDE_INT val;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]);
+ REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, l);
+
+ operands[2] = gen_lowpart (DImode, operands[0]);
+ operands[3] = gen_highpart (DImode, operands[0]);
+#if HOST_BITS_PER_WIDE_INT >= 64
+ val = ((HOST_WIDE_INT)(unsigned long)l[0] << 32
+ | ((HOST_WIDE_INT)(unsigned long)l[1]));
+ operands[4] = gen_int_mode (val, DImode);
+
+ val = ((HOST_WIDE_INT)(unsigned long)l[2] << 32
+ | ((HOST_WIDE_INT)(unsigned long)l[3]));
+ operands[5] = gen_int_mode (val, DImode);
+#else
+ operands[4] = immed_double_const (l[1], l[0], DImode);
+ operands[5] = immed_double_const (l[3], l[2], DImode);
+#endif
+}")
+
+(define_insn "extenddftf2"
[(set (match_operand:TF 0 "gpc_reg_operand" "=f")
(float_extend:TF (match_operand:DF 1 "gpc_reg_operand" "f")))]
"DEFAULT_ABI == ABI_AIX && TARGET_HARD_FLOAT && TARGET_FPRS
&& TARGET_LONG_DOUBLE_128"
- "#"
- ""
- [(set (match_dup 2) (match_dup 3))]
- "
+ "*
{
- operands[2] = gen_rtx_REG (DFmode, REGNO (operands[0] + 1));
- operands[3] = CONST0_RTX (DFmode);
-}")
+ if (REGNO (operands[0]) == REGNO (operands[1]))
+ return \"fsub %L0,%L0,%L0\";
+ else
+ return \"fmr %0,%1\;fsub %L0,%L0,%L0\";
+}"
+ [(set_attr "type" "fp")])
-(define_insn_and_split "extendsftf2"
+(define_insn "extendsftf2"
[(set (match_operand:TF 0 "gpc_reg_operand" "=f")
(float_extend:TF (match_operand:SF 1 "gpc_reg_operand" "f")))]
"DEFAULT_ABI == ABI_AIX && TARGET_HARD_FLOAT && TARGET_FPRS
&& TARGET_LONG_DOUBLE_128"
- "#"
- ""
- [(set (match_dup 2) (match_dup 3))]
- "
+ "*
{
- operands[2] = gen_rtx_REG (SFmode, REGNO (operands[0] + 1));
- operands[3] = CONST0_RTX (SFmode);
-}")
+ if (REGNO (operands[0]) == REGNO (operands[1]))
+ return \"fsub %L0,%L0,%L0\";
+ else
+ return \"fmr %0,%1\;fsub %L0,%L0,%L0\";
+}"
+ [(set_attr "type" "fp")])
(define_insn "trunctfdf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "=f")
@@ -8767,8 +8885,8 @@
"#"
"&& reload_completed"
[(set (match_dup 2)
- (float:DF (match_operand:DI 1 "gpc_reg_operand" "")))
- (set (match_operand:TF 0 "gpc_reg_operand" "")
+ (float:DF (match_dup 1)))
+ (set (match_dup 0)
(float_extend:TF (match_dup 2)))]
"")
@@ -8781,34 +8899,36 @@
"#"
"&& reload_completed"
[(set (match_dup 2)
- (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
- (set (match_operand:TF 0 "gpc_reg_operand" "")
+ (float:DF (match_dup 1)))
+ (set (match_dup 0)
(float_extend:TF (match_dup 2)))]
"")
(define_insn_and_split "fix_trunctfdi2"
[(set (match_operand:DI 0 "gpc_reg_operand" "=*f")
- (fix:DI (match_operand:TF 1 "gpc_reg_operand" "f")))]
+ (fix:DI (match_operand:TF 1 "gpc_reg_operand" "f")))
+ (clobber (match_scratch:DF 2 "=f"))]
"DEFAULT_ABI == ABI_AIX && TARGET_POWERPC64
&& TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
"#"
"&& reload_completed"
[(set (match_dup 2)
- (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))
- (set (match_operand:DI 0 "gpc_reg_operand" "")
- (fix:SI (match_dup 2)))]
+ (float_truncate:DF (match_dup 1)))
+ (set (match_dup 0)
+ (fix:DI (match_dup 2)))]
"")
(define_insn_and_split "fix_trunctfsi2"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
- (fix:SI (match_operand:TF 1 "gpc_reg_operand" "f")))]
+ (fix:SI (match_operand:TF 1 "gpc_reg_operand" "f")))
+ (clobber (match_scratch:DF 2 "=f"))]
"DEFAULT_ABI == ABI_AIX && TARGET_HARD_FLOAT && TARGET_FPRS
&& TARGET_LONG_DOUBLE_128"
"#"
"&& reload_completed"
[(set (match_dup 2)
- (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))
- (set (match_operand:SI 0 "gpc_reg_operand" "")
+ (float_truncate:DF (match_dup 1)))
+ (set (match_dup 0)
(fix:SI (match_dup 2)))]
"")
@@ -8912,7 +9032,7 @@
}
}"
[(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*,*,*,*")
- (set_attr "length" "8,8,8,*,*,*,8,12,8,12,16")])
+ (set_attr "length" "8,8,8,4,4,4,8,12,8,12,16")])
(define_split
[(set (match_operand:DI 0 "gpc_reg_operand" "")
@@ -8952,7 +9072,7 @@
}")
(define_insn "*movdi_internal64"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,f,f,m,r,*h,*h")
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,?f,f,m,r,*h,*h")
(match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,f,m,f,*h,r,0"))]
"TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], DImode)
@@ -9127,12 +9247,12 @@
}
}"
[(set_attr "type" "store,store,*,load,load")
- (set_attr "length" "*,16,16,*,16")])
+ (set_attr "length" "4,16,16,4,16")])
(define_insn "*movti_string"
- [(set (match_operand:TI 0 "reg_or_mem_operand" "=m,????r,????r")
- (match_operand:TI 1 "reg_or_mem_operand" "r,r,m"))
- (clobber (match_scratch:SI 2 "=X,X,X"))]
+ [(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r")
+ (match_operand:TI 1 "reg_or_mem_operand" "r,r,r,Q,m"))
+ (clobber (match_scratch:SI 2 "=X,X,X,X,X"))]
"TARGET_STRING && ! TARGET_POWER && ! TARGET_POWERPC64
&& (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))"
"*
@@ -9143,9 +9263,10 @@
abort ();
case 0:
- return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\;{st|stw} %Y1,%Y0\;{st|stw} %Z1,%Z0\";
-
+ return \"{stsi|stswi} %1,%P0,16\";
case 1:
+ return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\;{st|stw} %Y1,%Y0\;{st|stw} %Z1,%Z0\";
+ case 2:
/* Normally copy registers with lowest numbered register copied first.
But copy in the other order if the first register of the output
is the second, third, or fourth register in the input. */
@@ -9154,7 +9275,13 @@
return \"mr %Z0,%Z1\;mr %Y0,%Y1\;mr %L0,%L1\;mr %0,%1\";
else
return \"mr %0,%1\;mr %L0,%L1\;mr %Y0,%Y1\;mr %Z0,%Z1\";
- case 2:
+ case 3:
+ /* If the address is not used in the output, we can use lsi. Otherwise,
+ fall through to generating four loads. */
+ if (! reg_overlap_mentioned_p (operands[0], operands[1]))
+ return \"{lsi|lswi} %0,%P1,16\";
+ /* ... fall through ... */
+ case 4:
/* If the address register is the same as the register for the lowest-
addressed word, load it last. Similarly for the next two words.
Otherwise load lowest address to highest. */
@@ -9171,8 +9298,8 @@
return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\;{l|lwz} %Y0,%Y1\;{l|lwz} %Z0,%Z1\";
}
}"
- [(set_attr "type" "store,*,load")
- (set_attr "length" "16,16,16")])
+ [(set_attr "type" "store,store,*,load,load")
+ (set_attr "length" "4,16,16,4,16")])
(define_insn "*movti_ppc64"
[(set (match_operand:TI 0 "nonimmediate_operand" "=r,r,m")
@@ -10153,8 +10280,8 @@
[(set (match_operand:SI 0 "register_operand" "=l")
(match_operand:SI 1 "immediate_operand" "s"))
(unspec [(match_dup 1)] 7)]
- "TARGET_ELF && flag_pic == 2"
- "bl %1\\n%1:"
+ "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
+ "bcl 20,31,%1\\n%1:"
[(set_attr "type" "branch")
(set_attr "length" "4")])
@@ -10162,46 +10289,69 @@
[(set (match_operand:SI 0 "register_operand" "=l")
(match_operand:SI 1 "immediate_operand" "s"))
(unspec [(match_dup 1) (match_operand 2 "immediate_operand" "s")] 6)]
- "TARGET_ELF && flag_pic == 2"
- "bl %1\\n\\t.long %2-%1+4\\n%1:"
+ "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
+ "bcl 20,31,%1\\n\\t.long %2-%1+4\\n%1:"
[(set_attr "type" "branch")
(set_attr "length" "8")])
(define_insn "load_toc_v4_PIC_2"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
- (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "r")
+ (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b")
(minus:SI (match_operand:SI 2 "immediate_operand" "s")
(match_operand:SI 3 "immediate_operand" "s")))))]
- "TARGET_ELF && flag_pic == 2"
+ "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2"
"{l|lwz} %0,%2-%3(%1)"
[(set_attr "type" "load")])
(define_insn "load_macho_picbase"
[(set (match_operand:SI 0 "register_operand" "=l")
- (unspec:SI [(const_int 0)] 15))]
+ (unspec:SI [(match_operand:SI 1 "immediate_operand" "s")] 15))]
"(DEFAULT_ABI == ABI_DARWIN) && flag_pic"
- "*
-{
-#if TARGET_MACHO
- char *picbase = machopic_function_base_name ();
- operands[1] = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (picbase, -1));
-#endif
- return \"bcl 20,31,%1\\n%1:\";
-}"
+ "bcl 20,31,%1\\n%1:"
[(set_attr "type" "branch")
(set_attr "length" "4")])
+(define_insn "macho_correct_pic"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+ (plus:SI (match_operand:SI 1 "gpc_reg_operand" "=r")
+ (unspec:SI [(match_operand:SI 2 "immediate_operand" "s")
+ (match_operand:SI 3 "immediate_operand" "s")]
+ 16)))]
+ "DEFAULT_ABI == ABI_DARWIN"
+ "addis %0,%1,ha16(%2-%3)\n\taddi %1,%1,lo16(%2-%3)"
+ [(set_attr "length" "8")])
+
;; If the TOC is shared over a translation unit, as happens with all
;; the kinds of PIC that we support, we need to restore the TOC
;; pointer only when jumping over units of translation.
+;; On Darwin, we need to reload the picbase.
(define_expand "builtin_setjmp_receiver"
[(use (label_ref (match_operand 0 "" "")))]
"(DEFAULT_ABI == ABI_V4 && flag_pic == 1)
- || (TARGET_TOC && TARGET_MINIMAL_TOC)"
+ || (TARGET_TOC && TARGET_MINIMAL_TOC)
+ || (DEFAULT_ABI == ABI_DARWIN && flag_pic)"
"
{
- rs6000_emit_load_toc_table (FALSE);
+#if TARGET_MACHO
+ if (DEFAULT_ABI == ABI_DARWIN)
+ {
+ char *picbase = machopic_function_base_name ();
+ rtx picrtx = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (picbase, -1));
+ rtx picreg = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM);
+ rtx tmplabrtx;
+ char tmplab[20];
+
+ ASM_GENERATE_INTERNAL_LABEL(tmplab, \"LSJR\",
+ CODE_LABEL_NUMBER (operands[0]));
+ tmplabrtx = gen_rtx_SYMBOL_REF (Pmode, ggc_alloc_string (tmplab, -1));
+
+ emit_insn (gen_load_macho_picbase (picreg, tmplabrtx));
+ emit_insn (gen_macho_correct_pic (picreg, picreg, picrtx, tmplabrtx));
+ }
+ else
+#endif
+ rs6000_emit_load_toc_table (FALSE);
DONE;
}")
@@ -10400,7 +10550,7 @@
}")
;; Call to function in current module. No TOC pointer reload needed.
-;; Operand2 is non-zero if we are using the V.4 calling sequence and
+;; Operand2 is nonzero if we are using the V.4 calling sequence and
;; either the function was not prototyped, or it was prototyped as a
;; variable argument function. It is > 0 if FP registers were passed
;; and < 0 if they were not.
@@ -10486,7 +10636,7 @@
;; Call to function which may be in another module. Restore the TOC
;; pointer (r2) after the call unless this is System V.
-;; Operand2 is non-zero if we are using the V.4 calling sequence and
+;; Operand2 is nonzero if we are using the V.4 calling sequence and
;; either the function was not prototyped, or it was prototyped as a
;; variable argument function. It is > 0 if FP registers were passed
;; and < 0 if they were not.
@@ -14016,7 +14166,7 @@
return \"bdz $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
(define_insn "*ctrsi_internal2"
[(set (pc)
@@ -14040,7 +14190,7 @@
return \"{bdn|bdnz} $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
(define_insn "*ctrdi_internal1"
[(set (pc)
@@ -14064,7 +14214,7 @@
return \"bdz $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
(define_insn "*ctrdi_internal2"
[(set (pc)
@@ -14088,7 +14238,7 @@
return \"{bdn|bdnz} $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
;; Similar, but we can use GE since we have a REG_NONNEG.
@@ -14114,7 +14264,7 @@
return \"bdz $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
(define_insn "*ctrsi_internal4"
[(set (pc)
@@ -14138,7 +14288,7 @@
return \"{bdn|bdnz} $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
(define_insn "*ctrdi_internal3"
[(set (pc)
@@ -14162,7 +14312,7 @@
return \"bdz $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
(define_insn "*ctrdi_internal4"
[(set (pc)
@@ -14186,7 +14336,7 @@
return \"{bdn|bdnz} $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
;; Similar but use EQ
@@ -14212,7 +14362,7 @@
return \"{bdn|bdnz} $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
(define_insn "*ctrsi_internal6"
[(set (pc)
@@ -14236,7 +14386,7 @@
return \"bdz $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
(define_insn "*ctrdi_internal5"
[(set (pc)
@@ -14260,7 +14410,7 @@
return \"{bdn|bdnz} $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
(define_insn "*ctrdi_internal6"
[(set (pc)
@@ -14284,7 +14434,7 @@
return \"bdz $+8\;b %l0\";
}"
[(set_attr "type" "branch")
- (set_attr "length" "*,12,16")])
+ (set_attr "length" "4,12,16")])
;; Now the splitters if we could not allocate the CTR register