[(set_attr "type" "lea")
(set_attr "mode" "SI")])
+;; The lea patterns for non-Pmodes needs to be matched by several
+;; insns converted to real lea by splitters.
+
+(define_insn_and_split "*lea_general_1"
+ [(set (match_operand 0 "register_operand" "=r")
+ (plus (plus (match_operand 1 "register_operand" "r")
+ (match_operand 2 "register_operand" "r"))
+ (match_operand 3 "immediate_operand" "i")))]
+ "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode)
+ && (!TARGET_PARTIAL_REG_STALL || optimize_size)
+ && GET_MODE (operands[0]) == GET_MODE (operands[1])
+ && GET_MODE (operands[0]) == GET_MODE (operands[2])
+ && (GET_MODE (operands[0]) == GET_MODE (operands[3])
+ || GET_MODE (operands[3]) == VOIDmode)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ "
+{
+ rtx pat;
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (Pmode, operands[1]);
+ operands[2] = gen_lowpart (Pmode, operands[2]);
+ operands[3] = gen_lowpart (Pmode, operands[3]);
+ pat = gen_rtx_PLUS (Pmode, gen_rtx_PLUS (Pmode, operands[1], operands[2]),
+ operands[3]);
+ if (Pmode != SImode)
+ pat = gen_rtx_SUBREG (SImode, pat, 0);
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
+ DONE;
+}"
+ [(set_attr "type" "lea")
+ (set_attr "mode" "SI")])
+
+(define_insn_and_split "*lea_general_2"
+ [(set (match_operand 0 "register_operand" "=r")
+ (plus (mult (match_operand 1 "register_operand" "r")
+ (match_operand 2 "const248_operand" "i"))
+ (match_operand 3 "nonmemory_operand" "ri")))]
+ "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode)
+ && (!TARGET_PARTIAL_REG_STALL || optimize_size)
+ && GET_MODE (operands[0]) == GET_MODE (operands[1])
+ && (GET_MODE (operands[0]) == GET_MODE (operands[3])
+ || GET_MODE (operands[3]) == VOIDmode)"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ "
+{
+ rtx pat;
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (Pmode, operands[1]);
+ operands[3] = gen_lowpart (Pmode, operands[3]);
+ pat = gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1], operands[2]),
+ operands[3]);
+ if (Pmode != SImode)
+ pat = gen_rtx_SUBREG (SImode, pat, 0);
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
+ DONE;
+}"
+ [(set_attr "type" "lea")
+ (set_attr "mode" "SI")])
+
+(define_insn_and_split "*lea_general_3"
+ [(set (match_operand 0 "register_operand" "=r")
+ (plus (plus (mult (match_operand 1 "register_operand" "r")
+ (match_operand 2 "const248_operand" "i"))
+ (match_operand 3 "register_operand" "r"))
+ (match_operand 4 "immediate_operand" "i")))]
+ "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode)
+ && (!TARGET_PARTIAL_REG_STALL || optimize_size)
+ && GET_MODE (operands[0]) == GET_MODE (operands[1])
+ && GET_MODE (operands[0]) == GET_MODE (operands[3])"
+ "#"
+ "reload_completed"
+ [(const_int 0)]
+ "
+{
+ rtx pat;
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (Pmode, operands[1]);
+ operands[3] = gen_lowpart (Pmode, operands[3]);
+ operands[4] = gen_lowpart (Pmode, operands[4]);
+ pat = gen_rtx_PLUS (Pmode,
+ gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1],
+ operands[2]),
+ operands[3]),
+ operands[4]);
+ if (Pmode != SImode)
+ pat = gen_rtx_SUBREG (SImode, pat, 0);
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
+ DONE;
+}"
+ [(set_attr "type" "lea")
+ (set_attr "mode" "SI")])
+
(define_insn "*addsi_1"
[(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r")
(plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r")
;; Convert lea to the lea pattern to avoid flags dependency.
(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (plus:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:SI 2 "nonmemory_operand" "")))
+ [(set (match_operand 0 "register_operand" "")
+ (plus (match_operand 1 "register_operand" "")
+ (match_operand 2 "nonmemory_operand" "")))
(clobber (reg:CC 17))]
- "reload_completed
- && true_regnum (operands[0]) != true_regnum (operands[1])"
- [(set (match_dup 0)
- (plus:SI (match_dup 1)
- (match_dup 2)))]
- "")
+ "reload_completed"
+ [(const_int 0)]
+ "
+{
+ rtx pat;
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ /* In -fPIC mode the constructs like (const (unspec [symbol_ref]))
+ may confuse gen_lowpart. */
+ if (GET_MODE (operands[0]) != Pmode)
+ {
+ operands[1] = gen_lowpart (Pmode, operands[1]);
+ operands[2] = gen_lowpart (Pmode, operands[2]);
+ }
+ pat = gen_rtx_PLUS (Pmode, operands[1], operands[2]);
+ if (Pmode != SImode)
+ pat = gen_rtx_SUBREG (SImode, pat, 0);
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
+ DONE;
+}")
(define_insn "*addsi_2"
[(set (reg 17)
;; type optimizations enabled by define-splits. This is not important
;; for PII, and in fact harmful because of partial register stalls.
+(define_insn "*addhi_1_lea"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r")
+ (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r")
+ (match_operand:HI 2 "general_operand" "ri,rm,rni")))
+ (clobber (reg:CC 17))]
+ "!TARGET_PARTIAL_REG_STALL
+ && ix86_binary_operator_ok (PLUS, HImode, operands)"
+ "*
+{
+ switch (get_attr_type (insn))
+ {
+ case TYPE_LEA:
+ return \"#\";
+ case TYPE_INCDEC:
+ if (operands[2] == const1_rtx)
+ return \"inc{w}\\t%0\";
+ else if (operands[2] == constm1_rtx
+ || (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 65535))
+ return \"dec{w}\\t%0\";
+ abort();
+
+ default:
+ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
+ Exceptions: -128 encodes smaller than 128, so swap sign and op. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (INTVAL (operands[2]) == 128
+ || (INTVAL (operands[2]) < 0
+ && INTVAL (operands[2]) != -128)))
+ {
+ operands[2] = GEN_INT (-INTVAL (operands[2]));
+ return \"sub{w}\\t{%2, %0|%0, %2}\";
+ }
+ return \"add{w}\\t{%2, %0|%0, %2}\";
+ }
+}"
+ [(set (attr "type")
+ (if_then_else (eq_attr "alternative" "2")
+ (const_string "lea")
+ (if_then_else (match_operand:HI 2 "incdec_operand" "")
+ (const_string "incdec")
+ (const_string "alu"))))
+ (set_attr "mode" "HI,HI,SI")])
+
(define_insn "*addhi_1"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
(plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
(match_operand:HI 2 "general_operand" "ri,rm")))
(clobber (reg:CC 17))]
- "ix86_binary_operator_ok (PLUS, HImode, operands)"
+ "TARGET_PARTIAL_REG_STALL
+ && ix86_binary_operator_ok (PLUS, HImode, operands)"
"*
{
switch (get_attr_type (insn))
"ix86_expand_binary_operator (PLUS, QImode, operands); DONE;")
;; %%% Potential partial reg stall on alternative 2. What to do?
+(define_insn "*addqi_1_lea"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r,r")
+ (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,r")
+ (match_operand:QI 2 "general_operand" "qn,qmn,rn,rn")))
+ (clobber (reg:CC 17))]
+ "!TARGET_PARTIAL_REG_STALL
+ && ix86_binary_operator_ok (PLUS, QImode, operands)"
+ "*
+{
+ int widen = (which_alternative == 2);
+ switch (get_attr_type (insn))
+ {
+ case TYPE_LEA:
+ return \"#\";
+ case TYPE_INCDEC:
+ if (operands[2] == const1_rtx)
+ return widen ? \"inc{l}\\t%k0\" : \"inc{b}\\t%0\";
+ else if (operands[2] == constm1_rtx
+ || (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 255))
+ return widen ? \"dec{l}\\t%k0\" : \"dec{b}\\t%0\";
+ abort();
+
+ default:
+ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
+ Exceptions: -128 encodes smaller than 128, so swap sign and op. */
+ if (GET_CODE (operands[2]) == CONST_INT
+ && (INTVAL (operands[2]) == 128
+ || (INTVAL (operands[2]) < 0
+ && INTVAL (operands[2]) != -128)))
+ {
+ operands[2] = GEN_INT (-INTVAL (operands[2]));
+ if (widen)
+ return \"sub{l}\\t{%2, %k0|%k0, %2}\";
+ else
+ return \"sub{b}\\t{%2, %0|%0, %2}\";
+ }
+ if (widen)
+ return \"add{l}\\t{%k2, %k0|%k0, %k2}\";
+ else
+ return \"add{b}\\t{%2, %0|%0, %2}\";
+ }
+}"
+ [(set (attr "type")
+ (if_then_else (eq_attr "alternative" "3")
+ (const_string "lea")
+ (if_then_else (match_operand:HI 2 "incdec_operand" "")
+ (const_string "incdec")
+ (const_string "alu"))))
+ (set_attr "mode" "HI,HI,SI,SI")])
+
(define_insn "*addqi_1"
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r")
(plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
(match_operand:QI 2 "general_operand" "qn,qmn,rn")))
(clobber (reg:CC 17))]
- "ix86_binary_operator_ok (PLUS, QImode, operands)"
+ "TARGET_PARTIAL_REG_STALL
+ && ix86_binary_operator_ok (PLUS, QImode, operands)"
"*
{
int widen = (which_alternative == 2);
;; Convert lea to the lea pattern to avoid flags dependency.
(define_split
- [(set (match_operand:SI 0 "register_operand" "")
- (ashift:SI (match_operand:SI 1 "register_operand" "")
- (match_operand:QI 2 "immediate_operand" "")))
+ [(set (match_operand 0 "register_operand" "")
+ (ashift (match_operand 1 "register_operand" "")
+ (match_operand:QI 2 "const_int_operand" "")))
(clobber (reg:CC 17))]
- "reload_completed
- && true_regnum (operands[0]) != true_regnum (operands[1])"
- [(set (match_dup 0)
- (mult:SI (match_dup 1)
- (match_dup 2)))]
- "operands[2] = GEN_INT (1 << INTVAL (operands[2]));")
+ "reload_completed"
+ [(const_int 0)]
+ "
+{
+ rtx pat;
+ operands[0] = gen_lowpart (SImode, operands[0]);
+ operands[1] = gen_lowpart (Pmode, operands[1]);
+ operands[2] = GEN_INT (1 << INTVAL (operands[2]));
+ pat = gen_rtx_MULT (Pmode, operands[1], operands[2]);
+ if (Pmode != SImode)
+ pat = gen_rtx_SUBREG (SImode, pat, 0);
+ emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
+ DONE;
+}")
;; This pattern can't accept a variable shift count, since shifts by
;; zero don't affect the flags. We assume that shifts by constant
"TARGET_HIMODE_MATH"
"ix86_expand_binary_operator (ASHIFT, HImode, operands); DONE;")
+(define_insn "*ashlhi3_1_lea"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+ (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,r")
+ (match_operand:QI 2 "nonmemory_operand" "cI,M")))
+ (clobber (reg:CC 17))]
+ "!TARGET_PARTIAL_REG_STALL
+ && ix86_binary_operator_ok (ASHIFT, HImode, operands)"
+ "*
+{
+ switch (get_attr_type (insn))
+ {
+ case TYPE_LEA:
+ return \"#\";
+ case TYPE_ALU:
+ if (operands[2] != const1_rtx)
+ abort ();
+ return \"add{w}\\t{%0, %0|%0, %0}\";
+
+ default:
+ if (REG_P (operands[2]))
+ return \"sal{w}\\t{%b2, %0|%0, %b2}\";
+ else if (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 1
+ && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
+ return \"sal{w}\\t%0\";
+ else
+ return \"sal{w}\\t{%2, %0|%0, %2}\";
+ }
+}"
+ [(set (attr "type")
+ (cond [(eq_attr "alternative" "1")
+ (const_string "lea")
+ (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+ (const_int 0))
+ (match_operand 0 "register_operand" ""))
+ (match_operand 2 "const1_operand" ""))
+ (const_string "alu")
+ ]
+ (const_string "ishift")))
+ (set_attr "mode" "HI,SI")])
+
(define_insn "*ashlhi3_1"
[(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
(ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
(match_operand:QI 2 "nonmemory_operand" "cI")))
(clobber (reg:CC 17))]
- "ix86_binary_operator_ok (ASHIFT, HImode, operands)"
+ "TARGET_PARTIAL_REG_STALL
+ && ix86_binary_operator_ok (ASHIFT, HImode, operands)"
"*
{
switch (get_attr_type (insn))
"ix86_expand_binary_operator (ASHIFT, QImode, operands); DONE;")
;; %%% Potential partial reg stall on alternative 2. What to do?
+
+(define_insn "*ashlqi3_1_lea"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r,r")
+ (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,r")
+ (match_operand:QI 2 "nonmemory_operand" "cI,cI,r")))
+ (clobber (reg:CC 17))]
+ "!TARGET_PARTIAL_REG_STALL
+ && ix86_binary_operator_ok (ASHIFT, QImode, operands)"
+ "*
+{
+ switch (get_attr_type (insn))
+ {
+ case TYPE_LEA:
+ return \"#\";
+ case TYPE_ALU:
+ if (operands[2] != const1_rtx)
+ abort ();
+ if (NON_QI_REG_P (operands[1]))
+ return \"add{l}\\t{%k0, %k0|%k0, %k0}\";
+ else
+ return \"add{b}\\t{%0, %0|%0, %0}\";
+
+ default:
+ if (REG_P (operands[2]))
+ {
+ if (get_attr_mode (insn) == MODE_SI)
+ return \"sal{l}\\t{%b2, %k0|%k0, %b2}\";
+ else
+ return \"sal{b}\\t{%b2, %0|%0, %b2}\";
+ }
+ else if (GET_CODE (operands[2]) == CONST_INT
+ && INTVAL (operands[2]) == 1
+ && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
+ {
+ if (get_attr_mode (insn) == MODE_SI)
+ return \"sal{l}\\t%0\";
+ else
+ return \"sal{b}\\t%0\";
+ }
+ else
+ {
+ if (get_attr_mode (insn) == MODE_SI)
+ return \"sal{l}\\t{%2, %k0|%k0, %2}\";
+ else
+ return \"sal{b}\\t{%2, %0|%0, %2}\";
+ }
+ }
+}"
+ [(set (attr "type")
+ (cond [(eq_attr "alternative" "2")
+ (const_string "lea")
+ (and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+ (const_int 0))
+ (match_operand 0 "register_operand" ""))
+ (match_operand 2 "const1_operand" ""))
+ (const_string "alu")
+ ]
+ (const_string "ishift")))
+ (set_attr "mode" "QI,SI,SI")])
+
(define_insn "*ashlqi3_1"
[(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r")
(ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
(match_operand:QI 2 "nonmemory_operand" "cI,cI")))
(clobber (reg:CC 17))]
- "ix86_binary_operator_ok (ASHIFT, QImode, operands)"
+ "TARGET_PARTIAL_REG_STALL
+ && ix86_binary_operator_ok (ASHIFT, QImode, operands)"
"*
{
switch (get_attr_type (insn))