summaryrefslogtreecommitdiffstats
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog8
-rw-r--r--gcc/config/xtensa/xtensa.c61
2 files changed, 44 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5f8a9fe9b91..da090ca1a28 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2004-03-05 Bob Wilson <bob.wilson@acm.org>
+
+ * config/xtensa/xtensa.c (function_arg): Handle 16-byte aligned args.
+ (xtensa_va_start): Initialize __va_stk to ($arg_ptr - 32). Adjust
+ __va_ndx by 2 words when referencing an argument on the stack.
+ (xtensa_va_arg): Handle 16-byte aligned args. Adjust __va_ndx by 2
+ words when an arg on the stack is first seen.
+
2004-03-05 Paul Brook <paul@codesourcery.com>
* arm.h (ARM_FLAG_VFP): Remove.
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index cb03b536d9b..14db30f4a99 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -1805,7 +1805,10 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
: int_size_in_bytes (type)) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
if (type && (TYPE_ALIGN (type) > BITS_PER_WORD))
- *arg_words += (*arg_words & 1);
+ {
+ int align = TYPE_ALIGN (type) / BITS_PER_WORD;
+ *arg_words = (*arg_words + align - 1) & -align;
+ }
if (*arg_words + words > max)
return (rtx)0;
@@ -2335,17 +2338,20 @@ xtensa_return_addr (int count, rtx frame)
/* Create the va_list data type.
- This structure is set up by __builtin_saveregs. The __va_reg
- field points to a stack-allocated region holding the contents of the
- incoming argument registers. The __va_ndx field is an index initialized
- to the position of the first unnamed (variable) argument. This same index
- is also used to address the arguments passed in memory. Thus, the
- __va_stk field is initialized to point to the position of the first
- argument in memory offset to account for the arguments passed in
- registers. E.G., if there are 6 argument registers, and each register is
- 4 bytes, then __va_stk is set to $sp - (6 * 4); then __va_reg[N*4]
- references argument word N for 0 <= N < 6, and __va_stk[N*4] references
- argument word N for N >= 6. */
+
+ This structure is set up by __builtin_saveregs. The __va_reg field
+ points to a stack-allocated region holding the contents of the
+ incoming argument registers. The __va_ndx field is an index
+ initialized to the position of the first unnamed (variable)
+ argument. This same index is also used to address the arguments
+ passed in memory. Thus, the __va_stk field is initialized to point
+ to the position of the first argument in memory offset to account
+ for the arguments passed in registers and to account for the size
+ of the argument registers not being 16-byte aligned. E.G., there
+ are 6 argument registers of 4 bytes each, but we want the __va_ndx
+ for the first stack argument to have the maximal alignment of 16
+ bytes, so we offset the __va_stk address by 32 bytes so that
+ __va_stk[32] references the first argument on the stack. */
static tree
xtensa_build_builtin_va_list (void)
@@ -2436,15 +2442,18 @@ xtensa_va_start (tree valist, rtx nextarg ATTRIBUTE_UNUSED)
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- /* Set the __va_stk member to $arg_ptr - (size of __va_reg area) */
+ /* Set the __va_stk member to ($arg_ptr - 32). */
u = make_tree (ptr_type_node, virtual_incoming_args_rtx);
- u = fold (build (PLUS_EXPR, ptr_type_node, u,
- build_int_2 (-MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, -1)));
+ u = fold (build (PLUS_EXPR, ptr_type_node, u, build_int_2 (-32, -1)));
t = build (MODIFY_EXPR, ptr_type_node, stk, u);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
- /* Set the __va_ndx member. */
+ /* Set the __va_ndx member. If the first variable argument is on
+ the stack, adjust __va_ndx by 2 words to account for the extra
+ alignment offset for __va_stk. */
+ if (arg_words >= MAX_ARGS_IN_REGISTERS)
+ arg_words += 2;
u = build_int_2 (arg_words * UNITS_PER_WORD, 0);
t = build (MODIFY_EXPR, integer_type_node, ndx, u);
TREE_SIDE_EFFECTS (t) = 1;
@@ -2506,17 +2515,19 @@ xtensa_va_arg (tree valist, tree type)
emit_move_insn (va_size, r);
- /* First align __va_ndx to a double word boundary if necessary for this arg:
+ /* First align __va_ndx if necessary for this arg:
- if (__alignof__ (TYPE) > 4)
- (AP).__va_ndx = (((AP).__va_ndx + 7) & -8); */
+ if (__alignof__ (TYPE) > 4 )
+ (AP).__va_ndx = (((AP).__va_ndx + __alignof__ (TYPE) - 1)
+ & -__alignof__ (TYPE)); */
if (TYPE_ALIGN (type) > BITS_PER_WORD)
{
+ int align = TYPE_ALIGN (type) / BITS_PER_UNIT;
tmp = build (PLUS_EXPR, integer_type_node, ndx,
- build_int_2 ((2 * UNITS_PER_WORD) - 1, 0));
+ build_int_2 (align - 1, 0));
tmp = build (BIT_AND_EXPR, integer_type_node, tmp,
- build_int_2 (-2 * UNITS_PER_WORD, -1));
+ build_int_2 (-align, -1));
tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
TREE_SIDE_EFFECTS (tmp) = 1;
expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2574,18 +2585,18 @@ xtensa_va_arg (tree valist, tree type)
else
{
- if (orig_ndx < __MAX_ARGS_IN_REGISTERS * 4)
- (AP).__va_ndx = __MAX_ARGS_IN_REGISTERS * 4 + __va_size (TYPE);
+ if (orig_ndx <= __MAX_ARGS_IN_REGISTERS * 4)
+ (AP).__va_ndx = 32 + __va_size (TYPE);
__array = (AP).__va_stk;
} */
lab_false2 = gen_label_rtx ();
emit_cmp_and_jump_insns (orig_ndx,
GEN_INT (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD),
- GE, const1_rtx, SImode, 0, lab_false2);
+ GT, const1_rtx, SImode, 0, lab_false2);
tmp = build (PLUS_EXPR, sizetype, make_tree (intSI_type_node, va_size),
- build_int_2 (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, 0));
+ build_int_2 (32, 0));
tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
TREE_SIDE_EFFECTS (tmp) = 1;
expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
OpenPOWER on IntegriCloud