diff options
Diffstat (limited to 'gcc/config/ia64/ia64.c')
-rw-r--r-- | gcc/config/ia64/ia64.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 0891ed23cd8..14fdfe25a1c 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -51,6 +51,7 @@ Boston, MA 02111-1307, USA. */ #include "hashtab.h" #include "langhooks.h" #include "cfglayout.h" +#include "tree-gimple.h" /* This is used for communication between ASM_OUTPUT_LABEL and ASM_OUTPUT_LABELREF. */ @@ -273,6 +274,7 @@ static void ia64_vms_init_libfuncs (void) static tree ia64_handle_model_attribute (tree *, tree, tree, int, bool *); static void ia64_encode_section_info (tree, rtx, int); static rtx ia64_struct_value_rtx (tree, int); +static void ia64_gimplify_va_arg (tree *, tree *, tree *); /* Table of valid machine attributes. */ @@ -407,6 +409,9 @@ static const struct attribute_spec ia64_attribute_table[] = #undef TARGET_STRICT_ARGUMENT_NAMING #define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true +#undef TARGET_GIMPLIFY_VA_ARG_EXPR +#define TARGET_GIMPLIFY_VA_ARG_EXPR ia64_gimplify_va_arg + struct gcc_target targetm = TARGET_INITIALIZER; /* Return 1 if OP is a valid operand for the MEM of a CALL insn. */ @@ -3987,6 +3992,39 @@ ia64_va_arg (tree valist, tree type) return std_expand_builtin_va_arg (valist, type); } + +static void +ia64_gimplify_va_arg (tree *expr_p, tree *pre_p, tree *post_p) +{ + tree valist = TREE_OPERAND (*expr_p, 0); + tree type = TREE_TYPE (*expr_p); + + /* Variable sized types are passed by reference. */ + if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST) + { + TREE_TYPE (*expr_p) = build_pointer_type (type); + std_gimplify_va_arg_expr (expr_p, pre_p, post_p); + *expr_p = build_fold_indirect_ref (*expr_p); + return; + } + + /* Aggregate arguments with alignment larger than 8 bytes start at + the next even boundary. Integer and floating point arguments + do so if they are larger than 8 bytes, whether or not they are + also aligned larger than 8 bytes. */ + if ((TREE_CODE (type) == REAL_TYPE || TREE_CODE (type) == INTEGER_TYPE) + ? int_size_in_bytes (type) > 8 : TYPE_ALIGN (type) > 8 * BITS_PER_UNIT) + { + tree t = build (PLUS_EXPR, TREE_TYPE (valist), valist, + build_int_2 (2 * UNITS_PER_WORD - 1, 0)); + t = build (BIT_AND_EXPR, TREE_TYPE (t), t, + build_int_2 (-2 * UNITS_PER_WORD, -1)); + t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t); + gimplify_and_add (t, pre_p); + } + + std_gimplify_va_arg_expr (expr_p, pre_p, post_p); +} /* Return 1 if function return value returned in memory. Return 0 if it is in a register. */ |