return;
}
-/* Split a conversion from __float128 to an integer type into separate insns.
- OPERANDS points to the destination, source, and V2DI temporary
- register. CODE is either FIX or UNSIGNED_FIX. */
-
-void
-convert_float128_to_int (rtx *operands, enum rtx_code code)
-{
- rtx dest = operands[0];
- rtx src = operands[1];
- rtx tmp = operands[2];
- rtx cvt;
- rtvec cvt_vec;
- rtx cvt_unspec;
- rtvec move_vec;
- rtx move_unspec;
-
- if (GET_CODE (tmp) == SCRATCH)
- tmp = gen_reg_rtx (V2DImode);
-
- if (MEM_P (dest))
- dest = rs6000_address_for_fpconvert (dest);
-
- /* Generate the actual convert insn of the form:
- (set (tmp) (unspec:V2DI [(fix:SI (reg:KF))] UNSPEC_IEEE128_CONVERT)). */
- cvt = gen_rtx_fmt_e (code, GET_MODE (dest), src);
- cvt_vec = gen_rtvec (1, cvt);
- cvt_unspec = gen_rtx_UNSPEC (V2DImode, cvt_vec, UNSPEC_IEEE128_CONVERT);
- emit_insn (gen_rtx_SET (tmp, cvt_unspec));
-
- /* Generate the move insn of the form:
- (set (dest:SI) (unspec:SI [(tmp:V2DI))] UNSPEC_IEEE128_MOVE)). */
- move_vec = gen_rtvec (1, tmp);
- move_unspec = gen_rtx_UNSPEC (GET_MODE (dest), move_vec, UNSPEC_IEEE128_MOVE);
- emit_insn (gen_rtx_SET (dest, move_unspec));
-}
-
-/* Split a conversion from an integer type to __float128 into separate insns.
- OPERANDS points to the destination, source, and V2DI temporary
- register. CODE is either FLOAT or UNSIGNED_FLOAT. */
-
-void
-convert_int_to_float128 (rtx *operands, enum rtx_code code)
-{
- rtx dest = operands[0];
- rtx src = operands[1];
- rtx tmp = operands[2];
- rtx cvt;
- rtvec cvt_vec;
- rtx cvt_unspec;
- rtvec move_vec;
- rtx move_unspec;
- rtx unsigned_flag;
-
- if (GET_CODE (tmp) == SCRATCH)
- tmp = gen_reg_rtx (V2DImode);
-
- if (MEM_P (src))
- src = rs6000_address_for_fpconvert (src);
-
- /* Generate the move of the integer into the Altivec register of the form:
- (set (tmp:V2DI) (unspec:V2DI [(src:SI)
- (const_int 0)] UNSPEC_IEEE128_MOVE)).
-
- or:
- (set (tmp:V2DI) (unspec:V2DI [(src:DI)] UNSPEC_IEEE128_MOVE)). */
-
- if (GET_MODE (src) == SImode)
- {
- unsigned_flag = (code == UNSIGNED_FLOAT) ? const1_rtx : const0_rtx;
- move_vec = gen_rtvec (2, src, unsigned_flag);
- }
- else
- move_vec = gen_rtvec (1, src);
-
- move_unspec = gen_rtx_UNSPEC (V2DImode, move_vec, UNSPEC_IEEE128_MOVE);
- emit_insn (gen_rtx_SET (tmp, move_unspec));
-
- /* Generate the actual convert insn of the form:
- (set (dest:KF) (float:KF (unspec:DI [(tmp:V2DI)]
- UNSPEC_IEEE128_CONVERT))). */
- cvt_vec = gen_rtvec (1, tmp);
- cvt_unspec = gen_rtx_UNSPEC (DImode, cvt_vec, UNSPEC_IEEE128_CONVERT);
- cvt = gen_rtx_fmt_e (code, GET_MODE (dest), cvt_unspec);
- emit_insn (gen_rtx_SET (dest, cvt));
-}
-
\f
/* Emit the RTL for an sISEL pattern. */
UNSPEC_FUSION_P9
UNSPEC_FUSION_ADDIS
UNSPEC_ROUND_TO_ODD
- UNSPEC_IEEE128_MOVE
- UNSPEC_IEEE128_CONVERT
UNSPEC_SIGNBIT
UNSPEC_SF_FROM_SI
UNSPEC_SI_FROM_SF
"")
(define_expand "floatsi<mode>2"
- [(set (match_operand:FLOAT128 0 "gpc_reg_operand" "")
- (float:FLOAT128 (match_operand:SI 1 "gpc_reg_operand" "")))]
+ [(parallel [(set (match_operand:FLOAT128 0 "gpc_reg_operand")
+ (float:FLOAT128 (match_operand:SI 1 "gpc_reg_operand")))
+ (clobber (match_scratch:DI 2))])]
"TARGET_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE)
&& TARGET_LONG_DOUBLE_128"
{
- if (FLOAT128_IEEE_P (<MODE>mode))
- rs6000_expand_float128_convert (operands[0], operands[1], false);
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+
+ if (TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode))
+ ;
+ else if (FLOAT128_IEEE_P (<MODE>mode))
+ {
+ rs6000_expand_float128_convert (op0, op1, false);
+ DONE;
+ }
else
{
rtx tmp = gen_reg_rtx (DFmode);
- expand_float (tmp, operands[1], false);
+ expand_float (tmp, op1, false);
if (<MODE>mode == TFmode)
- emit_insn (gen_extenddftf2 (operands[0], tmp));
+ emit_insn (gen_extenddftf2 (op0, tmp));
else if (<MODE>mode == IFmode)
- emit_insn (gen_extenddfif2 (operands[0], tmp));
+ emit_insn (gen_extenddfif2 (op0, tmp));
else
gcc_unreachable ();
+ DONE;
}
- DONE;
})
; fadd, but rounding towards zero.
"TARGET_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE) && TARGET_LONG_DOUBLE_128"
{
- if (FLOAT128_IEEE_P (<MODE>mode))
- rs6000_expand_float128_convert (operands[0], operands[1], false);
- else if (TARGET_E500_DOUBLE && <MODE>mode == TFmode)
- emit_insn (gen_spe_fix_trunctfsi2 (operands[0], operands[1]));
- else if (<MODE>mode == TFmode)
- emit_insn (gen_fix_trunctfsi2_fprs (operands[0], operands[1]));
- else if (<MODE>mode == IFmode)
- emit_insn (gen_fix_truncifsi2_fprs (operands[0], operands[1]));
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+
+ if (TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode))
+ ;
else
- gcc_unreachable ();
- DONE;
+ {
+ if (FLOAT128_IEEE_P (<MODE>mode))
+ rs6000_expand_float128_convert (op0, op1, false);
+ else if (TARGET_E500_DOUBLE && <MODE>mode == TFmode)
+ emit_insn (gen_spe_fix_trunctfsi2 (op0, op1));
+ else if (<MODE>mode == TFmode)
+ emit_insn (gen_fix_trunctfsi2_fprs (op0, op1));
+ else if (<MODE>mode == IFmode)
+ emit_insn (gen_fix_truncifsi2_fprs (op0, op1));
+ else
+ gcc_unreachable ();
+ DONE;
+ }
})
(define_expand "fix_trunc<mode>si2_fprs"
(fix:DI (match_operand:IEEE128 1 "gpc_reg_operand" "")))]
"TARGET_FLOAT128_TYPE"
{
- rs6000_expand_float128_convert (operands[0], operands[1], false);
- DONE;
+ if (!TARGET_FLOAT128_HW)
+ {
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ DONE;
+ }
})
(define_expand "fixuns_trunc<IEEE128:mode><SDI:mode>2"
(float:IEEE128 (match_operand:DI 1 "gpc_reg_operand" "")))]
"TARGET_FLOAT128_TYPE"
{
- rs6000_expand_float128_convert (operands[0], operands[1], false);
- DONE;
+ if (!TARGET_FLOAT128_HW)
+ {
+ rs6000_expand_float128_convert (operands[0], operands[1], false);
+ DONE;
+ }
})
-(define_expand "floatuns<SDI:mode><IEEE128:mode>2"
+(define_expand "floatunsdi<IEEE128:mode>2"
[(set (match_operand:IEEE128 0 "gpc_reg_operand" "")
- (unsigned_float:IEEE128 (match_operand:SDI 1 "gpc_reg_operand" "")))]
+ (unsigned_float:IEEE128 (match_operand:DI 1 "gpc_reg_operand" "")))]
"TARGET_FLOAT128_TYPE"
{
- rs6000_expand_float128_convert (operands[0], operands[1], true);
+ if (!TARGET_FLOAT128_HW)
+ {
+ rs6000_expand_float128_convert (operands[0], operands[1], true);
+ DONE;
+ }
+})
+
+(define_expand "floatuns<IEEE128:mode>2"
+ [(set (match_operand:IEEE128 0 "gpc_reg_operand" "")
+ (unsigned_float:IEEE128 (match_operand:SI 1 "gpc_reg_operand" "")))]
+ "TARGET_FLOAT128_TYPE"
+{
+ rtx op0 = operands[0];
+ rtx op1 = operands[1];
+
+ if (TARGET_FLOAT128_HW)
+ emit_insn (gen_floatuns_<IEEE128:mode>si2_hw (op0, op1));
+ else
+ rs6000_expand_float128_convert (op0, op1, true);
DONE;
})
[(set_attr "type" "vecfloat")
(set_attr "length" "8")])
-;; At present SImode is not allowed in VSX registers at all, and DImode is only
-;; allowed in the traditional floating point registers. Use V2DImode so that
-;; we can get a value in an Altivec register.
+;; Conversion between IEEE 128-bit and integer types
+(define_insn "fix_<mode>di2_hw"
+ [(set (match_operand:DI 0 "altivec_register_operand" "=v")
+ (fix:DI (match_operand:IEEE128 1 "altivec_register_operand" "v")))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xscvqpsdz %0,%1"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
-(define_insn_and_split "fix<uns>_<mode>si2_hw"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,Z")
- (any_fix:SI (match_operand:IEEE128 1 "altivec_register_operand" "v,v")))
- (clobber (match_scratch:V2DI 2 "=v,v"))]
+(define_insn "fixuns_<mode>di2_hw"
+ [(set (match_operand:DI 0 "altivec_register_operand" "=v")
+ (unsigned_fix:DI (match_operand:IEEE128 1 "altivec_register_operand" "v")))]
"TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
- "#"
- "&& 1"
- [(pc)]
-{
- convert_float128_to_int (operands, <CODE>);
- DONE;
-}
- [(set_attr "length" "8")
- (set_attr "type" "mftgpr,fpstore")])
+ "xscvqpudz %0,%1"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
-(define_insn_and_split "fix<uns>_<mode>di2_hw"
- [(set (match_operand:DI 0 "nonimmediate_operand" "=wr,wi,Z")
- (any_fix:DI (match_operand:IEEE128 1 "altivec_register_operand" "v,v,v")))
- (clobber (match_scratch:V2DI 2 "=v,v,v"))]
+(define_insn "fix_<mode>si2_hw"
+ [(set (match_operand:SI 0 "altivec_register_operand" "=v")
+ (fix:SI (match_operand:IEEE128 1 "altivec_register_operand" "v")))]
"TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
- "#"
- "&& 1"
- [(pc)]
-{
- convert_float128_to_int (operands, <CODE>);
- DONE;
-}
- [(set_attr "length" "8")
- (set_attr "type" "mftgpr,vecsimple,fpstore")])
+ "xscvqpswz %0,%1"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
-(define_insn_and_split "float<uns>_<mode>si2_hw"
- [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v,v")
- (any_float:IEEE128 (match_operand:SI 1 "nonimmediate_operand" "r,Z")))
- (clobber (match_scratch:V2DI 2 "=v,v"))]
+(define_insn "fixuns_<mode>si2_hw"
+ [(set (match_operand:SI 0 "altivec_register_operand" "=v")
+ (unsigned_fix:SI (match_operand:IEEE128 1 "altivec_register_operand" "v")))]
"TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
- "#"
- "&& 1"
- [(pc)]
-{
- convert_int_to_float128 (operands, <CODE>);
- DONE;
-}
- [(set_attr "length" "8")
- (set_attr "type" "vecfloat")])
+ "xscvqpuwz %0,%1"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
-(define_insn_and_split "float<uns>_<mode>di2_hw"
- [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v,v,v")
- (any_float:IEEE128 (match_operand:DI 1 "nonimmediate_operand" "wi,wr,Z")))
- (clobber (match_scratch:V2DI 2 "=v,v,v"))]
+;; Combiner pattern to prevent moving the result of converting an IEEE 128-bit
+;; floating point value to 32-bit integer to GPR in order to save it.
+(define_insn_and_split "*fix<uns>_<mode>_mem"
+ [(set (match_operand:SI 0 "memory_operand" "=Z")
+ (any_fix:SI (match_operand:IEEE128 1 "altivec_register_operand" "v")))
+ (clobber (match_scratch:SI 2 "=v"))]
"TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
"#"
- "&& 1"
- [(pc)]
-{
- convert_int_to_float128 (operands, <CODE>);
- DONE;
-}
- [(set_attr "length" "8")
- (set_attr "type" "vecfloat")])
-
-;; Integer conversion instructions, using V2DImode to get an Altivec register
-(define_insn "*xscvqp<su>wz_<mode>"
- [(set (match_operand:V2DI 0 "altivec_register_operand" "=v")
- (unspec:V2DI
- [(any_fix:SI
- (match_operand:IEEE128 1 "altivec_register_operand" "v"))]
- UNSPEC_IEEE128_CONVERT))]
+ "&& reload_completed"
+ [(set (match_dup 2)
+ (any_fix:SI (match_dup 1)))
+ (set (match_dup 0)
+ (match_dup 2))])
+
+(define_insn "float_<mode>di2_hw"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (float:IEEE128 (match_operand:DI 1 "altivec_register_operand" "v")))]
"TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
- "xscvqp<su>wz %0,%1"
+ "xscvsdqp %0,%1"
[(set_attr "type" "vecfloat")
(set_attr "size" "128")])
-(define_insn "*xscvqp<su>dz_<mode>"
- [(set (match_operand:V2DI 0 "altivec_register_operand" "=v")
- (unspec:V2DI
- [(any_fix:DI
- (match_operand:IEEE128 1 "altivec_register_operand" "v"))]
- UNSPEC_IEEE128_CONVERT))]
+(define_insn_and_split "float_<mode>si2_hw"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (float:IEEE128 (match_operand:SI 1 "nonimmediate_operand" "vrZ")))
+ (clobber (match_scratch:DI 2 "=v"))]
"TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
- "xscvqp<su>dz %0,%1"
- [(set_attr "type" "vecfloat")
- (set_attr "size" "128")])
+ "#"
+ "&& 1"
+ [(set (match_dup 2)
+ (sign_extend:DI (match_dup 1)))
+ (set (match_dup 0)
+ (float:IEEE128 (match_dup 2)))]
+{
+ if (GET_CODE (operands[2]) == SCRATCH)
+ operands[2] = gen_reg_rtx (DImode);
+})
-(define_insn "*xscv<su>dqp_<mode>"
+(define_insn "floatuns_<mode>di2_hw"
[(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
- (any_float:IEEE128
- (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v")]
- UNSPEC_IEEE128_CONVERT)))]
+ (unsigned_float:IEEE128
+ (match_operand:DI 1 "altivec_register_operand" "v")))]
"TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
- "xscv<su>dqp %0,%1"
+ "xscvudqp %0,%1"
[(set_attr "type" "vecfloat")
(set_attr "size" "128")])
-(define_insn "*ieee128_mfvsrd_64bit"
- [(set (match_operand:DI 0 "reg_or_indexed_operand" "=wr,Z,wi")
- (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v,v")]
- UNSPEC_IEEE128_MOVE))]
- "TARGET_FLOAT128_HW && TARGET_POWERPC64"
- "@
- mfvsrd %0,%x1
- stxsdx %x1,%y0
- xxlor %x0,%x1,%x1"
- [(set_attr "type" "mftgpr,fpstore,veclogical")])
-
-
-(define_insn "*ieee128_mfvsrd_32bit"
- [(set (match_operand:DI 0 "reg_or_indexed_operand" "=Z,wi")
- (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
- UNSPEC_IEEE128_MOVE))]
- "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
- "@
- stxsdx %x1,%y0
- xxlor %x0,%x1,%x1"
- [(set_attr "type" "fpstore,veclogical")])
-
-(define_insn "*ieee128_mfvsrwz"
- [(set (match_operand:SI 0 "reg_or_indexed_operand" "=r,Z")
- (unspec:SI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
- UNSPEC_IEEE128_MOVE))]
- "TARGET_FLOAT128_HW"
- "@
- mfvsrwz %0,%x1
- stxsiwx %x1,%y0"
- [(set_attr "type" "mftgpr,fpstore")])
-
-;; 0 says do sign-extension, 1 says zero-extension
-(define_insn "*ieee128_mtvsrw"
- [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v,v")
- (unspec:V2DI [(match_operand:SI 1 "nonimmediate_operand" "r,Z,r,Z")
- (match_operand:SI 2 "const_0_to_1_operand" "O,O,n,n")]
- UNSPEC_IEEE128_MOVE))]
- "TARGET_FLOAT128_HW"
- "@
- mtvsrwa %x0,%1
- lxsiwax %x0,%y1
- mtvsrwz %x0,%1
- lxsiwzx %x0,%y1"
- [(set_attr "type" "mffgpr,fpload,mffgpr,fpload")])
-
-
-(define_insn "*ieee128_mtvsrd_64bit"
- [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v")
- (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "wr,Z,wi")]
- UNSPEC_IEEE128_MOVE))]
- "TARGET_FLOAT128_HW && TARGET_POWERPC64"
- "@
- mtvsrd %x0,%1
- lxsdx %x0,%y1
- xxlor %x0,%x1,%x1"
- [(set_attr "type" "mffgpr,fpload,veclogical")])
-
-(define_insn "*ieee128_mtvsrd_32bit"
- [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v")
- (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "Z,wi")]
- UNSPEC_IEEE128_MOVE))]
- "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
- "@
- lxsdx %x0,%y1
- xxlor %x0,%x1,%x1"
- [(set_attr "type" "fpload,veclogical")])
+(define_insn_and_split "floatuns_<mode>si2_hw"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unsigned_float:IEEE128
+ (match_operand:SI 1 "nonimmediate_operand" "vrZ")))
+ (clobber (match_scratch:DI 2 "=v"))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "#"
+ "&& 1"
+ [(set (match_dup 2)
+ (zero_extend:DI (match_dup 1)))
+ (set (match_dup 0)
+ (float:IEEE128 (match_dup 2)))]
+{
+ if (GET_CODE (operands[2]) == SCRATCH)
+ operands[2] = gen_reg_rtx (DImode);
+})
;; IEEE 128-bit instructions with round to odd semantics
(define_insn "*trunc<mode>df2_odd"