aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorEric Botcazou <ebotcazou@adacore.com>2016-02-29 10:20:31 +0000
committerEric Botcazou <ebotcazou@gcc.gnu.org>2016-02-29 10:20:31 +0000
commit84ea0f58505179d38b083f1df788adc7a4597629 (patch)
treed253331df7d56edd4f18a30266dfc41303a1de89 /gcc
parent8ea456b94ac356fd36ba7043195a2d6c65eebfa7 (diff)
downloadgcc-84ea0f58505179d38b083f1df788adc7a4597629.zip
gcc-84ea0f58505179d38b083f1df788adc7a4597629.tar.gz
gcc-84ea0f58505179d38b083f1df788adc7a4597629.tar.bz2
re PR target/69706 (internal compiler error: in extract_constrain_insn, at recog.c:2246)
PR target/69706 * config/sparc/sparc.c (ROUND_ADVANCE): Rename to... (NWORDS_UP): ...this (init_cumulative_args): Minor tweaks. (sparc_promote_function_mode): Likewise. (scan_record_type): Delete. (traverse_record_type): New function template. (classify_data_t): New structure type. (classify_registers): New inline function. (function_arg_slotno): In 64-bit mode, bail out early if FP slots are exhausted. Instantiate traverse_record_type on classify_registers and deal with the case of a structure passed in slot #15 with no FP field in the first word. (assign_data_t): New structure type. (compute_int_layout): New static function. (compute_fp_layout): Likewise. (count_registers): New inline function. (assign_int_registers): New static function. (assign_fp_registers): Likewise. (assign_registers): New inline function. (function_arg_record_value_1): Delete. (function_arg_record_value_2): Likewise. (function_arg_record_value_3): Likewise. (function_arg_record_value): Adjust to above changes. Instantiate traverse_record_type on count_registers to first count the number of registers to be used and then on assign_registers to assign them. (function_arg_union_value): Adjust to above renaming. (sparc_function_arg_1); Minor tweaks. Remove commented out code. (sparc_arg_partial_bytes): Adjust to above renaming. Deal with the case of a structure passed in slot #15 (sparc_function_arg_advance): Likewise. (function_arg_padding): Minor tweak. From-SVN: r233808
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog35
-rw-r--r--gcc/config/sparc/sparc.c664
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.target/sparc/20160229-1.c157
4 files changed, 490 insertions, 370 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 772fc3b..3edc42e 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,38 @@
+2016-02-29 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR target/69706
+ * config/sparc/sparc.c (ROUND_ADVANCE): Rename to...
+ (NWORDS_UP): ...this
+ (init_cumulative_args): Minor tweaks.
+ (sparc_promote_function_mode): Likewise.
+ (scan_record_type): Delete.
+ (traverse_record_type): New function template.
+ (classify_data_t): New structure type.
+ (classify_registers): New inline function.
+ (function_arg_slotno): In 64-bit mode, bail out early if FP slots are
+ exhausted. Instantiate traverse_record_type on classify_registers and
+ deal with the case of a structure passed in slot #15 with no FP field
+ in the first word.
+ (assign_data_t): New structure type.
+ (compute_int_layout): New static function.
+ (compute_fp_layout): Likewise.
+ (count_registers): New inline function.
+ (assign_int_registers): New static function.
+ (assign_fp_registers): Likewise.
+ (assign_registers): New inline function.
+ (function_arg_record_value_1): Delete.
+ (function_arg_record_value_2): Likewise.
+ (function_arg_record_value_3): Likewise.
+ (function_arg_record_value): Adjust to above changes. Instantiate
+ traverse_record_type on count_registers to first count the number of
+ registers to be used and then on assign_registers to assign them.
+ (function_arg_union_value): Adjust to above renaming.
+ (sparc_function_arg_1); Minor tweaks. Remove commented out code.
+ (sparc_arg_partial_bytes): Adjust to above renaming. Deal with the
+ case of a structure passed in slot #15
+ (sparc_function_arg_advance): Likewise.
+ (function_arg_padding): Minor tweak.
+
2016-02-29 Richard Biener <rguenther@suse.de>
PR tree-optimization/69720
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 71609f2..d077680 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -518,7 +518,6 @@ int sparc_indent_opcode = 0;
static void sparc_option_override (void);
static void sparc_init_modes (void);
-static void scan_record_type (const_tree, int *, int *, int *);
static int function_arg_slotno (const CUMULATIVE_ARGS *, machine_mode,
const_tree, bool, bool, int *, int *);
@@ -6086,8 +6085,8 @@ conventions. */
#define SPARC_INT_ARG_MAX 6
/* Maximum number of fp regs for args. */
#define SPARC_FP_ARG_MAX 16
-
-#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+/* Number of words (partially) occupied for a given size in units. */
+#define NWORDS_UP(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
/* Handle the INIT_CUMULATIVE_ARGS macro.
Initialize a variable CUM of type CUMULATIVE_ARGS
@@ -6095,25 +6094,20 @@ conventions. */
For a library call, FNTYPE is 0. */
void
-init_cumulative_args (struct sparc_args *cum, tree fntype,
- rtx libname ATTRIBUTE_UNUSED,
- tree fndecl ATTRIBUTE_UNUSED)
+init_cumulative_args (struct sparc_args *cum, tree fntype, rtx, tree)
{
cum->words = 0;
cum->prototype_p = fntype && prototype_p (fntype);
- cum->libcall_p = fntype == 0;
+ cum->libcall_p = !fntype;
}
/* Handle promotion of pointer and integer arguments. */
static machine_mode
-sparc_promote_function_mode (const_tree type,
- machine_mode mode,
- int *punsignedp,
- const_tree fntype ATTRIBUTE_UNUSED,
- int for_return ATTRIBUTE_UNUSED)
+sparc_promote_function_mode (const_tree type, machine_mode mode,
+ int *punsignedp, const_tree, int)
{
- if (type != NULL_TREE && POINTER_TYPE_P (type))
+ if (type && POINTER_TYPE_P (type))
{
*punsignedp = POINTERS_EXTEND_UNSIGNED;
return Pmode;
@@ -6135,36 +6129,75 @@ sparc_strict_argument_naming (cumulative_args_t ca ATTRIBUTE_UNUSED)
return TARGET_ARCH64 ? true : false;
}
-/* Scan the record type TYPE and return the following predicates:
- - INTREGS_P: the record contains at least one field or sub-field
- that is eligible for promotion in integer registers.
- - FP_REGS_P: the record contains at least one field or sub-field
- that is eligible for promotion in floating-point registers.
- - PACKED_P: the record contains at least one field that is packed. */
+/* Traverse the record TYPE recursively and call FUNC on its fields.
+ NAMED is true if this is for a named parameter. DATA is passed
+ to FUNC for each field. OFFSET is the starting position and
+ PACKED is true if we are inside a packed record. */
+template <typename T, void Func (const_tree, HOST_WIDE_INT, bool, T*)>
static void
-scan_record_type (const_tree type, int *intregs_p, int *fpregs_p,
- int *packed_p)
+traverse_record_type (const_tree type, bool named, T *data,
+ HOST_WIDE_INT offset = 0, bool packed = false)
{
- for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
- {
- if (TREE_CODE (field) == FIELD_DECL)
+ /* The ABI obviously doesn't specify how packed structures are passed.
+ These are passed in integer regs if possible, otherwise memory. */
+ if (!packed)
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
{
- tree field_type = TREE_TYPE (field);
+ packed = true;
+ break;
+ }
- if (TREE_CODE (field_type) == RECORD_TYPE)
- scan_record_type (field_type, intregs_p, fpregs_p, packed_p);
- else if ((FLOAT_TYPE_P (field_type)
- || TREE_CODE (field_type) == VECTOR_TYPE)
- && TARGET_FPU)
- *fpregs_p = 1;
- else
- *intregs_p = 1;
+ /* Walk the real fields, but skip those with no size or a zero size.
+ ??? Fields with variable offset are handled as having zero offset. */
+ for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ if (TREE_CODE (field) == FIELD_DECL)
+ {
+ if (!DECL_SIZE (field) || integer_zerop (DECL_SIZE (field)))
+ continue;
- if (DECL_PACKED (field))
- *packed_p = 1;
- }
+ HOST_WIDE_INT bitpos = offset;
+ if (TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST)
+ bitpos += int_bit_position (field);
+
+ tree field_type = TREE_TYPE (field);
+ if (TREE_CODE (field_type) == RECORD_TYPE)
+ traverse_record_type<T, Func> (field_type, named, data, bitpos,
+ packed);
+ else
+ {
+ const bool fp_type
+ = FLOAT_TYPE_P (field_type) || VECTOR_TYPE_P (field_type);
+ Func (field, bitpos, fp_type && named && !packed && TARGET_FPU,
+ data);
+ }
+ }
+}
+
+/* Handle recursive register classifying for structure layout. */
+
+typedef struct
+{
+ bool int_regs; /* true if field eligible to int registers. */
+ bool fp_regs; /* true if field eligible to FP registers. */
+ bool fp_regs_in_first_word; /* true if such field in first word. */
+} classify_data_t;
+
+/* A subroutine of function_arg_slotno. Classify the field. */
+
+inline void
+classify_registers (const_tree, HOST_WIDE_INT bitpos, bool fp,
+ classify_data_t *data)
+{
+ if (fp)
+ {
+ data->fp_regs = true;
+ if (bitpos < BITS_PER_WORD)
+ data->fp_regs_in_first_word = true;
}
+ else
+ data->int_regs = true;
}
/* Compute the slot number to pass an argument in.
@@ -6178,16 +6211,16 @@ scan_record_type (const_tree type, int *intregs_p, int *fpregs_p,
not be available.
NAMED is nonzero if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis).
- INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.
+ INCOMING is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.
*PREGNO records the register number to use if scalar type.
*PPADDING records the amount of padding needed in words. */
static int
function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
- const_tree type, bool named, bool incoming_p,
+ const_tree type, bool named, bool incoming,
int *pregno, int *ppadding)
{
- int regbase = (incoming_p
+ int regbase = (incoming
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno = cum->words;
@@ -6243,8 +6276,10 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
case MODE_VECTOR_INT:
if (TARGET_ARCH64 && TARGET_FPU && named)
{
+ /* If all arg slots are filled, then must pass on stack. */
if (slotno >= SPARC_FP_ARG_MAX)
return -1;
+
regno = SPARC_FP_ARG_FIRST + slotno * 2;
/* Arguments filling only one single FP register are
right-justified in the outer double FP register. */
@@ -6256,8 +6291,10 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
case MODE_INT:
case MODE_COMPLEX_INT:
+ /* If all arg slots are filled, then must pass on stack. */
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
+
regno = regbase + slotno;
break;
@@ -6270,42 +6307,43 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
if (TARGET_ARCH32
|| !type
- || (TREE_CODE (type) != VECTOR_TYPE
- && TREE_CODE (type) != RECORD_TYPE))
+ || (TREE_CODE (type) != RECORD_TYPE
+ && TREE_CODE (type) != VECTOR_TYPE))
{
+ /* If all arg slots are filled, then must pass on stack. */
if (slotno >= SPARC_INT_ARG_MAX)
return -1;
+
regno = regbase + slotno;
}
else /* TARGET_ARCH64 && type */
{
- int intregs_p = 0, fpregs_p = 0, packed_p = 0;
-
- /* First see what kinds of registers we would need. */
- if (TREE_CODE (type) == VECTOR_TYPE)
- fpregs_p = 1;
- else
- scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
-
- /* The ABI obviously doesn't specify how packed structures
- are passed. These are defined to be passed in int regs
- if possible, otherwise memory. */
- if (packed_p || !named)
- fpregs_p = 0, intregs_p = 1;
-
/* If all arg slots are filled, then must pass on stack. */
- if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
+ if (slotno >= SPARC_FP_ARG_MAX)
return -1;
- /* If there are only int args and all int arg slots are filled,
- then must pass on stack. */
- if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
- return -1;
+ if (TREE_CODE (type) == RECORD_TYPE)
+ {
+ classify_data_t data = { false, false, false };
+ traverse_record_type<classify_data_t, classify_registers>
+ (type, named, &data);
+
+ /* If all slots are filled except for the last one, but there
+ is no FP field in the first word, then must pass on stack. */
+ if (data.fp_regs
+ && !data.fp_regs_in_first_word
+ && slotno >= SPARC_FP_ARG_MAX - 1)
+ return -1;
+
+ /* If there are only int args and all int slots are filled,
+ then must pass on stack. */
+ if (!data.fp_regs
+ && data.int_regs
+ && slotno >= SPARC_INT_ARG_MAX)
+ return -1;
+ }
- /* Note that even if all int arg slots are filled, fp members may
- still be passed in regs if such regs are available.
- *PREGNO isn't set because there may be more than one, it's up
- to the caller to compute them. */
+ /* PREGNO isn't set since both int and FP regs can be used. */
return slotno;
}
break;
@@ -6318,277 +6356,211 @@ function_arg_slotno (const struct sparc_args *cum, machine_mode mode,
return slotno;
}
-/* Handle recursive register counting for structure field layout. */
+/* Handle recursive register counting/assigning for structure layout. */
-struct function_arg_record_value_parms
+typedef struct
{
- rtx ret; /* return expression being built. */
int slotno; /* slot number of the argument. */
- int named; /* whether the argument is named. */
int regbase; /* regno of the base register. */
- int stack; /* 1 if part of the argument is on the stack. */
int intoffset; /* offset of the first pending integer field. */
- unsigned int nregs; /* number of words passed in registers. */
-};
-
-static void function_arg_record_value_3
- (HOST_WIDE_INT, struct function_arg_record_value_parms *);
-static void function_arg_record_value_2
- (const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
-static void function_arg_record_value_1
- (const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
-static rtx function_arg_record_value (const_tree, machine_mode, int, int, int);
-static rtx function_arg_union_value (int, machine_mode, int, int);
+ int nregs; /* number of words passed in registers. */
+ bool stack; /* true if part of the argument is on the stack. */
+ rtx ret; /* return expression being built. */
+} assign_data_t;
-/* A subroutine of function_arg_record_value. Traverse the structure
- recursively and determine how many registers will be required. */
+/* A subroutine of function_arg_record_value. Compute the number of integer
+ registers to be assigned between PARMS->intoffset and BITPOS. Return
+ true if at least one integer register is assigned or false otherwise. */
-static void
-function_arg_record_value_1 (const_tree type, HOST_WIDE_INT startbitpos,
- struct function_arg_record_value_parms *parms,
- bool packed_p)
+static bool
+compute_int_layout (HOST_WIDE_INT bitpos, assign_data_t *data, int *pnregs)
{
- tree field;
+ if (data->intoffset < 0)
+ return false;
- /* We need to compute how many registers are needed so we can
- allocate the PARALLEL but before we can do that we need to know
- whether there are any packed fields. The ABI obviously doesn't
- specify how structures are passed in this case, so they are
- defined to be passed in int regs if possible, otherwise memory,
- regardless of whether there are fp values present. */
+ const int intoffset = data->intoffset;
+ data->intoffset = -1;
- if (! packed_p)
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
- {
- if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
- {
- packed_p = true;
- break;
- }
- }
+ const int this_slotno = data->slotno + intoffset / BITS_PER_WORD;
+ const unsigned int startbit = ROUND_DOWN (intoffset, BITS_PER_WORD);
+ const unsigned int endbit = ROUND_UP (bitpos, BITS_PER_WORD);
+ int nregs = (endbit - startbit) / BITS_PER_WORD;
- /* Compute how many registers we need. */
- for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ if (nregs > 0 && nregs > SPARC_INT_ARG_MAX - this_slotno)
{
- if (TREE_CODE (field) == FIELD_DECL)
- {
- HOST_WIDE_INT bitpos = startbitpos;
+ nregs = SPARC_INT_ARG_MAX - this_slotno;
- if (DECL_SIZE (field) != 0)
- {
- if (integer_zerop (DECL_SIZE (field)))
- continue;
+ /* We need to pass this field (partly) on the stack. */
+ data->stack = 1;
+ }
- if (tree_fits_uhwi_p (bit_position (field)))
- bitpos += int_bit_position (field);
- }
+ if (nregs <= 0)
+ return false;
- /* ??? FIXME: else assume zero offset. */
-
- if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
- function_arg_record_value_1 (TREE_TYPE (field),
- bitpos,
- parms,
- packed_p);
- else if ((FLOAT_TYPE_P (TREE_TYPE (field))
- || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
- && TARGET_FPU
- && parms->named
- && ! packed_p)
- {
- if (parms->intoffset != -1)
- {
- unsigned int startbit, endbit;
- int intslots, this_slotno;
+ *pnregs = nregs;
+ return true;
+}
- startbit = ROUND_DOWN (parms->intoffset, BITS_PER_WORD);
- endbit = ROUND_UP (bitpos, BITS_PER_WORD);
+/* A subroutine of function_arg_record_value. Compute the number and the mode
+ of the FP registers to be assigned for FIELD. Return true if at least one
+ FP register is assigned or false otherwise. */
- intslots = (endbit - startbit) / BITS_PER_WORD;
- this_slotno = parms->slotno + parms->intoffset
- / BITS_PER_WORD;
+static bool
+compute_fp_layout (const_tree field, HOST_WIDE_INT bitpos,
+ assign_data_t *data,
+ int *pnregs, machine_mode *pmode)
+{
+ const int this_slotno = data->slotno + bitpos / BITS_PER_WORD;
+ machine_mode mode = DECL_MODE (field);
+ int nregs, nslots;
- if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno)
- {
- intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno);
- /* We need to pass this field on the stack. */
- parms->stack = 1;
- }
+ /* Slots are counted as words while regs are counted as having the size of
+ the (inner) mode. */
+ if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE && mode == BLKmode)
+ {
+ mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+ nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
+ }
+ else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
+ {
+ mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
+ nregs = 2;
+ }
+ else
+ nregs = 1;
- parms->nregs += intslots;
- parms->intoffset = -1;
- }
+ nslots = NWORDS_UP (nregs * GET_MODE_SIZE (mode));
- /* There's no need to check this_slotno < SPARC_FP_ARG MAX.
- If it wasn't true we wouldn't be here. */
- if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
- && DECL_MODE (field) == BLKmode)
- parms->nregs += TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
- else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
- parms->nregs += 2;
- else
- parms->nregs += 1;
- }
- else
- {
- if (parms->intoffset == -1)
- parms->intoffset = bitpos;
- }
- }
+ if (nslots > SPARC_FP_ARG_MAX - this_slotno)
+ {
+ nslots = SPARC_FP_ARG_MAX - this_slotno;
+ nregs = (nslots * UNITS_PER_WORD) / GET_MODE_SIZE (mode);
+
+ /* We need to pass this field (partly) on the stack. */
+ data->stack = 1;
+
+ if (nregs <= 0)
+ return false;
}
+
+ *pnregs = nregs;
+ *pmode = mode;
+ return true;
}
-/* A subroutine of function_arg_record_value. Assign the bits of the
- structure between parms->intoffset and bitpos to integer registers. */
+/* A subroutine of function_arg_record_value. Count the number of registers
+ to be assigned for FIELD and between PARMS->intoffset and BITPOS. */
-static void
-function_arg_record_value_3 (HOST_WIDE_INT bitpos,
- struct function_arg_record_value_parms *parms)
+inline void
+count_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
+ assign_data_t *data)
{
- machine_mode mode;
- unsigned int regno;
- unsigned int startbit, endbit;
- int this_slotno, intslots, intoffset;
- rtx reg;
+ if (fp)
+ {
+ int nregs;
+ machine_mode mode;
- if (parms->intoffset == -1)
- return;
+ if (compute_int_layout (bitpos, data, &nregs))
+ data->nregs += nregs;
- intoffset = parms->intoffset;
- parms->intoffset = -1;
+ if (compute_fp_layout (field, bitpos, data, &nregs, &mode))
+ data->nregs += nregs;
+ }
+ else
+ {
+ if (data->intoffset < 0)
+ data->intoffset = bitpos;
+ }
+}
- startbit = ROUND_DOWN (intoffset, BITS_PER_WORD);
- endbit = ROUND_UP (bitpos, BITS_PER_WORD);
- intslots = (endbit - startbit) / BITS_PER_WORD;
- this_slotno = parms->slotno + intoffset / BITS_PER_WORD;
+/* A subroutine of function_arg_record_value. Assign the bits of the
+ structure between PARMS->intoffset and BITPOS to integer registers. */
+
+static void
+assign_int_registers (HOST_WIDE_INT bitpos, assign_data_t *data)
+{
+ int intoffset = data->intoffset;
+ machine_mode mode;
+ int nregs;
- intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
- if (intslots <= 0)
+ if (!compute_int_layout (bitpos, data, &nregs))
return;
/* If this is the trailing part of a word, only load that much into
the register. Otherwise load the whole register. Note that in
the latter case we may pick up unwanted bits. It's not a problem
at the moment but may wish to revisit. */
-
if (intoffset % BITS_PER_WORD != 0)
mode = smallest_mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
MODE_INT);
else
mode = word_mode;
+ const int this_slotno = data->slotno + intoffset / BITS_PER_WORD;
+ unsigned int regno = data->regbase + this_slotno;
intoffset /= BITS_PER_UNIT;
+
do
{
- regno = parms->regbase + this_slotno;
- reg = gen_rtx_REG (mode, regno);
- XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
+ rtx reg = gen_rtx_REG (mode, regno);
+ XVECEXP (data->ret, 0, data->stack + data->nregs)
= gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
-
- this_slotno += 1;
- intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
+ data->nregs += 1;
mode = word_mode;
- parms->nregs += 1;
- intslots -= 1;
+ regno += 1;
+ intoffset = (intoffset | (UNITS_PER_WORD - 1)) + 1;
}
- while (intslots > 0);
+ while (--nregs > 0);
}
-/* A subroutine of function_arg_record_value. Traverse the structure
- recursively and assign bits to floating point registers. Track which
- bits in between need integer registers; invoke function_arg_record_value_3
- to make that happen. */
+/* A subroutine of function_arg_record_value. Assign FIELD at position
+ BITPOS to FP registers. */
static void
-function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
- struct function_arg_record_value_parms *parms,
- bool packed_p)
+assign_fp_registers (const_tree field, HOST_WIDE_INT bitpos,
+ assign_data_t *data)
{
- tree field;
+ int nregs;
+ machine_mode mode;
- if (! packed_p)
- for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
- {
- if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
- {
- packed_p = true;
- break;
- }
- }
+ if (!compute_fp_layout (field, bitpos, data, &nregs, &mode))
+ return;
+
+ const int this_slotno = data->slotno + bitpos / BITS_PER_WORD;
+ int regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
+ if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
+ regno++;
+ int pos = bitpos / BITS_PER_UNIT;
- for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+ do
{
- if (TREE_CODE (field) == FIELD_DECL)
- {
- HOST_WIDE_INT bitpos = startbitpos;
+ rtx reg = gen_rtx_REG (mode, regno);
+ XVECEXP (data->ret, 0, data->stack + data->nregs)
+ = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
+ data->nregs += 1;
+ regno += GET_MODE_SIZE (mode) / 4;
+ pos += GET_MODE_SIZE (mode);
+ }
+ while (--nregs > 0);
+}
- if (DECL_SIZE (field) != 0)
- {
- if (integer_zerop (DECL_SIZE (field)))
- continue;
+/* A subroutine of function_arg_record_value. Assign FIELD and the bits of
+ the structure between PARMS->intoffset and BITPOS to registers. */
- if (tree_fits_uhwi_p (bit_position (field)))
- bitpos += int_bit_position (field);
- }
+inline void
+assign_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
+ assign_data_t *data)
+{
+ if (fp)
+ {
+ assign_int_registers (bitpos, data);
- /* ??? FIXME: else assume zero offset. */
-
- if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
- function_arg_record_value_2 (TREE_TYPE (field),
- bitpos,
- parms,
- packed_p);
- else if ((FLOAT_TYPE_P (TREE_TYPE (field))
- || TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
- && TARGET_FPU
- && parms->named
- && ! packed_p)
- {
- int this_slotno = parms->slotno + bitpos / BITS_PER_WORD;
- int regno, nregs, pos;
- machine_mode mode = DECL_MODE (field);
- rtx reg;
-
- function_arg_record_value_3 (bitpos, parms);
-
- if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
- && mode == BLKmode)
- {
- mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
- nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
- }
- else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
- {
- mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
- nregs = 2;
- }
- else
- nregs = 1;
-
- regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
- if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
- regno++;
- reg = gen_rtx_REG (mode, regno);
- pos = bitpos / BITS_PER_UNIT;
- XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
- = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
- parms->nregs += 1;
- while (--nregs > 0)
- {
- regno += GET_MODE_SIZE (mode) / 4;
- reg = gen_rtx_REG (mode, regno);
- pos += GET_MODE_SIZE (mode);
- XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
- = gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
- parms->nregs += 1;
- }
- }
- else
- {
- if (parms->intoffset == -1)
- parms->intoffset = bitpos;
- }
- }
+ assign_fp_registers (field, bitpos, data);
+ }
+ else
+ {
+ if (data->intoffset < 0)
+ data->intoffset = bitpos;
}
}
@@ -6602,52 +6574,33 @@ function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
not be available.
MODE is the argument's machine mode.
SLOTNO is the index number of the argument's slot in the parameter array.
- NAMED is nonzero if this argument is a named parameter
+ NAMED is true if this argument is a named parameter
(otherwise it is an extra parameter matching an ellipsis).
REGBASE is the regno of the base register for the parameter array. */
static rtx
function_arg_record_value (const_tree type, machine_mode mode,
- int slotno, int named, int regbase)
+ int slotno, bool named, int regbase)
{
HOST_WIDE_INT typesize = int_size_in_bytes (type);
- struct function_arg_record_value_parms parms;
- unsigned int nregs;
+ assign_data_t data;
+ int nregs;
- parms.ret = NULL_RTX;
- parms.slotno = slotno;
- parms.named = named;
- parms.regbase = regbase;
- parms.stack = 0;
+ data.slotno = slotno;
+ data.regbase = regbase;
- /* Compute how many registers we need. */
- parms.nregs = 0;
- parms.intoffset = 0;
- function_arg_record_value_1 (type, 0, &parms, false);
+ /* Count how many registers we need. */
+ data.nregs = 0;
+ data.intoffset = 0;
+ data.stack = false;
+ traverse_record_type<assign_data_t, count_registers> (type, named, &data);
/* Take into account pending integer fields. */
- if (parms.intoffset != -1)
- {
- unsigned int startbit, endbit;
- int intslots, this_slotno;
-
- startbit = ROUND_DOWN (parms.intoffset, BITS_PER_WORD);
- endbit = ROUND_UP (typesize*BITS_PER_UNIT, BITS_PER_WORD);
- intslots = (endbit - startbit) / BITS_PER_WORD;
- this_slotno = slotno + parms.intoffset / BITS_PER_WORD;
-
- if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno)
- {
- intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno);
- /* We need to pass this field on the stack. */
- parms.stack = 1;
- }
-
- parms.nregs += intslots;
- }
+ if (compute_int_layout (typesize * BITS_PER_UNIT, &data, &nregs))
+ data.nregs += nregs;
/* Allocate the vector and handle some annoying special cases. */
- nregs = parms.nregs;
+ nregs = data.nregs;
if (nregs == 0)
{
@@ -6670,7 +6623,7 @@ function_arg_record_value (const_tree type, machine_mode mode,
gcc_assert (nregs > 0);
- parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (parms.stack + nregs));
+ data.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (data.stack + nregs));
/* If at least one field must be passed on the stack, generate
(parallel [(expr_list (nil) ...) ...]) so that all fields will
@@ -6678,19 +6631,21 @@ function_arg_record_value (const_tree type, machine_mode mode,
semantics of TARGET_ARG_PARTIAL_BYTES doesn't handle the case
of structures for which the fields passed exclusively in registers
are not at the beginning of the structure. */
- if (parms.stack)
- XVECEXP (parms.ret, 0, 0)
+ if (data.stack)
+ XVECEXP (data.ret, 0, 0)
= gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
- /* Fill in the entries. */
- parms.nregs = 0;
- parms.intoffset = 0;
- function_arg_record_value_2 (type, 0, &parms, false);
- function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms);
+ /* Assign the registers. */
+ data.nregs = 0;
+ data.intoffset = 0;
+ traverse_record_type<assign_data_t, assign_registers> (type, named, &data);
- gcc_assert (parms.nregs == nregs);
+ /* Assign pending integer fields. */
+ assign_int_registers (typesize * BITS_PER_UNIT, &data);
- return parms.ret;
+ gcc_assert (data.nregs == nregs);
+
+ return data.ret;
}
/* Used by function_arg and sparc_function_value_1 to implement the conventions
@@ -6706,7 +6661,7 @@ static rtx
function_arg_union_value (int size, machine_mode mode, int slotno,
int regno)
{
- int nwords = ROUND_ADVANCE (size), i;
+ int nwords = NWORDS_UP (size), i;
rtx regs;
/* See comment in previous function for empty structures. */
@@ -6777,17 +6732,17 @@ function_arg_vector_value (int size, int regno)
static rtx
sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
- const_tree type, bool named, bool incoming_p)
+ const_tree type, bool named, bool incoming)
{
const CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
- int regbase = (incoming_p
+ int regbase = (incoming
? SPARC_INCOMING_INT_ARG_FIRST
: SPARC_OUTGOING_INT_ARG_FIRST);
int slotno, regno, padding;
enum mode_class mclass = GET_MODE_CLASS (mode);
- slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
+ slotno = function_arg_slotno (cum, mode, type, named, incoming,
&regno, &padding);
if (slotno == -1)
return 0;
@@ -6837,35 +6792,7 @@ sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
{
rtx reg = gen_rtx_REG (mode, regno);
if (cum->prototype_p || cum->libcall_p)
- {
- /* "* 2" because fp reg numbers are recorded in 4 byte
- quantities. */
-#if 0
- /* ??? This will cause the value to be passed in the fp reg and
- in the stack. When a prototype exists we want to pass the
- value in the reg but reserve space on the stack. That's an
- optimization, and is deferred [for a bit]. */
- if ((regno - SPARC_FP_ARG_FIRST) >= SPARC_INT_ARG_MAX * 2)
- return gen_rtx_PARALLEL (mode,
- gen_rtvec (2,
- gen_rtx_EXPR_LIST (VOIDmode,
- NULL_RTX, const0_rtx),
- gen_rtx_EXPR_LIST (VOIDmode,
- reg, const0_rtx)));
- else
-#else
- /* ??? It seems that passing back a register even when past
- the area declared by REG_PARM_STACK_SPACE will allocate
- space appropriately, and will not copy the data onto the
- stack, exactly as we desire.
-
- This is due to locate_and_pad_parm being called in
- expand_call whenever reg_parm_stack_space > 0, which
- while beneficial to our example here, would seem to be
- in error from what had been intended. Ho hum... -- r~ */
-#endif
- return reg;
- }
+ return reg;
else
{
rtx v0, v1;
@@ -6877,7 +6804,7 @@ sparc_function_arg_1 (cumulative_args_t cum_v, machine_mode mode,
/* On incoming, we don't need to know that the value
is passed in %f0 and %i0, and it confuses other parts
causing needless spillage even on the simplest cases. */
- if (incoming_p)
+ if (incoming)
return reg;
intreg = (SPARC_OUTGOING_INT_ARG_FIRST
@@ -6956,7 +6883,7 @@ sparc_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
{
int slotno, regno, padding;
- /* We pass false for incoming_p here, it doesn't matter. */
+ /* We pass false for incoming here, it doesn't matter. */
slotno = function_arg_slotno (get_cumulative_args (cum), mode, type, named,
false, &regno, &padding);
@@ -6966,8 +6893,8 @@ sparc_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
if (TARGET_ARCH32)
{
if ((slotno + (mode == BLKmode
- ? ROUND_ADVANCE (int_size_in_bytes (type))
- : ROUND_ADVANCE (GET_MODE_SIZE (mode))))
+ ? NWORDS_UP (int_size_in_bytes (type))
+ : NWORDS_UP (GET_MODE_SIZE (mode))))
> SPARC_INT_ARG_MAX)
return (SPARC_INT_ARG_MAX - slotno) * UNITS_PER_WORD;
}
@@ -6982,7 +6909,8 @@ sparc_arg_partial_bytes (cumulative_args_t cum, machine_mode mode,
int size = int_size_in_bytes (type);
if (size > UNITS_PER_WORD
- && slotno == SPARC_INT_ARG_MAX - 1)
+ && (slotno == SPARC_INT_ARG_MAX - 1
+ || slotno == SPARC_FP_ARG_MAX - 1))
return UNITS_PER_WORD;
}
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
@@ -7068,18 +6996,16 @@ sparc_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
int regno, padding;
- /* We pass false for incoming_p here, it doesn't matter. */
+ /* We pass false for incoming here, it doesn't matter. */
function_arg_slotno (cum, mode, type, named, false, &regno, &padding);
/* If argument requires leading padding, add it. */
cum->words += padding;
if (TARGET_ARCH32)
- {
- cum->words += (mode != BLKmode
- ? ROUND_ADVANCE (GET_MODE_SIZE (mode))
- : ROUND_ADVANCE (int_size_in_bytes (type)));
- }
+ cum->words += (mode == BLKmode
+ ? NWORDS_UP (int_size_in_bytes (type))
+ : NWORDS_UP (GET_MODE_SIZE (mode)));
else
{
if (type && AGGREGATE_TYPE_P (type))
@@ -7094,11 +7020,9 @@ sparc_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
++cum->words;
}
else
- {
- cum->words += (mode != BLKmode
- ? ROUND_ADVANCE (GET_MODE_SIZE (mode))
- : ROUND_ADVANCE (int_size_in_bytes (type)));
- }
+ cum->words += (mode == BLKmode
+ ? NWORDS_UP (int_size_in_bytes (type))
+ : NWORDS_UP (GET_MODE_SIZE (mode)));
}
}
@@ -7109,7 +7033,7 @@ sparc_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
enum direction
function_arg_padding (machine_mode mode, const_tree type)
{
- if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type))
+ if (TARGET_ARCH64 && type && AGGREGATE_TYPE_P (type))
return upward;
/* Fall back to the default. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4e85314..e5ec39c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
2016-02-29 Eric Botcazou <ebotcazou@adacore.com>
+ * gcc.target/sparc/20160229-1.c: New test.
+
+2016-02-29 Eric Botcazou <ebotcazou@adacore.com>
+
* gnat.dg/stack_usage3.adb: New test.
* gnat.dg/stack_usage3_pkg.ads: New helper.
diff --git a/gcc/testsuite/gcc.target/sparc/20160229-1.c b/gcc/testsuite/gcc.target/sparc/20160229-1.c
new file mode 100644
index 0000000..c64b7a8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/sparc/20160229-1.c
@@ -0,0 +1,157 @@
+/* PR target/69706 */
+/* Reported by John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> */
+
+/* { dg-do run } */
+/* { dg-options "-std=gnu99" }
+/* { dg-require-effective-target lp64 } */
+
+extern void abort (void);
+
+
+/* Pass a 12-byte structure partially in slot #15 and on the stack. */
+
+struct t_rgb { float r, g, b; };
+
+void write_xpm (void *out, unsigned int flags, const char *title,
+ const char *legend, const char *label_x, const char *label_y,
+ int n_x, int n_y, float axis_x[], float axis_y[], float *mat[],
+ float lo, float hi, struct t_rgb rlo, struct t_rgb rhi)
+{
+ register float f30 asm ("f30");
+ register float f31 asm ("f31");
+
+ if (f30 != 1.0f)
+ abort ();
+
+ if (f31 != 2.0f)
+ abort ();
+
+ if (rhi.r != 1.0f)
+ abort ();
+
+ if (rhi.g != 2.0f)
+ abort ();
+
+ if (rhi.b != 3.0f)
+ abort ();
+}
+
+
+/* Pass a 16-byte structure partially in slot #15 and on the stack. */
+
+struct S1 { _Complex float f1; _Complex float f2; };
+
+void f1 (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8,
+ int p9, int p10, int p11, int p12, int p13, int p14, int p15,
+ struct S1 s1)
+{
+ register float f30 asm ("f30");
+ register float f31 asm ("f31");
+
+ if (f30 != 4.0f)
+ abort ();
+
+ if (f31 != 5.0f)
+ abort ();
+
+ if (__real__ s1.f1 != 4.0f)
+ abort ();
+
+ if (__imag__ s1.f1 != 5.0f)
+ abort ();
+
+ if (__real__ s1.f2 != 6.0f)
+ abort ();
+
+ if (__imag__ s1.f2 != 7.0f)
+ abort ();
+}
+
+
+/* Pass a 16-byte structure partially in slot #15 and on the stack. */
+
+struct S2 { double d1; double d2; };
+
+void f2 (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8,
+ int p9, int p10, int p11, int p12, int p13, int p14, int p15,
+ struct S2 s2)
+{
+ register double d30 asm ("f30");
+
+ if (d30 != 1.0)
+ abort ();
+
+ if (s2.d1 != 1.0)
+ abort ();
+
+ if (s2.d2 != 2.0)
+ abort ();
+}
+
+
+/* Pass a 16-byte structure partially in slot #15 and on the stack. */
+
+struct S3 { _Complex double d; };
+
+void f3 (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8,
+ int p9, int p10, int p11, int p12, int p13, int p14, int p15,
+ struct S3 s3)
+{
+ register double d30 asm ("f30");
+
+ if (d30 != 3.0)
+ abort ();
+
+ if (__real__ s3.d != 3.0)
+ abort ();
+
+ if (__imag__ s3.d != 4.0)
+ abort ();
+}
+
+
+/* Pass a 16-byte structure entirely on the stack. */
+
+struct S4 { long l; double d; };
+
+void f4 (int p1, int p2, int p3, int p4, int p5, int p6, int p7, int p8,
+ int p9, int p10, int p11, int p12, int p13, int p14, int p15,
+ struct S4 s4)
+{
+ if (s4.l != 5)
+ abort ();
+
+ if (s4.d != 6.0)
+ abort ();
+}
+
+
+#define PI 3.141592654
+
+int main (void)
+{
+ struct t_rgb lo = { -1.0f, -2.0f, -3.0f };
+ struct t_rgb hi = { 1.0f, 2.0f, 3.0f };
+ float arrf[1];
+ float *arrp[1];
+ struct S1 s1 = { 4.0f + 5.0fi, 6.0f + 7.0fi };
+ struct S2 s2 = { 1.0, 2.0 };
+ struct S3 s3 = { 3.0 + 4.0i };
+ struct S4 s4 = { 5, 6.0 };
+ register double d32 asm ("f32") = PI;
+
+ write_xpm (0, 0, "", "", "", "", 0, 0, arrf, arrf, arrp, 0.0f, 0.0f, lo, hi);
+
+ f1 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, s1);
+
+ f2 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, s2);
+
+ f3 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, s3);
+
+ f4 (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, s4);
+
+ if (d32 != PI)
+ abort ();
+
+ return 0;
+}