diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2013-02-08 05:24:37 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2013-02-08 05:24:37 +0000 |
commit | 179cadb75599f7924ef7b4bb265e947640bc95fc (patch) | |
tree | 2a1c4d730715dd0687b1adcc31ad73f498edaf63 /gnu | |
parent | 85567d9bc3924cfdc2e30fc221be7500de672128 (diff) |
Replace the dummy definition of FUNCTION_ARG_PASS_BY_REFERENCE(). The new
definition forces variable-sized types to always be passed by reference.
Update the varargs code to cope with this.
gcc.c-torture/execute/20020412-1 finally passes.
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/usr.bin/gcc/gcc/config/m88k/m88k-protos.h | 3 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/gcc/config/m88k/m88k.c | 78 | ||||
-rw-r--r-- | gnu/usr.bin/gcc/gcc/config/m88k/m88k.h | 3 |
3 files changed, 74 insertions, 10 deletions
diff --git a/gnu/usr.bin/gcc/gcc/config/m88k/m88k-protos.h b/gnu/usr.bin/gcc/gcc/config/m88k/m88k-protos.h index f97cadd9222..69880cc0973 100644 --- a/gnu/usr.bin/gcc/gcc/config/m88k/m88k-protos.h +++ b/gnu/usr.bin/gcc/gcc/config/m88k/m88k-protos.h @@ -94,6 +94,9 @@ extern struct rtx_def *m88k_function_arg PARAMS ((CUMULATIVE_ARGS, int)); extern void m88k_function_arg_advance PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, tree, int)); +extern int m88k_function_arg_pass_by_reference PARAMS ((CUMULATIVE_ARGS *, + enum machine_mode, + tree, int)); extern struct rtx_def *m88k_va_arg PARAMS ((tree, tree)); extern tree m88k_build_va_list PARAMS ((void)); #endif /* TREE_CODE */ diff --git a/gnu/usr.bin/gcc/gcc/config/m88k/m88k.c b/gnu/usr.bin/gcc/gcc/config/m88k/m88k.c index 3654d228dfa..07cb561b2ae 100644 --- a/gnu/usr.bin/gcc/gcc/config/m88k/m88k.c +++ b/gnu/usr.bin/gcc/gcc/config/m88k/m88k.c @@ -2243,6 +2243,17 @@ m88k_function_arg (args_so_far, mode, type, named) abort (); /* m88k_function_arg argument `type' is NULL for BLKmode. */ bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type); + + /* Variable-sized types get passed by reference, which can be passed + in registers. */ + if (bytes < 0) + { + if (args_so_far > 8 - (POINTER_SIZE / BITS_PER_WORD)) + return (rtx) 0; + + return gen_rtx_REG (Pmode, 2 + args_so_far); + } + words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; if ((args_so_far & 1) != 0 @@ -2280,6 +2291,18 @@ m88k_function_arg_advance (args_so_far, mode, type, named) mode = BLKmode; bytes = (mode != BLKmode) ? GET_MODE_SIZE (mode) : int_size_in_bytes (type); + asf = *args_so_far; + + /* Variable-sized types get passed by reference, which can be passed + in registers. */ + if (bytes < 0) + { + if (asf <= 8 - (POINTER_SIZE / BITS_PER_WORD)) + *args_so_far += POINTER_SIZE / BITS_PER_WORD; + + return; + } + words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD; /* Struct and unions which are not exactly the size of a register are to be @@ -2288,7 +2311,6 @@ m88k_function_arg_advance (args_so_far, mode, type, named) && (TYPE_ALIGN (type) != BITS_PER_WORD || bytes != UNITS_PER_WORD)) return; - asf = *args_so_far; /* Align arguments requiring more than word alignment to a double-word boundary (or an even register number if the argument will get passed in registers). */ @@ -2303,10 +2325,29 @@ m88k_function_arg_advance (args_so_far, mode, type, named) (*args_so_far) = asf + words; } +/* A C expression that indicates when an argument must be passed by + reference. If nonzero for an argument, a copy of that argument is + made in memory and a pointer to the argument is passed instead of + the argument itself. The pointer is passed in whatever way is + appropriate for passing a pointer to that type. + + On m88k, only variable sized types are passed by reference. */ + +int +m88k_function_arg_pass_by_reference (cum, mode, type, named) + CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED; + enum machine_mode mode ATTRIBUTE_UNUSED; + tree type; + int named ATTRIBUTE_UNUSED; +{ + return type != 0 && int_size_in_bytes (type) < 0; +} + /* Perform any needed actions needed for a function that is receiving a variable number of arguments. - CUM is as above. + CUM is a variable of type CUMULATIVE_ARGS which gives info about + the preceding args and about the function being called. MODE and TYPE are the mode and type of the current parameter. @@ -2478,7 +2519,7 @@ m88k_va_arg (valist, type) tree valist, type; { tree field_reg, field_stk, field_arg; - int size, wsize, align, reg_p; + int indirect_p, size, wsize, align, reg_p; rtx addr_rtx; rtx lab_done; @@ -2487,10 +2528,22 @@ m88k_va_arg (valist, type) field_reg = TREE_CHAIN (field_stk); size = int_size_in_bytes (type); - wsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; - reg_p = (AGGREGATE_TYPE_P (type) - ? size == UNITS_PER_WORD && TYPE_ALIGN (type) == BITS_PER_WORD - : size <= 2*UNITS_PER_WORD); + /* Variable sized types are passed by reference. */ + if (size < 0) + { + indirect_p = 1; + wsize = POINTER_SIZE / BITS_PER_WORD; + type = 0; + reg_p = 1; + } + else + { + indirect_p = 0; + wsize = (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD; + reg_p = (AGGREGATE_TYPE_P (type) + ? size == UNITS_PER_WORD && TYPE_ALIGN (type) == BITS_PER_WORD + : size <= 2*UNITS_PER_WORD); + } addr_rtx = gen_reg_rtx (Pmode); lab_done = gen_label_rtx (); @@ -2507,7 +2560,7 @@ m88k_va_arg (valist, type) /* Align __va_arg to a doubleword boundary if necessary. */ arg = build (COMPONENT_REF, TREE_TYPE (field_arg), valist, field_arg); - align = TYPE_ALIGN (type) / BITS_PER_WORD; + align = type == 0 ? 0 : TYPE_ALIGN (type) / BITS_PER_WORD; if (align > 1) { t = build (PLUS_EXPR, TREE_TYPE (arg), arg, build_int_2 (align - 1, 0)); @@ -2558,7 +2611,7 @@ m88k_va_arg (valist, type) stk = build (COMPONENT_REF, TREE_TYPE (field_stk), valist, field_stk); /* Align __va_stk to the type boundary if necessary. */ - align = TYPE_ALIGN (type) / BITS_PER_UNIT; + align = type == 0 ? 0 : TYPE_ALIGN (type) / BITS_PER_UNIT; if (align > UNITS_PER_WORD) { t = build (PLUS_EXPR, TREE_TYPE (stk), stk, build_int_2 (align - 1, 0)); @@ -2583,6 +2636,13 @@ m88k_va_arg (valist, type) emit_label (lab_done); + if (indirect_p) + { + rtx r = gen_rtx_MEM (Pmode, addr_rtx); + set_mem_alias_set (r, get_varargs_alias_set ()); + emit_move_insn (addr_rtx, r); + } + return addr_rtx; } diff --git a/gnu/usr.bin/gcc/gcc/config/m88k/m88k.h b/gnu/usr.bin/gcc/gcc/config/m88k/m88k.h index 12d38735eea..16f874a6125 100644 --- a/gnu/usr.bin/gcc/gcc/config/m88k/m88k.h +++ b/gnu/usr.bin/gcc/gcc/config/m88k/m88k.h @@ -848,7 +848,8 @@ enum reg_class { NO_REGS, AP_REG, XRF_REGS, GENERAL_REGS, AGRF_REGS, made in memory and a pointer to the argument is passed instead of the argument itself. The pointer is passed in whatever way is appropriate for passing a pointer to that type. */ -#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) (0) +#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \ + m88k_function_arg_pass_by_reference(&CUM, MODE, TYPE, NAMED) /* A C type for declaring a variable that is used as the first argument of `FUNCTION_ARG' and other related values. It suffices to count |