Add SH4 support:
* config/sh/lib1funcs.asm (___movstr_i4_even, ___movstr_i4_odd): Define. (___movstrSI12_i4, ___sdivsi3_i4, ___udivsi3_i4): Define. * sh.c (reg_class_from_letter, regno_reg_class): Add DF_REGS. (fp_reg_names, assembler_dialect): New variables. (print_operand_address): Handle SUBREGs. (print_operand): Added 'o' case. Don't use adj_offsettable_operand on PRE_DEC / POST_INC. Name of FP registers depends on mode. (expand_block_move): Emit different code for SH4 hardware. (prepare_scc_operands): Use emit_sf_insn / emit_df_insn as appropriate. (from_compare): Likewise. (add_constant): New argument last_value. Changed all callers. (find_barrier): Don't try HImode load for FPUL_REG. (machine_dependent_reorg): Likewise. (sfunc_uses_reg): A CLOBBER cannot be the address register use. (gen_far_branch): Emit a barrier after the new jump. (barrier_align): Don't trust instruction lengths before fixing up pcloads. (machine_dependent_reorg): Add support for FIRST_XD_REG .. LAST_XD_REG. Use auto-inc addressing for fp registers if doubles need to be loaded in two steps. Set sh_flag_remove_dead_before_cse. (push): Support for TARGET_FMOVD. Use gen_push_fpul for fpul. (pop): Support for TARGET_FMOVD. Use gen_pop_fpul for fpul. (calc_live_regs): Support for TARGET_FMOVD. Don't save FPSCR. Support for FIRST_XD_REG .. LAST_XD_REG. (sh_expand_prologue): Support for FIRST_XD_REG .. LAST_XD_REG. (sh_expand_epilogue): Likewise. (sh_builtin_saveregs): Use DFmode moves for fp regs on SH4. (initial_elimination_offset): Take TARGET_ALIGN_DOUBLE into account. (arith_reg_operand): FPUL_REG is OK for SH4. (fp_arith_reg_operand, fp_extended_operand) New functions. (tertiary_reload_operand, fpscr_operand): Likewise. (commutative_float_operator, noncommutative_float_operator): Likewise. (binary_float_operator, get_fpscr_rtx, emit_sf_insn): Likewise. (emit_df_insn, expand_sf_unop, expand_sf_binop): Likewise. (expand_df_unop, expand_df_binop, expand_fp_branch): Likewise. (emit_fpscr_use, mark_use, remove_dead_before_cse): Likewise. * sh.h (CPP_SPEC): Add support for -m4, m4-single, m4-single-only. (CONDITIONAL_REGISTER_USAGE): Likewise. (HARD_SH4_BIT, FPU_SINGLE_BIT, SH4_BIT, FMOVD_BIT): Define. (TARGET_CACHE32, TARGET_SUPERSCALAR, TARGET_HARWARD): Define. (TARGET_HARD_SH4, TARGET_FPU_SINGLE, TARGET_SH4, TARGET_FMOVD): Define. (target_flag): Add -m4, m4-single, m4-single-only, -mfmovd. (OPTIMIZATION_OPTIONS): If optimizing, set flag_omit_frame_pointer to -1 and sh_flag_remove_dead_before_cse to 1. (ASSEMBLER_DIALECT): Define to assembler_dialect. (assembler_dialect, fp_reg_names): Declare. (OVERRIDE_OPTIONS): Add code for TARGET_SH4. Hide names of registers that are not accessible. (CACHE_LOG): Take TARGET_CACHE32 into account. (LOOP_ALIGN): Take TARGET_HARWARD into account. (FIRST_XD_REG, LAST_XD_REG, FPSCR_REG): Define. (FIRST_PSEUDO_REGISTER: Now 49. (FIXED_REGISTERS, CALL_USED_REGISTERS): Include values for registers. (HARD_REGNO_NREGS): Special treatment of FIRST_XD_REG .. LAST_XD_REG. (HARD_REGNO_MODE_OK): Update. (enum reg_class): Add DF_REGS and FPSCR_REGS. (REG_CLASS_NAMES, REG_CLASS_CONTENTS, REG_ALLOC_ORDER): Likewise. (SECONDARY_OUTPUT_RELOAD_CLASS, SECONDARY_INPUT_RELOAD_CLASS): Update. (CLASS_CANNOT_CHANGE_SIZE, DEBUG_REGISTER_NAMES): Define. (NPARM_REGS): Eight floating point parameter registers on SH4. (BASE_RETURN_VALUE_REG): SH4 also passes double values in floating point registers. (GET_SH_ARG_CLASS) Likewise. Complex float types are also returned in float registers. (BASE_ARG_REG): Complex float types are also passes in float registers. (FUNCTION_VALUE): Change mode like PROMOTE_MODE does. (LIBCALL_VALUE): Remove trailing semicolon. (ROUND_REG): Round when double precision value is passed in floating point register(s). (FUNCTION_ARG_ADVANCE): No change wanted for SH4 when things are passed on the stack. (FUNCTION_ARG): Little endian adjustment for SH4 SFmode. (FUNCTION_ARG_PARTIAL_NREGS): Zero for SH4. (TRAMPOLINE_ALIGNMENT): Take TARGET_HARWARD into account. (INITIALIZE_TRAMPOLINE): Emit ic_invalidate_line for TARGET_HARWARD. (MODE_DISP_OK_8): Not for SH4 DFmode. (GO_IF_LEGITIMATE_ADDRESS): No base reg + index reg for SH4 DFmode. Allow indexed addressing for PSImode after reload. (LEGITIMIZE_ADDRESS): Not for SH4 DFmode. (LEGITIMIZE_RELOAD_ADDRESS): Handle SH3E SFmode. Don't change SH4 DFmode nor PSImode RELOAD_FOR_INPUT_ADDRESS. (DOUBLE_TYPE_SIZE): 64 for SH4. (RTX_COSTS): Add PLUS case. Increae cost of ASHIFT, ASHIFTRT, LSHIFTRT case. (REGISTER_MOVE_COST): Add handling of R0_REGS, FPUL_REGS, T_REGS, MAC_REGS, PR_REGS, DF_REGS. (REGISTER_NAMES): Use fp_reg_names. (enum processor_type): Add PROCESSOR_SH4. (sh_flag_remove_dead_before_cse): Declare. (rtx_equal_function_value_matters, fpscr_rtx, get_fpscr_rtx): Declare. (PREDICATE_CODES): Add binary_float_operator, commutative_float_operator, fp_arith_reg_operand, fp_extended_operand, fpscr_operand, noncommutative_float_operator. (ADJUST_COST): Use different scale for TARGET_SUPERSCALAR. (SH_DYNAMIC_SHIFT_COST): Cheaper for SH4. * sh.md (attribute cpu): Add value sh4. (attrbutes fmovd, issues): Define. (attribute type): Add values dfp_arith, dfp_cmp, dfp_conv, dfdiv. (function units memory, int, mpy, fp): Make dependent on issue rate. (function units issue, single_issue, load_si, load): Define. (function units load_store, fdiv, gp_fpul): Define. (attribute hit_stack): Provide proper default. (use_sfunc_addr+1, udivsi3): Predicated on ! TARGET_SH4. (udivsi3_i4, udivsi3_i4_single, divsi3_i4, divsi3_i4_single): New insns. (udivsi3, divsi3): Emit special patterns for SH4 hardware, (mulsi3_call): Now uses match_operand for function address. (mulsi3): Also emit code for SH1 case. Wrap result in REG_LIBCALL / REG_RETVAL notes. (push, pop, push_e, pop_e): Now define_expands. (push_fpul, push_4, pop_fpul, pop_4, ic_invalidate_line): New expanders. (movsi_ie): Added y/i alternative. (ic_invalidate_line_i, movdf_i4): New insns. (movdf_i4+[123], reload_outdf+[12345], movsi_y+[12]): New splitters. (reload_indf, reload_outdf, reload_outsf, reload_insi): New expanders. (movdf): Add special code for SH4. (movsf_ie, movsf_ie+1, reload_insf, calli): Make use of fpscr visible. (call_valuei, calli, call_value): Likewise. (movsf): Emit no-op move. (mov_nop, movsi_y): New insns. (blt, sge): generalize to handle DFmode. (return predicate): Call emit_fpscr_use and remove_dead_before_cse. (block_move_real, block_lump_real): Predicate on ! TARGET_HARD_SH4. (block_move_real_i4, block_lump_real_i4, fpu_switch): New insns. (fpu_switch0, fpu_switch1, movpsi): New expanders. (fpu_switch+[12], fix_truncsfsi2_i4_2+1): New splitters. (toggle_sz): New insn. (addsf3, subsf3, mulsf3, divsf3): Now define_expands. (addsf3_i, subsf3_i, mulsf3_i4, mulsf3_ie, divsf3_i): New insns. (macsf3): Make use of fpscr visible. Disable for SH4. (floatsisf2): Make use of fpscr visible. (floatsisf2_i4): New insn. (floatsisf2_ie, fixsfsi, cmpgtsf_t, cmpeqsf_t): Disable for SH4. (ieee_ccmpeqsf_t): Likewise. (fix_truncsfsi2): Emit different code for SH4. (fix_truncsfsi2_i4, fix_truncsfsi2_i4_2, cmpgtsf_t_i4): New insns. (cmpeqsf_t_i4, ieee_ccmpeqsf_t_4): New insns. (negsf2, sqrtsf2, abssf2): Now expanders. (adddf3, subdf3i, muldf2, divdf3, floatsidf2): New expanders. (negsf2_i, sqrtsf2_i, abssf2_i, adddf3_i, subdf3_i): New insns. (muldf3_i, divdf3_i, floatsidf2_i, fix_truncdfsi2_i): New insns. (fix_truncdfsi2, cmpdf, negdf2, sqrtdf2, absdf2): New expanders. (fix_truncdfsi2_i4, cmpgtdf_t, cmpeqdf_t, ieee_ccmpeqdf_t): New insns. (fix_truncdfsi2_i4_2+1): New splitters. (negdf2_i, sqrtdf2_i, absdf2_i, extendsfdf2_i4): New insns. (extendsfdf2, truncdfsf2): New expanders. (truncdfsf2_i4): New insn. * t-sh (LIB1ASMFUNCS): Add _movstr_i4, _sdivsi3_i4, _udivsi3_i4. (MULTILIB_OPTIONS): Add m4-single-only/m4-single/m4. * float-sh.h: When testing for __SH3E__, also test for __SH4_SINGLE_ONLY__ . * va-sh.h (__va_freg): Define to float. (__va_greg, __fa_freg, __gnuc_va_list, va_start): Define for __SH4_SINGLE_ONLY__ like for __SH3E__ . (__PASS_AS_FLOAT, __TARGET_SH4_P): Likewise. (__PASS_AS_FLOAT): Use different definition for __SH4__ and __SH4_SINGLE__. (TARGET_SH4_P): Define. (va_arg): Use it. * sh.md (movdf_k, movsf_i): Tweak the condition so that init_expr_once is satisfied about the existence of load / store insns. * sh.md (movsi_i, movsi_ie, movsi_i_lowpart, movsf_i, movsf_ie): change m constraint in source operand to mr / mf . * va-sh.h (__va_arg_sh1): Use __asm instead of asm. * (__VA_REEF): Define. (__va_arg_sh1): Use it. * va-sh.h (va_start, va_arg, va_copy): Add parenteses. From-SVN: r23777
This commit is contained in:
parent
57cfc5dd86
commit
225e4f43cc
178
gcc/ChangeLog
178
gcc/ChangeLog
|
@ -1,3 +1,181 @@
|
||||||
|
Mon Nov 23 16:46:46 1998 J"orn Rennecke <amylaar@cygnus.co.uk>
|
||||||
|
|
||||||
|
Add SH4 support:
|
||||||
|
|
||||||
|
* config/sh/lib1funcs.asm (___movstr_i4_even, ___movstr_i4_odd): Define.
|
||||||
|
(___movstrSI12_i4, ___sdivsi3_i4, ___udivsi3_i4): Define.
|
||||||
|
* sh.c (reg_class_from_letter, regno_reg_class): Add DF_REGS.
|
||||||
|
(fp_reg_names, assembler_dialect): New variables.
|
||||||
|
(print_operand_address): Handle SUBREGs.
|
||||||
|
(print_operand): Added 'o' case.
|
||||||
|
Don't use adj_offsettable_operand on PRE_DEC / POST_INC.
|
||||||
|
Name of FP registers depends on mode.
|
||||||
|
(expand_block_move): Emit different code for SH4 hardware.
|
||||||
|
(prepare_scc_operands): Use emit_sf_insn / emit_df_insn as appropriate.
|
||||||
|
(from_compare): Likewise.
|
||||||
|
(add_constant): New argument last_value. Changed all callers.
|
||||||
|
(find_barrier): Don't try HImode load for FPUL_REG.
|
||||||
|
(machine_dependent_reorg): Likewise.
|
||||||
|
(sfunc_uses_reg): A CLOBBER cannot be the address register use.
|
||||||
|
(gen_far_branch): Emit a barrier after the new jump.
|
||||||
|
(barrier_align): Don't trust instruction lengths before
|
||||||
|
fixing up pcloads.
|
||||||
|
(machine_dependent_reorg): Add support for FIRST_XD_REG .. LAST_XD_REG.
|
||||||
|
Use auto-inc addressing for fp registers if doubles need to
|
||||||
|
be loaded in two steps.
|
||||||
|
Set sh_flag_remove_dead_before_cse.
|
||||||
|
(push): Support for TARGET_FMOVD. Use gen_push_fpul for fpul.
|
||||||
|
(pop): Support for TARGET_FMOVD. Use gen_pop_fpul for fpul.
|
||||||
|
(calc_live_regs): Support for TARGET_FMOVD. Don't save FPSCR.
|
||||||
|
Support for FIRST_XD_REG .. LAST_XD_REG.
|
||||||
|
(sh_expand_prologue): Support for FIRST_XD_REG .. LAST_XD_REG.
|
||||||
|
(sh_expand_epilogue): Likewise.
|
||||||
|
(sh_builtin_saveregs): Use DFmode moves for fp regs on SH4.
|
||||||
|
(initial_elimination_offset): Take TARGET_ALIGN_DOUBLE into account.
|
||||||
|
(arith_reg_operand): FPUL_REG is OK for SH4.
|
||||||
|
(fp_arith_reg_operand, fp_extended_operand) New functions.
|
||||||
|
(tertiary_reload_operand, fpscr_operand): Likewise.
|
||||||
|
(commutative_float_operator, noncommutative_float_operator): Likewise.
|
||||||
|
(binary_float_operator, get_fpscr_rtx, emit_sf_insn): Likewise.
|
||||||
|
(emit_df_insn, expand_sf_unop, expand_sf_binop): Likewise.
|
||||||
|
(expand_df_unop, expand_df_binop, expand_fp_branch): Likewise.
|
||||||
|
(emit_fpscr_use, mark_use, remove_dead_before_cse): Likewise.
|
||||||
|
* sh.h (CPP_SPEC): Add support for -m4, m4-single, m4-single-only.
|
||||||
|
(CONDITIONAL_REGISTER_USAGE): Likewise.
|
||||||
|
(HARD_SH4_BIT, FPU_SINGLE_BIT, SH4_BIT, FMOVD_BIT): Define.
|
||||||
|
(TARGET_CACHE32, TARGET_SUPERSCALAR, TARGET_HARWARD): Define.
|
||||||
|
(TARGET_HARD_SH4, TARGET_FPU_SINGLE, TARGET_SH4, TARGET_FMOVD): Define.
|
||||||
|
(target_flag): Add -m4, m4-single, m4-single-only, -mfmovd.
|
||||||
|
(OPTIMIZATION_OPTIONS): If optimizing, set flag_omit_frame_pointer
|
||||||
|
to -1 and sh_flag_remove_dead_before_cse to 1.
|
||||||
|
(ASSEMBLER_DIALECT): Define to assembler_dialect.
|
||||||
|
(assembler_dialect, fp_reg_names): Declare.
|
||||||
|
(OVERRIDE_OPTIONS): Add code for TARGET_SH4.
|
||||||
|
Hide names of registers that are not accessible.
|
||||||
|
(CACHE_LOG): Take TARGET_CACHE32 into account.
|
||||||
|
(LOOP_ALIGN): Take TARGET_HARWARD into account.
|
||||||
|
(FIRST_XD_REG, LAST_XD_REG, FPSCR_REG): Define.
|
||||||
|
(FIRST_PSEUDO_REGISTER: Now 49.
|
||||||
|
(FIXED_REGISTERS, CALL_USED_REGISTERS): Include values for registers.
|
||||||
|
(HARD_REGNO_NREGS): Special treatment of FIRST_XD_REG .. LAST_XD_REG.
|
||||||
|
(HARD_REGNO_MODE_OK): Update.
|
||||||
|
(enum reg_class): Add DF_REGS and FPSCR_REGS.
|
||||||
|
(REG_CLASS_NAMES, REG_CLASS_CONTENTS, REG_ALLOC_ORDER): Likewise.
|
||||||
|
(SECONDARY_OUTPUT_RELOAD_CLASS, SECONDARY_INPUT_RELOAD_CLASS): Update.
|
||||||
|
(CLASS_CANNOT_CHANGE_SIZE, DEBUG_REGISTER_NAMES): Define.
|
||||||
|
(NPARM_REGS): Eight floating point parameter registers on SH4.
|
||||||
|
(BASE_RETURN_VALUE_REG): SH4 also passes double values
|
||||||
|
in floating point registers.
|
||||||
|
(GET_SH_ARG_CLASS) Likewise.
|
||||||
|
Complex float types are also returned in float registers.
|
||||||
|
(BASE_ARG_REG): Complex float types are also passes in float registers.
|
||||||
|
(FUNCTION_VALUE): Change mode like PROMOTE_MODE does.
|
||||||
|
(LIBCALL_VALUE): Remove trailing semicolon.
|
||||||
|
(ROUND_REG): Round when double precision value is passed in floating
|
||||||
|
point register(s).
|
||||||
|
(FUNCTION_ARG_ADVANCE): No change wanted for SH4 when things are
|
||||||
|
passed on the stack.
|
||||||
|
(FUNCTION_ARG): Little endian adjustment for SH4 SFmode.
|
||||||
|
(FUNCTION_ARG_PARTIAL_NREGS): Zero for SH4.
|
||||||
|
(TRAMPOLINE_ALIGNMENT): Take TARGET_HARWARD into account.
|
||||||
|
(INITIALIZE_TRAMPOLINE): Emit ic_invalidate_line for TARGET_HARWARD.
|
||||||
|
(MODE_DISP_OK_8): Not for SH4 DFmode.
|
||||||
|
(GO_IF_LEGITIMATE_ADDRESS): No base reg + index reg for SH4 DFmode.
|
||||||
|
Allow indexed addressing for PSImode after reload.
|
||||||
|
(LEGITIMIZE_ADDRESS): Not for SH4 DFmode.
|
||||||
|
(LEGITIMIZE_RELOAD_ADDRESS): Handle SH3E SFmode.
|
||||||
|
Don't change SH4 DFmode nor PSImode RELOAD_FOR_INPUT_ADDRESS.
|
||||||
|
(DOUBLE_TYPE_SIZE): 64 for SH4.
|
||||||
|
(RTX_COSTS): Add PLUS case.
|
||||||
|
Increae cost of ASHIFT, ASHIFTRT, LSHIFTRT case.
|
||||||
|
(REGISTER_MOVE_COST): Add handling of R0_REGS, FPUL_REGS, T_REGS,
|
||||||
|
MAC_REGS, PR_REGS, DF_REGS.
|
||||||
|
(REGISTER_NAMES): Use fp_reg_names.
|
||||||
|
(enum processor_type): Add PROCESSOR_SH4.
|
||||||
|
(sh_flag_remove_dead_before_cse): Declare.
|
||||||
|
(rtx_equal_function_value_matters, fpscr_rtx, get_fpscr_rtx): Declare.
|
||||||
|
(PREDICATE_CODES): Add binary_float_operator,
|
||||||
|
commutative_float_operator, fp_arith_reg_operand, fp_extended_operand,
|
||||||
|
fpscr_operand, noncommutative_float_operator.
|
||||||
|
(ADJUST_COST): Use different scale for TARGET_SUPERSCALAR.
|
||||||
|
(SH_DYNAMIC_SHIFT_COST): Cheaper for SH4.
|
||||||
|
* sh.md (attribute cpu): Add value sh4.
|
||||||
|
(attrbutes fmovd, issues): Define.
|
||||||
|
(attribute type): Add values dfp_arith, dfp_cmp, dfp_conv, dfdiv.
|
||||||
|
(function units memory, int, mpy, fp): Make dependent on issue rate.
|
||||||
|
(function units issue, single_issue, load_si, load): Define.
|
||||||
|
(function units load_store, fdiv, gp_fpul): Define.
|
||||||
|
(attribute hit_stack): Provide proper default.
|
||||||
|
(use_sfunc_addr+1, udivsi3): Predicated on ! TARGET_SH4.
|
||||||
|
(udivsi3_i4, udivsi3_i4_single, divsi3_i4, divsi3_i4_single): New insns.
|
||||||
|
(udivsi3, divsi3): Emit special patterns for SH4 hardware,
|
||||||
|
(mulsi3_call): Now uses match_operand for function address.
|
||||||
|
(mulsi3): Also emit code for SH1 case. Wrap result in REG_LIBCALL /
|
||||||
|
REG_RETVAL notes.
|
||||||
|
(push, pop, push_e, pop_e): Now define_expands.
|
||||||
|
(push_fpul, push_4, pop_fpul, pop_4, ic_invalidate_line): New expanders.
|
||||||
|
(movsi_ie): Added y/i alternative.
|
||||||
|
(ic_invalidate_line_i, movdf_i4): New insns.
|
||||||
|
(movdf_i4+[123], reload_outdf+[12345], movsi_y+[12]): New splitters.
|
||||||
|
(reload_indf, reload_outdf, reload_outsf, reload_insi): New expanders.
|
||||||
|
(movdf): Add special code for SH4.
|
||||||
|
(movsf_ie, movsf_ie+1, reload_insf, calli): Make use of fpscr visible.
|
||||||
|
(call_valuei, calli, call_value): Likewise.
|
||||||
|
(movsf): Emit no-op move.
|
||||||
|
(mov_nop, movsi_y): New insns.
|
||||||
|
(blt, sge): generalize to handle DFmode.
|
||||||
|
(return predicate): Call emit_fpscr_use and remove_dead_before_cse.
|
||||||
|
(block_move_real, block_lump_real): Predicate on ! TARGET_HARD_SH4.
|
||||||
|
(block_move_real_i4, block_lump_real_i4, fpu_switch): New insns.
|
||||||
|
(fpu_switch0, fpu_switch1, movpsi): New expanders.
|
||||||
|
(fpu_switch+[12], fix_truncsfsi2_i4_2+1): New splitters.
|
||||||
|
(toggle_sz): New insn.
|
||||||
|
(addsf3, subsf3, mulsf3, divsf3): Now define_expands.
|
||||||
|
(addsf3_i, subsf3_i, mulsf3_i4, mulsf3_ie, divsf3_i): New insns.
|
||||||
|
(macsf3): Make use of fpscr visible. Disable for SH4.
|
||||||
|
(floatsisf2): Make use of fpscr visible.
|
||||||
|
(floatsisf2_i4): New insn.
|
||||||
|
(floatsisf2_ie, fixsfsi, cmpgtsf_t, cmpeqsf_t): Disable for SH4.
|
||||||
|
(ieee_ccmpeqsf_t): Likewise.
|
||||||
|
(fix_truncsfsi2): Emit different code for SH4.
|
||||||
|
(fix_truncsfsi2_i4, fix_truncsfsi2_i4_2, cmpgtsf_t_i4): New insns.
|
||||||
|
(cmpeqsf_t_i4, ieee_ccmpeqsf_t_4): New insns.
|
||||||
|
(negsf2, sqrtsf2, abssf2): Now expanders.
|
||||||
|
(adddf3, subdf3i, muldf2, divdf3, floatsidf2): New expanders.
|
||||||
|
(negsf2_i, sqrtsf2_i, abssf2_i, adddf3_i, subdf3_i): New insns.
|
||||||
|
(muldf3_i, divdf3_i, floatsidf2_i, fix_truncdfsi2_i): New insns.
|
||||||
|
(fix_truncdfsi2, cmpdf, negdf2, sqrtdf2, absdf2): New expanders.
|
||||||
|
(fix_truncdfsi2_i4, cmpgtdf_t, cmpeqdf_t, ieee_ccmpeqdf_t): New insns.
|
||||||
|
(fix_truncdfsi2_i4_2+1): New splitters.
|
||||||
|
(negdf2_i, sqrtdf2_i, absdf2_i, extendsfdf2_i4): New insns.
|
||||||
|
(extendsfdf2, truncdfsf2): New expanders.
|
||||||
|
(truncdfsf2_i4): New insn.
|
||||||
|
* t-sh (LIB1ASMFUNCS): Add _movstr_i4, _sdivsi3_i4, _udivsi3_i4.
|
||||||
|
(MULTILIB_OPTIONS): Add m4-single-only/m4-single/m4.
|
||||||
|
* float-sh.h: When testing for __SH3E__, also test for
|
||||||
|
__SH4_SINGLE_ONLY__ .
|
||||||
|
* va-sh.h (__va_freg): Define to float.
|
||||||
|
(__va_greg, __fa_freg, __gnuc_va_list, va_start):
|
||||||
|
Define for __SH4_SINGLE_ONLY__ like for __SH3E__ .
|
||||||
|
(__PASS_AS_FLOAT, __TARGET_SH4_P): Likewise.
|
||||||
|
(__PASS_AS_FLOAT): Use different definition for __SH4__ and
|
||||||
|
__SH4_SINGLE__.
|
||||||
|
(TARGET_SH4_P): Define.
|
||||||
|
(va_arg): Use it.
|
||||||
|
|
||||||
|
* sh.md (movdf_k, movsf_i): Tweak the condition so that
|
||||||
|
init_expr_once is satisfied about the existence of load / store insns.
|
||||||
|
|
||||||
|
* sh.md (movsi_i, movsi_ie, movsi_i_lowpart, movsf_i, movsf_ie):
|
||||||
|
change m constraint in source operand to mr / mf .
|
||||||
|
|
||||||
|
* va-sh.h (__va_arg_sh1): Use __asm instead of asm.
|
||||||
|
|
||||||
|
* (__VA_REEF): Define.
|
||||||
|
(__va_arg_sh1): Use it.
|
||||||
|
|
||||||
|
* va-sh.h (va_start, va_arg, va_copy): Add parenteses.
|
||||||
|
|
||||||
Sun Nov 22 21:34:02 1998 Jeffrey A Law (law@cygnus.com)
|
Sun Nov 22 21:34:02 1998 Jeffrey A Law (law@cygnus.com)
|
||||||
|
|
||||||
* i386/dgux.c (struct option): Add new "description field".
|
* i386/dgux.c (struct option): Add new "description field".
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#undef FLT_MAX_10_EXP
|
#undef FLT_MAX_10_EXP
|
||||||
#define FLT_MAX_10_EXP 38
|
#define FLT_MAX_10_EXP 38
|
||||||
|
|
||||||
#ifdef __SH3E__
|
#if defined (__SH3E__) || defined (__SH4_SINGLE_ONLY__)
|
||||||
|
|
||||||
/* Number of base-FLT_RADIX digits in the significand of a double */
|
/* Number of base-FLT_RADIX digits in the significand of a double */
|
||||||
#undef DBL_MANT_DIG
|
#undef DBL_MANT_DIG
|
||||||
|
|
|
@ -770,6 +770,64 @@ ___movstr:
|
||||||
add #64,r4
|
add #64,r4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef L_movstr_i4
|
||||||
|
#if defined(__SH4__) || defined(__SH4_SINGLE__) || defined(__SH4_SINGLE_ONLY__)
|
||||||
|
.text
|
||||||
|
.global ___movstr_i4_even
|
||||||
|
.global ___movstr_i4_odd
|
||||||
|
.global ___movstrSI12_i4
|
||||||
|
|
||||||
|
.p2align 5
|
||||||
|
L_movstr_2mod4_end:
|
||||||
|
mov.l r0,@(16,r4)
|
||||||
|
rts
|
||||||
|
mov.l r1,@(20,r4)
|
||||||
|
|
||||||
|
.p2align 2
|
||||||
|
|
||||||
|
___movstr_i4_odd:
|
||||||
|
mov.l @r5+,r1
|
||||||
|
add #-4,r4
|
||||||
|
mov.l @r5+,r2
|
||||||
|
mov.l @r5+,r3
|
||||||
|
mov.l r1,@(4,r4)
|
||||||
|
mov.l r2,@(8,r4)
|
||||||
|
|
||||||
|
L_movstr_loop:
|
||||||
|
mov.l r3,@(12,r4)
|
||||||
|
dt r6
|
||||||
|
mov.l @r5+,r0
|
||||||
|
bt/s L_movstr_2mod4_end
|
||||||
|
mov.l @r5+,r1
|
||||||
|
add #16,r4
|
||||||
|
L_movstr_start_even:
|
||||||
|
mov.l @r5+,r2
|
||||||
|
mov.l @r5+,r3
|
||||||
|
mov.l r0,@r4
|
||||||
|
dt r6
|
||||||
|
mov.l r1,@(4,r4)
|
||||||
|
bf/s L_movstr_loop
|
||||||
|
mov.l r2,@(8,r4)
|
||||||
|
rts
|
||||||
|
mov.l r3,@(12,r4)
|
||||||
|
|
||||||
|
___movstr_i4_even:
|
||||||
|
mov.l @r5+,r0
|
||||||
|
bra L_movstr_start_even
|
||||||
|
mov.l @r5+,r1
|
||||||
|
|
||||||
|
.p2align 4
|
||||||
|
___movstrSI12_i4:
|
||||||
|
mov.l @r5,r0
|
||||||
|
mov.l @(4,r5),r1
|
||||||
|
mov.l @(8,r5),r2
|
||||||
|
mov.l r0,@r4
|
||||||
|
mov.l r1,@(4,r4)
|
||||||
|
rts
|
||||||
|
mov.l r2,@(8,r4)
|
||||||
|
#endif /* ! __SH4__ */
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef L_mulsi3
|
#ifdef L_mulsi3
|
||||||
|
|
||||||
|
|
||||||
|
@ -808,9 +866,47 @@ hiset: sts macl,r0 ! r0 = bb*dd
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#ifdef L_sdivsi3
|
#ifdef L_sdivsi3_i4
|
||||||
.title "SH DIVIDE"
|
.title "SH DIVIDE"
|
||||||
!! 4 byte integer Divide code for the Hitachi SH
|
!! 4 byte integer Divide code for the Hitachi SH
|
||||||
|
#ifdef __SH4__
|
||||||
|
!! args in r4 and r5, result in fpul, clobber dr0, dr2
|
||||||
|
|
||||||
|
.global ___sdivsi3_i4
|
||||||
|
___sdivsi3_i4:
|
||||||
|
lds r4,fpul
|
||||||
|
float fpul,dr0
|
||||||
|
lds r5,fpul
|
||||||
|
float fpul,dr2
|
||||||
|
fdiv dr2,dr0
|
||||||
|
rts
|
||||||
|
ftrc dr0,fpul
|
||||||
|
|
||||||
|
#elif defined(__SH4_SINGLE__) || defined(__SH4_SINGLE_ONLY__)
|
||||||
|
!! args in r4 and r5, result in fpul, clobber r2, dr0, dr2
|
||||||
|
|
||||||
|
.global ___sdivsi3_i4
|
||||||
|
___sdivsi3_i4:
|
||||||
|
sts.l fpscr,@-r15
|
||||||
|
mov #8,r2
|
||||||
|
swap.w r2,r2
|
||||||
|
lds r2,fpscr
|
||||||
|
lds r4,fpul
|
||||||
|
float fpul,dr0
|
||||||
|
lds r5,fpul
|
||||||
|
float fpul,dr2
|
||||||
|
fdiv dr2,dr0
|
||||||
|
ftrc dr0,fpul
|
||||||
|
rts
|
||||||
|
lds.l @r15+,fpscr
|
||||||
|
|
||||||
|
#endif /* ! __SH4__ */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef L_sdivsi3
|
||||||
|
/* __SH4_SINGLE_ONLY__ keeps this part for link compatibility with
|
||||||
|
sh3e code. */
|
||||||
|
#if ! defined(__SH4__) && ! defined (__SH4_SINGLE__)
|
||||||
!!
|
!!
|
||||||
!! Steve Chamberlain
|
!! Steve Chamberlain
|
||||||
!! sac@cygnus.com
|
!! sac@cygnus.com
|
||||||
|
@ -904,11 +1000,109 @@ ___sdivsi3:
|
||||||
div0: rts
|
div0: rts
|
||||||
mov #0,r0
|
mov #0,r0
|
||||||
|
|
||||||
|
#endif /* ! __SH4__ */
|
||||||
#endif
|
#endif
|
||||||
#ifdef L_udivsi3
|
#ifdef L_udivsi3_i4
|
||||||
|
|
||||||
.title "SH DIVIDE"
|
.title "SH DIVIDE"
|
||||||
!! 4 byte integer Divide code for the Hitachi SH
|
!! 4 byte integer Divide code for the Hitachi SH
|
||||||
|
#ifdef __SH4__
|
||||||
|
!! args in r4 and r5, result in fpul, clobber r0, r1, r4, r5, dr0, dr2, dr4
|
||||||
|
|
||||||
|
.global ___udivsi3_i4
|
||||||
|
___udivsi3_i4:
|
||||||
|
mov #1,r1
|
||||||
|
cmp/hi r1,r5
|
||||||
|
bf trivial
|
||||||
|
rotr r1
|
||||||
|
xor r1,r4
|
||||||
|
lds r4,fpul
|
||||||
|
mova L1,r0
|
||||||
|
#ifdef FMOVD_WORKS
|
||||||
|
fmov.d @r0+,dr4
|
||||||
|
#else
|
||||||
|
#ifdef __LITTLE_ENDIAN__
|
||||||
|
fmov.s @r0+,fr5
|
||||||
|
fmov.s @r0,fr4
|
||||||
|
#else
|
||||||
|
fmov.s @r0+,fr4
|
||||||
|
fmov.s @r0,fr5
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
float fpul,dr0
|
||||||
|
xor r1,r5
|
||||||
|
lds r5,fpul
|
||||||
|
float fpul,dr2
|
||||||
|
fadd dr4,dr0
|
||||||
|
fadd dr4,dr2
|
||||||
|
fdiv dr2,dr0
|
||||||
|
rts
|
||||||
|
ftrc dr0,fpul
|
||||||
|
|
||||||
|
trivial:
|
||||||
|
rts
|
||||||
|
lds r4,fpul
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
L1:
|
||||||
|
.double 2147483648
|
||||||
|
|
||||||
|
#elif defined(__SH4_SINGLE__) || defined(__SH4_SINGLE_ONLY__)
|
||||||
|
!! args in r4 and r5, result in fpul, clobber r0, r1, r4, r5, dr0, dr2, dr4
|
||||||
|
|
||||||
|
.global ___udivsi3_i4
|
||||||
|
___udivsi3_i4:
|
||||||
|
mov #1,r1
|
||||||
|
cmp/hi r1,r5
|
||||||
|
bf trivial
|
||||||
|
sts.l fpscr,@-r15
|
||||||
|
mova L1,r0
|
||||||
|
lds.l @r0+,fpscr
|
||||||
|
rotr r1
|
||||||
|
xor r1,r4
|
||||||
|
lds r4,fpul
|
||||||
|
#ifdef FMOVD_WORKS
|
||||||
|
fmov.d @r0+,dr4
|
||||||
|
#else
|
||||||
|
#ifdef __LITTLE_ENDIAN__
|
||||||
|
fmov.s @r0+,fr5
|
||||||
|
fmov.s @r0,fr4
|
||||||
|
#else
|
||||||
|
fmov.s @r0+,fr4
|
||||||
|
fmov.s @r0,fr5
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
float fpul,dr0
|
||||||
|
xor r1,r5
|
||||||
|
lds r5,fpul
|
||||||
|
float fpul,dr2
|
||||||
|
fadd dr4,dr0
|
||||||
|
fadd dr4,dr2
|
||||||
|
fdiv dr2,dr0
|
||||||
|
ftrc dr0,fpul
|
||||||
|
rts
|
||||||
|
lds.l @r15+,fpscr
|
||||||
|
|
||||||
|
trivial:
|
||||||
|
rts
|
||||||
|
lds r4,fpul
|
||||||
|
|
||||||
|
.align 2
|
||||||
|
L1:
|
||||||
|
#ifdef __LITTLE_ENDIAN__
|
||||||
|
.long 0x80000
|
||||||
|
#else
|
||||||
|
.long 0x180000
|
||||||
|
#endif
|
||||||
|
.double 2147483648
|
||||||
|
|
||||||
|
#endif /* ! __SH4__ */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef L_udivsi3
|
||||||
|
/* __SH4_SINGLE_ONLY__ keeps this part for link compatibility with
|
||||||
|
sh3e code. */
|
||||||
|
#if ! defined(__SH4__) && ! defined (__SH4_SINGLE__)
|
||||||
!!
|
!!
|
||||||
!! Steve Chamberlain
|
!! Steve Chamberlain
|
||||||
!! sac@cygnus.com
|
!! sac@cygnus.com
|
||||||
|
@ -966,22 +1160,40 @@ vshortway:
|
||||||
ret: rts
|
ret: rts
|
||||||
mov r4,r0
|
mov r4,r0
|
||||||
|
|
||||||
|
#endif /* __SH4__ */
|
||||||
#endif
|
#endif
|
||||||
#ifdef L_set_fpscr
|
#ifdef L_set_fpscr
|
||||||
#if defined (__SH3E__)
|
#if defined (__SH3E__) || defined(__SH4_SINGLE__) || defined(__SH4__) || defined(__SH4_SINGLE_ONLY__)
|
||||||
.global ___set_fpscr
|
.global ___set_fpscr
|
||||||
___set_fpscr:
|
___set_fpscr:
|
||||||
lds r4,fpscr
|
lds r4,fpscr
|
||||||
mov.l ___set_fpscr_L1,r1
|
mov.l ___set_fpscr_L1,r1
|
||||||
swap.w r4,r0
|
swap.w r4,r0
|
||||||
or #24,r0
|
or #24,r0
|
||||||
|
#ifndef FMOVD_WORKS
|
||||||
xor #16,r0
|
xor #16,r0
|
||||||
|
#endif
|
||||||
|
#if defined(__SH4__)
|
||||||
|
swap.w r0,r3
|
||||||
|
mov.l r3,@(4,r1)
|
||||||
|
#else /* defined(__SH3E__) || defined(__SH4_SINGLE*__) */
|
||||||
swap.w r0,r2
|
swap.w r0,r2
|
||||||
mov.l r2,@r1
|
mov.l r2,@r1
|
||||||
|
#endif
|
||||||
|
#ifndef FMOVD_WORKS
|
||||||
xor #8,r0
|
xor #8,r0
|
||||||
|
#else
|
||||||
|
xor #24,r0
|
||||||
|
#endif
|
||||||
|
#if defined(__SH4__)
|
||||||
|
swap.w r0,r2
|
||||||
|
rts
|
||||||
|
mov.l r2,@r1
|
||||||
|
#else /* defined(__SH3E__) || defined(__SH4_SINGLE*__) */
|
||||||
swap.w r0,r3
|
swap.w r0,r3
|
||||||
rts
|
rts
|
||||||
mov.l r3,@(4,r1)
|
mov.l r3,@(4,r1)
|
||||||
|
#endif
|
||||||
.align 2
|
.align 2
|
||||||
___set_fpscr_L1:
|
___set_fpscr_L1:
|
||||||
.long ___fpscr_values
|
.long ___fpscr_values
|
||||||
|
@ -990,5 +1202,5 @@ ___set_fpscr_L1:
|
||||||
#else
|
#else
|
||||||
.comm ___fpscr_values,8
|
.comm ___fpscr_values,8
|
||||||
#endif /* ELF */
|
#endif /* ELF */
|
||||||
#endif /* SH3E */
|
#endif /* SH3E / SH4 */
|
||||||
#endif /* L_set_fpscr */
|
#endif /* L_set_fpscr */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Output routines for GCC for Hitachi Super-H.
|
/* Output routines for GCC for Hitachi Super-H.
|
||||||
Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
|
Copyright (C) 1993-1998 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GNU CC.
|
This file is part of GNU CC.
|
||||||
|
|
||||||
|
@ -103,6 +103,17 @@ int regno_reg_class[FIRST_PSEUDO_REGISTER] =
|
||||||
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
||||||
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
||||||
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
FP_REGS, FP_REGS, FP_REGS, FP_REGS,
|
||||||
|
DF_REGS, DF_REGS, DF_REGS, DF_REGS,
|
||||||
|
DF_REGS, DF_REGS, DF_REGS, DF_REGS,
|
||||||
|
FPSCR_REGS,
|
||||||
|
};
|
||||||
|
|
||||||
|
char fp_reg_names[][5] =
|
||||||
|
{
|
||||||
|
"fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
|
||||||
|
"fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
|
||||||
|
"fpul",
|
||||||
|
"xd0","xd2","xd4", "xd6", "xd8", "xd10", "xd12", "xd14",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Provide reg_class from a letter such as appears in the machine
|
/* Provide reg_class from a letter such as appears in the machine
|
||||||
|
@ -110,7 +121,7 @@ int regno_reg_class[FIRST_PSEUDO_REGISTER] =
|
||||||
|
|
||||||
enum reg_class reg_class_from_letter[] =
|
enum reg_class reg_class_from_letter[] =
|
||||||
{
|
{
|
||||||
/* a */ NO_REGS, /* b */ NO_REGS, /* c */ NO_REGS, /* d */ NO_REGS,
|
/* a */ ALL_REGS, /* b */ NO_REGS, /* c */ FPSCR_REGS, /* d */ DF_REGS,
|
||||||
/* e */ NO_REGS, /* f */ FP_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
|
/* e */ NO_REGS, /* f */ FP_REGS, /* g */ NO_REGS, /* h */ NO_REGS,
|
||||||
/* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS,
|
/* i */ NO_REGS, /* j */ NO_REGS, /* k */ NO_REGS, /* l */ PR_REGS,
|
||||||
/* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,
|
/* m */ NO_REGS, /* n */ NO_REGS, /* o */ NO_REGS, /* p */ NO_REGS,
|
||||||
|
@ -119,6 +130,12 @@ enum reg_class reg_class_from_letter[] =
|
||||||
/* y */ FPUL_REGS, /* z */ R0_REGS
|
/* y */ FPUL_REGS, /* z */ R0_REGS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int assembler_dialect;
|
||||||
|
|
||||||
|
rtx get_fpscr_rtx ();
|
||||||
|
void emit_sf_insn ();
|
||||||
|
void emit_df_insn ();
|
||||||
|
|
||||||
static void split_branches PROTO ((rtx));
|
static void split_branches PROTO ((rtx));
|
||||||
|
|
||||||
/* Print the operand address in x to the stream. */
|
/* Print the operand address in x to the stream. */
|
||||||
|
@ -131,7 +148,8 @@ print_operand_address (stream, x)
|
||||||
switch (GET_CODE (x))
|
switch (GET_CODE (x))
|
||||||
{
|
{
|
||||||
case REG:
|
case REG:
|
||||||
fprintf (stream, "@%s", reg_names[REGNO (x)]);
|
case SUBREG:
|
||||||
|
fprintf (stream, "@%s", reg_names[true_regnum (x)]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PLUS:
|
case PLUS:
|
||||||
|
@ -143,13 +161,19 @@ print_operand_address (stream, x)
|
||||||
{
|
{
|
||||||
case CONST_INT:
|
case CONST_INT:
|
||||||
fprintf (stream, "@(%d,%s)", INTVAL (index),
|
fprintf (stream, "@(%d,%s)", INTVAL (index),
|
||||||
reg_names[REGNO (base)]);
|
reg_names[true_regnum (base)]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case REG:
|
case REG:
|
||||||
fprintf (stream, "@(r0,%s)",
|
case SUBREG:
|
||||||
reg_names[MAX (REGNO (base), REGNO (index))]);
|
{
|
||||||
break;
|
int base_num = true_regnum (base);
|
||||||
|
int index_num = true_regnum (index);
|
||||||
|
|
||||||
|
fprintf (stream, "@(r0,%s)",
|
||||||
|
reg_names[MAX (base_num, index_num)]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
debug_rtx (x);
|
debug_rtx (x);
|
||||||
|
@ -159,11 +183,11 @@ print_operand_address (stream, x)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PRE_DEC:
|
case PRE_DEC:
|
||||||
fprintf (stream, "@-%s", reg_names[REGNO (XEXP (x, 0))]);
|
fprintf (stream, "@-%s", reg_names[true_regnum (XEXP (x, 0))]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case POST_INC:
|
case POST_INC:
|
||||||
fprintf (stream, "@%s+", reg_names[REGNO (XEXP (x, 0))]);
|
fprintf (stream, "@%s+", reg_names[true_regnum (XEXP (x, 0))]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -182,7 +206,8 @@ print_operand_address (stream, x)
|
||||||
'O' print a constant without the #
|
'O' print a constant without the #
|
||||||
'R' print the LSW of a dp value - changes if in little endian
|
'R' print the LSW of a dp value - changes if in little endian
|
||||||
'S' print the MSW of a dp value - changes if in little endian
|
'S' print the MSW of a dp value - changes if in little endian
|
||||||
'T' print the next word of a dp value - same as 'R' in big endian mode. */
|
'T' print the next word of a dp value - same as 'R' in big endian mode.
|
||||||
|
'o' output an operator. */
|
||||||
|
|
||||||
void
|
void
|
||||||
print_operand (stream, x, code)
|
print_operand (stream, x, code)
|
||||||
|
@ -230,16 +255,31 @@ print_operand (stream, x, code)
|
||||||
fputs (reg_names[REGNO (x) + 1], (stream));
|
fputs (reg_names[REGNO (x) + 1], (stream));
|
||||||
break;
|
break;
|
||||||
case MEM:
|
case MEM:
|
||||||
print_operand_address (stream,
|
if (GET_CODE (XEXP (x, 0)) != PRE_DEC
|
||||||
XEXP (adj_offsettable_operand (x, 4), 0));
|
&& GET_CODE (XEXP (x, 0)) != POST_INC)
|
||||||
|
x = adj_offsettable_operand (x, 4);
|
||||||
|
print_operand_address (stream, XEXP (x, 0));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'o':
|
||||||
|
switch (GET_CODE (x))
|
||||||
|
{
|
||||||
|
case PLUS: fputs ("add", stream); break;
|
||||||
|
case MINUS: fputs ("sub", stream); break;
|
||||||
|
case MULT: fputs ("mul", stream); break;
|
||||||
|
case DIV: fputs ("div", stream); break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
switch (GET_CODE (x))
|
switch (GET_CODE (x))
|
||||||
{
|
{
|
||||||
case REG:
|
case REG:
|
||||||
fputs (reg_names[REGNO (x)], (stream));
|
if (REGNO (x) >= FIRST_FP_REG && REGNO (x) <= LAST_FP_REG
|
||||||
|
&& GET_MODE_SIZE (GET_MODE (x)) > 4)
|
||||||
|
fprintf ((stream), "d%s", reg_names[REGNO (x)]+1);
|
||||||
|
else
|
||||||
|
fputs (reg_names[REGNO (x)], (stream));
|
||||||
break;
|
break;
|
||||||
case MEM:
|
case MEM:
|
||||||
output_address (XEXP (x, 0));
|
output_address (XEXP (x, 0));
|
||||||
|
@ -273,6 +313,55 @@ expand_block_move (operands)
|
||||||
if (! constp || align < 4 || (bytes % 4 != 0))
|
if (! constp || align < 4 || (bytes % 4 != 0))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (TARGET_HARD_SH4)
|
||||||
|
{
|
||||||
|
if (bytes < 12)
|
||||||
|
return 0;
|
||||||
|
else if (bytes == 12)
|
||||||
|
{
|
||||||
|
tree entry_name;
|
||||||
|
rtx func_addr_rtx;
|
||||||
|
rtx r4 = gen_rtx (REG, SImode, 4);
|
||||||
|
rtx r5 = gen_rtx (REG, SImode, 5);
|
||||||
|
|
||||||
|
entry_name = get_identifier ("__movstrSI12_i4");
|
||||||
|
|
||||||
|
func_addr_rtx
|
||||||
|
= copy_to_mode_reg (Pmode,
|
||||||
|
gen_rtx_SYMBOL_REF (Pmode,
|
||||||
|
IDENTIFIER_POINTER (entry_name)));
|
||||||
|
emit_insn (gen_move_insn (r4, XEXP (operands[0], 0)));
|
||||||
|
emit_insn (gen_move_insn (r5, XEXP (operands[1], 0)));
|
||||||
|
emit_insn (gen_block_move_real_i4 (func_addr_rtx));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (! TARGET_SMALLCODE)
|
||||||
|
{
|
||||||
|
tree entry_name;
|
||||||
|
rtx func_addr_rtx;
|
||||||
|
int dwords;
|
||||||
|
rtx r4 = gen_rtx (REG, SImode, 4);
|
||||||
|
rtx r5 = gen_rtx (REG, SImode, 5);
|
||||||
|
rtx r6 = gen_rtx (REG, SImode, 6);
|
||||||
|
|
||||||
|
entry_name = get_identifier (bytes & 4
|
||||||
|
? "__movstr_i4_odd"
|
||||||
|
: "__movstr_i4_even");
|
||||||
|
func_addr_rtx
|
||||||
|
= copy_to_mode_reg (Pmode,
|
||||||
|
gen_rtx_SYMBOL_REF (Pmode,
|
||||||
|
IDENTIFIER_POINTER (entry_name)));
|
||||||
|
emit_insn (gen_move_insn (r4, XEXP (operands[0], 0)));
|
||||||
|
emit_insn (gen_move_insn (r5, XEXP (operands[1], 0)));
|
||||||
|
|
||||||
|
dwords = bytes >> 3;
|
||||||
|
emit_insn (gen_move_insn (r6, GEN_INT (dwords - 1)));
|
||||||
|
emit_insn (gen_block_lump_real_i4 (func_addr_rtx));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (bytes < 64)
|
if (bytes < 64)
|
||||||
{
|
{
|
||||||
char entry[30];
|
char entry[30];
|
||||||
|
@ -405,9 +494,17 @@ prepare_scc_operands (code)
|
||||||
|| TARGET_SH3E && GET_MODE_CLASS (mode) == MODE_FLOAT)
|
|| TARGET_SH3E && GET_MODE_CLASS (mode) == MODE_FLOAT)
|
||||||
sh_compare_op1 = force_reg (mode, sh_compare_op1);
|
sh_compare_op1 = force_reg (mode, sh_compare_op1);
|
||||||
|
|
||||||
emit_insn (gen_rtx (SET, VOIDmode, t_reg,
|
if (TARGET_SH4 && GET_MODE_CLASS (mode) == MODE_FLOAT)
|
||||||
gen_rtx (code, SImode, sh_compare_op0,
|
(mode == SFmode ? emit_sf_insn : emit_df_insn)
|
||||||
sh_compare_op1)));
|
(gen_rtx (PARALLEL, VOIDmode, gen_rtvec (2,
|
||||||
|
gen_rtx (SET, VOIDmode, t_reg,
|
||||||
|
gen_rtx (code, SImode,
|
||||||
|
sh_compare_op0, sh_compare_op1)),
|
||||||
|
gen_rtx (USE, VOIDmode, get_fpscr_rtx ()))));
|
||||||
|
else
|
||||||
|
emit_insn (gen_rtx (SET, VOIDmode, t_reg,
|
||||||
|
gen_rtx (code, SImode, sh_compare_op0,
|
||||||
|
sh_compare_op1)));
|
||||||
|
|
||||||
return t_reg;
|
return t_reg;
|
||||||
}
|
}
|
||||||
|
@ -443,7 +540,15 @@ from_compare (operands, code)
|
||||||
insn = gen_rtx (SET, VOIDmode,
|
insn = gen_rtx (SET, VOIDmode,
|
||||||
gen_rtx (REG, SImode, 18),
|
gen_rtx (REG, SImode, 18),
|
||||||
gen_rtx (code, SImode, sh_compare_op0, sh_compare_op1));
|
gen_rtx (code, SImode, sh_compare_op0, sh_compare_op1));
|
||||||
emit_insn (insn);
|
if (TARGET_SH4 && GET_MODE_CLASS (mode) == MODE_FLOAT)
|
||||||
|
{
|
||||||
|
insn = gen_rtx (PARALLEL, VOIDmode,
|
||||||
|
gen_rtvec (2, insn,
|
||||||
|
gen_rtx (USE, VOIDmode, get_fpscr_rtx ())));
|
||||||
|
(mode == SFmode ? emit_sf_insn : emit_df_insn) (insn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
emit_insn (insn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Functions to output assembly code. */
|
/* Functions to output assembly code. */
|
||||||
|
@ -1722,7 +1827,8 @@ static int pool_size;
|
||||||
/* Add a constant to the pool and return its label. */
|
/* Add a constant to the pool and return its label. */
|
||||||
|
|
||||||
static rtx
|
static rtx
|
||||||
add_constant (x, mode)
|
add_constant (x, mode, last_value)
|
||||||
|
rtx last_value;
|
||||||
rtx x;
|
rtx x;
|
||||||
enum machine_mode mode;
|
enum machine_mode mode;
|
||||||
{
|
{
|
||||||
|
@ -1741,13 +1847,27 @@ add_constant (x, mode)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (rtx_equal_p (x, pool_vector[i].value))
|
if (rtx_equal_p (x, pool_vector[i].value))
|
||||||
return pool_vector[i].label;
|
{
|
||||||
|
lab = 0;
|
||||||
|
if (! last_value
|
||||||
|
|| ! i
|
||||||
|
|| ! rtx_equal_p (last_value, pool_vector[i-1].value))
|
||||||
|
{
|
||||||
|
lab = pool_vector[i].label;
|
||||||
|
if (! lab)
|
||||||
|
pool_vector[i].label = lab = gen_label_rtx ();
|
||||||
|
}
|
||||||
|
return lab;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Need a new one. */
|
/* Need a new one. */
|
||||||
pool_vector[pool_size].value = x;
|
pool_vector[pool_size].value = x;
|
||||||
lab = gen_label_rtx ();
|
if (last_value && rtx_equal_p (last_value, pool_vector[pool_size - 1].value))
|
||||||
|
lab = 0;
|
||||||
|
else
|
||||||
|
lab = gen_label_rtx ();
|
||||||
pool_vector[pool_size].mode = mode;
|
pool_vector[pool_size].mode = mode;
|
||||||
pool_vector[pool_size].label = lab;
|
pool_vector[pool_size].label = lab;
|
||||||
pool_size++;
|
pool_size++;
|
||||||
|
@ -1965,7 +2085,8 @@ find_barrier (num_mova, mova, from)
|
||||||
/* We must explicitly check the mode, because sometimes the
|
/* We must explicitly check the mode, because sometimes the
|
||||||
front end will generate code to load unsigned constants into
|
front end will generate code to load unsigned constants into
|
||||||
HImode targets without properly sign extending them. */
|
HImode targets without properly sign extending them. */
|
||||||
if (mode == HImode || (mode == SImode && hi_const (src)))
|
if (mode == HImode
|
||||||
|
|| (mode == SImode && hi_const (src) && REGNO (dst) != FPUL_REG))
|
||||||
{
|
{
|
||||||
found_hi += 2;
|
found_hi += 2;
|
||||||
/* We put the short constants before the long constants, so
|
/* We put the short constants before the long constants, so
|
||||||
|
@ -2130,7 +2251,7 @@ sfunc_uses_reg (insn)
|
||||||
for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
|
for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
part = XVECEXP (pattern, 0, i);
|
part = XVECEXP (pattern, 0, i);
|
||||||
if (part == reg_part)
|
if (part == reg_part || GET_CODE (part) == CLOBBER)
|
||||||
continue;
|
continue;
|
||||||
if (reg_mentioned_p (reg, ((GET_CODE (part) == SET
|
if (reg_mentioned_p (reg, ((GET_CODE (part) == SET
|
||||||
&& GET_CODE (SET_DEST (part)) == REG)
|
&& GET_CODE (SET_DEST (part)) == REG)
|
||||||
|
@ -2470,6 +2591,13 @@ gen_far_branch (bp)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
jump = emit_jump_insn_after (gen_return (), insn);
|
jump = emit_jump_insn_after (gen_return (), insn);
|
||||||
|
/* Emit a barrier so that reorg knows that any following instructions
|
||||||
|
are not reachable via a fall-through path.
|
||||||
|
But don't do this when not optimizing, since we wouldn't supress the
|
||||||
|
alignment for the barrier then, and could end up with out-of-range
|
||||||
|
pc-relative loads. */
|
||||||
|
if (optimize)
|
||||||
|
emit_barrier_after (jump);
|
||||||
emit_label_after (bp->near_label, insn);
|
emit_label_after (bp->near_label, insn);
|
||||||
JUMP_LABEL (jump) = bp->far_label;
|
JUMP_LABEL (jump) = bp->far_label;
|
||||||
if (! invert_jump (insn, label))
|
if (! invert_jump (insn, label))
|
||||||
|
@ -2556,36 +2684,42 @@ barrier_align (barrier_or_label)
|
||||||
if (! TARGET_SH3 || ! optimize)
|
if (! TARGET_SH3 || ! optimize)
|
||||||
return CACHE_LOG;
|
return CACHE_LOG;
|
||||||
|
|
||||||
/* Check if there is an immediately preceding branch to the insn beyond
|
/* When fixing up pcloads, a constant table might be inserted just before
|
||||||
the barrier. We must weight the cost of discarding useful information
|
the basic block that ends with the barrier. Thus, we can't trust the
|
||||||
from the current cache line when executing this branch and there is
|
instruction lengths before that. */
|
||||||
an alignment, against that of fetching unneeded insn in front of the
|
if (mdep_reorg_phase > SH_FIXUP_PCLOAD)
|
||||||
branch target when there is no alignment. */
|
|
||||||
|
|
||||||
/* PREV is presumed to be the JUMP_INSN for the barrier under
|
|
||||||
investigation. Skip to the insn before it. */
|
|
||||||
prev = prev_real_insn (prev);
|
|
||||||
|
|
||||||
for (slot = 2, credit = 1 << (CACHE_LOG - 2) + 2;
|
|
||||||
credit >= 0 && prev && GET_CODE (prev) == INSN;
|
|
||||||
prev = prev_real_insn (prev))
|
|
||||||
{
|
{
|
||||||
if (GET_CODE (PATTERN (prev)) == USE
|
/* Check if there is an immediately preceding branch to the insn beyond
|
||||||
|| GET_CODE (PATTERN (prev)) == CLOBBER)
|
the barrier. We must weight the cost of discarding useful information
|
||||||
continue;
|
from the current cache line when executing this branch and there is
|
||||||
if (GET_CODE (PATTERN (prev)) == SEQUENCE)
|
an alignment, against that of fetching unneeded insn in front of the
|
||||||
prev = XVECEXP (PATTERN (prev), 0, 1);
|
branch target when there is no alignment. */
|
||||||
if (slot &&
|
|
||||||
get_attr_in_delay_slot (prev) == IN_DELAY_SLOT_YES)
|
/* PREV is presumed to be the JUMP_INSN for the barrier under
|
||||||
slot = 0;
|
investigation. Skip to the insn before it. */
|
||||||
credit -= get_attr_length (prev);
|
prev = prev_real_insn (prev);
|
||||||
|
|
||||||
|
for (slot = 2, credit = 1 << (CACHE_LOG - 2) + 2;
|
||||||
|
credit >= 0 && prev && GET_CODE (prev) == INSN;
|
||||||
|
prev = prev_real_insn (prev))
|
||||||
|
{
|
||||||
|
if (GET_CODE (PATTERN (prev)) == USE
|
||||||
|
|| GET_CODE (PATTERN (prev)) == CLOBBER)
|
||||||
|
continue;
|
||||||
|
if (GET_CODE (PATTERN (prev)) == SEQUENCE)
|
||||||
|
prev = XVECEXP (PATTERN (prev), 0, 1);
|
||||||
|
if (slot &&
|
||||||
|
get_attr_in_delay_slot (prev) == IN_DELAY_SLOT_YES)
|
||||||
|
slot = 0;
|
||||||
|
credit -= get_attr_length (prev);
|
||||||
|
}
|
||||||
|
if (prev
|
||||||
|
&& GET_CODE (prev) == JUMP_INSN
|
||||||
|
&& JUMP_LABEL (prev)
|
||||||
|
&& next_real_insn (JUMP_LABEL (prev)) == next_real_insn (barrier_or_label)
|
||||||
|
&& (credit - slot >= (GET_CODE (SET_SRC (PATTERN (prev))) == PC ? 2 : 0)))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
if (prev
|
|
||||||
&& GET_CODE (prev) == JUMP_INSN
|
|
||||||
&& JUMP_LABEL (prev)
|
|
||||||
&& next_real_insn (JUMP_LABEL (prev)) == next_real_insn (barrier_or_label)
|
|
||||||
&& (credit - slot >= (GET_CODE (SET_SRC (PATTERN (prev))) == PC ? 2 : 0)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return CACHE_LOG;
|
return CACHE_LOG;
|
||||||
}
|
}
|
||||||
|
@ -2914,7 +3048,8 @@ machine_dependent_reorg (first)
|
||||||
dst = SET_DEST (pat);
|
dst = SET_DEST (pat);
|
||||||
mode = GET_MODE (dst);
|
mode = GET_MODE (dst);
|
||||||
|
|
||||||
if (mode == SImode && hi_const (src))
|
if (mode == SImode && hi_const (src)
|
||||||
|
&& REGNO (dst) != FPUL_REG)
|
||||||
{
|
{
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
|
|
||||||
|
@ -2929,7 +3064,7 @@ machine_dependent_reorg (first)
|
||||||
|
|
||||||
if (GET_CODE (dst) == REG
|
if (GET_CODE (dst) == REG
|
||||||
&& ((REGNO (dst) >= FIRST_FP_REG
|
&& ((REGNO (dst) >= FIRST_FP_REG
|
||||||
&& REGNO (dst) <= LAST_FP_REG)
|
&& REGNO (dst) <= LAST_XD_REG)
|
||||||
|| REGNO (dst) == FPUL_REG))
|
|| REGNO (dst) == FPUL_REG))
|
||||||
{
|
{
|
||||||
if (last_float
|
if (last_float
|
||||||
|
@ -2943,7 +3078,8 @@ machine_dependent_reorg (first)
|
||||||
last_float_move = scan;
|
last_float_move = scan;
|
||||||
last_float = src;
|
last_float = src;
|
||||||
newsrc = gen_rtx (MEM, mode,
|
newsrc = gen_rtx (MEM, mode,
|
||||||
(REGNO (dst) == FPUL_REG
|
((TARGET_SH4 && ! TARGET_FMOVD
|
||||||
|
|| REGNO (dst) == FPUL_REG)
|
||||||
? r0_inc_rtx
|
? r0_inc_rtx
|
||||||
: r0_rtx));
|
: r0_rtx));
|
||||||
last_float_addr = &XEXP (newsrc, 0);
|
last_float_addr = &XEXP (newsrc, 0);
|
||||||
|
@ -2983,6 +3119,16 @@ machine_dependent_reorg (first)
|
||||||
emit_insn_before (gen_use_sfunc_addr (reg), insn);
|
emit_insn_before (gen_use_sfunc_addr (reg), insn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
/* fpscr is not actually a user variable, but we pretend it is for the
|
||||||
|
sake of the previous optimization passes, since we want it handled like
|
||||||
|
one. However, we don't have eny debugging information for it, so turn
|
||||||
|
it into a non-user variable now. */
|
||||||
|
if (TARGET_SH4)
|
||||||
|
REG_USERVAR_P (get_fpscr_rtx ()) = 0;
|
||||||
|
#endif
|
||||||
|
if (optimize)
|
||||||
|
sh_flag_remove_dead_before_cse = 1;
|
||||||
mdep_reorg_phase = SH_AFTER_MDEP_REORG;
|
mdep_reorg_phase = SH_AFTER_MDEP_REORG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3386,8 +3532,16 @@ push (rn)
|
||||||
int rn;
|
int rn;
|
||||||
{
|
{
|
||||||
rtx x;
|
rtx x;
|
||||||
if ((rn >= FIRST_FP_REG && rn <= LAST_FP_REG)
|
if (rn == FPUL_REG)
|
||||||
|| rn == FPUL_REG)
|
x = gen_push_fpul ();
|
||||||
|
else if (TARGET_SH4 && TARGET_FMOVD && ! TARGET_FPU_SINGLE
|
||||||
|
&& rn >= FIRST_FP_REG && rn <= LAST_XD_REG)
|
||||||
|
{
|
||||||
|
if ((rn - FIRST_FP_REG) & 1 && rn <= LAST_FP_REG)
|
||||||
|
return;
|
||||||
|
x = gen_push_4 (gen_rtx (REG, DFmode, rn));
|
||||||
|
}
|
||||||
|
else if (TARGET_SH3E && rn >= FIRST_FP_REG && rn <= LAST_FP_REG)
|
||||||
x = gen_push_e (gen_rtx (REG, SFmode, rn));
|
x = gen_push_e (gen_rtx (REG, SFmode, rn));
|
||||||
else
|
else
|
||||||
x = gen_push (gen_rtx (REG, SImode, rn));
|
x = gen_push (gen_rtx (REG, SImode, rn));
|
||||||
|
@ -3404,8 +3558,16 @@ pop (rn)
|
||||||
int rn;
|
int rn;
|
||||||
{
|
{
|
||||||
rtx x;
|
rtx x;
|
||||||
if ((rn >= FIRST_FP_REG && rn <= LAST_FP_REG)
|
if (rn == FPUL_REG)
|
||||||
|| rn == FPUL_REG)
|
x = gen_pop_fpul ();
|
||||||
|
else if (TARGET_SH4 && TARGET_FMOVD && ! TARGET_FPU_SINGLE
|
||||||
|
&& rn >= FIRST_FP_REG && rn <= LAST_XD_REG)
|
||||||
|
{
|
||||||
|
if ((rn - FIRST_FP_REG) & 1 && rn <= LAST_FP_REG)
|
||||||
|
return;
|
||||||
|
x = gen_pop_4 (gen_rtx (REG, DFmode, rn));
|
||||||
|
}
|
||||||
|
else if (TARGET_SH3E && rn >= FIRST_FP_REG && rn <= LAST_FP_REG)
|
||||||
x = gen_pop_e (gen_rtx (REG, SFmode, rn));
|
x = gen_pop_e (gen_rtx (REG, SFmode, rn));
|
||||||
else
|
else
|
||||||
x = gen_pop (gen_rtx (REG, SImode, rn));
|
x = gen_pop (gen_rtx (REG, SImode, rn));
|
||||||
|
@ -3453,6 +3615,16 @@ calc_live_regs (count_ptr, live_regs_mask2)
|
||||||
int count;
|
int count;
|
||||||
|
|
||||||
*live_regs_mask2 = 0;
|
*live_regs_mask2 = 0;
|
||||||
|
/* If we can save a lot of saves by switching to double mode, do that. */
|
||||||
|
if (TARGET_SH4 && TARGET_FMOVD && TARGET_FPU_SINGLE)
|
||||||
|
for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
|
||||||
|
if (regs_ever_live[reg] && regs_ever_live[reg+1]
|
||||||
|
&& (! call_used_regs[reg] || (pragma_interrupt && ! pragma_trapa))
|
||||||
|
&& ++count > 2)
|
||||||
|
{
|
||||||
|
target_flags &= ~FPU_SINGLE_BIT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
for (count = 0, reg = FIRST_PSEUDO_REGISTER - 1; reg >= 0; reg--)
|
for (count = 0, reg = FIRST_PSEUDO_REGISTER - 1; reg >= 0; reg--)
|
||||||
{
|
{
|
||||||
if ((pragma_interrupt && ! pragma_trapa)
|
if ((pragma_interrupt && ! pragma_trapa)
|
||||||
|
@ -3463,7 +3635,7 @@ calc_live_regs (count_ptr, live_regs_mask2)
|
||||||
&& regs_ever_live[PR_REG]))
|
&& regs_ever_live[PR_REG]))
|
||||||
&& reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM
|
&& reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM
|
||||||
&& reg != RETURN_ADDRESS_POINTER_REGNUM
|
&& reg != RETURN_ADDRESS_POINTER_REGNUM
|
||||||
&& reg != T_REG && reg != GBR_REG)
|
&& reg != T_REG && reg != GBR_REG && reg != FPSCR_REG)
|
||||||
: (/* Only push those regs which are used and need to be saved. */
|
: (/* Only push those regs which are used and need to be saved. */
|
||||||
regs_ever_live[reg] && ! call_used_regs[reg]))
|
regs_ever_live[reg] && ! call_used_regs[reg]))
|
||||||
{
|
{
|
||||||
|
@ -3472,6 +3644,24 @@ calc_live_regs (count_ptr, live_regs_mask2)
|
||||||
else
|
else
|
||||||
live_regs_mask |= 1 << reg;
|
live_regs_mask |= 1 << reg;
|
||||||
count++;
|
count++;
|
||||||
|
if (TARGET_SH4 && TARGET_FMOVD && reg >= FIRST_FP_REG)
|
||||||
|
if (reg <= LAST_FP_REG)
|
||||||
|
{
|
||||||
|
if (! TARGET_FPU_SINGLE && ! regs_ever_live[reg ^ 1])
|
||||||
|
{
|
||||||
|
if (reg >= 32)
|
||||||
|
*live_regs_mask2 |= 1 << ((reg ^ 1) - 32);
|
||||||
|
else
|
||||||
|
live_regs_mask |= 1 << (reg ^ 1);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (reg <= LAST_XD_REG)
|
||||||
|
{
|
||||||
|
/* Must switch to double mode to access these registers. */
|
||||||
|
target_flags &= ~FPU_SINGLE_BIT;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3487,6 +3677,7 @@ sh_expand_prologue ()
|
||||||
int live_regs_mask;
|
int live_regs_mask;
|
||||||
int d, i;
|
int d, i;
|
||||||
int live_regs_mask2;
|
int live_regs_mask2;
|
||||||
|
int save_flags = target_flags;
|
||||||
int double_align = 0;
|
int double_align = 0;
|
||||||
|
|
||||||
/* We have pretend args if we had an object sent partially in registers
|
/* We have pretend args if we had an object sent partially in registers
|
||||||
|
@ -3524,11 +3715,19 @@ sh_expand_prologue ()
|
||||||
emit_insn (gen_sp_switch_1 ());
|
emit_insn (gen_sp_switch_1 ());
|
||||||
|
|
||||||
live_regs_mask = calc_live_regs (&d, &live_regs_mask2);
|
live_regs_mask = calc_live_regs (&d, &live_regs_mask2);
|
||||||
|
/* ??? Maybe we could save some switching if we can move a mode switch
|
||||||
|
that already happens to be at the function start into the prologue. */
|
||||||
|
if (target_flags != save_flags)
|
||||||
|
emit_insn (gen_toggle_sz ());
|
||||||
push_regs (live_regs_mask, live_regs_mask2);
|
push_regs (live_regs_mask, live_regs_mask2);
|
||||||
|
if (target_flags != save_flags)
|
||||||
|
emit_insn (gen_toggle_sz ());
|
||||||
|
|
||||||
if (TARGET_ALIGN_DOUBLE && d & 1)
|
if (TARGET_ALIGN_DOUBLE && d & 1)
|
||||||
double_align = 4;
|
double_align = 4;
|
||||||
|
|
||||||
|
target_flags = save_flags;
|
||||||
|
|
||||||
output_stack_adjust (-get_frame_size () - double_align,
|
output_stack_adjust (-get_frame_size () - double_align,
|
||||||
stack_pointer_rtx, 3);
|
stack_pointer_rtx, 3);
|
||||||
|
|
||||||
|
@ -3543,6 +3742,7 @@ sh_expand_epilogue ()
|
||||||
int d, i;
|
int d, i;
|
||||||
|
|
||||||
int live_regs_mask2;
|
int live_regs_mask2;
|
||||||
|
int save_flags = target_flags;
|
||||||
int frame_size = get_frame_size ();
|
int frame_size = get_frame_size ();
|
||||||
|
|
||||||
live_regs_mask = calc_live_regs (&d, &live_regs_mask2);
|
live_regs_mask = calc_live_regs (&d, &live_regs_mask2);
|
||||||
|
@ -3573,7 +3773,8 @@ sh_expand_epilogue ()
|
||||||
|
|
||||||
/* Pop all the registers. */
|
/* Pop all the registers. */
|
||||||
|
|
||||||
live_regs_mask = calc_live_regs (&d, &live_regs_mask2);
|
if (target_flags != save_flags)
|
||||||
|
emit_insn (gen_toggle_sz ());
|
||||||
if (live_regs_mask & (1 << PR_REG))
|
if (live_regs_mask & (1 << PR_REG))
|
||||||
pop (PR_REG);
|
pop (PR_REG);
|
||||||
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
||||||
|
@ -3584,6 +3785,9 @@ sh_expand_epilogue ()
|
||||||
else if (j >= 32 && (live_regs_mask2 & (1 << (j - 32))))
|
else if (j >= 32 && (live_regs_mask2 & (1 << (j - 32))))
|
||||||
pop (j);
|
pop (j);
|
||||||
}
|
}
|
||||||
|
if (target_flags != save_flags)
|
||||||
|
emit_insn (gen_toggle_sz ());
|
||||||
|
target_flags = save_flags;
|
||||||
|
|
||||||
output_stack_adjust (extra_push + current_function_pretend_args_size,
|
output_stack_adjust (extra_push + current_function_pretend_args_size,
|
||||||
stack_pointer_rtx, 7);
|
stack_pointer_rtx, 7);
|
||||||
|
@ -3651,6 +3855,25 @@ sh_builtin_saveregs (arglist)
|
||||||
emit_move_insn (fpregs, XEXP (regbuf, 0));
|
emit_move_insn (fpregs, XEXP (regbuf, 0));
|
||||||
emit_insn (gen_addsi3 (fpregs, fpregs,
|
emit_insn (gen_addsi3 (fpregs, fpregs,
|
||||||
GEN_INT (n_floatregs * UNITS_PER_WORD)));
|
GEN_INT (n_floatregs * UNITS_PER_WORD)));
|
||||||
|
if (TARGET_SH4)
|
||||||
|
{
|
||||||
|
for (regno = NPARM_REGS (DFmode) - 2; regno >= first_floatreg; regno -= 2)
|
||||||
|
{
|
||||||
|
emit_insn (gen_addsi3 (fpregs, fpregs,
|
||||||
|
GEN_INT (-2 * UNITS_PER_WORD)));
|
||||||
|
emit_move_insn (gen_rtx (MEM, DFmode, fpregs),
|
||||||
|
gen_rtx (REG, DFmode, BASE_ARG_REG (DFmode) + regno));
|
||||||
|
}
|
||||||
|
regno = first_floatreg;
|
||||||
|
if (regno & 1)
|
||||||
|
{
|
||||||
|
emit_insn (gen_addsi3 (fpregs, fpregs, GEN_INT (- UNITS_PER_WORD)));
|
||||||
|
emit_move_insn (gen_rtx (MEM, SFmode, fpregs),
|
||||||
|
gen_rtx (REG, SFmode, BASE_ARG_REG (SFmode) + regno
|
||||||
|
- (TARGET_LITTLE_ENDIAN != 0)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
for (regno = NPARM_REGS (SFmode) - 1; regno >= first_floatreg; regno--)
|
for (regno = NPARM_REGS (SFmode) - 1; regno >= first_floatreg; regno--)
|
||||||
{
|
{
|
||||||
emit_insn (gen_addsi3 (fpregs, fpregs, GEN_INT (- UNITS_PER_WORD)));
|
emit_insn (gen_addsi3 (fpregs, fpregs, GEN_INT (- UNITS_PER_WORD)));
|
||||||
|
@ -3677,6 +3900,8 @@ initial_elimination_offset (from, to)
|
||||||
|
|
||||||
int live_regs_mask, live_regs_mask2;
|
int live_regs_mask, live_regs_mask2;
|
||||||
live_regs_mask = calc_live_regs (®s_saved, &live_regs_mask2);
|
live_regs_mask = calc_live_regs (®s_saved, &live_regs_mask2);
|
||||||
|
if (TARGET_ALIGN_DOUBLE && regs_saved & 1)
|
||||||
|
total_auto_space += 4;
|
||||||
target_flags = save_flags;
|
target_flags = save_flags;
|
||||||
|
|
||||||
total_saved_regs_space = (regs_saved) * 4;
|
total_saved_regs_space = (regs_saved) * 4;
|
||||||
|
@ -3885,12 +4110,48 @@ arith_reg_operand (op, mode)
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return (regno != T_REG && regno != PR_REG && regno != FPUL_REG
|
return (regno != T_REG && regno != PR_REG
|
||||||
|
&& (regno != FPUL_REG || TARGET_SH4)
|
||||||
&& regno != MACH_REG && regno != MACL_REG);
|
&& regno != MACH_REG && regno != MACL_REG);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fp_arith_reg_operand (op, mode)
|
||||||
|
rtx op;
|
||||||
|
enum machine_mode mode;
|
||||||
|
{
|
||||||
|
if (register_operand (op, mode))
|
||||||
|
{
|
||||||
|
int regno;
|
||||||
|
|
||||||
|
if (GET_CODE (op) == REG)
|
||||||
|
regno = REGNO (op);
|
||||||
|
else if (GET_CODE (op) == SUBREG && GET_CODE (SUBREG_REG (op)) == REG)
|
||||||
|
regno = REGNO (SUBREG_REG (op));
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return (regno != T_REG && regno != PR_REG && regno > 15
|
||||||
|
&& regno != MACH_REG && regno != MACL_REG);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fp_extended_operand (op, mode)
|
||||||
|
rtx op;
|
||||||
|
enum machine_mode mode;
|
||||||
|
{
|
||||||
|
if (GET_CODE (op) == FLOAT_EXTEND && GET_MODE (op) == mode)
|
||||||
|
{
|
||||||
|
op = XEXP (op, 0);
|
||||||
|
mode = GET_MODE (op);
|
||||||
|
}
|
||||||
|
return fp_arith_reg_operand (op, mode);
|
||||||
|
}
|
||||||
|
|
||||||
/* Returns 1 if OP is a valid source operand for an arithmetic insn. */
|
/* Returns 1 if OP is a valid source operand for an arithmetic insn. */
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -3991,6 +4252,73 @@ braf_label_ref_operand(op, mode)
|
||||||
if (GET_CODE (prev) != PLUS || XEXP (prev, 1) != op)
|
if (GET_CODE (prev) != PLUS || XEXP (prev, 1) != op)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
tertiary_reload_operand (op, mode)
|
||||||
|
rtx op;
|
||||||
|
enum machine_mode mode;
|
||||||
|
{
|
||||||
|
enum rtx_code code = GET_CODE (op);
|
||||||
|
return code == MEM || (TARGET_SH4 && code == CONST_DOUBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fpscr_operand (op)
|
||||||
|
rtx op;
|
||||||
|
{
|
||||||
|
return (GET_CODE (op) == REG && REGNO (op) == FPSCR_REG
|
||||||
|
&& GET_MODE (op) == PSImode);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
commutative_float_operator (op, mode)
|
||||||
|
rtx op;
|
||||||
|
enum machine_mode mode;
|
||||||
|
{
|
||||||
|
if (GET_MODE (op) != mode)
|
||||||
|
return 0;
|
||||||
|
switch (GET_CODE (op))
|
||||||
|
{
|
||||||
|
case PLUS:
|
||||||
|
case MULT:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
noncommutative_float_operator (op, mode)
|
||||||
|
rtx op;
|
||||||
|
enum machine_mode mode;
|
||||||
|
{
|
||||||
|
if (GET_MODE (op) != mode)
|
||||||
|
return 0;
|
||||||
|
switch (GET_CODE (op))
|
||||||
|
{
|
||||||
|
case MINUS:
|
||||||
|
case DIV:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
binary_float_operator (op, mode)
|
||||||
|
rtx op;
|
||||||
|
enum machine_mode mode;
|
||||||
|
{
|
||||||
|
if (GET_MODE (op) != mode)
|
||||||
|
return 0;
|
||||||
|
switch (GET_CODE (op))
|
||||||
|
{
|
||||||
|
case PLUS:
|
||||||
|
case MINUS:
|
||||||
|
case MULT:
|
||||||
|
case DIV:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the destination address of a branch. */
|
/* Return the destination address of a branch. */
|
||||||
|
|
||||||
|
@ -4102,3 +4430,304 @@ reg_unused_after (reg, insn)
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern struct obstack permanent_obstack;
|
||||||
|
|
||||||
|
rtx
|
||||||
|
get_fpscr_rtx ()
|
||||||
|
{
|
||||||
|
static rtx fpscr_rtx;
|
||||||
|
|
||||||
|
if (! fpscr_rtx)
|
||||||
|
{
|
||||||
|
push_obstacks (&permanent_obstack, &permanent_obstack);
|
||||||
|
fpscr_rtx = gen_rtx (REG, PSImode, 48);
|
||||||
|
REG_USERVAR_P (fpscr_rtx) = 1;
|
||||||
|
pop_obstacks ();
|
||||||
|
mark_user_reg (fpscr_rtx);
|
||||||
|
}
|
||||||
|
if (! reload_completed || mdep_reorg_phase != SH_AFTER_MDEP_REORG)
|
||||||
|
mark_user_reg (fpscr_rtx);
|
||||||
|
return fpscr_rtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
emit_sf_insn (pat)
|
||||||
|
rtx pat;
|
||||||
|
{
|
||||||
|
rtx addr;
|
||||||
|
/* When generating reload insns, we must not create new registers. FPSCR
|
||||||
|
should already have the correct value, so do nothing to change it. */
|
||||||
|
if (! TARGET_FPU_SINGLE && ! reload_in_progress)
|
||||||
|
{
|
||||||
|
addr = gen_reg_rtx (SImode);
|
||||||
|
emit_insn (gen_fpu_switch0 (addr));
|
||||||
|
}
|
||||||
|
emit_insn (pat);
|
||||||
|
if (! TARGET_FPU_SINGLE && ! reload_in_progress)
|
||||||
|
{
|
||||||
|
addr = gen_reg_rtx (SImode);
|
||||||
|
emit_insn (gen_fpu_switch1 (addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
emit_df_insn (pat)
|
||||||
|
rtx pat;
|
||||||
|
{
|
||||||
|
rtx addr;
|
||||||
|
if (TARGET_FPU_SINGLE && ! reload_in_progress)
|
||||||
|
{
|
||||||
|
addr = gen_reg_rtx (SImode);
|
||||||
|
emit_insn (gen_fpu_switch0 (addr));
|
||||||
|
}
|
||||||
|
emit_insn (pat);
|
||||||
|
if (TARGET_FPU_SINGLE && ! reload_in_progress)
|
||||||
|
{
|
||||||
|
addr = gen_reg_rtx (SImode);
|
||||||
|
emit_insn (gen_fpu_switch1 (addr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expand_sf_unop (fun, operands)
|
||||||
|
rtx (*fun)();
|
||||||
|
rtx *operands;
|
||||||
|
{
|
||||||
|
emit_sf_insn ((*fun) (operands[0], operands[1], get_fpscr_rtx ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expand_sf_binop (fun, operands)
|
||||||
|
rtx (*fun)();
|
||||||
|
rtx *operands;
|
||||||
|
{
|
||||||
|
emit_sf_insn ((*fun) (operands[0], operands[1], operands[2],
|
||||||
|
get_fpscr_rtx ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expand_df_unop (fun, operands)
|
||||||
|
rtx (*fun)();
|
||||||
|
rtx *operands;
|
||||||
|
{
|
||||||
|
emit_df_insn ((*fun) (operands[0], operands[1], get_fpscr_rtx ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expand_df_binop (fun, operands)
|
||||||
|
rtx (*fun)();
|
||||||
|
rtx *operands;
|
||||||
|
{
|
||||||
|
emit_df_insn ((*fun) (operands[0], operands[1], operands[2],
|
||||||
|
get_fpscr_rtx ()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
expand_fp_branch (compare, branch)
|
||||||
|
rtx (*compare) (), (*branch) ();
|
||||||
|
{
|
||||||
|
(GET_MODE (sh_compare_op0) == SFmode ? emit_sf_insn : emit_df_insn)
|
||||||
|
((*compare) ());
|
||||||
|
emit_jump_insn ((*branch) ());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We don't want to make fpscr call-saved, because that would prevent
|
||||||
|
channging it, and it would also cost an exstra instruction to save it.
|
||||||
|
We don't want it to be known as a global register either, because
|
||||||
|
that disables all flow analysis. But it has to be live at the function
|
||||||
|
return. Thus, we need to insert a USE at the end of the function. */
|
||||||
|
/* This should best be called at about the time FINALIZE_PIC is called,
|
||||||
|
but not dependent on flag_pic. Alas, there is no suitable hook there,
|
||||||
|
so this gets called from HAVE_RETURN. */
|
||||||
|
int
|
||||||
|
emit_fpscr_use ()
|
||||||
|
{
|
||||||
|
static int fpscr_uses = 0;
|
||||||
|
|
||||||
|
if (rtx_equal_function_value_matters)
|
||||||
|
{
|
||||||
|
emit_insn (gen_rtx (USE, VOIDmode, get_fpscr_rtx ()));
|
||||||
|
fpscr_uses++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (fpscr_uses > 1)
|
||||||
|
{
|
||||||
|
/* Due to he crude way we emit the USEs, we might end up with
|
||||||
|
some extra ones. Delete all but the last one. */
|
||||||
|
rtx insn;
|
||||||
|
|
||||||
|
for (insn = get_last_insn(); insn; insn = PREV_INSN (insn))
|
||||||
|
if (GET_CODE (insn) == INSN
|
||||||
|
&& GET_CODE (PATTERN (insn)) == USE
|
||||||
|
&& GET_CODE (XEXP (PATTERN (insn), 0)) == REG
|
||||||
|
&& REGNO (XEXP (PATTERN (insn), 0)) == FPSCR_REG)
|
||||||
|
{
|
||||||
|
insn = PREV_INSN (insn);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (; insn; insn = PREV_INSN (insn))
|
||||||
|
if (GET_CODE (insn) == INSN
|
||||||
|
&& GET_CODE (PATTERN (insn)) == USE
|
||||||
|
&& GET_CODE (XEXP (PATTERN (insn), 0)) == REG
|
||||||
|
&& REGNO (XEXP (PATTERN (insn), 0)) == FPSCR_REG)
|
||||||
|
{
|
||||||
|
PUT_CODE (insn, NOTE);
|
||||||
|
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||||
|
NOTE_SOURCE_FILE (insn) = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fpscr_uses = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ??? gcc does flow analysis strictly after common subexpression
|
||||||
|
elimination. As a result, common subespression elimination fails
|
||||||
|
when there are some intervening statements setting the same register.
|
||||||
|
If we did nothing about this, this would hurt the precision switching
|
||||||
|
for SH4 badly. There is some cse after reload, but it is unable to
|
||||||
|
undo the extra register pressure from the unused instructions, and
|
||||||
|
it cannot remove auto-increment loads.
|
||||||
|
|
||||||
|
A C code example that shows this flow/cse weakness for (at least) SH
|
||||||
|
and sparc (as of gcc ss-970706) is this:
|
||||||
|
|
||||||
|
double
|
||||||
|
f(double a)
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
d = 0.1;
|
||||||
|
a += d;
|
||||||
|
d = 1.1;
|
||||||
|
d = 0.1;
|
||||||
|
a *= d;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
So we add another pass before common subexpression elimination, to
|
||||||
|
remove assignments that are dead due to a following assignment in the
|
||||||
|
same basic block. */
|
||||||
|
|
||||||
|
int sh_flag_remove_dead_before_cse;
|
||||||
|
|
||||||
|
static void
|
||||||
|
mark_use (x, reg_set_block)
|
||||||
|
rtx x, *reg_set_block;
|
||||||
|
{
|
||||||
|
enum rtx_code code;
|
||||||
|
|
||||||
|
if (! x)
|
||||||
|
return;
|
||||||
|
code = GET_CODE (x);
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case REG:
|
||||||
|
{
|
||||||
|
int regno = REGNO (x);
|
||||||
|
int nregs = (regno < FIRST_PSEUDO_REGISTER
|
||||||
|
? HARD_REGNO_NREGS (regno, GET_MODE (x))
|
||||||
|
: 1);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
reg_set_block[regno + nregs - 1] = 0;
|
||||||
|
}
|
||||||
|
while (--nregs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SET:
|
||||||
|
{
|
||||||
|
rtx dest = SET_DEST (x);
|
||||||
|
|
||||||
|
if (GET_CODE (dest) == SUBREG)
|
||||||
|
dest = SUBREG_REG (dest);
|
||||||
|
if (GET_CODE (dest) != REG)
|
||||||
|
mark_use (dest, reg_set_block);
|
||||||
|
mark_use (SET_SRC (x), reg_set_block);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLOBBER:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
char *fmt = GET_RTX_FORMAT (code);
|
||||||
|
int i, j;
|
||||||
|
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (fmt[i] == 'e')
|
||||||
|
mark_use (XEXP (x, i), reg_set_block);
|
||||||
|
else if (fmt[i] == 'E')
|
||||||
|
for (j = XVECLEN (x, i) - 1; j >= 0; j--)
|
||||||
|
mark_use (XVECEXP (x, i, j), reg_set_block);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
remove_dead_before_cse ()
|
||||||
|
{
|
||||||
|
rtx *reg_set_block, last, last_call, insn, set;
|
||||||
|
int in_libcall = 0;
|
||||||
|
|
||||||
|
/* This pass should run just once, after rtl generation. */
|
||||||
|
|
||||||
|
if (! sh_flag_remove_dead_before_cse
|
||||||
|
|| rtx_equal_function_value_matters
|
||||||
|
|| reload_completed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sh_flag_remove_dead_before_cse = 0;
|
||||||
|
|
||||||
|
reg_set_block = (rtx *)alloca (max_reg_num () * sizeof (rtx));
|
||||||
|
bzero ((char *)reg_set_block, max_reg_num () * sizeof (rtx));
|
||||||
|
last_call = last = get_last_insn ();
|
||||||
|
for (insn = last; insn; insn = PREV_INSN (insn))
|
||||||
|
{
|
||||||
|
if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
|
||||||
|
continue;
|
||||||
|
if (GET_CODE (insn) == JUMP_INSN)
|
||||||
|
{
|
||||||
|
last_call = last = insn;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
set = single_set (insn);
|
||||||
|
|
||||||
|
/* Don't delete parts of libcalls, since that would confuse cse, loop
|
||||||
|
and flow. */
|
||||||
|
if (find_reg_note (insn, REG_RETVAL, NULL_RTX))
|
||||||
|
in_libcall = 1;
|
||||||
|
else if (in_libcall)
|
||||||
|
{
|
||||||
|
if (find_reg_note (insn, REG_LIBCALL, NULL_RTX))
|
||||||
|
in_libcall = 0;
|
||||||
|
}
|
||||||
|
else if (set && GET_CODE (SET_DEST (set)) == REG)
|
||||||
|
{
|
||||||
|
int regno = REGNO (SET_DEST (set));
|
||||||
|
rtx ref_insn = (regno < FIRST_PSEUDO_REGISTER && call_used_regs[regno]
|
||||||
|
? last_call
|
||||||
|
: last);
|
||||||
|
if (reg_set_block[regno] == ref_insn
|
||||||
|
&& (regno >= FIRST_PSEUDO_REGISTER
|
||||||
|
|| HARD_REGNO_NREGS (regno, GET_MODE (SET_DEST (set))) == 1)
|
||||||
|
&& (GET_CODE (insn) != CALL_INSN || CONST_CALL_P (insn)))
|
||||||
|
{
|
||||||
|
PUT_CODE (insn, NOTE);
|
||||||
|
NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
|
||||||
|
NOTE_SOURCE_FILE (insn) = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reg_set_block[REGNO (SET_DEST (set))] = ref_insn;
|
||||||
|
}
|
||||||
|
if (GET_CODE (insn) == CALL_INSN)
|
||||||
|
{
|
||||||
|
last_call = insn;
|
||||||
|
mark_use (CALL_INSN_FUNCTION_USAGE (insn), reg_set_block);
|
||||||
|
}
|
||||||
|
mark_use (PATTERN (insn), reg_set_block);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Definitions of target machine for GNU compiler for Hitachi Super-H.
|
/* Definitions of target machine for GNU compiler for Hitachi Super-H.
|
||||||
Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
|
Copyright (C) 1993-1998 Free Software Foundation, Inc.
|
||||||
Contributed by Steve Chamberlain (sac@cygnus.com).
|
Contributed by Steve Chamberlain (sac@cygnus.com).
|
||||||
Improved by Jim Wilson (wilson@cygnus.com).
|
Improved by Jim Wilson (wilson@cygnus.com).
|
||||||
|
|
||||||
|
@ -43,7 +43,10 @@ extern int code_for_indirect_jump_scratch;
|
||||||
%{m2:-D__sh2__} \
|
%{m2:-D__sh2__} \
|
||||||
%{m3:-D__sh3__} \
|
%{m3:-D__sh3__} \
|
||||||
%{m3e:-D__SH3E__} \
|
%{m3e:-D__SH3E__} \
|
||||||
%{!m1:%{!m2:%{!m3:%{!m3e:-D__sh1__}}}}"
|
%{m4-single-only:-D__SH4_SINGLE_ONLY__} \
|
||||||
|
%{m4-single:-D__SH4_SINGLE__} \
|
||||||
|
%{m4:-D__SH4__} \
|
||||||
|
%{!m1:%{!m2:%{!m3:%{!m3e:%{!m4:%{!m4-single:%{!m4-single-only:-D__sh1__}}}}}}}"
|
||||||
|
|
||||||
#define CPP_PREDEFINES "-D__sh__ -Acpu(sh) -Amachine(sh)"
|
#define CPP_PREDEFINES "-D__sh__ -Acpu(sh) -Amachine(sh)"
|
||||||
|
|
||||||
|
@ -54,19 +57,28 @@ extern int code_for_indirect_jump_scratch;
|
||||||
/* We can not debug without a frame pointer. */
|
/* We can not debug without a frame pointer. */
|
||||||
/* #define CAN_DEBUG_WITHOUT_FP */
|
/* #define CAN_DEBUG_WITHOUT_FP */
|
||||||
|
|
||||||
#define CONDITIONAL_REGISTER_USAGE \
|
#define CONDITIONAL_REGISTER_USAGE \
|
||||||
if (! TARGET_SH3E) \
|
if (! TARGET_SH4 || ! TARGET_FMOVD) \
|
||||||
{ \
|
{ \
|
||||||
int regno; \
|
int regno; \
|
||||||
for (regno = FIRST_FP_REG; regno <= LAST_FP_REG; regno++) \
|
for (regno = FIRST_XD_REG; regno <= LAST_XD_REG; regno++) \
|
||||||
fixed_regs[regno] = call_used_regs[regno] = 1; \
|
fixed_regs[regno] = call_used_regs[regno] = 1; \
|
||||||
fixed_regs[FPUL_REG] = call_used_regs[FPUL_REG] = 1; \
|
if (! TARGET_SH4) \
|
||||||
} \
|
{ \
|
||||||
/* Hitachi saves and restores mac registers on call. */ \
|
if (! TARGET_SH3E) \
|
||||||
if (TARGET_HITACHI) \
|
{ \
|
||||||
{ \
|
int regno; \
|
||||||
call_used_regs[MACH_REG] = 0; \
|
for (regno = FIRST_FP_REG; regno <= LAST_FP_REG; regno++) \
|
||||||
call_used_regs[MACL_REG] = 0; \
|
fixed_regs[regno] = call_used_regs[regno] = 1; \
|
||||||
|
fixed_regs[FPUL_REG] = call_used_regs[FPUL_REG] = 1; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
/* Hitachi saves and restores mac registers on call. */ \
|
||||||
|
if (TARGET_HITACHI) \
|
||||||
|
{ \
|
||||||
|
call_used_regs[MACH_REG] = 0; \
|
||||||
|
call_used_regs[MACL_REG] = 0; \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ??? Need to write documentation for all SH options and add it to the
|
/* ??? Need to write documentation for all SH options and add it to the
|
||||||
|
@ -81,6 +93,10 @@ extern int target_flags;
|
||||||
#define SH2_BIT (1<<9)
|
#define SH2_BIT (1<<9)
|
||||||
#define SH3_BIT (1<<10)
|
#define SH3_BIT (1<<10)
|
||||||
#define SH3E_BIT (1<<11)
|
#define SH3E_BIT (1<<11)
|
||||||
|
#define HARD_SH4_BIT (1<<5)
|
||||||
|
#define FPU_SINGLE_BIT (1<<7)
|
||||||
|
#define SH4_BIT (1<<12)
|
||||||
|
#define FMOVD_BIT (1<<4)
|
||||||
#define SPACE_BIT (1<<13)
|
#define SPACE_BIT (1<<13)
|
||||||
#define BIGTABLE_BIT (1<<14)
|
#define BIGTABLE_BIT (1<<14)
|
||||||
#define RELAX_BIT (1<<15)
|
#define RELAX_BIT (1<<15)
|
||||||
|
@ -107,6 +123,27 @@ extern int target_flags;
|
||||||
/* Nonzero if we should generate code using type 3E insns. */
|
/* Nonzero if we should generate code using type 3E insns. */
|
||||||
#define TARGET_SH3E (target_flags & SH3E_BIT)
|
#define TARGET_SH3E (target_flags & SH3E_BIT)
|
||||||
|
|
||||||
|
/* Nonzero if the cache line size is 32. */
|
||||||
|
#define TARGET_CACHE32 (target_flags & HARD_SH4_BIT)
|
||||||
|
|
||||||
|
/* Nonzero if we schedule for a superscalar implementation. */
|
||||||
|
#define TARGET_SUPERSCALAR (target_flags & HARD_SH4_BIT)
|
||||||
|
|
||||||
|
/* Nonzero if the target has separate instruction and data caches. */
|
||||||
|
#define TARGET_HARWARD (target_flags & HARD_SH4_BIT)
|
||||||
|
|
||||||
|
/* Nonzero if compiling for SH4 hardware (to be used for insn costs etc.) */
|
||||||
|
#define TARGET_HARD_SH4 (target_flags & HARD_SH4_BIT)
|
||||||
|
|
||||||
|
/* Nonzero if the default precision of th FPU is single */
|
||||||
|
#define TARGET_FPU_SINGLE (target_flags & FPU_SINGLE_BIT)
|
||||||
|
|
||||||
|
/* Nonzero if we should generate code using type 4 insns. */
|
||||||
|
#define TARGET_SH4 (target_flags & SH4_BIT)
|
||||||
|
|
||||||
|
/* Nonzero if we should generate fmovd. */
|
||||||
|
#define TARGET_FMOVD (target_flags & FMOVD_BIT)
|
||||||
|
|
||||||
/* Nonzero if we respect NANs. */
|
/* Nonzero if we respect NANs. */
|
||||||
#define TARGET_IEEE (target_flags & IEEE_BIT)
|
#define TARGET_IEEE (target_flags & IEEE_BIT)
|
||||||
|
|
||||||
|
@ -137,10 +174,14 @@ extern int target_flags;
|
||||||
{ {"1", SH1_BIT}, \
|
{ {"1", SH1_BIT}, \
|
||||||
{"2", SH2_BIT}, \
|
{"2", SH2_BIT}, \
|
||||||
{"3", SH3_BIT|SH2_BIT}, \
|
{"3", SH3_BIT|SH2_BIT}, \
|
||||||
{"3e", SH3E_BIT|SH3_BIT|SH2_BIT}, \
|
{"3e", SH3E_BIT|SH3_BIT|SH2_BIT|FPU_SINGLE_BIT}, \
|
||||||
|
{"4-single-only", SH3E_BIT|SH3_BIT|SH2_BIT|SH3E_BIT|HARD_SH4_BIT|FPU_SINGLE_BIT}, \
|
||||||
|
{"4-single", SH4_BIT|SH3E_BIT|SH3_BIT|SH2_BIT|HARD_SH4_BIT|FPU_SINGLE_BIT},\
|
||||||
|
{"4", SH4_BIT|SH3E_BIT|SH3_BIT|SH2_BIT|HARD_SH4_BIT}, \
|
||||||
{"b", -LITTLE_ENDIAN_BIT}, \
|
{"b", -LITTLE_ENDIAN_BIT}, \
|
||||||
{"bigtable", BIGTABLE_BIT}, \
|
{"bigtable", BIGTABLE_BIT}, \
|
||||||
{"dalign", DALIGN_BIT}, \
|
{"dalign", DALIGN_BIT}, \
|
||||||
|
{"fmovd", FMOVD_BIT}, \
|
||||||
{"hitachi", HITACHI_BIT}, \
|
{"hitachi", HITACHI_BIT}, \
|
||||||
{"ieee", IEEE_BIT}, \
|
{"ieee", IEEE_BIT}, \
|
||||||
{"isize", ISIZE_BIT}, \
|
{"isize", ISIZE_BIT}, \
|
||||||
|
@ -160,26 +201,58 @@ extern int target_flags;
|
||||||
|
|
||||||
#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) \
|
#define OPTIMIZATION_OPTIONS(LEVEL,SIZE) \
|
||||||
do { \
|
do { \
|
||||||
|
if (LEVEL) \
|
||||||
|
flag_omit_frame_pointer = -1; \
|
||||||
|
if (LEVEL) \
|
||||||
|
sh_flag_remove_dead_before_cse = 1; \
|
||||||
if (SIZE) \
|
if (SIZE) \
|
||||||
target_flags |= SPACE_BIT; \
|
target_flags |= SPACE_BIT; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ASSEMBLER_DIALECT 0 /* will allow to distinguish b[tf].s and b[tf]/s . */
|
#define ASSEMBLER_DIALECT assembler_dialect
|
||||||
#define OVERRIDE_OPTIONS \
|
|
||||||
do { \
|
extern int assembler_dialect;
|
||||||
sh_cpu = CPU_SH1; \
|
|
||||||
if (TARGET_SH2) \
|
#define OVERRIDE_OPTIONS \
|
||||||
sh_cpu = CPU_SH2; \
|
do { \
|
||||||
if (TARGET_SH3) \
|
sh_cpu = CPU_SH1; \
|
||||||
sh_cpu = CPU_SH3; \
|
assembler_dialect = 0; \
|
||||||
if (TARGET_SH3E) \
|
if (TARGET_SH2) \
|
||||||
sh_cpu = CPU_SH3E; \
|
sh_cpu = CPU_SH2; \
|
||||||
\
|
if (TARGET_SH3) \
|
||||||
/* Never run scheduling before reload, since that can \
|
sh_cpu = CPU_SH3; \
|
||||||
break global alloc, and generates slower code anyway due \
|
if (TARGET_SH3E) \
|
||||||
to the pressure on R0. */ \
|
sh_cpu = CPU_SH3E; \
|
||||||
flag_schedule_insns = 0; \
|
if (TARGET_SH4) \
|
||||||
sh_addr_diff_vec_mode = TARGET_BIGTABLE ? SImode : HImode; \
|
{ \
|
||||||
|
assembler_dialect = 1; \
|
||||||
|
sh_cpu = CPU_SH4; \
|
||||||
|
} \
|
||||||
|
if (! TARGET_SH4 || ! TARGET_FMOVD) \
|
||||||
|
{ \
|
||||||
|
/* Prevent usage of explicit register names for variables \
|
||||||
|
for registers not present / not addressable in the \
|
||||||
|
target architecture. */ \
|
||||||
|
int regno; \
|
||||||
|
for (regno = (TARGET_SH3E) ? 17 : 0; \
|
||||||
|
regno <= 24; regno++) \
|
||||||
|
fp_reg_names[regno][0] = 0; \
|
||||||
|
} \
|
||||||
|
if (flag_omit_frame_pointer < 0) \
|
||||||
|
/* The debugging information is sufficient, \
|
||||||
|
but gdb doesn't implement this yet */ \
|
||||||
|
if (0) \
|
||||||
|
flag_omit_frame_pointer \
|
||||||
|
= (PREFERRED_DEBUGGING_TYPE == DWARF_DEBUG \
|
||||||
|
|| PREFERRED_DEBUGGING_TYPE == DWARF2_DEBUG); \
|
||||||
|
else \
|
||||||
|
flag_omit_frame_pointer = 0; \
|
||||||
|
\
|
||||||
|
/* Never run scheduling before reload, since that can \
|
||||||
|
break global alloc, and generates slower code anyway due \
|
||||||
|
to the pressure on R0. */ \
|
||||||
|
flag_schedule_insns = 0; \
|
||||||
|
sh_addr_diff_vec_mode = TARGET_BIGTABLE ? SImode : HImode; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/* Target machine storage layout. */
|
/* Target machine storage layout. */
|
||||||
|
@ -233,7 +306,7 @@ do { \
|
||||||
|
|
||||||
/* The log (base 2) of the cache line size, in bytes. Processors prior to
|
/* The log (base 2) of the cache line size, in bytes. Processors prior to
|
||||||
SH3 have no actual cache, but they fetch code in chunks of 4 bytes. */
|
SH3 have no actual cache, but they fetch code in chunks of 4 bytes. */
|
||||||
#define CACHE_LOG (TARGET_SH3 ? 4 : 2)
|
#define CACHE_LOG (TARGET_CACHE32 ? 5 : TARGET_SH3 ? 4 : 2)
|
||||||
|
|
||||||
/* Allocation boundary (in *bits*) for the code of a function.
|
/* Allocation boundary (in *bits*) for the code of a function.
|
||||||
32 bit alignment is faster, because instructions are always fetched as a
|
32 bit alignment is faster, because instructions are always fetched as a
|
||||||
|
@ -279,7 +352,7 @@ do { \
|
||||||
barrier_align (LABEL_AFTER_BARRIER)
|
barrier_align (LABEL_AFTER_BARRIER)
|
||||||
|
|
||||||
#define LOOP_ALIGN(A_LABEL) \
|
#define LOOP_ALIGN(A_LABEL) \
|
||||||
((! optimize || TARGET_SMALLCODE) ? 0 : 2)
|
((! optimize || TARGET_HARWARD || TARGET_SMALLCODE) ? 0 : 2)
|
||||||
|
|
||||||
#define LABEL_ALIGN(A_LABEL) \
|
#define LABEL_ALIGN(A_LABEL) \
|
||||||
( \
|
( \
|
||||||
|
@ -341,8 +414,11 @@ do { \
|
||||||
#define RAP_REG 23
|
#define RAP_REG 23
|
||||||
#define FIRST_FP_REG 24
|
#define FIRST_FP_REG 24
|
||||||
#define LAST_FP_REG 39
|
#define LAST_FP_REG 39
|
||||||
|
#define FIRST_XD_REG 40
|
||||||
|
#define LAST_XD_REG 47
|
||||||
|
#define FPSCR_REG 48
|
||||||
|
|
||||||
#define FIRST_PSEUDO_REGISTER 40
|
#define FIRST_PSEUDO_REGISTER 49
|
||||||
|
|
||||||
/* 1 for registers that have pervasive standard uses
|
/* 1 for registers that have pervasive standard uses
|
||||||
and are not available for the register allocator.
|
and are not available for the register allocator.
|
||||||
|
@ -361,6 +437,9 @@ do { \
|
||||||
0, 0, 0, 0, \
|
0, 0, 0, 0, \
|
||||||
0, 0, 0, 0, \
|
0, 0, 0, 0, \
|
||||||
0, 0, 0, 0, \
|
0, 0, 0, 0, \
|
||||||
|
0, 0, 0, 0, \
|
||||||
|
0, 0, 0, 0, \
|
||||||
|
1, \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 1 for registers not available across function calls.
|
/* 1 for registers not available across function calls.
|
||||||
|
@ -381,6 +460,9 @@ do { \
|
||||||
1, 1, 1, 1, \
|
1, 1, 1, 1, \
|
||||||
1, 1, 1, 1, \
|
1, 1, 1, 1, \
|
||||||
0, 0, 0, 0, \
|
0, 0, 0, 0, \
|
||||||
|
1, 1, 1, 1, \
|
||||||
|
1, 1, 0, 0, \
|
||||||
|
1, \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return number of consecutive hard regs needed starting at reg REGNO
|
/* Return number of consecutive hard regs needed starting at reg REGNO
|
||||||
|
@ -388,20 +470,39 @@ do { \
|
||||||
This is ordinarily the length in words of a value of mode MODE
|
This is ordinarily the length in words of a value of mode MODE
|
||||||
but can be less for certain modes in special long registers.
|
but can be less for certain modes in special long registers.
|
||||||
|
|
||||||
On the SH regs are UNITS_PER_WORD bits wide. */
|
On the SH all but the XD regs are UNITS_PER_WORD bits wide. */
|
||||||
|
|
||||||
#define HARD_REGNO_NREGS(REGNO, MODE) \
|
#define HARD_REGNO_NREGS(REGNO, MODE) \
|
||||||
(((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
|
((REGNO) >= FIRST_XD_REG && (REGNO) <= LAST_XD_REG \
|
||||||
|
? (GET_MODE_SIZE (MODE) / (2 * UNITS_PER_WORD)) \
|
||||||
|
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) \
|
||||||
|
|
||||||
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
|
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
|
||||||
We can allow any mode in any general register. The special registers
|
We can allow any mode in any general register. The special registers
|
||||||
only allow SImode. Don't allow any mode in the PR. */
|
only allow SImode. Don't allow any mode in the PR. */
|
||||||
|
|
||||||
|
/* We cannot hold DCmode values in the XD registers because alter_reg
|
||||||
|
handles subregs of them incorrectly. We could work around this by
|
||||||
|
spacing the XD registers like the DR registers, but this would require
|
||||||
|
additional memory in every compilation to hold larger register vectors.
|
||||||
|
We could hold SFmode / SCmode values in XD registers, but that
|
||||||
|
would require a tertiary reload when reloading from / to memory,
|
||||||
|
and a secondary reload to reload from / to general regs; that
|
||||||
|
seems to be a loosing proposition. */
|
||||||
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
|
#define HARD_REGNO_MODE_OK(REGNO, MODE) \
|
||||||
(SPECIAL_REG (REGNO) ? (MODE) == SImode \
|
(SPECIAL_REG (REGNO) ? (MODE) == SImode \
|
||||||
: (REGNO) == FPUL_REG ? (MODE) == SImode || (MODE) == SFmode \
|
: (REGNO) == FPUL_REG ? (MODE) == SImode || (MODE) == SFmode \
|
||||||
: (REGNO) >= FIRST_FP_REG && (REGNO) <= LAST_FP_REG ? (MODE) == SFmode \
|
: (REGNO) >= FIRST_FP_REG && (REGNO) <= LAST_FP_REG && (MODE) == SFmode \
|
||||||
|
? 1 \
|
||||||
|
: (REGNO) >= FIRST_FP_REG && (REGNO) <= LAST_FP_REG \
|
||||||
|
? ((MODE) == SFmode \
|
||||||
|
|| (TARGET_SH3E && (MODE) == SCmode) \
|
||||||
|
|| (((TARGET_SH4 && (MODE) == DFmode) || (MODE) == DCmode) \
|
||||||
|
&& (((REGNO) - FIRST_FP_REG) & 1) == 0)) \
|
||||||
|
: (REGNO) >= FIRST_XD_REG && (REGNO) <= LAST_XD_REG \
|
||||||
|
? (MODE) == DFmode \
|
||||||
: (REGNO) == PR_REG ? 0 \
|
: (REGNO) == PR_REG ? 0 \
|
||||||
|
: (REGNO) == FPSCR_REG ? (MODE) == PSImode \
|
||||||
: 1)
|
: 1)
|
||||||
|
|
||||||
/* Value is 1 if it is a good idea to tie two pseudo registers
|
/* Value is 1 if it is a good idea to tie two pseudo registers
|
||||||
|
@ -541,6 +642,8 @@ enum reg_class
|
||||||
GENERAL_REGS,
|
GENERAL_REGS,
|
||||||
FP0_REGS,
|
FP0_REGS,
|
||||||
FP_REGS,
|
FP_REGS,
|
||||||
|
DF_REGS,
|
||||||
|
FPSCR_REGS,
|
||||||
GENERAL_FP_REGS,
|
GENERAL_FP_REGS,
|
||||||
ALL_REGS,
|
ALL_REGS,
|
||||||
LIM_REG_CLASSES
|
LIM_REG_CLASSES
|
||||||
|
@ -560,6 +663,8 @@ enum reg_class
|
||||||
"GENERAL_REGS", \
|
"GENERAL_REGS", \
|
||||||
"FP0_REGS", \
|
"FP0_REGS", \
|
||||||
"FP_REGS", \
|
"FP_REGS", \
|
||||||
|
"DF_REGS", \
|
||||||
|
"FPSCR_REGS", \
|
||||||
"GENERAL_FP_REGS", \
|
"GENERAL_FP_REGS", \
|
||||||
"ALL_REGS", \
|
"ALL_REGS", \
|
||||||
}
|
}
|
||||||
|
@ -579,8 +684,10 @@ enum reg_class
|
||||||
{ 0x0081FFFF, 0x00000000 }, /* GENERAL_REGS */ \
|
{ 0x0081FFFF, 0x00000000 }, /* GENERAL_REGS */ \
|
||||||
{ 0x01000000, 0x00000000 }, /* FP0_REGS */ \
|
{ 0x01000000, 0x00000000 }, /* FP0_REGS */ \
|
||||||
{ 0xFF000000, 0x000000FF }, /* FP_REGS */ \
|
{ 0xFF000000, 0x000000FF }, /* FP_REGS */ \
|
||||||
{ 0xFF81FFFF, 0x000000FF }, /* GENERAL_FP_REGS */ \
|
{ 0xFF000000, 0x0000FFFF }, /* DF_REGS */ \
|
||||||
{ 0xFFFFFFFF, 0x000000FF }, /* ALL_REGS */ \
|
{ 0x00000000, 0x00010000 }, /* FPSCR_REGS */ \
|
||||||
|
{ 0xFF81FFFF, 0x0000FFFF }, /* GENERAL_FP_REGS */ \
|
||||||
|
{ 0xFFFFFFFF, 0x0001FFFF }, /* ALL_REGS */ \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The same information, inverted:
|
/* The same information, inverted:
|
||||||
|
@ -603,6 +710,7 @@ extern int regno_reg_class[];
|
||||||
spilled or used otherwise, we better have the FP_REGS allocated first. */
|
spilled or used otherwise, we better have the FP_REGS allocated first. */
|
||||||
#define REG_ALLOC_ORDER \
|
#define REG_ALLOC_ORDER \
|
||||||
{ 25,26,27,28,29,30,31,24,32,33,34,35,36,37,38,39, \
|
{ 25,26,27,28,29,30,31,24,32,33,34,35,36,37,38,39, \
|
||||||
|
40,41,42,43,44,45,46,47,48, \
|
||||||
1,2,3,7,6,5,4,0,8,9,10,11,12,13,14, \
|
1,2,3,7,6,5,4,0,8,9,10,11,12,13,14, \
|
||||||
22,15,16,17,18,19,20,21,23 }
|
22,15,16,17,18,19,20,21,23 }
|
||||||
|
|
||||||
|
@ -657,7 +765,8 @@ extern enum reg_class reg_class_from_letter[];
|
||||||
#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS)
|
#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS)
|
||||||
|
|
||||||
#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \
|
#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \
|
||||||
((((((CLASS) == FP_REGS || (CLASS) == FP0_REGS) \
|
((((((CLASS) == FP_REGS || (CLASS) == FP0_REGS \
|
||||||
|
|| (CLASS) == DF_REGS) \
|
||||||
&& (GET_CODE (X) == REG && REGNO (X) <= AP_REG)) \
|
&& (GET_CODE (X) == REG && REGNO (X) <= AP_REG)) \
|
||||||
|| (((CLASS) == GENERAL_REGS || (CLASS) == R0_REGS) \
|
|| (((CLASS) == GENERAL_REGS || (CLASS) == R0_REGS) \
|
||||||
&& GET_CODE (X) == REG \
|
&& GET_CODE (X) == REG \
|
||||||
|
@ -666,7 +775,7 @@ extern enum reg_class reg_class_from_letter[];
|
||||||
? FPUL_REGS \
|
? FPUL_REGS \
|
||||||
: ((CLASS) == FPUL_REGS \
|
: ((CLASS) == FPUL_REGS \
|
||||||
&& (GET_CODE (X) == MEM \
|
&& (GET_CODE (X) == MEM \
|
||||||
|| GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER))\
|
|| (GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER)))\
|
||||||
? GENERAL_REGS \
|
? GENERAL_REGS \
|
||||||
: (((CLASS) == MAC_REGS || (CLASS) == PR_REGS) \
|
: (((CLASS) == MAC_REGS || (CLASS) == PR_REGS) \
|
||||||
&& GET_CODE (X) == REG && REGNO (X) > 15 \
|
&& GET_CODE (X) == REG && REGNO (X) > 15 \
|
||||||
|
@ -674,10 +783,19 @@ extern enum reg_class reg_class_from_letter[];
|
||||||
? GENERAL_REGS : NO_REGS)
|
? GENERAL_REGS : NO_REGS)
|
||||||
|
|
||||||
#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \
|
#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \
|
||||||
((((CLASS) == FP_REGS || (CLASS) == FP0_REGS) \
|
((((CLASS) == FP_REGS || (CLASS) == FP0_REGS || (CLASS) == DF_REGS) \
|
||||||
&& immediate_operand ((X), (MODE)) \
|
&& immediate_operand ((X), (MODE)) \
|
||||||
&& ! (fp_zero_operand (X) || fp_one_operand (X))) \
|
&& ! ((fp_zero_operand (X) || fp_one_operand (X)) && (MODE) == SFmode))\
|
||||||
? R0_REGS : SECONDARY_OUTPUT_RELOAD_CLASS((CLASS),(MODE),(X)))
|
? R0_REGS \
|
||||||
|
: CLASS == FPUL_REGS && immediate_operand ((X), (MODE)) \
|
||||||
|
? (GET_CODE (X) == CONST_INT && CONST_OK_FOR_I (INTVAL (X)) \
|
||||||
|
? GENERAL_REGS \
|
||||||
|
: R0_REGS) \
|
||||||
|
: (CLASS == FPSCR_REGS \
|
||||||
|
&& ((GET_CODE (X) == REG && REGNO (X) >= FIRST_PSEUDO_REGISTER) \
|
||||||
|
|| GET_CODE (X) == MEM && GET_CODE (XEXP ((X), 0)) == PLUS)) \
|
||||||
|
? GENERAL_REGS \
|
||||||
|
: SECONDARY_OUTPUT_RELOAD_CLASS((CLASS),(MODE),(X)))
|
||||||
|
|
||||||
/* Return the maximum number of consecutive registers
|
/* Return the maximum number of consecutive registers
|
||||||
needed to represent mode MODE in a register of class CLASS.
|
needed to represent mode MODE in a register of class CLASS.
|
||||||
|
@ -685,6 +803,11 @@ extern enum reg_class reg_class_from_letter[];
|
||||||
On SH this is the size of MODE in words. */
|
On SH this is the size of MODE in words. */
|
||||||
#define CLASS_MAX_NREGS(CLASS, MODE) \
|
#define CLASS_MAX_NREGS(CLASS, MODE) \
|
||||||
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
||||||
|
|
||||||
|
/* If defined, gives a class of registers that cannot be used as the
|
||||||
|
operand of a SUBREG that changes the size of the object. */
|
||||||
|
|
||||||
|
#define CLASS_CANNOT_CHANGE_SIZE DF_REGS
|
||||||
|
|
||||||
/* Stack layout; function entry, exit and calling. */
|
/* Stack layout; function entry, exit and calling. */
|
||||||
|
|
||||||
|
@ -694,6 +817,9 @@ extern enum reg_class reg_class_from_letter[];
|
||||||
#define NPARM_REGS(MODE) \
|
#define NPARM_REGS(MODE) \
|
||||||
(TARGET_SH3E && (MODE) == SFmode \
|
(TARGET_SH3E && (MODE) == SFmode \
|
||||||
? 8 \
|
? 8 \
|
||||||
|
: TARGET_SH4 && (GET_MODE_CLASS (MODE) == MODE_FLOAT \
|
||||||
|
|| GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \
|
||||||
|
? 8 \
|
||||||
: 4)
|
: 4)
|
||||||
|
|
||||||
#define FIRST_PARM_REG 4
|
#define FIRST_PARM_REG 4
|
||||||
|
@ -752,25 +878,48 @@ extern enum reg_class reg_class_from_letter[];
|
||||||
#define BASE_RETURN_VALUE_REG(MODE) \
|
#define BASE_RETURN_VALUE_REG(MODE) \
|
||||||
((TARGET_SH3E && ((MODE) == SFmode)) \
|
((TARGET_SH3E && ((MODE) == SFmode)) \
|
||||||
? FIRST_FP_RET_REG \
|
? FIRST_FP_RET_REG \
|
||||||
|
: TARGET_SH3E && (MODE) == SCmode \
|
||||||
|
? FIRST_FP_RET_REG \
|
||||||
|
: (TARGET_SH4 \
|
||||||
|
&& ((MODE) == DFmode || (MODE) == SFmode \
|
||||||
|
|| (MODE) == DCmode || (MODE) == SCmode )) \
|
||||||
|
? FIRST_FP_RET_REG \
|
||||||
: FIRST_RET_REG)
|
: FIRST_RET_REG)
|
||||||
|
|
||||||
#define BASE_ARG_REG(MODE) \
|
#define BASE_ARG_REG(MODE) \
|
||||||
((TARGET_SH3E && ((MODE) == SFmode)) \
|
((TARGET_SH3E && ((MODE) == SFmode)) \
|
||||||
? FIRST_FP_PARM_REG \
|
? FIRST_FP_PARM_REG \
|
||||||
|
: TARGET_SH4 && (GET_MODE_CLASS (MODE) == MODE_FLOAT \
|
||||||
|
|| GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT)\
|
||||||
|
? FIRST_FP_PARM_REG \
|
||||||
: FIRST_PARM_REG)
|
: FIRST_PARM_REG)
|
||||||
|
|
||||||
/* Define how to find the value returned by a function.
|
/* Define how to find the value returned by a function.
|
||||||
VALTYPE is the data type of the value (as a tree).
|
VALTYPE is the data type of the value (as a tree).
|
||||||
If the precise function being called is known, FUNC is its FUNCTION_DECL;
|
If the precise function being called is known, FUNC is its FUNCTION_DECL;
|
||||||
otherwise, FUNC is 0. */
|
otherwise, FUNC is 0.
|
||||||
|
For the SH, this is like LIBCALL_VALUE, except that we must change the
|
||||||
|
mode like PROMOTE_MODE does.
|
||||||
|
??? PROMOTE_MODE is ignored for non-scalar types. The set of types
|
||||||
|
tested here has to be kept in sync with the one in explow.c:promote_mode. */
|
||||||
|
|
||||||
#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
||||||
LIBCALL_VALUE (TYPE_MODE (VALTYPE))
|
gen_rtx (REG, \
|
||||||
|
((GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_INT \
|
||||||
|
&& GET_MODE_SIZE (TYPE_MODE (VALTYPE)) < UNITS_PER_WORD \
|
||||||
|
&& (TREE_CODE (VALTYPE) == INTEGER_TYPE \
|
||||||
|
|| TREE_CODE (VALTYPE) == ENUMERAL_TYPE \
|
||||||
|
|| TREE_CODE (VALTYPE) == BOOLEAN_TYPE \
|
||||||
|
|| TREE_CODE (VALTYPE) == CHAR_TYPE \
|
||||||
|
|| TREE_CODE (VALTYPE) == REAL_TYPE \
|
||||||
|
|| TREE_CODE (VALTYPE) == OFFSET_TYPE)) \
|
||||||
|
? SImode : TYPE_MODE (VALTYPE)), \
|
||||||
|
BASE_RETURN_VALUE_REG (TYPE_MODE (VALTYPE)))
|
||||||
|
|
||||||
/* Define how to find the value returned by a library function
|
/* Define how to find the value returned by a library function
|
||||||
assuming the value has mode MODE. */
|
assuming the value has mode MODE. */
|
||||||
#define LIBCALL_VALUE(MODE) \
|
#define LIBCALL_VALUE(MODE) \
|
||||||
gen_rtx (REG, (MODE), BASE_RETURN_VALUE_REG (MODE));
|
gen_rtx (REG, (MODE), BASE_RETURN_VALUE_REG (MODE))
|
||||||
|
|
||||||
/* 1 if N is a possible register number for a function value. */
|
/* 1 if N is a possible register number for a function value. */
|
||||||
#define FUNCTION_VALUE_REGNO_P(REGNO) \
|
#define FUNCTION_VALUE_REGNO_P(REGNO) \
|
||||||
|
@ -801,7 +950,11 @@ struct sh_args {
|
||||||
#define CUMULATIVE_ARGS struct sh_args
|
#define CUMULATIVE_ARGS struct sh_args
|
||||||
|
|
||||||
#define GET_SH_ARG_CLASS(MODE) \
|
#define GET_SH_ARG_CLASS(MODE) \
|
||||||
((TARGET_SH3E && ((MODE) == SFmode)) ? SH_ARG_FLOAT : SH_ARG_INT)
|
((TARGET_SH3E && (MODE) == SFmode) \
|
||||||
|
? SH_ARG_FLOAT \
|
||||||
|
: TARGET_SH4 && (GET_MODE_CLASS (MODE) == MODE_FLOAT \
|
||||||
|
|| GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT) \
|
||||||
|
? SH_ARG_FLOAT : SH_ARG_INT)
|
||||||
|
|
||||||
#define ROUND_ADVANCE(SIZE) \
|
#define ROUND_ADVANCE(SIZE) \
|
||||||
(((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
(((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
||||||
|
@ -813,7 +966,9 @@ struct sh_args {
|
||||||
round doubles to even regs when asked to explicitly. */
|
round doubles to even regs when asked to explicitly. */
|
||||||
|
|
||||||
#define ROUND_REG(CUM, MODE) \
|
#define ROUND_REG(CUM, MODE) \
|
||||||
((TARGET_ALIGN_DOUBLE \
|
(((TARGET_ALIGN_DOUBLE \
|
||||||
|
|| (TARGET_SH4 && ((MODE) == DFmode || (MODE) == DCmode) \
|
||||||
|
&& (CUM).arg_count[(int) SH_ARG_FLOAT] < NPARM_REGS (MODE)))\
|
||||||
&& GET_MODE_UNIT_SIZE ((MODE)) > UNITS_PER_WORD) \
|
&& GET_MODE_UNIT_SIZE ((MODE)) > UNITS_PER_WORD) \
|
||||||
? ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] \
|
? ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] \
|
||||||
+ ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] & 1)) \
|
+ ((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] & 1)) \
|
||||||
|
@ -838,11 +993,12 @@ struct sh_args {
|
||||||
available.) */
|
available.) */
|
||||||
|
|
||||||
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
|
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \
|
||||||
((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] = \
|
if (! TARGET_SH4 || PASS_IN_REG_P ((CUM), (MODE), (TYPE))) \
|
||||||
(ROUND_REG ((CUM), (MODE)) \
|
((CUM).arg_count[(int) GET_SH_ARG_CLASS (MODE)] \
|
||||||
+ ((MODE) != BLKmode \
|
= (ROUND_REG ((CUM), (MODE)) \
|
||||||
? ROUND_ADVANCE (GET_MODE_SIZE (MODE)) \
|
+ ((MODE) == BLKmode \
|
||||||
: ROUND_ADVANCE (int_size_in_bytes (TYPE)))))
|
? ROUND_ADVANCE (int_size_in_bytes (TYPE)) \
|
||||||
|
: ROUND_ADVANCE (GET_MODE_SIZE (MODE)))))
|
||||||
|
|
||||||
/* Return boolean indicating arg of mode MODE will be passed in a reg.
|
/* Return boolean indicating arg of mode MODE will be passed in a reg.
|
||||||
This macro is only used in this file. */
|
This macro is only used in this file. */
|
||||||
|
@ -883,7 +1039,9 @@ extern int current_function_varargs;
|
||||||
((PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \
|
((PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \
|
||||||
&& ((NAMED) || TARGET_SH3E || ! current_function_varargs)) \
|
&& ((NAMED) || TARGET_SH3E || ! current_function_varargs)) \
|
||||||
? gen_rtx (REG, (MODE), \
|
? gen_rtx (REG, (MODE), \
|
||||||
(BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE)))) \
|
((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \
|
||||||
|
^ ((MODE) == SFmode && TARGET_SH4 \
|
||||||
|
&& TARGET_LITTLE_ENDIAN != 0))) \
|
||||||
: 0)
|
: 0)
|
||||||
|
|
||||||
/* For an arg passed partly in registers and partly in memory,
|
/* For an arg passed partly in registers and partly in memory,
|
||||||
|
@ -894,8 +1052,9 @@ extern int current_function_varargs;
|
||||||
|
|
||||||
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
|
#define FUNCTION_ARG_PARTIAL_NREGS(CUM, MODE, TYPE, NAMED) \
|
||||||
((PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \
|
((PASS_IN_REG_P ((CUM), (MODE), (TYPE)) \
|
||||||
|
&& ! TARGET_SH4 \
|
||||||
&& (ROUND_REG ((CUM), (MODE)) \
|
&& (ROUND_REG ((CUM), (MODE)) \
|
||||||
+ (MODE != BLKmode \
|
+ ((MODE) != BLKmode \
|
||||||
? ROUND_ADVANCE (GET_MODE_SIZE (MODE)) \
|
? ROUND_ADVANCE (GET_MODE_SIZE (MODE)) \
|
||||||
: ROUND_ADVANCE (int_size_in_bytes (TYPE))) \
|
: ROUND_ADVANCE (int_size_in_bytes (TYPE))) \
|
||||||
- NPARM_REGS (MODE) > 0)) \
|
- NPARM_REGS (MODE) > 0)) \
|
||||||
|
@ -955,7 +1114,7 @@ extern int current_function_anonymous_args;
|
||||||
|
|
||||||
/* Alignment required for a trampoline in bits . */
|
/* Alignment required for a trampoline in bits . */
|
||||||
#define TRAMPOLINE_ALIGNMENT \
|
#define TRAMPOLINE_ALIGNMENT \
|
||||||
((CACHE_LOG < 3 || TARGET_SMALLCODE) ? 32 : 64) \
|
((CACHE_LOG < 3 || TARGET_SMALLCODE && ! TARGET_HARWARD) ? 32 : 64)
|
||||||
|
|
||||||
/* Emit RTL insns to initialize the variable parts of a trampoline.
|
/* Emit RTL insns to initialize the variable parts of a trampoline.
|
||||||
FNADDR is an RTX for the address of the function's pure code.
|
FNADDR is an RTX for the address of the function's pure code.
|
||||||
|
@ -971,6 +1130,8 @@ extern int current_function_anonymous_args;
|
||||||
(CXT)); \
|
(CXT)); \
|
||||||
emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \
|
emit_move_insn (gen_rtx (MEM, SImode, plus_constant ((TRAMP), 12)), \
|
||||||
(FNADDR)); \
|
(FNADDR)); \
|
||||||
|
if (TARGET_HARWARD) \
|
||||||
|
emit_insn (gen_ic_invalidate_line (TRAMP)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A C expression whose value is RTL representing the value of the return
|
/* A C expression whose value is RTL representing the value of the return
|
||||||
|
@ -1086,7 +1247,10 @@ extern struct rtx_def *sh_builtin_saveregs ();
|
||||||
#define MODE_DISP_OK_4(X,MODE) \
|
#define MODE_DISP_OK_4(X,MODE) \
|
||||||
(GET_MODE_SIZE (MODE) == 4 && (unsigned) INTVAL (X) < 64 \
|
(GET_MODE_SIZE (MODE) == 4 && (unsigned) INTVAL (X) < 64 \
|
||||||
&& ! (INTVAL (X) & 3) && ! (TARGET_SH3E && (MODE) == SFmode))
|
&& ! (INTVAL (X) & 3) && ! (TARGET_SH3E && (MODE) == SFmode))
|
||||||
#define MODE_DISP_OK_8(X,MODE) ((GET_MODE_SIZE(MODE)==8) && ((unsigned)INTVAL(X)<60) && (!(INTVAL(X) &3)))
|
|
||||||
|
#define MODE_DISP_OK_8(X,MODE) \
|
||||||
|
((GET_MODE_SIZE(MODE)==8) && ((unsigned)INTVAL(X)<60) \
|
||||||
|
&& ! (INTVAL(X) & 3) && ! (TARGET_SH4 && (MODE) == DFmode))
|
||||||
|
|
||||||
#define BASE_REGISTER_RTX_P(X) \
|
#define BASE_REGISTER_RTX_P(X) \
|
||||||
((GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \
|
((GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \
|
||||||
|
@ -1141,13 +1305,15 @@ extern struct rtx_def *sh_builtin_saveregs ();
|
||||||
else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC) \
|
else if ((GET_CODE (X) == POST_INC || GET_CODE (X) == PRE_DEC) \
|
||||||
&& BASE_REGISTER_RTX_P (XEXP ((X), 0))) \
|
&& BASE_REGISTER_RTX_P (XEXP ((X), 0))) \
|
||||||
goto LABEL; \
|
goto LABEL; \
|
||||||
else if (GET_CODE (X) == PLUS && MODE != PSImode) \
|
else if (GET_CODE (X) == PLUS \
|
||||||
|
&& ((MODE) != PSImode || reload_completed)) \
|
||||||
{ \
|
{ \
|
||||||
rtx xop0 = XEXP ((X), 0); \
|
rtx xop0 = XEXP ((X), 0); \
|
||||||
rtx xop1 = XEXP ((X), 1); \
|
rtx xop1 = XEXP ((X), 1); \
|
||||||
if (GET_MODE_SIZE (MODE) <= 8 && BASE_REGISTER_RTX_P (xop0)) \
|
if (GET_MODE_SIZE (MODE) <= 8 && BASE_REGISTER_RTX_P (xop0)) \
|
||||||
GO_IF_LEGITIMATE_INDEX ((MODE), xop1, LABEL); \
|
GO_IF_LEGITIMATE_INDEX ((MODE), xop1, LABEL); \
|
||||||
if (GET_MODE_SIZE (MODE) <= 4) \
|
if (GET_MODE_SIZE (MODE) <= 4 \
|
||||||
|
|| TARGET_SH4 && TARGET_FMOVD && MODE == DFmode) \
|
||||||
{ \
|
{ \
|
||||||
if (BASE_REGISTER_RTX_P (xop1) && INDEX_REGISTER_RTX_P (xop0))\
|
if (BASE_REGISTER_RTX_P (xop1) && INDEX_REGISTER_RTX_P (xop0))\
|
||||||
goto LABEL; \
|
goto LABEL; \
|
||||||
|
@ -1181,6 +1347,7 @@ extern struct rtx_def *sh_builtin_saveregs ();
|
||||||
|| GET_MODE_SIZE (MODE) == 8) \
|
|| GET_MODE_SIZE (MODE) == 8) \
|
||||||
&& GET_CODE (XEXP ((X), 1)) == CONST_INT \
|
&& GET_CODE (XEXP ((X), 1)) == CONST_INT \
|
||||||
&& BASE_REGISTER_RTX_P (XEXP ((X), 0)) \
|
&& BASE_REGISTER_RTX_P (XEXP ((X), 0)) \
|
||||||
|
&& ! (TARGET_SH4 && (MODE) == DFmode) \
|
||||||
&& ! (TARGET_SH3E && (MODE) == SFmode)) \
|
&& ! (TARGET_SH3E && (MODE) == SFmode)) \
|
||||||
{ \
|
{ \
|
||||||
rtx index_rtx = XEXP ((X), 1); \
|
rtx index_rtx = XEXP ((X), 1); \
|
||||||
|
@ -1228,12 +1395,21 @@ extern struct rtx_def *sh_builtin_saveregs ();
|
||||||
&& (GET_MODE_SIZE (MODE) == 4 || GET_MODE_SIZE (MODE) == 8) \
|
&& (GET_MODE_SIZE (MODE) == 4 || GET_MODE_SIZE (MODE) == 8) \
|
||||||
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
|
&& GET_CODE (XEXP (X, 1)) == CONST_INT \
|
||||||
&& BASE_REGISTER_RTX_P (XEXP (X, 0)) \
|
&& BASE_REGISTER_RTX_P (XEXP (X, 0)) \
|
||||||
&& ! (TARGET_SH3E && MODE == SFmode)) \
|
&& ! (TARGET_SH4 && (MODE) == DFmode) \
|
||||||
|
&& ! ((MODE) == PSImode && (TYPE) == RELOAD_FOR_INPUT_ADDRESS)) \
|
||||||
{ \
|
{ \
|
||||||
rtx index_rtx = XEXP (X, 1); \
|
rtx index_rtx = XEXP (X, 1); \
|
||||||
HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base; \
|
HOST_WIDE_INT offset = INTVAL (index_rtx), offset_base; \
|
||||||
rtx sum; \
|
rtx sum; \
|
||||||
\
|
\
|
||||||
|
if (TARGET_SH3E && MODE == SFmode) \
|
||||||
|
{ \
|
||||||
|
X = copy_rtx (X); \
|
||||||
|
push_reload (index_rtx, NULL_RTX, &XEXP (X, 1), NULL_PTR, \
|
||||||
|
INDEX_REG_CLASS, Pmode, VOIDmode, 0, 0, (OPNUM), \
|
||||||
|
(TYPE)); \
|
||||||
|
goto WIN; \
|
||||||
|
} \
|
||||||
/* Instead of offset_base 128..131 use 124..127, so that \
|
/* Instead of offset_base 128..131 use 124..127, so that \
|
||||||
simple add suffices. */ \
|
simple add suffices. */ \
|
||||||
if (offset > 127) \
|
if (offset > 127) \
|
||||||
|
@ -1315,7 +1491,7 @@ extern struct rtx_def *sh_builtin_saveregs ();
|
||||||
|
|
||||||
/* Since the SH3e has only `float' support, it is desirable to make all
|
/* Since the SH3e has only `float' support, it is desirable to make all
|
||||||
floating point types equivalent to `float'. */
|
floating point types equivalent to `float'. */
|
||||||
#define DOUBLE_TYPE_SIZE (TARGET_SH3E ? 32 : 64)
|
#define DOUBLE_TYPE_SIZE ((TARGET_SH3E && ! TARGET_SH4) ? 32 : 64)
|
||||||
|
|
||||||
/* 'char' is signed by default. */
|
/* 'char' is signed by default. */
|
||||||
#define DEFAULT_SIGNED_CHAR 1
|
#define DEFAULT_SIGNED_CHAR 1
|
||||||
|
@ -1407,6 +1583,11 @@ extern struct rtx_def *sh_builtin_saveregs ();
|
||||||
return 10;
|
return 10;
|
||||||
|
|
||||||
#define RTX_COSTS(X, CODE, OUTER_CODE) \
|
#define RTX_COSTS(X, CODE, OUTER_CODE) \
|
||||||
|
case PLUS: \
|
||||||
|
return (COSTS_N_INSNS (1) \
|
||||||
|
+ rtx_cost (XEXP ((X), 0), PLUS) \
|
||||||
|
+ (rtx_equal_p (XEXP ((X), 0), XEXP ((X), 1))\
|
||||||
|
? 0 : rtx_cost (XEXP ((X), 1), PLUS)));\
|
||||||
case AND: \
|
case AND: \
|
||||||
return COSTS_N_INSNS (andcosts (X)); \
|
return COSTS_N_INSNS (andcosts (X)); \
|
||||||
case MULT: \
|
case MULT: \
|
||||||
|
@ -1414,7 +1595,13 @@ extern struct rtx_def *sh_builtin_saveregs ();
|
||||||
case ASHIFT: \
|
case ASHIFT: \
|
||||||
case ASHIFTRT: \
|
case ASHIFTRT: \
|
||||||
case LSHIFTRT: \
|
case LSHIFTRT: \
|
||||||
return COSTS_N_INSNS (shiftcosts (X)) ; \
|
/* Add one extra unit for the matching constraint. \
|
||||||
|
Otherwise loop strength reduction would think that\
|
||||||
|
a shift with different sourc and destination is \
|
||||||
|
as cheap as adding a constant to a register. */ \
|
||||||
|
return (COSTS_N_INSNS (shiftcosts (X)) \
|
||||||
|
+ rtx_cost (XEXP ((X), 0), (CODE)) \
|
||||||
|
+ 1); \
|
||||||
case DIV: \
|
case DIV: \
|
||||||
case UDIV: \
|
case UDIV: \
|
||||||
case MOD: \
|
case MOD: \
|
||||||
|
@ -1462,11 +1649,29 @@ extern struct rtx_def *sh_builtin_saveregs ();
|
||||||
/* Compute extra cost of moving data between one register class
|
/* Compute extra cost of moving data between one register class
|
||||||
and another. */
|
and another. */
|
||||||
|
|
||||||
|
/* Regclass always uses 2 for moves in the same register class;
|
||||||
|
If SECONDARY*_RELOAD_CLASS says something about the src/dst pair,
|
||||||
|
it uses this information. Hence, the general register <-> floating point
|
||||||
|
register information here is not used for SFmode. */
|
||||||
#define REGISTER_MOVE_COST(SRCCLASS, DSTCLASS) \
|
#define REGISTER_MOVE_COST(SRCCLASS, DSTCLASS) \
|
||||||
((DSTCLASS) == PR_REG ? 10 \
|
((((DSTCLASS) == T_REGS) || ((DSTCLASS) == PR_REG)) ? 10 \
|
||||||
: (((DSTCLASS) == FP_REGS && (SRCCLASS) == GENERAL_REGS) \
|
: ((((DSTCLASS) == FP0_REGS || (DSTCLASS) == FP_REGS || (DSTCLASS) == DF_REGS) \
|
||||||
|| ((DSTCLASS) == GENERAL_REGS && (SRCCLASS) == FP_REGS)) ? 4 \
|
&& ((SRCCLASS) == GENERAL_REGS || (SRCCLASS) == R0_REGS)) \
|
||||||
: 1)
|
|| (((DSTCLASS) == GENERAL_REGS || (DSTCLASS) == R0_REGS) \
|
||||||
|
&& ((SRCCLASS) == FP0_REGS || (SRCCLASS) == FP_REGS \
|
||||||
|
|| (SRCCLASS) == DF_REGS))) \
|
||||||
|
? TARGET_FMOVD ? 8 : 12 \
|
||||||
|
: (((DSTCLASS) == FPUL_REGS \
|
||||||
|
&& ((SRCCLASS) == GENERAL_REGS || (SRCCLASS) == R0_REGS)) \
|
||||||
|
|| (SRCCLASS == FPUL_REGS \
|
||||||
|
&& ((DSTCLASS) == GENERAL_REGS || (DSTCLASS) == R0_REGS))) \
|
||||||
|
? 5 \
|
||||||
|
: (((DSTCLASS) == FPUL_REGS \
|
||||||
|
&& ((SRCCLASS) == PR_REGS || (SRCCLASS) == MAC_REGS)) \
|
||||||
|
|| ((SRCCLASS) == FPUL_REGS \
|
||||||
|
&& ((DSTCLASS) == PR_REGS || (DSTCLASS) == MAC_REGS))) \
|
||||||
|
? 7 \
|
||||||
|
: 2)
|
||||||
|
|
||||||
/* ??? Perhaps make MEMORY_MOVE_COST depend on compiler option? This
|
/* ??? Perhaps make MEMORY_MOVE_COST depend on compiler option? This
|
||||||
would be so that people would slow memory systems could generate
|
would be so that people would slow memory systems could generate
|
||||||
|
@ -1573,13 +1778,32 @@ dtors_section() \
|
||||||
the Real framepointer; it can also be used as a normal general register.
|
the Real framepointer; it can also be used as a normal general register.
|
||||||
Note that the name `fp' is horribly misleading since `fp' is in fact only
|
Note that the name `fp' is horribly misleading since `fp' is in fact only
|
||||||
the argument-and-return-context pointer. */
|
the argument-and-return-context pointer. */
|
||||||
|
|
||||||
|
extern char fp_reg_names[][5];
|
||||||
|
|
||||||
#define REGISTER_NAMES \
|
#define REGISTER_NAMES \
|
||||||
|
{ \
|
||||||
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
|
||||||
|
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
|
||||||
|
"ap", "pr", "t", "gbr", "mach","macl", fp_reg_names[16], "rap", \
|
||||||
|
fp_reg_names[0], fp_reg_names[1] , fp_reg_names[2], fp_reg_names[3], \
|
||||||
|
fp_reg_names[4], fp_reg_names[5], fp_reg_names[6], fp_reg_names[7], \
|
||||||
|
fp_reg_names[8], fp_reg_names[9], fp_reg_names[10], fp_reg_names[11], \
|
||||||
|
fp_reg_names[12], fp_reg_names[13], fp_reg_names[14], fp_reg_names[15], \
|
||||||
|
fp_reg_names[17], fp_reg_names[18], fp_reg_names[19], fp_reg_names[20], \
|
||||||
|
fp_reg_names[21], fp_reg_names[22], fp_reg_names[23], fp_reg_names[24], \
|
||||||
|
"fpscr", \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEBUG_REGISTER_NAMES \
|
||||||
{ \
|
{ \
|
||||||
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
|
"r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
|
||||||
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
|
"r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", \
|
||||||
"ap", "pr", "t", "gbr", "mach","macl", "fpul","rap", \
|
"ap", "pr", "t", "gbr", "mach","macl", "fpul","rap", \
|
||||||
"fr0","fr1","fr2", "fr3", "fr4", "fr5", "fr6", "fr7", \
|
"fr0","fr1","fr2", "fr3", "fr4", "fr5", "fr6", "fr7", \
|
||||||
"fr8","fr9","fr10","fr11","fr12","fr13","fr14","fr15",\
|
"fr8","fr9","fr10","fr11","fr12","fr13","fr14","fr15",\
|
||||||
|
"xd0","xd2","xd4", "xd6", "xd8", "xd10","xd12","xd14", \
|
||||||
|
"fpscr", \
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DBX register number for a given compiler register number. */
|
/* DBX register number for a given compiler register number. */
|
||||||
|
@ -1773,7 +1997,8 @@ enum processor_type {
|
||||||
PROCESSOR_SH1,
|
PROCESSOR_SH1,
|
||||||
PROCESSOR_SH2,
|
PROCESSOR_SH2,
|
||||||
PROCESSOR_SH3,
|
PROCESSOR_SH3,
|
||||||
PROCESSOR_SH3E
|
PROCESSOR_SH3E,
|
||||||
|
PROCESSOR_SH4
|
||||||
};
|
};
|
||||||
|
|
||||||
#define sh_cpu_attr ((enum attr_cpu)sh_cpu)
|
#define sh_cpu_attr ((enum attr_cpu)sh_cpu)
|
||||||
|
@ -1837,6 +2062,11 @@ extern int sh_valid_machine_decl_attribute ();
|
||||||
#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
|
#define VALID_MACHINE_DECL_ATTRIBUTE(DECL, ATTRIBUTES, IDENTIFIER, ARGS) \
|
||||||
sh_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
|
sh_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
|
||||||
|
|
||||||
|
extern int sh_flag_remove_dead_before_cse;
|
||||||
|
extern int rtx_equal_function_value_matters;
|
||||||
|
extern struct rtx_def *fpscr_rtx;
|
||||||
|
extern struct rtx_def *get_fpscr_rtx ();
|
||||||
|
|
||||||
|
|
||||||
#define MOVE_RATIO (TARGET_SMALLCODE ? 2 : 16)
|
#define MOVE_RATIO (TARGET_SMALLCODE ? 2 : 16)
|
||||||
|
|
||||||
|
@ -1860,10 +2090,16 @@ sh_valid_machine_decl_attribute (DECL, ATTRIBUTES, IDENTIFIER, ARGS)
|
||||||
{"arith_operand", {SUBREG, REG, CONST_INT}}, \
|
{"arith_operand", {SUBREG, REG, CONST_INT}}, \
|
||||||
{"arith_reg_operand", {SUBREG, REG}}, \
|
{"arith_reg_operand", {SUBREG, REG}}, \
|
||||||
{"arith_reg_or_0_operand", {SUBREG, REG, CONST_INT}}, \
|
{"arith_reg_or_0_operand", {SUBREG, REG, CONST_INT}}, \
|
||||||
|
{"binary_float_operator", {PLUS, MULT}}, \
|
||||||
{"braf_label_ref_operand", {LABEL_REF}}, \
|
{"braf_label_ref_operand", {LABEL_REF}}, \
|
||||||
|
{"commutative_float_operator", {PLUS, MULT}}, \
|
||||||
|
{"fp_arith_reg_operand", {SUBREG, REG}}, \
|
||||||
|
{"fp_extended_operand", {SUBREG, REG, FLOAT_EXTEND}}, \
|
||||||
|
{"fpscr_operand", {REG}}, \
|
||||||
{"general_movsrc_operand", {SUBREG, REG, CONST_INT, MEM}}, \
|
{"general_movsrc_operand", {SUBREG, REG, CONST_INT, MEM}}, \
|
||||||
{"general_movdst_operand", {SUBREG, REG, CONST_INT, MEM}}, \
|
{"general_movdst_operand", {SUBREG, REG, CONST_INT, MEM}}, \
|
||||||
{"logical_operand", {SUBREG, REG, CONST_INT}}, \
|
{"logical_operand", {SUBREG, REG, CONST_INT}}, \
|
||||||
|
{"noncommutative_float_operator", {MINUS, DIV}}, \
|
||||||
{"register_operand", {SUBREG, REG}},
|
{"register_operand", {SUBREG, REG}},
|
||||||
|
|
||||||
/* Define this macro if it is advisable to hold scalars in registers
|
/* Define this macro if it is advisable to hold scalars in registers
|
||||||
|
@ -1929,7 +2165,7 @@ do { \
|
||||||
using their arguments pretty quickly. \
|
using their arguments pretty quickly. \
|
||||||
Assume a four cycle delay before they are needed. */ \
|
Assume a four cycle delay before they are needed. */ \
|
||||||
if (! reg_set_p (reg, dep_insn)) \
|
if (! reg_set_p (reg, dep_insn)) \
|
||||||
cost -= 4; \
|
cost -= TARGET_SUPERSCALAR ? 40 : 4; \
|
||||||
} \
|
} \
|
||||||
/* Adjust load_si / pcload_si type insns latency. Use the known \
|
/* Adjust load_si / pcload_si type insns latency. Use the known \
|
||||||
nominal latency and form of the insn to speed up the check. */ \
|
nominal latency and form of the insn to speed up the check. */ \
|
||||||
|
@ -1939,9 +2175,14 @@ do { \
|
||||||
it's actually a move insn. */ \
|
it's actually a move insn. */ \
|
||||||
&& general_movsrc_operand (SET_SRC (PATTERN (dep_insn)), SImode))\
|
&& general_movsrc_operand (SET_SRC (PATTERN (dep_insn)), SImode))\
|
||||||
cost = 2; \
|
cost = 2; \
|
||||||
|
else if (cost == 30 \
|
||||||
|
&& GET_CODE (PATTERN (dep_insn)) == SET \
|
||||||
|
&& GET_MODE (SET_SRC (PATTERN (dep_insn))) == SImode) \
|
||||||
|
cost = 20; \
|
||||||
} while (0) \
|
} while (0) \
|
||||||
|
|
||||||
/* For the sake of libgcc2.c, indicate target supports atexit. */
|
/* For the sake of libgcc2.c, indicate target supports atexit. */
|
||||||
#define HAVE_ATEXIT
|
#define HAVE_ATEXIT
|
||||||
|
|
||||||
#define SH_DYNAMIC_SHIFT_COST (TARGET_SH3 ? (TARGET_SMALLCODE ? 1 : 2) : 20)
|
#define SH_DYNAMIC_SHIFT_COST \
|
||||||
|
(TARGET_HARD_SH4 ? 1 : TARGET_SH3 ? (TARGET_SMALLCODE ? 1 : 2) : 20)
|
||||||
|
|
1444
gcc/config/sh/sh.md
1444
gcc/config/sh/sh.md
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
CROSS_LIBGCC1 = libgcc1-asm.a
|
CROSS_LIBGCC1 = libgcc1-asm.a
|
||||||
LIB1ASMSRC = sh/lib1funcs.asm
|
LIB1ASMSRC = sh/lib1funcs.asm
|
||||||
LIB1ASMFUNCS = _ashiftrt _ashiftrt_n _ashiftlt _lshiftrt _movstr \
|
LIB1ASMFUNCS = _ashiftrt _ashiftrt_n _ashiftlt _lshiftrt _movstr \
|
||||||
_mulsi3 _sdivsi3 _udivsi3 _set_fpscr
|
_movstr_i4 _mulsi3 _sdivsi3 _sdivsi3_i4 _udivsi3 _udivsi3_i4 _set_fpscr
|
||||||
|
|
||||||
# These are really part of libgcc1, but this will cause them to be
|
# These are really part of libgcc1, but this will cause them to be
|
||||||
# built correctly, so...
|
# built correctly, so...
|
||||||
|
@ -21,7 +21,7 @@ fp-bit.c: $(srcdir)/config/fp-bit.c
|
||||||
echo '#endif' >> fp-bit.c
|
echo '#endif' >> fp-bit.c
|
||||||
cat $(srcdir)/config/fp-bit.c >> fp-bit.c
|
cat $(srcdir)/config/fp-bit.c >> fp-bit.c
|
||||||
|
|
||||||
MULTILIB_OPTIONS= ml m2/m3e
|
MULTILIB_OPTIONS= ml m2/m3e/m4-single-only/m4-single/m4
|
||||||
MULTILIB_DIRNAMES=
|
MULTILIB_DIRNAMES=
|
||||||
MULTILIB_MATCHES = m2=m3
|
MULTILIB_MATCHES = m2=m3
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@
|
||||||
#ifndef __GNUC_VA_LIST
|
#ifndef __GNUC_VA_LIST
|
||||||
#define __GNUC_VA_LIST
|
#define __GNUC_VA_LIST
|
||||||
|
|
||||||
#ifdef __SH3E__
|
#if defined (__SH3E__) || defined (__SH4_SINGLE__) || defined (__SH4__) || defined (__SH4_SINGLE_ONLY__)
|
||||||
|
|
||||||
typedef long __va_greg;
|
typedef long __va_greg;
|
||||||
typedef double __va_freg;
|
typedef float __va_freg;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
__va_greg * __va_next_o; /* next available register */
|
__va_greg * __va_next_o; /* next available register */
|
||||||
|
@ -33,24 +33,24 @@ typedef void *__gnuc_va_list;
|
||||||
|
|
||||||
#ifdef _STDARG_H
|
#ifdef _STDARG_H
|
||||||
|
|
||||||
#ifdef __SH3E__
|
#if defined (__SH3E__) || defined (__SH4_SINGLE__) || defined (__SH4__) || defined (__SH4_SINGLE_ONLY__)
|
||||||
|
|
||||||
#define va_start(AP, LASTARG) \
|
#define va_start(AP, LASTARG) \
|
||||||
__extension__ \
|
__extension__ \
|
||||||
({ \
|
({ \
|
||||||
AP.__va_next_fp = (__va_freg *) __builtin_saveregs (); \
|
(AP).__va_next_fp = (__va_freg *) __builtin_saveregs (); \
|
||||||
AP.__va_next_fp_limit = (AP.__va_next_fp + \
|
(AP).__va_next_fp_limit = ((AP).__va_next_fp + \
|
||||||
(__builtin_args_info (1) < 8 ? 8 - __builtin_args_info (1) : 0)); \
|
(__builtin_args_info (1) < 8 ? 8 - __builtin_args_info (1) : 0)); \
|
||||||
AP.__va_next_o = (__va_greg *) AP.__va_next_fp_limit; \
|
(AP).__va_next_o = (__va_greg *) (AP).__va_next_fp_limit; \
|
||||||
AP.__va_next_o_limit = (AP.__va_next_o + \
|
(AP).__va_next_o_limit = ((AP).__va_next_o + \
|
||||||
(__builtin_args_info (0) < 4 ? 4 - __builtin_args_info (0) : 0)); \
|
(__builtin_args_info (0) < 4 ? 4 - __builtin_args_info (0) : 0)); \
|
||||||
AP.__va_next_stack = (__va_greg *) __builtin_next_arg (LASTARG); \
|
(AP).__va_next_stack = (__va_greg *) __builtin_next_arg (LASTARG); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#else /* ! SH3E */
|
#else /* ! SH3E */
|
||||||
|
|
||||||
#define va_start(AP, LASTARG) \
|
#define va_start(AP, LASTARG) \
|
||||||
(AP = ((__gnuc_va_list) __builtin_next_arg (LASTARG)))
|
((AP) = ((__gnuc_va_list) __builtin_next_arg (LASTARG)))
|
||||||
|
|
||||||
#endif /* ! SH3E */
|
#endif /* ! SH3E */
|
||||||
|
|
||||||
|
@ -59,24 +59,26 @@ __extension__ \
|
||||||
#define va_alist __builtin_va_alist
|
#define va_alist __builtin_va_alist
|
||||||
#define va_dcl int __builtin_va_alist;...
|
#define va_dcl int __builtin_va_alist;...
|
||||||
|
|
||||||
#ifdef __SH3E__
|
#if defined (__SH3E__) || defined (__SH4_SINGLE__) || defined (__SH4__) || defined (__SH4_SINGLE_ONLY__)
|
||||||
|
|
||||||
#define va_start(AP) \
|
#define va_start(AP) \
|
||||||
__extension__ \
|
__extension__ \
|
||||||
({ \
|
({ \
|
||||||
AP.__va_next_fp = (__va_freg *) __builtin_saveregs (); \
|
(AP).__va_next_fp = (__va_freg *) __builtin_saveregs (); \
|
||||||
AP.__va_next_fp_limit = (AP.__va_next_fp + \
|
(AP).__va_next_fp_limit = ((AP).__va_next_fp + \
|
||||||
(__builtin_args_info (1) < 8 ? 8 - __builtin_args_info (1) : 0)); \
|
(__builtin_args_info (1) < 8 ? 8 - __builtin_args_info (1) : 0)); \
|
||||||
AP.__va_next_o = (__va_greg *) AP.__va_next_fp_limit; \
|
(AP).__va_next_o = (__va_greg *) (AP).__va_next_fp_limit; \
|
||||||
AP.__va_next_o_limit = (AP.__va_next_o + \
|
(AP).__va_next_o_limit = ((AP).__va_next_o + \
|
||||||
(__builtin_args_info (0) < 4 ? 4 - __builtin_args_info (0) : 0)); \
|
(__builtin_args_info (0) < 4 ? 4 - __builtin_args_info (0) : 0)); \
|
||||||
AP.__va_next_stack = (__va_greg *) __builtin_next_arg (__builtin_va_alist) \
|
(AP).__va_next_stack \
|
||||||
- (__builtin_args_info (0) >= 4 || __builtin_args_info (1) >= 8 ? 1 : 0); \
|
= ((__va_greg *) __builtin_next_arg (__builtin_va_alist) \
|
||||||
|
- (__builtin_args_info (0) >= 4 || __builtin_args_info (1) >= 8 \
|
||||||
|
? 1 : 0)); \
|
||||||
})
|
})
|
||||||
|
|
||||||
#else /* ! SH3E */
|
#else /* ! SH3E */
|
||||||
|
|
||||||
#define va_start(AP) AP=(char *) &__builtin_va_alist
|
#define va_start(AP) ((AP) = (char *) &__builtin_va_alist)
|
||||||
|
|
||||||
#endif /* ! SH3E */
|
#endif /* ! SH3E */
|
||||||
|
|
||||||
|
@ -136,53 +138,78 @@ enum __va_type_classes {
|
||||||
We want the MEM_IN_STRUCT_P bit set in the emitted RTL, therefore we
|
We want the MEM_IN_STRUCT_P bit set in the emitted RTL, therefore we
|
||||||
use unions even when it would otherwise be unnecessary. */
|
use unions even when it would otherwise be unnecessary. */
|
||||||
|
|
||||||
|
/* gcc has an extension that allows to use a casted lvalue as an lvalue,
|
||||||
|
But it doesn't work in C++ with -pedantic - even in the presence of
|
||||||
|
__extension__ . We work around this problem by using a reference type. */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define __VA_REF &
|
||||||
|
#else
|
||||||
|
#define __VA_REF
|
||||||
|
#endif
|
||||||
|
|
||||||
#define __va_arg_sh1(AP, TYPE) __extension__ \
|
#define __va_arg_sh1(AP, TYPE) __extension__ \
|
||||||
__extension__ \
|
|
||||||
({(sizeof (TYPE) == 1 \
|
({(sizeof (TYPE) == 1 \
|
||||||
? ({union {TYPE t; char c;} __t; \
|
? ({union {TYPE t; char c;} __t; \
|
||||||
asm("" \
|
__asm("" \
|
||||||
: "=r" (__t.c) \
|
: "=r" (__t.c) \
|
||||||
: "0" ((((union { int i, j; } *) (AP))++)->i)); \
|
: "0" ((((union { int i, j; } *__VA_REF) (AP))++)->i)); \
|
||||||
__t.t;}) \
|
__t.t;}) \
|
||||||
: sizeof (TYPE) == 2 \
|
: sizeof (TYPE) == 2 \
|
||||||
? ({union {TYPE t; short s;} __t; \
|
? ({union {TYPE t; short s;} __t; \
|
||||||
asm("" \
|
__asm("" \
|
||||||
: "=r" (__t.s) \
|
: "=r" (__t.s) \
|
||||||
: "0" ((((union { int i, j; } *) (AP))++)->i)); \
|
: "0" ((((union { int i, j; } *__VA_REF) (AP))++)->i)); \
|
||||||
__t.t;}) \
|
__t.t;}) \
|
||||||
: sizeof (TYPE) >= 4 || __LITTLE_ENDIAN_P \
|
: sizeof (TYPE) >= 4 || __LITTLE_ENDIAN_P \
|
||||||
? (((union { TYPE t; int i;} *) (AP))++)->t \
|
? (((union { TYPE t; int i;} *__VA_REF) (AP))++)->t \
|
||||||
: ((union {TYPE t;TYPE u;}*) ((char *)++(int *)(AP) - sizeof (TYPE)))->t);})
|
: ((union {TYPE t;TYPE u;}*) ((char *)++(int *__VA_REF)(AP) - sizeof (TYPE)))->t);})
|
||||||
|
|
||||||
#ifdef __SH3E__
|
#if defined (__SH3E__) || defined (__SH4_SINGLE__) || defined (__SH4__) || defined (__SH4_SINGLE_ONLY__)
|
||||||
|
|
||||||
#define __PASS_AS_FLOAT(TYPE_CLASS,SIZE) \
|
#define __PASS_AS_FLOAT(TYPE_CLASS,SIZE) \
|
||||||
(TYPE_CLASS == __real_type_class && SIZE == 4)
|
(TYPE_CLASS == __real_type_class && SIZE == 4)
|
||||||
|
|
||||||
|
#define __TARGET_SH4_P 0
|
||||||
|
|
||||||
|
#if defined(__SH4__) || defined(__SH4_SINGLE__)
|
||||||
|
#undef __PASS_AS_FLOAT
|
||||||
|
#define __PASS_AS_FLOAT(TYPE_CLASS,SIZE) \
|
||||||
|
(TYPE_CLASS == __real_type_class && SIZE <= 8 \
|
||||||
|
|| TYPE_CLASS == __complex_type_class && SIZE <= 16)
|
||||||
|
#undef __TARGET_SH4_P
|
||||||
|
#define __TARGET_SH4_P 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#define va_arg(pvar,TYPE) \
|
#define va_arg(pvar,TYPE) \
|
||||||
__extension__ \
|
__extension__ \
|
||||||
({int __type = __builtin_classify_type (* (TYPE *) 0); \
|
({int __type = __builtin_classify_type (* (TYPE *) 0); \
|
||||||
void * __result_p; \
|
void * __result_p; \
|
||||||
if (__PASS_AS_FLOAT (__type, sizeof(TYPE))) \
|
if (__PASS_AS_FLOAT (__type, sizeof(TYPE))) \
|
||||||
{ \
|
{ \
|
||||||
if (pvar.__va_next_fp < pvar.__va_next_fp_limit) \
|
if ((pvar).__va_next_fp < (pvar).__va_next_fp_limit) \
|
||||||
{ \
|
{ \
|
||||||
__result_p = &pvar.__va_next_fp; \
|
if (((__type == __real_type_class && sizeof (TYPE) > 4)\
|
||||||
|
|| sizeof (TYPE) > 8) \
|
||||||
|
&& (((int) (pvar).__va_next_fp ^ (int) (pvar).__va_next_fp_limit)\
|
||||||
|
& 4)) \
|
||||||
|
(pvar).__va_next_fp++; \
|
||||||
|
__result_p = &(pvar).__va_next_fp; \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
__result_p = &pvar.__va_next_stack; \
|
__result_p = &(pvar).__va_next_stack; \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
if (pvar.__va_next_o + ((sizeof (TYPE) + 3) / 4) \
|
if ((pvar).__va_next_o + ((sizeof (TYPE) + 3) / 4) \
|
||||||
<= pvar.__va_next_o_limit) \
|
<= (pvar).__va_next_o_limit) \
|
||||||
__result_p = &pvar.__va_next_o; \
|
__result_p = &(pvar).__va_next_o; \
|
||||||
else \
|
else \
|
||||||
{ \
|
{ \
|
||||||
if (sizeof (TYPE) > 4) \
|
if (sizeof (TYPE) > 4) \
|
||||||
pvar.__va_next_o = pvar.__va_next_o_limit; \
|
if (! __TARGET_SH4_P) \
|
||||||
|
(pvar).__va_next_o = (pvar).__va_next_o_limit; \
|
||||||
\
|
\
|
||||||
__result_p = &pvar.__va_next_stack; \
|
__result_p = &(pvar).__va_next_stack; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
__va_arg_sh1(*(void **)__result_p, TYPE);})
|
__va_arg_sh1(*(void **)__result_p, TYPE);})
|
||||||
|
@ -194,6 +221,6 @@ __extension__ \
|
||||||
#endif /* SH3E */
|
#endif /* SH3E */
|
||||||
|
|
||||||
/* Copy __gnuc_va_list into another variable of this type. */
|
/* Copy __gnuc_va_list into another variable of this type. */
|
||||||
#define __va_copy(dest, src) (dest) = (src)
|
#define __va_copy(dest, src) ((dest) = (src))
|
||||||
|
|
||||||
#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
|
#endif /* defined (_STDARG_H) || defined (_VARARGS_H) */
|
||||||
|
|
Loading…
Reference in New Issue