]> gcc.gnu.org Git - gcc.git/commitdiff
* config/xtensa/xtensa.c (xtensa_va_arg): Handle variable-sized types.
authorBob Wilson <bob.wilson@acm.org>
Tue, 26 Mar 2002 19:32:18 +0000 (19:32 +0000)
committerBob Wilson <bwilson@gcc.gnu.org>
Tue, 26 Mar 2002 19:32:18 +0000 (19:32 +0000)
From-SVN: r51400

gcc/ChangeLog
gcc/config/xtensa/xtensa.c

index 16b09646f5284c3e2eb63c26f06e7dcb483748c8..4054887c8706a4fbb4a5129b37822f22663eeaa1 100644 (file)
@@ -1,3 +1,7 @@
+2002-03-26  Bob Wilson  <bob.wilson@acm.org>
+
+       * config/xtensa/xtensa.c (xtensa_va_arg): Handle variable-sized types.
+
 2002-03-26  Richard Earnshaw  <rearnsha@arm.com>
 
        PR target/5621
index 5abb5f837c6a6d3e1dad7176d5fab32521b829d5..0455737baf59ca00412a18c11aacecae26d3aa8a 100644 (file)
@@ -2431,14 +2431,10 @@ xtensa_va_arg (valist, type)
   tree f_stk, stk;
   tree f_reg, reg;
   tree f_ndx, ndx;
-  tree tmp, addr_tree;
-  rtx array, orig_ndx, r, addr;
-  HOST_WIDE_INT size, va_size;
+  tree tmp, addr_tree, type_size;
+  rtx array, orig_ndx, r, addr, size, va_size;
   rtx lab_false, lab_over, lab_false2;
 
-  size = int_size_in_bytes (type);
-  va_size = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
-
   f_stk = TYPE_FIELDS (va_list_type_node);
   f_reg = TREE_CHAIN (f_stk);
   f_ndx = TREE_CHAIN (f_reg);
@@ -2447,6 +2443,20 @@ xtensa_va_arg (valist, type)
   reg = build (COMPONENT_REF, TREE_TYPE (f_reg), valist, f_reg);
   ndx = build (COMPONENT_REF, TREE_TYPE (f_ndx), valist, f_ndx);
 
+  type_size = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type));
+
+  va_size = gen_reg_rtx (SImode);
+  tmp = fold (build (MULT_EXPR, sizetype,
+                    fold (build (TRUNC_DIV_EXPR, sizetype,
+                                 fold (build (PLUS_EXPR, sizetype,
+                                              type_size,
+                                              size_int (UNITS_PER_WORD - 1))),
+                                 size_int (UNITS_PER_WORD))),
+                    size_int (UNITS_PER_WORD)));
+  r = expand_expr (tmp, va_size, SImode, EXPAND_NORMAL);
+  if (r != va_size)
+    emit_move_insn (va_size, r);
+
 
   /* First align __va_ndx to a double word boundary if necessary for this arg:
 
@@ -2477,7 +2487,8 @@ xtensa_va_arg (valist, type)
   if (r != orig_ndx)
     emit_move_insn (orig_ndx, r);
 
-  tmp = build (PLUS_EXPR, integer_type_node, ndx, build_int_2 (va_size, 0));
+  tmp = build (PLUS_EXPR, integer_type_node, ndx,
+              make_tree (intSI_type_node, va_size));
   tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
   TREE_SIDE_EFFECTS (tmp) = 1;
   expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2522,7 +2533,8 @@ xtensa_va_arg (valist, type)
                           GEN_INT (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD),
                           GE, const1_rtx, SImode, 0, lab_false2);
 
-  tmp = build_int_2 ((MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD) + va_size, 0);
+  tmp = build (PLUS_EXPR, sizetype, make_tree (intSI_type_node, va_size),
+              build_int_2 (MAX_ARGS_IN_REGISTERS * UNITS_PER_WORD, 0));
   tmp = build (MODIFY_EXPR, integer_type_node, ndx, tmp);
   TREE_SIDE_EFFECTS (tmp) = 1;
   expand_expr (tmp, const0_rtx, VOIDmode, EXPAND_NORMAL);
@@ -2533,31 +2545,44 @@ xtensa_va_arg (valist, type)
   if (r != array)
     emit_move_insn (array, r);
 
+  emit_label (lab_over);
+
 
   /* Given the base array pointer (__array) and index to the subsequent
      argument (__va_ndx), find the address:
 
-     Big-endian:
-     __array + (AP).__va_ndx - sizeof (TYPE)
-
-     Little-endian:
-     __array + (AP).__va_ndx - __va_size (TYPE)
+     __array + (AP).__va_ndx - (BYTES_BIG_ENDIAN && sizeof (TYPE) < 4
+                               ? sizeof (TYPE)
+                               : __va_size (TYPE))
 
      The results are endian-dependent because values smaller than one word
      are aligned differently.
   */
 
-  emit_label (lab_over);
+  size = gen_reg_rtx (SImode);
+  emit_move_insn (size, va_size);
+  
+  if (BYTES_BIG_ENDIAN)
+    {
+      rtx lab_use_va_size = gen_label_rtx ();
+
+      emit_cmp_and_jump_insns (expand_expr (type_size, NULL_RTX, SImode,
+                                           EXPAND_NORMAL),
+                              GEN_INT (PARM_BOUNDARY / BITS_PER_UNIT),
+                              GE, const1_rtx, SImode, 0, lab_use_va_size);
+
+      r = expand_expr (type_size, size, SImode, EXPAND_NORMAL);
+      if (r != size)
+       emit_move_insn (size, r);
+
+      emit_label (lab_use_va_size);
+    }
 
   addr_tree = build (PLUS_EXPR, ptr_type_node,
                     make_tree (ptr_type_node, array),
                     ndx);
-  addr_tree = build (PLUS_EXPR, ptr_type_node,
-                    addr_tree,
-                    build_int_2 (BYTES_BIG_ENDIAN
-                                 && size < (PARM_BOUNDARY / BITS_PER_UNIT)
-                                 ? -size
-                                 : -va_size, -1));
+  addr_tree = build (MINUS_EXPR, ptr_type_node, addr_tree,
+                    make_tree (intSI_type_node, size));
   addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
   addr = copy_to_reg (addr);
   return addr;
This page took 0.076059 seconds and 5 git commands to generate.