===================================================================
@@ -129,6 +129,9 @@ extern void rs6000_emit_parity (rtx, rtx
extern rtx rs6000_machopic_legitimize_pic_address (rtx, enum machine_mode,
rtx);
+extern rtx rs6000_address_for_fpconvert (rtx);
+extern rtx rs6000_allocate_stack_temp (enum machine_mode, bool, bool);
+extern void rs6000_expand_convert_si_to_sfdf (rtx, rtx, bool);
#endif /* RTX_CODE */
#ifdef TREE_CODE
===================================================================
@@ -2501,10 +2501,10 @@ rs6000_override_options (const char *def
POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT
| MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP
| MASK_MFPGPR | MASK_RECIP_PRECISION},
- {"power7", PROCESSOR_POWER7,
+ {"power7", PROCESSOR_POWER7, /* Don't add MASK_ISEL by default */
POWERPC_7400_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_MFCRF
| MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP | MASK_POPCNTD
- | MASK_VSX| MASK_RECIP_PRECISION}, /* Don't add MASK_ISEL by default */
+ | MASK_VSX | MASK_RECIP_PRECISION},
{"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK},
{"powerpc64", PROCESSOR_POWERPC64,
POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64},
@@ -2541,15 +2541,19 @@ rs6000_override_options (const char *def
ISA_2_1_MASKS = MASK_MFCRF,
ISA_2_2_MASKS = (ISA_2_1_MASKS | MASK_POPCNTB | MASK_FPRND),
- /* For ISA 2.05, do not add MFPGPR, since it isn't in ISA 2.06, and
- don't add ALTIVEC, since in general it isn't a win on power6. */
- ISA_2_5_MASKS = (ISA_2_2_MASKS | MASK_CMPB | MASK_RECIP_PRECISION
- | MASK_DFP),
+ /* For ISA 2.05, do not add MFPGPR, since it isn't in ISA 2.06, and don't
+ add ALTIVEC, since in general it isn't a win on power6. In ISA 2.04,
+ fsel, fre, fsqrt, etc. were no longer documented as optional. Group
+ masks by server and embedded. */
+ ISA_2_5_MASKS_EMBEDDED = (ISA_2_2_MASKS | MASK_CMPB | MASK_RECIP_PRECISION
+ | MASK_PPC_GFXOPT | MASK_PPC_GPOPT),
+ ISA_2_5_MASKS_SERVER = (ISA_2_5_MASKS_EMBEDDED | MASK_DFP),
/* For ISA 2.06, don't add ISEL, since in general it isn't a win, but
altivec is a win so enable it. */
- ISA_2_6_MASKS = (ISA_2_5_MASKS | MASK_ALTIVEC | MASK_POPCNTD
- | MASK_VSX | MASK_RECIP_PRECISION)
+ ISA_2_6_MASKS_EMBEDDED = (ISA_2_5_MASKS_EMBEDDED | MASK_POPCNTD),
+ ISA_2_6_MASKS_SERVER = (ISA_2_5_MASKS_SERVER | MASK_POPCNTD | MASK_ALTIVEC
+ | MASK_VSX)
};
/* Numerous experiment shows that IRA based loop pressure
@@ -2690,15 +2694,22 @@ rs6000_override_options (const char *def
{
warning (0, msg);
target_flags &= ~ MASK_VSX;
+ target_flags_explicit |= MASK_VSX;
}
}
/* For the newer switches (vsx, dfp, etc.) set some of the older options,
unless the user explicitly used the -mno-<option> to disable the code. */
if (TARGET_VSX)
- target_flags |= (ISA_2_6_MASKS & ~target_flags_explicit);
+ target_flags |= (ISA_2_6_MASKS_SERVER & ~target_flags_explicit);
+ else if (TARGET_POPCNTD)
+ target_flags |= (ISA_2_6_MASKS_EMBEDDED & ~target_flags_explicit);
else if (TARGET_DFP)
- target_flags |= (ISA_2_5_MASKS & ~target_flags_explicit);
+ target_flags |= (ISA_2_5_MASKS_SERVER & ~target_flags_explicit);
+ else if (TARGET_CMPB)
+ target_flags |= (ISA_2_5_MASKS_EMBEDDED & ~target_flags_explicit);
+ else if (TARGET_POPCNTB || TARGET_FPRND)
+ target_flags |= (ISA_2_2_MASKS & ~target_flags_explicit);
else if (TARGET_ALTIVEC)
target_flags |= (MASK_PPC_GFXOPT & ~target_flags_explicit);
@@ -26941,4 +26952,122 @@ rs6000_final_prescan_insn (rtx insn, rtx
}
}
+
+/* Allocate a stack temp and fixup the address so it meets the particular
+ memory requirements (either offetable or REG+REG addressing). */
+
+rtx
+rs6000_allocate_stack_temp (enum machine_mode mode,
+ bool offsettable_p,
+ bool reg_reg_p)
+{
+ rtx stack = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
+ rtx addr = XEXP (stack, 0);
+ int strict_p = (reload_in_progress || reload_completed);
+
+ if (!legitimate_indirect_address_p (addr, strict_p))
+ {
+ if (offsettable_p
+ && !rs6000_legitimate_offset_address_p (mode, addr, strict_p))
+ stack = replace_equiv_address (stack, copy_addr_to_reg (addr));
+
+ else if (reg_reg_p && !legitimate_indexed_address_p (addr, strict_p))
+ stack = replace_equiv_address (stack, copy_addr_to_reg (addr));
+ }
+
+ return stack;
+}
+
+/* Given a memory reference, if it is not a reg or reg+reg addressing, convert
+ to such a form to deal with memory reference instructions like STFIWX that
+ only take reg+reg addressing. */
+
+rtx
+rs6000_address_for_fpconvert (rtx x)
+{
+ int strict_p = (reload_in_progress || reload_completed);
+ rtx addr;
+
+ gcc_assert (MEM_P (x));
+ addr = XEXP (x, 0);
+ if (! legitimate_indirect_address_p (addr, strict_p)
+ && ! legitimate_indexed_address_p (addr, strict_p))
+ x = replace_equiv_address (x, copy_addr_to_reg (addr));
+
+ return x;
+}
+
+/* Expand 32-bit int -> floating point conversions. Return true if
+ successful. */
+
+void
+rs6000_expand_convert_si_to_sfdf (rtx dest, rtx src, bool unsigned_p)
+{
+ enum machine_mode dmode = GET_MODE (dest);
+ rtx (*func_si) (rtx, rtx, rtx, rtx);
+ rtx (*func_si_mem) (rtx, rtx);
+ rtx (*func_di) (rtx, rtx);
+ rtx reg, stack;
+
+ gcc_assert (GET_MODE (src) == SImode);
+
+ if (dmode == SFmode)
+ {
+ if (unsigned_p)
+ {
+ gcc_assert (TARGET_FCFIDUS && TARGET_LFIWZX);
+ func_si = gen_floatunssisf2_lfiwzx;
+ func_si_mem = gen_floatunssisf2_lfiwzx_mem;
+ func_di = gen_floatunsdisf2;
+ }
+ else
+ {
+ gcc_assert (TARGET_FCFIDS && TARGET_LFIWAX);
+ func_si = gen_floatsisf2_lfiwax;
+ func_si_mem = gen_floatsisf2_lfiwax_mem;
+ func_di = gen_floatdisf2;
+ }
+ }
+
+ else if (dmode == DFmode)
+ {
+ if (unsigned_p)
+ {
+ gcc_assert (TARGET_FCFIDU && TARGET_LFIWZX);
+ func_si = gen_floatunssidf2_lfiwzx;
+ func_si_mem = gen_floatunssidf2_lfiwzx_mem;
+ func_di = gen_floatunsdidf2;
+ }
+ else
+ {
+ gcc_assert (TARGET_FCFID && TARGET_LFIWAX);
+ func_si = gen_floatsidf2_lfiwax;
+ func_si_mem = gen_floatsidf2_lfiwax_mem;
+ func_di = gen_floatdidf2;
+ }
+ }
+
+ else
+ gcc_unreachable ();
+
+ if (MEM_P (src))
+ {
+ src = rs6000_address_for_fpconvert (src);
+ emit_insn (func_si_mem (dest, src));
+ }
+ else if (!TARGET_MFPGPR)
+ {
+ reg = gen_reg_rtx (DImode);
+ stack = rs6000_allocate_stack_temp (SImode, false, true);
+ emit_insn (func_si (dest, src, stack, reg));
+ }
+ else
+ {
+ if (!REG_P (src))
+ src = force_reg (SImode, src);
+ reg = convert_to_mode (DImode, src, unsigned_p);
+ emit_insn (func_di (dest, reg));
+ }
+}
+
#include "gt-rs6000.h"
===================================================================
@@ -105,6 +105,11 @@ (define_constants
(UNSPEC_BPERM 51)
(UNSPEC_COPYSIGN 52)
(UNSPEC_PARITY 53)
+ (UNSPEC_FCTIW 54)
+ (UNSPEC_FCTID 55)
+ (UNSPEC_LFIWAX 56)
+ (UNSPEC_LFIWZX 57)
+ (UNSPEC_FCTIWUZ 58)
])
;;
@@ -252,13 +257,19 @@ (define_mode_attr mptrsize [(SI "si")
(DI "di")])
(define_mode_attr rreg [(SF "f")
- (DF "Ws")
- (V4SF "Wf")
- (V2DF "Wd")])
+ (DF "ws")
+ (V4SF "wf")
+ (V2DF "wd")])
(define_mode_attr rreg2 [(SF "f")
(DF "d")])
+(define_mode_attr SI_CONVERT_FP [(SF "TARGET_FCFIDS")
+ (DF "TARGET_FCFID")])
+
+(define_mode_attr E500_CONVERT [(SF "!TARGET_FPRS")
+ (DF "TARGET_E500_DOUBLE")])
+
(define_mode_attr TARGET_FLOAT [(SF "TARGET_SINGLE_FLOAT")
(DF "TARGET_DOUBLE_FLOAT")])
@@ -6448,6 +6459,150 @@ (define_expand "fixuns_truncdfdi2"
"TARGET_HARD_FLOAT && TARGET_VSX"
"")
+; We don't define lfiwax/lfiwzx with the normal definition, because we
+; don't want to support putting SImode in FPR registers.
+(define_insn "lfiwax"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+ (unspec:DI [(match_operand:SI 1 "indexed_or_indirect_operand" "Z")]
+ UNSPEC_LFIWAX))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX"
+ "lfiwax %0,%y1"
+ [(set_attr "type" "fpload")])
+
+(define_insn_and_split "floatsi<mode>2_lfiwax"
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>,<rreg2>")
+ (float:SFDF (match_operand:SI 1 "nonimmediate_operand" "Z,r")))
+ (clobber (match_operand:SI 2 "indexed_or_indirect_operand" "=Z,Z"))
+ (clobber (match_operand:DI 3 "gpc_reg_operand" "=d,d"))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
+ && <SI_CONVERT_FP>"
+ "#"
+ "MEM_P (operands[1]) || reload_completed"
+ [(pc)]
+ "
+{
+ if (MEM_P (operands[1]))
+ {
+ operands[1] = rs6000_address_for_fpconvert (operands[1]);
+ emit_insn (gen_lfiwax (operands[3], operands[1]));
+ }
+ else
+ {
+ emit_move_insn (operands[2], operands[1]);
+ emit_insn (gen_lfiwax (operands[3], operands[2]));
+ }
+ emit_insn (gen_floatdi<mode>2 (operands[0], operands[3]));
+ DONE;
+}"
+ [(set_attr "length" "8,12")])
+
+(define_insn_and_split "floatsi<mode>2_lfiwax_mem"
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+ (float:SFDF (match_operand:SI 1 "memory_operand" "Z")))
+ (clobber (match_scratch:DI 2 "=d"))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
+ && <SI_CONVERT_FP>"
+ "#"
+ "&& reload_completed"
+ [(pc)]
+ "
+{
+ emit_insn (gen_lfiwax (operands[2], operands[1]));
+ emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+ DONE;
+}"
+ [(set_attr "length" "8")])
+
+(define_insn_and_split "floatsi<mode>2_lfiwax_mem2"
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+ (float:SFDF
+ (sign_extend:DI
+ (match_operand:SI 1 "memory_operand" "Z"))))
+ (clobber (match_scratch:DI 2 "=d"))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX
+ && <SI_CONVERT_FP>"
+ "#"
+ "&& reload_completed"
+ [(pc)]
+ "
+{
+ emit_insn (gen_lfiwax (operands[2], operands[1]));
+ emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+ DONE;
+}"
+ [(set_attr "length" "8")])
+
+(define_insn "lfiwzx"
+ [(set (match_operand:DI 0 "gpc_reg_operand" "=d")
+ (unspec:DI [(match_operand:SI 1 "indexed_or_indirect_operand" "Z")]
+ UNSPEC_LFIWZX))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX"
+ "lfiwzx %0,%y1"
+ [(set_attr "type" "fpload")])
+
+(define_insn_and_split "floatunssi<mode>2_lfiwzx"
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>,<rreg2>")
+ (unsigned_float:SFDF (match_operand:SI 1 "gpc_reg_operand" "Z,r")))
+ (clobber (match_operand:SI 2 "indexed_or_indirect_operand" "=Z,Z"))
+ (clobber (match_operand:DI 3 "gpc_reg_operand" "=d,d"))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
+ && <SI_CONVERT_FP>"
+ "#"
+ "MEM_P (operands[1]) || reload_completed"
+ [(pc)]
+ "
+{
+ if (MEM_P (operands[1]))
+ {
+ operands[1] = rs6000_address_for_fpconvert (operands[1]);
+ emit_insn (gen_lfiwzx (operands[3], operands[1]));
+ }
+ else
+ {
+ emit_move_insn (operands[2], operands[1]);
+ emit_insn (gen_lfiwzx (operands[3], operands[2]));
+ }
+ emit_insn (gen_floatdi<mode>2 (operands[0], operands[3]));
+ DONE;
+}"
+ [(set_attr "length" "8,12")])
+
+(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem"
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+ (unsigned_float:SFDF (match_operand:SI 1 "memory_operand" "Z")))
+ (clobber (match_scratch:DI 2 "=d"))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
+ && <SI_CONVERT_FP>"
+ "#"
+ "&& reload_completed"
+ [(pc)]
+ "
+{
+ emit_insn (gen_lfiwzx (operands[2], operands[1]));
+ emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+ DONE;
+}"
+ [(set_attr "length" "8")])
+
+(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem2"
+ [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>")
+ (unsigned_float:SFDF
+ (zero_extend:DI
+ (match_operand:SI 1 "memory_operand" "Z"))))
+ (clobber (match_scratch:DI 2 "=d"))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX
+ && <SI_CONVERT_FP>"
+ "#"
+ "&& reload_completed"
+ [(pc)]
+ "
+{
+ emit_insn (gen_lfiwzx (operands[2], operands[1]));
+ emit_insn (gen_floatdi<mode>2 (operands[0], operands[2]));
+ DONE;
+}"
+ [(set_attr "length" "8")])
+
; For each of these conversions, there is a define_expand, a define_insn
; with a '#' template, and a define_split (with C code). The idea is
; to allow constant folding with the template of the define_insn,
@@ -6455,7 +6610,7 @@ (define_expand "fixuns_truncdfdi2"
(define_expand "floatsidf2"
[(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
- (float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (float:DF (match_operand:SI 1 "nonimmediate_operand" "")))
(use (match_dup 2))
(use (match_dup 3))
(clobber (match_dup 4))
@@ -6467,19 +6622,31 @@ (define_expand "floatsidf2"
{
if (TARGET_E500_DOUBLE)
{
+ if (!REG_P (operands[1]))
+ operands[1] = force_reg (SImode, operands[1]);
emit_insn (gen_spe_floatsidf2 (operands[0], operands[1]));
DONE;
}
- if (TARGET_POWERPC64)
+ else if (TARGET_LFIWAX && TARGET_FCFID)
+ {
+ rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], false);
+ DONE;
+ }
+ else if (TARGET_FCFID)
{
- rtx x = convert_to_mode (DImode, operands[1], 0);
- emit_insn (gen_floatdidf2 (operands[0], x));
+ rtx dreg = operands[1];
+ if (!REG_P (dreg))
+ dreg = force_reg (SImode, dreg);
+ dreg = convert_to_mode (DImode, dreg, false);
+ emit_insn (gen_floatdidf2 (operands[0], dreg));
DONE;
}
+ if (!REG_P (operands[1]))
+ operands[1] = force_reg (SImode, operands[1]);
operands[2] = force_reg (SImode, GEN_INT (0x43300000));
operands[3] = force_reg (DFmode, CONST_DOUBLE_ATOF (\"4503601774854144\", DFmode));
- operands[4] = assign_stack_temp (DFmode, GET_MODE_SIZE (DFmode), 0);
+ operands[4] = rs6000_allocate_stack_temp (DFmode, true, false);
operands[5] = gen_reg_rtx (DFmode);
operands[6] = gen_reg_rtx (SImode);
}")
@@ -6492,7 +6659,7 @@ (define_insn_and_split "*floatsidf2_inte
(clobber (match_operand:DF 4 "offsettable_mem_operand" "=o"))
(clobber (match_operand:DF 5 "gpc_reg_operand" "=&d"))
(clobber (match_operand:SI 6 "gpc_reg_operand" "=&r"))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
+ "! TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
"#"
""
[(pc)]
@@ -6518,37 +6685,79 @@ (define_insn_and_split "*floatsidf2_inte
}"
[(set_attr "length" "24")])
+;; If we don't have a direct conversion to single precision, don't enable this
+;; conversion for 32-bit without fast math, because we don't have the insn to
+;; generate the fixup swizzle to avoid double rounding problems.
(define_expand "floatunssisf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "")
- (unsigned_float:SF (match_operand:SI 1 "gpc_reg_operand" "")))]
- "TARGET_HARD_FLOAT && !TARGET_FPRS && TARGET_SINGLE_FLOAT"
- "")
+ (unsigned_float:SF (match_operand:SI 1 "nonimmediate_operand" "")))]
+ "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT
+ && (!TARGET_FPRS
+ || (TARGET_FPRS
+ && ((TARGET_FCFIDUS && TARGET_LFIWZX)
+ || (TARGET_DOUBLE_FLOAT && TARGET_FCFID
+ && (TARGET_POWERPC64 || flag_unsafe_math_optimizations)))))"
+ "
+{
+ if (!TARGET_FPRS)
+ {
+ if (!REG_P (operands[1]))
+ operands[1] = force_reg (SImode, operands[1]);
+ }
+ else if (TARGET_LFIWZX && TARGET_FCFIDUS)
+ {
+ rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], true);
+ DONE;
+ }
+ else
+ {
+ rtx dreg = operands[1];
+ if (!REG_P (dreg))
+ dreg = force_reg (SImode, dreg);
+ dreg = convert_to_mode (DImode, dreg, true);
+ emit_insn (gen_floatdisf2 (operands[0], dreg));
+ DONE;
+ }
+}")
(define_expand "floatunssidf2"
[(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "")
- (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "")))
+ (unsigned_float:DF (match_operand:SI 1 "nonimmediate_operand" "")))
(use (match_dup 2))
(use (match_dup 3))
(clobber (match_dup 4))
(clobber (match_dup 5))])]
- "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
+ "TARGET_HARD_FLOAT
+ && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)"
"
{
if (TARGET_E500_DOUBLE)
{
+ if (!REG_P (operands[1]))
+ operands[1] = force_reg (SImode, operands[1]);
emit_insn (gen_spe_floatunssidf2 (operands[0], operands[1]));
DONE;
}
- if (TARGET_POWERPC64)
+ else if (TARGET_LFIWZX && TARGET_FCFID)
+ {
+ rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], true);
+ DONE;
+ }
+ else if (TARGET_FCFID)
{
- rtx x = convert_to_mode (DImode, operands[1], 1);
- emit_insn (gen_floatdidf2 (operands[0], x));
+ rtx dreg = operands[1];
+ if (!REG_P (dreg))
+ dreg = force_reg (SImode, dreg);
+ dreg = convert_to_mode (DImode, dreg, true);
+ emit_insn (gen_floatdidf2 (operands[0], dreg));
DONE;
}
+ if (!REG_P (operands[1]))
+ operands[1] = force_reg (SImode, operands[1]);
operands[2] = force_reg (SImode, GEN_INT (0x43300000));
operands[3] = force_reg (DFmode, CONST_DOUBLE_ATOF (\"4503599627370496\", DFmode));
- operands[4] = assign_stack_temp (DFmode, GET_MODE_SIZE (DFmode), 0);
+ operands[4] = rs6000_allocate_stack_temp (DFmode, true, false);
operands[5] = gen_reg_rtx (DFmode);
}")
@@ -6559,7 +6768,8 @@ (define_insn_and_split "*floatunssidf2_i
(use (match_operand:DF 3 "gpc_reg_operand" "d"))
(clobber (match_operand:DF 4 "offsettable_mem_operand" "=o"))
(clobber (match_operand:DF 5 "gpc_reg_operand" "=&d"))]
- "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT"
+ "! TARGET_FCFIDU && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT
+ && !(TARGET_FCFID && TARGET_POWERPC64)"
"#"
""
[(pc)]
@@ -6782,76 +6992,154 @@ (define_insn "stfiwx"
"stfiwx %1,%y0"
[(set_attr "type" "fpstore")])
+;; If we don't have a direct conversion to single precision, don't enable this
+;; conversion for 32-bit without fast math, because we don't have the insn to
+;; generate the fixup swizzle to avoid double rounding problems.
(define_expand "floatsisf2"
[(set (match_operand:SF 0 "gpc_reg_operand" "")
- (float:SF (match_operand:SI 1 "gpc_reg_operand" "")))]
- "TARGET_HARD_FLOAT && !TARGET_FPRS"
- "")
+ (float:SF (match_operand:SI 1 "nonimmediate_operand" "")))]
+ "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT
+ && (!TARGET_FPRS
+ || (TARGET_FPRS
+ && ((TARGET_FCFIDS && TARGET_LFIWAX)
+ || (TARGET_DOUBLE_FLOAT && TARGET_FCFID
+ && (TARGET_POWERPC64 || flag_unsafe_math_optimizations)))))"
+ "
+{
+ if (!TARGET_FPRS)
+ {
+ if (!REG_P (operands[1]))
+ operands[1] = force_reg (SImode, operands[1]);
+ }
+ else if (TARGET_FCFIDS && TARGET_LFIWAX)
+ {
+ rs6000_expand_convert_si_to_sfdf (operands[0], operands[1], false);
+ DONE;
+ }
+ else
+ {
+ rtx dreg = operands[1];
+ if (!REG_P (dreg))
+ dreg = force_reg (SImode, dreg);
+ dreg = convert_to_mode (DImode, dreg, false);
+ emit_insn (gen_floatdisf2 (operands[0], dreg));
+ DONE;
+ }
+}")
(define_expand "floatdidf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "")
(float:DF (match_operand:DI 1 "gpc_reg_operand" "")))]
- "(TARGET_POWERPC64 || TARGET_XILINX_FPU || VECTOR_UNIT_VSX_P (DFmode))
- && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS"
+ "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS"
"")
(define_insn "*floatdidf2_fpr"
[(set (match_operand:DF 0 "gpc_reg_operand" "=d")
- (float:DF (match_operand:DI 1 "gpc_reg_operand" "!d#r")))]
- "(TARGET_POWERPC64 || TARGET_XILINX_FPU)
- && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
+ (float:DF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+ "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
&& !VECTOR_UNIT_VSX_P (DFmode)"
"fcfid %0,%1"
[(set_attr "type" "fp")])
+; Allow the combiner to merge source memory operands to the conversion so that
+; the optimizer/register allocator doesn't try to load the value too early in a
+; GPR and then use store/load to move it to a FPR and suffer from a store-load
+; hit. We will split after reload to avoid the trip through the GPRs
+
+(define_insn_and_split "*floatdidf2_mem"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+ (float:DF (match_operand:DI 1 "memory_operand" "m")))
+ (clobber (match_scratch:DI 2 "=d"))]
+ "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS && TARGET_FCFID"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (float:DF (match_dup 2)))]
+ ""
+ [(set_attr "length" "8")])
+
(define_expand "floatunsdidf2"
[(set (match_operand:DF 0 "gpc_reg_operand" "")
- (unsigned_float:DF (match_operand:DI 1 "gpc_reg_operand" "")))]
- "TARGET_VSX"
+ (unsigned_float:DF
+ (match_operand:DI 1 "gpc_reg_operand" "")))]
+ "TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode)"
"")
-(define_expand "fix_truncdfdi2"
- [(set (match_operand:DI 0 "gpc_reg_operand" "")
- (fix:DI (match_operand:DF 1 "gpc_reg_operand" "")))]
- "(TARGET_POWERPC64 || TARGET_XILINX_FPU || VECTOR_UNIT_VSX_P (DFmode))
- && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS"
- "")
+(define_insn "*floatunsdidf2_fcfidu"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+ (unsigned_float:DF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+ "TARGET_FCFIDU && !VECTOR_UNIT_VSX_P (DFmode)"
+ "fcfidu %0,%1"
+ [(set_attr "type" "fp")
+ (set_attr "length" "4")])
-(define_insn "*fix_truncdfdi2_fpr"
- [(set (match_operand:DI 0 "gpc_reg_operand" "=!d#r")
- (fix:DI (match_operand:DF 1 "gpc_reg_operand" "d")))]
- "(TARGET_POWERPC64 || TARGET_XILINX_FPU)
- && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS
- && !VECTOR_UNIT_VSX_P (DFmode)"
- "fctidz %0,%1"
- [(set_attr "type" "fp")])
+(define_insn_and_split "*floatunsdidf2_mem"
+ [(set (match_operand:DF 0 "gpc_reg_operand" "=d")
+ (unsigned_float:DF (match_operand:DI 1 "memory_operand" "m")))
+ (clobber (match_scratch:DI 2 "=d"))]
+ "TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode)"
+ "#"
+ "&& reload_completed"
+ [(set (match_dup 2) (match_dup 1))
+ (set (match_dup 0) (unsigned_float:DF (match_dup 2)))]
+ ""
+ [(set_attr "length" "8")])
(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 && TARGET_SINGLE_FLOAT "
+ "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+ && (TARGET_FCFIDS || TARGET_POWERPC64 || flag_unsafe_math_optimizations)"
"
{
- rtx val = operands[1];
- if (!flag_unsafe_math_optimizations)
+ if (!TARGET_FCFIDS)
{
- rtx label = gen_label_rtx ();
- val = gen_reg_rtx (DImode);
- emit_insn (gen_floatdisf2_internal2 (val, operands[1], label));
- emit_label (label);
+ rtx val = operands[1];
+ if (!flag_unsafe_math_optimizations)
+ {
+ rtx label = gen_label_rtx ();
+ val = gen_reg_rtx (DImode);
+ emit_insn (gen_floatdisf2_internal2 (val, operands[1], label));
+ emit_label (label);
+ }
+ emit_insn (gen_floatdisf2_internal1 (operands[0], val));
+ DONE;
}
- emit_insn (gen_floatdisf2_internal1 (operands[0], val));
- DONE;
}")
+(define_insn "floatdisf2_fcfids"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+ && TARGET_DOUBLE_FLOAT && TARGET_FCFIDS"
+ "fcfids %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn_and_split "*floatdisf2_mem"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (float:SF (match_operand:DI 1 "memory_operand" "m")))
+ (clobber (match_scratch:DI 2 "=f"))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+ && TARGET_DOUBLE_FLOAT && TARGET_FCFIDS"
+ "#"
+ "&& reload_completed"
+ [(pc)]
+ "
+{
+ emit_move_insn (operands[2], operands[1]);
+ emit_insn (gen_floatdisf2_fcfids (operands[0], operands[2]));
+ DONE;
+}"
+ [(set_attr "length" "8")])
+
;; 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" "!d#r")))
+ (float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))
(clobber (match_scratch:DF 2 "=d"))]
- "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
+ "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT"
"#"
"&& reload_completed"
[(set (match_dup 2)
@@ -6891,6 +7179,38 @@ (define_expand "floatdisf2_internal2"
operands[3] = gen_reg_rtx (DImode);
operands[4] = gen_reg_rtx (CCUNSmode);
}")
+
+(define_expand "floatunsdisf2"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "")
+ (unsigned_float:SF (match_operand:DI 1 "gpc_reg_operand" "")))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+ && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS"
+ "")
+
+(define_insn "floatunsdisf2_fcfidus"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (unsigned_float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+ && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS"
+ "fcfidus %0,%1"
+ [(set_attr "type" "fp")])
+
+(define_insn_and_split "*floatunsdisf2_mem"
+ [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
+ (unsigned_float:SF (match_operand:DI 1 "memory_operand" "m")))
+ (clobber (match_scratch:DI 2 "=f"))]
+ "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT
+ && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS"
+ "#"
+ "&& reload_completed"
+ [(pc)]
+ "
+{
+ emit_move_insn (operands[2], operands[1]);
+ emit_insn (gen_floatunsdisf2_fcfidus (operands[0], operands[2]));
+ DONE;
+}"
+ [(set_attr "length" "8")])
;; Define the DImode operations that can be done in a small number
;; of instructions. The & constraints are to prevent the register
===================================================================
@@ -1,6 +1,7 @@
/* Definitions of target machine for GNU compiler, for IBM RS/6000.
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ 2010
Free Software Foundation, Inc.
Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu)
@@ -554,6 +555,25 @@ extern int rs6000_vector_align[];
#define TARGET_E500_DOUBLE 0
#define CHECK_E500_OPTIONS do { } while (0)
+/* ISA 2.01 allowed FCFID to be done in 32-bit, previously it was 64-bit only.
+ Enable 32-bit fcfid's on any of the switches for newer ISA machines or
+ XILINX. */
+#define TARGET_FCFID (TARGET_POWERPC64 \
+ || TARGET_POPCNTB /* ISA 2.02 */ \
+ || TARGET_CMPB /* ISA 2.05 */ \
+ || TARGET_POPCNTD /* ISA 2.06 */ \
+ || TARGET_XILINX_FPU)
+
+#define TARGET_FCTIDZ TARGET_FCFID
+#define TARGET_STFIWX TARGET_PPC_GFXOPT
+#define TARGET_LFIWAX TARGET_CMPB
+#define TARGET_LFIWZX TARGET_POPCNTD
+#define TARGET_FCFIDS TARGET_POPCNTD
+#define TARGET_FCFIDU TARGET_POPCNTD
+#define TARGET_FCFIDUS TARGET_POPCNTD
+#define TARGET_FCTIDUZ TARGET_POPCNTD
+#define TARGET_FCTIWUZ TARGET_POPCNTD
+
/* E500 processors only support plain "sync", not lwsync. */
#define TARGET_NO_LWSYNC TARGET_E500
===================================================================
@@ -0,0 +1,50 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O2 -mcpu=power7 -ffast-math" } */
+/* { dg-final { scan-assembler-times "lfiwax" 2 } } */
+/* { dg-final { scan-assembler-times "lfiwzx" 2 } } */
+/* { dg-final { scan-assembler-times "fcfids" 3 } } */
+/* { dg-final { scan-assembler-times "fcfidus" 1 } } */
+/* { dg-final { scan-assembler-times "xscvsxddp" 3 } } */
+/* { dg-final { scan-assembler-times "xscvuxddp" 1 } } */
+
+void int_to_float (float *dest, int *src)
+{
+ *dest = (float) *src;
+}
+
+void int_to_double (double *dest, int *src)
+{
+ *dest = (double) *src;
+}
+
+void uint_to_float (float *dest, unsigned int *src)
+{
+ *dest = (float) *src;
+}
+
+void uint_to_double (double *dest, unsigned int *src)
+{
+ *dest = (double) *src;
+}
+
+void llong_to_float (float *dest, long long *src)
+{
+ *dest = (float) *src;
+}
+
+void llong_to_double (double *dest, long long *src)
+{
+ *dest = (double) *src;
+}
+
+void ullong_to_float (float *dest, unsigned long long *src)
+{
+ *dest = (float) *src;
+}
+
+void ullong_to_double (double *dest, unsigned long long *src)
+{
+ *dest = (double) *src;
+}
===================================================================
@@ -0,0 +1,51 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-O2 -mcpu=power6 -ffast-math" } */
+/* { dg-final { scan-assembler-times "lfiwax" 1 } } */
+/* { dg-final { scan-assembler-not "lfiwzx" } } */
+/* { dg-final { scan-assembler-times "fcfid " 10 } } */
+/* { dg-final { scan-assembler-not "fcfids" } } */
+/* { dg-final { scan-assembler-not "fcfidus" } } */
+/* { dg-final { scan-assembler-not "xscvsxddp" } } */
+/* { dg-final { scan-assembler-not "xscvuxddp" } } */
+
+void int_to_float (float *dest, int *src)
+{
+ *dest = (float) *src;
+}
+
+void int_to_double (double *dest, int *src)
+{
+ *dest = (double) *src;
+}
+
+void uint_to_float (float *dest, unsigned int *src)
+{
+ *dest = (float) *src;
+}
+
+void uint_to_double (double *dest, unsigned int *src)
+{
+ *dest = (double) *src;
+}
+
+void llong_to_float (float *dest, long long *src)
+{
+ *dest = (float) *src;
+}
+
+void llong_to_double (double *dest, long long *src)
+{
+ *dest = (double) *src;
+}
+
+void ullong_to_float (float *dest, unsigned long long *src)
+{
+ *dest = (float) *src;
+}
+
+void ullong_to_double (double *dest, unsigned long long *src)
+{
+ *dest = (double) *src;
+}
===================================================================
@@ -0,0 +1,51 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O2 -mcpu=power5 -ffast-math" } */
+/* { dg-final { scan-assembler-not "lfiwax" } } */
+/* { dg-final { scan-assembler-not "lfiwzx" } } */
+/* { dg-final { scan-assembler-times "fcfid " 10 } } */
+/* { dg-final { scan-assembler-not "fcfids" } } */
+/* { dg-final { scan-assembler-not "fcfidus" } } */
+/* { dg-final { scan-assembler-not "xscvsxddp" } } */
+/* { dg-final { scan-assembler-not "xscvuxddp" } } */
+
+void int_to_float (float *dest, int *src)
+{
+ *dest = (float) *src;
+}
+
+void int_to_double (double *dest, int *src)
+{
+ *dest = (double) *src;
+}
+
+void uint_to_float (float *dest, unsigned int *src)
+{
+ *dest = (float) *src;
+}
+
+void uint_to_double (double *dest, unsigned int *src)
+{
+ *dest = (double) *src;
+}
+
+void llong_to_float (float *dest, long long *src)
+{
+ *dest = (float) *src;
+}
+
+void llong_to_double (double *dest, long long *src)
+{
+ *dest = (double) *src;
+}
+
+void ullong_to_float (float *dest, unsigned long long *src)
+{
+ *dest = (float) *src;
+}
+
+void ullong_to_double (double *dest, unsigned long long *src)
+{
+ *dest = (double) *src;
+}
===================================================================
@@ -0,0 +1,51 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } { "*" } { "" } } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O2 -mcpu=750 -ffast-math" } */
+/* { dg-final { scan-assembler-not "lfiwax" } } */
+/* { dg-final { scan-assembler-not "lfiwzx" } } */
+/* { dg-final { scan-assembler-not "fcfid " } } */
+/* { dg-final { scan-assembler-not "fcfids" } } */
+/* { dg-final { scan-assembler-not "fcfidus" } } */
+/* { dg-final { scan-assembler-not "xscvsxddp" } } */
+/* { dg-final { scan-assembler-not "xscvuxddp" } } */
+
+void int_to_float (float *dest, int *src)
+{
+ *dest = (float) *src;
+}
+
+void int_to_double (double *dest, int *src)
+{
+ *dest = (double) *src;
+}
+
+void uint_to_float (float *dest, unsigned int *src)
+{
+ *dest = (float) *src;
+}
+
+void uint_to_double (double *dest, unsigned int *src)
+{
+ *dest = (double) *src;
+}
+
+void llong_to_float (float *dest, long long *src)
+{
+ *dest = (float) *src;
+}
+
+void llong_to_double (double *dest, long long *src)
+{
+ *dest = (double) *src;
+}
+
+void ullong_to_float (float *dest, unsigned long long *src)
+{
+ *dest = (float) *src;
+}
+
+void ullong_to_double (double *dest, unsigned long long *src)
+{
+ *dest = (double) *src;
+}