* i386.c (general_no_elim_operand): New.
(nonmemory_no_elim_operand): New.
(ix86_expand_move): Copy eliminable operands before a push.
* i386-protos.h: Declare new functions.
* i386.h (CAN_ELIMINATE): Simplify.
(PREDICATE_CODES): Update.
* i386.md (push insns): Don't allow eliminable register operands.
From-SVN: r31755
+2000-02-01 Richard Henderson <rth@cygnus.com>
+
+ * i386.c (general_no_elim_operand): New.
+ (nonmemory_no_elim_operand): New.
+ (ix86_expand_move): Copy eliminable operands before a push.
+ * i386-protos.h: Declare new functions.
+ * i386.h (CAN_ELIMINATE): Simplify.
+ (PREDICATE_CODES): Update.
+ * i386.md (push insns): Don't allow eliminable register operands.
+
2000-02-01 Richard Henderson <rth@cygnus.com>
* flow.c (mark_regs_live_at_end): Follow expand_function_end and
extern int const248_operand PARAMS ((rtx, enum machine_mode));
extern int incdec_operand PARAMS ((rtx, enum machine_mode));
extern int reg_no_sp_operand PARAMS ((rtx, enum machine_mode));
+extern int general_no_elim_operand PARAMS ((rtx, enum machine_mode));
+extern int nonmemory_no_elim_operand PARAMS ((rtx, enum machine_mode));
extern int q_regs_operand PARAMS ((rtx, enum machine_mode));
extern int non_q_regs_operand PARAMS ((rtx, enum machine_mode));
extern int no_comparison_operator PARAMS ((rtx, enum machine_mode));
return register_operand (op, mode);
}
+/* Return false if this is any eliminable register. Otherwise
+ general_operand. */
+
+int
+general_no_elim_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ rtx t = op;
+ if (GET_CODE (t) == SUBREG)
+ t = SUBREG_REG (t);
+ if (t == arg_pointer_rtx || t == frame_pointer_rtx
+ || t == virtual_incoming_args_rtx || t == virtual_stack_vars_rtx
+ || t == virtual_stack_dynamic_rtx)
+ return 0;
+
+ return general_operand (op, mode);
+}
+
+/* Return false if this is any eliminable register. Otherwise
+ register_operand or const_int. */
+
+int
+nonmemory_no_elim_operand (op, mode)
+ register rtx op;
+ enum machine_mode mode;
+{
+ rtx t = op;
+ if (GET_CODE (t) == SUBREG)
+ t = SUBREG_REG (t);
+ if (t == arg_pointer_rtx || t == frame_pointer_rtx
+ || t == virtual_incoming_args_rtx || t == virtual_stack_vars_rtx
+ || t == virtual_stack_dynamic_rtx)
+ return 0;
+
+ return GET_CODE (op) == CONST_INT || register_operand (op, mode);
+}
+
/* Return true if op is a Q_REGS class register. */
int
&& GET_CODE (operands[1]) == MEM)
operands[1] = force_reg (mode, operands[1]);
+ if (push_operand (operands[0], mode)
+ && ! general_no_elim_operand (operands[1], mode))
+ operands[1] = copy_to_mode_reg (mode, operands[1]);
+
if (FLOAT_MODE_P (mode))
{
/* If we are loading a floating point constant to a register,
{ FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
{ FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}} \
-/* Given FROM and TO register numbers, say whether this elimination is allowed.
- Frame pointer elimination is automatically handled.
-
- For the i386, if frame pointer elimination is being done, we would like to
- convert ap into sp, not fp.
+/* Given FROM and TO register numbers, say whether this elimination is
+ allowed. Frame pointer elimination is automatically handled.
All other eliminations are valid. */
-#define CAN_ELIMINATE(FROM, TO) \
- ((((FROM) == ARG_POINTER_REGNUM || (FROM) == FRAME_POINTER_REGNUM) \
- && (TO) == STACK_POINTER_REGNUM) \
- ? ! frame_pointer_needed \
- : 1)
+#define CAN_ELIMINATE(FROM, TO) \
+ ((TO) == STACK_POINTER_REGNUM ? ! frame_pointer_needed : 1)
/* Define the offset between two registers, one to be eliminated, and the other
its replacement, at the start of a routine. */
{"const248_operand", {CONST_INT}}, \
{"incdec_operand", {CONST_INT}}, \
{"reg_no_sp_operand", {SUBREG, REG}}, \
+ {"general_no_elim_operand", {CONST_INT, CONST_DOUBLE, CONST, \
+ SYMBOL_REF, LABEL_REF, SUBREG, REG, MEM}}, \
+ {"nonmemory_no_elim_operand", {CONST_INT, REG, SUBREG}}, \
{"q_regs_operand", {SUBREG, REG}}, \
{"non_q_regs_operand", {SUBREG, REG}}, \
{"no_comparison_operator", {EQ, NE, LT, GE, LTU, GTU, LEU, GEU}}, \
(define_insn "pushsi2"
[(set (match_operand:SI 0 "push_operand" "=<")
- (match_operand:SI 1 "general_operand" "ri*m"))]
+ (match_operand:SI 1 "general_no_elim_operand" "ri*m"))]
""
"push{l}\\t%1"
[(set_attr "type" "push")])
(define_insn "pushhi2"
[(set (match_operand:HI 0 "push_operand" "=<,<")
- (match_operand:HI 1 "general_operand" "n,r*m"))]
+ (match_operand:HI 1 "general_no_elim_operand" "n,r*m"))]
""
"@
push{w}\\t{|WORD PTR }%1
(define_insn "pushqi2"
[(set (match_operand:QI 0 "push_operand" "=<,<")
- (match_operand:QI 1 "nonmemory_operand" "n,r"))]
+ (match_operand:QI 1 "nonmemory_no_elim_operand" "n,r"))]
""
"@
push{w}\\t{|word ptr }%1
(define_insn "*pushdi"
[(set (match_operand:DI 0 "push_operand" "=<")
- (match_operand:DI 1 "general_operand" "riF*m"))]
+ (match_operand:DI 1 "general_no_elim_operand" "riF*m"))]
""
"#")
(define_insn "*pushsf"
[(set (match_operand:SF 0 "push_operand" "=<,<")
- (match_operand:SF 1 "general_operand" "f#r,rFm#f"))]
+ (match_operand:SF 1 "general_no_elim_operand" "f#r,rFm#f"))]
""
"*
{
(define_insn "*pushdf"
[(set (match_operand:DF 0 "push_operand" "=<,<")
- (match_operand:DF 1 "general_operand" "f#r,rFo#f"))]
+ (match_operand:DF 1 "general_no_elim_operand" "f#r,rFo#f"))]
""
"*
{
(define_insn "*pushxf_nointeger"
[(set (match_operand:XF 0 "push_operand" "=<,<,<")
- (match_operand:XF 1 "general_operand" "f,Fo,*r"))]
+ (match_operand:XF 1 "general_no_elim_operand" "f,Fo,*r"))]
"optimize_size"
"*
{
(define_insn "*pushxf_integer"
[(set (match_operand:XF 0 "push_operand" "=<,<")
- (match_operand:XF 1 "general_operand" "f#r,rFo#f"))]
+ (match_operand:XF 1 "general_no_elim_operand" "f#r,rFo#f"))]
"!optimize_size"
"*
{