From 3cb7a12915b19dc2f21263f46764df080e75aab8 Mon Sep 17 00:00:00 2001 From: jakub Date: Tue, 13 Dec 2005 08:08:46 +0000 Subject: [PATCH] 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. * gcc.target/i386/pr25293.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@108463 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 13 +++++++++ gcc/config/i386/i386.h | 9 +++--- gcc/config/i386/i386.md | 28 ++++++++---------- gcc/expr.c | 19 ++++++++++-- gcc/testsuite/ChangeLog | 6 ++++ gcc/testsuite/gcc.target/i386/pr25293.c | 51 +++++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 23 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr25293.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 222bda4..cc2131f 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2005-12-13 Jakub Jelinek + + 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 * c-cppbuiltin.c (builtin_define_float_constants): Add diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index e0dbd6b..de29adb 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1374,9 +1374,10 @@ enum reg_class /* 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. */ @@ -1384,7 +1385,7 @@ enum reg_class #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 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index d0bfc8a..4498319 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -1274,14 +1274,12 @@ "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" @@ -1290,7 +1288,7 @@ "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") @@ -1435,18 +1433,16 @@ "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" @@ -1455,7 +1451,7 @@ "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 diff --git a/gcc/expr.c b/gcc/expr.c index de66a0d..2e26ef0 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -2852,6 +2852,19 @@ emit_move_resolve_push (enum machine_mode mode, rtx x) #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. */ @@ -2865,13 +2878,13 @@ emit_move_resolve_push (enum machine_mode mode, rtx x) { 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 (); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ce14f6a..5b71d70 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2005-12-13 Jakub Jelinek + + PR debug/25023 + PR target/25293 + * gcc.target/i386/pr25293.c: New test. + 2005-12-13 Petr Machata PR c++/24907 diff --git a/gcc/testsuite/gcc.target/i386/pr25293.c b/gcc/testsuite/gcc.target/i386/pr25293.c new file mode 100644 index 0000000..6217da2 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr25293.c @@ -0,0 +1,51 @@ +/* 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; +} -- 2.7.4