PR target/25293
* expr.c (emit_move_resolve_push): Handle PRE_MODIFY
and POST_MODIFY with CONST_INT adjustment equal to PUSH_ROUNDING.
Fix POST_INC/POST_DEC handling if PUSH_ROUNDING is not identity.
* config/i386/i386.md (pushhi2, pushqi2): Use pushl instead of pushw.
Set mode to SI, adjust constraints.
(pushhi2_rex64, pushqi2_rex64): Set mode to DI.
* config/i386/i386.h (PUSH_ROUNDING): Round up to 4 instead of 2 for
32-bit code.
* gcc.target/i386/pr25293.c: New test.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@108463
138bc75d-0d04-0410-961f-
82ee72b054a4
+2005-12-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR debug/25023
+ PR target/25293
+ * expr.c (emit_move_resolve_push): Handle PRE_MODIFY
+ and POST_MODIFY with CONST_INT adjustment equal to PUSH_ROUNDING.
+ Fix POST_INC/POST_DEC handling if PUSH_ROUNDING is not identity.
+ * config/i386/i386.md (pushhi2, pushqi2): Use pushl instead of pushw.
+ Set mode to SI, adjust constraints.
+ (pushhi2_rex64, pushqi2_rex64): Set mode to DI.
+ * config/i386/i386.h (PUSH_ROUNDING): Round up to 4 instead of 2 for
+ 32-bit code.
+
2005-12-13 Carlos O'Donell <carlos@codesourcery.com>
* c-cppbuiltin.c (builtin_define_float_constants): Add
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
- On 386 pushw decrements by exactly 2 no matter what the position was.
- On the 386 there is no pushb; we use pushw instead, and this
- has the effect of rounding up to 2.
+ On 386, we have pushw instruction that decrements by exactly 2 no
+ matter what the position was, there is no pushb.
+ But as CIE data alignment factor on this arch is -4, we need to make
+ sure all stack pointer adjustments are in multiple of 4.
For 64bit ABI we round up to 8 bytes.
*/
#define PUSH_ROUNDING(BYTES) \
(TARGET_64BIT \
? (((BYTES) + 7) & (-8)) \
- : (((BYTES) + 1) & (-2)))
+ : (((BYTES) + 3) & (-4)))
/* If defined, the maximum amount of space required for outgoing arguments will
be computed and placed into the variable
"ix86_expand_move (HImode, operands); DONE;")
(define_insn "*pushhi2"
- [(set (match_operand:HI 0 "push_operand" "=<,<")
- (match_operand:HI 1 "general_no_elim_operand" "n,r*m"))]
+ [(set (match_operand:HI 0 "push_operand" "=X")
+ (match_operand:HI 1 "nonmemory_no_elim_operand" "rn"))]
"!TARGET_64BIT"
- "@
- push{w}\t{|WORD PTR }%1
- push{w}\t%1"
+ "push{l}\t%k1"
[(set_attr "type" "push")
- (set_attr "mode" "HI")])
+ (set_attr "mode" "SI")])
;; For 64BIT abi we always round up to 8 bytes.
(define_insn "*pushhi2_rex64"
"TARGET_64BIT"
"push{q}\t%q1"
[(set_attr "type" "push")
- (set_attr "mode" "QI")])
+ (set_attr "mode" "DI")])
(define_insn "*movhi_1"
[(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m")
"ix86_expand_move (QImode, operands); DONE;")
;; emit_push_insn when it calls move_by_pieces requires an insn to
-;; "push a byte". But actually we use pushw, which has the effect
-;; of rounding the amount pushed up to a halfword.
+;; "push a byte". But actually we use pushl, which has the effect
+;; of rounding the amount pushed up to a word.
(define_insn "*pushqi2"
- [(set (match_operand:QI 0 "push_operand" "=X,X")
- (match_operand:QI 1 "nonmemory_no_elim_operand" "n,r"))]
+ [(set (match_operand:QI 0 "push_operand" "=X")
+ (match_operand:QI 1 "nonmemory_no_elim_operand" "rn"))]
"!TARGET_64BIT"
- "@
- push{w}\t{|word ptr }%1
- push{w}\t%w1"
+ "push{l}\t%k1"
[(set_attr "type" "push")
- (set_attr "mode" "HI")])
+ (set_attr "mode" "SI")])
;; For 64BIT abi we always round up to 8 bytes.
(define_insn "*pushqi2_rex64"
"TARGET_64BIT"
"push{q}\t%q1"
[(set_attr "type" "push")
- (set_attr "mode" "QI")])
+ (set_attr "mode" "DI")])
;; Situation is quite tricky about when to choose full sized (SImode) move
;; over QImode moves. For Q_REG -> Q_REG move we use full size only for
#endif
if (code == PRE_DEC || code == POST_DEC)
adjust = -adjust;
+ else if (code == PRE_MODIFY || code == POST_MODIFY)
+ {
+ rtx expr = XEXP (XEXP (x, 0), 1);
+ HOST_WIDE_INT val;
+
+ gcc_assert (GET_CODE (expr) == PLUS || GET_CODE (expr) == MINUS);
+ gcc_assert (GET_CODE (XEXP (expr, 1)) == CONST_INT);
+ val = INTVAL (XEXP (expr, 1));
+ if (GET_CODE (expr) == MINUS)
+ val = -val;
+ gcc_assert (adjust == val || adjust == -val);
+ adjust = val;
+ }
/* Do not use anti_adjust_stack, since we don't want to update
stack_pointer_delta. */
{
case PRE_INC:
case PRE_DEC:
+ case PRE_MODIFY:
temp = stack_pointer_rtx;
break;
case POST_INC:
- temp = plus_constant (stack_pointer_rtx, -GET_MODE_SIZE (mode));
- break;
case POST_DEC:
- temp = plus_constant (stack_pointer_rtx, GET_MODE_SIZE (mode));
+ case POST_MODIFY:
+ temp = plus_constant (stack_pointer_rtx, -adjust);
break;
default:
gcc_unreachable ();
+2005-12-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR debug/25023
+ PR target/25293
+ * gcc.target/i386/pr25293.c: New test.
+
2005-12-13 Petr Machata <machata@post.cz>
PR c++/24907
--- /dev/null
+/* PR target/25293 */
+/* { dg-do compile } */
+/* { dg-options "-mpreferred-stack-boundary=2 -mtune=i586 -O2 -fomit-frame-pointer -g" } */
+/* { dg-require-effective-target ilp32 } */
+
+struct T { unsigned short t1, t2, t3, t4, t5, t6, t7; };
+struct S { struct T s1; unsigned short s2, s3; };
+unsigned short v1;
+int f1 (void);
+int f2 (struct T);
+int f3 (const char *);
+
+int
+foo (struct S *x, struct T y)
+{
+ unsigned short a, b, c;
+ unsigned long d, e;
+ int f = 0;
+ y.t6 = 6;
+ a = y.t7;
+ b = y.t6;
+ c = y.t7;
+ switch (a)
+ {
+ case 8:
+ case 7:
+ c = 9;
+ break;
+ case 1:
+ case 6:
+ case 3:
+ b = 16;
+ c = 9;
+ break;
+ }
+ if ((f = f1 ()))
+ goto error;
+ if ((f = f2 (y)))
+ goto error;
+ d = (long) &y;
+ e = (long) &x->s1;
+ __asm __volatile ("" : "+D" (e), "+S" (d) :: "memory");
+ x->s2 = b;
+ x->s3 = c;
+ f3 ("foo");
+ return 0;
+error:
+ if (v1 >= 1)
+ f3 ("bar");
+ return f;
+}