src1 = force_reg (mode, src1);
}
- /* If the operation is not commutable, source 1 cannot be a constant. */
- if (CONSTANT_P (src1) && GET_RTX_CLASS (code) != 'c')
+ /* If the operation is not commutable, source 1 cannot be a constant
+ or non-matching memory. */
+ if ((CONSTANT_P (src1)
+ || (!matching_memory && GET_CODE (src1) == MEM))
+ && GET_RTX_CLASS (code) != 'c')
src1 = force_reg (mode, src1);
/* If optimizing, copy to regs to improve CSE */
|| (GET_RTX_CLASS (code) == 'c'
&& rtx_equal_p (operands[0], operands[2]))))
return 0;
+ /* If the operation is not commutable and the source 1 is memory, we must
+ have a matching destionation. */
+ if (GET_CODE (operands[1]) == MEM
+ && GET_RTX_CLASS (code) != 'c'
+ && ! rtx_equal_p (operands[0], operands[1]))
+ return 0;
return 1;
}
enum machine_mode mode;
rtx operands[];
{
- /* If optimizing, copy to regs to improve CSE */
- if (optimize
- && ((reload_in_progress | reload_completed) == 0)
- && GET_CODE (operands[1]) == MEM)
- operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+ int matching_memory;
+ rtx src, dst, op, clob;
+
+ dst = operands[0];
+ src = operands[1];
- if (! ix86_unary_operator_ok (code, mode, operands))
+ /* If the destination is memory, and we do not have matching source
+ operands, do things in registers. */
+ matching_memory = 0;
+ if (GET_CODE (dst) == MEM)
{
- if (optimize == 0
- && ((reload_in_progress | reload_completed) == 0)
- && GET_CODE (operands[1]) == MEM)
- {
- operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
- if (! ix86_unary_operator_ok (code, mode, operands))
- return FALSE;
- }
+ if (rtx_equal_p (dst, src))
+ matching_memory = 1;
else
- return FALSE;
+ dst = gen_reg_rtx (mode);
}
- return TRUE;
+ /* When source operand is memory, destination must match. */
+ if (!matching_memory && GET_CODE (src) == MEM)
+ src = force_reg (mode, src);
+
+ /* If optimizing, copy to regs to improve CSE */
+ if (optimize && !reload_in_progress && !reload_completed)
+ {
+ if (GET_CODE (dst) == MEM)
+ dst = gen_reg_rtx (mode);
+ if (GET_CODE (src) == MEM)
+ src = force_reg (mode, src);
+ }
+
+ /* Emit the instruction. */
+
+ op = gen_rtx_SET (VOIDmode, dst, gen_rtx_fmt_e (code, mode, src));
+ if (reload_in_progress || code == NOT)
+ {
+ /* Reload doesn't know about the flags register, and doesn't know that
+ it doesn't want to clobber it. */
+ if (code != NOT)
+ abort ();
+ emit_insn (op);
+ }
+ else
+ {
+ clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+ emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, op, clob)));
+ }
+
+ /* Fix up the destination if needed. */
+ if (dst != operands[0])
+ emit_move_insn (operands[0], dst);
}
/* Return TRUE or FALSE depending on whether the unary operator meets the
enum machine_mode mode ATTRIBUTE_UNUSED;
rtx operands[2] ATTRIBUTE_UNUSED;
{
+ /* If one of operands is memory, source and destination must match. */
+ if ((GET_CODE (operands[0]) == MEM
+ || GET_CODE (operands[1]) == MEM)
+ && ! rtx_equal_p (operands[0], operands[1]))
+ return FALSE;
return TRUE;
}
(define_expand "adddf3"
[(set (match_operand:DF 0 "register_operand" "")
- (plus:DF (match_operand:DF 1 "nonimmediate_operand" "")
+ (plus:DF (match_operand:DF 1 "register_operand" "")
(match_operand:DF 2 "nonimmediate_operand" "")))]
"TARGET_80387"
"")
(define_expand "addsf3"
[(set (match_operand:SF 0 "register_operand" "")
- (plus:SF (match_operand:SF 1 "nonimmediate_operand" "")
+ (plus:SF (match_operand:SF 1 "register_operand" "")
(match_operand:SF 2 "nonimmediate_operand" "")))]
"TARGET_80387"
"")
(define_expand "subdf3"
[(set (match_operand:DF 0 "register_operand" "")
- (minus:DF (match_operand:DF 1 "nonimmediate_operand" "")
+ (minus:DF (match_operand:DF 1 "register_operand" "")
(match_operand:DF 2 "nonimmediate_operand" "")))]
"TARGET_80387"
"")
(define_expand "subsf3"
[(set (match_operand:SF 0 "register_operand" "")
- (minus:SF (match_operand:SF 1 "nonimmediate_operand" "")
+ (minus:SF (match_operand:SF 1 "register_operand" "")
(match_operand:SF 2 "nonimmediate_operand" "")))]
"TARGET_80387"
"")
;; %%% define_expand from the very first?
-(define_insn "negdi2"
+(define_expand "negdi2"
+ [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (neg:DI (match_operand:DI 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ ""
+ "ix86_expand_unary_operator (NEG, DImode, operands); DONE;")
+
+(define_insn "*negdi2_1"
[(set (match_operand:DI 0 "nonimmediate_operand" "=ro")
(neg:DI (match_operand:DI 1 "general_operand" "0")))
(clobber (reg:CC 17))]
- ""
+ "ix86_unary_operator_ok (NEG, DImode, operands)"
"#")
(define_split
"split_di (operands+1, 1, operands+2, operands+3);
split_di (operands+0, 1, operands+0, operands+1);")
-(define_insn "negsi2"
+(define_expand "negsi2"
+ [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (neg:SI (match_operand:SI 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ ""
+ "ix86_expand_unary_operator (NEG, SImode, operands); DONE;")
+
+(define_insn "*negsi2_1"
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))
(clobber (reg:CC 17))]
- ""
+ "ix86_unary_operator_ok (NEG, SImode, operands)"
"neg{l}\\t%0"
[(set_attr "type" "negnot")])
(const_int 0)))
(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(neg:SI (match_dup 1)))]
- ""
+ "ix86_unary_operator_ok (NEG, SImode, operands)"
"neg{l}\\t%0"
[(set_attr "type" "negnot")])
(const_int 0)))
(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(neg:SI (match_dup 1)))]
- ""
+ "ix86_unary_operator_ok (NEG, SImode, operands)"
"neg{l}\\t%0"
[(set_attr "type" "negnot")])
-(define_insn "neghi2"
+(define_expand "neghi2"
+ [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (neg:HI (match_operand:HI 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ ""
+ "ix86_expand_unary_operator (NEG, HImode, operands); DONE;")
+
+(define_insn "*neghi2_1"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
(neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))
(clobber (reg:CC 17))]
- ""
+ "ix86_unary_operator_ok (NEG, HImode, operands)"
"neg{w}\\t%0"
[(set_attr "type" "negnot")])
(const_int 0)))
(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
(neg:HI (match_dup 1)))]
- ""
+ "ix86_unary_operator_ok (NEG, HImode, operands)"
"neg{w}\\t%0"
[(set_attr "type" "negnot")])
(const_int 0)))
(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
(neg:HI (match_dup 1)))]
- ""
+ "ix86_unary_operator_ok (NEG, HImode, operands)"
"neg{w}\\t%0"
[(set_attr "type" "negnot")])
-(define_insn "negqi2"
+(define_expand "negqi2"
+ [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (neg:QI (match_operand:QI 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ ""
+ "ix86_expand_unary_operator (NEG, QImode, operands); DONE;")
+
+(define_insn "*negqi2_1"
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
(neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))
(clobber (reg:CC 17))]
- ""
+ "ix86_unary_operator_ok (NEG, QImode, operands)"
"neg{b}\\t%0"
[(set_attr "type" "negnot")])
(const_int 0)))
(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
(neg:QI (match_dup 1)))]
- ""
+ "ix86_unary_operator_ok (NEG, QImode, operands)"
"neg{b}\\t%0"
[(set_attr "type" "negnot")])
(const_int 0)))
(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
(neg:QI (match_dup 1)))]
- ""
+ "ix86_unary_operator_ok (NEG, QImode, operands)"
"neg{b}\\t%0"
[(set_attr "type" "negnot")])
-;; Changing of sign for FP values is duable using integer unit too.
+;; Changing of sign for FP values is doable using integer unit too.
-(define_insn "negsf2"
+(define_expand "negsf2"
+ [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
+ (neg:SF (match_operand:SF 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ "TARGET_80387"
+ "ix86_expand_unary_operator (NEG, SFmode, operands); DONE;")
+
+(define_insn "*negsf2_if"
[(set (match_operand:SF 0 "nonimmediate_operand" "=frm")
(neg:SF (match_operand:SF 1 "nonimmediate_operand" "0")))
(clobber (reg:CC 17))]
- "TARGET_80387"
+ "TARGET_80387 && ix86_unary_operator_ok (NEG, SFmode, operands)"
"#")
(define_split
operands[1] = GEN_INT (0x80);
}")
-(define_insn "negdf2"
+(define_expand "negdf2"
+ [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (neg:DF (match_operand:DF 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ "TARGET_80387"
+ "ix86_expand_unary_operator (NEG, DFmode, operands); DONE;")
+
+(define_insn "*negdf2_if"
[(set (match_operand:DF 0 "nonimmediate_operand" "=frm")
(neg:DF (match_operand:DF 1 "nonimmediate_operand" "0")))
(clobber (reg:CC 17))]
- "TARGET_80387"
+ "TARGET_80387 && ix86_unary_operator_ok (NEG, DFmode, operands)"
"#")
(define_split
"operands[4] = GEN_INT (0x80000000);
split_di (operands+0, 1, operands+2, operands+3);")
-(define_insn "negxf2"
+(define_expand "negxf2"
+ [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "")
+ (neg:XF (match_operand:XF 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ "TARGET_80387"
+ "ix86_expand_unary_operator (NEG, XFmode, operands); DONE;")
+
+(define_insn "*negxf2_if"
[(set (match_operand:XF 0 "nonimmediate_operand" "=frm")
(neg:XF (match_operand:XF 1 "nonimmediate_operand" "0")))
(clobber (reg:CC 17))]
- "TARGET_80387"
+ "TARGET_80387 && ix86_unary_operator_ok (NEG, XFmode, operands)"
"#")
(define_split
\f
;; Absolute value instructions
-(define_insn "abssf2"
+(define_expand "abssf2"
+ [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
+ (neg:SF (match_operand:SF 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ "TARGET_80387"
+ "ix86_expand_unary_operator (ABS, SFmode, operands); DONE;")
+
+(define_insn "*abssf2_if"
[(set (match_operand:SF 0 "nonimmediate_operand" "=frm")
(abs:SF (match_operand:SF 1 "nonimmediate_operand" "0")))
(clobber (reg:CC 17))]
- "TARGET_80387"
+ "TARGET_80387 && ix86_unary_operator_ok (ABS, SFmode, operands)"
"#")
(define_split
operands[1] = GEN_INT (~0x80);
}")
-(define_insn "absdf2"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=frm")
- (abs:DF (match_operand:DF 1 "nonimmediate_operand" "0")))]
+(define_expand "absdf2"
+ [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
+ (neg:DF (match_operand:DF 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
"TARGET_80387"
+ "ix86_expand_unary_operator (ABS, DFmode, operands); DONE;")
+
+(define_insn "*absdf2_if"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=frm")
+ (abs:DF (match_operand:DF 1 "nonimmediate_operand" "0")))
+ (clobber (reg:CC 17))]
+ "TARGET_80387 && ix86_unary_operator_ok (ABS, DFmode, operands)"
"#")
(define_split
"operands[4] = GEN_INT (~0x80000000);
split_di (operands+0, 1, operands+2, operands+3);")
-(define_insn "absxf2"
+(define_expand "absxf2"
+ [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "")
+ (neg:XF (match_operand:XF 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ "TARGET_80387"
+ "ix86_expand_unary_operator (ABS, XFmode, operands); DONE;")
+
+(define_insn "*absxf2_if"
[(set (match_operand:XF 0 "nonimmediate_operand" "=frm")
(abs:XF (match_operand:XF 1 "nonimmediate_operand" "0")))
(clobber (reg:CC 17))]
- "TARGET_80387"
+ "TARGET_80387 && ix86_unary_operator_ok (ABS, XFmode, operands)"
"#")
(define_split
\f
;; One complement instructions
-(define_insn "one_cmplsi2"
+(define_expand "one_cmplsi2"
+ [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (not:SI (match_operand:SI 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ ""
+ "ix86_expand_unary_operator (NOT, SImode, operands); DONE;")
+
+(define_insn "*one_cmplsi2_1"
[(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
- ""
+ "ix86_unary_operator_ok (NEG, SImode, operands)"
"not{l}\\t%0"
[(set_attr "type" "negnot")])
-(define_insn "*one_cmplsi2_1"
+(define_insn "*one_cmplsi2_2"
[(set (reg:CCNO 17)
(compare:CCNO (not:SI (match_operand:SI 1 "nonimmediate_operand" "0"))
(const_int 0)))
(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
(not:SI (match_dup 1)))]
- ""
+ "ix86_unary_operator_ok (NEG, SImode, operands)"
"#"
[(set_attr "type" "alu1")])
(xor:SI (match_dup 1) (const_int -1)))])]
"")
-(define_insn "one_cmplhi2"
+(define_expand "one_cmplhi2"
+ [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
+ (not:HI (match_operand:HI 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ ""
+ "ix86_expand_unary_operator (NOT, HImode, operands); DONE;")
+
+(define_insn "*one_cmplhi2_1"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
(not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
- ""
+ "ix86_unary_operator_ok (NEG, HImode, operands)"
"not{w}\\t%0"
[(set_attr "type" "negnot")])
"operands[0] = gen_lowpart (SImode, operands[0]);
operands[1] = gen_lowpart (SImode, operands[1]);")
-(define_insn "*one_cmplhi2_1"
+(define_insn "*one_cmplhi2_2"
[(set (reg:CCNO 17)
(compare:CCNO (not:HI (match_operand:HI 1 "nonimmediate_operand" "0"))
(const_int 0)))
(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
(not:HI (match_dup 1)))]
- ""
+ "ix86_unary_operator_ok (NEG, HImode, operands)"
"#"
[(set_attr "type" "alu1")])
"")
;; %%% Potential partial reg stall on alternative 1. What to do?
-(define_insn "one_cmplqi2"
+(define_expand "one_cmplqi2"
+ [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "")
+ (not:QI (match_operand:QI 1 "general_operand" "")))
+ (clobber (reg:CC 17))])]
+ ""
+ "ix86_expand_unary_operator (NOT, QImode, operands); DONE;")
+
+(define_insn "*one_cmplqi2_1"
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,*r")
(not:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))]
- ""
+ "ix86_unary_operator_ok (NEG, QImode, operands)"
"@
not{b}\\t%0
not{l}\\t%k0"
[(set_attr "type" "negnot")])
-(define_insn "*one_cmplqi2_1"
+(define_insn "*one_cmplqi2_2"
[(set (reg:CCNO 17)
(compare:CCNO (not:QI (match_operand:QI 1 "nonimmediate_operand" "0"))
(const_int 0)))
(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
(not:QI (match_dup 1)))]
- ""
+ "ix86_unary_operator_ok (NEG, QImode, operands)"
"#"
[(set_attr "type" "alu1")])