From mboxrd@z Thu Jan 1 00:00:00 1970 From: Weiwen Liu To: rth@cygnus.com Cc: egcs@cygnus.com Subject: Re: complex support on alpha Date: Sun, 05 Oct 1997 16:16:00 -0000 Message-id: References: <199710020532.WAA16123@dot.cygnus.com> X-SW-Source: 1997-10/msg00204.html On Wed, 1 Oct 1997, Richard Henderson wrote: > Well, it is enough to compile those examples properly, but it is > not completely correct. The problem is that complex numbers should > be treated as two distinct arguments on Alpha, which affects padding > of the arguments passed on the stack. > Here is a patch for it. It should be applied against egcs-970929. Beside fixing complex-5.c in the testsuite, egcs with this patch generates the same result from 'make check-gcc' as without it. On an alpha-dec-osf4.0, this patch correctly compiles the following test program with F=char, short, int, long, float, double: #ifndef F #define F float #endif typedef __complex__ F FC; FC f1(int odd, FC a, FC b, FC c) { return a + b + c; } FC f2a(F a, F b, F c, F d, F e, F f, F g, F h) { return (a + c + e + g) + 1i * (b + d + f + h); } FC f2b(FC a, FC b, FC c, FC d) { return a + b + c + d; } int main() { FC a, b, c, d, e; a = 1 + 2i; b = 3+4i; c = 5+6i; d = 7+8i; e = f1(1,a,b,c); if (e != 9+12i) abort (); e=f2b(a,b,c,d); if (e != 16+20i) abort (); e=f2a(1,2,3,4,5,6,7,8); if (e != 16+20i) abort (); return 0; } This patch has only been tested on alpha-dec-osf4.0, because I have no access to other machines. To support compless on other machines, the machine-dependent tm.h has to be modified similarly to what is done for alpha.h here. Weiwen Sun Oct 5 19:00:00 Weiwen Liu * c-tree.h: Define complex_long_integer_type_node to support __complex__ long. * c-decl.c (init_decl_processing): Initialize complex_long_integer_type_node. * c-lex.c (yylex): Enable __complex__ long. * expr.h: Define COMPLEX_WORD_MODE and GET_COMPLEX_MODE_SIZE. * emit-rtl.c (gen_lowpart_common, gen_highpart, operand_subword): Use them. * expr.c (move_block_to_reg, emit_push_insn): Use them. * emit-rtl.c (operand_subword): Deal with a complex mode. * regs.h: Correctly calculate REG_SIZE for a complex mode. * config/alpha/alpha.h: Correctly deal with a complex mode in HARD_REGNO_NREGS, FUNCTION_VALUE, ALPHA_ARG_SIZE. *** gcc/c-decl.c.orig Sat Sep 27 14:16:06 1997 --- gcc/c-decl.c Wed Oct 1 16:19:39 1997 *************** tree double_type_node; *** 135,140 **** --- 135,141 ---- tree long_double_type_node; tree complex_integer_type_node; + tree complex_long_integer_type_node; tree complex_float_type_node; tree complex_double_type_node; tree complex_long_double_type_node; *************** init_decl_processing () *** 2989,2994 **** --- 2990,3001 ---- complex_integer_type_node)); TREE_TYPE (complex_integer_type_node) = integer_type_node; layout_type (complex_integer_type_node); + + complex_long_integer_type_node = make_node (COMPLEX_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long int"), + complex_long_integer_type_node)); + TREE_TYPE (complex_long_integer_type_node) = long_integer_type_node; + layout_type (complex_long_integer_type_node); complex_float_type_node = make_node (COMPLEX_TYPE); pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"), *** gcc/c-lex.c.orig Fri Aug 15 01:32:53 1997 --- gcc/c-lex.c Wed Oct 1 16:19:39 1997 *************** yylex () *** 1769,1774 **** --- 1769,1780 ---- = build_complex (NULL_TREE, integer_zero_node, convert (integer_type_node, yylval.ttype)); + else if (TYPE_PRECISION (type) + <= TYPE_PRECISION (long_integer_type_node)) + yylval.ttype + = build_complex (NULL_TREE, integer_zero_node, + convert (long_integer_type_node, + yylval.ttype)); else error ("complex integer constant is too wide for `complex int'"); } *** gcc/c-tree.h.orig Mon Aug 11 11:57:03 1997 --- gcc/c-tree.h Wed Oct 1 16:19:40 1997 *************** extern tree long_long_integer_type_node; *** 219,224 **** --- 219,225 ---- extern tree long_long_unsigned_type_node; extern tree long_unsigned_type_node; extern tree complex_integer_type_node; + extern tree complex_long_integer_type_node; extern tree complex_float_type_node; extern tree complex_double_type_node; extern tree complex_long_double_type_node; *** gcc/emit-rtl.c.orig Mon Sep 22 13:41:24 1997 --- gcc/emit-rtl.c Sun Oct 5 17:48:05 1997 *************** gen_lowpart_common (mode, x) *** 635,644 **** / UNITS_PER_WORD))) return 0; ! if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) ! word = ((GET_MODE_SIZE (GET_MODE (x)) ! - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) ! / UNITS_PER_WORD); if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND) && (GET_MODE_CLASS (mode) == MODE_INT --- 635,644 ---- / UNITS_PER_WORD))) return 0; ! if (WORDS_BIG_ENDIAN && GET_MODE_SIZE (GET_MODE (x)) >0) ! word = GET_COMPLEX_MODE_SIZE (GET_MODE (x)) ! - ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) ! / UNITS_PER_WORD); if ((GET_CODE (x) == ZERO_EXTEND || GET_CODE (x) == SIGN_EXTEND) && (GET_MODE_CLASS (mode) == MODE_INT *************** gen_highpart (mode, x) *** 1013,1022 **** int word = 0; if (! WORDS_BIG_ENDIAN ! && GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD) ! word = ((GET_MODE_SIZE (GET_MODE (x)) ! - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD)) ! / UNITS_PER_WORD); /* * ??? This fails miserably for complex values being passed in registers --- 1013,1022 ---- int word = 0; if (! WORDS_BIG_ENDIAN ! && GET_MODE_SIZE (GET_MODE (x)) > 0) ! word = GET_COMPLEX_MODE_SIZE (GET_MODE (x)) ! - ((GET_MODE_SIZE (mode) + (UNITS_PER_WORD - 1)) ! / UNITS_PER_WORD); /* * ??? This fails miserably for complex values being passed in registers *************** operand_subword (op, i, validate_address *** 1100,1105 **** --- 1100,1107 ---- /* If OP is narrower than a word or if we want a word outside OP, fail. */ if (mode != BLKmode + && (GET_MODE_CLASS (mode) != MODE_COMPLEX_INT + && GET_MODE_CLASS (mode) != MODE_COMPLEX_FLOAT) && (GET_MODE_SIZE (mode) < UNITS_PER_WORD || (i + 1) * UNITS_PER_WORD > GET_MODE_SIZE (mode))) return 0; *************** operand_subword (op, i, validate_address *** 1127,1133 **** || op == arg_pointer_rtx #endif || op == stack_pointer_rtx) ! return gen_rtx (SUBREG, word_mode, op, i); else return gen_rtx (REG, word_mode, REGNO (op) + i); } --- 1129,1135 ---- || op == arg_pointer_rtx #endif || op == stack_pointer_rtx) ! return gen_rtx (SUBREG, COMPLEX_WORD_MODE (mode), op, i); else return gen_rtx (REG, word_mode, REGNO (op) + i); } *************** operand_subword (op, i, validate_address *** 1135,1141 **** return gen_rtx (SUBREG, word_mode, SUBREG_REG (op), i + SUBREG_WORD (op)); else if (GET_CODE (op) == CONCAT) { ! int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD; if (i < partwords) return operand_subword (XEXP (op, 0), i, validate_address, mode); return operand_subword (XEXP (op, 1), i - partwords, --- 1137,1144 ---- return gen_rtx (SUBREG, word_mode, SUBREG_REG (op), i + SUBREG_WORD (op)); else if (GET_CODE (op) == CONCAT) { ! int partwords = (GET_MODE_UNIT_SIZE (GET_MODE (op)) ! + (UNITS_PER_WORD - 1))/ UNITS_PER_WORD; if (i < partwords) return operand_subword (XEXP (op, 0), i, validate_address, mode); return operand_subword (XEXP (op, 1), i - partwords, *************** operand_subword (op, i, validate_address *** 1145,1151 **** /* Form a new MEM at the requested address. */ if (GET_CODE (op) == MEM) { ! rtx addr = plus_constant (XEXP (op, 0), i * UNITS_PER_WORD); rtx new; if (validate_address) --- 1148,1158 ---- /* Form a new MEM at the requested address. */ if (GET_CODE (op) == MEM) { ! rtx addr = plus_constant ( ! XEXP (op, 0), ! (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT ! || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)? ! i*GET_MODE_UNIT_SIZE (mode): i * UNITS_PER_WORD); rtx new; if (validate_address) *************** operand_subword (op, i, validate_address *** 1159,1165 **** addr = memory_address (word_mode, addr); } ! new = gen_rtx (MEM, word_mode, addr); MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op); MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op); --- 1166,1172 ---- addr = memory_address (word_mode, addr); } ! new = gen_rtx (MEM, COMPLEX_WORD_MODE (mode), addr); MEM_VOLATILE_P (new) = MEM_VOLATILE_P (op); MEM_IN_STRUCT_P (new) = MEM_IN_STRUCT_P (op); *** gcc/expr.c.orig Sat Oct 4 03:12:35 1997 --- gcc/expr.c Sun Oct 5 18:21:18 1997 *************** move_block_to_reg (regno, x, nregs, mode *** 1701,1707 **** #endif for (i = 0; i < nregs; i++) ! emit_move_insn (gen_rtx (REG, word_mode, regno + i), operand_subword_force (x, i, mode)); } --- 1701,1707 ---- #endif for (i = 0; i < nregs; i++) ! emit_move_insn (gen_rtx (REG, COMPLEX_WORD_MODE (mode), regno + i), operand_subword_force (x, i, mode)); } *************** move_block_from_reg (regno, x, nregs, si *** 1724,1729 **** --- 1724,1731 ---- /* If SIZE is that of a mode no bigger than a word, just use that mode's store operation. */ if (size <= UNITS_PER_WORD + && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_INT + && GET_MODE_CLASS (GET_MODE (x)) != MODE_COMPLEX_FLOAT && (mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0)) != BLKmode) { emit_move_insn (change_address (x, mode, NULL), *************** move_block_from_reg (regno, x, nregs, si *** 1769,1780 **** for (i = 0; i < nregs; i++) { ! rtx tem = operand_subword (x, i, 1, BLKmode); if (tem == 0) abort (); ! emit_move_insn (tem, gen_rtx (REG, word_mode, regno + i)); } } --- 1771,1786 ---- for (i = 0; i < nregs; i++) { ! rtx tem = operand_subword ! (x, i, 1, (GET_MODE_CLASS(GET_MODE (x)) == MODE_COMPLEX_INT ! || GET_MODE_CLASS(GET_MODE (x)) == MODE_COMPLEX_FLOAT)? ! GET_MODE(x):BLKmode); if (tem == 0) abort (); ! emit_move_insn (tem, gen_rtx (REG, COMPLEX_WORD_MODE (GET_MODE (x)), ! regno + i)); } } *************** emit_push_insn (x, mode, type, size, ali *** 2687,2693 **** { /* Scalar partly in registers. */ ! int size = GET_MODE_SIZE (mode) / UNITS_PER_WORD; int i; int not_stack; /* # words of start of argument --- 2693,2699 ---- { /* Scalar partly in registers. */ ! int size = GET_COMPLEX_MODE_SIZE (mode); int i; int not_stack; /* # words of start of argument *************** emit_push_insn (x, mode, type, size, ali *** 2696,2701 **** --- 2702,2716 ---- int args_offset = INTVAL (args_so_far); int skip; + /* For a complex argument passing partially in a register, + save the image part in stack immedially following the space + used for save the part passig in register (see function + assign_parms in function.c). */ + if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT + || GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT) + if (GET_MODE_UNIT_SIZE (mode) < UNITS_PER_WORD) + args_offset += GET_MODE_UNIT_SIZE (mode) - UNITS_PER_WORD; + /* Push padding now if padding above and stack grows down, or if padding below and stack grows up. But if space already allocated, this has already been done. */ *************** emit_push_insn (x, mode, type, size, ali *** 2742,2748 **** #endif if (i >= not_stack + offset) emit_push_insn (operand_subword_force (x, i, mode), ! word_mode, NULL_TREE, NULL_RTX, align, 0, NULL_RTX, 0, args_addr, GEN_INT (args_offset + ((i - not_stack + skip) * UNITS_PER_WORD))); --- 2757,2764 ---- #endif if (i >= not_stack + offset) emit_push_insn (operand_subword_force (x, i, mode), ! COMPLEX_WORD_MODE (mode), ! NULL_TREE, NULL_RTX, align, 0, NULL_RTX, 0, args_addr, GEN_INT (args_offset + ((i - not_stack + skip) * UNITS_PER_WORD))); *** gcc/expr.h.orig Sat Oct 4 23:46:34 1997 --- gcc/expr.h Sun Oct 5 18:21:14 1997 *************** extern void bc_adjust_stack PROTO ((in *** 952,954 **** --- 952,970 ---- extern void bc_load_localaddr PROTO ((rtx)); extern void do_jump_by_parts_greater_rtx PROTO ((enum machine_mode, int, rtx, rtx, rtx, rtx)); + + /* Determine the mode for the imagine and real part of a complex MODE. + For a non-complex MODE, use WORD_MODE.*/ + #define COMPLEX_WORD_MODE(MODE) \ + (((GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT \ + || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \ + && GET_MODE_UNIT_SIZE (MODE) < UNITS_PER_WORD)? \ + mode_for_size (GET_MODE_UNIT_SIZE(MODE)*BITS_PER_UNIT, \ + (GET_MODE_CLASS (MODE) == MODE_COMPLEX_INT)? \ + MODE_INT:MODE_FLOAT, \ + 0):word_mode) + + /* Calculate number of bytes needed for a complex MODE */ + #define GET_COMPLEX_MODE_SIZE(MODE) \ + (((GET_MODE_UNIT_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) \ + * (GET_MODE_SIZE (MODE)) / GET_MODE_UNIT_SIZE (MODE)) *** gcc/regs.h.orig Mon Aug 11 11:57:12 1997 --- gcc/regs.h Wed Oct 1 16:19:31 1997 *************** Boston, MA 02111-1307, USA. */ *** 27,33 **** valid way to get this value. You cannot get it from the regno. */ #define REG_SIZE(R) \ ! ((mode_size[(int) GET_MODE (R)] + UNITS_PER_WORD - 1) / UNITS_PER_WORD) /* Maximum register number used in this function, plus one. */ --- 27,36 ---- valid way to get this value. You cannot get it from the regno. */ #define REG_SIZE(R) \ ! (GET_MODE_SIZE (GET_MODE (R)) == 0? \ ! 0:(((GET_MODE_UNIT_SIZE (GET_MODE (R)) + (UNITS_PER_WORD - 1)) \ ! / UNITS_PER_WORD) * (GET_MODE_SIZE (GET_MODE (R)) \ ! / GET_MODE_UNIT_SIZE (GET_MODE (R))))) /* Maximum register number used in this function, plus one. */ *** gcc/config/alpha/alpha.h.orig Wed Oct 1 16:16:31 1997 --- gcc/config/alpha/alpha.h Fri Oct 3 11:41:58 1997 *************** extern void override_options (); *** 515,521 **** but can be less for certain modes in special long registers. */ #define HARD_REGNO_NREGS(REGNO, MODE) \ ! ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. On Alpha, the integer registers can hold any mode. The floating-point --- 515,524 ---- but can be less for certain modes in special long registers. */ #define HARD_REGNO_NREGS(REGNO, MODE) \ ! (GET_MODE_SIZE (MODE) == 0? \ ! 0:(((GET_MODE_UNIT_SIZE (MODE) + (UNITS_PER_WORD - 1)) \ ! / UNITS_PER_WORD) * (GET_MODE_SIZE (MODE) \ ! / GET_MODE_UNIT_SIZE (MODE)))) /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. On Alpha, the integer registers can hold any mode. The floating-point *************** enum reg_class { NO_REGS, GENERAL_REGS, *** 891,901 **** #define FUNCTION_VALUE(VALTYPE, FUNC) \ gen_rtx (REG, \ (INTEGRAL_MODE_P (TYPE_MODE (VALTYPE)) \ && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \ ? word_mode : TYPE_MODE (VALTYPE), \ ((TARGET_FPREGS \ && (TREE_CODE (VALTYPE) == REAL_TYPE \ ! || TREE_CODE (VALTYPE) == COMPLEX_TYPE)) \ ? 32 : 0)) /* Define how to find the value returned by a library function --- 894,908 ---- #define FUNCTION_VALUE(VALTYPE, FUNC) \ gen_rtx (REG, \ (INTEGRAL_MODE_P (TYPE_MODE (VALTYPE)) \ + && (GET_MODE_CLASS(TYPE_MODE (VALTYPE)) \ + != MODE_COMPLEX_INT) \ && TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \ ? word_mode : TYPE_MODE (VALTYPE), \ ((TARGET_FPREGS \ && (TREE_CODE (VALTYPE) == REAL_TYPE \ ! || TREE_CODE (VALTYPE) == COMPLEX_TYPE) \ ! && (GET_MODE_CLASS(TYPE_MODE (VALTYPE)) \ ! != MODE_COMPLEX_INT)) \ ? 32 : 0)) /* Define how to find the value returned by a library function *************** enum reg_class { NO_REGS, GENERAL_REGS, *** 953,959 **** #define ALPHA_ARG_SIZE(MODE, TYPE, NAMED) \ ((MODE) != BLKmode \ ! ? (GET_MODE_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD \ : (int_size_in_bytes (TYPE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) /* Update the data in CUM to advance over an argument --- 960,969 ---- #define ALPHA_ARG_SIZE(MODE, TYPE, NAMED) \ ((MODE) != BLKmode \ ! ? (GET_MODE_SIZE (MODE) > 0? \ ! (GET_MODE_UNIT_SIZE (MODE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD \ ! * GET_MODE_SIZE (MODE) / GET_MODE_UNIT_SIZE (MODE) \ ! : 0) \ : (int_size_in_bytes (TYPE) + (UNITS_PER_WORD - 1)) / UNITS_PER_WORD) /* Update the data in CUM to advance over an argument