From: Eric Botcazou Date: Mon, 29 Feb 2016 10:20:31 +0000 (+0000) Subject: re PR target/69706 (internal compiler error: in extract_constrain_insn, at recog... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=84ea0f58505179d38b083f1df788adc7a4597629;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 772fc3b7582..3edc42e47ff 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,38 @@ +2016-02-29 Eric Botcazou + + 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 PR tree-optimization/69720 diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 71609f27701..d077680048c 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 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 (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 + (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 (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 (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, ®no, &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, ®no, &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, ®no, &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 4e85314e00b..e5ec39c67f7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2016-02-29 Eric Botcazou + + * gcc.target/sparc/20160229-1.c: New test. + 2016-02-29 Eric Botcazou * gnat.dg/stack_usage3.adb: New test. 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 00000000000..c64b7a83540 --- /dev/null +++ b/gcc/testsuite/gcc.target/sparc/20160229-1.c @@ -0,0 +1,157 @@ +/* PR target/69706 */ +/* Reported by John Paul Adrian Glaubitz */ + +/* { 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; +}