From beed8fc0bb23590fdfa4665c3ad5b3ca7edb17f7 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Thu, 8 Jul 2004 03:40:34 +0000 Subject: [PATCH] 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 * config/h8300/h8300.md: Rename movstr*, except for movstrict*, to movmem* and clrstr* to clrmem*. 2004-06-27 Alexandre Oliva * 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 * config/h8300/h8300.md (logicalhi3_sn, logicalsi3_sn): New. 2004-06-16 Alexandre Oliva * 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 * 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 * 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 * config/h8300/h8300.md (extzv): Make subreg check more robust. 2003-07-21 Richard Sandiford * 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 * 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 * 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 * 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 * 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. 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 * 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 * 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 * 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 * 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 * 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 * 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 * config/h8300/h8300.c (h8300_rtx_costs): Add h8sx handling. 2003-06-20 Richard Sandiford * 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 * 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 * 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 * 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 * config/h8300/h8300.h (EXTRA_MEMORY_CONSTRAINT): Define. 2003-06-04 Richard Sandiford * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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 * 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) : 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 * 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 * 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 * 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 * config/h8300/h8300.c (dosize): Truncate sign * size to Pmode. From-SVN: r84257 --- gcc/ChangeLog | 421 +++++++ gcc/builtins.c | 138 +- gcc/config/h8300/crti.asm | 7 + gcc/config/h8300/crtn.asm | 7 + gcc/config/h8300/elf.h | 2 +- gcc/config/h8300/genmova.sh | 163 +++ gcc/config/h8300/h8300-protos.h | 13 +- gcc/config/h8300/h8300.c | 1771 +++++++++++++++++++++++--- gcc/config/h8300/h8300.h | 177 ++- gcc/config/h8300/h8300.md | 2099 +++++++++++++++++++++++-------- gcc/config/h8300/lib1funcs.asm | 9 +- gcc/config/h8300/mova.md | 841 +++++++++++++ gcc/config/h8300/t-h8300 | 12 +- gcc/doc/md.texi | 22 +- gcc/final.c | 2 + gcc/genattrtab.c | 5 + gcc/tree.c | 5 + 17 files changed, 4936 insertions(+), 758 deletions(-) create mode 100644 gcc/config/h8300/genmova.sh create mode 100644 gcc/config/h8300/mova.md diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 160c0e35556..c58997ae008 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,424 @@ +2004-07-08 Alexandre Oliva + + 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 + * config/h8300/h8300.md: Rename movstr*, except for movstrict*, to + movmem* and clrstr* to clrmem*. + 2004-06-27 Alexandre Oliva + * 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 + * config/h8300/h8300.md (logicalhi3_sn, logicalsi3_sn): New. + 2004-06-16 Alexandre Oliva + * 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 + * 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 + * 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 + * config/h8300/h8300.md (extzv): Make subreg check more robust. + 2003-07-21 Richard Sandiford + * 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 + * 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 + * 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 + * 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 + * 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. 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * config/h8300/h8300.c (h8300_rtx_costs): Add h8sx handling. + 2003-06-20 Richard Sandiford + * 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 + * 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 + * 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 + * 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 + * config/h8300/h8300.h (EXTRA_MEMORY_CONSTRAINT): Define. + 2003-06-04 Richard Sandiford + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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 + * 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) : 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 + * 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 + * 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 + * 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 + * config/h8300/h8300.c (dosize): Truncate sign * size to Pmode. + 2004-05-28 Aaron W. LaFramboise * config.gcc (i[34567]86-*-mingw32*): Enable threads by default. diff --git a/gcc/builtins.c b/gcc/builtins.c index 004ac527bb5..72cf798a021 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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); } } diff --git a/gcc/config/h8300/crti.asm b/gcc/config/h8300/crti.asm index 8070a84c600..3835698554f 100644 --- a/gcc/config/h8300/crti.asm +++ b/gcc/config/h8300/crti.asm @@ -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 diff --git a/gcc/config/h8300/crtn.asm b/gcc/config/h8300/crtn.asm index 5b7a1c05a16..2d0e0458361 100644 --- a/gcc/config/h8300/crtn.asm +++ b/gcc/config/h8300/crtn.asm @@ -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 diff --git a/gcc/config/h8300/elf.h b/gcc/config/h8300/elf.h index ecd0603814c..542ffcf81a2 100644 --- a/gcc/config/h8300/elf.h +++ b/gcc/config/h8300/elf.h @@ -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 index 00000000000..1988afa512a --- /dev/null +++ b/gcc/config/h8300/genmova.sh @@ -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 < 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; } } @@ -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); +} + +/* 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; +} + +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; + } } + +/* 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); } /* 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; diff --git a/gcc/config/h8300/h8300.h b/gcc/config/h8300/h8300.h index fcb082372a1..d7b73e8f3a0 100644 --- a/gcc/config/h8300/h8300.h +++ b/gcc/config/h8300/h8300.h @@ -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') + #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; /* 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}}, \ diff --git a/gcc/config/h8300/h8300.md b/gcc/config/h8300/h8300.md index 91f7922db00..e718a82e40b 100644 --- a/gcc/config/h8300/h8300.md +++ b/gcc/config/h8300/h8300.md @@ -52,9 +52,16 @@ [(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) @@ -69,16 +76,22 @@ (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") @@ -87,7 +100,30 @@ (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. @@ -104,6 +140,32 @@ (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. @@ -139,7 +201,7 @@ (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))" "@ @@ -153,6 +215,16 @@ (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" ""))] @@ -160,7 +232,8 @@ " { /* 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); @@ -168,19 +241,15 @@ }") (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 @@ -209,7 +278,7 @@ (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))" "@ @@ -223,6 +292,20 @@ (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" ""))] @@ -238,19 +321,16 @@ }") (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 @@ -265,7 +345,7 @@ 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) @@ -350,7 +430,7 @@ (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 @@ -423,6 +503,273 @@ (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 ,er6 +;; movmd.sz +;; mov.l er6, +;; mov.l @er7+,er6 +;; +;; where is the current destination register (operand 4). +;; The fourth instruction will be deleted if 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" ""))] @@ -434,7 +781,7 @@ 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) @@ -504,7 +851,7 @@ (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))" "@ @@ -641,7 +988,7 @@ 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) @@ -707,7 +1054,7 @@ 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)) @@ -760,17 +1107,17 @@ (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" "")))] "" " { @@ -791,46 +1138,54 @@ (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")]) ;; ---------------------------------------------------------------------- ;; 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 @@ -873,8 +1228,8 @@ (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 @@ -896,6 +1251,20 @@ [(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,P3X")))] + "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"))))] @@ -1036,7 +1436,28 @@ [(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"))))] @@ -1045,16 +1466,58 @@ [(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"))))] @@ -1063,6 +1526,53 @@ [(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 @@ -1099,6 +1609,42 @@ ;; 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 @@ -1187,10 +1733,22 @@ ;; 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)" "@ @@ -1200,20 +1758,16 @@ (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" "")))] "" "") @@ -1275,7 +1829,7 @@ (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" "")))] "" "") @@ -1284,39 +1838,36 @@ ;; ---------------------------------------------------------------------- (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" "")))] "" "") @@ -1327,37 +1878,34 @@ (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" "")))] "" "") @@ -1365,12 +1913,40 @@ ;; {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)")) @@ -1378,11 +1954,11 @@ (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)")) @@ -1393,12 +1969,18 @@ ;; 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" @@ -1424,11 +2006,11 @@ "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" @@ -1454,11 +2036,11 @@ "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" @@ -1509,17 +2091,23 @@ ;; 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" "")))] "" "") @@ -1531,16 +2119,16 @@ [(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" "")))] "" "") @@ -1552,12 +2140,12 @@ [(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")]) ;; ---------------------------------------------------------------------- ;; JUMP INSTRUCTIONS @@ -1673,6 +2261,64 @@ [(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" @@ -1681,7 +2327,31 @@ "" "* { - 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\"; @@ -1689,6 +2359,10 @@ 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. @@ -1767,7 +2441,8 @@ 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)))]) @@ -1790,7 +2465,8 @@ 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)))]) @@ -1814,311 +2490,77 @@ (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)] @@ -2136,6 +2578,7 @@ return \"rts\"; }" [(set_attr "cc" "none") + (set_attr "can_delay" "no") (set_attr "length" "2")]) (define_expand "prologue" @@ -2146,7 +2589,7 @@ (define_expand "epilogue" [(return)] "" - "h8300_expand_epilogue ();") + "h8300_expand_epilogue (); DONE;") (define_insn "monitor_prologue" [(unspec_volatile [(const_int 0)] UNSPEC_MONITOR)] @@ -2211,7 +2654,10 @@ [(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") @@ -2225,13 +2671,13 @@ (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) @@ -2246,7 +2692,7 @@ (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) @@ -2255,6 +2701,14 @@ (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" "")))] @@ -2325,7 +2779,7 @@ (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) @@ -2334,6 +2788,14 @@ (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" "")))] @@ -2383,21 +2845,41 @@ (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") @@ -2416,24 +2898,44 @@ (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") @@ -2452,24 +2954,44 @@ (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") @@ -2560,7 +3082,7 @@ (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") @@ -2576,7 +3098,7 @@ (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") @@ -2592,7 +3114,7 @@ (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") @@ -2703,9 +3225,54 @@ (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; @@ -2730,9 +3297,52 @@ (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; @@ -2767,6 +3377,282 @@ "" "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")]) + ;; ----------------------------------------------------------------- ;; COMBINE PATTERNS @@ -3674,7 +4560,7 @@ (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]));") @@ -3684,7 +4570,7 @@ (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]));") @@ -3697,7 +4583,7 @@ (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]));") @@ -3707,7 +4593,7 @@ (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]));") @@ -3724,18 +4610,22 @@ (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 @@ -3748,18 +4638,22 @@ (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. @@ -3772,16 +4666,19 @@ (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 @@ -3792,16 +4689,19 @@ (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. @@ -3812,14 +4712,16 @@ (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 @@ -3828,14 +4730,16 @@ (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 @@ -4045,6 +4949,7 @@ (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)) @@ -4066,6 +4971,9 @@ && 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]))" @@ -4108,6 +5016,7 @@ (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) @@ -5064,3 +5973,143 @@ (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))]) diff --git a/gcc/config/h8300/lib1funcs.asm b/gcc/config/h8300/lib1funcs.asm index 8a7e5054256..a638d8d8e6d 100644 --- a/gcc/config/h8300/lib1funcs.asm +++ b/gcc/config/h8300/lib1funcs.asm @@ -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 index 00000000000..5c4d5d9d911 --- /dev/null +++ b/gcc/config/h8300/mova.md @@ -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")]) + diff --git a/gcc/config/h8300/t-h8300 b/gcc/config/h8300/t-h8300 index 28ea2cf71bd..1311d968711 100644 --- a/gcc/config/h8300/t-h8300 +++ b/gcc/config/h8300/t-h8300 @@ -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 diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index cbb581bcf62..bbd20437e79 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -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 diff --git a/gcc/final.c b/gcc/final.c index a264fca6bc6..48be2929c83 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -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; diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c index d89425381de..4a9ad8c43af 100644 --- a/gcc/genattrtab.c +++ b/gcc/genattrtab.c @@ -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. */ diff --git a/gcc/tree.c b/gcc/tree.c index 410acdfb552..7b0e872711b 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -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; -- 2.30.2