+ DECL_FIELD_CONTEXT (field_arg) = record;
+ DECL_FIELD_CONTEXT (field_stk) = record;
+ DECL_FIELD_CONTEXT (field_reg) = record;
+
+ TYPE_FIELDS (record) = field_arg;
+ TREE_CHAIN (field_arg) = field_stk;
+ TREE_CHAIN (field_stk) = field_reg;
+
+ layout_type (record);
+ return record;
+}
+
+/* Implement `va_start' for varargs and stdarg. */
+
+void
+m88k_va_start (stdarg_p, valist, nextarg)
+ int stdarg_p ATTRIBUTE_UNUSED;
+ tree valist;
+ rtx nextarg ATTRIBUTE_UNUSED;
+{
+ tree field_reg, field_stk, field_arg;
+ tree reg, stk, arg, t;
+
+ field_arg = TYPE_FIELDS (va_list_type_node);
+ field_stk = TREE_CHAIN (field_arg);
+ field_reg = TREE_CHAIN (field_stk);
+
+ arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
+ stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
+ reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
+
+ /* Fill in the ARG member. */
+ {
+ tree fntype = TREE_TYPE (current_function_decl);
+ int argadj = ((!(TYPE_ARG_TYPES (fntype) != 0
+ && (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
+ != void_type_node)))
+ ? -UNITS_PER_WORD : 0) + UNITS_PER_WORD - 1;
+ tree argsize;
+
+ if (CONSTANT_P (current_function_arg_offset_rtx))
+ {
+ int fixed = (INTVAL (current_function_arg_offset_rtx)
+ + argadj) / UNITS_PER_WORD;
+
+ argsize = build_int_2 (fixed, 0);
+ }
+ else
+ {
+ argsize = make_tree (integer_type_node,
+ current_function_arg_offset_rtx);
+ argsize = fold (build (PLUS_EXPR, integer_type_node, argsize,
+ build_int_2 (argadj, 0)));
+ argsize = fold (build (RSHIFT_EXPR, integer_type_node, argsize,
+ build_int_2 (2, 0)));
+ }
+
+ t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, argsize);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ }
+
+ /* Store the arg pointer in the __va_stk member. */
+ t = make_tree (TREE_TYPE (stk), virtual_incoming_args_rtx);
+ t = build (MODIFY_EXPR, TREE_TYPE (stk), stk, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ /* Tuck the return value from __builtin_saveregs into __va_reg. */
+ t = make_tree (TREE_TYPE (reg), expand_builtin_saveregs ());
+ t = build (MODIFY_EXPR, TREE_TYPE (reg), reg, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+}
+
+/* Implement `va_arg'. */
+
+rtx
+m88k_va_arg (valist, type)
+ tree valist, type;
+{
+ tree field_reg, field_stk, field_arg;
+ tree reg, stk, arg, arg_align, base, t;
+ int size, wsize, align, reg_p;
+ rtx addr_rtx;
+
+ field_arg = TYPE_FIELDS (va_list_type_node);
+ field_stk = TREE_CHAIN (field_arg);
+ field_reg = TREE_CHAIN (field_stk);
+
+ arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg);
+ stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk);
+ reg = build (COMPONENT_REF, TREE_TYPE (field_reg), valist, field_reg);
+
+ size = int_size_in_bytes (type);
+ wsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+ align = 1 << ((TYPE_ALIGN (type) / BITS_PER_UNIT) >> 3);
+ reg_p = (AGGREGATE_TYPE_P (type)
+ ? size == UNITS_PER_WORD && TYPE_ALIGN (type) == BITS_PER_WORD
+ : size <= 2*UNITS_PER_WORD);
+
+ /* Align __va_arg to the (doubleword?) boundary above. */
+ t = build (PLUS_EXPR, TREE_TYPE (arg), arg, build_int_2 (align - 1, 0));
+ arg_align = build (BIT_AND_EXPR, TREE_TYPE (t), t, build_int_2 (-align, -1));
+ arg_align = save_expr (arg_align);
+
+ /* Decide if we should read from stack or regs. */
+ t = build (LT_EXPR, integer_type_node, arg_align, build_int_2 (8, 0));
+ base = build (COND_EXPR, TREE_TYPE (reg), t, reg, stk);
+
+ /* Find the final address. */
+ t = build (PLUS_EXPR, TREE_TYPE (base), base, arg_align);
+ addr_rtx = expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
+ addr_rtx = copy_to_reg (addr_rtx);
+
+ /* Increment __va_arg. */
+ t = build (PLUS_EXPR, TREE_TYPE (arg), arg_align, build_int_2 (wsize, 0));
+ t = build (MODIFY_EXPR, TREE_TYPE (arg), arg, t);
+ TREE_SIDE_EFFECTS (t) = 1;
+ expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+ return addr_rtx;