This patch introduces support for the H8SX processor to the h8300 port. Unfortunately, h8300-elf wouldn't build out of mainline, so I regression tested it with an older tree that built h8300-elf successfully, without any regressions on h8300-elf (multilibs default, -ms, -mh, and the latter two with -mint32). The patch fixes whatever problem it was that prevented building of h8300-elf in mainline; I didn't try to track down what exact set of changes fixed it, and I hope I don't have to. Suffice it to say that the test results I got in mainline after installing the patch were only slightly worse than those in the older tree. Since the patch was the same, I think it's reasonably safe to assume that it doesn't introduce any regressions in mainline, but since it was totally broken before installing the patch (and has been for quite a while), it's hard to tell. I hope this is good enough. There are very few changes to machine-independent code, that I enclose as plain text below, even though they're also in the compressed patch, such that global-write maintainers can more easily look at them and hopefully approve them to go in along with the rest of the patch, that should probably be reviewed by the H8 maintainers. I'm Cc:ing Richard Sandiford, who wrote most of them, and most of the port as well, in case clarifications on the need for the changes are needed. As for the change I recently wrote myself, to tree.c:get_narrower(), the problem was that it would strip conversions from a 16-bit pointer type to a 16-bit integer type, and then to 32 bits. c-type.c:build_binary_op() `shorten && none_complex' code made a big fuss about that when it passed the pointer type to int_fits_type_p(), after c_common_signed_or_unsigned_type() returned it unchanged. I figured stopping the conversion-stripping while we still have an integral type (as long as we started with one) would be best. Bootstrapped on i686-pc-linux-gnu native, and cross-built and tested for target h8300-elf. Ok to install? Index: gcc/builtins.c =================================================================== RCS file: /cvs/uberbaum/gcc/builtins.c,v retrieving revision 1.342 diff -u -p -r1.342 builtins.c --- gcc/builtins.c 20 Jun 2004 17:03:02 -0000 1.342 +++ gcc/builtins.c 21 Jun 2004 10:57:01 -0000 @@ -3002,7 +3002,11 @@ expand_builtin_strcpy (tree arglist, rtx len = c_strlen (src, 1); if (len == 0 || TREE_SIDE_EFFECTS (len)) - return 0; + /* Try using a stpcpy pattern. If we don't need to use the + return value, it's better to treat this like strpcy(). */ + return expand_strcpy (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist)), + target, target == const0_rtx); len = size_binop (PLUS_EXPR, len, ssize_int (1)); arglist = build_tree_list (NULL_TREE, len); @@ -3043,7 +3047,9 @@ expand_builtin_stpcpy (tree arglist, rtx when used to produce the return value. */ src = TREE_VALUE (TREE_CHAIN (arglist)); if (! c_getstr (src) || ! (len = c_strlen (src, 0))) - return 0; + return expand_strcpy (TREE_VALUE (arglist), + TREE_VALUE (TREE_CHAIN (arglist)), + target, 1); dst = TREE_VALUE (arglist); len = fold (size_binop (PLUS_EXPR, len, ssize_int (1))); Index: gcc/expr.c =================================================================== RCS file: /cvs/uberbaum/gcc/expr.c,v retrieving revision 1.654 diff -u -p -r1.654 expr.c --- gcc/expr.c 19 Jun 2004 15:33:05 -0000 1.654 +++ gcc/expr.c 21 Jun 2004 10:57:08 -0000 @@ -10212,4 +10212,95 @@ const_vector_from_tree (tree exp) return gen_rtx_raw_CONST_VECTOR (mode, v); } + + +#ifdef HAVE_stpcpy +static rtx expand_strcpy_arg (tree); +static void legitimize_strcpy_operand (const struct insn_operand_data *, rtx); + +/* Subroutine of expand_strcpy. Return a BLKmode + reference to the string pointed to by ARG. */ + +static rtx +expand_strcpy_arg (tree arg) +{ + rtx addr, mem; + + addr = protect_from_queue (expand_expr (arg, 0, Pmode, 0), 0); + mem = gen_rtx_MEM (BLKmode, memory_address (BLKmode, addr)); + set_mem_attributes (mem, TREE_TYPE (arg), 1); + + return mem; +} + +/* Subroutine of expand_strcpy. If memory reference OPERAND + doesn't satisfy DATA, convert it into a (mem (reg)). */ + +static void +legitimize_strcpy_operand (const struct insn_operand_data * data, + rtx operand) +{ + if (data->predicate != 0 + && ! data->predicate (operand, data->mode)) + XEXP (operand, 0) = copy_to_mode_reg (Pmode, operand); +} +#endif + +/* Try to copy a string from SRC to DEST, where both SRC and DEST + are pointers. If ENDP, return a pointer to DEST's null terminator, + otherwise return a pointer to its first character. Use TARGET as + the destination if convenient. + + Return null if the machine has no special way of implementing + such moves. */ + +rtx +expand_strcpy (tree dest ATTRIBUTE_UNUSED, + tree src ATTRIBUTE_UNUSED, + rtx target ATTRIBUTE_UNUSED, + int endp ATTRIBUTE_UNUSED) +{ +#ifndef HAVE_stpcpy + return 0; +#else + rtx end; + rtx dest_mem; + rtx src_mem; + rtx insn; + const struct insn_data * data; + + if (!HAVE_stpcpy) + return 0; + + dest_mem = expand_strcpy_arg (dest); + src_mem = expand_strcpy_arg (src); + if (!endp) + { + XEXP (dest_mem, 0) = force_reg (Pmode, XEXP (dest_mem, 0)); + target = XEXP (dest_mem, 0); + end = gen_reg_rtx (Pmode); + } + else + { + if (target == 0) + target = gen_reg_rtx (Pmode); + end = target; + } + + data = insn_data + CODE_FOR_stpcpy; + + if (data->operand[0].mode != VOIDmode) + end = gen_lowpart (data->operand[0].mode, end); + legitimize_strcpy_operand (data->operand + 1, dest_mem); + legitimize_strcpy_operand (data->operand + 2, src_mem); + + insn = data->genfun (end, dest_mem, src_mem); + if (insn == 0) + abort (); + + emit_insn (insn); + return target; +#endif +} + #include "gt-expr.h" Index: gcc/expr.h =================================================================== RCS file: /cvs/uberbaum/gcc/expr.h,v retrieving revision 1.158 diff -u -p -r1.158 expr.h --- gcc/expr.h 2 Jun 2004 02:09:45 -0000 1.158 +++ gcc/expr.h 21 Jun 2004 10:57:08 -0000 @@ -501,6 +501,8 @@ extern rtx emit_move_insn_1 (rtx, rtx); and return an rtx to address the beginning of the block. */ extern rtx push_block (rtx, int, int); +extern rtx expand_strcpy (tree, tree, rtx, int); + /* Generate code to push something onto the stack, given its mode and type. */ extern void emit_push_insn (rtx, enum machine_mode, tree, rtx, unsigned int, int, rtx, int, rtx, rtx, int, rtx); Index: gcc/final.c =================================================================== RCS file: /cvs/uberbaum/gcc/final.c,v retrieving revision 1.315 diff -u -p -r1.315 final.c --- gcc/final.c 15 Jun 2004 18:02:19 -0000 1.315 +++ gcc/final.c 21 Jun 2004 10:57:10 -0000 @@ -2655,11 +2655,13 @@ walk_alter_subreg (rtx *xp) { case PLUS: case MULT: + case AND: XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); XEXP (x, 1) = walk_alter_subreg (&XEXP (x, 1)); break; case MEM: + case ZERO_EXTEND: XEXP (x, 0) = walk_alter_subreg (&XEXP (x, 0)); break; Index: gcc/genattrtab.c =================================================================== RCS file: /cvs/uberbaum/gcc/genattrtab.c,v retrieving revision 1.145 diff -u -p -r1.145 genattrtab.c --- gcc/genattrtab.c 13 May 2004 06:39:42 -0000 1.145 +++ gcc/genattrtab.c 21 Jun 2004 10:57:14 -0000 @@ -5520,6 +5520,11 @@ write_eligible_delay (const char *kind) printf (" if (slot >= %d)\n", max_slots); printf (" abort ();\n"); printf ("\n"); + /* Allow dbr_schedule to pass labels, etc. This can happen if try_split + converts a compound instruction into a loop. */ + printf (" if (!INSN_P (candidate_insn))\n"); + printf (" return 0;\n"); + printf ("\n"); /* If more than one delay type, find out which type the delay insn is. */ Index: gcc/tree.c =================================================================== RCS file: /cvs/uberbaum/gcc/tree.c,v retrieving revision 1.376 diff -u -p -r1.376 tree.c --- gcc/tree.c 15 Jun 2004 18:37:32 -0000 1.376 +++ gcc/tree.c 21 Jun 2004 10:57:17 -0000 @@ -4471,6 +4471,7 @@ get_narrower (tree op, int *unsignedp_pt int uns = 0; int first = 1; tree win = op; + bool integral_p = INTEGRAL_TYPE_P (TREE_TYPE (op)); while (TREE_CODE (op) == NOP_EXPR) { @@ -4507,6 +4508,10 @@ get_narrower (tree op, int *unsignedp_pt uns = TYPE_UNSIGNED (TREE_TYPE (op)); first = 0; op = TREE_OPERAND (op, 0); + /* Keep trying to narrow, but don't assign op to win if it + would turn an integral type into something else. */ + if (INTEGRAL_TYPE_P (TREE_TYPE (op)) != integral_p) + continue; } win = op;