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);
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:
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);
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);
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;