From 015b1ad1dfa8fbd7323691515a5c1c38c4c1541d Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Wed, 4 Sep 2002 18:09:32 +0000 Subject: [PATCH] expr.c (emit_group_load): Revise to allow splitting TCmode source into DImode pieces. * expr.c (emit_group_load): Revise to allow splitting TCmode source into DImode pieces. * pa-64.h (LONG_DOUBLE_TYPE_SIZE): Define to 128. * pa64-regs.h (CLASS_CANNOT_CHANGE_MODE_P): Inhibit changes from SImode for floating-point register class. * pa.c (function_arg): Fix handling of modes wider than one word for TARGET_64BIT. From-SVN: r56805 --- gcc/ChangeLog | 11 +++++ gcc/config/pa/pa-64.h | 4 +- gcc/config/pa/pa.c | 96 ++++++++++++++------------------------- gcc/config/pa/pa64-regs.h | 19 +++++--- gcc/expr.c | 21 +++++---- 5 files changed, 71 insertions(+), 80 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 682001bb491..e7d7646dc49 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2002-09-04 John David Anglin + + * expr.c (emit_group_load): Revise to allow splitting TCmode source + into DImode pieces. + + * pa-64.h (LONG_DOUBLE_TYPE_SIZE): Define to 128. + * pa64-regs.h (CLASS_CANNOT_CHANGE_MODE_P): Inhibit changes from SImode + for floating-point register class. + * pa.c (function_arg): Fix handling of modes wider than one word for + TARGET_64BIT. + Wed Sep 4 18:48:10 2002 J"orn Rennecke * combine.c (make_compound_operation): Don't generate zero / sign diff --git a/gcc/config/pa/pa-64.h b/gcc/config/pa/pa-64.h index 2658038c51f..82ce3ef45f2 100644 --- a/gcc/config/pa/pa-64.h +++ b/gcc/config/pa/pa-64.h @@ -65,10 +65,8 @@ Boston, MA 02111-1307, USA. */ #define FLOAT_TYPE_SIZE 32 #undef DOUBLE_TYPE_SIZE #define DOUBLE_TYPE_SIZE 64 -/* This should be 128, but until we work out the ABI for the 128bit - FP codes supplied by HP we'll keep it at 64 bits. */ #undef LONG_DOUBLE_TYPE_SIZE -#define LONG_DOUBLE_TYPE_SIZE 64 +#define LONG_DOUBLE_TYPE_SIZE 128 /* Temporary until we figure out what to do with those *(&@$ 32bit relocs which appear in stabs. */ diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c index 718ad1382a1..2d655394a0d 100644 --- a/gcc/config/pa/pa.c +++ b/gcc/config/pa/pa.c @@ -7446,6 +7446,8 @@ function_arg (cum, mode, type, named, incoming) int incoming; { int max_arg_words = (TARGET_64BIT ? 8 : 4); + int arg_size = FUNCTION_ARG_SIZE (mode, type); + int alignment = 0; int fpr_reg_base; int gpr_reg_base; rtx retval; @@ -7456,16 +7458,15 @@ function_arg (cum, mode, type, named, incoming) this routine should return zero. FUNCTION_ARG_PARTIAL_NREGS will handle arguments which are split between regs and stack slots if the ABI mandates split arguments. */ - if (cum->words + FUNCTION_ARG_SIZE (mode, type) > max_arg_words + if (cum->words + arg_size > max_arg_words || mode == VOIDmode) return NULL_RTX; } else { - int offset = 0; - if (FUNCTION_ARG_SIZE (mode, type) > 1 && (cum->words & 1)) - offset = 1; - if (cum->words + offset >= max_arg_words + if (arg_size > 1) + alignment = cum->words & 1; + if (cum->words + alignment >= max_arg_words || mode == VOIDmode) return NULL_RTX; } @@ -7474,70 +7475,54 @@ function_arg (cum, mode, type, named, incoming) particularly in their handling of FP registers. We might be able to cleverly share code between them, but I'm not going to bother in the hope that splitting them up results - in code that is more easily understood. + in code that is more easily understood. */ - The 64bit code probably is very wrong for structure passing. */ if (TARGET_64BIT) { /* Advance the base registers to their current locations. Remember, gprs grow towards smaller register numbers while - fprs grow to higher register numbers. Also remember FP regs - are always 4 bytes wide, while the size of an integer register - varies based on the size of the target word. */ + fprs grow to higher register numbers. Also remember that + although FP regs are 32-bit addressable, we pretend that + the registers are 64-bits wide. */ gpr_reg_base = 26 - cum->words; fpr_reg_base = 32 + cum->words; - /* If the argument is more than a word long, then we need to align - the base registers. Same caveats as above. */ - if (FUNCTION_ARG_SIZE (mode, type) > 1) + /* Arguments wider than one word need special treatment. */ + if (arg_size > 1) { - if (mode != BLKmode) - { - /* First deal with alignment of the doubleword. */ - gpr_reg_base -= (cum->words & 1); + /* Double-extended precision (80-bit), quad-precision (128-bit) + and aggregates including complex numbers are aligned on + 128-bit boundaries. The first eight 64-bit argument slots + are associated one-to-one, with general registers r26 + through r19, and also with floating-point registers fr4 + through fr11. Arguments larger than one word are always + passed in general registers. */ - /* This seems backwards, but it is what HP specifies. We need - gpr_reg_base to point to the smaller numbered register of - the integer register pair. So if we have an even register - number, then decrement the gpr base. */ - gpr_reg_base -= ((gpr_reg_base % 2) == 0); + rtx loc[8]; + int i, offset = 0, ub = arg_size; - /* FP values behave sanely, except that each FP reg is only - half of word. */ - fpr_reg_base += ((fpr_reg_base % 2) == 0); - } - else + /* Align the base register. */ + gpr_reg_base -= alignment; + + ub = MIN (ub, max_arg_words - cum->words - alignment); + for (i = 0; i < ub; i++) { - rtx loc[8]; - int i, offset = 0, ub; - ub = FUNCTION_ARG_SIZE (mode, type); - ub = MIN (ub, - MAX (0, max_arg_words - cum->words - (cum->words & 1))); - gpr_reg_base -= (cum->words & 1); - for (i = 0; i < ub; i++) - { - loc[i] = gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (DImode, - gpr_reg_base), - GEN_INT (offset)); - gpr_reg_base -= 1; - offset += 8; - } - if (ub == 0) - return NULL_RTX; - else if (ub == 1) - return XEXP (loc[0], 0); - else - return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc)); + loc[i] = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_REG (DImode, gpr_reg_base), + GEN_INT (offset)); + gpr_reg_base -= 1; + offset += 8; } + + return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc)); } } else { /* If the argument is larger than a word, then we know precisely which registers we must use. */ - if (FUNCTION_ARG_SIZE (mode, type) > 1) + if (arg_size > 1) { if (cum->words) { @@ -7559,19 +7544,6 @@ function_arg (cum, mode, type, named, incoming) } } - if (TARGET_64BIT && mode == TFmode) - { - return - gen_rtx_PARALLEL - (mode, - gen_rtvec (2, - gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (DImode, gpr_reg_base + 1), - const0_rtx), - gen_rtx_EXPR_LIST (VOIDmode, - gen_rtx_REG (DImode, gpr_reg_base), - GEN_INT (8)))); - } /* Determine if the argument needs to be passed in both general and floating point registers. */ if (((TARGET_PORTABLE_RUNTIME || TARGET_64BIT || TARGET_ELF32) diff --git a/gcc/config/pa/pa64-regs.h b/gcc/config/pa/pa64-regs.h index b193c99b075..0af4c5fb270 100644 --- a/gcc/config/pa/pa64-regs.h +++ b/gcc/config/pa/pa64-regs.h @@ -234,16 +234,21 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FPUPPER_REGS, FP_REGS, /* If defined, gives a class of registers that cannot be used as the operand of a SUBREG that changes the mode of the object illegally. */ -/* ??? This may not actually be necessary anymore. But until I can prove - otherwise it will stay. */ + #define CLASS_CANNOT_CHANGE_MODE (FP_REGS) -/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */ -#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) +/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. -/* The same information, inverted: - Return the class number of the smallest class containing + SImode loads to floating-point registers are not zero-extended. + The definition for LOAD_EXTEND_OP specifies that integer loads + narrower than BITS_PER_WORD will be zero-extended. As a result, + we inhibit changes from SImode unless they are to a mode that is + identical in size. */ + +#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \ + ((FROM) == SImode && GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) + +/* Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression or could index an array. */ diff --git a/gcc/expr.c b/gcc/expr.c index ca8952bffc7..5872ab055fb 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -2265,21 +2265,26 @@ emit_group_load (dst, orig_src, ssize) } else if (GET_CODE (src) == CONCAT) { - if ((bytepos == 0 - && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 0)))) - || (bytepos == (HOST_WIDE_INT) GET_MODE_SIZE (GET_MODE (XEXP (src, 0))) - && bytelen == GET_MODE_SIZE (GET_MODE (XEXP (src, 1))))) + unsigned int slen = GET_MODE_SIZE (GET_MODE (src)); + unsigned int slen0 = GET_MODE_SIZE (GET_MODE (XEXP (src, 0))); + + if ((bytepos == 0 && bytelen == slen0) + || (bytepos != 0 && bytepos + bytelen <= slen)) { - tmps[i] = XEXP (src, bytepos != 0); + /* The following assumes that the concatenated objects all + have the same size. In this case, a simple calculation + can be used to determine the object and the bit field + to be extracted. */ + tmps[i] = XEXP (src, bytepos / slen0); if (! CONSTANT_P (tmps[i]) && (GET_CODE (tmps[i]) != REG || GET_MODE (tmps[i]) != mode)) tmps[i] = extract_bit_field (tmps[i], bytelen * BITS_PER_UNIT, - 0, 1, NULL_RTX, mode, mode, ssize); + (bytepos % slen0) * BITS_PER_UNIT, + 1, NULL_RTX, mode, mode, ssize); } else if (bytepos == 0) { - rtx mem = assign_stack_temp (GET_MODE (src), - GET_MODE_SIZE (GET_MODE (src)), 0); + rtx mem = assign_stack_temp (GET_MODE (src), slen, 0); emit_move_insn (mem, src); tmps[i] = adjust_address (mem, mode, 0); }