ix86_expand_fp_absneg_operator (enum rtx_code code, machine_mode mode,
rtx operands[])
{
- rtx mask, set, dst, src;
+ rtx set, dst, src;
bool use_sse = false;
bool vector_mode = VECTOR_MODE_P (mode);
machine_mode vmode = mode;
+ rtvec par;
if (vector_mode)
use_sse = true;
vmode = V2DFmode;
}
- /* NEG and ABS performed with SSE use bitwise mask operations.
- Create the appropriate mask now. */
- if (use_sse)
- mask = ix86_build_signbit_mask (vmode, vector_mode, code == ABS);
- else
- mask = NULL_RTX;
-
dst = operands[0];
src = operands[1];
set = gen_rtx_fmt_e (code, mode, src);
set = gen_rtx_SET (dst, set);
- if (mask)
+ if (use_sse)
{
- rtx use, clob;
- rtvec par;
+ rtx mask, use, clob;
+ /* NEG and ABS performed with SSE use bitwise mask operations.
+ Create the appropriate mask now. */
+ mask = ix86_build_signbit_mask (vmode, vector_mode, code == ABS);
use = gen_rtx_USE (VOIDmode, mask);
if (vector_mode)
par = gen_rtvec (2, set, use);
clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
par = gen_rtvec (3, set, use, clob);
}
- emit_insn (gen_rtx_PARALLEL (VOIDmode, par));
}
else
- emit_insn (set);
+ {
+ rtx clob;
+
+ /* Changing of sign for FP values is doable using integer unit too. */
+ clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+ par = gen_rtvec (2, set, clob);
+ }
+
+ emit_insn (gen_rtx_PARALLEL (VOIDmode, par));
+}
+
+/* Deconstruct a floating point ABS or NEG operation
+ with integer registers into integer operations. */
+
+void
+ix86_split_fp_absneg_operator (enum rtx_code code, machine_mode mode,
+ rtx operands[])
+{
+ enum rtx_code absneg_op;
+ rtx dst, set;
+
+ gcc_assert (operands_match_p (operands[0], operands[1]));
+
+ switch (mode)
+ {
+ case E_SFmode:
+ dst = gen_lowpart (SImode, operands[0]);
+
+ if (code == ABS)
+ {
+ set = gen_int_mode (0x7fffffff, SImode);
+ absneg_op = AND;
+ }
+ else
+ {
+ set = gen_int_mode (0x80000000, SImode);
+ absneg_op = XOR;
+ }
+ set = gen_rtx_fmt_ee (absneg_op, SImode, dst, set);
+ break;
+
+ case E_DFmode:
+ if (TARGET_64BIT)
+ {
+ dst = gen_lowpart (DImode, operands[0]);
+ dst = gen_rtx_ZERO_EXTRACT (DImode, dst, const1_rtx, GEN_INT (63));
+
+ if (code == ABS)
+ set = const0_rtx;
+ else
+ set = gen_rtx_NOT (DImode, dst);
+ }
+ else
+ {
+ dst = gen_highpart (SImode, operands[0]);
+
+ if (code == ABS)
+ {
+ set = gen_int_mode (0x7fffffff, SImode);
+ absneg_op = AND;
+ }
+ else
+ {
+ set = gen_int_mode (0x80000000, SImode);
+ absneg_op = XOR;
+ }
+ set = gen_rtx_fmt_ee (absneg_op, SImode, dst, set);
+ }
+ break;
+
+ case E_XFmode:
+ dst = gen_rtx_REG (SImode,
+ REGNO (operands[0]) + (TARGET_64BIT ? 1 : 2));
+ if (code == ABS)
+ {
+ set = GEN_INT (0x7fff);
+ absneg_op = AND;
+ }
+ else
+ {
+ set = GEN_INT (0x8000);
+ absneg_op = XOR;
+ }
+ set = gen_rtx_fmt_ee (absneg_op, SImode, dst, set);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ set = gen_rtx_SET (dst, set);
+
+ rtx clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+ rtvec par = gen_rtvec (2, set, clob);
+
+ emit_insn (gen_rtx_PARALLEL (VOIDmode, par));
}
/* Expand a copysign operation. Special case operand 0 being a constant. */
;; All x87 floating point modes
(define_mode_iterator X87MODEF [SF DF XF])
+;; All SSE floating point modes
+(define_mode_iterator SSEMODEF [SF DF TF])
+(define_mode_attr ssevecmodef [(SF "V4SF") (DF "V2DF") (TF "TF")])
+
;; SSE instruction suffix for various modes
(define_mode_attr ssemodesuffix
[(SF "ss") (DF "sd")
[(set_attr "type" "negnot")
(set_attr "mode" "<MODE>")])
-;; Changing of sign for FP values is doable using integer unit too.
+(define_expand "<code>tf2"
+ [(set (match_operand:TF 0 "register_operand")
+ (absneg:TF (match_operand:TF 1 "register_operand")))]
+ "TARGET_SSE"
+ "ix86_expand_fp_absneg_operator (<CODE>, TFmode, operands); DONE;")
+
+(define_insn "*<code>tf2_1"
+ [(set (match_operand:TF 0 "register_operand" "=x,x,Yv,Yv")
+ (absneg:TF
+ (match_operand:TF 1 "vector_operand" "0,xBm,Yv,m")))
+ (use (match_operand:TF 2 "vector_operand" "xBm,0,Yvm,Yv"))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_SSE"
+ "#"
+ [(set_attr "isa" "noavx,noavx,avx,avx")])
(define_expand "<code><mode>2"
[(set (match_operand:X87MODEF 0 "register_operand")
"TARGET_80387 || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
"ix86_expand_fp_absneg_operator (<CODE>, <MODE>mode, operands); DONE;")
-(define_insn "*absneg<mode>2"
- [(set (match_operand:MODEF 0 "register_operand" "=Yv,Yv,f,!r")
- (match_operator:MODEF 3 "absneg_operator"
- [(match_operand:MODEF 1 "register_operand" "0,Yv,0,0")]))
- (use (match_operand:<ssevecmode> 2 "nonimmediate_operand" "Yvm,0,X,X"))
+;; Changing of sign for FP values is doable using integer unit too.
+(define_insn "*<code><mode>2_i387_1"
+ [(set (match_operand:X87MODEF 0 "register_operand" "=f,!r")
+ (absneg:X87MODEF
+ (match_operand:X87MODEF 1 "register_operand" "0,0")))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_80387"
+ "#")
+
+(define_split
+ [(set (match_operand:X87MODEF 0 "fp_register_operand")
+ (absneg:X87MODEF (match_operand:X87MODEF 1 "fp_register_operand")))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_80387 && reload_completed"
+ [(set (match_dup 0) (absneg:X87MODEF (match_dup 1)))])
+
+(define_split
+ [(set (match_operand:X87MODEF 0 "general_reg_operand")
+ (absneg:X87MODEF (match_operand:X87MODEF 1 "general_reg_operand")))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_80387 && reload_completed"
+ [(const_int 0)]
+ "ix86_split_fp_absneg_operator (<CODE>, <MODE>mode, operands); DONE;")
+
+(define_insn "*<code><mode>2_1"
+ [(set (match_operand:MODEF 0 "register_operand" "=x,x,Yv,f,!r")
+ (absneg:MODEF
+ (match_operand:MODEF 1 "register_operand" "0,x,Yv,0,0")))
+ (use (match_operand:<ssevecmode> 2 "vector_operand" "xBm,0,Yvm,X,X"))
(clobber (reg:CC FLAGS_REG))]
"TARGET_80387 || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
"#"
- [(set (attr "enabled")
+ [(set_attr "isa" "noavx,noavx,avx,*,*")
+ (set (attr "enabled")
(if_then_else
(match_test ("SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH"))
(if_then_else
- (eq_attr "alternative" "2")
+ (eq_attr "alternative" "3,4")
(symbol_ref "TARGET_MIX_SSE_I387")
- (symbol_ref "true"))
+ (const_string "*"))
(if_then_else
- (eq_attr "alternative" "2,3")
+ (eq_attr "alternative" "3,4")
(symbol_ref "true")
(symbol_ref "false"))))])
-(define_insn "*absnegxf2_i387"
- [(set (match_operand:XF 0 "register_operand" "=f,!r")
- (match_operator:XF 3 "absneg_operator"
- [(match_operand:XF 1 "register_operand" "0,0")]))
- (use (match_operand 2))
- (clobber (reg:CC FLAGS_REG))]
- "TARGET_80387"
- "#")
-
-(define_expand "<code>tf2"
- [(set (match_operand:TF 0 "register_operand")
- (absneg:TF (match_operand:TF 1 "register_operand")))]
- "TARGET_SSE"
- "ix86_expand_fp_absneg_operator (<CODE>, TFmode, operands); DONE;")
-
-(define_insn "*absnegtf2_sse"
- [(set (match_operand:TF 0 "register_operand" "=Yv,Yv")
- (match_operator:TF 3 "absneg_operator"
- [(match_operand:TF 1 "register_operand" "0,Yv")]))
- (use (match_operand:TF 2 "nonimmediate_operand" "Yvm,0"))
- (clobber (reg:CC FLAGS_REG))]
- "TARGET_SSE"
- "#")
-
-;; Splitters for fp abs and neg.
-
(define_split
- [(set (match_operand 0 "fp_register_operand")
- (match_operator 1 "absneg_operator" [(match_dup 0)]))
- (use (match_operand 2))
+ [(set (match_operand:SSEMODEF 0 "sse_reg_operand")
+ (absneg:SSEMODEF
+ (match_operand:SSEMODEF 1 "vector_operand")))
+ (use (match_operand:<ssevecmodef> 2 "vector_operand"))
(clobber (reg:CC FLAGS_REG))]
- "reload_completed"
- [(set (match_dup 0) (match_op_dup 1 [(match_dup 0)]))])
-
-(define_split
- [(set (match_operand 0 "sse_reg_operand")
- (match_operator 3 "absneg_operator"
- [(match_operand 1 "register_operand")]))
- (use (match_operand 2 "nonimmediate_operand"))
- (clobber (reg:CC FLAGS_REG))]
- "reload_completed"
+ "((SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
+ || (TARGET_SSE && (<MODE>mode == TFmode)))
+ && reload_completed"
[(set (match_dup 0) (match_dup 3))]
{
- machine_mode mode = GET_MODE (operands[0]);
- machine_mode vmode = GET_MODE (operands[2]);
- rtx tmp;
+ machine_mode mode = <MODE>mode;
+ machine_mode vmode = <ssevecmodef>mode;
+ enum rtx_code absneg_op = <CODE> == ABS ? AND : XOR;
operands[0] = lowpart_subreg (vmode, operands[0], mode);
operands[1] = lowpart_subreg (vmode, operands[1], mode);
- if (operands_match_p (operands[0], operands[2]))
- std::swap (operands[1], operands[2]);
- if (GET_CODE (operands[3]) == ABS)
- tmp = gen_rtx_AND (vmode, operands[1], operands[2]);
- else
- tmp = gen_rtx_XOR (vmode, operands[1], operands[2]);
- operands[3] = tmp;
-})
-(define_split
- [(set (match_operand:SF 0 "general_reg_operand")
- (match_operator:SF 1 "absneg_operator" [(match_dup 0)]))
- (use (match_operand:V4SF 2))
- (clobber (reg:CC FLAGS_REG))]
- "reload_completed"
- [(parallel [(set (match_dup 0) (match_dup 1))
- (clobber (reg:CC FLAGS_REG))])]
-{
- rtx tmp;
- operands[0] = gen_lowpart (SImode, operands[0]);
- if (GET_CODE (operands[1]) == ABS)
+ if (TARGET_AVX)
{
- tmp = gen_int_mode (0x7fffffff, SImode);
- tmp = gen_rtx_AND (SImode, operands[0], tmp);
+ if (MEM_P (operands[1]))
+ std::swap (operands[1], operands[2]);
}
else
- {
- tmp = gen_int_mode (0x80000000, SImode);
- tmp = gen_rtx_XOR (SImode, operands[0], tmp);
- }
- operands[1] = tmp;
+ {
+ if (operands_match_p (operands[0], operands[2]))
+ std::swap (operands[1], operands[2]);
+ }
+
+ operands[3]
+ = gen_rtx_fmt_ee (absneg_op, vmode, operands[1], operands[2]);
})
(define_split
- [(set (match_operand:DF 0 "general_reg_operand")
- (match_operator:DF 1 "absneg_operator" [(match_dup 0)]))
+ [(set (match_operand:MODEF 0 "fp_register_operand")
+ (absneg:MODEF (match_operand:MODEF 1 "fp_register_operand")))
(use (match_operand 2))
(clobber (reg:CC FLAGS_REG))]
- "reload_completed"
- [(parallel [(set (match_dup 0) (match_dup 1))
- (clobber (reg:CC FLAGS_REG))])]
-{
- rtx tmp;
- if (TARGET_64BIT)
- {
- tmp = gen_lowpart (DImode, operands[0]);
- tmp = gen_rtx_ZERO_EXTRACT (DImode, tmp, const1_rtx, GEN_INT (63));
- operands[0] = tmp;
-
- if (GET_CODE (operands[1]) == ABS)
- tmp = const0_rtx;
- else
- tmp = gen_rtx_NOT (DImode, tmp);
- }
- else
- {
- operands[0] = gen_highpart (SImode, operands[0]);
- if (GET_CODE (operands[1]) == ABS)
- {
- tmp = gen_int_mode (0x7fffffff, SImode);
- tmp = gen_rtx_AND (SImode, operands[0], tmp);
- }
- else
- {
- tmp = gen_int_mode (0x80000000, SImode);
- tmp = gen_rtx_XOR (SImode, operands[0], tmp);
- }
- }
- operands[1] = tmp;
-})
+ "TARGET_80387 && reload_completed"
+ [(set (match_dup 0) (absneg:X87MODEF (match_dup 1)))])
(define_split
- [(set (match_operand:XF 0 "general_reg_operand")
- (match_operator:XF 1 "absneg_operator" [(match_dup 0)]))
+ [(set (match_operand:MODEF 0 "general_reg_operand")
+ (absneg:MODEF (match_operand:MODEF 1 "general_reg_operand")))
(use (match_operand 2))
(clobber (reg:CC FLAGS_REG))]
- "reload_completed"
- [(parallel [(set (match_dup 0) (match_dup 1))
- (clobber (reg:CC FLAGS_REG))])]
-{
- rtx tmp;
- operands[0] = gen_rtx_REG (SImode,
- REGNO (operands[0]) + (TARGET_64BIT ? 1 : 2));
- if (GET_CODE (operands[1]) == ABS)
- {
- tmp = GEN_INT (0x7fff);
- tmp = gen_rtx_AND (SImode, operands[0], tmp);
- }
- else
- {
- tmp = GEN_INT (0x8000);
- tmp = gen_rtx_XOR (SImode, operands[0], tmp);
- }
- operands[1] = tmp;
-})
+ "TARGET_80387 && reload_completed"
+ [(const_int 0)]
+ "ix86_split_fp_absneg_operator (<CODE>, <MODE>mode, operands); DONE;")
;; Conditionalize these after reload. If they match before reload, we
;; lose the clobber and ability to use integer instructions.
-(define_insn "*<code><mode>2_1"
+(define_insn "*<code><mode>2_i387"
[(set (match_operand:X87MODEF 0 "register_operand" "=f")
(absneg:X87MODEF (match_operand:X87MODEF 1 "register_operand" "0")))]
- "TARGET_80387
- && (reload_completed
- || !(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH))"
+ "TARGET_80387 && reload_completed"
"<absneg_mnemonic>"
[(set_attr "type" "fsgn")
(set_attr "mode" "<MODE>")])
;; Copysign instructions
-(define_mode_iterator CSGNMODE [SF DF TF])
-(define_mode_attr CSGNVMODE [(SF "V4SF") (DF "V2DF") (TF "TF")])
-
(define_expand "copysign<mode>3"
- [(match_operand:CSGNMODE 0 "register_operand")
- (match_operand:CSGNMODE 1 "nonmemory_operand")
- (match_operand:CSGNMODE 2 "register_operand")]
+ [(match_operand:SSEMODEF 0 "register_operand")
+ (match_operand:SSEMODEF 1 "nonmemory_operand")
+ (match_operand:SSEMODEF 2 "register_operand")]
"(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
|| (TARGET_SSE && (<MODE>mode == TFmode))"
"ix86_expand_copysign (operands); DONE;")
(define_insn_and_split "copysign<mode>3_const"
- [(set (match_operand:CSGNMODE 0 "register_operand" "=Yv")
- (unspec:CSGNMODE
- [(match_operand:<CSGNVMODE> 1 "nonimm_or_0_operand" "YvmC")
- (match_operand:CSGNMODE 2 "register_operand" "0")
- (match_operand:<CSGNVMODE> 3 "nonimmediate_operand" "Yvm")]
+ [(set (match_operand:SSEMODEF 0 "register_operand" "=Yv")
+ (unspec:SSEMODEF
+ [(match_operand:<ssevecmodef> 1 "nonimm_or_0_operand" "YvmC")
+ (match_operand:SSEMODEF 2 "register_operand" "0")
+ (match_operand:<ssevecmodef> 3 "nonimmediate_operand" "Yvm")]
UNSPEC_COPYSIGN))]
"(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
|| (TARGET_SSE && (<MODE>mode == TFmode))"
"ix86_split_copysign_const (operands); DONE;")
(define_insn "copysign<mode>3_var"
- [(set (match_operand:CSGNMODE 0 "register_operand" "=Yv,Yv,Yv,Yv,Yv")
- (unspec:CSGNMODE
- [(match_operand:CSGNMODE 2 "register_operand" "Yv,0,0,Yv,Yv")
- (match_operand:CSGNMODE 3 "register_operand" "1,1,Yv,1,Yv")
- (match_operand:<CSGNVMODE> 4
+ [(set (match_operand:SSEMODEF 0 "register_operand" "=Yv,Yv,Yv,Yv,Yv")
+ (unspec:SSEMODEF
+ [(match_operand:SSEMODEF 2 "register_operand" "Yv,0,0,Yv,Yv")
+ (match_operand:SSEMODEF 3 "register_operand" "1,1,Yv,1,Yv")
+ (match_operand:<ssevecmodef> 4
"nonimmediate_operand" "X,Yvm,Yvm,0,0")
- (match_operand:<CSGNVMODE> 5
+ (match_operand:<ssevecmodef> 5
"nonimmediate_operand" "0,Yvm,1,Yvm,1")]
UNSPEC_COPYSIGN))
- (clobber (match_scratch:<CSGNVMODE> 1 "=Yv,Yv,Yv,Yv,Yv"))]
+ (clobber (match_scratch:<ssevecmodef> 1 "=Yv,Yv,Yv,Yv,Yv"))]
"(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
|| (TARGET_SSE && (<MODE>mode == TFmode))"
"#")
(define_split
- [(set (match_operand:CSGNMODE 0 "register_operand")
- (unspec:CSGNMODE
- [(match_operand:CSGNMODE 2 "register_operand")
- (match_operand:CSGNMODE 3 "register_operand")
- (match_operand:<CSGNVMODE> 4)
- (match_operand:<CSGNVMODE> 5)]
+ [(set (match_operand:SSEMODEF 0 "register_operand")
+ (unspec:SSEMODEF
+ [(match_operand:SSEMODEF 2 "register_operand")
+ (match_operand:SSEMODEF 3 "register_operand")
+ (match_operand:<ssevecmodef> 4)
+ (match_operand:<ssevecmodef> 5)]
UNSPEC_COPYSIGN))
- (clobber (match_scratch:<CSGNVMODE> 1))]
+ (clobber (match_scratch:<ssevecmodef> 1))]
"((SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
|| (TARGET_SSE && (<MODE>mode == TFmode)))
&& reload_completed"