aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/i386/i386.md
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2000-07-30 18:59:56 +0000
committerJan Hubicka <jh@suse.cz>2000-07-30 18:59:56 +0000
commit1e4b680ae6d7ae3b72fe5e61935ade0ef76ae9fc (patch)
tree5c77df3c7f1a3b16186f59f8a8bf96e45a6bca95 /gcc/config/i386/i386.md
parentc37aadeb42d1b7da8ec92536c2164b00400f7741 (diff)
* i386.md (*lea_general_[123]) New insns and splits.
(addsi3 to lea splitter): Handle other modes too. (shlsi3 to lea splitter): Likewise. (addhi_1_lea, shlhi_1_lea): New patterns. (addhi_1, shlhi_1): Conditionize by PARTIAL_REG_STALL. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@35351 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config/i386/i386.md')
-rw-r--r--gcc/config/i386/i386.md361
1 files changed, 339 insertions, 22 deletions
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index a47c6dcc6ce..eecb151db8a 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -3740,6 +3740,102 @@
[(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")
@@ -3796,16 +3892,29 @@
;; 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)
@@ -3883,12 +3992,57 @@
;; 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))
@@ -3986,12 +4140,64 @@
"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);
@@ -6279,16 +6485,24 @@
;; 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
@@ -6341,12 +6555,54 @@
"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))
@@ -6429,12 +6685,73 @@
"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))