===================================================================
@@ -239,6 +239,25 @@ (define_predicate "int_reg_operand"
return INT_REGNO_P (REGNO (op));
})
+;; Like int_reg_operand, but don't return true for pseudo registers
+(define_predicate "int_reg_operand_not_pseudo"
+ (match_operand 0 "register_operand")
+{
+ if ((TARGET_E500_DOUBLE || TARGET_SPE) && invalid_e500_subreg (op, mode))
+ return 0;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ if (!REG_P (op))
+ return 0;
+
+ if (REGNO (op) >= FIRST_PSEUDO_REGISTER)
+ return 0;
+
+ return INT_REGNO_P (REGNO (op));
+})
+
;; Like int_reg_operand, but only return true for base registers
(define_predicate "base_reg_operand"
(match_operand 0 "int_reg_operand")
===================================================================
@@ -348,6 +348,8 @@ (define_mode_iterator FP [
&& TARGET_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE)
&& TARGET_LONG_DOUBLE_128")
+ (IF "TARGET_FLOAT128")
+ (KF "TARGET_FLOAT128")
(DD "TARGET_DFP")
(TD "TARGET_DFP")])
@@ -365,9 +367,14 @@ (define_mode_iterator FMA_F [
(define_mode_iterator FMOVE32 [SF SD])
(define_mode_iterator FMOVE64 [DF DD])
(define_mode_iterator FMOVE64X [DI DF DD])
-(define_mode_iterator FMOVE128 [(TF "!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128")
+(define_mode_iterator FMOVE128 [(TF "TARGET_LONG_DOUBLE_128")
+ (IF "TARGET_LONG_DOUBLE_128")
(TD "TARGET_HARD_FLOAT && TARGET_FPRS")])
+(define_mode_iterator FMOVE128_FPR [(TF "FLOAT128_2REG_P (TFmode)")
+ (IF "FLOAT128_2REG_P (IFmode)")
+ (TD "TARGET_HARD_FLOAT && TARGET_FPRS")])
+
; Iterators for 128 bit types for direct move
(define_mode_iterator FMOVE128_GPR [(TI "TARGET_VSX_TIMODE")
(V16QI "")
@@ -376,7 +383,13 @@ (define_mode_iterator FMOVE128_GPR [(TI
(V4SF "")
(V2DI "")
(V2DF "")
- (V1TI "")])
+ (V1TI "")
+ (KF "")
+ (TF "")
+ (IF "")])
+
+; Iterator for 128-bit VSX types for pack/unpack
+(define_mode_iterator FMOVE128_VSX [V1TI KF])
; Whether a floating point move is ok, don't allow SD without hardware FP
(define_mode_attr fmove_ok [(SF "")
@@ -432,6 +445,25 @@ (define_mode_iterator RECIPF [SF DF V4SF
; Iterator for just SF/DF
(define_mode_iterator SFDF [SF DF])
+; Iterator for float128 floating conversions
+(define_mode_iterator FLOAT128_SFDFTF [
+ (SF "TARGET_FLOAT128")
+ (DF "TARGET_FLOAT128")
+ (TF "FLOAT128_IBM_P (TFmode)")
+ (IF "TARGET_FLOAT128")])
+
+; Iterator for special 128-bit floating point. This is for non-default
+; conversions, so TFmode is not used here.
+(define_mode_iterator IFKF [IF KF])
+
+; Iterator for 128-bit floating point that uses the IBM double-double format
+(define_mode_iterator IBM128 [IF TF])
+
+; Iterator for 128-bit floating point
+(define_mode_iterator TFIFKF [(KF "TARGET_FLOAT128")
+ (IF "TARGET_FLOAT128")
+ (TF "TARGET_LONG_DOUBLE_128")])
+
; SF/DF suffix for traditional floating instructions
(define_mode_attr Ftrad [(SF "s") (DF "")])
@@ -596,7 +628,7 @@ (define_mode_attr BOOL_REGS_UNARY [(TI "
;; Reload iterator for creating the function to allocate a base register to
;; supplement addressing modes.
(define_mode_iterator RELOAD [V16QI V8HI V4SI V2DI V4SF V2DF V1TI
- SF SD SI DF DD DI TI PTI])
+ SF SD SI DF DD DI TI PTI KF IF TF])
;; Start with fixed-point load and store insns. Here we put only the more
@@ -4216,19 +4248,18 @@ (define_insn "*truncdfsf2_fpr"
;; This expander is here to avoid FLOAT_WORDS_BIGENDIAN tests in
;; builtins.c and optabs.c that are not correct for IBM long double
;; when little-endian.
-(define_expand "signbittf2"
+(define_expand "signbit<mode>2"
[(set (match_dup 2)
- (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))
+ (float_truncate:DF (match_operand:IBM128 1 "gpc_reg_operand" "")))
(set (match_dup 3)
(subreg:DI (match_dup 2) 0))
(set (match_dup 4)
(match_dup 5))
(set (match_operand:SI 0 "gpc_reg_operand" "")
(match_dup 6))]
- "!TARGET_IEEEQUAD
+ "FLOAT128_IBM_P (<MODE>mode)
&& TARGET_HARD_FLOAT
- && (TARGET_FPRS || TARGET_E500_DOUBLE)
- && TARGET_LONG_DOUBLE_128"
+ && (TARGET_FPRS || TARGET_E500_DOUBLE)"
{
operands[2] = gen_reg_rtx (DFmode);
operands[3] = gen_reg_rtx (DImode);
@@ -6402,9 +6433,10 @@ (define_expand "mov<mode>"
;; problematical. Don't allow direct move for this case.
(define_insn_and_split "*mov<mode>_64bit_dm"
- [(set (match_operand:FMOVE128 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r,r,wm")
- (match_operand:FMOVE128 1 "input_operand" "d,m,d,j,r,jY,r,wm,r"))]
+ [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r,r,wm")
+ (match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,j,r,jY,r,wm,r"))]
"TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_POWERPC64
+ && FLOAT128_2REG_P (<MODE>mode)
&& (<MODE>mode != TDmode || WORDS_BIG_ENDIAN)
&& (gpc_reg_operand (operands[0], <MODE>mode)
|| gpc_reg_operand (operands[1], <MODE>mode))"
@@ -6427,9 +6459,12 @@ (define_insn_and_split "*movtd_64bit_nod
[(set_attr "length" "8,8,8,8,12,12,8")])
(define_insn_and_split "*mov<mode>_32bit"
- [(set (match_operand:FMOVE128 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r")
- (match_operand:FMOVE128 1 "input_operand" "d,m,d,j,r,jY,r"))]
+ [(set (match_operand:FMOVE128_FPR 0 "nonimmediate_operand" "=m,d,d,ws,Y,r,r")
+ (match_operand:FMOVE128_FPR 1 "input_operand" "d,m,d,j,r,jY,r"))]
"TARGET_HARD_FLOAT && TARGET_FPRS && !TARGET_POWERPC64
+ && (FLOAT128_2REG_P (<MODE>mode)
+ || int_reg_operand_not_pseudo (operands[0], <MODE>mode)
+ || int_reg_operand_not_pseudo (operands[1], <MODE>mode))
&& (gpc_reg_operand (operands[0], <MODE>mode)
|| gpc_reg_operand (operands[1], <MODE>mode))"
"#"
@@ -6663,20 +6698,37 @@ (define_insn_and_split "*fix_trunctfsi2_
DONE;
})
-(define_expand "negtf2"
- [(set (match_operand:TF 0 "gpc_reg_operand" "")
- (neg:TF (match_operand:TF 1 "gpc_reg_operand" "")))]
- "!TARGET_IEEEQUAD
- && TARGET_HARD_FLOAT
- && (TARGET_FPRS || TARGET_E500_DOUBLE)
- && TARGET_LONG_DOUBLE_128"
- "")
+(define_expand "neg<mode>2"
+ [(set (match_operand:TFIFKF 0 "gpc_reg_operand" "")
+ (neg:TFIFKF (match_operand:TFIFKF 1 "gpc_reg_operand" "")))]
+ "FLOAT128_IEEE_P (<MODE>mode)
+ || (FLOAT128_IBM_P (<MODE>mode)
+ && TARGET_HARD_FLOAT
+ && (TARGET_FPRS || TARGET_E500_DOUBLE))"
+ "
+{
+ if (FLOAT128_IEEE_P (<MODE>mode))
+ {
+ if (TARGET_FLOAT128)
+ emit_insn (gen_ieee_128bit_vsx_neg<mode>2 (operands[0], operands[1]));
+ else
+ {
+ rtx libfunc = optab_libfunc (neg_optab, <MODE>mode);
+ rtx target = emit_library_call_value (libfunc, operands[0], LCT_CONST,
+ <MODE>mode, 1,
+ operands[1], <MODE>mode);
+
+ if (target && !rtx_equal_p (target, operands[0]))
+ emit_move_insn (operands[0], target);
+ }
+ DONE;
+ }
+}")
(define_insn "negtf2_internal"
[(set (match_operand:TF 0 "gpc_reg_operand" "=d")
(neg:TF (match_operand:TF 1 "gpc_reg_operand" "d")))]
- "!TARGET_IEEEQUAD
- && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128"
+ "TARGET_HARD_FLOAT && TARGET_FPRS && FLOAT128_IBM_P (TFmode)"
"*
{
if (REGNO (operands[0]) == REGNO (operands[1]) + 1)
@@ -6687,16 +6739,29 @@ (define_insn "negtf2_internal"
[(set_attr "type" "fp")
(set_attr "length" "8")])
-(define_expand "abstf2"
- [(set (match_operand:TF 0 "gpc_reg_operand" "")
- (abs:TF (match_operand:TF 1 "gpc_reg_operand" "")))]
- "!TARGET_IEEEQUAD
- && TARGET_HARD_FLOAT
- && (TARGET_FPRS || TARGET_E500_DOUBLE)
- && TARGET_LONG_DOUBLE_128"
+(define_expand "abs<mode>2"
+ [(set (match_operand:TFIFKF 0 "gpc_reg_operand" "")
+ (abs:TFIFKF (match_operand:TFIFKF 1 "gpc_reg_operand" "")))]
+ "FLOAT128_IEEE_P (<MODE>mode)
+ || (FLOAT128_IBM_P (<MODE>mode)
+ && TARGET_HARD_FLOAT
+ && (TARGET_FPRS || TARGET_E500_DOUBLE))"
"
{
- rtx label = gen_label_rtx ();
+ rtx label;
+
+ if (FLOAT128_IEEE_P (<MODE>mode))
+ {
+ if (TARGET_FLOAT128)
+ {
+ emit_insn (gen_ieee_128bit_vsx_abs<mode>2 (operands[0], operands[1]));
+ DONE;
+ }
+ else
+ FAIL;
+ }
+
+ label = gen_label_rtx ();
if (TARGET_E500_DOUBLE)
{
if (flag_finite_math_only && !flag_trapping_math)
@@ -6732,6 +6797,129 @@ (define_expand "abstf2_internal"
operands[5] = simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word);
operands[6] = simplify_gen_subreg (DFmode, operands[0], TFmode, lo_word);
}")
+
+
+;; Generate IEEE 128-bit -0.0 (0x80000000000000000000000000000000) in a vector
+;; register
+
+(define_expand "ieee_128bit_negative_zero"
+ [(set (match_operand:V16QI 0 "register_operand" "") (match_dup 1))]
+ "TARGET_FLOAT128"
+{
+ rtvec v = rtvec_alloc (16);
+ int i, high;
+
+ for (i = 0; i < 16; i++)
+ RTVEC_ELT (v, i) = const0_rtx;
+
+ high = (BYTES_BIG_ENDIAN) ? 0 : 15;
+ RTVEC_ELT (v, high) = GEN_INT (0x80);
+
+ rs6000_expand_vector_init (operands[0], gen_rtx_PARALLEL (V16QImode, v));
+ DONE;
+})
+
+;; IEEE 128-bit negate
+
+;; We have 2 insns here for negate and absolute value. The first uses
+;; match_scratch so that phases like combine can recognize neg/abs as generic
+;; insns, and second insn after the first split pass loads up the bit to
+;; twiddle the sign bit. Later GCSE passes can then combine multiple uses of
+;; neg/abs to create the constant just once.
+
+(define_insn_and_split "ieee_128bit_vsx_neg<mode>2"
+ [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+ (neg:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa")))
+ (clobber (match_scratch:V16QI 2 "=v"))]
+ "TARGET_FLOAT128 && FLOAT128_IEEE_P (<MODE>mode)"
+ "#"
+ "&& 1"
+ [(parallel [(set (match_dup 0)
+ (neg:TFIFKF (match_dup 1)))
+ (use (match_dup 2))])]
+{
+ if (GET_CODE (operands[2]) == SCRATCH)
+ operands[2] = gen_reg_rtx (V16QImode);
+
+ operands[3] = gen_reg_rtx (V16QImode);
+ emit_insn (gen_ieee_128bit_negative_zero (operands[2]));
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "vecsimple")])
+
+(define_insn "*ieee_128bit_vsx_neg<mode>2_internal"
+ [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+ (neg:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa")))
+ (use (match_operand:V16QI 2 "register_operand" "=v"))]
+ "TARGET_FLOAT128"
+ "xxlxor %x0,%x1,%x2"
+ [(set_attr "length" "4")
+ (set_attr "type" "vecsimple")])
+
+;; IEEE 128-bit absolute value
+(define_insn_and_split "ieee_128bit_vsx_abs<mode>2"
+ [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+ (abs:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa")))
+ (clobber (match_scratch:V16QI 2 "=v"))]
+ "TARGET_FLOAT128 && FLOAT128_IEEE_P (<MODE>mode)"
+ "#"
+ "&& 1"
+ [(parallel [(set (match_dup 0)
+ (abs:TFIFKF (match_dup 1)))
+ (use (match_dup 2))])]
+{
+ if (GET_CODE (operands[2]) == SCRATCH)
+ operands[2] = gen_reg_rtx (V16QImode);
+
+ operands[3] = gen_reg_rtx (V16QImode);
+ emit_insn (gen_ieee_128bit_negative_zero (operands[2]));
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "vecsimple")])
+
+(define_insn "*ieee_128bit_vsx_abs<mode>2_internal"
+ [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+ (abs:TFIFKF (match_operand:TFIFKF 1 "register_operand" "wa")))
+ (use (match_operand:V16QI 2 "register_operand" "=v"))]
+ "TARGET_FLOAT128"
+ "xxlandc %x0,%x1,%x2"
+ [(set_attr "length" "4")
+ (set_attr "type" "vecsimple")])
+
+;; IEEE 128-bit negative absolute value
+(define_insn_and_split "*ieee_128bit_vsx_nabs<mode>2"
+ [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+ (neg:TFIFKF
+ (abs:TFIFKF
+ (match_operand:TFIFKF 1 "register_operand" "wa"))))
+ (clobber (match_scratch:V16QI 2 "=v"))]
+ "TARGET_FLOAT128 && FLOAT128_IEEE_P (<MODE>mode)"
+ "#"
+ "&& 1"
+ [(parallel [(set (match_dup 0)
+ (abs:TFIFKF (match_dup 1)))
+ (use (match_dup 2))])]
+{
+ if (GET_CODE (operands[2]) == SCRATCH)
+ operands[2] = gen_reg_rtx (V16QImode);
+
+ operands[3] = gen_reg_rtx (V16QImode);
+ emit_insn (gen_ieee_128bit_negative_zero (operands[2]));
+}
+ [(set_attr "length" "8")
+ (set_attr "type" "vecsimple")])
+
+(define_insn "*ieee_128bit_vsx_nabs<mode>2_internal"
+ [(set (match_operand:TFIFKF 0 "register_operand" "=wa")
+ (neg:TFIFKF
+ (abs:TFIFKF
+ (match_operand:TFIFKF 1 "register_operand" "wa"))))
+ (use (match_operand:V16QI 2 "register_operand" "=v"))]
+ "TARGET_FLOAT128"
+ "xxlor %x0,%x1,%x2"
+ [(set_attr "length" "4")
+ (set_attr "type" "vecsimple")])
+
;; Reload helper functions used by rs6000_secondary_reload. The patterns all
;; must have 3 arguments, and scratch register constraint must be a single
@@ -12134,7 +12322,10 @@ (define_insn "div<div_extend>_<mode>"
;; Pack/unpack 128-bit floating point types that take 2 scalar registers
; Type of the 64-bit part when packing/unpacking 128-bit floating point types
-(define_mode_attr FP128_64 [(TF "DF") (TD "DI")])
+(define_mode_attr FP128_64 [(TF "DF")
+ (IF "DF")
+ (TD "DI")
+ (KF "DI")])
(define_expand "unpack<mode>"
[(set (match_operand:<FP128_64> 0 "nonimmediate_operand" "")
@@ -12142,7 +12333,7 @@ (define_expand "unpack<mode>"
[(match_operand:FMOVE128 1 "register_operand" "")
(match_operand:QI 2 "const_0_to_1_operand" "")]
UNSPEC_UNPACK_128BIT))]
- ""
+ "FLOAT128_2REG_P (<MODE>mode)"
"")
(define_insn_and_split "unpack<mode>_dm"
@@ -12151,7 +12342,7 @@ (define_insn_and_split "unpack<mode>_dm"
[(match_operand:FMOVE128 1 "register_operand" "d,d,r,d,r")
(match_operand:QI 2 "const_0_to_1_operand" "i,i,i,i,i")]
UNSPEC_UNPACK_128BIT))]
- "TARGET_POWERPC64 && TARGET_DIRECT_MOVE"
+ "TARGET_POWERPC64 && TARGET_DIRECT_MOVE && FLOAT128_2REG_P (<MODE>mode)"
"#"
"&& reload_completed"
[(set (match_dup 0) (match_dup 3))]
@@ -12175,7 +12366,7 @@ (define_insn_and_split "unpack<mode>_nod
[(match_operand:FMOVE128 1 "register_operand" "d,d")
(match_operand:QI 2 "const_0_to_1_operand" "i,i")]
UNSPEC_UNPACK_128BIT))]
- "!TARGET_POWERPC64 || !TARGET_DIRECT_MOVE"
+ "(!TARGET_POWERPC64 || !TARGET_DIRECT_MOVE) && FLOAT128_2REG_P (<MODE>mode)"
"#"
"&& reload_completed"
[(set (match_dup 0) (match_dup 3))]
@@ -12199,7 +12390,7 @@ (define_insn_and_split "pack<mode>"
[(match_operand:<FP128_64> 1 "register_operand" "0,d")
(match_operand:<FP128_64> 2 "register_operand" "d,d")]
UNSPEC_PACK_128BIT))]
- ""
+ "FLOAT128_2REG_P (<MODE>mode)"
"@
fmr %L0,%2
#"
@@ -12219,12 +12410,12 @@ (define_insn_and_split "pack<mode>"
[(set_attr "type" "fp,fp")
(set_attr "length" "4,8")])
-(define_insn "unpackv1ti"
+(define_insn "unpack<mode>"
[(set (match_operand:DI 0 "register_operand" "=d,d")
- (unspec:DI [(match_operand:V1TI 1 "register_operand" "0,wa")
+ (unspec:DI [(match_operand:FMOVE128_VSX 1 "register_operand" "0,wa")
(match_operand:QI 2 "const_0_to_1_operand" "O,i")]
UNSPEC_UNPACK_128BIT))]
- "TARGET_VSX"
+ "VECTOR_MEM_ALTIVEC_OR_VSX_P (<MODE>mode)"
{
if (REGNO (operands[0]) == REGNO (operands[1]) && INTVAL (operands[2]) == 0)
return ASM_COMMENT_START " xxpermdi to same register";
@@ -12235,9 +12426,9 @@ (define_insn "unpackv1ti"
[(set_attr "type" "vecperm")
(set_attr "length" "4")])
-(define_insn "packv1ti"
- [(set (match_operand:V1TI 0 "register_operand" "=wa")
- (unspec:V1TI
+(define_insn "pack<mode>"
+ [(set (match_operand:FMOVE128_VSX 0 "register_operand" "=wa")
+ (unspec:FMOVE128_VSX
[(match_operand:DI 1 "register_operand" "d")
(match_operand:DI 2 "register_operand" "d")]
UNSPEC_PACK_128BIT))]