Introduce H8SX support.
authorAlexandre Oliva <aoliva@redhat.com>
Thu, 8 Jul 2004 03:40:34 +0000 (03:40 +0000)
committerAlexandre Oliva <aoliva@gcc.gnu.org>
Thu, 8 Jul 2004 03:40:34 +0000 (03:40 +0000)
* expr.c (expand_strcpy): Renamed and moved to...
* builtins.c (expand_movstr): ... here.  Tweak.
(expand_builtin_strcpy): Adjust.  Use movstr if len can't be
computed or has side effects.
(expand_builtin_stpcpy): Likewise.  Use strcpy if return value is
unused, or if mempcpy fails.  Adjust the return value in the
latter case.  Use movstr if everything else fails.
* doc/md.texi (movstr): Document.
(movmemM, clrmemM): Fix explanation of memory block operands.
* config/h8300/h8300.md (stpcpy): Renamed to...
(movstr): ... this.  Adjust.
2004-07-07  Alexandre Oliva  <aoliva@redhat.com>
* config/h8300/h8300.md: Rename movstr*, except for movstrict*, to
movmem* and clrstr* to clrmem*.
2004-06-27  Alexandre Oliva  <aoliva@redhat.com>
* config/h8300/h8300.c (h8300_reg_class_from_letter): Map 'D' to
GENERAL_REGS, always.
(h8300_swap_into_er6, h8300_swap_into_er6): Handle the case of
getting the stack pointer as addr.
* config/h8300/h8300.h (PREDICATE_CODES): Remove constant rtxes
from general_operand_dst.
* config/h8300/h8300.md (movmd_internal_normal): New, normal-mode
variant of...
(movmd_internal): ... this.  Add modes to operands.  Disparage `D'
instead of requiring it to match only before reload.
(stpcpy_internal_normal): New, normal-mode variant of...
(stpcpy_internal): ... this.  Add modes to operands.  Disparage
`D' instead of requiring it to match only before reload.
* config/h8300/h8300-protos.h (h8300_legitimate_address_p): Add
mode argument.
* config/h8300/h8300.h (GO_IF_LEGITIMATE_ADDRESS): Pass it to...
* config/h8300/h8300.c (h8300_legitimate_address_p): Pass it to
h8300_get_index.
* config/h8300/h8300.md (attr type): Add call.
(attr can_delay): If type is call, set it no.
(call, call_value): Set type to call.
2004-06-21  Alexandre Oliva  <aoliva@redhat.com>
* config/h8300/h8300.md (logicalhi3_sn, logicalsi3_sn): New.
2004-06-16  Alexandre Oliva  <aoliva@redhat.com>
* tree.c (get_narrower): Don't narrow integral types into
non-integral types.
* config/h8300/h8300.c (h8300_expand_epilogue): Initialize
frame_size *before* the first use.
* config/h8300/h8300.md (movstrictqi): Reintroduce post-increment
on input.
(peephole2): Don't widen instructions that push SP.  Move
decrement of SP to the end of all stm-generating peepholes.
2003-07-24  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.md (insv): Prefer to use AND to clear a bitfield
and OR to set it to all ones.
2003-07-24  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.md (can_delay): Default to "no" for bit branches.
(call, call_value): Set can_delay to "no".
2003-07-22  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.md (extzv): Make subreg check more robust.
2003-07-21  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.md (*brabit): Remove.
* config/h8300/h8300.md (*brabc, *brabs): Remove mode from
zero_extract.  Use bit_memory_operand as the predicate for
operand 1 and 'WU' as the constraint.  Check the difference
between the base length and the final one when deciding which
type of branch to use.
2003-07-21  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.md (extzv): Remove mode from operands 0 and 1.
Use convert_move to extend the result for TARGET_H8300SX.  Check
for QImode memory references.  Optimize the case where the
destination is a paradoxical subreg.
2003-07-21  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.md (*movsf_h8sx): Add an r <- G alternative.
* config/h8300/h8300.md (andqi): Remove bclr from h8sx version.
2003-07-21  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.md: Include mova.md
(length_table): Add mova and mova_zero.
* config/h8300/h8300.c (print_operand): Handle '%o'.  Print a length
after all constant addresses for '%R', '%X', '%T' and '%S'.
(h8300_mova_length): New function.
(h8300_insn_length_from_table): Use it to handle mova and mova_zero.
* config/h8300/t-h8300 (mova.md): Generate from genmova.sh.  Add to
dependencies for s-config, etc.
* config/h8300/gemova.sh: New file.
* config/h8300/mova.md: Generated.
2003-07-20  Alexandre Oliva  <aoliva@redhat.com>
* config/h8300/h8300.c (h8300_bitfield_length): New.
(nibble_operand): Adjust.
(h8300_binary_length): Handle conditional binary op.
(h8300_insn_length_from_table): Handle bitfield and bitbranch.
* config/h8300/h8300.h: Change constraints W# and Y# to P#>X and
P#<X, respectively.  The original P is now IP4>X.  Introduced P#>0
and P#<0, unused so far.  W and Y are now prefixes to multi-letter
constraints.  WU is introduced as a variant of U that requires a
mem, and is therefore considered an EXTRA_MEMORY_CONSTRAINT.
* config/h8300/h8300.md (attr type): Added bitbranch.
(attr length_table): Added bitfield and bitbranch.
(attr length): Compute bitbranch length.
(andqi): Separate pattern for H8300SX.  Use bfld for loading the
least-significant bit of a byte.
(brabit, brabc, brabs): New.
(insv, extzv): Emit bfst and bfld on H8300SX.
(bfld, bfst, seq, sne): New.
(bstzhireg, cmpstz, bstz, bistz): New.
(cmpcondbset, condbset, cmpcondbclr, condbclr): New.
(cmpcondbsetreg, condbsetreg, cmpcondbclrreg, condbclrreg): New.
2003-07-11  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.c (h8sx_binary_memory_operator): New function.
(h8sx_unary_memory_operator): New function.
* config/h8300/h8300.h (EXTRA_MEMORY_CONSTRAINT): Disable.
(PREDICATE_CODES): Add h8sx_{unary,binary}_memory_operator.
* config/h8300/h8300.md: Add peepholes to combine reloads and
arithmetic insns.
2003-07-10  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h830.md (cmpqi): Use 'i' rather than 'n' in constraints.
(*cmphi_h8300hs, *addqi3, *addhi3_h8sx, subhi3): Likewise.
(and?i, ior?i, xor?i): Likewise.
2003-07-10  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.c: Move enums and prototypes to head of file.
Various whitespace fixes.
(h8300_constant_length): New function, split out from...
(h8300_displacement_size): ...here.  Rename h8300_displacement_length.
(h8300_classify_operand): Use IN_RANGE.
(h8300_classify_operand): Use h8300_constant_length.
(h8300_short_move_mem_p): Tighten size check.
(h8sx_mergeable_memrefs_p): Tighten equality check.
2003-06-30  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.h (TARGET_CPU_CPP_BUILTINS): Define __H8300SX__
for -msx.
* config/h8300/crti.asm: Use .h8300sx or .h8300sxn for -msx code.
* config/h8300/crtn.asm: Likewise.
* config/h8300/lib1funcs.asm: Likewise.  Use 32-bit pointers
if __H8300SX__ is defined.
2003-06-27  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300-protos.h (h8300_get_index): Add mode parameter.
* config/h8300/h8300.h (GO_IF_LEGITIMATE_ADDRESS): Update accordingly.
(GO_IF_MODE_DEPENDENT_ADDRESS): Treat POST_DEC, PRE_INC and indexed
addresses as mode-dependent.
* config/h8300/h8300.c (print_operand_address): Update call to
h8300_get_index.
(h8300_get_index): Take a mode argument.  Rework to fix an
earlier misunderstanding.
2003-06-26  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.c (zero_extendqisi2): Force the source operand
into a register if TARGET_H8300SX.
(*zero_extendqisi2_h8300hs, *extendqisi2_h8300): Disable for
TARGET_H8300SX.  Also disable related define_splits.
(*zero_extendqisi2_h8sx, *extendqisi2_h8sx): New patterns.
2003-06-23  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.c (h8300_rtx_costs): Add h8sx handling.
2003-06-20  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.h (OK_FOR_Z): New macro.
(EXTRA_CONSTRAINT_STR): Check it.
* config/h8300/h8300.c (h8300_classify_operand): Accept null
class arguments.
(h8300_insn_length_from_table): Handle LENGTH_TABLE_MOV_IMM4.
* config/h8300/h8300.md (length_table): Add mov_imm4.
(movqi, movhi): Add Z <- W4 alternatives to h8sx patterns.
2003-06-20  Richard Sandiford  <rsandifo@redhat.com>
* genattrtab.c (write_eligible_delay): Allow candidate_insn to
be a label.
* config/h8300/h8300.h (DELAY_SLOT_LENGTH): New macro.
* config/h8300/h8300.c (h8300_reorg): New function.
(TARGET_MACHINE_DEPENDENT_REORG): Define.
* config/h8300/h8300.md (length): Subtract the length of the
delay slot from (pc) when checking the range of forward branches.
(delay_slot, can_delay): New attributes.
(define_delay): Add bra/s handling.
(movmd_internal, return_h8sx, *return_1): Set can_delay to no.
(jump): Add delayed-branch handling.
2003-06-17  Richard Sandiford  <rsandifo@redhat.com>
* expr.c (expand_strcpy): New function.
* builtins.c (expand_builtin_strcpy): Fall back on expand_strcpy.
(expand_builtin_stpcpy): Likewise.
* config/h8300/h8300-protos.h (h8sx_split_movmd): Remove.
(h8300_swap_into_er6, h8300_swap_out_of_er6): Declare.
* config/h8300/h8300.c (h8300_reg_class_from_letter): Tweak 'd'
handling to improve register allocation for -fno-omit-frame-pointer.
(h8sx_split_movmd): Delete, moving er6 handling into...
(h8300_swap_into_er6, h8300_swap_out_of_er6): ...these new functions.
* config/h8300/h8300.md (UNSPEC_STPCPY): New unspec constant.
(movmd): Add calls to copy_rtx.
(movmd_internal): In the second alternative, allow the initial and
final destination registers to be different .  Update the splitter
accordingly.  Call h8300_swap_into_er6 and h8300_swap_out_of_er6
instead of h8sx_split_movmd.
(stpcpy, movsd): New expanders.
(movsd_internal): New define_insn.
2003-06-13  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300-protos.h (h8300_reg_class_from_letter): Declare.
(h8sx_emit_movmd, h8sx_split_movmd): Declare.
* config/h8300/h8300.h (reg_class): Add COUNTER_REGS, SOURCE_REGS
and DESTINATION_REGS.
(REG_CLASS_NAMES, REG_CLASS_CONTENTS): Update accordingly.
(REGNO_REG_CLASS): Map er4, er5 and er6 to the new classes.
(REG_CLASS_FROM_LETTER): Use h8300_reg_class_from_letter.
(h8300_move_ratio): Declare.
(MOVE_RATIO): Use it.
* config/h8300/h8300.c (h8300_move_ratio): New variable.
(h8300_init_once): Initialize it.
(h8300_reg_class_from_letter): New function.
(print_operand): Add an 'm' prefix for printing ".b", ".w" or ".l".
(h8sx_emit_movmd, h8sx_split_movmd): New functions.
* config/h8300/h8300.md (UNSPEC_MOVMD): New unspec constant.
(COUNTER_REG, SOURCE_REG, DESTINATION_REG): New register constants.
(movstrsi, movmd): New expanders.
(movmd_internal): New insn.
2003-06-06  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.h (EXTRA_MEMORY_CONSTRAINT): Define.
2003-06-04  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/elf.h (LINK_SPEC): Use -m h8300sxnelf for -msx -mn.
* config/h8300/h8300.c (asm_file_start): Use .h8300sxn likewise.
2003-06-03  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.c (nibble_operand): Fix warning.
* config/h8300/h8300.md (movstricthi): Set adjust_length to no.
(movsi_h8sx): Likewise here and the normal h8sx movhi pattern.
(movsf_h8300h): Disable for TARGET_H8300SX.
2003-06-03  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.h (PREDICATE_CODES): Add h8300_ldm_parallel,
h8300_stm_parallel and h8300_return_parallel.
* config/h8300/h8300.c (h8300_push_pop, h8300_stack_offset_p,
h8300_ldm_stm_regno, h8300_ldm_stm_parallel, h8300_ldm_parallel,
h8300_stm_parallel, h8300_return_parallel): New functions.
(h8300_expand_prologue): Don't enforce ldm/stm register alignment
if TARGET_H8300SX.  Use h8300_push_pop.
(h8300_expand_epilogue): Likewise.  Try to merge the return insn
and final pop when generating h8sx code.  Always emit some form
of return insn.
* config/h8300/h8300.md: Don't enforce register alignment in
stm peepholes if TARGET_H8300SX.
(ldm_h8300s, stm_h8300s, return_h8sx): New patterns.
(ldm_h8300s_[234], stm_h8300_[234]): Disable.
(epilogue): Expect h8300_expand_epilogue to emit a return insn.
2003-06-03  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/t-h8300 (MULTILIB_OPTIONS): Add a -msx multilib.
(MULTILIB_DIRNAMES): Add a directory for it.
(MULTILIB_MATCHES): Delete.
2003-05-28  Richard Sandiford  <rsandifo@redhat.com>
* final.c (walk_alter_subreg): Handle addresses with subregs
inside a ZERO_EXTEND or AND.
* config/h8300/h8300-protos.h (h8300_get_index): Declare.
* config/h8300/h8300.h (INDEX_REG_CLASS): Set to GENERAL_REGS
if TARGET_H8300SX.
(GO_IF_LEGITIMATE_ADDRESS): Use h8300_get_index.
* config/h8300/h8300.c (print_operand_address): Handle @(dd,RnL.b),
@(dd,Rn.w) and @(dd,ERn.L).
(h8300_displacement_size): Take the whole address as argument.
(h8300_classify_operand, h8300_short_move_mem_p): Adjust accordingly.
2003-05-28  Richard Sandiford  <rsandifo@redhat.com>
* config/mips/mips-protos.h (h8300_operands_match_p): Declare.
(h8sx_mergeable_memrefs_p): Declare.
* config/h8300/h8300.h (HAVE_POST_DECREMENT): Define to TARGET_H8300SX.
(HAVE_PRE_INCREMENT): Likewise.
(GO_IF_LEGITIMATE_ADDRESS): Accept pre/post increment/decrement
addresses for TARGET_H8300SX,
* config/h8300/h8300.c (print_operand_address): Deal with PRE_INC
and POST_DEC.
(movb_length_table, movl_length_table): New tables.
(movw_length_table): Define to movb_length_table.
(h8300_displacement_size): New, split out from...
(h8300_classify_address): ...here.  Handle pre/post inc/dec.
(h8300_short_immediate_length): Allow H8OP_MEM_COMPLEX operands.
(h8300_insn_length_from_table): Add cases for movb, movw and movl.
(h8sx_mergeable_memrefs_p, h8300_operands_match_p): New functions.
(output_plussi): Use add.l #xx:3,Rn and sub.l #xx:3,Rn for h8sx.
(compute_plussi_length, compute_plussi_cc): Update accordingly.
(h8sx_unary_shift_operator): Get the mode from the operator.
(binary_shift_operator): Likewise.
* config/h8300/h8300.md: If a peephole2 applies gen_lowpart to
a memory reference, check whether the reference is offsettable.
(length_table): Add movb, movw and movl.
(movqi): Add new h8sx pattern.  Don't force one operand to be a
register when generating h8sx code.
(movhi, movsi, movsf): Likewise.
(movstrictqi): Use the length_table attribute.
(movstricthi): Likewise.  Add h8sx alternative for mov.w #xx:3,Rn.
(addqi3): Split into a define_expand and define_insn.  Don't accept
memory operands in the expander.  Use h8300_operands_match_p to
check for matching operands in the define_insn.
(subqi3, negqi2, one_cmplqi2): Likewise.
(add[hs]i3): Don't accept memory operands in the expander.  Likewise
in any patterns that are unused in h8sx code.  In the h8sx patterns,
use h8300_operands_match_p to check whether operands match.
(sub[hs]i3, and[hi]3, ior[hs]i3, xor[hs]i3, neg[hsi]3,
one_cmpl[hs]i3): Likewise.
(andqi3, iorqi3, xorqi3): Likewise.  Don't call fix_bit_operand
in the expander.
2003-05-23  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300-protos.h (expand_a_shift): Return a bool.
(h8300_insn_length_from_table): Add a second parameter.
(output_h8sx_shift): Declare.
* config/h8300/h8300.h (OK_FOR_W, OK_FOR_Y): New macros.
(EXTRA_CONSTRAINT): Replace with...
(EXTRA_CONSTRAINT_STR): ...this.  Use OK_FOR_W and OK_FOR_Y.
(CONSTRAINT_LEN): Define, returning 2 for 'W' and 'Y'.
(PREDICATE_CODES): Add entries for h8sx_unary_shift_operator
and h8sx_binary_shift_operator.
* config/h8300/h8300.c (two_insn_adds_subs_operand): Return false
for TARGET_H8300SX.
(bit_operand): Replace use of EXTRA_CONSTRAINT with OK_FOR_U.
(bit_memory_operand, fix_bit_operand): Likewise.
(h8300_length_table_for_insn): Remove.
(h8300_classify_operand): Fix check for 16-bit operands in 32-bit
instructions.
(h8300_short_immediate_length, h8300_binary_length): New functions.
(h8300_insn_length_from_table): Add an opcodes parameter.  Rework.
(output_plussi): Use sub to add negative constants.
(compute_plussi_length): Adjust accordingly.
(h8sx_single_shift_type): New enum.
(h8sx_single_shift, h8sx_unary_shift_operator,
h8sx_binary_shift_operator, output_h8sx_shift): New functions.
(expand_a_shift, expand_a_rotate): Emit nothing if the shift is a
single h8sx instruction.  Return false in this case.
* config/h8300/h8300.md (length_table): Add short_immediate.
(length): Pass the operand array to h8300_insn_length_from_table.
(adjust_length): Assume "no" for insns with a length_table attribute.
(*cmphi_h8300hs, cmpsi): Add alternatives for #xx:3.
(*addhi3_h8300hs): Don't use for h8sx.
(*addhi3_h8sx): New pattern, with alternatives for add.w #xx:3
and sub.w #xx:3.
(ashl[qhs]i3, lshr[qhs]i3, ashr[qhs]i3, rotl[qhs]i3): Change operand
1's predicate to nonimmediate_operand.  Only skip default expansion
if expand_a_shift or expand_a_rotate returns true.  Add new patterns
for single h8sx shift instructions.
2003-05-22  Alexandre Oliva  <aoliva@redhat.com>
* config/h8300/h8300.c (nibble_operand): Split out of...
(reg_or_nibble_operand): ... this.
* config/h8300/h8300.h (PREDICATE_CODES): Added nibble_operand.
* config/h8300/h8300.md: (mulqihi3, mulhisi3, umulqihi3,
umulhisi3): Introduce expand, and introduce separate insns for
sign- or zero-extended REG and already-extended CONST_INT.
2003-05-20  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.c (h8300_unary_length): Fix miscounting.
* config/h8300/h8300.md (subqi3): Generalize for h8sx.
(subhi3): Likewise.  Don't accept immediates for operand 1.
Remove the early clobber from second alternative of the h8300s pattern.
(subsi3): Generalize for h8sx.  Force operand 2 into a register
on plain h8300 targets.
(subsi3_h8300): Use h8300_dst_operand for consistency with expander.
(subsi3_h8300h): Generalize for h8sx.
(one_cmplqi2, one_cmplhi2, one_cmplsi2): Likewise.
2003-05-19  Alexandre Oliva  <aoliva@redhat.com>
* config/h8300/h8300.c (reg_or_nibble_operand): New.
* config/h8300/h8300.h (PREDICATE_CODES): Adjust.
(TARGET_H8300SXMUL): New.
(CONST_OK_FOR_P): New.
(CONST_OK_FOR_LETTER_P): Adjust.
* config/h8300/h8300.md (mulqihi3, mulhisi3, umulqihi3,
umulhisi3): Accept 4-bit immediate on H8SX.
(mulhi3, mulsi3, smulsi3_highpart, umulsi3_highpart): New.
(udivsi3, divhi3, udivsi3, divsi3): New.
2003-05-19  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300-protos.h (h8300_insn_length_from_table): Declare.
* config/h8300/h8300.h (OK_FOR_Q): New macro.
(EXTRA_CONSTRAINT): Use it to check the 'Q' constraint.
(PREDICATE_CODES): Add h8300_src_operand and h8300_dst_operand.
Add ADDRESSOF to the bit_operand entry.
* config/h8300/h8300.c (h8300_dst_operand): New predicate.
(h8300_src_operand): Likewise.
(bit_operand): Check nonimmediate_operand rather than general_operand.
Accept any nonimmediate_operand in h8sx code.
(h8300_and_costs): Initialize operands[1].
(h8300_rtx_costs) <AND>: Return false if the operands aren't valid.
(h8300_operand_class): New enum.
(h8300_length_table): New typedef.
(addb_length_table, addw_length_table, addl_length_table,
logicl_length_table): New tables.
(logicb_length_table, logicw_length_table): New macros.
(h8300_classify_operand, h8300_length_from_table,
h8300_length_table_for_insn, h8300_unary_length,
h8300_insn_length_from_table): New functions.
(output_plussi): Only use adds and subs for register destinations.
Disable redundant clause.
(compute_plussi_cc): Likewise.
(compute_plussi_length): Likewise.  Use h8300_length_from_table
to work out the length of an insn.
(output_logical_op): Only use narrower immediate instructions
if the destination is a register.
(compute_logical_op_cc): Likewise.
(compute_logical_op_length): Likewise.  Use h8300_length_from_table.
(h8300_adjust_insn_length): Tighten check for reg<->mem moves.
* config/h8300/h8300.md (length_table): New attribute.
(length): When an instruction has a length_table attribute, use
h8300_insn_length_from_table to calculate its default length.
(cmpqi): Use h8300_dst_operand for the first operand and
h8300_src_operand for the second.
(cmphi, *cmphi_h8300hs, cmpsi, negqi2, neghi2, neghi2_h8300h, negsi2,
negsi2_h8300h, addqi3, addhi3, *addhi3_h8300, *addhi3_h8300hs, addsi3,
addsi_h8300, addsi_h8300h, andhi3, andsi3, iorhi3,
iorsi3, xorhi3, xorsi3): Likewise.
(andqi3): Use h8300_src_operand for operand 2.  Adjust the condition
so that it allows any combination of operands for TARGET_H8300SX.
(iorqi3, xorqi3): Likewise.
(cmpqi): Use the length_table attribute.
(*cmphi_h8300hs, cmpsi, addqi, *addhi3_h8300hs, andqi3, iorqi3,
xorqi3, negqi2, neghi2_h8300h, negsi2_h8300h): Likewise.
(cmpqi): Add 'Q' constraint.
(*cmphi_h8300hs, cmpsi, addqi, *addhi3_h8300hs, addsi_h8300h, andqi3,
iorqi3, xorqi3, negqi2, neghi2_h8300h, negsi2_h8300h): Likewise.
2003-05-14  Richard Sandiford  <rsandifo@redhat.com>
* config/h8300/h8300.h (MASK_H8300SX): New macro.
(TARGET_H8300S): True for both -ms and -msx.
(TARGET_H8300SX): New macro.
(TARGET_SWITCHES): Add entries for -msx and -mno-sx.
* config/h8300/h8300.c (asm_file_start): Write .h8300sx for -msx.
* config/h8300/elf.h (LINK_SPEC): Use -m h8300sxelf for -msx.
* config/h8300/t-h8300 (MULTILIB_MATCHES): Use -ms multilibs for -msx.
[Temporary change.]
2003-02-28  Alexandre Oliva  <aoliva@redhat.com>
* config/h8300/h8300.h (SIZE_TYPE, PTRDIFF_TYPE): Use short with
16-bit pointers and 32-bit ints.
* config/h8300/h8300.h (LEGITIMATE_CONSTANT_P): Accept
CONST_DOUBLE with mode no wider than SImode.
* config/h8300/h8300.md (extendqisi2_h8300): Add constraints for
output operand.
2003-02-27  Alexandre Oliva  <aoliva@redhat.com>
* config/h8300/h8300.c (general_operand_src): Match CONSTANT_P_RTX
or SUBREG thereof.
* config/h8300/h8300.h (PREDICATE_CODES): Adjust.
2003-02-22  Alexandre Oliva  <aoliva@redhat.com>
* config/h8300/h8300.c (dosize): Truncate sign * size to Pmode.

From-SVN: r84257

17 files changed:
gcc/ChangeLog
gcc/builtins.c
gcc/config/h8300/crti.asm
gcc/config/h8300/crtn.asm
gcc/config/h8300/elf.h
gcc/config/h8300/genmova.sh [new file with mode: 0644]
gcc/config/h8300/h8300-protos.h
gcc/config/h8300/h8300.c
gcc/config/h8300/h8300.h
gcc/config/h8300/h8300.md
gcc/config/h8300/lib1funcs.asm
gcc/config/h8300/mova.md [new file with mode: 0644]
gcc/config/h8300/t-h8300
gcc/doc/md.texi
gcc/final.c
gcc/genattrtab.c
gcc/tree.c

index 160c0e355564384158b31931e29f21cc8f48c1bc..c58997ae0083f76d82b92f2e1eae1e9f0704c66c 100644 (file)
@@ -1,3 +1,424 @@
+2004-07-08  Alexandre Oliva  <aoliva@redhat.com>
+
+       Introduce H8SX support.
+       * expr.c (expand_strcpy): Renamed and moved to...
+       * builtins.c (expand_movstr): ... here.  Tweak.
+       (expand_builtin_strcpy): Adjust.  Use movstr if len can't be
+       computed or has side effects.
+       (expand_builtin_stpcpy): Likewise.  Use strcpy if return value is
+       unused, or if mempcpy fails.  Adjust the return value in the
+       latter case.  Use movstr if everything else fails.
+       * doc/md.texi (movstr): Document.
+       (movmemM, clrmemM): Fix explanation of memory block operands.
+       * config/h8300/h8300.md (stpcpy): Renamed to...
+       (movstr): ... this.  Adjust.
+       2004-07-07  Alexandre Oliva  <aoliva@redhat.com>
+       * config/h8300/h8300.md: Rename movstr*, except for movstrict*, to
+       movmem* and clrstr* to clrmem*.
+       2004-06-27  Alexandre Oliva  <aoliva@redhat.com>
+       * config/h8300/h8300.c (h8300_reg_class_from_letter): Map 'D' to
+       GENERAL_REGS, always.
+       (h8300_swap_into_er6, h8300_swap_into_er6): Handle the case of
+       getting the stack pointer as addr.
+       * config/h8300/h8300.h (PREDICATE_CODES): Remove constant rtxes
+       from general_operand_dst.
+       * config/h8300/h8300.md (movmd_internal_normal): New, normal-mode
+       variant of...
+       (movmd_internal): ... this.  Add modes to operands.  Disparage `D'
+       instead of requiring it to match only before reload.
+       (stpcpy_internal_normal): New, normal-mode variant of...
+       (stpcpy_internal): ... this.  Add modes to operands.  Disparage
+       `D' instead of requiring it to match only before reload.
+       * config/h8300/h8300-protos.h (h8300_legitimate_address_p): Add
+       mode argument.
+       * config/h8300/h8300.h (GO_IF_LEGITIMATE_ADDRESS): Pass it to...
+       * config/h8300/h8300.c (h8300_legitimate_address_p): Pass it to
+       h8300_get_index.
+       * config/h8300/h8300.md (attr type): Add call.
+       (attr can_delay): If type is call, set it no.
+       (call, call_value): Set type to call.
+       2004-06-21  Alexandre Oliva  <aoliva@redhat.com>
+       * config/h8300/h8300.md (logicalhi3_sn, logicalsi3_sn): New.
+       2004-06-16  Alexandre Oliva  <aoliva@redhat.com>
+       * tree.c (get_narrower): Don't narrow integral types into
+       non-integral types.
+       * config/h8300/h8300.c (h8300_expand_epilogue): Initialize
+       frame_size *before* the first use.
+       * config/h8300/h8300.md (movstrictqi): Reintroduce post-increment
+       on input.
+       (peephole2): Don't widen instructions that push SP.  Move
+       decrement of SP to the end of all stm-generating peepholes.
+       2003-07-24  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.md (insv): Prefer to use AND to clear a bitfield
+       and OR to set it to all ones.
+       2003-07-24  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.md (can_delay): Default to "no" for bit branches.
+       (call, call_value): Set can_delay to "no".
+       2003-07-22  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.md (extzv): Make subreg check more robust.
+       2003-07-21  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.md (*brabit): Remove.
+       * config/h8300/h8300.md (*brabc, *brabs): Remove mode from
+       zero_extract.  Use bit_memory_operand as the predicate for
+       operand 1 and 'WU' as the constraint.  Check the difference
+       between the base length and the final one when deciding which
+       type of branch to use.
+       2003-07-21  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.md (extzv): Remove mode from operands 0 and 1.
+       Use convert_move to extend the result for TARGET_H8300SX.  Check
+       for QImode memory references.  Optimize the case where the
+       destination is a paradoxical subreg.
+       2003-07-21  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.md (*movsf_h8sx): Add an r <- G alternative.
+       * config/h8300/h8300.md (andqi): Remove bclr from h8sx version.
+       2003-07-21  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.md: Include mova.md
+       (length_table): Add mova and mova_zero.
+       * config/h8300/h8300.c (print_operand): Handle '%o'.  Print a length
+       after all constant addresses for '%R', '%X', '%T' and '%S'.
+       (h8300_mova_length): New function.
+       (h8300_insn_length_from_table): Use it to handle mova and mova_zero.
+       * config/h8300/t-h8300 (mova.md): Generate from genmova.sh.  Add to
+       dependencies for s-config, etc.
+       * config/h8300/gemova.sh: New file.
+       * config/h8300/mova.md: Generated.
+       2003-07-20  Alexandre Oliva  <aoliva@redhat.com>
+       * config/h8300/h8300.c (h8300_bitfield_length): New.
+       (nibble_operand): Adjust.
+       (h8300_binary_length): Handle conditional binary op.
+       (h8300_insn_length_from_table): Handle bitfield and bitbranch.
+       * config/h8300/h8300.h: Change constraints W# and Y# to P#>X and
+       P#<X, respectively.  The original P is now IP4>X.  Introduced P#>0
+       and P#<0, unused so far.  W and Y are now prefixes to multi-letter
+       constraints.  WU is introduced as a variant of U that requires a
+       mem, and is therefore considered an EXTRA_MEMORY_CONSTRAINT.
+       * config/h8300/h8300.md (attr type): Added bitbranch.
+       (attr length_table): Added bitfield and bitbranch.
+       (attr length): Compute bitbranch length.
+       (andqi): Separate pattern for H8300SX.  Use bfld for loading the
+       least-significant bit of a byte.
+       (brabit, brabc, brabs): New.
+       (insv, extzv): Emit bfst and bfld on H8300SX.
+       (bfld, bfst, seq, sne): New.
+       (bstzhireg, cmpstz, bstz, bistz): New.
+       (cmpcondbset, condbset, cmpcondbclr, condbclr): New.
+       (cmpcondbsetreg, condbsetreg, cmpcondbclrreg, condbclrreg): New.
+       2003-07-11  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.c (h8sx_binary_memory_operator): New function.
+       (h8sx_unary_memory_operator): New function.
+       * config/h8300/h8300.h (EXTRA_MEMORY_CONSTRAINT): Disable.
+       (PREDICATE_CODES): Add h8sx_{unary,binary}_memory_operator.
+       * config/h8300/h8300.md: Add peepholes to combine reloads and
+       arithmetic insns.
+       2003-07-10  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h830.md (cmpqi): Use 'i' rather than 'n' in constraints.
+       (*cmphi_h8300hs, *addqi3, *addhi3_h8sx, subhi3): Likewise.
+       (and?i, ior?i, xor?i): Likewise.
+       2003-07-10  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.c: Move enums and prototypes to head of file.
+       Various whitespace fixes.
+       (h8300_constant_length): New function, split out from...
+       (h8300_displacement_size): ...here.  Rename h8300_displacement_length.
+       (h8300_classify_operand): Use IN_RANGE.
+       (h8300_classify_operand): Use h8300_constant_length.
+       (h8300_short_move_mem_p): Tighten size check.
+       (h8sx_mergeable_memrefs_p): Tighten equality check.
+       2003-06-30  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.h (TARGET_CPU_CPP_BUILTINS): Define __H8300SX__
+       for -msx.
+       * config/h8300/crti.asm: Use .h8300sx or .h8300sxn for -msx code.
+       * config/h8300/crtn.asm: Likewise.
+       * config/h8300/lib1funcs.asm: Likewise.  Use 32-bit pointers
+       if __H8300SX__ is defined.
+       2003-06-27  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300-protos.h (h8300_get_index): Add mode parameter.
+       * config/h8300/h8300.h (GO_IF_LEGITIMATE_ADDRESS): Update accordingly.
+       (GO_IF_MODE_DEPENDENT_ADDRESS): Treat POST_DEC, PRE_INC and indexed
+       addresses as mode-dependent.
+       * config/h8300/h8300.c (print_operand_address): Update call to
+       h8300_get_index.
+       (h8300_get_index): Take a mode argument.  Rework to fix an
+       earlier misunderstanding.
+       2003-06-26  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.c (zero_extendqisi2): Force the source operand
+       into a register if TARGET_H8300SX.
+       (*zero_extendqisi2_h8300hs, *extendqisi2_h8300): Disable for
+       TARGET_H8300SX.  Also disable related define_splits.
+       (*zero_extendqisi2_h8sx, *extendqisi2_h8sx): New patterns.
+       2003-06-23  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.c (h8300_rtx_costs): Add h8sx handling.
+       2003-06-20  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.h (OK_FOR_Z): New macro.
+       (EXTRA_CONSTRAINT_STR): Check it.
+       * config/h8300/h8300.c (h8300_classify_operand): Accept null
+       class arguments.
+       (h8300_insn_length_from_table): Handle LENGTH_TABLE_MOV_IMM4.
+       * config/h8300/h8300.md (length_table): Add mov_imm4.
+       (movqi, movhi): Add Z <- W4 alternatives to h8sx patterns.
+       2003-06-20  Richard Sandiford  <rsandifo@redhat.com>
+       * genattrtab.c (write_eligible_delay): Allow candidate_insn to
+       be a label.
+       * config/h8300/h8300.h (DELAY_SLOT_LENGTH): New macro.
+       * config/h8300/h8300.c (h8300_reorg): New function.
+       (TARGET_MACHINE_DEPENDENT_REORG): Define.
+       * config/h8300/h8300.md (length): Subtract the length of the
+       delay slot from (pc) when checking the range of forward branches.
+       (delay_slot, can_delay): New attributes.
+       (define_delay): Add bra/s handling.
+       (movmd_internal, return_h8sx, *return_1): Set can_delay to no.
+       (jump): Add delayed-branch handling.
+       2003-06-17  Richard Sandiford  <rsandifo@redhat.com>
+       * expr.c (expand_strcpy): New function.
+       * builtins.c (expand_builtin_strcpy): Fall back on expand_strcpy.
+       (expand_builtin_stpcpy): Likewise.
+       * config/h8300/h8300-protos.h (h8sx_split_movmd): Remove.
+       (h8300_swap_into_er6, h8300_swap_out_of_er6): Declare.
+       * config/h8300/h8300.c (h8300_reg_class_from_letter): Tweak 'd'
+       handling to improve register allocation for -fno-omit-frame-pointer.
+       (h8sx_split_movmd): Delete, moving er6 handling into...
+       (h8300_swap_into_er6, h8300_swap_out_of_er6): ...these new functions.
+       * config/h8300/h8300.md (UNSPEC_STPCPY): New unspec constant.
+       (movmd): Add calls to copy_rtx.
+       (movmd_internal): In the second alternative, allow the initial and
+       final destination registers to be different .  Update the splitter
+       accordingly.  Call h8300_swap_into_er6 and h8300_swap_out_of_er6
+       instead of h8sx_split_movmd.
+       (stpcpy, movsd): New expanders.
+       (movsd_internal): New define_insn.
+       2003-06-13  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300-protos.h (h8300_reg_class_from_letter): Declare.
+       (h8sx_emit_movmd, h8sx_split_movmd): Declare.
+       * config/h8300/h8300.h (reg_class): Add COUNTER_REGS, SOURCE_REGS
+       and DESTINATION_REGS.
+       (REG_CLASS_NAMES, REG_CLASS_CONTENTS): Update accordingly.
+       (REGNO_REG_CLASS): Map er4, er5 and er6 to the new classes.
+       (REG_CLASS_FROM_LETTER): Use h8300_reg_class_from_letter.
+       (h8300_move_ratio): Declare.
+       (MOVE_RATIO): Use it.
+       * config/h8300/h8300.c (h8300_move_ratio): New variable.
+       (h8300_init_once): Initialize it.
+       (h8300_reg_class_from_letter): New function.
+       (print_operand): Add an 'm' prefix for printing ".b", ".w" or ".l".
+       (h8sx_emit_movmd, h8sx_split_movmd): New functions.
+       * config/h8300/h8300.md (UNSPEC_MOVMD): New unspec constant.
+       (COUNTER_REG, SOURCE_REG, DESTINATION_REG): New register constants.
+       (movstrsi, movmd): New expanders.
+       (movmd_internal): New insn.
+       2003-06-06  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.h (EXTRA_MEMORY_CONSTRAINT): Define.
+       2003-06-04  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/elf.h (LINK_SPEC): Use -m h8300sxnelf for -msx -mn.
+       * config/h8300/h8300.c (asm_file_start): Use .h8300sxn likewise.
+       2003-06-03  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.c (nibble_operand): Fix warning.
+       * config/h8300/h8300.md (movstricthi): Set adjust_length to no.
+       (movsi_h8sx): Likewise here and the normal h8sx movhi pattern.
+       (movsf_h8300h): Disable for TARGET_H8300SX.
+       2003-06-03  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.h (PREDICATE_CODES): Add h8300_ldm_parallel,
+       h8300_stm_parallel and h8300_return_parallel.
+       * config/h8300/h8300.c (h8300_push_pop, h8300_stack_offset_p,
+       h8300_ldm_stm_regno, h8300_ldm_stm_parallel, h8300_ldm_parallel,
+       h8300_stm_parallel, h8300_return_parallel): New functions.
+       (h8300_expand_prologue): Don't enforce ldm/stm register alignment
+       if TARGET_H8300SX.  Use h8300_push_pop.
+       (h8300_expand_epilogue): Likewise.  Try to merge the return insn
+       and final pop when generating h8sx code.  Always emit some form
+       of return insn.
+       * config/h8300/h8300.md: Don't enforce register alignment in
+       stm peepholes if TARGET_H8300SX.
+       (ldm_h8300s, stm_h8300s, return_h8sx): New patterns.
+       (ldm_h8300s_[234], stm_h8300_[234]): Disable.
+       (epilogue): Expect h8300_expand_epilogue to emit a return insn.
+       2003-06-03  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/t-h8300 (MULTILIB_OPTIONS): Add a -msx multilib.
+       (MULTILIB_DIRNAMES): Add a directory for it.
+       (MULTILIB_MATCHES): Delete.
+       2003-05-28  Richard Sandiford  <rsandifo@redhat.com>
+       * final.c (walk_alter_subreg): Handle addresses with subregs
+       inside a ZERO_EXTEND or AND.
+       * config/h8300/h8300-protos.h (h8300_get_index): Declare.
+       * config/h8300/h8300.h (INDEX_REG_CLASS): Set to GENERAL_REGS
+       if TARGET_H8300SX.
+       (GO_IF_LEGITIMATE_ADDRESS): Use h8300_get_index.
+       * config/h8300/h8300.c (print_operand_address): Handle @(dd,RnL.b),
+       @(dd,Rn.w) and @(dd,ERn.L).
+       (h8300_displacement_size): Take the whole address as argument.
+       (h8300_classify_operand, h8300_short_move_mem_p): Adjust accordingly.
+       2003-05-28  Richard Sandiford  <rsandifo@redhat.com>
+       * config/mips/mips-protos.h (h8300_operands_match_p): Declare.
+       (h8sx_mergeable_memrefs_p): Declare.
+       * config/h8300/h8300.h (HAVE_POST_DECREMENT): Define to TARGET_H8300SX.
+       (HAVE_PRE_INCREMENT): Likewise.
+       (GO_IF_LEGITIMATE_ADDRESS): Accept pre/post increment/decrement
+       addresses for TARGET_H8300SX,
+       * config/h8300/h8300.c (print_operand_address): Deal with PRE_INC
+       and POST_DEC.
+       (movb_length_table, movl_length_table): New tables.
+       (movw_length_table): Define to movb_length_table.
+       (h8300_displacement_size): New, split out from...
+       (h8300_classify_address): ...here.  Handle pre/post inc/dec.
+       (h8300_short_immediate_length): Allow H8OP_MEM_COMPLEX operands.
+       (h8300_insn_length_from_table): Add cases for movb, movw and movl.
+       (h8sx_mergeable_memrefs_p, h8300_operands_match_p): New functions.
+       (output_plussi): Use add.l #xx:3,Rn and sub.l #xx:3,Rn for h8sx.
+       (compute_plussi_length, compute_plussi_cc): Update accordingly.
+       (h8sx_unary_shift_operator): Get the mode from the operator.
+       (binary_shift_operator): Likewise.
+       * config/h8300/h8300.md: If a peephole2 applies gen_lowpart to
+       a memory reference, check whether the reference is offsettable.
+       (length_table): Add movb, movw and movl.
+       (movqi): Add new h8sx pattern.  Don't force one operand to be a
+       register when generating h8sx code.
+       (movhi, movsi, movsf): Likewise.
+       (movstrictqi): Use the length_table attribute.
+       (movstricthi): Likewise.  Add h8sx alternative for mov.w #xx:3,Rn.
+       (addqi3): Split into a define_expand and define_insn.  Don't accept
+       memory operands in the expander.  Use h8300_operands_match_p to
+       check for matching operands in the define_insn.
+       (subqi3, negqi2, one_cmplqi2): Likewise.
+       (add[hs]i3): Don't accept memory operands in the expander.  Likewise
+       in any patterns that are unused in h8sx code.  In the h8sx patterns,
+       use h8300_operands_match_p to check whether operands match.
+       (sub[hs]i3, and[hi]3, ior[hs]i3, xor[hs]i3, neg[hsi]3,
+       one_cmpl[hs]i3): Likewise.
+       (andqi3, iorqi3, xorqi3): Likewise.  Don't call fix_bit_operand
+       in the expander.
+       2003-05-23  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300-protos.h (expand_a_shift): Return a bool.
+       (h8300_insn_length_from_table): Add a second parameter.
+       (output_h8sx_shift): Declare.
+       * config/h8300/h8300.h (OK_FOR_W, OK_FOR_Y): New macros.
+       (EXTRA_CONSTRAINT): Replace with...
+       (EXTRA_CONSTRAINT_STR): ...this.  Use OK_FOR_W and OK_FOR_Y.
+       (CONSTRAINT_LEN): Define, returning 2 for 'W' and 'Y'.
+       (PREDICATE_CODES): Add entries for h8sx_unary_shift_operator
+       and h8sx_binary_shift_operator.
+       * config/h8300/h8300.c (two_insn_adds_subs_operand): Return false
+       for TARGET_H8300SX.
+       (bit_operand): Replace use of EXTRA_CONSTRAINT with OK_FOR_U.
+       (bit_memory_operand, fix_bit_operand): Likewise.
+       (h8300_length_table_for_insn): Remove.
+       (h8300_classify_operand): Fix check for 16-bit operands in 32-bit
+       instructions.
+       (h8300_short_immediate_length, h8300_binary_length): New functions.
+       (h8300_insn_length_from_table): Add an opcodes parameter.  Rework.
+       (output_plussi): Use sub to add negative constants.
+       (compute_plussi_length): Adjust accordingly.
+       (h8sx_single_shift_type): New enum.
+       (h8sx_single_shift, h8sx_unary_shift_operator,
+       h8sx_binary_shift_operator, output_h8sx_shift): New functions.
+       (expand_a_shift, expand_a_rotate): Emit nothing if the shift is a
+       single h8sx instruction.  Return false in this case.
+       * config/h8300/h8300.md (length_table): Add short_immediate.
+       (length): Pass the operand array to h8300_insn_length_from_table.
+       (adjust_length): Assume "no" for insns with a length_table attribute.
+       (*cmphi_h8300hs, cmpsi): Add alternatives for #xx:3.
+       (*addhi3_h8300hs): Don't use for h8sx.
+       (*addhi3_h8sx): New pattern, with alternatives for add.w #xx:3
+       and sub.w #xx:3.
+       (ashl[qhs]i3, lshr[qhs]i3, ashr[qhs]i3, rotl[qhs]i3): Change operand
+       1's predicate to nonimmediate_operand.  Only skip default expansion
+       if expand_a_shift or expand_a_rotate returns true.  Add new patterns
+       for single h8sx shift instructions.
+       2003-05-22  Alexandre Oliva  <aoliva@redhat.com>
+       * config/h8300/h8300.c (nibble_operand): Split out of...
+       (reg_or_nibble_operand): ... this.
+       * config/h8300/h8300.h (PREDICATE_CODES): Added nibble_operand.
+       * config/h8300/h8300.md: (mulqihi3, mulhisi3, umulqihi3,
+       umulhisi3): Introduce expand, and introduce separate insns for
+       sign- or zero-extended REG and already-extended CONST_INT.
+       2003-05-20  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.c (h8300_unary_length): Fix miscounting.
+       * config/h8300/h8300.md (subqi3): Generalize for h8sx.
+       (subhi3): Likewise.  Don't accept immediates for operand 1.
+       Remove the early clobber from second alternative of the h8300s pattern.
+       (subsi3): Generalize for h8sx.  Force operand 2 into a register
+       on plain h8300 targets.
+       (subsi3_h8300): Use h8300_dst_operand for consistency with expander.
+       (subsi3_h8300h): Generalize for h8sx.
+       (one_cmplqi2, one_cmplhi2, one_cmplsi2): Likewise.
+       2003-05-19  Alexandre Oliva  <aoliva@redhat.com>
+       * config/h8300/h8300.c (reg_or_nibble_operand): New.
+       * config/h8300/h8300.h (PREDICATE_CODES): Adjust.
+       (TARGET_H8300SXMUL): New.
+       (CONST_OK_FOR_P): New.
+       (CONST_OK_FOR_LETTER_P): Adjust.
+       * config/h8300/h8300.md (mulqihi3, mulhisi3, umulqihi3,
+       umulhisi3): Accept 4-bit immediate on H8SX.
+       (mulhi3, mulsi3, smulsi3_highpart, umulsi3_highpart): New.
+       (udivsi3, divhi3, udivsi3, divsi3): New.
+       2003-05-19  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300-protos.h (h8300_insn_length_from_table): Declare.
+       * config/h8300/h8300.h (OK_FOR_Q): New macro.
+       (EXTRA_CONSTRAINT): Use it to check the 'Q' constraint.
+       (PREDICATE_CODES): Add h8300_src_operand and h8300_dst_operand.
+       Add ADDRESSOF to the bit_operand entry.
+       * config/h8300/h8300.c (h8300_dst_operand): New predicate.
+       (h8300_src_operand): Likewise.
+       (bit_operand): Check nonimmediate_operand rather than general_operand.
+       Accept any nonimmediate_operand in h8sx code.
+       (h8300_and_costs): Initialize operands[1].
+       (h8300_rtx_costs) <AND>: Return false if the operands aren't valid.
+       (h8300_operand_class): New enum.
+       (h8300_length_table): New typedef.
+       (addb_length_table, addw_length_table, addl_length_table,
+       logicl_length_table): New tables.
+       (logicb_length_table, logicw_length_table): New macros.
+       (h8300_classify_operand, h8300_length_from_table,
+       h8300_length_table_for_insn, h8300_unary_length,
+       h8300_insn_length_from_table): New functions.
+       (output_plussi): Only use adds and subs for register destinations.
+       Disable redundant clause.
+       (compute_plussi_cc): Likewise.
+       (compute_plussi_length): Likewise.  Use h8300_length_from_table
+       to work out the length of an insn.
+       (output_logical_op): Only use narrower immediate instructions
+       if the destination is a register.
+       (compute_logical_op_cc): Likewise.
+       (compute_logical_op_length): Likewise.  Use h8300_length_from_table.
+       (h8300_adjust_insn_length): Tighten check for reg<->mem moves.
+       * config/h8300/h8300.md (length_table): New attribute.
+       (length): When an instruction has a length_table attribute, use
+       h8300_insn_length_from_table to calculate its default length.
+       (cmpqi): Use h8300_dst_operand for the first operand and
+       h8300_src_operand for the second.
+       (cmphi, *cmphi_h8300hs, cmpsi, negqi2, neghi2, neghi2_h8300h, negsi2,
+       negsi2_h8300h, addqi3, addhi3, *addhi3_h8300, *addhi3_h8300hs, addsi3,
+       addsi_h8300, addsi_h8300h, andhi3, andsi3, iorhi3,
+       iorsi3, xorhi3, xorsi3): Likewise.
+       (andqi3): Use h8300_src_operand for operand 2.  Adjust the condition
+       so that it allows any combination of operands for TARGET_H8300SX.
+       (iorqi3, xorqi3): Likewise.
+       (cmpqi): Use the length_table attribute.
+       (*cmphi_h8300hs, cmpsi, addqi, *addhi3_h8300hs, andqi3, iorqi3,
+       xorqi3, negqi2, neghi2_h8300h, negsi2_h8300h): Likewise.
+       (cmpqi): Add 'Q' constraint.
+       (*cmphi_h8300hs, cmpsi, addqi, *addhi3_h8300hs, addsi_h8300h, andqi3,
+       iorqi3, xorqi3, negqi2, neghi2_h8300h, negsi2_h8300h): Likewise.
+       2003-05-14  Richard Sandiford  <rsandifo@redhat.com>
+       * config/h8300/h8300.h (MASK_H8300SX): New macro.
+       (TARGET_H8300S): True for both -ms and -msx.
+       (TARGET_H8300SX): New macro.
+       (TARGET_SWITCHES): Add entries for -msx and -mno-sx.
+       * config/h8300/h8300.c (asm_file_start): Write .h8300sx for -msx.
+       * config/h8300/elf.h (LINK_SPEC): Use -m h8300sxelf for -msx.
+       * config/h8300/t-h8300 (MULTILIB_MATCHES): Use -ms multilibs for -msx.
+       [Temporary change.]
+       2003-02-28  Alexandre Oliva  <aoliva@redhat.com>
+       * config/h8300/h8300.h (SIZE_TYPE, PTRDIFF_TYPE): Use short with
+       16-bit pointers and 32-bit ints.
+       * config/h8300/h8300.h (LEGITIMATE_CONSTANT_P): Accept
+       CONST_DOUBLE with mode no wider than SImode.
+       * config/h8300/h8300.md (extendqisi2_h8300): Add constraints for
+       output operand.
+       2003-02-27  Alexandre Oliva  <aoliva@redhat.com>
+       * config/h8300/h8300.c (general_operand_src): Match CONSTANT_P_RTX
+       or SUBREG thereof.
+       * config/h8300/h8300.h (PREDICATE_CODES): Adjust.
+       2003-02-22  Alexandre Oliva  <aoliva@redhat.com>
+       * config/h8300/h8300.c (dosize): Truncate sign * size to Pmode.
+
 2004-05-28  Aaron W. LaFramboise <aaronraolete36@aaronwl.com>
 
        * config.gcc (i[34567]86-*-mingw32*): Enable threads by default.
index 004ac527bb5fddd00725e307ef54102cb1b8921d..72cf798a021dddb59270273dc96cfe8bd004f2b2 100644 (file)
@@ -2976,6 +2976,72 @@ expand_builtin_bcopy (tree arglist)
   return expand_builtin_memmove (newarglist, const0_rtx, VOIDmode);
 }
 
+#ifndef HAVE_movstr
+# define HAVE_movstr 0
+# define CODE_FOR_movstr CODE_FOR_nothing
+#endif
+
+/* Expand into a movstr instruction, if one is available.  Return 0 if
+   we failed, the caller should emit a normal call, otherwise try to
+   get the result in TARGET, if convenient.  If ENDP is 0 return the
+   destination pointer, if ENDP is 1 return the end pointer ala
+   mempcpy, and if ENDP is 2 return the end pointer minus one ala
+   stpcpy.  */
+
+static rtx
+expand_movstr (tree dest, tree src, rtx target, int endp)
+{
+  rtx end;
+  rtx dest_mem;
+  rtx src_mem;
+  rtx insn;
+  const struct insn_data * data;
+
+  if (!HAVE_movstr)
+    return 0;
+
+  dest_mem = get_memory_rtx (dest);
+  src_mem = get_memory_rtx (src);
+  if (!endp)
+    {
+      target = force_reg (Pmode, XEXP (dest_mem, 0));
+      dest_mem = replace_equiv_address (dest_mem, target);
+      end = gen_reg_rtx (Pmode);
+    }
+  else
+    {
+      if (target == 0 || target == const0_rtx)
+       {
+         end = gen_reg_rtx (Pmode);
+         if (target == 0)
+           target = end;
+       }
+      else
+       end = target;
+    }
+
+  data = insn_data + CODE_FOR_movstr;
+
+  if (data->operand[0].mode != VOIDmode)
+    end = gen_lowpart (data->operand[0].mode, end);
+
+  insn = data->genfun (end, dest_mem, src_mem);
+
+  if (insn == 0)
+    abort ();
+
+  emit_insn (insn);
+
+  /* movstr is supposed to set end to the address of the NUL
+     terminator.  If the caller requested a mempcpy-like return value,
+     adjust it.  */
+  if (endp == 1 && target != const0_rtx)
+    emit_move_insn (target, plus_constant (gen_lowpart (GET_MODE (target),
+                                                       end), 1));
+
+  return target;
+}
+
 /* Expand expression EXP, which is a call to the strcpy builtin.  Return 0
    if we failed the caller should emit a normal call, otherwise try to get
    the result in TARGET, if convenient (and in mode MODE if that's
@@ -2996,12 +3062,14 @@ expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode)
   if (operand_equal_p (src, dst, 0))
     return expand_expr (dst, target, mode, EXPAND_NORMAL);
 
-  fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
-  if (!fn)
-    return 0;
-
   len = c_strlen (src, 1);
   if (len == 0 || TREE_SIDE_EFFECTS (len))
+    return expand_movstr (TREE_VALUE (arglist),
+                         TREE_VALUE (TREE_CHAIN (arglist)),
+                         target, /*endp=*/0);
+
+  fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+  if (!fn)
     return 0;
 
   len = size_binop (PLUS_EXPR, len, ssize_int (1));
@@ -3020,22 +3088,17 @@ expand_builtin_strcpy (tree arglist, rtx target, enum machine_mode mode)
 static rtx
 expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode)
 {
+  /* If return value is ignored, transform stpcpy into strcpy.  */
+  if (target == const0_rtx)
+    return expand_builtin_strcpy (arglist, target, mode);
+
   if (!validate_arglist (arglist, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return 0;
   else
     {
       tree dst, src, len;
-
-      /* If return value is ignored, transform stpcpy into strcpy.  */
-      if (target == const0_rtx)
-       {
-         tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
-         if (!fn)
-           return 0;
-
-         return expand_expr (build_function_call_expr (fn, arglist),
-                             target, mode, EXPAND_NORMAL);
-       }
+      tree narglist;
+      rtx ret;
 
       /* Ensure we get an actual string whose length can be evaluated at
          compile-time, not an expression containing a string.  This is
@@ -3043,14 +3106,49 @@ expand_builtin_stpcpy (tree arglist, rtx target, enum machine_mode mode)
          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_movstr (TREE_VALUE (arglist),
+                             TREE_VALUE (TREE_CHAIN (arglist)),
+                             target, /*endp=*/2);
 
       dst = TREE_VALUE (arglist);
       len = fold (size_binop (PLUS_EXPR, len, ssize_int (1)));
-      arglist = build_tree_list (NULL_TREE, len);
-      arglist = tree_cons (NULL_TREE, src, arglist);
-      arglist = tree_cons (NULL_TREE, dst, arglist);
-      return expand_builtin_mempcpy (arglist, target, mode, /*endp=*/2);
+      narglist = build_tree_list (NULL_TREE, len);
+      narglist = tree_cons (NULL_TREE, src, narglist);
+      narglist = tree_cons (NULL_TREE, dst, narglist);
+      ret = expand_builtin_mempcpy (narglist, target, mode, /*endp=*/2);
+
+      if (ret)
+       return ret;
+
+      if (TREE_CODE (len) == INTEGER_CST)
+       {
+         rtx len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
+
+         if (GET_CODE (len_rtx) == CONST_INT)
+           {
+             ret = expand_builtin_strcpy (arglist, target, mode);
+
+             if (ret)
+               {
+                 if (! target)
+                   target = gen_reg_rtx (mode);
+                 if (GET_MODE (target) != GET_MODE (ret))
+                   ret = gen_lowpart (GET_MODE (target), ret);
+
+                 ret = emit_move_insn (target,
+                                       plus_constant (ret,
+                                                      INTVAL (len_rtx)));
+                 if (! ret)
+                   abort ();
+
+                 return target;
+               }
+           }
+       }
+
+      return expand_movstr (TREE_VALUE (arglist),
+                           TREE_VALUE (TREE_CHAIN (arglist)),
+                           target, /*endp=*/2);
     }
 }
 
index 8070a84c600f048fe3ff13d9579c8a5aaabece71..3835698554f74bb8cb350c54c2e0500cdef4829a 100644 (file)
@@ -51,6 +51,13 @@ Boston, MA 02111-1307, USA.  */
 #else
        .h8300s
 #endif
+#endif
+#ifdef __H8300SX__
+#ifdef __NORMAL_MODE__
+       .h8300sxn
+#else
+       .h8300sx
+#endif
 #endif
 
        .section .init
index 5b7a1c05a16c21ba1d686f400fca06bf8ccfb2a9..2d0e04583611a9dfa7b92123ddb5506e1c3aa9f0 100644 (file)
@@ -43,6 +43,13 @@ Boston, MA 02111-1307, USA.  */
 #else
        .h8300s
 #endif
+#endif
+#ifdef __H8300SX__
+#ifdef __NORMAL_MODE__
+       .h8300sxn
+#else
+       .h8300sx
+#endif
 #endif
        .section .init
        rts
index ecd0603814c2491d8a99b9357cc6881e6e7ebee0..542ffcf81a2bf3464e9faaac27ac3f6e75fc10a8 100644 (file)
@@ -40,6 +40,6 @@ Boston, MA 02111-1307, USA.  */
 #define JUMP_TABLES_IN_TEXT_SECTION (flag_pic)
 
 #undef LINK_SPEC
-#define LINK_SPEC "%{mh:%{mn:-m h8300hnelf}} %{mh:%{!mn:-m h8300helf}} %{ms:%{mn:-m h8300snelf}} %{ms:%{!mn:-m h8300self}}"
+#define LINK_SPEC "%{mh:%{mn:-m h8300hnelf}} %{mh:%{!mn:-m h8300helf}} %{ms:%{mn:-m h8300snelf}} %{ms:%{!mn:-m h8300self}} %{msx:%{mn:-m h8300sxnelf;:-m h8300sxelf}}"
 
 #endif /* h8300/elf.h */
diff --git a/gcc/config/h8300/genmova.sh b/gcc/config/h8300/genmova.sh
new file mode 100644 (file)
index 0000000..1988afa
--- /dev/null
@@ -0,0 +1,163 @@
+#!/bin/sh
+# Generate mova.md, a file containing patterns that can be implemented
+# using the h8sx mova instruction.
+
+echo ";; -*- buffer-read-only: t -*-"
+echo ";; Generated automatically from genmova.sh"
+
+# Loop over modes for the source operand (the index).  Only 8-bit and
+# 16-bit indices are allowed.
+for s in QI HI; do
+
+  # Set $src to the operand syntax for this size of index.
+  case $s in
+    QI) src=%X1.b;;
+    HI) src=%T1.w;;
+  esac
+
+  # A match_operand for the source.
+  operand="(match_operand:$s 1 \"h8300_dst_operand\" \"0,rQ\")"
+
+  # Loop over the destination register's mode.  The QI and HI versions use
+  # the same instructions as the SI ones, they just ignore the upper bits
+  # of the result.
+  for d in QI HI SI; do
+
+    # If the destination is larger than the source, include a
+    # zero_extend/plus pattern.  We could also match zero extensions
+    # of memory without the plus, but it's not any smaller or faster
+    # than separate insns.
+    case $d:$s in
+      SI:QI | SI:HI | HI:QI)
+       cat <<EOF
+(define_insn ""
+  [(set (match_operand:$d 0 "register_operand" "=r,r")
+       (plus:$d (zero_extend:$d $operand)
+                (match_operand:$d 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/b.l @(%o2,$src),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+EOF
+       ;;
+    esac
+
+    # Loop over the shift amount.
+    for shift in 1 2; do
+      case $shift in
+       1) opsize=w mult=2;;
+       2) opsize=l mult=4;;
+      esac
+
+      # Calculate the mask of bits that will be nonzero after the source
+      # has been extended and shifted.
+      case $s:$shift in
+       QI:1) mask=510;;
+       QI:2) mask=1020;;
+       HI:1) mask=131070;;
+       HI:2) mask=262140;;
+      esac
+
+      # There doesn't seem to be a well-established canonical form for
+      # some of the patterns we need.  Emit both shift and multiplication
+      # patterns.
+      for form in mult ashift; do
+       case $form in
+         mult) amount=$mult;;
+         ashift) amount=$shift;;
+       esac
+
+       case $d:$s in
+         # If the source and destination are the same size, we can treat
+         # mova as a sort of multiply-add instruction.
+         QI:QI | HI:HI)
+           cat <<EOF
+(define_insn ""
+  [(set (match_operand:$d 0 "register_operand" "=r,r")
+       (plus:$d ($form:$d $operand
+                          (const_int $amount))
+                (match_operand:$d 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/$opsize.l @(%o2,$src),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+EOF
+           ;;
+
+         # Handle the cases where the source is smaller than the
+         # destination.  Sometimes combine will keep the extension,
+         # sometimes it will use an AND.
+         SI:QI | SI:HI | HI:QI)
+
+           # Emit the forms that use zero_extend.
+           cat <<EOF
+(define_insn ""
+  [(set (match_operand:$d 0 "register_operand" "=r,r")
+       ($form:$d (zero_extend:$d $operand)
+                 (const_int $amount)))]
+  "TARGET_H8300SX"
+  "mova/$opsize.l @(0,$src),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:$d 0 "register_operand" "=r,r")
+       (plus:$d ($form:$d (zero_extend:$d $operand)
+                          (const_int $amount))
+                (match_operand:$d 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/$opsize.l @(%o2,$src),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+EOF
+
+           # Now emit the forms that use AND.  When the index is a register,
+           # these forms are effectively $d-mode operations: the index will
+           # be a $d-mode REG or SUBREG.  When the index is a memory
+           # location, we will have a paradoxical subreg such as:
+           #
+           #   (and:SI (mult:SI (subreg:SI (mem:QI ...) 0)
+           #                    (const_int 4))
+           #           (const_int 1020))
+           #
+           # Match the two case separately: a $d-mode register_operand
+           # or a $d-mode subreg of an $s-mode memory_operand.  Match the
+           # memory form first since register_operand accepts mem subregs
+           # before reload.
+           memory="(match_operand:$s 1 \"memory_operand\" \"m\")"
+           memory="(subreg:$d $memory 0)"
+           register="(match_operand:$d 1 \"register_operand\" \"0\")"
+           for paradoxical in "$memory" "$register"; do
+             cat <<EOF
+(define_insn ""
+  [(set (match_operand:$d 0 "register_operand" "=r")
+       (and:$d ($form:$d $paradoxical
+                         (const_int $amount))
+               (const_int $mask)))]
+  "TARGET_H8300SX"
+  "mova/$opsize.l @(0,$src),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:$d 0 "register_operand" "=r")
+       (plus:$d (and:$d ($form:$d $paradoxical
+                                  (const_int $amount))
+                        (const_int $mask))
+                (match_operand:$d 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/$opsize.l @(%o2,$src),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+EOF
+             done
+           ;;
+       esac
+      done
+    done
+  done
+done
index 7ad2df861cdc8d1c9c0b9147c5d1ba367906840f..6df3d71097134de2374b06cfab76838e76fca184 100644 (file)
@@ -46,7 +46,7 @@ extern unsigned int compute_logical_op_length (enum machine_mode,
                                               rtx *);
 extern int compute_logical_op_cc (enum machine_mode, rtx *);
 extern void h8300_expand_branch (enum rtx_code, rtx);
-extern void expand_a_shift (enum machine_mode, int, rtx[]);
+extern bool expand_a_shift (enum machine_mode, int, rtx[]);
 extern int h8300_shift_needs_scratch_p (int, enum machine_mode);
 extern int expand_a_rotate (rtx[]);
 extern int fix_bit_operand (rtx *, enum rtx_code);
@@ -83,7 +83,7 @@ extern int same_cmp_preceding_p (rtx);
 extern int same_cmp_following_p (rtx);
 
 extern int h8300_legitimate_constant_p (rtx);
-extern int h8300_legitimate_address_p (rtx, int);
+extern int h8300_legitimate_address_p (enum machine_mode, rtx, int);
 
 /* Used in builtins.c */
 extern rtx h8300_return_addr_rtx (int, rtx);
@@ -111,5 +111,14 @@ extern int h8300_hard_regno_mode_ok (int, enum machine_mode);
 struct cpp_reader;
 extern void h8300_pr_interrupt (struct cpp_reader *);
 extern void h8300_pr_saveall (struct cpp_reader *);
+extern enum reg_class  h8300_reg_class_from_letter (int);
+extern rtx             h8300_get_index (rtx, enum machine_mode mode, int *);
+extern unsigned int    h8300_insn_length_from_table (rtx, rtx *);
+extern const char *    output_h8sx_shift (rtx *, int, int);
+extern bool            h8300_operands_match_p (rtx *);
+extern bool            h8sx_mergeable_memrefs_p (rtx, rtx);
+extern bool            h8sx_emit_movmd (rtx, rtx, rtx, HOST_WIDE_INT);
+extern void            h8300_swap_into_er6 (rtx);
+extern void            h8300_swap_out_of_er6 (rtx);
 
 #endif /* ! GCC_H8300_PROTOS_H */
index 9efa140c23b60792c0a4f986dc95b5685357c669..f7d41c1ca11f6d737de0938376bf1603889faa0e 100644 (file)
@@ -46,6 +46,57 @@ Boston, MA 02111-1307, USA.  */
 #include "target.h"
 #include "target-def.h"
 
+/* Classifies a h8300_src_operand or h8300_dst_operand.
+
+   H8OP_IMMEDIATE
+       A constant operand of some sort.
+
+   H8OP_REGISTER
+       An ordinary register.
+
+   H8OP_MEM_ABSOLUTE
+       A memory reference with a constant address.
+
+   H8OP_MEM_BASE
+       A memory reference with a register as its address.
+
+   H8OP_MEM_COMPLEX
+       Some other kind of memory reference.  */
+enum h8300_operand_class
+{
+  H8OP_IMMEDIATE,
+  H8OP_REGISTER,
+  H8OP_MEM_ABSOLUTE,
+  H8OP_MEM_BASE,
+  H8OP_MEM_COMPLEX,
+  NUM_H8OPS
+};
+
+/* Classifies an h8sx shift operation.
+
+   H8SX_SHIFT_NONE
+       The shift cannot be done in a single instruction.
+
+   H8SX_SHIFT_UNARY
+       The shift is effectively a unary operation.  The instruction will
+       allow any sort of destination operand and have a format similar
+       to neg and not.  This is true of certain power-of-2 shifts.
+
+   H8SX_SHIFT_BINARY
+       The shift is a binary operation.  The destination must be a
+       register and the source can be a register or a constant.  */
+enum h8sx_shift_type
+{
+  H8SX_SHIFT_NONE,
+  H8SX_SHIFT_UNARY,
+  H8SX_SHIFT_BINARY
+};
+
+/* For a general two-operand instruction, element [X][Y] gives
+   the length of the opcode fields when the first operand has class
+   (X + 1) and the second has class Y.  */
+typedef unsigned char h8300_length_table[NUM_H8OPS - 1][NUM_H8OPS];
+
 /* Forward declarations.  */
 static const char *byte_reg (rtx, int);
 static int h8300_interrupt_function_p (tree);
@@ -67,6 +118,22 @@ static void h8300_asm_named_section (const char *, unsigned int);
 #endif
 static int h8300_and_costs (rtx);
 static int h8300_shift_costs (rtx);
+static void          h8300_push_pop               (int, int, int, int);
+static int           h8300_stack_offset_p         (rtx, int);
+static int           h8300_ldm_stm_regno          (rtx, int, int, int);
+static int           h8300_ldm_stm_parallel       (rtvec, int, int);
+static void          h8300_reorg                  (void);
+static unsigned int  h8300_constant_length        (rtx);
+static unsigned int  h8300_displacement_length    (rtx, int);
+static unsigned int  h8300_classify_operand       (rtx, int, enum h8300_operand_class *);
+static unsigned int  h8300_length_from_table      (rtx, rtx, const h8300_length_table *);
+static unsigned int  h8300_unary_length           (rtx);
+static unsigned int  h8300_short_immediate_length (rtx);
+static unsigned int  h8300_bitfield_length        (rtx, rtx);
+static unsigned int  h8300_binary_length          (rtx, const h8300_length_table *);
+static bool          h8300_short_move_mem_p       (rtx, enum rtx_code);
+static unsigned int  h8300_move_length            (rtx *, const h8300_length_table *);
+enum h8sx_shift_type h8sx_classify_shift          (enum machine_mode, enum rtx_code, rtx);
 
 /* CPU_TYPE, says what cpu we're compiling for.  */
 int cpu_type;
@@ -94,6 +161,9 @@ const char * const *h8_reg_names;
 
 const char *h8_push_op, *h8_pop_op, *h8_mov_op;
 
+/* Value of MOVE_RATIO.  */
+int h8300_move_ratio;
+
 /* Machine-specific symbol_ref flags.  */
 #define SYMBOL_FLAG_FUNCVEC_FUNCTION   (SYMBOL_FLAG_MACH_DEP << 0)
 #define SYMBOL_FLAG_EIGHTBIT_DATA      (SYMBOL_FLAG_MACH_DEP << 1)
@@ -328,6 +398,102 @@ h8300_init_once (void)
       /* H8S */
       shift_alg_hi[H8_S][SHIFT_ASHIFTRT][14] = SHIFT_LOOP;
     }
+
+  /* Work out a value for MOVE_RATIO.  */
+  if (!TARGET_H8300SX)
+    {
+      /* Memory-memory moves are quite expensive without the
+        h8sx instructions.  */
+      h8300_move_ratio = 3;
+    }
+  else if (flag_omit_frame_pointer)
+    {
+      /* movmd sequences are fairly cheap when er6 isn't fixed.  They can
+        sometimes be as short as two individual memory-to-memory moves,
+        but since they use all the call-saved registers, it seems better
+        to allow up to three moves here.  */
+      h8300_move_ratio = 4;
+    }
+  else if (optimize_size)
+    {
+      /* In this case we don't use movmd sequences since they tend
+        to be longer than calls to memcpy().  Memory-to-memory
+        moves are cheaper than for !TARGET_H8300SX, so it makes
+        sense to have a slightly higher threshold.  */
+      h8300_move_ratio = 4;
+    }
+  else
+    {
+      /* We use movmd sequences for some moves since it can be quicker
+        than calling memcpy().  The sequences will need to save and
+        restore er6 though, so bump up the cost.  */
+      h8300_move_ratio = 6;
+    }
+}
+
+/* Implement REG_CLASS_FROM_LETTER.
+
+   Some patterns need to use er6 as a scratch register.  This is
+   difficult to arrange since er6 is the frame pointer and usually
+   can't be spilled.
+
+   Such patterns should define two alternatives, one which allows only
+   er6 and one which allows any general register.  The former alternative
+   should have a 'd' constraint while the latter should be disparaged and
+   use 'D'.
+
+   Normally, 'd' maps to DESTINATION_REGS and 'D' maps to GENERAL_REGS.
+   However, there are cases where they should be NO_REGS:
+
+     - 'd' should be NO_REGS when reloading a function that uses the
+       frame pointer.  In this case, DESTINATION_REGS won't contain any
+       spillable registers, so the first alternative can't be used.
+
+     - -fno-omit-frame-pointer means that the frame pointer will
+       always be in use.  It's therefore better to map 'd' to NO_REGS
+       before reload so that register allocator will pick the second
+       alternative.
+
+     - we would like 'D' to be be NO_REGS when the frame pointer isn't
+       live, but we the frame pointer may turn out to be needed after
+       we start reload, and then we may have already decided we don't
+       have a choice, so we can't do that.  Forcing the register
+       allocator to use er6 if possible might produce better code for
+       small functions: it's more efficient to save and restore er6 in
+       the prologue & epilogue than to do it in a define_split.
+       Hopefully disparaging 'D' will have a similar effect, without
+       forcing a reload failure if the frame pointer is found to be
+       needed too late.  */
+
+enum reg_class
+h8300_reg_class_from_letter (int c)
+{
+  switch (c)
+    {
+    case 'a':
+      return MAC_REGS;
+
+    case 'c':
+      return COUNTER_REGS;
+
+    case 'd':
+      if (!flag_omit_frame_pointer && !reload_completed)
+       return NO_REGS;
+      if (frame_pointer_needed && reload_in_progress)
+       return NO_REGS;
+      return DESTINATION_REGS;
+
+    case 'D':
+      /* The meaning of a constraint shouldn't change dynamically, so
+        we can't make this NO_REGS.  */
+      return GENERAL_REGS;
+
+    case 'f':
+      return SOURCE_REGS;
+
+    default:
+      return NO_REGS;
+    }
 }
 
 /* Return the byte register name for a register rtx X.  B should be 0
@@ -474,6 +640,196 @@ pop (int rn)
   REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_INC, stack_pointer_rtx, 0);
 }
 
+/* Emit an instruction to push or pop NREGS consecutive registers
+   starting at register REGNO.  POP_P selects a pop rather than a
+   push and RETURN_P is true if the instruction should return.
+
+   It must be possible to do the requested operation in a single
+   instruction.  If NREGS == 1 && !RETURN_P, use a normal push
+   or pop insn.  Otherwise emit a parallel of the form:
+
+     (parallel
+       [(return)  ;; if RETURN_P
+       (save or restore REGNO)
+       (save or restore REGNO + 1)
+       ...
+       (save or restore REGNO + NREGS - 1)
+       (set sp (plus sp (const_int adjust)))]  */
+
+static void
+h8300_push_pop (int regno, int nregs, int pop_p, int return_p)
+{
+  int i, j;
+  rtvec vec;
+  rtx sp, offset;
+
+  /* See whether we can use a simple push or pop.  */
+  if (!return_p && nregs == 1)
+    {
+      if (pop_p)
+       pop (regno);
+      else
+       push (regno);
+      return;
+    }
+
+  /* We need one element for the return insn, if present, one for each
+     register, and one for stack adjustment.  */
+  vec = rtvec_alloc ((return_p != 0) + nregs + 1);
+  sp = stack_pointer_rtx;
+  i = 0;
+
+  /* Add the return instruction.  */
+  if (return_p)
+    {
+      RTVEC_ELT (vec, i) = gen_rtx_RETURN (VOIDmode);
+      i++;
+    }
+
+  /* Add the register moves.  */
+  for (j = 0; j < nregs; j++)
+    {
+      rtx lhs, rhs;
+
+      if (pop_p)
+       {
+         /* Register REGNO + NREGS - 1 is popped first.  Before the
+            stack adjustment, its slot is at address @sp.  */
+         lhs = gen_rtx_REG (SImode, regno + j);
+         rhs = gen_rtx_MEM (SImode, plus_constant (sp, (nregs - j - 1) * 4));
+       }
+      else
+       {
+         /* Register REGNO is pushed first and will be stored at @(-4,sp).  */
+         lhs = gen_rtx_MEM (SImode, plus_constant (sp, (j + 1) * -4));
+         rhs = gen_rtx_REG (SImode, regno + j);
+       }
+      RTVEC_ELT (vec, i + j) = gen_rtx_SET (VOIDmode, lhs, rhs);
+    }
+
+  /* Add the stack adjustment.  */
+  offset = GEN_INT ((pop_p ? nregs : -nregs) * 4);
+  RTVEC_ELT (vec, i + j) = gen_rtx_SET (VOIDmode, sp,
+                                       gen_rtx_PLUS (Pmode, sp, offset));
+
+  emit_insn (gen_rtx_PARALLEL (VOIDmode, vec));
+}
+
+/* Return true if X has the value sp + OFFSET.  */
+
+static int
+h8300_stack_offset_p (rtx x, int offset)
+{
+  if (offset == 0)
+    return x == stack_pointer_rtx;
+
+  return (GET_CODE (x) == PLUS
+         && XEXP (x, 0) == stack_pointer_rtx
+         && GET_CODE (XEXP (x, 1)) == CONST_INT
+         && INTVAL (XEXP (x, 1)) == offset);
+}
+
+/* A subroutine of h8300_ldm_stm_parallel.  X is one pattern in
+   something that may be an ldm or stm instruction.  If it fits
+   the required template, return the register it loads or stores,
+   otherwise return -1.
+
+   LOAD_P is true if X should be a load, false if it should be a store.
+   NREGS is the number of registers that the whole instruction is expected
+   to load or store.  INDEX is the index of the register that X should
+   load or store, relative to the lowest-numbered register.  */
+
+static int
+h8300_ldm_stm_regno (rtx x, int load_p, int index, int nregs)
+{
+  int regindex, memindex, offset;
+
+  if (load_p)
+    regindex = 0, memindex = 1, offset = (nregs - index - 1) * 4;
+  else
+    memindex = 0, regindex = 1, offset = (index + 1) * -4;
+
+  if (GET_CODE (x) == SET
+      && GET_CODE (XEXP (x, regindex)) == REG
+      && GET_CODE (XEXP (x, memindex)) == MEM
+      && h8300_stack_offset_p (XEXP (XEXP (x, memindex), 0), offset))
+    return REGNO (XEXP (x, regindex));
+
+  return -1;
+}
+
+/* Return true if the elements of VEC starting at FIRST describe an
+   ldm or stm instruction (LOAD_P says which).  */
+
+static int
+h8300_ldm_stm_parallel (rtvec vec, int load_p, int first)
+{
+  rtx last;
+  int nregs, i, regno, adjust;
+
+  /* There must be a stack adjustment, a register move, and at least one
+     other operation (a return or another register move).  */
+  if (GET_NUM_ELEM (vec) < 3)
+    return false;
+
+  /* Get the range of registers to be pushed or popped.  */
+  nregs = GET_NUM_ELEM (vec) - first - 1;
+  regno = h8300_ldm_stm_regno (RTVEC_ELT (vec, first), load_p, 0, nregs);
+
+  /* Check that the call to h8300_ldm_stm_regno succeeded and
+     that we're only dealing with GPRs.  */
+  if (regno < 0 || regno + nregs > 8)
+    return false;
+
+  /* 2-register h8s instructions must start with an even-numbered register.
+     3- and 4-register instructions must start with er0 or er4.  */
+  if (!TARGET_H8300SX)
+    {
+      if ((regno & 1) != 0)
+       return false;
+      if (nregs > 2 && (regno & 3) != 0)
+       return false;
+    }
+
+  /* Check the other loads or stores.  */
+  for (i = 1; i < nregs; i++)
+    if (h8300_ldm_stm_regno (RTVEC_ELT (vec, first + i), load_p, i, nregs)
+       != regno + i)
+      return false;
+
+  /* Check the stack adjustment.  */
+  last = RTVEC_ELT (vec, first + nregs);
+  adjust = (load_p ? nregs : -nregs) * 4;
+  return (GET_CODE (last) == SET
+         && SET_DEST (last) == stack_pointer_rtx
+         && h8300_stack_offset_p (SET_SRC (last), adjust));
+}
+
+/* Return true if X is an ldm.l pattern.  X is known to be parallel.  */
+
+int
+h8300_ldm_parallel (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return h8300_ldm_stm_parallel (XVEC (x, 0), 1, 0);
+}
+
+/* Likewise stm.l.  */
+
+int
+h8300_stm_parallel (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return h8300_ldm_stm_parallel (XVEC (x, 0), 0, 0);
+}
+
+/* Likewise rts/l and rte/l.  Note that the .md pattern will check
+   for the return so there's no need to do that here.  */
+
+int
+h8300_return_parallel (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return h8300_ldm_stm_parallel (XVEC (x, 0), 1, 1);
+}
+
 /* This is what the stack looks like after the prolog of
    a function with a frame has been set up:
 
@@ -529,42 +885,20 @@ h8300_expand_prologue (void)
          if (TARGET_H8300S)
            {
              /* See how many registers we can push at the same time.  */
-             if ((regno == 0 || regno == 4)
+             if ((!TARGET_H8300SX || (regno & 3) == 0)
                  && ((saved_regs >> regno) & 0x0f) == 0x0f)
                n_regs = 4;
 
-             else if ((regno == 0 || regno == 4)
+             else if ((!TARGET_H8300SX || (regno & 3) == 0)
                       && ((saved_regs >> regno) & 0x07) == 0x07)
                n_regs = 3;
 
-             else if ((regno == 0 || regno == 2 || regno == 4 || regno == 6)
+             else if ((!TARGET_H8300SX || (regno & 1) == 0)
                       && ((saved_regs >> regno) & 0x03) == 0x03)
                n_regs = 2;
            }
 
-         switch (n_regs)
-           {
-           case 1:
-             push (regno);
-             break;
-           case 2:
-             emit_insn (gen_stm_h8300s_2 (gen_rtx_REG (SImode, regno),
-                                          gen_rtx_REG (SImode, regno + 1)));
-             break;
-           case 3:
-             emit_insn (gen_stm_h8300s_3 (gen_rtx_REG (SImode, regno),
-                                          gen_rtx_REG (SImode, regno + 1),
-                                          gen_rtx_REG (SImode, regno + 2)));
-             break;
-           case 4:
-             emit_insn (gen_stm_h8300s_4 (gen_rtx_REG (SImode, regno),
-                                          gen_rtx_REG (SImode, regno + 1),
-                                          gen_rtx_REG (SImode, regno + 2),
-                                          gen_rtx_REG (SImode, regno + 3)));
-             break;
-           default:
-             abort ();
-           }
+         h8300_push_pop (regno, n_regs, 0, 0);
        }
     }
 
@@ -592,14 +926,19 @@ h8300_expand_epilogue (void)
   int regno;
   int saved_regs;
   int n_regs;
+  HOST_WIDE_INT frame_size;
+  bool returned_p;
 
   if (h8300_os_task_function_p (current_function_decl))
     /* OS_Task epilogues are nearly naked -- they just have an
        rts instruction.  */
     return;
 
+  frame_size = round_frame_size (get_frame_size ());
+  returned_p = false;
+
   /* Deallocate locals.  */
-  h8300_emit_stack_adjustment (1, round_frame_size (get_frame_size ()));
+  h8300_emit_stack_adjustment (1, frame_size);
 
   /* Pop the saved registers in descending order.  */
   saved_regs = compute_saved_regs ();
@@ -611,48 +950,41 @@ h8300_expand_epilogue (void)
          if (TARGET_H8300S)
            {
              /* See how many registers we can pop at the same time.  */
-             if ((regno == 7 || regno == 3)
-                 && ((saved_regs >> (regno - 3)) & 0x0f) == 0x0f)
+             if ((TARGET_H8300SX || (regno & 3) == 3)
+                 && ((saved_regs << 3 >> regno) & 0x0f) == 0x0f)
                n_regs = 4;
 
-             else if ((regno == 6 || regno == 2)
-                      && ((saved_regs >> (regno - 2)) & 0x07) == 0x07)
+             else if ((TARGET_H8300SX || (regno & 3) == 2)
+                      && ((saved_regs << 2 >> regno) & 0x07) == 0x07)
                n_regs = 3;
 
-             else if ((regno == 7 || regno == 5 || regno == 3 || regno == 1)
-                      && ((saved_regs >> (regno - 1)) & 0x03) == 0x03)
+             else if ((TARGET_H8300SX || (regno & 1) == 1)
+                      && ((saved_regs << 1 >> regno) & 0x03) == 0x03)
                n_regs = 2;
            }
 
-         switch (n_regs)
-           {
-           case 1:
-             pop (regno);
-             break;
-           case 2:
-             emit_insn (gen_ldm_h8300s_2 (gen_rtx_REG (SImode, regno - 1),
-                                          gen_rtx_REG (SImode, regno)));
-             break;
-           case 3:
-             emit_insn (gen_ldm_h8300s_3 (gen_rtx_REG (SImode, regno - 2),
-                                          gen_rtx_REG (SImode, regno - 1),
-                                          gen_rtx_REG (SImode, regno)));
-             break;
-           case 4:
-             emit_insn (gen_ldm_h8300s_4 (gen_rtx_REG (SImode, regno - 3),
-                                          gen_rtx_REG (SImode, regno - 2),
-                                          gen_rtx_REG (SImode, regno - 1),
-                                          gen_rtx_REG (SImode, regno)));
-             break;
-           default:
-             abort ();
-           }
+         /* See if this pop would be the last insn before the return.
+            If so, use rte/l or rts/l instead of pop or ldm.l.  */
+         if (TARGET_H8300SX
+             && !frame_pointer_needed
+             && frame_size == 0
+             && (saved_regs & ((1 << (regno - n_regs + 1)) - 1)) == 0)
+           returned_p = true;
+
+         h8300_push_pop (regno - n_regs + 1, n_regs, 1, returned_p);
        }
     }
 
   /* Pop frame pointer if we had one.  */
   if (frame_pointer_needed)
-    pop (HARD_FRAME_POINTER_REGNUM);
+    {
+      if (TARGET_H8300SX)
+       returned_p = true;
+      h8300_push_pop (HARD_FRAME_POINTER_REGNUM, 1, 1, returned_p);
+    }
+
+  if (!returned_p)
+    emit_insn (gen_rtx_RETURN (VOIDmode));
 }
 
 /* Return nonzero if the current function is an interrupt
@@ -674,6 +1006,8 @@ h8300_file_start (void)
 
   if (TARGET_H8300H)
     fputs (TARGET_NORMAL_MODE ? "\t.h8300hn\n" : "\t.h8300h\n", asm_out_file);
+  else if (TARGET_H8300SX)
+    fputs (TARGET_NORMAL_MODE ? "\t.h8300sxn\n" : "\t.h8300sx\n", asm_out_file);
   else if (TARGET_H8300S)
     fputs (TARGET_NORMAL_MODE ? "\t.h8300sn\n" : "\t.h8300s\n", asm_out_file);
 }
@@ -712,6 +1046,46 @@ general_operand_dst (rtx op, enum machine_mode mode)
   return general_operand (op, mode);
 }
 
+/* Return true if OP is a suitable first operand for a general arithmetic
+   insn such as "add".  */
+
+int
+h8300_dst_operand (rtx op, enum machine_mode mode)
+{
+  if (TARGET_H8300SX)
+    return nonimmediate_operand (op, mode);
+  return register_operand (op, mode);
+}
+
+/* Likewise the second operand.  */
+
+int
+h8300_src_operand (rtx op, enum machine_mode mode)
+{
+  if (TARGET_H8300SX)
+    return general_operand (op, mode);
+  return nonmemory_operand (op, mode);
+}
+
+/* Check that an operand is either a register or an unsigned 4-bit
+   constant.  */
+
+int
+nibble_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (GET_CODE (op) == CONST_INT && TARGET_H8300SX
+         && INTVAL (op) >= 0 && INTVAL (op) <= 15);
+}
+
+/* Check that an operand is either a register or an unsigned 4-bit
+   constant.  */
+
+int
+reg_or_nibble_operand (rtx op, enum machine_mode mode)
+{
+  return (nibble_operand (op, mode) || register_operand (op, mode));
+}
+
 /* Return true if OP is a constant that contains only one 1 in its
    binary representation.  */
 
@@ -769,6 +1143,9 @@ call_insn_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 int
 two_insn_adds_subs_operand (rtx op, enum machine_mode mode)
 {
+  if (TARGET_H8300SX)
+    return 0;
+
   if (GET_CODE (op) == CONST_INT)
     {
       HOST_WIDE_INT value = INTVAL (op);
@@ -901,11 +1278,15 @@ jump_address_operand (rtx op, enum machine_mode mode)
 int
 bit_operand (rtx op, enum machine_mode mode)
 {
-  /* We can accept any general operand, except that MEM operands must
+  /* We can accept any nonimmediate operand, except that MEM operands must
      be limited to those that use addresses valid for the 'U' constraint.  */
-  if (!general_operand (op, mode))
+  if (!nonimmediate_operand (op, mode))
     return 0;
 
+  /* H8SX accepts pretty much anything here.  */
+  if (TARGET_H8300SX)
+    return 1;
+
   /* Accept any mem during RTL generation.  Otherwise, the code that does
      insv and extzv will think that we can not handle memory.  However,
      to avoid reload problems, we only accept 'U' MEM operands after RTL
@@ -917,7 +1298,7 @@ bit_operand (rtx op, enum machine_mode mode)
   if (GET_CODE (op) == SUBREG)
     return 1;
   return (GET_CODE (op) == MEM
-         && EXTRA_CONSTRAINT (op, 'U'));
+         && OK_FOR_U (op));
 }
 
 /* Return nonzero if OP is a MEM suitable for bit manipulation insns.  */
@@ -926,7 +1307,7 @@ int
 bit_memory_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return (GET_CODE (op) == MEM
-         && EXTRA_CONSTRAINT (op, 'U'));
+         && OK_FOR_U (op));
 }
 
 /* Handle machine specific pragmas for compatibility with existing
@@ -1038,7 +1419,7 @@ h8300_and_costs (rtx x)
     return 100;
 
   operands[0] = NULL;
-  operands[1] = NULL;
+  operands[1] = XEXP (x, 0);
   operands[2] = XEXP (x, 1);
   operands[3] = x;
   return compute_logical_op_length (GET_MODE (x), operands) / 2;
@@ -1068,12 +1449,35 @@ h8300_shift_costs (rtx x)
 static bool
 h8300_rtx_costs (rtx x, int code, int outer_code, int *total)
 {
+  if (TARGET_H8300SX && outer_code == MEM)
+    {
+      /* Estimate the number of execution states needed to calculate
+        the address.  */
+      if (register_operand (x, VOIDmode)
+         || GET_CODE (x) == POST_INC
+         || GET_CODE (x) == POST_DEC
+         || CONSTANT_P (x))
+       *total = 0;
+      else
+       *total = COSTS_N_INSNS (1);
+      return true;
+    }
+
   switch (code)
     {
     case CONST_INT:
       {
        HOST_WIDE_INT n = INTVAL (x);
 
+       if (TARGET_H8300SX)
+         {
+           /* Constant operands need the same number of processor
+              states as register operands.  Although we could try to
+              use a size-based cost for optimize_size, the lack of
+              of a mode makes the results very unpredictable.  */
+           *total = 0;
+           return true;
+         }
        if (-4 <= n || n <= 4)
          {
            switch ((int) n)
@@ -1103,6 +1507,12 @@ h8300_rtx_costs (rtx x, int code, int outer_code, int *total)
     case CONST:
     case LABEL_REF:
     case SYMBOL_REF:
+      if (TARGET_H8300SX)
+       {
+         /* See comment for CONST_INT.  */
+         *total = 0;
+         return true;
+       }
       *total = 3;
       return true;
 
@@ -1111,6 +1521,9 @@ h8300_rtx_costs (rtx x, int code, int outer_code, int *total)
       return true;
 
     case AND:
+      if (!h8300_dst_operand (XEXP (x, 0), VOIDmode)
+         || !h8300_src_operand (XEXP (x, 1), VOIDmode))
+       return false;
       *total = COSTS_N_INSNS (h8300_and_costs (x));
       return true;
 
@@ -1118,16 +1531,58 @@ h8300_rtx_costs (rtx x, int code, int outer_code, int *total)
        generate some really horrible code for division of a power of two.  */
     case MOD:
     case DIV:
-      *total = 60;
+    case UMOD:
+    case UDIV:
+      if (TARGET_H8300SX)
+       switch (GET_MODE (x))
+         {
+         case QImode:
+         case HImode:
+           *total = COSTS_N_INSNS (optimize_size ? 4 : 10);
+           return false;
+
+         case SImode:
+           *total = COSTS_N_INSNS (optimize_size ? 4 : 18);
+           return false;
+
+         default:
+           break;
+         }
+      *total = COSTS_N_INSNS (12);
       return true;
 
     case MULT:
-      *total = 20;
+      if (TARGET_H8300SX)
+       switch (GET_MODE (x))
+         {
+         case QImode:
+         case HImode:
+           *total = COSTS_N_INSNS (2);
+           return false;
+
+         case SImode:
+           *total = COSTS_N_INSNS (5);
+           return false;
+
+         default:
+           break;
+         }
+      *total = COSTS_N_INSNS (4);
       return true;
 
     case ASHIFT:
     case ASHIFTRT:
     case LSHIFTRT:
+      if (h8sx_binary_shift_operator (x, VOIDmode))
+       {
+         *total = COSTS_N_INSNS (2);
+         return false;
+       }
+      else if (h8sx_unary_shift_operator (x, VOIDmode))
+       {
+         *total = COSTS_N_INSNS (1);
+         return false;
+       }
       *total = COSTS_N_INSNS (h8300_shift_costs (x));
       return true;
 
@@ -1140,8 +1595,8 @@ h8300_rtx_costs (rtx x, int code, int outer_code, int *total)
       return true;
 
     default:
-      *total = 4;
-      return true;
+      *total = COSTS_N_INSNS (1);
+      return false;
     }
 }
 \f
@@ -1167,6 +1622,8 @@ h8300_rtx_costs (rtx x, int code, int outer_code, int *total)
        then +2. if const then least sig word
    'j' print operand as condition code.
    'k' print operand as reverse condition code.
+   'm' convert an integer operand to a size suffix (.b, .w or .l)
+   'o' print an integer without a leading '#'
    's' print as low byte of 16 bit value
    't' print as high byte of 16 bit value
    'w' print as low byte of 32 bit value
@@ -1373,6 +1830,21 @@ print_operand (FILE *file, rtx x, int code)
     case 'k':
       fputs (cond_string (reverse_condition (GET_CODE (x))), file);
       break;
+    case 'm':
+      if (GET_CODE (x) != CONST_INT)
+       abort ();
+      if (INTVAL (x) == 1)
+       fputs (".b", file);
+      else if (INTVAL (x) == 2)
+       fputs (".w", file);
+      else if (INTVAL (x) == 4)
+       fputs (".l", file);
+      else
+       abort ();
+      break;
+    case 'o':
+      print_operand_address (file, x);
+      break;
     case 's':
       if (GET_CODE (x) == CONST_INT)
        fprintf (file, "#%ld", (INTVAL (x)) & 0xff);
@@ -1445,32 +1917,41 @@ print_operand (FILE *file, rtx x, int code)
            fprintf (file, "@");
            output_address (addr);
 
-           /* We fall back from smaller addressing to larger
-              addressing in various ways depending on CODE.  */
-           switch (code)
-             {
-             case 'R':
-               /* Used for mov.b and bit operations.  */
-               if (h8300_eightbit_constant_address_p (addr))
-                 {
-                   fprintf (file, ":8");
-                   break;
-                 }
-
-               /* Fall through.  We should not get here if we are
-                  processing bit operations on H8/300 or H8/300H
-                  because 'U' constraint does not allow bit
-                  operations on the tiny area on these machines.  */
-
-             case 'T':
-             case 'S':
-               /* Used for mov.w and mov.l.  */
-               if (h8300_tiny_constant_address_p (addr))
-                 fprintf (file, ":16");
-               break;
-             default:
-               break;
-             }
+           /* Add a length suffix to constant addresses.  Although this
+              is often unnecessary, it helps to avoid ambiguity in the
+              syntax of mova.  If we wrote an insn like:
+
+                   mova/w.l @(1,@foo.b),er0
+
+              then .b would be considered part of the symbol name.
+              Adding a length after foo will avoid this.  */
+           if (CONSTANT_P (addr))
+             switch (code)
+               {
+               case 'R':
+                 /* Used for mov.b and bit operations.  */
+                 if (h8300_eightbit_constant_address_p (addr))
+                   {
+                     fprintf (file, ":8");
+                     break;
+                   }
+
+                 /* Fall through.  We should not get here if we are
+                    processing bit operations on H8/300 or H8/300H
+                    because 'U' constraint does not allow bit
+                    operations on the tiny area on these machines.  */
+
+               case 'X':
+               case 'T':
+               case 'S':
+                 if (h8300_constant_length (addr) == 2)
+                   fprintf (file, ":16");
+                 else
+                   fprintf (file, ":32");
+                 break;
+               default:
+                 break;
+               }
          }
          break;
 
@@ -1501,6 +1982,9 @@ print_operand (FILE *file, rtx x, int code)
 void
 print_operand_address (FILE *file, rtx addr)
 {
+  rtx index;
+  int size;
+
   switch (GET_CODE (addr))
     {
     case REG:
@@ -1515,14 +1999,45 @@ print_operand_address (FILE *file, rtx addr)
       fprintf (file, "%s+", h8_reg_names[REGNO (XEXP (addr, 0))]);
       break;
 
+    case PRE_INC:
+      fprintf (file, "+%s", h8_reg_names[REGNO (XEXP (addr, 0))]);
+      break;
+
+    case POST_DEC:
+      fprintf (file, "%s-", h8_reg_names[REGNO (XEXP (addr, 0))]);
+      break;
+
     case PLUS:
       fprintf (file, "(");
-      if (GET_CODE (XEXP (addr, 0)) == REG)
+
+      index = h8300_get_index (XEXP (addr, 0), VOIDmode, &size);
+      if (GET_CODE (index) == REG)
        {
          /* reg,foo */
          print_operand_address (file, XEXP (addr, 1));
          fprintf (file, ",");
-         print_operand_address (file, XEXP (addr, 0));
+         switch (size)
+           {
+           case 0:
+             print_operand_address (file, index);
+             break;
+
+           case 1:
+             print_operand (file, index, 'X');
+             fputs (".b", file);
+             break;
+
+           case 2:
+             print_operand (file, index, 'T');
+             fputs (".w", file);
+             break;
+
+           case 4:
+             print_operand (file, index, 'S');
+             fputs (".l", file);
+             break;
+           }
+         /* print_operand_address (file, XEXP (addr, 0)); */
        }
       else
        {
@@ -1731,125 +2246,826 @@ notice_update_cc (rtx body, rtx insn)
        }
       break;
 
-    case CC_COMPARE:
-      /* The insn is a compare instruction.  */
-      CC_STATUS_INIT;
-      cc_status.value1 = SET_SRC (body);
-      break;
+    case CC_COMPARE:
+      /* The insn is a compare instruction.  */
+      CC_STATUS_INIT;
+      cc_status.value1 = SET_SRC (body);
+      break;
+
+    case CC_CLOBBER:
+      /* Insn doesn't leave CC in a usable state.  */
+      CC_STATUS_INIT;
+      break;
+    }
+}
+
+/* Return nonzero if X is a stack pointer.  */
+
+int
+stack_pointer_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return x == stack_pointer_rtx;
+}
+
+/* Return nonzero if X is a constant whose absolute value is greater
+   than 2.  */
+
+int
+const_int_gt_2_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (GET_CODE (x) == CONST_INT
+         && abs (INTVAL (x)) > 2);
+}
+
+/* Return nonzero if X is a constant whose absolute value is no
+   smaller than 8.  */
+
+int
+const_int_ge_8_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (GET_CODE (x) == CONST_INT
+         && abs (INTVAL (x)) >= 8);
+}
+
+/* Return nonzero if X is a constant expressible in QImode.  */
+
+int
+const_int_qi_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (GET_CODE (x) == CONST_INT
+         && (INTVAL (x) & 0xff) == INTVAL (x));
+}
+
+/* Return nonzero if X is a constant expressible in HImode.  */
+
+int
+const_int_hi_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (GET_CODE (x) == CONST_INT
+         && (INTVAL (x) & 0xffff) == INTVAL (x));
+}
+
+/* Return nonzero if X is a constant suitable for inc/dec.  */
+
+int
+incdec_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (GET_CODE (x) == CONST_INT
+         && (CONST_OK_FOR_M (INTVAL (x))
+             || CONST_OK_FOR_O (INTVAL (x))));
+}
+
+/* Return nonzero if X is either EQ or NE.  */
+
+int
+eqne_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  enum rtx_code code = GET_CODE (x);
+
+  return (code == EQ || code == NE);
+}
+
+/* Return nonzero if X is either GT or LE.  */
+
+int
+gtle_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  enum rtx_code code = GET_CODE (x);
+
+  return (code == GT || code == LE);
+}
+
+/* Return nonzero if X is either GTU or LEU.  */
+
+int
+gtuleu_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  enum rtx_code code = GET_CODE (x);
+
+  return (code == GTU || code == LEU);
+}
+
+/* Return nonzero if X is either IOR or XOR.  */
+
+int
+iorxor_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  enum rtx_code code = GET_CODE (x);
+
+  return (code == IOR || code == XOR);
+}
+
+/* Recognize valid operators for bit instructions.  */
+
+int
+bit_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  enum rtx_code code = GET_CODE (x);
+
+  return (code == XOR
+         || code == AND
+         || code == IOR);
+}
+\f
+/* Given that X occurs in an address of the form (plus X constant),
+   return the part of X that is expected to be a register.  There are
+   four kinds of addressing mode to recognize:
+
+       @(dd,Rn)
+       @(dd,RnL.b)
+       @(dd,Rn.w)
+       @(dd,ERn.l)
+
+   If SIZE is nonnull, and the address is one of the last three forms,
+   set *SIZE to the index multiplication factor.  Set it to 0 for
+   plain @(dd,Rn) addresses.
+
+   MODE is the mode of the value being accessed.  It can be VOIDmode
+   if the address is known to be valid, but its mode is unknown.  */
+
+rtx
+h8300_get_index (rtx x, enum machine_mode mode, int *size)
+{
+  int dummy, factor;
+
+  if (size == 0)
+    size = &dummy;
+
+  factor = (mode == VOIDmode ? 0 : GET_MODE_SIZE (mode));
+  if (TARGET_H8300SX
+      && factor <= 4
+      && (mode == VOIDmode
+         || GET_MODE_CLASS (mode) == MODE_INT
+         || GET_MODE_CLASS (mode) == MODE_FLOAT))
+    {
+      if (factor <= 1 && GET_CODE (x) == ZERO_EXTEND)
+       {
+         /* When accessing byte-sized values, the index can be
+            a zero-extended QImode or HImode register.  */
+         *size = GET_MODE_SIZE (GET_MODE (XEXP (x, 0)));
+         return XEXP (x, 0);
+       }
+      else
+       {
+         /* We're looking for addresses of the form:
+
+                (mult X I)
+             or (mult (zero_extend X) I)
+
+            where I is the size of the operand being accessed.
+            The canonical form of the second expression is:
+
+                (and (mult (subreg X) I) J)
+
+            where J == GET_MODE_MASK (GET_MODE (X)) * I.  */
+         rtx index;
+
+         if (GET_CODE (x) == AND
+             && GET_CODE (XEXP (x, 1)) == CONST_INT
+             && (factor == 0
+                 || INTVAL (XEXP (x, 1)) == 0xff * factor
+                 || INTVAL (XEXP (x, 1)) == 0xffff * factor))
+           {
+             index = XEXP (x, 0);
+             *size = (INTVAL (XEXP (x, 1)) >= 0xffff ? 2 : 1);
+           }
+         else
+           {
+             index = x;
+             *size = 4;
+           }
+
+         if (GET_CODE (index) == MULT
+             && GET_CODE (XEXP (index, 1)) == CONST_INT
+             && (factor == 0 || factor == INTVAL (XEXP (index, 1))))
+           return XEXP (index, 0);
+       }
+    }
+  *size = 0;
+  return x;
+}
+\f
+static const h8300_length_table addb_length_table =
+{
+  /* #xx  Rs   @aa  @Rs  @xx  */
+  {  2,   2,   4,   4,   4  }, /* add.b xx,Rd  */
+  {  4,   4,   4,   4,   6  }, /* add.b xx,@aa */
+  {  4,   4,   4,   4,   6  }, /* add.b xx,@Rd */
+  {  6,   4,   4,   4,   6  }  /* add.b xx,@xx */
+};
+
+static const h8300_length_table addw_length_table =
+{
+  /* #xx  Rs   @aa  @Rs  @xx  */
+  {  2,   2,   4,   4,   4  }, /* add.w xx,Rd  */
+  {  4,   4,   4,   4,   6  }, /* add.w xx,@aa */
+  {  4,   4,   4,   4,   6  }, /* add.w xx,@Rd */
+  {  4,   4,   4,   4,   6  }  /* add.w xx,@xx */
+};
+
+static const h8300_length_table addl_length_table =
+{
+  /* #xx  Rs   @aa  @Rs  @xx  */
+  {  2,   2,   4,   4,   4  }, /* add.l xx,Rd  */
+  {  4,   4,   6,   6,   6  }, /* add.l xx,@aa */
+  {  4,   4,   6,   6,   6  }, /* add.l xx,@Rd */
+  {  4,   4,   6,   6,   6  }  /* add.l xx,@xx */
+};
+
+#define logicb_length_table addb_length_table
+#define logicw_length_table addw_length_table
+
+static const h8300_length_table logicl_length_table =
+{
+  /* #xx  Rs   @aa  @Rs  @xx  */
+  {  2,   4,   4,   4,   4  }, /* and.l xx,Rd  */
+  {  4,   4,   6,   6,   6  }, /* and.l xx,@aa */
+  {  4,   4,   6,   6,   6  }, /* and.l xx,@Rd */
+  {  4,   4,   6,   6,   6  }  /* and.l xx,@xx */
+};
+
+static const h8300_length_table movb_length_table =
+{
+  /* #xx  Rs   @aa  @Rs  @xx  */
+  {  2,   2,   2,   2,   4  }, /* mov.b xx,Rd  */
+  {  4,   2,   4,   4,   4  }, /* mov.b xx,@aa */
+  {  4,   2,   4,   4,   4  }, /* mov.b xx,@Rd */
+  {  4,   4,   4,   4,   4  }  /* mov.b xx,@xx */
+};
+
+#define movw_length_table movb_length_table
+
+static const h8300_length_table movl_length_table =
+{
+  /* #xx  Rs   @aa  @Rs  @xx  */
+  {  2,   2,   4,   4,   4  }, /* mov.l xx,Rd  */
+  {  4,   4,   4,   4,   4  }, /* mov.l xx,@aa */
+  {  4,   4,   4,   4,   4  }, /* mov.l xx,@Rd */
+  {  4,   4,   4,   4,   4  }  /* mov.l xx,@xx */
+};
+
+/* Return the size of the given address or displacement constant.  */
+
+static unsigned int
+h8300_constant_length (rtx constant)
+{
+  /* Check for (@d:16,Reg).  */
+  if (GET_CODE (constant) == CONST_INT
+      && IN_RANGE (INTVAL (constant), -0x8000, 0x7fff))
+    return 2;
+
+  /* Check for (@d:16,Reg) in cases where the displacement is
+     an absolute address.  */
+  if (Pmode == HImode || h8300_tiny_constant_address_p (constant))
+    return 2;
+
+  return 4;
+}
+
+/* Return the size of a displacement field in address ADDR, which should
+   have the form (plus X constant).  SIZE is the number of bytes being
+   accessed.  */
+
+static unsigned int
+h8300_displacement_length (rtx addr, int size)
+{
+  rtx offset;
+
+  offset = XEXP (addr, 1);
+
+  /* Check for @(d:2,Reg).  */
+  if (register_operand (XEXP (addr, 0), VOIDmode)
+      && GET_CODE (offset) == CONST_INT
+      && (INTVAL (offset) == size
+         || INTVAL (offset) == size * 2
+         || INTVAL (offset) == size * 3))
+    return 0;
+
+  return h8300_constant_length (offset);
+}
+
+/* Store the class of operand OP in *CLASS and return the length of any
+   extra operand fields.  SIZE is the number of bytes in OP.  CLASS
+   can be null if only the length is needed.  */
+
+static unsigned int
+h8300_classify_operand (rtx op, int size, enum h8300_operand_class *class)
+{
+  enum h8300_operand_class dummy;
+
+  if (class == 0)
+    class = &dummy;
+
+  if (CONSTANT_P (op))
+    {
+      *class = H8OP_IMMEDIATE;
+
+      /* Byte-sized immediates are stored in the opcode fields.  */
+      if (size == 1)
+       return 0;
+
+      /* If this is a 32-bit instruction, see whether the constant
+        will fit into a 16-bit immediate field.  */
+      if (TARGET_H8300SX
+         && size == 4
+         && GET_CODE (op) == CONST_INT
+         && IN_RANGE (INTVAL (op), 0, 0xffff))
+       return 2;
+
+      return size;
+    }
+  else if (GET_CODE (op) == MEM)
+    {
+      op = XEXP (op, 0);
+      if (CONSTANT_P (op))
+       {
+         *class = H8OP_MEM_ABSOLUTE;
+         return h8300_constant_length (op);
+       }
+      else if (GET_CODE (op) == PLUS && CONSTANT_P (XEXP (op, 1)))
+       {
+         *class = H8OP_MEM_COMPLEX;
+         return h8300_displacement_length (op, size);
+       }
+      else if (GET_RTX_CLASS (GET_CODE (op)) == RTX_AUTOINC)
+       {
+         *class = H8OP_MEM_COMPLEX;
+         return 0;
+       }
+      else if (register_operand (op, VOIDmode))
+       {
+         *class = H8OP_MEM_BASE;
+         return 0;
+       }
+    }
+  else if (register_operand (op, VOIDmode))
+    {
+      *class = H8OP_REGISTER;
+      return 0;
+    }
+  abort ();
+}
+
+/* Return the length of the instruction described by TABLE given that
+   its operands are OP1 and OP2.  OP1 must be an h8300_dst_operand
+   and OP2 must be an h8300_src_operand.  */
+
+static unsigned int
+h8300_length_from_table (rtx op1, rtx op2, const h8300_length_table *table)
+{
+  enum h8300_operand_class op1_class, op2_class;
+  unsigned int size, immediate_length;
+
+  size = GET_MODE_SIZE (GET_MODE (op1));
+  immediate_length = (h8300_classify_operand (op1, size, &op1_class)
+                     + h8300_classify_operand (op2, size, &op2_class));
+  return immediate_length + (*table)[op1_class - 1][op2_class];
+}
+
+/* Return the length of a unary instruction such as neg or not given that
+   its operand is OP.  */
+
+unsigned int
+h8300_unary_length (rtx op)
+{
+  enum h8300_operand_class class;
+  unsigned int size, operand_length;
+
+  size = GET_MODE_SIZE (GET_MODE (op));
+  operand_length = h8300_classify_operand (op, size, &class);
+  switch (class)
+    {
+    case H8OP_REGISTER:
+      return 2;
+
+    case H8OP_MEM_BASE:
+      return (size == 4 ? 6 : 4);
+
+    case H8OP_MEM_ABSOLUTE:
+      return operand_length + (size == 4 ? 6 : 4);
+
+    case H8OP_MEM_COMPLEX:
+      return operand_length + 6;
+
+    default:
+      abort ();
+    }
+}
+
+/* Likewise short immediate instructions such as add.w #xx:3,OP.  */
+
+static unsigned int
+h8300_short_immediate_length (rtx op)
+{
+  enum h8300_operand_class class;
+  unsigned int size, operand_length;
+
+  size = GET_MODE_SIZE (GET_MODE (op));
+  operand_length = h8300_classify_operand (op, size, &class);
+
+  switch (class)
+    {
+    case H8OP_REGISTER:
+      return 2;
+
+    case H8OP_MEM_BASE:
+    case H8OP_MEM_ABSOLUTE:
+    case H8OP_MEM_COMPLEX:
+      return 4 + operand_length;
+
+    default:
+      abort ();
+    }
+}
+
+/* Likewise bitfield load and store instructions.  */
 
-    case CC_CLOBBER:
-      /* Insn doesn't leave CC in a usable state.  */
-      CC_STATUS_INIT;
-      break;
+static unsigned int
+h8300_bitfield_length (rtx op, rtx op2)
+{
+  enum h8300_operand_class class;
+  unsigned int size, operand_length;
+
+  if (GET_CODE (op) == REG)
+    op = op2;
+  if (GET_CODE (op) == REG)
+    abort ();
+  
+  size = GET_MODE_SIZE (GET_MODE (op));
+  operand_length = h8300_classify_operand (op, size, &class);
+
+  switch (class)
+    {
+    case H8OP_MEM_BASE:
+    case H8OP_MEM_ABSOLUTE:
+    case H8OP_MEM_COMPLEX:
+      return 4 + operand_length;
+
+    default:
+      abort ();
     }
 }
 
-/* Return nonzero if X is a stack pointer.  */
+/* Calculate the length of general binary instruction INSN using TABLE.  */
 
-int
-stack_pointer_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+static unsigned int
+h8300_binary_length (rtx insn, const h8300_length_table *table)
 {
-  return x == stack_pointer_rtx;
+  rtx set;
+
+  set = single_set (insn);
+  if (set == 0)
+    abort ();
+
+  if (BINARY_P (SET_SRC (set)))
+    return h8300_length_from_table (XEXP (SET_SRC (set), 0),
+                                   XEXP (SET_SRC (set), 1), table);
+  else if (GET_RTX_CLASS (GET_CODE (SET_SRC (set))) == RTX_TERNARY)
+    return h8300_length_from_table (XEXP (XEXP (SET_SRC (set), 1), 0),
+                                   XEXP (XEXP (SET_SRC (set), 1), 1),
+                                   table);
+  else
+    abort ();
 }
 
-/* Return nonzero if X is a constant whose absolute value is greater
-   than 2.  */
+/* Subroutine of h8300_move_length.  Return true if OP is 1- or 2-byte
+   memory reference and either (1) it has the form @(d:16,Rn) or
+   (2) its address has the code given by INC_CODE.  */
 
-int
-const_int_gt_2_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+static bool
+h8300_short_move_mem_p (rtx op, enum rtx_code inc_code)
 {
-  return (GET_CODE (x) == CONST_INT
-         && abs (INTVAL (x)) > 2);
+  rtx addr;
+  unsigned int size;
+
+  if (GET_CODE (op) != MEM)
+    return false;
+
+  addr = XEXP (op, 0);
+  size = GET_MODE_SIZE (GET_MODE (op));
+  if (size != 1 && size != 2)
+    return false;
+
+  return (GET_CODE (addr) == inc_code
+         || (GET_CODE (addr) == PLUS
+             && GET_CODE (XEXP (addr, 0)) == REG
+             && h8300_displacement_length (addr, size) == 2));
 }
 
-/* Return nonzero if X is a constant whose absolute value is no
-   smaller than 8.  */
+/* Calculate the length of move instruction INSN using the given length
+   table.  Although the tables are correct for most cases, there is some
+   irregularity in the length of mov.b and mov.w.  The following forms:
 
-int
-const_int_ge_8_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+       mov @ERs+, Rd
+       mov @(d:16,ERs), Rd
+       mov Rs, @-ERd
+       mov Rs, @(d:16,ERd)
+
+   are two bytes shorter than most other "mov Rs, @complex" or
+   "mov @complex,Rd" combinations.  */
+
+static unsigned int
+h8300_move_length (rtx *operands, const h8300_length_table *table)
 {
-  return (GET_CODE (x) == CONST_INT
-         && abs (INTVAL (x)) >= 8);
+  unsigned int size;
+
+  size = h8300_length_from_table (operands[0], operands[1], table);
+  if (REG_P (operands[0]) && h8300_short_move_mem_p (operands[1], POST_INC))
+    size -= 2;
+  if (REG_P (operands[1]) && h8300_short_move_mem_p (operands[0], PRE_DEC))
+    size -= 2;
+  return size;
 }
 
-/* Return nonzero if X is a constant expressible in QImode.  */
+/* Return the length of a mova instruction with the given operands.
+   DEST is the register destination, SRC is the source address and
+   OFFSET is the 16-bit or 32-bit displacement.  */
 
-int
-const_int_qi_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+static unsigned int
+h8300_mova_length (rtx dest, rtx src, rtx offset)
 {
-  return (GET_CODE (x) == CONST_INT
-         && (INTVAL (x) & 0xff) == INTVAL (x));
+  unsigned int size;
+
+  size = (2
+         + h8300_constant_length (offset)
+         + h8300_classify_operand (src, GET_MODE_SIZE (GET_MODE (src)), 0));
+  if (!REG_P (dest) || !REG_P (src) || REGNO (src) != REGNO (dest))
+    size += 2;
+  return size;
 }
 
-/* Return nonzero if X is a constant expressible in HImode.  */
+/* Compute the length of INSN based on its length_table attribute.
+   OPERANDS is the array of its operands.  */
 
-int
-const_int_hi_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+unsigned int
+h8300_insn_length_from_table (rtx insn, rtx * operands)
 {
-  return (GET_CODE (x) == CONST_INT
-         && (INTVAL (x) & 0xffff) == INTVAL (x));
+  switch (get_attr_length_table (insn))
+    {
+    case LENGTH_TABLE_NONE:
+      abort ();
+
+    case LENGTH_TABLE_ADDB:
+      return h8300_binary_length (insn, &addb_length_table);
+
+    case LENGTH_TABLE_ADDW:
+      return h8300_binary_length (insn, &addw_length_table);
+
+    case LENGTH_TABLE_ADDL:
+      return h8300_binary_length (insn, &addl_length_table);
+
+    case LENGTH_TABLE_LOGICB:
+      return h8300_binary_length (insn, &logicb_length_table);
+
+    case LENGTH_TABLE_MOVB:
+      return h8300_move_length (operands, &movb_length_table);
+
+    case LENGTH_TABLE_MOVW:
+      return h8300_move_length (operands, &movw_length_table);
+
+    case LENGTH_TABLE_MOVL:
+      return h8300_move_length (operands, &movl_length_table);
+
+    case LENGTH_TABLE_MOVA:
+      return h8300_mova_length (operands[0], operands[1], operands[2]);
+
+    case LENGTH_TABLE_MOVA_ZERO:
+      return h8300_mova_length (operands[0], operands[1], const0_rtx);
+
+    case LENGTH_TABLE_UNARY:
+      return h8300_unary_length (operands[0]);
+
+    case LENGTH_TABLE_MOV_IMM4:
+      return 2 + h8300_classify_operand (operands[0], 0, 0);
+
+    case LENGTH_TABLE_SHORT_IMMEDIATE:
+      return h8300_short_immediate_length (operands[0]);
+
+    case LENGTH_TABLE_BITFIELD:
+      return h8300_bitfield_length (operands[0], operands[1]);
+      
+    case LENGTH_TABLE_BITBRANCH:
+      return h8300_bitfield_length (operands[1], operands[2]) - 2;
+      
+    }
+  abort ();
 }
 
-/* Return nonzero if X is a constant suitable for inc/dec.  */
+/* Return true if LHS and RHS are memory references that can be mapped
+   to the same h8sx assembly operand.  LHS appears as the destination of
+   an instruction and RHS appears as a source.
 
-int
-incdec_operand (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+   Three cases are allowed:
+
+       - RHS is @+Rn or @-Rn, LHS is @Rn
+       - RHS is @Rn, LHS is @Rn+ or @Rn-
+       - RHS and LHS have the same address and neither has side effects.  */
+
+bool
+h8sx_mergeable_memrefs_p (rtx lhs, rtx rhs)
 {
-  return (GET_CODE (x) == CONST_INT
-         && (CONST_OK_FOR_M (INTVAL (x))
-             || CONST_OK_FOR_O (INTVAL (x))));
+  if (GET_CODE (rhs) == MEM && GET_CODE (lhs) == MEM)
+    {
+      rhs = XEXP (rhs, 0);
+      lhs = XEXP (lhs, 0);
+
+      if (GET_CODE (rhs) == PRE_INC || GET_CODE (rhs) == PRE_DEC)
+       return rtx_equal_p (XEXP (rhs, 0), lhs);
+
+      if (GET_CODE (lhs) == POST_INC || GET_CODE (lhs) == POST_DEC)
+       return rtx_equal_p (rhs, XEXP (lhs, 0));
+
+      if (rtx_equal_p (rhs, lhs))
+       return true;
+    }
+  return false;
 }
 
-/* Return nonzero if X is either EQ or NE.  */
+/* Return true if OPERANDS[1] can be mapped to the same assembly
+   operand as OPERANDS[0].  */
 
-int
-eqne_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+bool
+h8300_operands_match_p (rtx *operands)
 {
-  enum rtx_code code = GET_CODE (x);
+  if (register_operand (operands[0], VOIDmode)
+      && register_operand (operands[1], VOIDmode))
+    return true;
 
-  return (code == EQ || code == NE);
+  if (h8sx_mergeable_memrefs_p (operands[0], operands[1]))
+    return true;
+
+  return false;
 }
 
-/* Return nonzero if X is either GT or LE.  */
+/* Return true if OP is a binary operator in which it would be safe to
+   replace register operands with memory operands.  */
 
 int
-gtle_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+h8sx_binary_memory_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (x);
+  if (!TARGET_H8300SX)
+    return false;
 
-  return (code == GT || code == LE);
+  if (GET_MODE (op) != QImode
+      && GET_MODE (op) != HImode
+      && GET_MODE (op) != SImode)
+    return false;
+
+  switch (GET_CODE (op))
+    {
+    case PLUS:
+    case MINUS:
+    case AND:
+    case IOR:
+    case XOR:
+      return true;
+
+    default:
+      return h8sx_unary_shift_operator (op, mode);
+    }
 }
 
-/* Return nonzero if X is either GTU or LEU.  */
+/* Like h8sx_binary_memory_operator, but applies to unary operators.  */
 
 int
-gtuleu_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+h8sx_unary_memory_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
-  enum rtx_code code = GET_CODE (x);
+  if (!TARGET_H8300SX)
+    return false;
 
-  return (code == GTU || code == LEU);
+  if (GET_MODE (op) != QImode
+      && GET_MODE (op) != HImode
+      && GET_MODE (op) != SImode)
+    return false;
+
+  switch (GET_CODE (op))
+    {
+    case NEG:
+    case NOT:
+      return true;
+
+    default:
+      return false;
+    }
 }
+\f
+/* Try using movmd to move LENGTH bytes from memory region SRC to memory
+   region DEST.  The two regions do not overlap and have the common
+   alignment given by ALIGNMENT.  Return true on success.
 
-/* Return nonzero if X is either IOR or XOR.  */
+   Using movmd for variable-length moves seems to involve some
+   complex trade-offs.  For instance:
 
-int
-iorxor_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+      - Preparing for a movmd instruction is similar to preparing
+       for a memcpy.  The main difference is that the arguments
+       are moved into er4, er5 and er6 rather than er0, er1 and er2.
+
+      - Since movmd clobbers the frame pointer, we need to save
+       and restore it somehow when frame_pointer_needed.  This can
+       sometimes make movmd sequences longer than calls to memcpy().
+
+      - The counter register is 16 bits, so the instruction is only
+       suitable for variable-length moves when sizeof (size_t) == 2.
+       That's only true in normal mode.
+
+      - We will often lack static alignment information.  Falling back
+       on movmd.b would likely be slower than calling memcpy(), at least
+       for big moves.
+
+   This function therefore only uses movmd when the length is a
+   known constant, and only then if -fomit-frame-pointer is in
+   effect or if we're not optimizing for size.
+
+   At the moment the function uses movmd for all in-range constants,
+   but it might be better to fall back on memcpy() for large moves
+   if ALIGNMENT == 1.  */
+
+bool
+h8sx_emit_movmd (rtx dest, rtx src, rtx length,
+                HOST_WIDE_INT alignment)
 {
-  enum rtx_code code = GET_CODE (x);
+  if (!flag_omit_frame_pointer && optimize_size)
+    return false;
 
-  return (code == IOR || code == XOR);
+  if (GET_CODE (length) == CONST_INT)
+    {
+      rtx dest_reg, src_reg, first_dest, first_src;
+      HOST_WIDE_INT n;
+      int factor;
+
+      /* Use movmd.l if the alignment allows it, otherwise fall back
+        on movmd.b.  */
+      factor = (alignment >= 2 ? 4 : 1);
+
+      /* Make sure the length is within range.  We can handle counter
+        values up to 65536, although HImode truncation will make
+        the count appear negative in rtl dumps.  */
+      n = INTVAL (length);
+      if (n <= 0 || n / factor > 65536)
+       return false;
+
+      /* Create temporary registers for the source and destination
+        pointers.  Initialize them to the start of each region.  */
+      dest_reg = copy_addr_to_reg (XEXP (dest, 0));
+      src_reg = copy_addr_to_reg (XEXP (src, 0));
+
+      /* Create references to the movmd source and destination blocks.  */
+      first_dest = replace_equiv_address (dest, dest_reg);
+      first_src = replace_equiv_address (src, src_reg);
+
+      set_mem_size (first_dest, GEN_INT (n & -factor));
+      set_mem_size (first_src, GEN_INT (n & -factor));
+
+      length = copy_to_mode_reg (HImode, gen_int_mode (n / factor, HImode));
+      emit_insn (gen_movmd (first_dest, first_src, length, GEN_INT (factor)));
+
+      if ((n & -factor) != n)
+       {
+         /* Move SRC and DEST past the region we just copied.
+            This is done to update the memory attributes.  */
+         dest = adjust_address (dest, BLKmode, n & -factor);
+         src = adjust_address (src, BLKmode, n & -factor);
+
+         /* Replace the addresses with the source and destination
+            registers, which movmd has left with the right values.  */
+         dest = replace_equiv_address (dest, dest_reg);
+         src = replace_equiv_address (src, src_reg);
+
+         /* Mop up the left-over bytes.  */
+         if (n & 2)
+           emit_move_insn (adjust_address (dest, HImode, 0),
+                           adjust_address (src, HImode, 0));
+         if (n & 1)
+           emit_move_insn (adjust_address (dest, QImode, n & 2),
+                           adjust_address (src, QImode, n & 2));
+       }
+      return true;
+    }
+  return false;
 }
 
-/* Recognize valid operators for bit instructions.  */
+/* Move ADDR into er6 after pushing its old value onto the stack.  */
 
-int
-bit_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+void
+h8300_swap_into_er6 (rtx addr)
 {
-  enum rtx_code code = GET_CODE (x);
+  push (HARD_FRAME_POINTER_REGNUM);
+  emit_move_insn (hard_frame_pointer_rtx, addr);
+  if (REGNO (addr) == SP_REG)
+    emit_move_insn (hard_frame_pointer_rtx,
+                   plus_constant (hard_frame_pointer_rtx,
+                                  GET_MODE_SIZE (word_mode)));
+}
 
-  return (code == XOR
-         || code == AND
-         || code == IOR);
+/* Move the current value of er6 into ADDR and pop its old value
+   from the stack.  */
+
+void
+h8300_swap_out_of_er6 (rtx addr)
+{
+  if (REGNO (addr) != SP_REG)
+    emit_move_insn (addr, hard_frame_pointer_rtx);
+  pop (HARD_FRAME_POINTER_REGNUM);
 }
 \f
 /* Return the length of mov instruction.  */
@@ -2137,13 +3353,16 @@ output_plussi (rtx *operands)
     }
   else
     {
-      if (GET_CODE (operands[2]) == REG)
-       return "add.l\t%S2,%S0";
-
-      if (GET_CODE (operands[2]) == CONST_INT)
+      if (GET_CODE (operands[2]) == CONST_INT
+         && register_operand (operands[1], VOIDmode))
        {
          HOST_WIDE_INT intval = INTVAL (operands[2]);
 
+         if (TARGET_H8300SX && (intval >= 1 && intval <= 7))
+           return "add.l\t%S2,%S0";
+         if (TARGET_H8300SX && (intval >= -7 && intval <= -1))
+           return "sub.l\t%G2,%S0";
+
          /* See if we can finish with 2 bytes.  */
 
          switch ((unsigned int) intval & 0xffffffff)
@@ -2177,10 +3396,17 @@ output_plussi (rtx *operands)
            }
        }
 
+      if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
+       {
+         operands[2] = GEN_INT (-INTVAL (operands[2]));
+         return "sub.l\t%S2,%S0";
+       }
       return "add.l\t%S2,%S0";
     }
 }
 
+/* ??? It would be much easier to add the h8sx stuff if a single function
+   classified the addition as either inc/dec, adds/subs, add.w or add.l.  */
 /* Compute the length of an addition insn.  */
 
 unsigned int
@@ -2212,13 +3438,16 @@ compute_plussi_length (rtx *operands)
     }
   else
     {
-      if (GET_CODE (operands[2]) == REG)
-       return 2;
-
-      if (GET_CODE (operands[2]) == CONST_INT)
+      if (GET_CODE (operands[2]) == CONST_INT
+         && register_operand (operands[1], VOIDmode))
        {
          HOST_WIDE_INT intval = INTVAL (operands[2]);
 
+         if (TARGET_H8300SX && (intval >= 1 && intval <= 7))
+           return 2;
+         if (TARGET_H8300SX && (intval >= -7 && intval <= -1))
+           return 2;
+
          /* See if we can finish with 2 bytes.  */
 
          switch ((unsigned int) intval & 0xffffffff)
@@ -2247,6 +3476,13 @@ compute_plussi_length (rtx *operands)
            return 4;
        }
 
+      if (GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) < 0)
+       return h8300_length_from_table (operands[0],
+                                       GEN_INT (-INTVAL (operands[2])),
+                                       &addl_length_table);
+      else
+       return h8300_length_from_table (operands[0], operands[2],
+                                       &addl_length_table);
       return 6;
     }
 }
@@ -2267,13 +3503,16 @@ compute_plussi_cc (rtx *operands)
     }
   else
     {
-      if (GET_CODE (operands[2]) == REG)
-       return CC_SET_ZN;
-
-      if (GET_CODE (operands[2]) == CONST_INT)
+      if (GET_CODE (operands[2]) == CONST_INT
+         && register_operand (operands[1], VOIDmode))
        {
          HOST_WIDE_INT intval = INTVAL (operands[2]);
 
+         if (TARGET_H8300SX && (intval >= 1 && intval <= 7))
+           return CC_SET_ZN;
+         if (TARGET_H8300SX && (intval >= -7 && intval <= -1))
+           return CC_SET_ZN;
+
          /* See if we can finish with 2 bytes.  */
 
          switch ((unsigned int) intval & 0xffffffff)
@@ -2316,6 +3555,11 @@ output_logical_op (enum machine_mode mode, rtx *operands)
   /* Pretend that every byte is affected if both operands are registers.  */
   const unsigned HOST_WIDE_INT intval =
     (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT)
+                             /* Always use the full instruction if the
+                                first operand is in memory.  It is better
+                                to use define_splits to generate the shorter
+                                sequence where valid.  */
+                             && register_operand (operands[1], VOIDmode)
                              ? INTVAL (operands[2]) : 0x55555555);
   /* The determinant of the algorithm.  If we perform an AND, 0
      affects a bit.  Otherwise, 1 affects a bit.  */
@@ -2492,6 +3736,11 @@ compute_logical_op_length (enum machine_mode mode, rtx *operands)
   /* Pretend that every byte is affected if both operands are registers.  */
   const unsigned HOST_WIDE_INT intval =
     (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT)
+                             /* Always use the full instruction if the
+                                first operand is in memory.  It is better
+                                to use define_splits to generate the shorter
+                                sequence where valid.  */
+                             && register_operand (operands[1], VOIDmode)
                              ? INTVAL (operands[2]) : 0x55555555);
   /* The determinant of the algorithm.  If we perform an AND, 0
      affects a bit.  Otherwise, 1 affects a bit.  */
@@ -2516,10 +3765,8 @@ compute_logical_op_length (enum machine_mode mode, rtx *operands)
          && b0 != 0
          && b1 != 0)
        {
-         if (REG_P (operands[2]))
-           length += 2;
-         else
-           length += 4;
+         length = h8300_length_from_table (operands[1], operands[2],
+                                           &logicw_length_table);
        }
       else
        {
@@ -2555,10 +3802,8 @@ compute_logical_op_length (enum machine_mode mode, rtx *operands)
          && !(code == IOR && w1 == 0xffff
               && (w0 & 0x8000) != 0 && lower_half_easy_p))
        {
-         if (REG_P (operands[2]))
-           length += 4;
-         else
-           length += 6;
+         length = h8300_length_from_table (operands[1], operands[2],
+                                           &logicl_length_table);
        }
       else
        {
@@ -2637,6 +3882,11 @@ compute_logical_op_cc (enum machine_mode mode, rtx *operands)
   /* Pretend that every byte is affected if both operands are registers.  */
   const unsigned HOST_WIDE_INT intval =
     (unsigned HOST_WIDE_INT) ((GET_CODE (operands[2]) == CONST_INT)
+                             /* Always use the full instruction if the
+                                first operand is in memory.  It is better
+                                to use define_splits to generate the shorter
+                                sequence where valid.  */
+                             && register_operand (operands[1], VOIDmode)
                              ? INTVAL (operands[2]) : 0x55555555);
   /* The determinant of the algorithm.  If we perform an AND, 0
      affects a bit.  Otherwise, 1 affects a bit.  */
@@ -2754,6 +4004,117 @@ h8300_expand_branch (enum rtx_code code, rtx label)
    For the details of the shift algorithms for various shift counts,
    refer to shift_alg_[qhs]i.  */
 
+/* Classify a shift with the given mode and code.  OP is the shift amount.  */
+
+enum h8sx_shift_type
+h8sx_classify_shift (enum machine_mode mode, enum rtx_code code, rtx op)
+{
+  if (!TARGET_H8300SX)
+    return H8SX_SHIFT_NONE;
+
+  switch (code)
+    {
+    case ASHIFT:
+    case LSHIFTRT:
+      /* Check for variable shifts (shll Rs,Rd and shlr Rs,Rd).  */
+      if (GET_CODE (op) != CONST_INT)
+       return H8SX_SHIFT_BINARY;
+
+      /* Reject out-of-range shift amounts.  */
+      if (INTVAL (op) <= 0 || INTVAL (op) >= GET_MODE_BITSIZE (mode))
+       return H8SX_SHIFT_NONE;
+
+      /* Power-of-2 shifts are effectively unary operations.  */
+      if (exact_log2 (INTVAL (op)) >= 0)
+       return H8SX_SHIFT_UNARY;
+
+      return H8SX_SHIFT_BINARY;
+
+    case ASHIFTRT:
+      if (op == const1_rtx || op == const2_rtx)
+       return H8SX_SHIFT_UNARY;
+      return H8SX_SHIFT_NONE;
+
+    case ROTATE:
+      if (GET_CODE (op) == CONST_INT
+         && (INTVAL (op) == 1
+             || INTVAL (op) == 2
+             || INTVAL (op) == GET_MODE_BITSIZE (mode) - 2
+             || INTVAL (op) == GET_MODE_BITSIZE (mode) - 1))
+       return H8SX_SHIFT_UNARY;
+      return H8SX_SHIFT_NONE;
+
+    default:
+      return H8SX_SHIFT_NONE;
+    }
+}
+
+/* Return true if X is a shift operation of type H8SX_SHIFT_UNARY.  */
+
+int
+h8sx_unary_shift_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (BINARY_P (x) && NON_COMMUTATIVE_P (x)
+         && (h8sx_classify_shift (GET_MODE (x), GET_CODE (x), XEXP (x, 1))
+             == H8SX_SHIFT_UNARY));
+}
+
+/* Likewise H8SX_SHIFT_BINARY.  */
+
+int
+h8sx_binary_shift_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+  return (BINARY_P (x) && NON_COMMUTATIVE_P (x)
+         && (h8sx_classify_shift (GET_MODE (x), GET_CODE (x), XEXP (x, 1))
+             == H8SX_SHIFT_BINARY));
+}
+
+/* Return the asm template for a single h8sx shift instruction.
+   OPERANDS[0] and OPERANDS[1] are the destination, OPERANDS[2]
+   is the source and OPERANDS[3] is the shift.  SUFFIX is the
+   size suffix ('b', 'w' or 'l') and OPTYPE is the print_operand
+   prefix for the destination operand.  */
+
+const char *
+output_h8sx_shift (rtx *operands, int suffix, int optype)
+{
+  static char buffer[16];
+  const char *stem;
+
+  switch (GET_CODE (operands[3]))
+    {
+    case ASHIFT:
+      stem = "shll";
+      break;
+
+    case ASHIFTRT:
+      stem = "shar";
+      break;
+
+    case LSHIFTRT:
+      stem = "shlr";
+      break;
+
+    case ROTATE:
+      stem = "rotl";
+      if (INTVAL (operands[2]) > 2)
+       {
+         /* This is really a right rotate.  */
+         operands[2] = GEN_INT (GET_MODE_BITSIZE (GET_MODE (operands[0]))
+                                - INTVAL (operands[2]));
+         stem = "rotr";
+       }
+      break;
+
+    default:
+      abort ();
+    }
+  if (operands[2] == const1_rtx)
+    sprintf (buffer, "%s.%c\t%%%c0", stem, suffix, optype);
+  else
+    sprintf (buffer, "%s.%c\t%%X2,%%%c0", stem, suffix, optype);
+  return buffer;
+}
 int
 nshift_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
@@ -2771,9 +4132,22 @@ nshift_operator (rtx x, enum machine_mode mode ATTRIBUTE_UNUSED)
 
 /* Emit code to do shifts.  */
 
-void
+bool
 expand_a_shift (enum machine_mode mode, int code, rtx operands[])
 {
+  switch (h8sx_classify_shift (mode, code, operands[2]))
+    {
+    case H8SX_SHIFT_BINARY:
+      operands[1] = force_reg (mode, operands[1]);
+      return false;
+
+    case H8SX_SHIFT_UNARY:
+      return false;
+
+    case H8SX_SHIFT_NONE:
+      break;
+    }
+
   emit_move_insn (operands[0], operands[1]);
 
   /* Need a loop to get all the bits we want  - we generate the
@@ -2787,6 +4161,7 @@ expand_a_shift (enum machine_mode mode, int code, rtx operands[])
                                                      operands[0], operands[2])),
                         gen_rtx_CLOBBER (VOIDmode,
                                          gen_rtx_SCRATCH (QImode)))));
+  return true;
 }
 
 /* Symbols of the various modes which can be used as indices.  */
@@ -3911,6 +5286,9 @@ expand_a_rotate (rtx operands[])
   rtx rotate_amount = operands[2];
   enum machine_mode mode = GET_MODE (dst);
 
+  if (h8sx_classify_shift (mode, ROTATE, rotate_amount) == H8SX_SHIFT_UNARY)
+    return false;
+
   /* We rotate in place.  */
   emit_move_insn (dst, src);
 
@@ -4155,7 +5533,7 @@ fix_bit_operand (rtx *operands, enum rtx_code code)
     {
       /* OK to have a memory dest.  */
       if (GET_CODE (operands[0]) == MEM
-         && !EXTRA_CONSTRAINT (operands[0], 'U'))
+         && !OK_FOR_U (operands[0]))
        {
          rtx mem = gen_rtx_MEM (GET_MODE (operands[0]),
                                 copy_to_mode_reg (Pmode,
@@ -4165,7 +5543,7 @@ fix_bit_operand (rtx *operands, enum rtx_code code)
        }
 
       if (GET_CODE (operands[1]) == MEM
-         && !EXTRA_CONSTRAINT (operands[1], 'U'))
+         && !OK_FOR_U (operands[1]))
        {
          rtx mem = gen_rtx_MEM (GET_MODE (operands[1]),
                                 copy_to_mode_reg (Pmode,
@@ -4498,6 +5876,17 @@ output_simode_bld (int bild, rtx operands[])
   return "";
 }
 
+/* Delayed-branch scheduling is more effective if we have some idea
+   how long each instruction will be.  Use a shorten_branches pass
+   to get an initial estimate.  */
+
+static void
+h8300_reorg (void)
+{
+  if (flag_delayed_branch)
+    shorten_branches (get_insns ());
+}
+
 #ifndef OBJECT_FORMAT_ELF
 static void
 h8300_asm_named_section (const char *name, unsigned int flags ATTRIBUTE_UNUSED)
@@ -4746,7 +6135,7 @@ h8300_rtx_ok_for_base_p (rtx x, int strict)
    CONSTANT_ADDRESS.  */
 
 int
-h8300_legitimate_address_p (rtx x, int strict)
+h8300_legitimate_address_p (enum machine_mode mode, rtx x, int strict)
 {
   /* The register indirect addresses like @er0 is always valid.  */
   if (h8300_rtx_ok_for_base_p (x, strict))
@@ -4755,9 +6144,18 @@ h8300_legitimate_address_p (rtx x, int strict)
   if (CONSTANT_ADDRESS_P (x))
     return 1;
 
+  if (TARGET_H8300SX
+      && (   GET_CODE (x) == PRE_INC
+         || GET_CODE (x) == PRE_DEC
+         || GET_CODE (x) == POST_INC
+         || GET_CODE (x) == POST_DEC)
+      && h8300_rtx_ok_for_base_p (XEXP (x, 0), strict))
+    return 1;
+
   if (GET_CODE (x) == PLUS
       && CONSTANT_ADDRESS_P (XEXP (x, 1))
-      && h8300_rtx_ok_for_base_p (XEXP (x, 0), strict))
+      && h8300_rtx_ok_for_base_p (h8300_get_index (XEXP (x, 0),
+                                                  mode, 0), strict))
     return 1;
 
   return 0;
@@ -4839,4 +6237,7 @@ h8300_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
 #undef TARGET_RETURN_IN_MEMORY
 #define TARGET_RETURN_IN_MEMORY h8300_return_in_memory
 
+#undef  TARGET_MACHINE_DEPENDENT_REORG
+#define TARGET_MACHINE_DEPENDENT_REORG h8300_reorg
+
 struct gcc_target targetm = TARGET_INITIALIZER;
index fcb082372a125a86dc6f8964e4208e23e90e8964..d7b73e8f3a0b0ed6898a747139ba0462fb4792b5 100644 (file)
@@ -51,6 +51,14 @@ extern const char * const *h8_reg_names;
              builtin_define ("__NORMAL_MODE__");       \
            }                                           \
        }                                               \
+      else if (TARGET_H8300SX)                         \
+       {                                               \
+         builtin_define ("__H8300SX__");               \
+         if (TARGET_NORMAL_MODE)                       \
+           {                                           \
+             builtin_define ("__NORMAL_MODE__");       \
+           }                                           \
+       }                                               \
       else if (TARGET_H8300S)                          \
        {                                               \
          builtin_define ("__H8300S__");                \
@@ -103,6 +111,7 @@ extern int target_flags;
 #define MASK_RELAX             0x00000400
 #define MASK_H8300H            0x00001000
 #define MASK_ALIGN_300         0x00002000
+#define MASK_H8300SX           0x00004000
 
 /* Macros used in the machine description to test the flags.  */
 
@@ -122,7 +131,12 @@ extern int target_flags;
 /* Select between the H8/300 and H8/300H CPUs.  */
 #define TARGET_H8300   (! TARGET_H8300H && ! TARGET_H8300S)
 #define TARGET_H8300H  (target_flags & MASK_H8300H)
-#define TARGET_H8300S  (target_flags & MASK_H8300S)
+#define TARGET_H8300S  (target_flags & (MASK_H8300S | MASK_H8300SX))
+#define TARGET_H8300SX (target_flags & MASK_H8300SX)
+/* Some multiply instructions are not available in all H8SX variants.
+   Use this macro instead of TARGET_H8300SX to indicate this, even
+   though we don't actually generate different code for now.  */
+#define TARGET_H8300SXMUL TARGET_H8300SX
 #define TARGET_NORMAL_MODE (target_flags & MASK_NORMAL_MODE)
 
 /* mac register and relevant instructions are available.  */
@@ -144,6 +158,8 @@ extern int target_flags;
 #define TARGET_SWITCHES                                                            \
 { {"s",                         MASK_H8300S, N_("Generate H8S code")},             \
   {"no-s",             -MASK_H8300S, N_("Do not generate H8S code")},      \
+  {"sx",                MASK_H8300SX, N_("Generate H8SX code")},           \
+  {"no-sx",            -MASK_H8300SX, N_("Do not generate H8SX code")},    \
   {"s2600",             MASK_MAC, N_("Generate H8S/2600 code")},           \
   {"no-s2600",         -MASK_MAC, N_("Do not generate H8S/2600 code")},    \
   {"int32",             MASK_INT32, N_("Make integers 32 bits wide")},     \
@@ -398,7 +414,8 @@ extern int target_flags;
    class that represents their union.  */
 
 enum reg_class {
-  NO_REGS, GENERAL_REGS, MAC_REGS, ALL_REGS, LIM_REG_CLASSES
+  NO_REGS, COUNTER_REGS, SOURCE_REGS, DESTINATION_REGS,
+  GENERAL_REGS, MAC_REGS, ALL_REGS, LIM_REG_CLASSES
 };
 
 #define N_REG_CLASSES ((int) LIM_REG_CLASSES)
@@ -406,7 +423,8 @@ enum reg_class {
 /* Give names of register classes as strings for dump file.  */
 
 #define REG_CLASS_NAMES \
-{ "NO_REGS", "GENERAL_REGS", "MAC_REGS", "ALL_REGS", "LIM_REGS" }
+{ "NO_REGS", "COUNTER_REGS", "SOURCE_REGS", "DESTINATION_REGS", \
+  "GENERAL_REGS", "MAC_REGS", "ALL_REGS", "LIM_REGS" }
 
 /* Define which registers fit in which classes.
    This is an initializer for a vector of HARD_REG_SET
@@ -414,8 +432,11 @@ enum reg_class {
 
 #define REG_CLASS_CONTENTS                     \
 {      {0},            /* No regs      */      \
+   {0x010},            /* COUNTER_REGS */      \
+   {0x020},            /* SOURCE_REGS */       \
+   {0x040},            /* DESTINATION_REGS */  \
    {0xeff},            /* GENERAL_REGS */      \
-   {0x100},            /* MAC_REGS */  \
+   {0x100},            /* MAC_REGS */          \
    {0xfff},            /* ALL_REGS     */      \
 }
 
@@ -424,18 +445,23 @@ enum reg_class {
    reg number REGNO.  This could be a conditional expression
    or could index an array.  */
 
-#define REGNO_REG_CLASS(REGNO) (REGNO != MAC_REG ? GENERAL_REGS : MAC_REGS)
+#define REGNO_REG_CLASS(REGNO)                         \
+  ((REGNO) == MAC_REG ? MAC_REGS                       \
+   : (REGNO) == COUNTER_REG ? COUNTER_REGS             \
+   : (REGNO) == SOURCE_REG ? SOURCE_REGS               \
+   : (REGNO) == DESTINATION_REG ? DESTINATION_REGS     \
+   : GENERAL_REGS)
 
 /* The class value for index registers, and the one for base regs.  */
 
-#define INDEX_REG_CLASS NO_REGS
+#define INDEX_REG_CLASS (TARGET_H8300SX ? GENERAL_REGS : NO_REGS)
 #define BASE_REG_CLASS  GENERAL_REGS
 
 /* Get reg_class from a letter such as appears in the machine description.
 
    'a' is the MAC register.  */
 
-#define REG_CLASS_FROM_LETTER(C) ((C) == 'a' ? MAC_REGS : NO_REGS)
+#define REG_CLASS_FROM_LETTER(C) (h8300_reg_class_from_letter (C))
 
 /* The letters I, J, K, L, M, N, O, P in a register constraint string
    can be used to stand for particular ranges of immediate operands.
@@ -458,6 +484,31 @@ enum reg_class {
 #define CONST_OK_FOR_O(VALUE)                          \
   ((VALUE) == -1 || (VALUE) == -2)
 
+/* Multi-letter constraints for constant are always started with P
+   (just because it was the only letter in the range left.  New
+   constraints for constants should be added here.  */
+#define CONST_OK_FOR_Ppositive(VALUE, NBITS)           \
+  ((VALUE) > 0 && (VALUE) < (1 << (NBITS)))
+#define CONST_OK_FOR_Pnegative(VALUE, NBITS)           \
+  ((VALUE) < 0 && (VALUE) > -(1 << (NBITS)))
+#define CONST_OK_FOR_P(VALUE, STR) \
+  ((STR)[1] >= '1' && (STR)[1] <= '9' && (STR)[2] == '<'       \
+   ? (((STR)[3] == '0' || ((STR)[3] == 'X' && TARGET_H8300SX)) \
+      && CONST_OK_FOR_Pnegative ((VALUE), (STR)[1] - '0'))     \
+   : ((STR)[1] >= '1' && (STR)[1] <= '9' && (STR)[2] == '>')   \
+   ? (((STR)[3] == '0' || ((STR)[3] == 'X' && TARGET_H8300SX)) \
+      && CONST_OK_FOR_Ppositive ((VALUE), (STR)[1] - '0'))     \
+   : 0)
+#define CONSTRAINT_LEN_FOR_P(STR) \
+  ((((STR)[1] >= '1' && (STR)[1] <= '9')                       \
+    && ((STR)[2] == '<' || (STR)[2] == '>')                    \
+    && ((STR)[3] == 'X' || (STR)[3] == '0')) ? 4               \
+   : 0)
+
+#define CONST_OK_FOR_CONSTRAINT_P(VALUE, C, STR)       \
+  ((C) == 'P' ? CONST_OK_FOR_P ((VALUE), (STR))                \
+   : CONST_OK_FOR_LETTER_P ((VALUE), (C)))
+  
 #define CONST_OK_FOR_LETTER_P(VALUE, C)                \
   ((C) == 'I' ? CONST_OK_FOR_I (VALUE) :       \
    (C) == 'J' ? CONST_OK_FOR_J (VALUE) :       \
@@ -753,6 +804,8 @@ struct cum_arg
 
 #define HAVE_POST_INCREMENT 1
 #define HAVE_PRE_DECREMENT 1
+#define HAVE_POST_DECREMENT TARGET_H8300SX
+#define HAVE_PRE_INCREMENT TARGET_H8300SX
 
 /* Macros to check register numbers against specific register classes.  */
 
@@ -824,6 +877,9 @@ struct cum_arg
 
 /* Extra constraints.  */
 
+#define OK_FOR_Q(OP)                                   \
+  (TARGET_H8300SX && memory_operand ((OP), VOIDmode))
+
 #define OK_FOR_R(OP)                                   \
   (GET_CODE (OP) == CONST_INT                          \
    ? !h8300_shift_needs_scratch_p (INTVAL (OP), QImode)        \
@@ -861,18 +917,79 @@ struct cum_arg
    || (GET_CODE (OP) == MEM && TARGET_H8300S                           \
        && GET_CODE (XEXP (OP, 0)) == CONST_INT))
 
-#define EXTRA_CONSTRAINT(OP, C)                        \
-  ((C) == 'R' ? OK_FOR_R (OP) :                        \
+/* Multi-letter constraints starting with W are to be used for
+   operands that require a memory operand, i.e,. that are never used
+   along with register constraints (see EXTRA_MEMORY_CONSTRAINTS).
+   For operands that require a memory operand (or not) but that always
+   accept a register, a multi-letter constraint starting with Y should
+   be used instead.  */
+
+#define OK_FOR_WU(OP)                                  \
+  (GET_CODE (OP) == MEM && OK_FOR_U (OP))
+
+#define OK_FOR_W(OP, STR)                              \
+  ((STR)[1] == 'U' ? OK_FOR_WU (OP)                    \
+   : 0)
+
+#define CONSTRAINT_LEN_FOR_W(STR)                      \
+  ((STR)[1] == 'U' ? 2                                 \
+   : 0)
+
+/* We don't have any constraint starting with Y yet, but before
+   someone uses it for a one-letter constraint and we're left without
+   any upper-case constraints left, we reserve it for extensions
+   here.  */
+#define OK_FOR_Y(OP, STR)                              \
+  (0)
+
+#define CONSTRAINT_LEN_FOR_Y(STR)                      \
+  (0)
+
+#define OK_FOR_Z(OP)                                   \
+  (TARGET_H8300SX                                      \
+   && GET_CODE (OP) == MEM                             \
+   && CONSTANT_P (XEXP ((OP), 0)))
+
+#define EXTRA_CONSTRAINT_STR(OP, C, STR)       \
+  ((C) == 'Q' ? OK_FOR_Q (OP) :                        \
+   (C) == 'R' ? OK_FOR_R (OP) :                        \
    (C) == 'S' ? OK_FOR_S (OP) :                        \
    (C) == 'T' ? OK_FOR_T (OP) :                        \
    (C) == 'U' ? OK_FOR_U (OP) :                        \
+   (C) == 'W' ? OK_FOR_W ((OP), (STR)) :       \
+   (C) == 'Y' ? OK_FOR_Y ((OP), (STR)) :       \
+   (C) == 'Z' ? OK_FOR_Z (OP) :                        \
    0)
+
+#define CONSTRAINT_LEN(C, STR) \
+  ((C) == 'P' ? CONSTRAINT_LEN_FOR_P (STR)     \
+   : (C) == 'W' ? CONSTRAINT_LEN_FOR_W (STR)   \
+   : (C) == 'Y' ? CONSTRAINT_LEN_FOR_Y (STR)   \
+   : DEFAULT_CONSTRAINT_LEN ((C), (STR)))
+
+/* Experiments suggest that it's better not add 'Q' or 'U' here.  No
+   patterns need it for correctness (no patterns use 'Q' and 'U'
+   without also providing a register alternative).  And defining it
+   will mean that a spilled pseudo could be replaced by its frame
+   location in several consecutive insns.
+
+   Instead, it seems to be better to force pseudos to be reloaded
+   into registers and then use peepholes to recombine insns when
+   beneficial.
+
+   Unfortunately, for WU (unlike plain U, that matches regs as well),
+   we must require a memory address.  In fact, all multi-letter
+   constraints started with W are supposed to have this property, so
+   we just test for W here.  */
+#define EXTRA_MEMORY_CONSTRAINT(C, STR) \
+  ((C) == 'W')
+
 \f
 #ifndef REG_OK_STRICT
 #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)        \
   do                                           \
     {                                          \
-      if (h8300_legitimate_address_p ((X), 0)) \
+      if (h8300_legitimate_address_p ((MODE), (X), 0)) \
        goto ADDR;                              \
     }                                          \
   while (0)
@@ -880,7 +997,7 @@ struct cum_arg
 #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, ADDR)        \
   do                                           \
     {                                          \
-      if (h8300_legitimate_address_p ((X), 1)) \
+      if (h8300_legitimate_address_p ((MODE), (X), 1)) \
        goto ADDR;                              \
     }                                          \
   while (0)
@@ -893,7 +1010,14 @@ struct cum_arg
    (the amount of decrement or increment being the length of the operand).  */
 
 #define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \
-  if (GET_CODE (ADDR) == POST_INC || GET_CODE (ADDR) == PRE_DEC) goto LABEL;
+  if (GET_CODE (ADDR) == POST_INC \
+      || GET_CODE (ADDR) == POST_DEC \
+      || GET_CODE (ADDR) == PRE_INC \
+      || GET_CODE (ADDR) == PRE_DEC) \
+    goto LABEL; \
+  if (GET_CODE (ADDR) == PLUS \
+      && h8300_get_index (XEXP (ADDR, 0), VOIDmode, 0) != XEXP (ADDR, 0)) \
+    goto LABEL;
 \f
 /* Specify the machine mode that this machine uses
    for the index in the tablejump instruction.  */
@@ -936,9 +1060,9 @@ struct cum_arg
    We use longs for the H8/300H and the H8S because ints can be 16 or 32.
    GCC requires SIZE_TYPE to be the same size as pointers.  */
 #define SIZE_TYPE                                                              \
-  (TARGET_H8300 || TARGET_NORMAL_MODE ? "unsigned int" : "long unsigned int")
+  (TARGET_H8300 || TARGET_NORMAL_MODE ? TARGET_INT32 ? "short unsigned int" : "unsigned int" : "long unsigned int")
 #define PTRDIFF_TYPE                                           \
-  (TARGET_H8300 || TARGET_NORMAL_MODE ? "int" : "long int")
+  (TARGET_H8300 || TARGET_NORMAL_MODE ? TARGET_INT32 ? "short int" : "int" : "long int")
 
 #define POINTER_SIZE                                                   \
   ((TARGET_H8300H || TARGET_H8300S) && !TARGET_NORMAL_MODE ? 32 : 16)
@@ -951,6 +1075,12 @@ struct cum_arg
    so give the MEM rtx a byte's mode.  */
 #define FUNCTION_MODE QImode
 
+/* Return the length of JUMP's delay slot insn (0 if it has none).
+   If JUMP is a delayed branch, NEXT_INSN (PREV_INSN (JUMP)) will
+   be the containing SEQUENCE, not JUMP itself.  */
+#define DELAY_SLOT_LENGTH(JUMP) \
+  (NEXT_INSN (PREV_INSN (JUMP)) == JUMP ? 0 : 2)
+
 #define BRANCH_COST 0
 
 /* Tell final.c how to eliminate redundant test instructions.  */
@@ -1139,14 +1269,29 @@ struct cum_arg
   final_prescan_insn (insn, operand, nop)
 
 #define MOVE_RATIO 3
+extern int h8300_move_ratio;
+#undef  MOVE_RATIO
+#define MOVE_RATIO h8300_move_ratio
 
 /* Define the codes that are matched by predicates in h8300.c.  */
 
 #define PREDICATE_CODES                                                        \
   {"general_operand_src", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
                           LABEL_REF, SUBREG, REG, MEM}},               \
-  {"general_operand_dst", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, \
-                          LABEL_REF, SUBREG, REG, MEM}},               \
+  {"general_operand_dst", {SUBREG, REG, MEM}},                         \
+  {"h8300_src_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,   \
+                        LABEL_REF, SUBREG, REG, MEM}},                 \
+  {"h8300_dst_operand", {SUBREG, REG, MEM}},                           \
+  {"nibble_operand", {CONST_INT}},                                     \
+  {"reg_or_nibble_operand", {CONST_INT, SUBREG, REG}},                 \
+  {"h8sx_unary_shift_operator", {ASHIFTRT, LSHIFTRT, ASHIFT, ROTATE}}, \
+  {"h8sx_binary_shift_operator", {ASHIFTRT, LSHIFTRT, ASHIFT}},                \
+  {"h8sx_binary_memory_operator", {PLUS, MINUS, AND, IOR, XOR, ASHIFT, \
+                                  ASHIFTRT, LSHIFTRT, ROTATE}},        \
+  {"h8sx_unary_memory_operator", {NEG, NOT}},                          \
+  {"h8300_ldm_parallel", {PARALLEL}},                                  \
+  {"h8300_stm_parallel", {PARALLEL}},                                  \
+  {"h8300_return_parallel", {PARALLEL}},                               \
   {"single_one_operand", {CONST_INT}},                                 \
   {"single_zero_operand", {CONST_INT}},                                        \
   {"call_insn_operand", {MEM}},                                                \
index 91f7922db00ce19333e9aaea1eafe12772e9573e..e718a82e40b5884d361a1c58608581fbc3c3cc3e 100644 (file)
   [(UNSPEC_INCDEC      0)
    (UNSPEC_MONITOR     1)])
 
+(define_constants
+  [(UNSPEC_MOVMD       100)
+   (UNSPEC_STPCPY      101)])
+
 (define_constants
   [(R0_REG      0)
    (SC_REG      3)
+   (COUNTER_REG  4)
+   (SOURCE_REG   5)
+   (DESTINATION_REG 6)
    (HFP_REG     6)
    (SP_REG      7)
    (MAC_REG     8)
 (define_attr "cpu" "h8300,h8300h"
   (const (symbol_ref "cpu_type")))
 
-(define_attr "type" "branch,arith"
+(define_attr "type" "branch,arith,bitbranch,call"
   (const_string "arith"))
 
+(define_attr "length_table" "none,addb,addw,addl,logicb,movb,movw,movl,mova_zero,mova,unary,mov_imm4,short_immediate,bitfield,bitbranch"
+  (const_string "none"))
+
 ;; The size of instructions in bytes.
 
 (define_attr "length" ""
   (cond [(eq_attr "type" "branch")
+        ;; In a forward delayed branch, (pc) represents the end of the
+        ;; delay sequence, not the end of the branch itself.
         (if_then_else (and (ge (minus (match_dup 0) (pc))
                                (const_int -126))
-                           (le (minus (match_dup 0) (pc))
+                           (le (plus (minus (match_dup 0) (pc))
+                                     (symbol_ref "DELAY_SLOT_LENGTH (insn)"))
                                (const_int 126)))
                       (const_int 2)
                       (if_then_else (and (eq_attr "cpu" "h8300h")
                                               (le (minus (pc) (match_dup 0))
                                                   (const_int 32000))))
                                     (const_int 4)
-                                    (const_int 6)))]
+                                    (const_int 6)))
+        (eq_attr "type" "bitbranch")
+        (if_then_else
+         (and (ge (minus (match_dup 0) (pc))
+                  (const_int -126))
+              (le (minus (match_dup 0) (pc))
+                  (const_int 126)))
+         (plus
+          (symbol_ref "h8300_insn_length_from_table (insn, operands)")
+          (const_int 2))
+         (if_then_else
+          (and (eq_attr "cpu" "h8300h")
+               (and (ge (minus (pc) (match_dup 0))
+                        (const_int -32000))
+                    (le (minus (pc) (match_dup 0))
+                        (const_int 32000))))
+          (plus
+           (symbol_ref "h8300_insn_length_from_table (insn, operands)")
+           (const_int 4))
+          (plus
+           (symbol_ref "h8300_insn_length_from_table (insn, operands)")
+           (const_int 6))))
+        (eq_attr "length_table" "!none")
+        (symbol_ref "h8300_insn_length_from_table (insn, operands)")]
        (const_int 200)))
 
 ;; Condition code settings.
 (define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber"
   (const_string "clobber"))
 
+;; Type of delay slot.  NONE means the instruction has no delay slot.
+;; JUMP means it is an unconditional jump that (if short enough)
+;; could be implemented using bra/s.
+(define_attr "delay_slot" "none,jump"
+  (const_string "none"))
+
+;; "yes" if the instruction can be put into a delay slot.  It's not
+;; entirely clear that jsr is not valid in delay slots, but it
+;; definitely doesn't have the effect of causing the called function
+;; to return to the target of the delayed branch.
+(define_attr "can_delay" "no,yes"
+  (cond [(eq_attr "type" "branch,bitbranch,call")
+          (const_string "no")
+        (ne (symbol_ref "get_attr_length (insn)") (const_int 2))
+          (const_string "no")]
+       (const_string "yes")))
+
+;; Only allow jumps to have a delay slot if we think they might
+;; be short enough.  This is just an optimisation: we don't know
+;; for certain whether they will be or not.
+(define_delay (and (eq_attr "delay_slot" "jump")
+                  (eq (symbol_ref "get_attr_length (insn)") (const_int 2)))
+  [(eq_attr "can_delay" "yes")
+   (nil)
+   (nil)])
+
 ;; Provide the maximum length of an assembly instruction in an asm
 ;; statement.  The maximum length of 14 bytes is achieved on H8SX.
 
 (define_insn "*movqi_h8300hs"
   [(set (match_operand:QI 0 "general_operand_dst" "=r,r ,<,r,r,m")
        (match_operand:QI 1 "general_operand_src" " I,r>,r,n,m,r"))]
-  "(TARGET_H8300H || TARGET_H8300S)
+  "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX
    && (register_operand (operands[0], QImode)
        || register_operand (operands[1], QImode))"
   "@
        (symbol_ref "compute_mov_length (operands)"))
    (set_attr "cc" "set_zn,set_znv,set_znv,clobber,set_znv,set_znv")])
 
+(define_insn "*movqi_h8sx"
+  [(set (match_operand:QI 0 "general_operand_dst" "=Z,rQ")
+       (match_operand:QI 1 "general_operand_src" "P4>X,rQi"))]
+  "TARGET_H8300SX"
+  "@
+    mov.b      %X1,%X0
+    mov.b      %X1,%X0"
+  [(set_attr "length_table" "mov_imm4,movb")
+   (set_attr "cc" "set_znv")])
+
 (define_expand "movqi"
   [(set (match_operand:QI 0 "general_operand_dst" "")
        (match_operand:QI 1 "general_operand_src" ""))]
   "
 {
   /* One of the ops has to be in a register.  */
-  if (!register_operand (operand0, QImode)
+  if (!TARGET_H8300SX
+      && !register_operand (operand0, QImode)
       && !register_operand (operand1, QImode))
     {
       operands[1] = copy_to_mode_reg (QImode, operand1);
 }")
 
 (define_insn "movstrictqi"
-  [(set (strict_low_part
-        (match_operand:QI 0 "register_operand"    "+r,r,r,r,r"))
-        (match_operand:QI 1 "general_operand_src" " I,r,n,>,m"))]
+  [(set (strict_low_part (match_operand:QI 0 "general_operand_dst" "+r,r"))
+                        (match_operand:QI 1 "general_operand_src" "I,rmi>"))]
   ""
   "@
    sub.b       %X0,%X0
-   mov.b       %X1,%X0
-   mov.b       %R1,%X0
-   mov.b       %X1,%X0
-   mov.b       %R1,%X0"
-  [(set (attr "length")
-       (symbol_ref "compute_mov_length (operands)"))
-   (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv")])
+   mov.b       %X1,%X0"
+  [(set_attr "length" "2,*")
+   (set_attr "length_table" "*,movb")
+   (set_attr "cc" "set_zn,set_znv")])
 
 ;; movhi
 
 (define_insn "*movhi_h8300hs"
   [(set (match_operand:HI 0 "general_operand_dst" "=r,r,<,r,r,m")
        (match_operand:HI 1 "general_operand_src" "I,r>,r,i,m,r"))]
-  "(TARGET_H8300H || TARGET_H8300S)
+  "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX
    && (register_operand (operands[0], HImode)
        || register_operand (operands[1], HImode))"
   "@
        (symbol_ref "compute_mov_length (operands)"))
    (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv,set_znv")])
 
+(define_insn "*movhi_h8sx"
+  [(set (match_operand:HI 0 "general_operand_dst" "=r,r,Z,Q,rQ")
+       (match_operand:HI 1 "general_operand_src" "I,P3>X,P4>X,IP8>X,rQi"))]
+  "TARGET_H8300SX"
+  "@
+   sub.w       %T0,%T0
+   mov.w       %T1,%T0
+   mov.w       %T1,%T0
+   mov.w       %T1,%T0
+   mov.w       %T1,%T0"
+  [(set_attr "length_table" "*,*,mov_imm4,short_immediate,movw")
+   (set_attr "length" "2,2,*,*,*")
+   (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv")])
+
 (define_expand "movhi"
   [(set (match_operand:HI 0 "general_operand_dst" "")
        (match_operand:HI 1 "general_operand_src" ""))]
 }")
 
 (define_insn "movstricthi"
-  [(set (strict_low_part
-        (match_operand:HI 0 "register_operand"    "+r,r,r,r,r"))
-        (match_operand:HI 1 "general_operand_src" " I,r,i,>,m"))]
+  [(set (strict_low_part (match_operand:HI 0 "general_operand_dst" "+r,r,r"))
+                        (match_operand:HI 1 "general_operand_src" "I,P3>X,rmi"))]
   ""
   "@
    sub.w       %T0,%T0
    mov.w       %T1,%T0
-   mov.w       %T1,%T0
-   mov.w       %T1,%T0
    mov.w       %T1,%T0"
-  [(set (attr "length")
-       (symbol_ref "compute_mov_length (operands)"))
-   (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,set_znv")])
+  [(set_attr "length" "2,2,*")
+   (set_attr "length_table" "*,*,movw")
+   (set_attr "cc" "set_zn,set_znv,set_znv")])
 
 ;; movsi
 
       if (h8300_expand_movsi (operands))
        DONE;
     }
-  else
+  else if (!TARGET_H8300SX)
     {
       /* One of the ops has to be in a register.  */
       if (!register_operand (operand1, SImode)
 (define_insn "*movsi_h8300hs"
   [(set (match_operand:SI 0 "general_operand_dst" "=r,r,r,<,r,r,m,*a,*a,r")
        (match_operand:SI 1 "general_operand_src" "I,r,i,r,>,m,r,I,r,*a"))]
-  "(TARGET_H8300S || TARGET_H8300H)
+  "(TARGET_H8300S || TARGET_H8300H) && !TARGET_H8300SX
    && (register_operand (operands[0], SImode)
        || register_operand (operands[1], SImode))
    && !(GET_CODE (operands[0]) == MEM
        (symbol_ref "compute_mov_length (operands)"))
    (set_attr "cc" "set_zn,set_znv,clobber,set_znv,set_znv,set_znv,set_znv,none_0hit,none_0hit,set_znv")])
 
+(define_insn "*movsi_h8sx"
+  [(set (match_operand:SI 0 "general_operand_dst" "=r,r,Q,rQ,*a,*a,r")
+       (match_operand:SI 1 "general_operand_src" "I,P3>X,IP8>X,rQi,I,r,*a"))]
+  "TARGET_H8300SX"
+  "@
+   sub.l       %S0,%S0
+   mov.l       %S1,%S0
+   mov.l       %S1,%S0
+   mov.l       %S1,%S0
+   clrmac
+   clrmac\;ldmac       %1,macl
+   stmac       macl,%0"
+  [(set_attr "length_table" "*,*,short_immediate,movl,*,*,*")
+   (set_attr "length" "2,2,*,*,2,6,4")
+   (set_attr "cc" "set_zn,set_znv,set_znv,set_znv,none_0hit,none_0hit,set_znv")])
+
+(define_insn "*movsf_h8sx"
+  [(set (match_operand:SF 0 "general_operand_dst" "=r,rQ")
+       (match_operand:SF 1 "general_operand_src" "G,rQi"))]
+  "TARGET_H8300SX"
+  "@
+    sub.l      %S0,%S0
+    mov.l      %S1,%S0"
+  [(set_attr "length" "2,*")
+   (set_attr "length_table" "*,movl")
+   (set_attr "cc" "set_zn,set_znv")])
+
+;; Implement block moves using movmd.  Defining movmemsi allows the full
+;; range of constant lengths (up to 0x40000 bytes when using movmd.l).
+;; See h8sx_emit_movmd for details.
+(define_expand "movmemsi"
+  [(use (match_operand:BLK 0 "memory_operand" ""))
+   (use (match_operand:BLK 1 "memory_operand" ""))
+   (use (match_operand:SI 2 "" ""))
+   (use (match_operand:SI 3 "const_int_operand" ""))]
+  "TARGET_H8300SX"
+  {
+    if (h8sx_emit_movmd (operands[0], operands[1], operands[2],
+                        INTVAL (operands[3])))
+      DONE;
+    else
+      FAIL;
+  })
+
+;; Expander for generating movmd insns.  Operand 0 is the destination
+;; memory region, operand 1 is the source, operand 2 is the counter
+;; register and operand 3 is the chunk size (1, 2 or 4).
+(define_expand "movmd"
+  [(parallel
+       [(set (match_operand:BLK 0 "memory_operand" "")
+            (match_operand:BLK 1 "memory_operand" ""))
+       (unspec [(match_operand:HI 2 "register_operand" "")
+                (match_operand:HI 3 "const_int_operand" "")] UNSPEC_MOVMD)
+       (clobber (match_dup 4))
+       (clobber (match_dup 5))
+       (set (match_dup 2)
+            (const_int 0))])]
+  "TARGET_H8300SX"
+  {
+    operands[4] = copy_rtx (XEXP (operands[0], 0));
+    operands[5] = copy_rtx (XEXP (operands[1], 0));
+  })
+
+
+;; This is a difficult instruction to reload since operand 0 must be the
+;; frame pointer.  See h8300_reg_class_from_letter for an explanation.
+(define_insn "movmd_internal_normal"
+  [(set (mem:BLK (match_operand:HI 3 "register_operand" "0,r"))
+       (mem:BLK (match_operand:HI 4 "register_operand" "1,1")))
+   (unspec [(match_operand:HI 5 "register_operand" "2,2")
+           (match_operand:HI 6 "const_int_operand" "n,n")] UNSPEC_MOVMD)
+   (clobber (match_operand:HI 0 "register_operand" "=d,??D"))
+   (clobber (match_operand:HI 1 "register_operand" "=f,f"))
+   (set (match_operand:HI 2 "register_operand" "=c,c")
+       (const_int 0))]
+  "TARGET_H8300SX && TARGET_NORMAL_MODE"
+  "@
+    movmd%m6
+    #"
+  [(set_attr "length" "2,14")
+   (set_attr "can_delay" "no")
+   (set_attr "cc" "none,clobber")])
+
+(define_insn "movmd_internal"
+  [(set (mem:BLK (match_operand:SI 3 "register_operand" "0,r"))
+       (mem:BLK (match_operand:SI 4 "register_operand" "1,1")))
+   (unspec [(match_operand:HI 5 "register_operand" "2,2")
+           (match_operand:HI 6 "const_int_operand" "n,n")] UNSPEC_MOVMD)
+   (clobber (match_operand:SI 0 "register_operand" "=d,??D"))
+   (clobber (match_operand:SI 1 "register_operand" "=f,f"))
+   (set (match_operand:HI 2 "register_operand" "=c,c")
+       (const_int 0))]
+  "TARGET_H8300SX && !TARGET_NORMAL_MODE"
+  "@
+    movmd%m6
+    #"
+  [(set_attr "length" "2,14")
+   (set_attr "can_delay" "no")
+   (set_attr "cc" "none,clobber")])
+
+;; Split the above instruction if the destination register isn't er6.
+;; We need a sequence like:
+;;
+;;     mov.l   er6,@-er7
+;;     mov.l   <dest>,er6
+;;     movmd.sz
+;;     mov.l   er6,<dest>
+;;     mov.l   @er7+,er6
+;;
+;; where <dest> is the current destination register (operand 4).
+;; The fourth instruction will be deleted if <dest> dies here.
+(define_split
+  [(set (match_operand:BLK 0 "memory_operand" "")
+       (match_operand:BLK 1 "memory_operand" ""))
+   (unspec [(match_operand:HI 2 "register_operand" "")
+           (match_operand:HI 3 "const_int_operand" "")] UNSPEC_MOVMD)
+   (clobber (match_operand:HI 4 "register_operand" ""))
+   (clobber (match_operand:HI 5 "register_operand" ""))
+   (set (match_dup 2)
+       (const_int 0))]
+  "TARGET_H8300SX && TARGET_NORMAL_MODE
+   && reload_completed
+   && REGNO (operands[4]) != DESTINATION_REG"
+  [(const_int 0)]
+  {
+    rtx dest;
+
+    h8300_swap_into_er6 (XEXP (operands[0], 0));
+    dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx);
+    emit_insn (gen_movmd (dest, operands[1], operands[2], operands[3]));
+    h8300_swap_out_of_er6 (operands[4]);
+    DONE;
+  })
+
+(define_split
+  [(set (match_operand:BLK 0 "memory_operand" "")
+       (match_operand:BLK 1 "memory_operand" ""))
+   (unspec [(match_operand:HI 2 "register_operand" "")
+           (match_operand:HI 3 "const_int_operand" "")] UNSPEC_MOVMD)
+   (clobber (match_operand:SI 4 "register_operand" ""))
+   (clobber (match_operand:SI 5 "register_operand" ""))
+   (set (match_dup 2)
+       (const_int 0))]
+  "TARGET_H8300SX && !TARGET_NORMAL_MODE
+   && reload_completed
+   && REGNO (operands[4]) != DESTINATION_REG"
+  [(const_int 0)]
+  {
+    rtx dest;
+
+    h8300_swap_into_er6 (XEXP (operands[0], 0));
+    dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx);
+    emit_insn (gen_movmd (dest, operands[1], operands[2], operands[3]));
+    h8300_swap_out_of_er6 (operands[4]);
+    DONE;
+  })
+
+;; Expand a call to stpcpy() using movsd.  Operand 0 should point to
+;; the final character, but movsd leaves it pointing to the character
+;; after that.
+(define_expand "movstr"
+  [(use (match_operand 0 "register_operand" ""))
+   (use (match_operand:BLK 1 "memory_operand" ""))
+   (use (match_operand:BLK 2 "memory_operand" ""))]
+  "TARGET_H8300SX"
+  {
+    operands[1] = replace_equiv_address
+      (operands[1], copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
+    operands[2] = replace_equiv_address
+      (operands[2], copy_to_mode_reg (Pmode, XEXP (operands[2], 0)));
+    emit_insn (gen_movsd (operands[1], operands[2], gen_reg_rtx (Pmode)));
+    emit_insn (gen_add3_insn (operands[0],
+                             XEXP (operands[1], 0),
+                             constm1_rtx));
+    DONE;
+  })
+
+;; Expander for generating a movsd instruction.  Operand 0 is the
+;; destination string, operand 1 is the source string and operand 2
+;; is a scratch register.
+(define_expand "movsd"
+  [(parallel
+     [(set (match_operand:BLK 0 "memory_operand" "")
+          (unspec:BLK [(match_operand:BLK 1 "memory_operand" "")]
+                      UNSPEC_STPCPY))
+      (clobber (match_dup 3))
+      (clobber (match_dup 4))
+      (clobber (match_operand 2 "register_operand" ""))])]
+  "TARGET_H8300SX"
+  {
+    operands[3] = copy_rtx (XEXP (operands[0], 0));
+    operands[4] = copy_rtx (XEXP (operands[1], 0));
+  })
+
+;; See comments above memcpy_internal().
+(define_insn "stpcpy_internal_normal"
+  [(set (mem:BLK (match_operand:HI 3 "register_operand" "0,r"))
+       (unspec:BLK [(mem:BLK (match_operand:HI 4 "register_operand" "1,1"))]
+               UNSPEC_STPCPY))
+   (clobber (match_operand:HI 0 "register_operand" "=d,??D"))
+   (clobber (match_operand:HI 1 "register_operand" "=f,f"))
+   (clobber (match_operand:HI 2 "register_operand" "=c,c"))]
+  "TARGET_H8300SX && TARGET_NORMAL_MODE"
+  "@
+    \n1:\tmovsd\t2f\;bra\t1b\n2:
+    #"
+  [(set_attr "length" "6,18")
+   (set_attr "cc" "none,clobber")])
+
+(define_insn "stpcpy_internal"
+  [(set (mem:BLK (match_operand:SI 3 "register_operand" "0,r"))
+       (unspec:BLK [(mem:BLK (match_operand:SI 4 "register_operand" "1,1"))]
+               UNSPEC_STPCPY))
+   (clobber (match_operand:SI 0 "register_operand" "=d,??D"))
+   (clobber (match_operand:SI 1 "register_operand" "=f,f"))
+   (clobber (match_operand:SI 2 "register_operand" "=c,c"))]
+  "TARGET_H8300SX && !TARGET_NORMAL_MODE"
+  "@
+    \n1:\tmovsd\t2f\;bra\t1b\n2:
+    #"
+  [(set_attr "length" "6,18")
+   (set_attr "cc" "none,clobber")])
+
+;; Split the above instruction if the destination isn't er6.  This works
+;; in the same way as the movmd splitter.
+(define_split
+  [(set (match_operand:BLK 0 "memory_operand" "")
+       (unspec:BLK [(match_operand:BLK 1 "memory_operand" "")] UNSPEC_STPCPY))
+   (clobber (match_operand:HI 2 "register_operand" ""))
+   (clobber (match_operand:HI 3 "register_operand" ""))
+   (clobber (match_operand:HI 4 "register_operand" ""))]
+  "TARGET_H8300SX && TARGET_NORMAL_MODE
+   && reload_completed
+   && REGNO (operands[2]) != DESTINATION_REG"
+  [(const_int 0)]
+  {
+    rtx dest;
+
+    h8300_swap_into_er6 (XEXP (operands[0], 0));
+    dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx);
+    emit_insn (gen_movsd (dest, operands[1], operands[4]));
+    h8300_swap_out_of_er6 (operands[2]);
+    DONE;
+  })
+
+(define_split
+  [(set (match_operand:BLK 0 "memory_operand" "")
+       (unspec:BLK [(match_operand:BLK 1 "memory_operand" "")] UNSPEC_STPCPY))
+   (clobber (match_operand:SI 2 "register_operand" ""))
+   (clobber (match_operand:SI 3 "register_operand" ""))
+   (clobber (match_operand:SI 4 "register_operand" ""))]
+  "TARGET_H8300SX && !TARGET_NORMAL_MODE
+   && reload_completed
+   && REGNO (operands[2]) != DESTINATION_REG"
+  [(const_int 0)]
+  {
+    rtx dest;
+
+    h8300_swap_into_er6 (XEXP (operands[0], 0));
+    dest = replace_equiv_address (operands[0], hard_frame_pointer_rtx);
+    emit_insn (gen_movsd (dest, operands[1], operands[4]));
+    h8300_swap_out_of_er6 (operands[2]);
+    DONE;
+  })
+
+(include "mova.md")
+
 (define_expand "movsf"
   [(set (match_operand:SF 0 "general_operand_dst" "")
        (match_operand:SF 1 "general_operand_src" ""))]
       if (h8300_expand_movsi (operands))
        DONE;
     }
-  else
+  else if (!TARGET_H8300SX)
     {
       /* One of the ops has to be in a register.  */
       if (!register_operand (operand1, SFmode)
 (define_insn "*movsf_h8300hs"
   [(set (match_operand:SF 0 "general_operand_dst" "=r,r,r,m,<,r")
        (match_operand:SF 1 "general_operand_src" "G,r,im,r,r,>"))]
-  "(TARGET_H8300H || TARGET_H8300S)
+  "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX
    && (register_operand (operands[0], SFmode)
        || register_operand (operands[1], SFmode))"
   "@
    btst\\t%Z1,%Y0
    #"
   "&& reload_completed
-   && !EXTRA_CONSTRAINT (operands[0], 'U')"
+   && !OK_FOR_U (operands[0])"
   [(set (match_dup 2)
        (match_dup 0))
    (parallel [(set (cc0) (zero_extract:SI (match_dup 2)
    btst\\t%w1,%X0
    #"
   "&& reload_completed
-   && !EXTRA_CONSTRAINT (operands[0], 'U')"
+   && !OK_FOR_U (operands[0])"
   [(set (match_dup 2)
        (match_dup 0))
    (parallel [(set (cc0) (zero_extract:SI (zero_extend:SI (match_dup 2))
 
 (define_insn "cmpqi"
   [(set (cc0)
-       (compare (match_operand:QI 0 "register_operand" "r")
-                (match_operand:QI 1 "nonmemory_operand" "rn")))]
+       (compare (match_operand:QI 0 "h8300_dst_operand" "rQ")
+                (match_operand:QI 1 "h8300_src_operand" "rQi")))]
   ""
   "cmp.b       %X1,%X0"
-  [(set_attr "length" "2")
+  [(set_attr "length_table" "addb")
    (set_attr "cc" "compare")])
 
 (define_expand "cmphi"
   [(set (cc0)
-       (compare (match_operand:HI 0 "register_operand" "")
-                (match_operand:HI 1 "nonmemory_operand" "")))]
+       (compare (match_operand:HI 0 "h8300_dst_operand" "")
+                (match_operand:HI 1 "h8300_src_operand" "")))]
   ""
   "
 {
 
 (define_insn "*cmphi_h8300hs_znvc"
   [(set (cc0)
-       (compare (match_operand:HI 0 "register_operand" "r,r")
-                (match_operand:HI 1 "nonmemory_operand" "r,n")))]
+       (compare (match_operand:HI 0 "h8300_dst_operand" "rU,rQ")
+                (match_operand:HI 1 "h8300_src_operand" "P3>X,rQi")))]
   "TARGET_H8300H || TARGET_H8300S"
   "cmp.w       %T1,%T0"
-  [(set_attr "length" "2,4")
+  [(set_attr "length_table" "short_immediate,addw")
    (set_attr "cc" "compare,compare")])
 
 (define_insn "cmpsi"
   [(set (cc0)
-       (compare (match_operand:SI 0 "register_operand" "r,r")
-                (match_operand:SI 1 "nonmemory_operand" "r,i")))]
+       (compare (match_operand:SI 0 "h8300_dst_operand" "r,rQ")
+                (match_operand:SI 1 "h8300_src_operand" "P3>X,rQi")))]
   "TARGET_H8300H || TARGET_H8300S"
   "cmp.l       %S1,%S0"
-  [(set_attr "length" "2,6")
+  [(set_attr "length" "2,*")
+   (set_attr "length_table" "*,addl")
    (set_attr "cc" "compare,compare")])
 \f
 ;; ----------------------------------------------------------------------
 ;; ADD INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "addqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (plus:QI (match_operand:QI 1 "register_operand" "%0")
-                (match_operand:QI 2 "nonmemory_operand" "rn")))]
+(define_expand "addqi3"
+  [(set (match_operand:QI 0 "register_operand" "")
+       (plus:QI (match_operand:QI 1 "register_operand" "")
+                (match_operand:QI 2 "h8300_src_operand" "")))]
   ""
+  "")
+
+(define_insn "*addqi3"
+  [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ")
+       (plus:QI (match_operand:QI 1 "h8300_dst_operand" "%0")
+                (match_operand:QI 2 "h8300_src_operand" "rQi")))]
+  "h8300_operands_match_p (operands)"
   "add.b       %X2,%X0"
-  [(set_attr "length" "2")
+  [(set_attr "length_table" "addb")
    (set_attr "cc" "set_zn")])
 
 (define_expand "addhi3"
   [(set (match_operand:HI 0 "register_operand" "")
        (plus:HI (match_operand:HI 1 "register_operand" "")
-                (match_operand:HI 2 "nonmemory_operand" "")))]
+                (match_operand:HI 2 "h8300_src_operand" "")))]
   ""
   "")
 
 (define_insn "*addhi3_h8300"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
        (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0")
-                (match_operand:HI 2 "nonmemory_operand" "L,N,J,n,r")))]
+                (match_operand:HI 2 "h8300_src_operand" "L,N,J,n,r")))]
   "TARGET_H8300"
   "@
    adds        %2,%T0
 (define_insn "*addhi3_h8300hs"
   [(set (match_operand:HI 0 "register_operand" "=r,r,r,r,r")
        (plus:HI (match_operand:HI 1 "register_operand" "%0,0,0,0,0")
-                (match_operand:HI 2 "nonmemory_operand" "L,N,J,n,r")))]
-  "TARGET_H8300H || TARGET_H8300S"
+                (match_operand:HI 2 "h8300_src_operand" "L,N,J,n,r")))]
+  "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX"
   "@
    adds        %2,%S0
    subs        %G2,%S0
   [(set_attr "length" "2,2")
    (set_attr "cc" "set_zn,set_zn")])
 
+(define_insn "*addhi3_h8sx"
+  [(set (match_operand:HI 0 "h8300_dst_operand" "=rU,rU,r,rQ")
+       (plus:HI (match_operand:HI 1 "h8300_dst_operand" "%0,0,0,0")
+                (match_operand:HI 2 "h8300_src_operand" "P3>X,P3<X,J,rQi")))]
+  "TARGET_H8300SX && h8300_operands_match_p (operands)"
+  "@
+   add.w       %T2,%T0
+   sub.w       %G2,%T0
+   add.b       %t2,%t0
+   add.w       %T2,%T0"
+  [(set_attr "length_table" "short_immediate,short_immediate,*,addw")
+   (set_attr "length" "*,*,2,*")
+   (set_attr "cc" "set_zn")])
+
 (define_split
   [(set (match_operand:HI 0 "register_operand" "")
        (plus:HI (match_dup 0)
 (define_expand "addsi3"
   [(set (match_operand:SI 0 "register_operand" "")
        (plus:SI (match_operand:SI 1 "register_operand" "")
-                (match_operand:SI 2 "nonmemory_operand" "")))]
+                (match_operand:SI 2 "h8300_src_operand" "")))]
   ""
   "")
 
 (define_insn "*addsi_h8300"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
        (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
-                (match_operand:SI 2 "nonmemory_operand" "n,r")))]
+                (match_operand:SI 2 "h8300_src_operand" "n,r")))]
   "TARGET_H8300"
   "* return output_plussi (operands);"
   [(set (attr "length")
        (symbol_ref "compute_plussi_cc (operands)"))])
 
 (define_insn "*addsi_h8300hs"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (plus:SI (match_operand:SI 1 "register_operand" "%0,0")
-                (match_operand:SI 2 "nonmemory_operand" "i,r")))]
-  "TARGET_H8300H || TARGET_H8300S"
+  [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ,rQ")
+       (plus:SI (match_operand:SI 1 "h8300_dst_operand" "%0,0")
+                (match_operand:SI 2 "h8300_src_operand" "i,rQ")))]
+  "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)"
   "* return output_plussi (operands);"
   [(set (attr "length")
        (symbol_ref "compute_plussi_length (operands)"))
 ;; SUBTRACT INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "subqi3"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (minus:QI (match_operand:QI 1 "register_operand" "0")
-                 (match_operand:QI 2 "register_operand" "r")))]
+(define_expand "subqi3"
+  [(set (match_operand:QI 0 "register_operand" "")
+       (minus:QI (match_operand:QI 1 "register_operand" "")
+                 (match_operand:QI 2 "h8300_src_operand" "")))]
   ""
+  "")
+
+(define_insn "*subqi3"
+  [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ")
+       (minus:QI (match_operand:QI 1 "h8300_dst_operand" "0")
+                 (match_operand:QI 2 "h8300_dst_operand" "rQ")))]
+  "h8300_operands_match_p (operands)"
   "sub.b       %X2,%X0"
-  [(set_attr "length" "2")
+  [(set_attr "length_table" "addb")
    (set_attr "cc" "set_zn")])
 
 (define_expand "subhi3"
   [(set (match_operand:HI 0 "register_operand" "")
-       (minus:HI (match_operand:HI 1 "general_operand" "")
-                 (match_operand:HI 2 "nonmemory_operand" "")))]
+       (minus:HI (match_operand:HI 1 "register_operand" "")
+                 (match_operand:HI 2 "h8300_src_operand" "")))]
   ""
   "")
 
 (define_insn "*subhi3_h8300"
   [(set (match_operand:HI 0 "register_operand" "=r,r")
-       (minus:HI (match_operand:HI 1 "general_operand" "0,0")
-                 (match_operand:HI 2 "nonmemory_operand" "r,n")))]
+       (minus:HI (match_operand:HI 1 "register_operand" "0,0")
+                 (match_operand:HI 2 "h8300_src_operand" "r,n")))]
   "TARGET_H8300"
   "@
    sub.w       %T2,%T0
    (set_attr "cc" "set_zn,clobber")])
 
 (define_insn "*subhi3_h8300hs"
-  [(set (match_operand:HI 0 "register_operand" "=r,r")
-       (minus:HI (match_operand:HI 1 "general_operand" "0,0")
-                 (match_operand:HI 2 "nonmemory_operand" "r,n")))]
-  "TARGET_H8300H || TARGET_H8300S"
+  [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ,rQ")
+       (minus:HI (match_operand:HI 1 "h8300_dst_operand" "0,0")
+                 (match_operand:HI 2 "h8300_src_operand" "rQ,i")))]
+  "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)"
   "@
    sub.w       %T2,%T0
    sub.w       %T2,%T0"
-  [(set_attr "length" "2,4")
-   (set_attr "cc" "set_zn,set_zn")])
+  [(set_attr "length_table" "addw")
+   (set_attr "cc" "set_zn")])
 
 (define_expand "subsi3"
   [(set (match_operand:SI 0 "register_operand" "")
        (minus:SI (match_operand:SI 1 "register_operand" "")
-                 (match_operand:SI 2 "nonmemory_operand" "")))]
+                 (match_operand:SI 2 "h8300_src_operand" "")))]
   ""
-  "")
+{
+  if (TARGET_H8300)
+    operands[2] = force_reg (SImode, operands[2]);
+})
 
 (define_insn "*subsi3_h8300"
   [(set (match_operand:SI 0 "register_operand" "=r")
   [(set_attr "length" "6")])
 
 (define_insn "*subsi3_h8300hs"
-  [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (minus:SI (match_operand:SI 1 "general_operand" "0,0")
-                 (match_operand:SI 2 "nonmemory_operand" "r,i")))]
-  "TARGET_H8300H || TARGET_H8300S"
+  [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ,rQ")
+       (minus:SI (match_operand:SI 1 "h8300_dst_operand" "0,0")
+                 (match_operand:SI 2 "h8300_src_operand" "rQ,i")))]
+  "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)"
   "@
    sub.l       %S2,%S0
    sub.l       %S2,%S0"
-  [(set_attr "length" "2,6")
-   (set_attr "cc" "set_zn,set_zn")])
+  [(set_attr "length_table" "addl")
+   (set_attr "cc" "set_zn")])
 \f
 ;; ----------------------------------------------------------------------
 ;; MULTIPLY INSTRUCTIONS
 
 ;; Note that the H8/300 can only handle umulqihi3.
 
-(define_insn "mulqihi3"
+(define_expand "mulqihi3"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" ""))
+                ;; intentionally-mismatched modes
+                (match_operand:QI 2 "reg_or_nibble_operand" "")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "
+{
+  if (GET_MODE (operands[2]) != VOIDmode)
+    operands[2] = gen_rtx_SIGN_EXTEND (HImode, operands[2]);
+}")
+
+(define_insn "*mulqihi3_const"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+                (match_operand:QI 2 "nibble_operand" "IP4>X")))]
+  "TARGET_H8300SX"
+  "mulxs.b     %X2,%T0"
+  [(set_attr "length" "4")
+   (set_attr "cc" "set_zn")])
+
+(define_insn "*mulqihi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
                 (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
   [(set_attr "length" "4")
    (set_attr "cc" "set_zn")])
 
-(define_insn "mulhisi3"
+(define_expand "mulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" ""))
+                ;; intentionally-mismatched modes
+                (match_operand:HI 2 "reg_or_nibble_operand" "")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "
+{
+  if (GET_MODE (operands[2]) != VOIDmode)
+    operands[2] = gen_rtx_SIGN_EXTEND (SImode, operands[2]);
+}")
+
+(define_insn "*mulhisi3_const"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
+                (match_operand:SI 2 "nibble_operand" "IP4>X")))]
+  "TARGET_H8300SX"
+  "mulxs.w     %T2,%S0"
+  [(set_attr "length" "4")
+   (set_attr "cc" "set_zn")])
+
+(define_insn "*mulhisi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%0"))
                 (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
   [(set_attr "length" "4")
    (set_attr "cc" "set_zn")])
 
-(define_insn "umulqihi3"
+(define_expand "umulqihi3"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" ""))
+                ;; intentionally-mismatched modes
+                (match_operand:QI 2 "reg_or_nibble_operand" "")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "
+{
+  if (GET_MODE (operands[2]) != VOIDmode)
+    operands[2] = gen_rtx_ZERO_EXTEND (HImode, operands[2]);
+}")
+
+(define_insn "*umulqihi3_const"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+                (match_operand:QI 2 "nibble_operand" "IP4>X")))]
+  "TARGET_H8300SX"
+  "mulxu.b     %X2,%T0"
+  [(set_attr "length" "4")
+   (set_attr "cc" "set_zn")])
+
+(define_insn "*umulqihi3"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
                 (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
   ""
-  "mulxu       %X2,%T0"
+  "mulxu.b     %X2,%T0"
   [(set_attr "length" "2")
    (set_attr "cc" "none_0hit")])
 
-(define_insn "umulhisi3"
+(define_expand "umulhisi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" ""))
+                ;; intentionally-mismatched modes
+                (match_operand:HI 2 "reg_or_nibble_operand" "")))]
+  "TARGET_H8300H || TARGET_H8300S"
+  "
+{
+  if (GET_MODE (operands[2]) != VOIDmode)
+    operands[2] = gen_rtx_ZERO_EXTEND (SImode, operands[2]);
+}")
+
+(define_insn "*umulhisi3_const"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
+                (match_operand:SI 2 "nibble_operand" "IP4>X")))]
+  "TARGET_H8300SX"
+  "mulxu.w     %T2,%S0"
+  [(set_attr "length" "4")
+   (set_attr "cc" "set_zn")])
+
+(define_insn "*umulhisi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%0"))
                 (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))]
   [(set_attr "length" "2")
    (set_attr "cc" "none_0hit")])
 
+;; We could have used mulu.[wl] here, but mulu.[lw] is only available
+;; on a H8SX with a multiplier, whereas muls.w seems to be available
+;; on all H8SX variants.
+(define_insn "mulhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+        (mult:HI (match_operand:HI 1 "register_operand" "%0")
+                (match_operand:HI 2 "reg_or_nibble_operand" "r IP4>X")))]
+  "TARGET_H8300SX"
+  "muls.w\\t%T2,%T0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_zn")])
+
+(define_insn "mulsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (mult:SI (match_operand:SI 1 "register_operand" "%0")
+                (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X")))]
+  "TARGET_H8300SX"
+  "muls.l\\t%S2,%S0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_zn")])
+
+(define_insn "smulsi3_highpart"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (truncate:SI
+        (lshiftrt:DI
+         (mult:DI
+          (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
+          (sign_extend:DI (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X")))
+         (const_int 32))))]
+  "TARGET_H8300SXMUL"
+  "muls/u.l\\t%S2,%S0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_zn")])
+
+(define_insn "umulsi3_highpart"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (truncate:SI
+        (ashiftrt:DI
+         (mult:DI
+          (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
+          (zero_extend:DI (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X")))
+         (const_int 32))))]
+  "TARGET_H8300SX"
+  "mulu/u.l\\t%S2,%S0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "none_0hit")])
+
 ;; This is a "bridge" instruction.  Combine can't cram enough insns
 ;; together to crate a MAC instruction directly, but it can create
 ;; this instruction, which then allows combine to create the real
 ;; DIVIDE/MOD INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
+(define_insn "udivhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (udiv:HI
+        (match_operand:HI 1 "register_operand" "0")
+        (match_operand:HI 2 "reg_or_nibble_operand" "r IP4>X")))]
+  "TARGET_H8300SX"
+  "divu.w\\t%T2,%T0"
+  [(set_attr "length" "2")])
+  
+(define_insn "divhi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (div:HI
+        (match_operand:HI 1 "register_operand" "0")
+        (match_operand:HI 2 "reg_or_nibble_operand" "r IP4>X")))]
+  "TARGET_H8300SX"
+  "divs.w\\t%T2,%T0"
+  [(set_attr "length" "2")])
+  
+(define_insn "udivsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (udiv:SI
+        (match_operand:SI 1 "register_operand" "0")
+        (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X")))]
+  "TARGET_H8300SX"
+  "divu.l\\t%S2,%S0"
+  [(set_attr "length" "2")])
+  
+(define_insn "divsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (div:SI
+        (match_operand:SI 1 "register_operand" "0")
+        (match_operand:SI 2 "reg_or_nibble_operand" "r IP4>X")))]
+  "TARGET_H8300SX"
+  "divs.l\\t%S2,%S0"
+  [(set_attr "length" "2")])
+  
 (define_insn "udivmodqi4"
   [(set (match_operand:QI 0 "register_operand" "=r")
        (truncate:QI
 ;; AND INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
+(define_insn "*andqi3_2"
+  [(set (match_operand:QI 0 "bit_operand" "=rQ,r")
+       (and:QI (match_operand:QI 1 "bit_operand" "%0,WU")
+               (match_operand:QI 2 "h8300_src_operand" "rQi,IP1>X")))]
+  "TARGET_H8300SX"
+  "@
+   and %X2,%X0
+   bfld        %2,%1,%R0"
+  [(set_attr "length" "*,8")
+   (set_attr "length_table" "logicb,*")
+   (set_attr "cc" "set_znv,none_0hit")])
+
 (define_insn "andqi3_1"
   [(set (match_operand:QI 0 "bit_operand" "=r,U")
        (and:QI (match_operand:QI 1 "bit_operand" "%0,0")
-               (match_operand:QI 2 "nonmemory_operand" "rn,n")))]
+               (match_operand:QI 2 "h8300_src_operand" "rn,n")))]
   "register_operand (operands[0], QImode)
    || single_zero_operand (operands[2], QImode)"
   "@
    (set_attr "cc" "set_znv,none_0hit")])
 
 (define_expand "andqi3"
-  [(set (match_operand:QI 0 "bit_operand" "")
-       (and:QI (match_operand:QI 1 "bit_operand" "")
-               (match_operand:QI 2 "nonmemory_operand" "")))]
+  [(set (match_operand:QI 0 "register_operand" "")
+       (and:QI (match_operand:QI 1 "register_operand" "")
+               (match_operand:QI 2 "h8300_src_operand" "")))]
   ""
-  "
-{
-  if (fix_bit_operand (operands, AND))
-    DONE;
-}")
+  "")
 
 (define_expand "andhi3"
   [(set (match_operand:HI 0 "register_operand" "")
        (and:HI (match_operand:HI 1 "register_operand" "")
-               (match_operand:HI 2 "nonmemory_operand" "")))]
+               (match_operand:HI 2 "h8300_src_operand" "")))]
   ""
   "")
 
 (define_expand "andsi3"
   [(set (match_operand:SI 0 "register_operand" "")
        (and:SI (match_operand:SI 1 "register_operand" "")
-               (match_operand:SI 2 "nonmemory_operand" "")))]
+               (match_operand:SI 2 "h8300_src_operand" "")))]
   ""
   "")
 
 ;; ----------------------------------------------------------------------
 
 (define_insn "iorqi3_1"
-  [(set (match_operand:QI 0 "bit_operand" "=r,U")
+  [(set (match_operand:QI 0 "bit_operand" "=rQ,U")
        (ior:QI (match_operand:QI 1 "bit_operand" "%0,0")
-               (match_operand:QI 2 "nonmemory_operand" "rn,n")))]
-  "register_operand (operands[0], QImode)
+               (match_operand:QI 2 "h8300_src_operand" "rQi,n")))]
+  "TARGET_H8300SX || register_operand (operands[0], QImode)
    || single_one_operand (operands[2], QImode)"
   "@
    or\\t%X2,%X0
    bset\\t%V2,%R0"
-  [(set_attr "length" "2,8")
+  [(set_attr "length" "*,8")
+   (set_attr "length_table" "logicb,*")
    (set_attr "cc" "set_znv,none_0hit")])
 
 (define_expand "iorqi3"
-  [(set (match_operand:QI 0 "bit_operand" "")
-       (ior:QI (match_operand:QI 1 "bit_operand" "")
-               (match_operand:QI 2 "nonmemory_operand" "")))]
+  [(set (match_operand:QI 0 "register_operand" "")
+       (ior:QI (match_operand:QI 1 "register_operand" "")
+               (match_operand:QI 2 "h8300_src_operand" "")))]
   ""
-  "
-{
-  if (fix_bit_operand (operands, IOR))
-    DONE;
-}")
+  "")
 
 (define_expand "iorhi3"
   [(set (match_operand:HI 0 "register_operand" "")
        (ior:HI (match_operand:HI 1 "register_operand" "")
-               (match_operand:HI 2 "nonmemory_operand" "")))]
+               (match_operand:HI 2 "h8300_src_operand" "")))]
   ""
   "")
 
 (define_expand "iorsi3"
   [(set (match_operand:SI 0 "register_operand" "")
        (ior:SI (match_operand:SI 1 "register_operand" "")
-               (match_operand:SI 2 "nonmemory_operand" "")))]
+               (match_operand:SI 2 "h8300_src_operand" "")))]
   ""
   "")
 
 (define_insn "xorqi3_1"
   [(set (match_operand:QI 0 "bit_operand" "=r,U")
        (xor:QI (match_operand:QI 1 "bit_operand" "%0,0")
-               (match_operand:QI 2 "nonmemory_operand" "rn,n")))]
-  "register_operand (operands[0], QImode)
+               (match_operand:QI 2 "h8300_src_operand" "rQi,n")))]
+  "TARGET_H8300SX || register_operand (operands[0], QImode)
    || single_one_operand (operands[2], QImode)"
   "@
    xor\\t%X2,%X0
    bnot\\t%V2,%R0"
-  [(set_attr "length" "2,8")
+  [(set_attr "length" "*,8")
+   (set_attr "length_table" "logicb,*")
    (set_attr "cc" "set_znv,none_0hit")])
 
 (define_expand "xorqi3"
-  [(set (match_operand:QI 0 "bit_operand" "")
-       (xor:QI (match_operand:QI 1 "bit_operand" "")
-               (match_operand:QI 2 "nonmemory_operand" "")))]
+  [(set (match_operand:QI 0 "register_operand" "")
+       (xor:QI (match_operand:QI 1 "register_operand" "")
+               (match_operand:QI 2 "h8300_src_operand" "")))]
   ""
-  "
-{
-  if (fix_bit_operand (operands, XOR))
-    DONE;
-}")
+  "")
 
 (define_expand "xorhi3"
   [(set (match_operand:HI 0 "register_operand" "")
        (xor:HI (match_operand:HI 1 "register_operand" "")
-               (match_operand:HI 2 "nonmemory_operand" "")))]
+               (match_operand:HI 2 "h8300_src_operand" "")))]
   ""
   "")
 
 (define_expand "xorsi3"
   [(set (match_operand:SI 0 "register_operand" "")
        (xor:SI (match_operand:SI 1 "register_operand" "")
-               (match_operand:SI 2 "nonmemory_operand" "")))]
+               (match_operand:SI 2 "h8300_src_operand" "")))]
   ""
   "")
 
 ;; {AND,IOR,XOR}{HI3,SI3} PATTERNS
 ;; ----------------------------------------------------------------------
 
+;; We need a separate pattern here because machines other than the
+;; original H8300 don't have to split the 16-bit operand into a pair
+;; of high/low instructions, so we can accept literal addresses, that
+;; have to be loaded into a register on H8300.
+(define_insn "*logicalhi3_sn"
+  [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ")
+       (match_operator:HI 3 "bit_operator"
+         [(match_operand:HI 1 "h8300_dst_operand" "%0")
+          (match_operand:HI 2 "h8300_src_operand" "rQi")]))]
+  "(TARGET_H8300S || TARGET_H8300H) && h8300_operands_match_p (operands)"
+  "* return output_logical_op (HImode, operands);"
+  [(set (attr "length")
+       (symbol_ref "compute_logical_op_length (HImode, operands)"))
+   (set (attr "cc")
+       (symbol_ref "compute_logical_op_cc (HImode, operands)"))])
+
+(define_insn "*logicalsi3_sn"
+  [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ")
+       (match_operator:SI 3 "bit_operator"
+         [(match_operand:SI 1 "h8300_dst_operand" "%0")
+          (match_operand:SI 2 "h8300_src_operand" "rQi")]))]
+  "(TARGET_H8300S || TARGET_H8300H) && h8300_operands_match_p (operands)"
+  "* return output_logical_op (SImode, operands);"
+  [(set (attr "length")
+       (symbol_ref "compute_logical_op_length (SImode, operands)"))
+   (set (attr "cc")
+       (symbol_ref "compute_logical_op_cc (SImode, operands)"))])
+
 (define_insn "*logicalhi3"
-  [(set (match_operand:HI 0 "register_operand" "=r")
+  [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ")
        (match_operator:HI 3 "bit_operator"
-         [(match_operand:HI 1 "register_operand" "%0")
-          (match_operand:HI 2 "nonmemory_operand" "rn")]))]
-  ""
+         [(match_operand:HI 1 "h8300_dst_operand" "%0")
+          (match_operand:HI 2 "h8300_src_operand" "rQi")]))]
+  "h8300_operands_match_p (operands)"
   "* return output_logical_op (HImode, operands);"
   [(set (attr "length")
        (symbol_ref "compute_logical_op_length (HImode, operands)"))
        (symbol_ref "compute_logical_op_cc (HImode, operands)"))])
 
 (define_insn "*logicalsi3"
-  [(set (match_operand:SI 0 "register_operand" "=r")
+  [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ")
        (match_operator:SI 3 "bit_operator"
-         [(match_operand:SI 1 "register_operand" "%0")
-          (match_operand:SI 2 "nonmemory_operand" "rn")]))]
-  ""
+         [(match_operand:SI 1 "h8300_dst_operand" "%0")
+          (match_operand:SI 2 "h8300_src_operand" "rQi")]))]
+  "h8300_operands_match_p (operands)"
   "* return output_logical_op (SImode, operands);"
   [(set (attr "length")
        (symbol_ref "compute_logical_op_length (SImode, operands)"))
 ;; NEGATION INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "negqi2"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (neg:QI (match_operand:QI 1 "register_operand" "0")))]
+(define_expand "negqi2"
+  [(set (match_operand:QI 0 "register_operand" "")
+       (neg:QI (match_operand:QI 1 "register_operand" "")))]
+  ""
+  "")
+
+(define_insn "*negqi2"
+  [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ")
+       (neg:QI (match_operand:QI 1 "h8300_dst_operand" "0")))]
   ""
   "neg %X0"
-  [(set_attr "length" "2")
+  [(set_attr "length_table" "unary")
    (set_attr "cc" "set_zn")])
 
 (define_expand "neghi2"
   "operands[2] = gen_reg_rtx (HImode);")
 
 (define_insn "*neghi2_h8300hs"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (neg:HI (match_operand:HI 1 "register_operand" "0")))]
-  "TARGET_H8300H || TARGET_H8300S"
-  "neg %T0"
-  [(set_attr "length" "2")
+  [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ")
+       (neg:HI (match_operand:HI 1 "h8300_dst_operand" "0")))]
+  "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)"
+  "neg.w       %T0"
+  [(set_attr "length_table" "unary")
    (set_attr "cc" "set_zn")])
 
 (define_expand "negsi2"
   "operands[2] = gen_reg_rtx (SImode);")
 
 (define_insn "*negsi2_h8300hs"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (neg:SI (match_operand:SI 1 "register_operand" "0")))]
-  "TARGET_H8300H || TARGET_H8300S"
-  "neg %S0"
-  [(set_attr "length" "2")
+  [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ")
+       (neg:SI (match_operand:SI 1 "h8300_dst_operand" "0")))]
+  "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)"
+  "neg.l       %S0"
+  [(set_attr "length_table" "unary")
    (set_attr "cc" "set_zn")])
 
 (define_expand "negsf2"
 ;; NOT INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
-(define_insn "one_cmplqi2"
-  [(set (match_operand:QI 0 "register_operand" "=r")
-       (not:QI (match_operand:QI 1 "register_operand" "0")))]
+(define_expand "one_cmplqi2"
+  [(set (match_operand:QI 0 "register_operand" "")
+       (not:QI (match_operand:QI 1 "register_operand" "")))]
+  ""
+  "")
+
+(define_insn "*one_cmplqi2"
+  [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ")
+       (not:QI (match_operand:QI 1 "h8300_dst_operand" "0")))]
   ""
   "not %X0"
-  [(set_attr "length" "2")
+  [(set_attr "length_table" "unary")
    (set_attr "cc" "set_znv")])
 
 (define_expand "one_cmplhi2"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (not:HI (match_operand:HI 1 "register_operand" "0")))]
+  [(set (match_operand:HI 0 "register_operand" "")
+       (not:HI (match_operand:HI 1 "register_operand" "")))]
   ""
   "")
 
   [(set_attr "length" "4")])
 
 (define_insn "*one_cmplhi2_h8300hs"
-  [(set (match_operand:HI 0 "register_operand" "=r")
-       (not:HI (match_operand:HI 1 "register_operand" "0")))]
-  "TARGET_H8300H || TARGET_H8300S"
-  "not %T0"
+  [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ")
+       (not:HI (match_operand:HI 1 "h8300_dst_operand" "0")))]
+  "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)"
+  "not.w       %T0"
   [(set_attr "cc" "set_znv")
-   (set_attr "length" "2")])
+   (set_attr "length_table" "unary")])
 
 (define_expand "one_cmplsi2"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (not:SI (match_operand:SI 1 "register_operand" "0")))]
+  [(set (match_operand:SI 0 "register_operand" "")
+       (not:SI (match_operand:SI 1 "register_operand" "")))]
   ""
   "")
 
   [(set_attr "length" "8")])
 
 (define_insn "*one_cmplsi2_h8300hs"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (not:SI (match_operand:SI 1 "register_operand" "0")))]
-  "TARGET_H8300H || TARGET_H8300S"
-  "not %S0"
+  [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ")
+       (not:SI (match_operand:SI 1 "h8300_dst_operand" "0")))]
+  "(TARGET_H8300H || TARGET_H8300S) && h8300_operands_match_p (operands)"
+  "not.l       %S0"
   [(set_attr "cc" "set_znv")
-   (set_attr "length" "2")])
+   (set_attr "length_table" "unary")])
 \f
 ;; ----------------------------------------------------------------------
 ;; JUMP INSTRUCTIONS
   [(set_attr "type" "branch")
    (set_attr "cc" "none")])
 
+(define_insn "*brabc"
+  [(set (pc)
+       (if_then_else
+        (eq (zero_extract (match_operand:QI 1 "bit_memory_operand" "WU")
+                          (const_int 1)
+                          (match_operand:QI 2 "immediate_operand" "n"))
+            (const_int 0))
+        (label_ref (match_operand 0 "" ""))
+        (pc)))]
+  "TARGET_H8300SX"
+  "*
+{
+  switch (get_attr_length (insn)
+         - h8300_insn_length_from_table (insn, operands))
+    {
+    case 2:
+      return \"bra/bc  %2,%R1,%l0\";
+
+    case 4:
+      return \"bra/bc  %2,%R1,%l0:16\";
+
+    default:
+      return \"bra/bs  %2,%R1,.Lh8BR%=\;jmp    @%l0\\n.Lh8BR%=:\";
+    }
+}"
+  [(set_attr "type" "bitbranch")
+   (set_attr "length_table" "bitbranch")
+   (set_attr "cc" "none")])
+
+(define_insn "*brabs"
+  [(set (pc)
+       (if_then_else
+        (ne (zero_extract (match_operand:QI 1 "bit_memory_operand" "WU")
+                          (const_int 1)
+                          (match_operand:QI 2 "immediate_operand" "n"))
+            (const_int 0))
+        (label_ref (match_operand 0 "" ""))
+        (pc)))]
+  "TARGET_H8300SX"
+  "*
+{
+  switch (get_attr_length (insn)
+         - h8300_insn_length_from_table (insn, operands))
+    {
+    case 2:
+      return \"bra/bs  %2,%R1,%l0\";
+
+    case 4:
+      return \"bra/bs  %2,%R1,%l0:16\";
+
+    default:
+      return \"bra/bc  %2,%R1,.Lh8BR%=\;jmp    @%l0\\n.Lh8BR%=:\";
+    }
+}"
+  [(set_attr "type" "bitbranch")
+   (set_attr "length_table" "bitbranch")
+   (set_attr "cc" "none")])
+
 ;; Unconditional and other jump instructions.
 
 (define_insn "jump"
   ""
   "*
 {
-  if (get_attr_length (insn) == 2)
+  if (final_sequence != 0)
+    {
+      if (get_attr_length (insn) == 2)
+       return \"bra/s  %l0\";
+      else
+       {
+         /* The branch isn't short enough to use bra/s.  Output the
+            branch and delay slot in their normal order.
+
+            If this is a backward branch, it will now be branching two
+            bytes further than previously thought.  The length-based
+            test for bra vs. jump is very conservative though, so the
+            branch will still be within range.  */
+         rtvec vec;
+         int seen;
+
+         vec = XVEC (final_sequence, 0);
+         final_sequence = 0;
+         final_scan_insn (RTVEC_ELT (vec, 1), asm_out_file, optimize, 0, 1, & seen);
+         final_scan_insn (RTVEC_ELT (vec, 0), asm_out_file, optimize, 0, 1, & seen);
+         INSN_DELETED_P (RTVEC_ELT (vec, 1)) = 1;
+         return \"\";
+       }
+    }
+  else if (get_attr_length (insn) == 2)
     return \"bra       %l0\";
   else if (get_attr_length (insn) == 4)
     return \"bra       %l0:16\";
     return \"jmp       @%l0\";
 }"
   [(set_attr "type" "branch")
+   (set (attr "delay_slot")
+       (if_then_else (ne (symbol_ref "TARGET_H8300SX") (const_int 0))
+                     (const_string "jump")
+                     (const_string "none")))
    (set_attr "cc" "none")])
 
 ;; This is a define expand, because pointers may be either 16 or 32 bits.
   else
     return \"jsr\\t%0\";
 }"
-  [(set (attr "length")
+  [(set_attr "type" "call")
+   (set (attr "length")
        (if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
                      (const_int 2)
                      (const_int 4)))])
   else
     return \"jsr\\t%1\";
 }"
-  [(set (attr "length")
+  [(set_attr "type" "call")
+   (set (attr "length")
        (if_then_else (match_operand:QI 0 "small_call_insn_operand" "")
                      (const_int 2)
                      (const_int 4)))])
 
 (define_expand "push_h8300hs_advanced"
   [(set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
-        (match_operand:SI 0 "register_operand" ""))]
-  "TARGET_H8300H && TARGET_H8300S && !TARGET_NORMAL_MODE"
-  "")
-
-(define_expand "push_h8300hs_normal"
-  [(set (mem:SI (pre_dec:HI (reg:HI SP_REG)))
-        (match_operand:SI 0 "register_operand" ""))]
-  "TARGET_H8300H && TARGET_H8300S && TARGET_NORMAL_MODE"
-  "")
-
-(define_expand "pop_h8300"
-  [(set (match_operand:HI 0 "register_operand" "")
-       (mem:HI (post_inc:HI (reg:HI SP_REG))))]
-  "TARGET_H8300"
-  "")
-
-(define_expand "pop_h8300hs_advanced"
-  [(set (match_operand:SI 0 "register_operand" "")
-       (mem:SI (post_inc:SI (reg:SI SP_REG))))]
-  "TARGET_H8300H && TARGET_H8300S && !TARGET_NORMAL_MODE"
-  "")
-
-(define_expand "pop_h8300hs_normal"
-  [(set (match_operand:SI 0 "register_operand" "")
-       (mem:SI (post_inc:HI (reg:HI SP_REG))))]
-  "TARGET_H8300H && TARGET_H8300S && TARGET_NORMAL_MODE"
-  "")
-
-(define_insn "stm_h8300s_2_advanced"
-  [(set (reg:SI SP_REG)
-       (plus:SI (reg:SI SP_REG) (const_int -8)))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8)))
-       (match_operand:SI 1 "register_operand" ""))]
-  "TARGET_H8300S && !TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (2, operands)"
-  "stm.l\\t%S0-%S1,@-er7"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
-
-(define_insn "stm_h8300s_2_normal"
-  [(set (reg:HI SP_REG)
-       (plus:HI (reg:HI SP_REG) (const_int -8)))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -8)))
-       (match_operand:SI 1 "register_operand" ""))]
-  "TARGET_H8300S && TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (2, operands)"
-  "stm.l\\t%S0-%S1,@-er7"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
-
-(define_expand "stm_h8300s_2"
-  [(match_operand:SI 0 "register_operand" "")
-   (match_operand:SI 1 "register_operand" "")]
-  "TARGET_H8300S
-   && h8300_regs_ok_for_stm (2, operands)"
-  "
-{
-  if (!TARGET_NORMAL_MODE)
-    emit_insn (gen_stm_h8300s_2_advanced (operands[0], operands[1]));
-  else
-    emit_insn (gen_stm_h8300s_2_normal (operands[0], operands[1]));
-  DONE;
-}")
-
-(define_insn "stm_h8300s_3_advanced"
-  [(set (reg:SI SP_REG)
-       (plus:SI (reg:SI SP_REG) (const_int -12)))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8)))
-       (match_operand:SI 1 "register_operand" ""))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -12)))
-       (match_operand:SI 2 "register_operand" ""))]
-  "TARGET_H8300S && !TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (3, operands)"
-  "stm.l\\t%S0-%S2,@-er7"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
-
-(define_insn "stm_h8300s_3_normal"
-  [(set (reg:HI SP_REG)
-       (plus:HI (reg:HI SP_REG) (const_int -12)))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -8)))
-       (match_operand:SI 1 "register_operand" ""))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -12)))
-       (match_operand:SI 2 "register_operand" ""))]
-  "TARGET_H8300S && TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (3, operands)"
-  "stm.l\\t%S0-%S2,@-er7"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
-
-(define_expand "stm_h8300s_3"
-  [(match_operand:SI 0 "register_operand" "")
-   (match_operand:SI 1 "register_operand" "")
-   (match_operand:SI 2 "register_operand" "")]
-  "TARGET_H8300S
-   && h8300_regs_ok_for_stm (3, operands)"
-  "
-{
-  if (!TARGET_NORMAL_MODE)
-    emit_insn (gen_stm_h8300s_3_advanced (operands[0], operands[1],
-                                         operands[2]));
-  else
-    emit_insn (gen_stm_h8300s_3_normal (operands[0], operands[1],
-                                       operands[2]));
-  DONE;
-}")
-
-(define_insn "stm_h8300s_4_advanced"
-  [(set (reg:SI SP_REG)
-       (plus:SI (reg:SI SP_REG) (const_int -16)))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8)))
-       (match_operand:SI 1 "register_operand" ""))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -12)))
-       (match_operand:SI 2 "register_operand" ""))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -16)))
-       (match_operand:SI 3 "register_operand" ""))]
-  "TARGET_H8300S && !TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (4, operands)"
-  "stm.l\\t%S0-%S3,@-er7"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
-
-(define_insn "stm_h8300s_4_normal"
-  [(set (reg:HI SP_REG)
-       (plus:HI (reg:HI SP_REG) (const_int -16)))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -8)))
-       (match_operand:SI 1 "register_operand" ""))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -12)))
-       (match_operand:SI 2 "register_operand" ""))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -16)))
-       (match_operand:SI 3 "register_operand" ""))]
-  "TARGET_H8300S && TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (4, operands)"
-  "stm.l\\t%S0-%S3,@-er7"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
-
-(define_expand "stm_h8300s_4"
-  [(match_operand:SI 0 "register_operand" "")
-   (match_operand:SI 1 "register_operand" "")
-   (match_operand:SI 2 "register_operand" "")
-   (match_operand:SI 3 "register_operand" "")]
-  "TARGET_H8300S
-   && h8300_regs_ok_for_stm (4, operands)"
-  "
-{
-  if (!TARGET_NORMAL_MODE)
-    emit_insn (gen_stm_h8300s_4_advanced (operands[0], operands[1],
-                                         operands[2], operands[3]));
-  else
-    emit_insn (gen_stm_h8300s_4_normal (operands[0], operands[1],
-                                       operands[2], operands[3]));
-  DONE;
-}")
-
-(define_insn "ldm_h8300s_2_advanced"
-  [(set (reg:SI SP_REG)
-       (plus:SI (reg:SI SP_REG) (const_int 8)))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int 4)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (reg:SI SP_REG))
-       (match_operand:SI 1 "register_operand" ""))]
-  "TARGET_H8300S && !TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (2, operands)"
-  "ldm.l\\t@er7+,%S0-%S1"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
-
-(define_insn "ldm_h8300s_2_normal"
-  [(set (reg:HI SP_REG)
-       (plus:HI (reg:HI SP_REG) (const_int 8)))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int 4)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (reg:HI SP_REG))
-       (match_operand:SI 1 "register_operand" ""))]
-  "TARGET_H8300S && TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (2, operands)"
-  "ldm.l\\t@er7+,%S0-%S1"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
-
-(define_expand "ldm_h8300s_2"
-  [(match_operand:SI 0 "register_operand" "")
-   (match_operand:SI 1 "register_operand" "")]
-  "TARGET_H8300S
-   && h8300_regs_ok_for_stm (2, operands)"
-  "
-{
-  if (!TARGET_NORMAL_MODE)
-    emit_insn (gen_ldm_h8300s_2_advanced (operands[0], operands[1]));
-  else
-    emit_insn (gen_ldm_h8300s_2_normal (operands[0], operands[1]));
-  DONE;
-}")
+        (match_operand:SI 0 "register_operand" ""))]
+  "TARGET_H8300H && TARGET_H8300S && !TARGET_NORMAL_MODE"
+  "")
 
-(define_insn "ldm_h8300s_3_advanced"
-  [(set (reg:SI SP_REG)
-       (plus:SI (reg:SI SP_REG) (const_int 12)))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int 8)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int 4)))
-       (match_operand:SI 1 "register_operand" ""))
-   (set (mem:SI (reg:SI SP_REG))
-       (match_operand:SI 2 "register_operand" ""))]
-  "TARGET_H8300S && !TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (3, operands)"
-  "ldm.l\\t@er7+,%S0-%S2"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
+(define_expand "push_h8300hs_normal"
+  [(set (mem:SI (pre_dec:HI (reg:HI SP_REG)))
+        (match_operand:SI 0 "register_operand" ""))]
+  "TARGET_H8300H && TARGET_H8300S && TARGET_NORMAL_MODE"
+  "")
 
-(define_insn "ldm_h8300s_3_normal"
-  [(set (reg:HI SP_REG)
-       (plus:HI (reg:HI SP_REG) (const_int 12)))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int 8)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int 4)))
-       (match_operand:SI 1 "register_operand" ""))
-   (set (mem:SI (reg:HI SP_REG))
-       (match_operand:SI 2 "register_operand" ""))]
-  "TARGET_H8300S && TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (3, operands)"
-  "ldm.l\\t@er7+,%S0-%S2"
-  [(set_attr "cc" "none")
-   (set_attr "length" "4")])
+(define_expand "pop_h8300"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (mem:HI (post_inc:HI (reg:HI SP_REG))))]
+  "TARGET_H8300"
+  "")
 
-(define_expand "ldm_h8300s_3"
-  [(match_operand:SI 0 "register_operand" "")
-   (match_operand:SI 1 "register_operand" "")
-   (match_operand:SI 2 "register_operand" "")]
-  "TARGET_H8300S
-   && h8300_regs_ok_for_stm (3, operands)"
-  "
-{
-  if (!TARGET_NORMAL_MODE)
-    emit_insn (gen_ldm_h8300s_3_advanced (operands[0], operands[1],
-                                         operands[2]));
-  else
-    emit_insn (gen_ldm_h8300s_3_normal (operands[0], operands[1],
-                                       operands[2]));
-  DONE;
-}")
+(define_expand "pop_h8300hs_advanced"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (mem:SI (post_inc:SI (reg:SI SP_REG))))]
+  "TARGET_H8300H && TARGET_H8300S && !TARGET_NORMAL_MODE"
+  "")
 
-(define_insn "ldm_h8300s_4_advanced"
-  [(set (reg:SI SP_REG)
-       (plus:SI (reg:SI SP_REG) (const_int 16)))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int 12)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int 8)))
-       (match_operand:SI 1 "register_operand" ""))
-   (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int 4)))
-       (match_operand:SI 2 "register_operand" ""))
-   (set (mem:SI (reg:SI SP_REG))
-       (match_operand:SI 3 "register_operand" ""))]
-  "TARGET_H8300S && !TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (4, operands)"
-  "ldm.l\\t@er7+,%S0-%S3"
+(define_expand "pop_h8300hs_normal"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (mem:SI (post_inc:HI (reg:HI SP_REG))))]
+  "TARGET_H8300H && TARGET_H8300S && TARGET_NORMAL_MODE"
+  "")
+
+(define_insn "ldm_h8300sx"
+  [(match_parallel           0 "h8300_ldm_parallel"
+     [(set (match_operand:SI 1 "register_operand" "")
+          (match_operand:SI 2 "memory_operand" ""))])]
+  "TARGET_H8300S"
+  {
+    operands[3] = SET_DEST (XVECEXP (operands[0], 0,
+                                    XVECLEN (operands[0], 0) - 2));
+    return "ldm.l\t@er7+,%S1-%S3";
+  }
   [(set_attr "cc" "none")
    (set_attr "length" "4")])
 
-(define_insn "ldm_h8300s_4_normal"
-  [(set (reg:HI SP_REG)
-       (plus:HI (reg:HI SP_REG) (const_int 16)))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int 12)))
-       (match_operand:SI 0 "register_operand" ""))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int 8)))
-       (match_operand:SI 1 "register_operand" ""))
-   (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int 4)))
-       (match_operand:SI 2 "register_operand" ""))
-   (set (mem:SI (reg:HI SP_REG))
-       (match_operand:SI 3 "register_operand" ""))]
-  "TARGET_H8300S && TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (4, operands)"
-  "ldm.l\\t@er7+,%S0-%S3"
+(define_insn "stm_h8300sx"
+  [(match_parallel           0 "h8300_stm_parallel"
+     [(set (match_operand:SI 1 "memory_operand" "")
+          (match_operand:SI 2 "register_operand" ""))])]
+  "TARGET_H8300S"
+  {
+    operands[3] = SET_SRC (XVECEXP (operands[0], 0,
+                                   XVECLEN (operands[0], 0) - 2));
+    return "stm.l\t%S2-%S3,@-er7";
+  }
   [(set_attr "cc" "none")
    (set_attr "length" "4")])
 
-(define_expand "ldm_h8300s_4"
-  [(match_operand:SI 0 "register_operand" "")
-   (match_operand:SI 1 "register_operand" "")
-   (match_operand:SI 2 "register_operand" "")
-   (match_operand:SI 3 "register_operand" "")]
-  "TARGET_H8300S
-   && h8300_regs_ok_for_stm (4, operands)"
-  "
-{
-  if (!TARGET_NORMAL_MODE)
-    emit_insn (gen_ldm_h8300s_4_advanced (operands[0], operands[1],
-                                         operands[2], operands[3]));
-  else
-    emit_insn (gen_ldm_h8300s_4_normal (operands[0], operands[1],
-                                       operands[2], operands[3]));
-  DONE;
-}")
+(define_insn "return_h8sx"
+  [(match_parallel           0 "h8300_return_parallel"
+     [(return)
+      (set (match_operand:SI 1 "register_operand" "")
+          (match_operand:SI 2 "memory_operand" ""))])]
+  "TARGET_H8300SX"
+  {
+    operands[3] = SET_DEST (XVECEXP (operands[0], 0,
+                                    XVECLEN (operands[0], 0) - 2));
+    if (h8300_current_function_interrupt_function_p ())
+      return "rte/l\t%S1-%S3";
+    else
+      return "rts/l\t%S1-%S3";
+  }
+  [(set_attr "cc" "none")
+   (set_attr "can_delay" "no")
+   (set_attr "length" "2")])
 
 (define_expand "return"
   [(return)]
     return \"rts\";
 }"
   [(set_attr "cc" "none")
+   (set_attr "can_delay" "no")
    (set_attr "length" "2")])
 
 (define_expand "prologue"
 (define_expand "epilogue"
   [(return)]
   ""
-  "h8300_expand_epilogue ();")
+  "h8300_expand_epilogue (); DONE;")
 
 (define_insn "monitor_prologue"
   [(unspec_volatile [(const_int 0)] UNSPEC_MONITOR)]
   [(set (match_operand:SI 0 "register_operand" "")
        (zero_extend:SI (match_operand:QI 1 "general_operand_src" "")))]
   ""
-  "")
+  {
+    if (TARGET_H8300SX)
+      operands[1] = force_reg (QImode, operands[1]);
+  })
 
 (define_insn "*zero_extendqisi2_h8300"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
 (define_insn "*zero_extendqisi2_h8300hs"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
        (zero_extend:SI (match_operand:QI 1 "general_operand_src" "0,g>")))]
-  "TARGET_H8300H || TARGET_H8300S"
+  "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX"
   "#")
 
 (define_split
   [(set (match_operand:SI 0 "register_operand" "")
        (zero_extend:SI (match_operand:QI 1 "general_operand_src" "")))]
-  "(TARGET_H8300H || TARGET_H8300S)
+  "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX
    && reg_overlap_mentioned_p (operands[0], operands[1])
    && reload_completed"
   [(set (match_dup 2)
 (define_split
   [(set (match_operand:SI 0 "register_operand" "")
        (zero_extend:SI (match_operand:QI 1 "general_operand_src" "")))]
-  "(TARGET_H8300H || TARGET_H8300S)
+  "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX
    && !reg_overlap_mentioned_p (operands[0], operands[1])
    && reload_completed"
   [(set (match_dup 0)
        (match_dup 1))]
   "operands[2] = gen_rtx_REG (QImode, REGNO (operands[0]));")
 
+(define_insn "*zero_extendqisi2_h8sx"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (zero_extend:SI (match_operand:QI 1 "register_operand" "0")))]
+  "TARGET_H8300SX"
+  "extu.l\t#2,%0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_znv")])
+
 (define_expand "zero_extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "")
        (zero_extend:SI (match_operand:HI 1 "register_operand" "")))]
 (define_insn_and_split "*extendqisi2_h8300hs"
   [(set (match_operand:SI 0 "register_operand" "=r")
        (sign_extend:SI (match_operand:QI 1 "register_operand" "0")))]
-  "(TARGET_H8300H || TARGET_H8300S)"
+  "(TARGET_H8300H || TARGET_H8300S) && !TARGET_H8300SX"
   "#"
   "&& reload_completed"
   [(set (match_dup 2)
        (sign_extend:SI (match_dup 2)))]
   "operands[2] = gen_rtx_REG (HImode, REGNO (operands[0]));")
 
+(define_insn "*extendqisi2_h8sx"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (sign_extend:SI (match_operand:QI 1 "register_operand" "0")))]
+  "TARGET_H8300SX"
+  "exts.l\t#2,%0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "set_znv")])
+
 (define_expand "extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "")
        (sign_extend:SI (match_operand:HI 1 "register_operand" "")))]
        (ashift:QI (match_operand:QI 1 "register_operand" "")
                   (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "expand_a_shift (QImode, ASHIFT, operands); DONE;")
+  "if (expand_a_shift (QImode, ASHIFT, operands)) DONE;")
 
 (define_expand "ashrqi3"
   [(set (match_operand:QI 0 "register_operand" "")
        (ashiftrt:QI (match_operand:QI 1 "register_operand" "")
                     (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "expand_a_shift (QImode, ASHIFTRT, operands); DONE;")
+  "if (expand_a_shift (QImode, ASHIFTRT, operands)) DONE;")
 
 (define_expand "lshrqi3"
   [(set (match_operand:QI 0 "register_operand" "")
        (lshiftrt:QI (match_operand:QI 1 "register_operand" "")
                     (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "expand_a_shift (QImode, LSHIFTRT, operands); DONE;")
+  "if (expand_a_shift (QImode, LSHIFTRT, operands)) DONE;")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "h8300_dst_operand" "=rQ")
+       (match_operator:QI 3 "h8sx_unary_shift_operator"
+                       [(match_operand:QI 1 "h8300_dst_operand" "0")
+                        (match_operand:QI 2 "const_int_operand" "")]))]
+  "h8300_operands_match_p (operands)"
+  { return output_h8sx_shift (operands, 'b', 'X'); }
+  [(set_attr "length_table" "unary")
+   (set_attr "cc" "set_znv")])
+
+(define_insn ""
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (match_operator:QI 3 "h8sx_binary_shift_operator"
+                       [(match_operand:QI 1 "register_operand" "0")
+                        (match_operand:QI 2 "nonmemory_operand" "r P3>X")]))]
+  ""
+  { return output_h8sx_shift (operands, 'b', 'X'); }
+  [(set_attr "length" "4")
+   (set_attr "cc" "set_znv")])
 
 (define_insn "*shiftqi"
   [(set (match_operand:QI 0 "register_operand" "=r,r")
 
 (define_expand "ashlhi3"
   [(set (match_operand:HI 0 "register_operand" "")
-       (ashift:HI (match_operand:HI 1 "nonmemory_operand" "")
+       (ashift:HI (match_operand:HI 1 "register_operand" "")
                   (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "expand_a_shift (HImode, ASHIFT, operands); DONE;")
+  "if (expand_a_shift (HImode, ASHIFT, operands)) DONE;")
 
 (define_expand "lshrhi3"
   [(set (match_operand:HI 0 "register_operand" "")
-       (lshiftrt:HI (match_operand:HI 1 "general_operand" "")
+       (lshiftrt:HI (match_operand:HI 1 "register_operand" "")
                     (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "expand_a_shift (HImode, LSHIFTRT, operands); DONE;")
+  "if (expand_a_shift (HImode, LSHIFTRT, operands)) DONE;")
 
 (define_expand "ashrhi3"
   [(set (match_operand:HI 0 "register_operand" "")
        (ashiftrt:HI (match_operand:HI 1 "register_operand" "")
                     (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "expand_a_shift (HImode, ASHIFTRT, operands); DONE;")
+  "if (expand_a_shift (HImode, ASHIFTRT, operands)) DONE;")
+
+(define_insn ""
+  [(set (match_operand:HI 0 "h8300_dst_operand" "=rQ")
+       (match_operator:HI 3 "h8sx_unary_shift_operator"
+                       [(match_operand:HI 1 "h8300_dst_operand" "0")
+                        (match_operand:QI 2 "const_int_operand" "")]))]
+  "h8300_operands_match_p (operands)"
+  { return output_h8sx_shift (operands, 'w', 'T'); }
+  [(set_attr "length_table" "unary")
+   (set_attr "cc" "set_znv")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (match_operator:HI 3 "h8sx_binary_shift_operator"
+                       [(match_operand:HI 1 "register_operand" "0")
+                        (match_operand:QI 2 "nonmemory_operand" "r P4>X")]))]
+  ""
+  { return output_h8sx_shift (operands, 'w', 'T'); }
+  [(set_attr "length" "4")
+   (set_attr "cc" "set_znv")])
 
 (define_insn "*shifthi"
   [(set (match_operand:HI 0 "register_operand" "=r,r")
 
 (define_expand "ashlsi3"
   [(set (match_operand:SI 0 "register_operand" "")
-       (ashift:SI (match_operand:SI 1 "general_operand" "")
+       (ashift:SI (match_operand:SI 1 "register_operand" "")
                   (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "expand_a_shift (SImode, ASHIFT, operands); DONE;")
+  "if (expand_a_shift (SImode, ASHIFT, operands)) DONE;")
 
 (define_expand "lshrsi3"
   [(set (match_operand:SI 0 "register_operand" "")
-       (lshiftrt:SI (match_operand:SI 1 "general_operand" "")
+       (lshiftrt:SI (match_operand:SI 1 "register_operand" "")
                     (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "expand_a_shift (SImode, LSHIFTRT, operands); DONE;")
+  "if (expand_a_shift (SImode, LSHIFTRT, operands)) DONE;")
 
 (define_expand "ashrsi3"
   [(set (match_operand:SI 0 "register_operand" "")
-       (ashiftrt:SI (match_operand:SI 1 "general_operand" "")
+       (ashiftrt:SI (match_operand:SI 1 "register_operand" "")
                     (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "expand_a_shift (SImode, ASHIFTRT, operands); DONE;")
+  "if (expand_a_shift (SImode, ASHIFTRT, operands)) DONE;")
+
+(define_insn ""
+  [(set (match_operand:SI 0 "h8300_dst_operand" "=rQ")
+       (match_operator:SI 3 "h8sx_unary_shift_operator"
+                       [(match_operand:SI 1 "h8300_dst_operand" "0")
+                        (match_operand:QI 2 "const_int_operand" "")]))]
+  "h8300_operands_match_p (operands)"
+  { return output_h8sx_shift (operands, 'l', 'S'); }
+  [(set_attr "length_table" "unary")
+   (set_attr "cc" "set_znv")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (match_operator:SI 3 "h8sx_binary_shift_operator"
+                       [(match_operand:SI 1 "register_operand" "0")
+                        (match_operand:QI 2 "nonmemory_operand" "r P5>X")]))]
+  ""
+  { return output_h8sx_shift (operands, 'l', 'S'); }
+  [(set_attr "length" "4")
+   (set_attr "cc" "set_znv")])
 
 (define_insn "*shiftsi"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
        (rotate:QI (match_operand:QI 1 "register_operand" "")
                   (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "if (expand_a_rotate (operands)) DONE; else FAIL;")
+  "if (expand_a_rotate (operands)) DONE;")
 
 (define_insn "rotlqi3_1"
   [(set (match_operand:QI 0 "register_operand" "=r")
        (rotate:HI (match_operand:HI 1 "register_operand" "")
                   (match_operand:QI 2 "nonmemory_operand" "")))]
   ""
-  "if (expand_a_rotate (operands)) DONE; else FAIL;")
+  "if (expand_a_rotate (operands)) DONE;")
 
 (define_insn "rotlhi3_1"
   [(set (match_operand:HI 0 "register_operand" "=r")
        (rotate:SI (match_operand:SI 1 "register_operand" "")
                   (match_operand:QI 2 "nonmemory_operand" "")))]
   "TARGET_H8300H || TARGET_H8300S"
-  "if (expand_a_rotate (operands)) DONE; else FAIL;")
+  "if (expand_a_rotate (operands)) DONE;")
 
 (define_insn "rotlsi3_1"
   [(set (match_operand:SI 0 "register_operand" "=r")
                         (match_operand:HI 1 "general_operand" "")
                         (match_operand:HI 2 "general_operand" ""))
        (match_operand:HI 3 "general_operand" ""))]
-  "TARGET_H8300"
+  "TARGET_H8300 || TARGET_H8300SX"
   "
 {
+  if (TARGET_H8300SX)
+    {
+      if (GET_CODE (operands[1]) == CONST_INT
+          && GET_CODE (operands[2]) == CONST_INT
+          && INTVAL (operands[1]) <= 8
+          && INTVAL (operands[2]) >= 0
+          && INTVAL (operands[1]) + INTVAL (operands[2]) <= 8
+         && memory_operand (operands[0], GET_MODE (operands[0])))
+        {
+         /* If the source operand is zero, it's better to use AND rather
+            than BFST.  Likewise OR if the operand is all ones.  */
+         if (GET_CODE (operands[3]) == CONST_INT)
+           {
+             HOST_WIDE_INT mask = (1 << INTVAL (operands[1])) - 1;
+             if ((INTVAL (operands[3]) & mask) == 0)
+               FAIL;
+             if ((INTVAL (operands[3]) & mask) == mask)
+               FAIL;
+           }
+          if (! bit_memory_operand (operands[0], GET_MODE (operands[0])))
+           {
+             if (no_new_pseudos)
+               FAIL;
+             operands[0] =
+               replace_equiv_address (operands[0],
+                                      force_reg (Pmode,
+                                                 XEXP (operands[0], 0)));
+           }
+         operands[3] = gen_lowpart (QImode, operands[3]);
+         if (! operands[3])
+           FAIL;
+         if (! register_operand (operands[3], QImode))
+           {
+             if (no_new_pseudos)
+               FAIL;
+             operands[3] = force_reg (QImode, operands[3]);
+           }
+         emit_insn (gen_bfst (adjust_address (operands[0], QImode, 0),
+                              operands[3], operands[1], operands[2]));
+         DONE;
+        }
+
+      FAIL;
+    }
+
   /* We only have single bit bit-field instructions.  */
   if (INTVAL (operands[1]) != 1)
     FAIL;
        (zero_extract:HI (match_operand:HI 1 "bit_operand" "")
                         (match_operand:HI 2 "general_operand" "")
                         (match_operand:HI 3 "general_operand" "")))]
-  "TARGET_H8300"
+  "TARGET_H8300 || TARGET_H8300SX"
   "
 {
+  if (TARGET_H8300SX)
+    {
+      if (GET_CODE (operands[2]) == CONST_INT
+          && GET_CODE (operands[3]) == CONST_INT
+          && INTVAL (operands[2]) <= 8
+          && INTVAL (operands[3]) >= 0
+          && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8
+         && memory_operand (operands[1], QImode))
+       {
+         rtx temp;
+
+         /* Optimize the case where we're extracting into a paradoxical
+            subreg.  It's only necessary to extend to the inner reg.  */
+         if (GET_CODE (operands[0]) == SUBREG
+             && subreg_lowpart_p (operands[0])
+             && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (operands[0])))
+                 < GET_MODE_SIZE (GET_MODE (operands[0])))
+             && (GET_MODE_CLASS (GET_MODE (SUBREG_REG (operands[0])))
+                 == MODE_INT))
+           operands[0] = SUBREG_REG (operands[0]);
+
+         if (no_new_pseudos)
+           temp = gen_lowpart (QImode, operands[0]);
+         else
+           temp = gen_reg_rtx (QImode);
+         if (! temp)
+           FAIL;
+          if (! bit_memory_operand (operands[1], QImode))
+           {
+             if (no_new_pseudos)
+               FAIL;
+             operands[1] =
+               replace_equiv_address (operands[1],
+                                      force_reg (Pmode,
+                                                 XEXP (operands[1], 0)));
+           }
+         emit_insn (gen_bfld (temp, operands[1], operands[2], operands[3]));
+         convert_move (operands[0], temp, 1);
+         DONE;
+        }
+      FAIL;
+    }
+
   /* We only have single bit bit-field instructions.  */
   if (INTVAL (operands[2]) != 1)
     FAIL;
   ""
   "bld %Z2,%Y1\;b%c5   %Z4,%Y3\;bst    #0,%R0; bl3"
   [(set_attr "length" "6")])
+
+(define_insn "bfld"
+  [(set (match_operand:QI 0 "register_operand" "=r")
+       (zero_extract:QI (match_operand:QI 1 "bit_memory_operand" "WU")
+                        (match_operand:QI 2 "immediate_operand" "n")
+                        (match_operand:QI 3 "immediate_operand" "n")))]
+  "TARGET_H8300SX && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8"
+  "*
+{
+  operands[2] = GEN_INT ((1 << (INTVAL (operands[2]) + INTVAL (operands[3])))
+                        - (1 << INTVAL (operands[3])));
+  return \"bfld        %2,%1,%R0\";
+}"
+  [(set_attr "cc" "none_0hit")
+   (set_attr "length_table" "bitfield")])
+
+(define_insn "bfst"
+  [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU")
+                        (match_operand:QI 2 "immediate_operand" "n")
+                        (match_operand:QI 3 "immediate_operand" "n"))
+       (match_operand:QI 1 "register_operand" "r"))]
+  "TARGET_H8300SX && INTVAL (operands[2]) + INTVAL (operands[3]) <= 8"
+  "*
+{
+  operands[2] = GEN_INT ((1 << (INTVAL (operands[2]) + INTVAL (operands[3])))
+                        - (1 << INTVAL (operands[3])));
+  return \"bfst        %R1,%2,%0\";
+}"
+  [(set_attr "cc" "none_0hit")
+   (set_attr "length_table" "bitfield")])
+
+(define_expand "seq"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (eq:HI (cc0) (const_int 0)))]
+  "TARGET_H8300SX"
+  "")
+
+(define_expand "sne"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (ne:HI (cc0) (const_int 0)))]
+  "TARGET_H8300SX"
+  "")
+
+(define_insn "*bstzhireg"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (match_operator:HI 1 "eqne_operator" [(cc0) (const_int 0)]))]
+  "TARGET_H8300SX"
+  "mulu.w      #0,%T0\;b%k1    .Lh8BR%=\;inc.w #1,%T0\\n.Lh8BR%=:"
+  [(set_attr "cc" "clobber")])
+
+(define_insn_and_split "*cmpstz"
+  [(set (zero_extract:QI
+        (match_operand:QI 0 "bit_memory_operand" "+WU,+WU")
+        (const_int 1)
+        (match_operand:QI 1 "immediate_operand" "n,n"))
+       (match_operator:QI
+        2 "eqne_operator"
+        [(match_operand 3 "h8300_dst_operand" "r,rQ")
+         (match_operand 4 "h8300_src_operand" "I,rQi")]))]
+  "TARGET_H8300SX
+   && (GET_MODE (operands[3]) == GET_MODE (operands[4])
+       || GET_CODE (operands[4]) == CONST_INT)
+   && GET_MODE_CLASS (GET_MODE (operands[3])) == MODE_INT
+   && GET_MODE_SIZE (GET_MODE (operands[3])) <= 4"
+  "#"
+  "reload_completed"
+  [(set (cc0) (match_dup 5))
+   (set (zero_extract:QI (match_dup 0) (const_int 1) (match_dup 1))
+       (match_op_dup:QI 2 [(cc0) (const_int 0)]))]
+  "
+{
+  if (operands[4] == const0_rtx && GET_CODE (operands[3]) == REG)
+    operands[5] = operands[3];
+  else
+    operands[5] = gen_rtx_COMPARE (VOIDmode, operands[3], operands[4]);
+}"
+  [(set_attr "cc" "set_znv,compare")])
+   
+(define_insn "*bstz"
+  [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU")
+                        (const_int 1)
+                        (match_operand:QI 1 "immediate_operand" "n"))
+       (eq:QI (cc0) (const_int 0)))]
+  "TARGET_H8300SX && reload_completed"
+  "bstz        %1,%0"
+  [(set_attr "cc" "none_0hit")
+   (set_attr "length_table" "unary")])
+
+(define_insn "*bistz"
+  [(set (zero_extract:QI (match_operand:QI 0 "bit_memory_operand" "+WU")
+                        (const_int 1)
+                        (match_operand:QI 1 "immediate_operand" "n"))
+       (ne:QI (cc0) (const_int 0)))]
+  "TARGET_H8300SX && reload_completed"
+  "bistz       %1,%0"
+  [(set_attr "cc" "none_0hit")
+   (set_attr "length_table" "unary")])
+
+(define_insn_and_split "*cmpcondbset"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU")
+       (if_then_else:QI
+        (match_operator
+         1 "eqne_operator"
+         [(match_operand 2 "h8300_dst_operand" "r,rQ")
+          (match_operand 3 "h8300_src_operand" "I,rQi")])
+        (ior:QI
+         (match_operand:QI 4 "bit_memory_operand" "0,0")
+         (match_operand:QI 5 "single_one_operand" "n,n"))
+        (match_dup 4)))]
+  "TARGET_H8300SX"
+  "#"
+  "reload_completed"
+  [(set (cc0) (match_dup 6))
+   (set (match_dup 0)
+       (if_then_else:QI
+        (match_op_dup 1 [(cc0) (const_int 0)])
+        (ior:QI (match_dup 4) (match_dup 5)) (match_dup 4)))]
+  "
+{
+  if (operands[3] == const0_rtx && GET_CODE (operands[2]) == REG)
+    operands[6] = operands[2];
+  else
+    operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]);
+}"
+  [(set_attr "cc" "set_znv,compare")])
+   
+(define_insn "*condbset"
+  [(set (match_operand:QI 0 "bit_memory_operand" "=WU")
+       (if_then_else:QI
+        (match_operator:QI 2 "eqne_operator"
+                           [(cc0) (const_int 0)])
+        (ior:QI
+         (match_operand:QI 3 "bit_memory_operand" "0")
+         (match_operand:QI 1 "single_one_operand" "n"))
+        (match_dup 3)))]
+  "TARGET_H8300SX && reload_completed"
+  "bset/%j2\t%V1,%0"
+  [(set_attr "cc" "none_0hit")
+   (set_attr "length_table" "logicb")])
+
+(define_insn_and_split "*cmpcondbclr"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU")
+       (if_then_else:QI
+        (match_operator
+         1 "eqne_operator"
+         [(match_operand 2 "h8300_dst_operand" "r,rQ")
+          (match_operand 3 "h8300_src_operand" "I,rQi")])
+        (and:QI
+         (match_operand:QI 4 "bit_memory_operand" "0,0")
+         (match_operand:QI 5 "single_zero_operand" "n,n"))
+        (match_dup 4)))]
+  "TARGET_H8300SX"
+  "#"
+  "reload_completed"
+  [(set (cc0) (match_dup 6))
+   (set (match_dup 0)
+       (if_then_else:QI
+        (match_op_dup 1 [(cc0) (const_int 0)])
+        (and:QI (match_dup 4) (match_dup 5)) (match_dup 4)))]
+  "
+{
+  if (operands[3] == const0_rtx && GET_CODE (operands[2]) == REG)
+    operands[6] = operands[2];
+  else
+    operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]);
+}"
+  [(set_attr "cc" "set_znv,compare")])
+   
+(define_insn "*condbclr"
+  [(set (match_operand:QI 0 "bit_memory_operand" "=WU")
+       (if_then_else:QI
+        (match_operator:QI 2 "eqne_operator"
+                           [(cc0) (const_int 0)])
+        (and:QI
+         (match_operand:QI 3 "bit_memory_operand" "0")
+         (match_operand:QI 1 "single_zero_operand" "n"))
+        (match_dup 3)))]
+  "TARGET_H8300SX && reload_completed"
+  "bclr/%j2\t%W1,%0"
+  [(set_attr "cc" "none_0hit")
+   (set_attr "length_table" "logicb")])
+
+(define_insn_and_split "*cmpcondbsetreg"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU")
+       (if_then_else:QI
+        (match_operator
+         1 "eqne_operator"
+         [(match_operand 2 "h8300_dst_operand" "r,rQ")
+          (match_operand 3 "h8300_src_operand" "I,rQi")])
+        (ior:QI
+         (match_operand:QI 4 "bit_memory_operand" "0,0")
+         (ashift:QI (const_int 1)
+                    (match_operand:QI 5 "register_operand" "r,r")))
+        (match_dup 4)))]
+  "TARGET_H8300SX"
+  "#"
+  "reload_completed"
+  [(set (cc0) (match_dup 6))
+   (set (match_dup 0)
+       (if_then_else:QI
+        (match_op_dup 1 [(cc0) (const_int 0)])
+        (ior:QI (match_dup 4)
+                (ashift:QI (const_int 1)
+                           (match_operand:QI 5 "register_operand" "r,r")))
+        (match_dup 4)))]
+  "
+{
+  if (operands[3] == const0_rtx && GET_CODE (operands[2]) == REG)
+    operands[6] = operands[2];
+  else
+    operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]);
+}"
+  [(set_attr "cc" "set_znv,compare")])
+   
+(define_insn "*condbsetreg"
+  [(set (match_operand:QI 0 "bit_memory_operand" "=WU")
+       (if_then_else:QI
+        (match_operator:QI 2 "eqne_operator"
+                           [(cc0) (const_int 0)])
+        (ior:QI
+         (match_operand:QI 3 "bit_memory_operand" "0")
+         (ashift:QI (const_int 1)
+                    (match_operand:QI 1 "register_operand" "r")))
+        (match_dup 3)))]
+  "TARGET_H8300SX && reload_completed"
+  "bset/%j2\t%R1,%0"
+  [(set_attr "cc" "none_0hit")
+   (set_attr "length_table" "logicb")])
+
+(define_insn_and_split "*cmpcondbclrreg"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=WU,WU")
+       (if_then_else:QI
+        (match_operator
+         1 "eqne_operator"
+         [(match_operand 2 "h8300_dst_operand" "r,rQ")
+          (match_operand 3 "h8300_src_operand" "I,rQi")])
+        (and:QI
+         (match_operand:QI 4 "bit_memory_operand" "0,0")
+         (ashift:QI (const_int 1)
+                    (match_operand:QI 5 "register_operand" "r,r")))
+        (match_dup 4)))]
+  "TARGET_H8300SX"
+  "#"
+  "reload_completed"
+  [(set (cc0) (match_dup 6))
+   (set (match_dup 0)
+       (if_then_else:QI
+        (match_op_dup 1 [(cc0) (const_int 0)])
+        (and:QI (match_dup 4)
+                (ashift:QI (const_int 1)
+                           (match_operand:QI 5 "register_operand" "r,r")))
+        (match_dup 4)))]
+  "
+{
+  if (operands[3] == const0_rtx && GET_CODE (operands[2]) == REG)
+    operands[6] = operands[2];
+  else
+    operands[6] = gen_rtx_COMPARE (VOIDmode, operands[2], operands[3]);
+}"
+  [(set_attr "cc" "set_znv,compare")])
+   
+(define_insn "*condbclrreg"
+  [(set (match_operand:QI 0 "bit_memory_operand" "=WU")
+       (if_then_else:QI
+        (match_operator:QI 2 "eqne_operator"
+                           [(cc0) (const_int 0)])
+        (and:QI
+         (match_operand:QI 3 "bit_memory_operand" "0")
+         (ashift:QI (const_int 1)
+                    (match_operand:QI 1 "register_operand" "r")))
+        (match_dup 3)))]
+  "TARGET_H8300SX && reload_completed"
+  "bclr/%j2\t%R1,%0"
+  [(set_attr "cc" "none_0hit")
+   (set_attr "length_table" "logicb")])
+
 \f
 ;; -----------------------------------------------------------------
 ;; COMBINE PATTERNS
                    (plus:SI (reg:SI SP_REG) (const_int -4)))
               (set (mem:QI (plus:SI (reg:SI SP_REG) (const_int -3)))
                    (match_operand:QI 0 "register_operand" ""))])]
-  "TARGET_H8300S && !TARGET_NORMAL_MODE"
+  "TARGET_H8300S && !TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG"
   [(set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
        (match_dup 0))]
   "operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));")
                    (plus:HI (reg:HI SP_REG) (const_int -4)))
               (set (mem:QI (plus:HI (reg:HI SP_REG) (const_int -3)))
                    (match_operand:QI 0 "register_operand" ""))])]
-  "TARGET_H8300S && TARGET_NORMAL_MODE"
+  "TARGET_H8300S && TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG"
   [(set (mem:SI (pre_dec:HI (reg:HI SP_REG)))
        (match_dup 0))]
   "operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));")
                    (plus:SI (reg:SI SP_REG) (const_int -4)))
               (set (mem:HI (plus:SI (reg:SI SP_REG) (const_int -2)))
                    (match_operand:HI 0 "register_operand" ""))])]
-  "TARGET_H8300S && !TARGET_NORMAL_MODE"
+  "TARGET_H8300S && !TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG"
   [(set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
        (match_dup 0))]
   "operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));")
                    (plus:HI (reg:HI SP_REG) (const_int -4)))
               (set (mem:HI (plus:HI (reg:HI SP_REG) (const_int -2)))
                    (match_operand:HI 0 "register_operand" ""))])]
-  "TARGET_H8300S && TARGET_NORMAL_MODE"
+  "TARGET_H8300S && TARGET_NORMAL_MODE && REGNO (operands[0]) != SP_REG"
   [(set (mem:SI (pre_dec:HI (reg:HI SP_REG)))
        (match_dup 0))]
   "operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));")
    (set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
        (match_operand:SI 3 "register_operand" ""))]
   "TARGET_H8300S && !TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (4, operands)"
-  [(parallel [(set (reg:SI SP_REG)
-                  (plus:SI (reg:SI SP_REG)
-                           (const_int -16)))
-             (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4)))
+   && (REGNO_REG_CLASS (REGNO (operands[3])) == GENERAL_REGS
+       && REGNO (operands[1]) == REGNO (operands[0]) + 1
+       && REGNO (operands[2]) == REGNO (operands[0]) + 2
+       && REGNO (operands[3]) == REGNO (operands[0]) + 3
+       && (TARGET_H8300SX || REGNO (operands[0]) == 0))"
+  [(parallel [(set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4)))
                   (match_dup 0))
              (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8)))
                   (match_dup 1))
              (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -12)))
                   (match_dup 2))
              (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -16)))
-                  (match_dup 3))])]
+                  (match_dup 3))
+             (set (reg:SI SP_REG)
+                  (plus:SI (reg:SI SP_REG)
+                           (const_int -16)))])]
   "")
 
 (define_peephole2
    (set (mem:SI (pre_dec:HI (reg:HI SP_REG)))
        (match_operand:SI 3 "register_operand" ""))]
   "TARGET_H8300S && TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (4, operands)"
-  [(parallel [(set (reg:HI SP_REG)
-                  (plus:HI (reg:HI SP_REG)
-                           (const_int -16)))
-             (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4)))
+   && (REGNO_REG_CLASS (REGNO (operands[3])) == GENERAL_REGS
+       && REGNO (operands[1]) == REGNO (operands[0]) + 1
+       && REGNO (operands[2]) == REGNO (operands[0]) + 2
+       && REGNO (operands[3]) == REGNO (operands[0]) + 3
+       && (TARGET_H8300SX || REGNO (operands[0]) == 0))"
+  [(parallel [(set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4)))
                   (match_dup 0))
              (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -8)))
                   (match_dup 1))
              (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -12)))
                   (match_dup 2))
              (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -16)))
-                  (match_dup 3))])]
+                  (match_dup 3))
+             (set (reg:HI SP_REG)
+                  (plus:HI (reg:HI SP_REG)
+                           (const_int -16)))])]
   "")
 
 ;; Cram three pushes into stm.l.
    (set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
        (match_operand:SI 2 "register_operand" ""))]
   "TARGET_H8300S && !TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (3, operands)"
-  [(parallel [(set (reg:SI SP_REG)
-                  (plus:SI (reg:SI SP_REG)
-                           (const_int -12)))
-             (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4)))
+   && (REGNO_REG_CLASS (REGNO (operands[2])) == GENERAL_REGS
+       && REGNO (operands[1]) == REGNO (operands[0]) + 1
+       && REGNO (operands[2]) == REGNO (operands[0]) + 2
+       && (TARGET_H8300SX || (REGNO (operands[0]) & 3) == 0))"
+  [(parallel [(set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4)))
                   (match_dup 0))
              (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8)))
                   (match_dup 1))
              (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -12)))
-                  (match_dup 2))])]
+                  (match_dup 2))
+             (set (reg:SI SP_REG)
+                  (plus:SI (reg:SI SP_REG)
+                           (const_int -12)))])]
   "")
 
 (define_peephole2
    (set (mem:SI (pre_dec:HI (reg:HI SP_REG)))
        (match_operand:SI 2 "register_operand" ""))]
   "TARGET_H8300S && TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (3, operands)"
-  [(parallel [(set (reg:HI SP_REG)
-                  (plus:HI (reg:HI SP_REG)
-                           (const_int -12)))
-             (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4)))
+   && (REGNO_REG_CLASS (REGNO (operands[2])) == GENERAL_REGS
+       && REGNO (operands[1]) == REGNO (operands[0]) + 1
+       && REGNO (operands[2]) == REGNO (operands[0]) + 2
+       && (TARGET_H8300SX || (REGNO (operands[0]) & 3) == 0))"
+  [(parallel [(set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4)))
                   (match_dup 0))
              (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -8)))
                   (match_dup 1))
              (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -12)))
-                  (match_dup 2))])]
+                  (match_dup 2))
+             (set (reg:HI SP_REG)
+                  (plus:HI (reg:HI SP_REG)
+                           (const_int -12)))])]
   "")
 
 ;; Cram two pushes into stm.l.
    (set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
        (match_operand:SI 1 "register_operand" ""))]
   "TARGET_H8300S && !TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (2, operands)"
-  [(parallel [(set (reg:SI SP_REG)
-                  (plus:SI (reg:SI SP_REG)
-                           (const_int -8)))
-             (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4)))
+   && (REGNO_REG_CLASS (REGNO (operands[1])) == GENERAL_REGS
+       && REGNO (operands[1]) == REGNO (operands[0]) + 1
+       && (TARGET_H8300SX || (REGNO (operands[0]) & 1) == 0))"
+  [(parallel [(set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -4)))
                   (match_dup 0))
              (set (mem:SI (plus:SI (reg:SI SP_REG) (const_int -8)))
-                  (match_dup 1))])]
+                  (match_dup 1))
+             (set (reg:SI SP_REG)
+                  (plus:SI (reg:SI SP_REG)
+                           (const_int -8)))])]
   "")
 
 (define_peephole2
    (set (mem:SI (pre_dec:HI (reg:HI SP_REG)))
        (match_operand:SI 1 "register_operand" ""))]
   "TARGET_H8300S && TARGET_NORMAL_MODE
-   && h8300_regs_ok_for_stm (2, operands)"
-  [(parallel [(set (reg:HI SP_REG)
-                  (plus:HI (reg:HI SP_REG)
-                           (const_int -8)))
-             (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4)))
+   && (REGNO_REG_CLASS (REGNO (operands[1])) == GENERAL_REGS
+       && REGNO (operands[1]) == REGNO (operands[0]) + 1
+       && (TARGET_H8300SX || (REGNO (operands[0]) & 1) == 0))"
+  [(parallel [(set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -4)))
                   (match_dup 0))
              (set (mem:SI (plus:HI (reg:HI SP_REG) (const_int -8)))
-                  (match_dup 1))])]
+                  (match_dup 1))
+             (set (reg:HI SP_REG)
+                  (plus:HI (reg:HI SP_REG)
+                           (const_int -8)))])]
   "")
 
 ;; Turn
                (const_int 255)))]
   "(TARGET_H8300H || TARGET_H8300S)
    && !reg_overlap_mentioned_p (operands[0], operands[1])
+   && !(GET_CODE (operands[1]) == MEM && !offsettable_memref_p (operands[1]))
    && !(GET_CODE (operands[1]) == MEM && MEM_VOLATILE_P (operands[1]))"
   [(set (match_dup 0)
        (const_int 0))
    && GET_MODE (operands[0]) == GET_MODE (operands[1])
    && REGNO (operands[0]) == REGNO (operands[2])
    && !reg_overlap_mentioned_p (operands[2], operands[1])
+   && !(GET_MODE (operands[1]) != QImode
+       && GET_CODE (operands[1]) == MEM
+       && !offsettable_memref_p (operands[1]))
    && !(GET_MODE (operands[1]) != QImode
        && GET_CODE (operands[1]) == MEM
        && MEM_VOLATILE_P (operands[1]))"
                (match_operand:SI 2 "const_int_operand" "")))]
   "(TARGET_H8300H || TARGET_H8300S)
    && !MEM_VOLATILE_P (operands[1])
+   && offsettable_memref_p (operands[1])
    && (INTVAL (operands[2]) & ~0xffff) == 0
    && INTVAL (operands[2]) != 255"
   [(set (match_dup 3)
    (set (mem:SI (pre_dec:SI (reg:SI SP_REG)))
        (match_dup 0))]
   "")
+
+;; Transform
+;;
+;;     mov     dst,reg
+;;     op      src,reg
+;;     mov     reg,dst
+;;
+;; into
+;;
+;;     op      src,dst
+;;
+;; if "reg" dies at the end of the sequence.
+(define_peephole2
+  [(set (match_operand 0 "register_operand" "")
+       (match_operand 1 "memory_operand" ""))
+   (set (match_dup 0)
+       (match_operator 2 "h8sx_binary_memory_operator"
+          [(match_dup 0)
+           (match_operand 3 "h8300_src_operand" "")]))
+   (set (match_operand 4 "memory_operand" "")
+       (match_dup 0))]
+  "0 /* Disabale because it break compiling fp-bit.c.  */
+   && TARGET_H8300SX
+   && peep2_reg_dead_p (3, operands[0])
+   && !reg_overlap_mentioned_p (operands[0], operands[3])
+   && !reg_overlap_mentioned_p (operands[0], operands[4])
+   && h8sx_mergeable_memrefs_p (operands[4], operands[1])"
+  [(set (match_dup 4)
+       (match_dup 5))]
+  {
+    operands[5] = shallow_copy_rtx (operands[2]);
+    XEXP (operands[5], 0) = operands[1];
+  })
+
+;; Transform
+;;
+;;     mov     src,reg
+;;     op      reg,dst
+;;
+;; into
+;;
+;;     op      src,dst
+;;
+;; if "reg" dies in the second insn.
+(define_peephole2
+  [(set (match_operand 0 "register_operand" "")
+       (match_operand 1 "h8300_src_operand" ""))
+   (set (match_operand 2 "h8300_dst_operand" "")
+       (match_operator 3 "h8sx_binary_memory_operator"
+          [(match_operand 4 "h8300_dst_operand" "")
+           (match_dup 0)]))]
+  "0 /* Disabale because it break compiling fp-bit.c.  */
+   && TARGET_H8300SX
+   && peep2_reg_dead_p (2, operands[0])
+   && !reg_overlap_mentioned_p (operands[0], operands[4])"
+  [(set (match_dup 2)
+       (match_dup 5))]
+  {
+    operands[5] = shallow_copy_rtx (operands[3]);
+    XEXP (operands[5], 1) = operands[1];
+  })
+
+;; Transform
+;;
+;;     mov     dst,reg
+;;     op      reg
+;;     mov     reg,dst
+;;
+;; into
+;;
+;;     op      dst
+;;
+;; if "reg" dies at the end of the sequence.
+(define_peephole2
+  [(set (match_operand 0 "register_operand" "")
+       (match_operand 1 "memory_operand" ""))
+   (set (match_dup 0)
+       (match_operator 2 "h8sx_unary_memory_operator"
+          [(match_dup 0)]))
+   (set (match_operand 3 "memory_operand" "")
+       (match_dup 0))]
+  "TARGET_H8300SX
+   && peep2_reg_dead_p (3, operands[0])
+   && !reg_overlap_mentioned_p (operands[0], operands[3])
+   && h8sx_mergeable_memrefs_p (operands[3], operands[1])"
+  [(set (match_dup 3)
+       (match_dup 4))]
+  {
+    operands[4] = shallow_copy_rtx (operands[2]);
+    XEXP (operands[4], 0) = operands[1];
+  })
+
+;; Transform
+;;
+;;     mov     src1,reg
+;;     cmp     reg,src2
+;;
+;; into
+;;
+;;     cmp     src1,src2
+;;
+;; if "reg" dies in the comparison.
+(define_peephole2
+  [(set (match_operand 0 "register_operand" "")
+       (match_operand 1 "h8300_dst_operand" ""))
+   (set (cc0)
+       (compare (match_dup 0)
+                (match_operand 2 "h8300_src_operand" "")))]
+  "TARGET_H8300SX
+   && peep2_reg_dead_p (2, operands[0])
+   && !reg_overlap_mentioned_p (operands[0], operands[2])"
+  [(set (cc0)
+       (compare (match_dup 1)
+                (match_dup 2)))])
+
+;; Likewise for the second operand.
+(define_peephole2
+  [(set (match_operand 0 "register_operand" "")
+       (match_operand 1 "h8300_src_operand" ""))
+   (set (cc0)
+       (compare (match_operand 2 "h8300_dst_operand" "")
+                (match_dup 0)))]
+  "TARGET_H8300SX
+   && peep2_reg_dead_p (2, operands[0])
+   && !reg_overlap_mentioned_p (operands[0], operands[2])"
+  [(set (cc0)
+       (compare (match_dup 2)
+                (match_dup 1)))])
+
+;; Combine two moves.
+(define_peephole2
+  [(set (match_operand 0 "register_operand" "")
+       (match_operand 1 "h8300_src_operand" ""))
+   (set (match_operand 2 "h8300_dst_operand" "")
+       (match_dup 0))]
+  "TARGET_H8300SX
+   && peep2_reg_dead_p (2, operands[0])
+   && !reg_overlap_mentioned_p (operands[0], operands[2])"
+  [(set (match_dup 2)
+       (match_dup 1))])
index 8a7e5054256f62a8c8ea333218c90ee9d87f6cc9..a638d8d8e6d3ca4122846371395d6d8ca59315e5 100644 (file)
@@ -72,7 +72,7 @@ Boston, MA 02111-1307, USA.  */
 #define S2P    r6
 #endif
 
-#if defined (__H8300H__) || defined (__H8300S__)
+#if defined (__H8300H__) || defined (__H8300S__) || defined (__H8300SX__)
 #define PUSHP  push.l
 #define POPP   pop.l
 
@@ -105,6 +105,13 @@ Boston, MA 02111-1307, USA.  */
        .h8300s
 #endif
 #endif
+#ifdef __H8300SX__
+#ifdef __NORMAL_MODE__
+       .h8300sxn
+#else
+       .h8300sx
+#endif
+#endif
 
 #ifdef L_cmpsi2
 #ifdef __H8300__
diff --git a/gcc/config/h8300/mova.md b/gcc/config/h8300/mova.md
new file mode 100644 (file)
index 0000000..5c4d5d9
--- /dev/null
@@ -0,0 +1,841 @@
+;; -*- buffer-read-only: t -*-
+;; Generated automatically from genmova.sh
+(define_insn ""
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (plus:QI (mult:QI (match_operand:QI 1 "h8300_dst_operand" "0,rQ")
+                          (const_int 2))
+                (match_operand:QI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (plus:QI (ashift:QI (match_operand:QI 1 "h8300_dst_operand" "0,rQ")
+                          (const_int 1))
+                (match_operand:QI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (plus:QI (mult:QI (match_operand:QI 1 "h8300_dst_operand" "0,rQ")
+                          (const_int 4))
+                (match_operand:QI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:QI 0 "register_operand" "=r,r")
+       (plus:QI (ashift:QI (match_operand:QI 1 "h8300_dst_operand" "0,rQ")
+                          (const_int 2))
+                (match_operand:QI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (zero_extend:HI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                (match_operand:HI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/b.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (mult:HI (zero_extend:HI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 2)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (mult:HI (zero_extend:HI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 2))
+                (match_operand:HI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (and:HI (mult:HI (subreg:HI (match_operand:QI 1 "memory_operand" "m") 0)
+                         (const_int 2))
+               (const_int 510)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (and:HI (mult:HI (subreg:HI (match_operand:QI 1 "memory_operand" "m") 0)
+                                  (const_int 2))
+                        (const_int 510))
+                (match_operand:HI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (and:HI (mult:HI (match_operand:HI 1 "register_operand" "0")
+                         (const_int 2))
+               (const_int 510)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (and:HI (mult:HI (match_operand:HI 1 "register_operand" "0")
+                                  (const_int 2))
+                        (const_int 510))
+                (match_operand:HI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (ashift:HI (zero_extend:HI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 1)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (ashift:HI (zero_extend:HI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 1))
+                (match_operand:HI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (and:HI (ashift:HI (subreg:HI (match_operand:QI 1 "memory_operand" "m") 0)
+                         (const_int 1))
+               (const_int 510)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (and:HI (ashift:HI (subreg:HI (match_operand:QI 1 "memory_operand" "m") 0)
+                                  (const_int 1))
+                        (const_int 510))
+                (match_operand:HI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (and:HI (ashift:HI (match_operand:HI 1 "register_operand" "0")
+                         (const_int 1))
+               (const_int 510)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (and:HI (ashift:HI (match_operand:HI 1 "register_operand" "0")
+                                  (const_int 1))
+                        (const_int 510))
+                (match_operand:HI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (mult:HI (zero_extend:HI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 4)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (mult:HI (zero_extend:HI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 4))
+                (match_operand:HI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (and:HI (mult:HI (subreg:HI (match_operand:QI 1 "memory_operand" "m") 0)
+                         (const_int 4))
+               (const_int 1020)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (and:HI (mult:HI (subreg:HI (match_operand:QI 1 "memory_operand" "m") 0)
+                                  (const_int 4))
+                        (const_int 1020))
+                (match_operand:HI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (and:HI (mult:HI (match_operand:HI 1 "register_operand" "0")
+                         (const_int 4))
+               (const_int 1020)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (and:HI (mult:HI (match_operand:HI 1 "register_operand" "0")
+                                  (const_int 4))
+                        (const_int 1020))
+                (match_operand:HI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (ashift:HI (zero_extend:HI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 2)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (ashift:HI (zero_extend:HI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 2))
+                (match_operand:HI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (and:HI (ashift:HI (subreg:HI (match_operand:QI 1 "memory_operand" "m") 0)
+                         (const_int 2))
+               (const_int 1020)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (and:HI (ashift:HI (subreg:HI (match_operand:QI 1 "memory_operand" "m") 0)
+                                  (const_int 2))
+                        (const_int 1020))
+                (match_operand:HI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (and:HI (ashift:HI (match_operand:HI 1 "register_operand" "0")
+                         (const_int 2))
+               (const_int 1020)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (plus:HI (and:HI (ashift:HI (match_operand:HI 1 "register_operand" "0")
+                                  (const_int 2))
+                        (const_int 1020))
+                (match_operand:HI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (zero_extend:SI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/b.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (mult:SI (zero_extend:SI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 2)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (mult:SI (zero_extend:SI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 2))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (mult:SI (subreg:SI (match_operand:QI 1 "memory_operand" "m") 0)
+                         (const_int 2))
+               (const_int 510)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (mult:SI (subreg:SI (match_operand:QI 1 "memory_operand" "m") 0)
+                                  (const_int 2))
+                        (const_int 510))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                         (const_int 2))
+               (const_int 510)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                                  (const_int 2))
+                        (const_int 510))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (ashift:SI (zero_extend:SI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 1)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (ashift:SI (zero_extend:SI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 1))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (ashift:SI (subreg:SI (match_operand:QI 1 "memory_operand" "m") 0)
+                         (const_int 1))
+               (const_int 510)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (ashift:SI (subreg:SI (match_operand:QI 1 "memory_operand" "m") 0)
+                                  (const_int 1))
+                        (const_int 510))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                         (const_int 1))
+               (const_int 510)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                                  (const_int 1))
+                        (const_int 510))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (mult:SI (zero_extend:SI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 4)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (mult:SI (zero_extend:SI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 4))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (mult:SI (subreg:SI (match_operand:QI 1 "memory_operand" "m") 0)
+                         (const_int 4))
+               (const_int 1020)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (mult:SI (subreg:SI (match_operand:QI 1 "memory_operand" "m") 0)
+                                  (const_int 4))
+                        (const_int 1020))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                         (const_int 4))
+               (const_int 1020)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                                  (const_int 4))
+                        (const_int 1020))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (ashift:SI (zero_extend:SI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 2)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (ashift:SI (zero_extend:SI (match_operand:QI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 2))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (ashift:SI (subreg:SI (match_operand:QI 1 "memory_operand" "m") 0)
+                         (const_int 2))
+               (const_int 1020)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (ashift:SI (subreg:SI (match_operand:QI 1 "memory_operand" "m") 0)
+                                  (const_int 2))
+                        (const_int 1020))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                         (const_int 2))
+               (const_int 1020)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%X1.b),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                                  (const_int 2))
+                        (const_int 1020))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%X1.b),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (mult:HI (match_operand:HI 1 "h8300_dst_operand" "0,rQ")
+                          (const_int 2))
+                (match_operand:HI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (ashift:HI (match_operand:HI 1 "h8300_dst_operand" "0,rQ")
+                          (const_int 1))
+                (match_operand:HI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (mult:HI (match_operand:HI 1 "h8300_dst_operand" "0,rQ")
+                          (const_int 4))
+                (match_operand:HI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (plus:HI (ashift:HI (match_operand:HI 1 "h8300_dst_operand" "0,rQ")
+                          (const_int 2))
+                (match_operand:HI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (zero_extend:SI (match_operand:HI 1 "h8300_dst_operand" "0,rQ"))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/b.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (mult:SI (zero_extend:SI (match_operand:HI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 2)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (mult:SI (zero_extend:SI (match_operand:HI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 2))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (mult:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
+                         (const_int 2))
+               (const_int 131070)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (mult:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
+                                  (const_int 2))
+                        (const_int 131070))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                         (const_int 2))
+               (const_int 131070)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                                  (const_int 2))
+                        (const_int 131070))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (ashift:SI (zero_extend:SI (match_operand:HI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 1)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (ashift:SI (zero_extend:SI (match_operand:HI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 1))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (ashift:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
+                         (const_int 1))
+               (const_int 131070)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (ashift:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
+                                  (const_int 1))
+                        (const_int 131070))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                         (const_int 1))
+               (const_int 131070)))]
+  "TARGET_H8300SX"
+  "mova/w.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                                  (const_int 1))
+                        (const_int 131070))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/w.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (mult:SI (zero_extend:SI (match_operand:HI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 4)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (mult:SI (zero_extend:SI (match_operand:HI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 4))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (mult:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
+                         (const_int 4))
+               (const_int 262140)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (mult:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
+                                  (const_int 4))
+                        (const_int 262140))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                         (const_int 4))
+               (const_int 262140)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (mult:SI (match_operand:SI 1 "register_operand" "0")
+                                  (const_int 4))
+                        (const_int 262140))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (ashift:SI (zero_extend:SI (match_operand:HI 1 "h8300_dst_operand" "0,rQ"))
+                 (const_int 2)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (plus:SI (ashift:SI (zero_extend:SI (match_operand:HI 1 "h8300_dst_operand" "0,rQ"))
+                          (const_int 2))
+                (match_operand:SI 2 "immediate_operand" "i,i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (ashift:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
+                         (const_int 2))
+               (const_int 262140)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (ashift:SI (subreg:SI (match_operand:HI 1 "memory_operand" "m") 0)
+                                  (const_int 2))
+                        (const_int 262140))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                         (const_int 2))
+               (const_int 262140)))]
+  "TARGET_H8300SX"
+  "mova/l.l @(0,%T1.w),%S0"
+  [(set_attr "length_table" "mova_zero")
+   (set_attr "cc" "none")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (and:SI (ashift:SI (match_operand:SI 1 "register_operand" "0")
+                                  (const_int 2))
+                        (const_int 262140))
+                (match_operand:SI 2 "immediate_operand" "i")))]
+  "TARGET_H8300SX"
+  "mova/l.l @(%o2,%T1.w),%S0"
+  [(set_attr "length_table" "mova")
+   (set_attr "cc" "none")])
+
index 28ea2cf71bda94250d97aadf32e6170200e28057..1311d968711d92bbcf08eeb06687e9fafa23cf72 100644 (file)
@@ -27,9 +27,17 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
        echo '#endif' >> fp-bit.c
        cat $(srcdir)/config/fp-bit.c >> fp-bit.c
 
-MULTILIB_OPTIONS = mh/ms mn mint32
-MULTILIB_DIRNAMES = h8300h h8300s normal int32
+MULTILIB_OPTIONS = mh/ms/msx mn mint32
+MULTILIB_DIRNAMES = h8300h h8300s h8sx normal int32
 MULTILIB_EXCEPTIONS = mint32 mn mn/mint32
 
 LIBGCC = stmp-multilib
 INSTALL_LIBGCC = install-multilib
+
+s-config s-conditions s-flags s-codes s-constants s-emit s-recog \
+s-opinit s-extract s-peep s-attr s-attrtab s-output: \
+       $(srcdir)/config/h8300/mova.md
+
+$(srcdir)/config/h8300/mova.md: $(srcdir)/config/h8300/genmova.sh
+       $(SHELL) $(srcdir)/config/h8300/genmova.sh \
+         > $(srcdir)/config/h8300/mova.md
index cbb581bcf624cc082306df9cd6af944a8a439944..bbd20437e797c72c670f570f8a4d0f77d33d89a2 100644 (file)
@@ -2778,8 +2778,9 @@ The @samp{cmp@var{m}} patterns should be used instead.
 
 @cindex @code{movmem@var{m}} instruction pattern
 @item @samp{movmem@var{m}}
-Block move instruction.  The addresses of the destination and source
-strings are the first two operands, and both are in mode @code{Pmode}.
+Block move instruction.  The destination and source blocks of memory
+are the first two operands, and both are @code{mem:BLK}s with an
+address in mode @code{Pmode}.
 
 The number of bytes to move is the third operand, in mode @var{m}.
 Usually, you specify @code{word_mode} for @var{m}.  However, if you can
@@ -2803,12 +2804,21 @@ individually moved data units in the block.
 These patterns need not give special consideration to the possibility
 that the source and destination strings might overlap.
 
+@cindex @code{movstr} instruction pattern
+@item @samp{movstr}
+String copy instruction, with @code{stpcpy} semantics.  Operand 0 is
+an output operand in mode @code{Pmode}.  The addresses of the
+destination and source strings are operands 1 and 2, and both are
+@code{mem:BLK}s with addresses in mode @code{Pmode}.  The execution of
+the expansion of this pattern should store in operand 0 the address in
+which the @code{NUL} terminator was stored in the destination string.
+
 @cindex @code{clrmem@var{m}} instruction pattern
 @item @samp{clrmem@var{m}}
-Block clear instruction.  The addresses of the destination string is the
-first operand, in mode @code{Pmode}.  The number of bytes to clear is
-the second operand, in mode @var{m}.  See @samp{movmem@var{m}} for
-a discussion of the choice of mode.
+Block clear instruction.  The destination string is the first operand,
+given as a @code{mem:BLK} whose address is in mode @code{Pmode}.  The
+number of bytes to clear is the second operand, in mode @var{m}.  See
+@samp{movmem@var{m}} for a discussion of the choice of mode.
 
 The third operand is the known alignment of the destination, in the form
 of a @code{const_int} rtx.  Thus, if the compiler knows that the
index a264fca6bc62518ef0cabcb4d19b3145f24ab9f0..48be2929c83bff7e8c6e22c64028b20026dd6c82 100644 (file)
@@ -2660,11 +2660,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 d89425381de52788a5fd72b41f77d756bdf193c6..4a9ad8c43af6153ce9ddfeb4eedbaaa142e8df1d 100644 (file)
@@ -5525,6 +5525,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 410acdfb5521c9ce7f2b4915a57bdfe6d9bf78fe..7b0e872711b5ad53a87eb42b9c301624b169d2a1 100644 (file)
@@ -4544,6 +4544,7 @@ get_narrower (tree op, int *unsignedp_ptr)
   int uns = 0;
   int first = 1;
   tree win = op;
+  bool integral_p = INTEGRAL_TYPE_P (TREE_TYPE (op));
 
   while (TREE_CODE (op) == NOP_EXPR)
     {
@@ -4580,6 +4581,10 @@ get_narrower (tree op, int *unsignedp_ptr)
            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;