summaryrefslogtreecommitdiff
path: root/gnu
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2013-02-08 05:24:37 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2013-02-08 05:24:37 +0000
commit179cadb75599f7924ef7b4bb265e947640bc95fc (patch)
tree2a1c4d730715dd0687b1adcc31ad73f498edaf63 /gnu
parent85567d9bc3924cfdc2e30fc221be7500de672128 (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.h3
-rw-r--r--gnu/usr.bin/gcc/gcc/config/m88k/m88k.c78
-rw-r--r--gnu/usr.bin/gcc/gcc/config/m88k/m88k.h3
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