Commit 84ea0f58 by Eric Botcazou Committed by Eric Botcazou

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
parent 8ea456b9
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
......
......@@ -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)
{
/* 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))
{
packed = true;
break;
}
/* 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)
{
tree field_type = TREE_TYPE (field);
if (!DECL_SIZE (field) || integer_zerop (DECL_SIZE (field)))
continue;
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)
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;
traverse_record_type<T, Func> (field_type, named, data, bitpos,
packed);
else
*intregs_p = 1;
if (DECL_PACKED (field))
*packed_p = 1;
{
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);
/* If all arg slots are filled, then must pass on stack. */
if (slotno >= SPARC_FP_ARG_MAX)
return -1;
/* 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 (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 arg slots are filled, then must pass on stack. */
if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
/* 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 arg slots are filled,
/* If there are only int args and all int slots are filled,
then must pass on stack. */
if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
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))
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;
if (nregs > 0 && nregs > SPARC_INT_ARG_MAX - this_slotno)
{
packed_p = true;
break;
}
nregs = SPARC_INT_ARG_MAX - this_slotno;
/* We need to pass this field (partly) on the stack. */
data->stack = 1;
}
/* Compute how many registers we need. */
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
if (TREE_CODE (field) == FIELD_DECL)
{
HOST_WIDE_INT bitpos = startbitpos;
if (nregs <= 0)
return false;
if (DECL_SIZE (field) != 0)
{
if (integer_zerop (DECL_SIZE (field)))
continue;
*pnregs = nregs;
return true;
}
if (tree_fits_uhwi_p (bit_position (field)))
bitpos += int_bit_position (field);
}
/* 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. */
/* ??? FIXME: else assume zero offset. */
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 (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)
/* 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)
{
if (parms->intoffset != -1)
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
}
else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
{
unsigned int startbit, endbit;
int intslots, this_slotno;
startbit = ROUND_DOWN (parms->intoffset, BITS_PER_WORD);
endbit = ROUND_UP (bitpos, BITS_PER_WORD);
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
nregs = 2;
}
else
nregs = 1;
intslots = (endbit - startbit) / BITS_PER_WORD;
this_slotno = parms->slotno + parms->intoffset
/ BITS_PER_WORD;
nslots = NWORDS_UP (nregs * GET_MODE_SIZE (mode));
if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno)
if (nslots > SPARC_FP_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;
}
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;
parms->nregs += intslots;
parms->intoffset = -1;
if (nregs <= 0)
return false;
}
/* 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;
*pnregs = nregs;
*pmode = mode;
return true;
}
/* A subroutine of function_arg_record_value. Count the number of registers
to be assigned for FIELD and between PARMS->intoffset and BITPOS. */
inline void
count_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
assign_data_t *data)
{
if (fp)
{
int nregs;
machine_mode mode;
if (compute_int_layout (bitpos, data, &nregs))
data->nregs += nregs;
if (compute_fp_layout (field, bitpos, data, &nregs, &mode))
data->nregs += nregs;
}
else
{
if (parms->intoffset == -1)
parms->intoffset = bitpos;
}
}
if (data->intoffset < 0)
data->intoffset = bitpos;
}
}
/* A subroutine of function_arg_record_value. Assign the bits of the
structure between parms->intoffset and bitpos to integer registers. */
structure between PARMS->intoffset and BITPOS to integer registers. */
static void
function_arg_record_value_3 (HOST_WIDE_INT bitpos,
struct function_arg_record_value_parms *parms)
assign_int_registers (HOST_WIDE_INT bitpos, assign_data_t *data)
{
int intoffset = data->intoffset;
machine_mode mode;
unsigned int regno;
unsigned int startbit, endbit;
int this_slotno, intslots, intoffset;
rtx reg;
if (parms->intoffset == -1)
return;
intoffset = parms->intoffset;
parms->intoffset = -1;
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;
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;
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
{
if (TREE_CODE (field) == FIELD_DECL)
{
HOST_WIDE_INT bitpos = startbitpos;
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;
if (DECL_SIZE (field) != 0)
do
{
if (integer_zerop (DECL_SIZE (field)))
continue;
if (tree_fits_uhwi_p (bit_position (field)))
bitpos += int_bit_position (field);
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);
}
/* ??? 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);
/* A subroutine of function_arg_record_value. Assign FIELD and the bits of
the structure between PARMS->intoffset and BITPOS to registers. */
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)
inline void
assign_registers (const_tree field, HOST_WIDE_INT bitpos, bool fp,
assign_data_t *data)
{
if (fp)
{
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
nregs = 2;
}
else
nregs = 1;
assign_int_registers (bitpos, data);
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;
}
assign_fp_registers (field, bitpos, data);
}
else
{
if (parms->intoffset == -1)
parms->intoffset = bitpos;
}
}
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;
}
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. */
......
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.
......
/* 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment