From 8c2a3f3b6cc7bc38af483ac4923258d376f90954 Mon Sep 17 00:00:00 2001 From: Oleg Endo Date: Wed, 11 Apr 2012 11:35:32 +0000 Subject: [PATCH] re PR target/50751 (SH Target: Displacement addressing does not work for QImode and HImode) PR target/50751 * config/sh/sh-protos.h (sh_legitimate_index_p): Add new arguments consider_sh2a and allow_zero. * config/sh/sh.c (sh_legitimate_index_p): Likewise. (disp_addr_displacement): New function. (sh_address_cost): Use disp_addr_displacement function instead of DISP_ADDR_OFFSET. (sh_legitimate_address_p): Adapt to changed sh_legitimate_index_p declaration. (sh_find_mov_disp_adjust): Remove HImode check. (sh_secondary_reload): Add HImode case. Use satisfies_constraint_Sdd, disp_addr_displacement and max_mov_insn_displacement. (max_mov_insn_displacement): Remove HImode check. * config/sh/sh.h (CONST_OK_FOR_K04, CONST_OK_FOR_K12, DISP_ADDR_P, DISP_ADDR_OFFSET): Remove. * config/sh/constraints.md (K05, K13): New constraints. (K12): Correct comment. (Sdd): Do not use DISP_ADDR_P macro. (Snd, Sbw): Use satisfies_constraint_Sdd. * config/sh/sh.md (extendhisi2): Remove constraints from expander. (*extendhisi2_compact, movhi_i): Remove. (*extendhisi2_compact_reg, *extendhisi2_compact_mem_disp, *extendhisi2_compact_mem_disp, *extendhisi2_compact_snd, *movhi_reg_reg, *movhi_store_mem_disp05, *movhi_store_mem_disp13, *movhi_load_mem_disp, *movhi_load_mem_disp, *movhi): New insns. (*extendqisi2_compact_mem_disp, *extendqisi2_compact_mem_disp, *movqi_store_mem_disp04, *movqi_store_mem_disp12, *movqi_load_mem_disp, *movqi_load_mem_disp): Use sh_legitimate_index_p instead of CONST_OK_FOR_Kxx. Add new peepholes for HImode displacement addressing. From-SVN: r186311 --- gcc/ChangeLog | 33 ++++++ gcc/config/sh/constraints.md | 36 ++++-- gcc/config/sh/predicates.md | 4 +- gcc/config/sh/sh-protos.h | 2 +- gcc/config/sh/sh.c | 43 ++++---- gcc/config/sh/sh.h | 12 -- gcc/config/sh/sh.md | 258 ++++++++++++++++++++++++++++++++----------- 7 files changed, 276 insertions(+), 112 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f0ae48f..f456157 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,38 @@ 2012-04-11 Oleg Endo + PR target/50751 + * config/sh/sh-protos.h (sh_legitimate_index_p): Add new arguments + consider_sh2a and allow_zero. + * config/sh/sh.c (sh_legitimate_index_p): Likewise. + (disp_addr_displacement): New function. + (sh_address_cost): Use disp_addr_displacement function instead + of DISP_ADDR_OFFSET. + (sh_legitimate_address_p): Adapt to changed + sh_legitimate_index_p declaration. + (sh_find_mov_disp_adjust): Remove HImode check. + (sh_secondary_reload): Add HImode case. Use satisfies_constraint_Sdd, + disp_addr_displacement and max_mov_insn_displacement. + (max_mov_insn_displacement): Remove HImode check. + * config/sh/sh.h (CONST_OK_FOR_K04, CONST_OK_FOR_K12, + DISP_ADDR_P, DISP_ADDR_OFFSET): Remove. + * config/sh/constraints.md (K05, K13): New constraints. + (K12): Correct comment. + (Sdd): Do not use DISP_ADDR_P macro. + (Snd, Sbw): Use satisfies_constraint_Sdd. + * config/sh/sh.md (extendhisi2): Remove constraints from expander. + (*extendhisi2_compact, movhi_i): Remove. + (*extendhisi2_compact_reg, *extendhisi2_compact_mem_disp, + *extendhisi2_compact_mem_disp, *extendhisi2_compact_snd, + *movhi_reg_reg, *movhi_store_mem_disp05, *movhi_store_mem_disp13, + *movhi_load_mem_disp, *movhi_load_mem_disp, *movhi): New insns. + (*extendqisi2_compact_mem_disp, *extendqisi2_compact_mem_disp, + *movqi_store_mem_disp04, *movqi_store_mem_disp12, *movqi_load_mem_disp, + *movqi_load_mem_disp): Use sh_legitimate_index_p instead of + CONST_OK_FOR_Kxx. + Add new peepholes for HImode displacement addressing. + +2012-04-11 Oleg Endo + * config/sh/sh.h (SIDI_OFF): Remove. * config/sh/sh.md: Use gen_highpart and gen_lowpart to access DImode subregs instead of gen_rtx_REG or simplifly_gen_subreg diff --git a/gcc/config/sh/constraints.md b/gcc/config/sh/constraints.md index 3a5fc36..6c9bc5e 100644 --- a/gcc/config/sh/constraints.md +++ b/gcc/config/sh/constraints.md @@ -145,16 +145,28 @@ (and (match_code "const_int") (match_test "ival >= 0 && ival <= 15"))) +(define_constraint "K05" + "An unsigned 5-bit constant, as used in mov.w displacement addressing." + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 31"))) + (define_constraint "K08" "An unsigned 8-bit constant, as used in and, or, etc." (and (match_code "const_int") (match_test "ival >= 0 && ival <= 255"))) (define_constraint "K12" - "An unsigned 12-bit constant, as used in SH2A 12-bit displacement addressing." + "An unsigned 12-bit constant, as used in SH2A 12-bit mov.b displacement + addressing." (and (match_code "const_int") (match_test "ival >= 0 && ival <= 4095"))) +(define_constraint "K13" + "An unsigned 13-bit constant, as used in SH2A 12-bit mov.w displacement + addressing." + (and (match_code "const_int") + (match_test "ival >= 0 && ival <= 8191"))) + (define_constraint "K16" "An unsigned 16-bit constant, as used in SHmedia shori." (and (match_code "const_int") @@ -262,6 +274,16 @@ (and (match_test "memory_operand (op, GET_MODE (op))") (match_test "GET_CODE (XEXP (op, 0)) != PLUS"))) +(define_memory_constraint "Sdd" + "A memory reference that uses displacement addressing." + (and (match_test "MEM_P (op) && GET_CODE (XEXP (op, 0)) == PLUS") + (match_test "REG_P (XEXP (XEXP (op, 0), 0))") + (match_test "CONST_INT_P (XEXP (XEXP (op, 0), 1))"))) + +(define_memory_constraint "Snd" + "A memory reference that excludes displacement addressing." + (match_test "! satisfies_constraint_Sdd (op)")) + (define_memory_constraint "Sbv" "A memory reference, as used in SH2A bclr.b, bset.b, etc." (and (match_test "MEM_P (op) && GET_MODE (op) == QImode") @@ -269,15 +291,7 @@ (define_memory_constraint "Sbw" "A memory reference, as used in SH2A bclr.b, bset.b, etc." - (and (match_test "MEM_P (op) && GET_MODE (op) == QImode") - (match_test "GET_CODE (XEXP (op, 0)) == PLUS") - (match_test "REG_P (XEXP (XEXP (op, 0), 0))") + (and (match_test "satisfies_constraint_Sdd (op)") + (match_test "GET_MODE (op) == QImode") (match_test "satisfies_constraint_K12 (XEXP (XEXP (op, 0), 1))"))) -(define_memory_constraint "Snd" - "A memory reference that excludes displacement addressing." - (match_test "! DISP_ADDR_P (op)")) - -(define_memory_constraint "Sdd" - "A memory reference that uses displacement addressing." - (match_test "DISP_ADDR_P (op)")) diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md index b00ad14..c6d0d46 100644 --- a/gcc/config/sh/predicates.md +++ b/gcc/config/sh/predicates.md @@ -404,7 +404,7 @@ if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) - return sh_legitimate_index_p (mode, XEXP (x, 1)); + return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false); } if (TARGET_SHMEDIA @@ -466,7 +466,7 @@ if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) - return sh_legitimate_index_p (mode, XEXP (x, 1)); + return sh_legitimate_index_p (mode, XEXP (x, 1), TARGET_SH2A, false); } return general_operand (op, mode); diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index 8143749..cb9ad0f 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -56,7 +56,7 @@ extern int sh_loop_align (rtx); extern bool fp_zero_operand (rtx); extern bool fp_one_operand (rtx); extern rtx get_fpscr_rtx (void); -extern bool sh_legitimate_index_p (enum machine_mode, rtx); +extern bool sh_legitimate_index_p (enum machine_mode, rtx, bool, bool); extern bool sh_legitimize_reload_address (rtx *, enum machine_mode, int, int); extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx); extern bool nonpic_symbol_mentioned_p (rtx); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 443f800..e7e1945 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -304,6 +304,7 @@ static bool sh_legitimate_constant_p (enum machine_mode, rtx); static int mov_insn_size (enum machine_mode, bool); static int max_mov_insn_displacement (enum machine_mode, bool); static int mov_insn_alignment_mask (enum machine_mode, bool); +static HOST_WIDE_INT disp_addr_displacement (rtx); static void sh_init_sync_libfuncs (void) ATTRIBUTE_UNUSED; @@ -3160,11 +3161,6 @@ max_mov_insn_displacement (enum machine_mode mode, bool consider_sh2a) scale the max. displacement value accordingly. */ const int disp_scale = consider_sh2a ? (4095 / 15) : 1; - /* FIXME: HImode with displacement addressing is not supported yet. - Make it purposefully fail for now. */ - if (mode == HImode) - return 0; - /* SH2A supports FPU move insns with 12 bit displacements. Other variants to do not support any kind of displacements for FPU move insns. */ @@ -3194,15 +3190,24 @@ mov_insn_alignment_mask (enum machine_mode mode, bool consider_sh2a) return mov_insn_sz > 0 ? (mov_insn_sz - 1) : 0; } +/* Return the displacement value of a displacement address. */ + +static inline HOST_WIDE_INT +disp_addr_displacement (rtx x) +{ + gcc_assert (satisfies_constraint_Sdd (x)); + return INTVAL (XEXP (XEXP (x, 0), 1)); +} + /* Compute the cost of an address. */ static int sh_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED) { /* 'reg + disp' addressing. */ - if (DISP_ADDR_P (x)) + if (satisfies_constraint_Sdd (x)) { - const HOST_WIDE_INT offset = DISP_ADDR_OFFSET (x); + const HOST_WIDE_INT offset = disp_addr_displacement (x); const enum machine_mode mode = GET_MODE (x); /* The displacement would fit into a 2 byte move insn. */ @@ -9665,7 +9670,8 @@ sh_insn_length_adjustment (rtx insn) with MODE. */ bool -sh_legitimate_index_p (enum machine_mode mode, rtx op) +sh_legitimate_index_p (enum machine_mode mode, rtx op, bool consider_sh2a, + bool allow_zero) { if (! CONST_INT_P (op)) return false; @@ -9686,15 +9692,15 @@ sh_legitimate_index_p (enum machine_mode mode, rtx op) else { const HOST_WIDE_INT offset = INTVAL (op); - const int max_disp = max_mov_insn_displacement (mode, TARGET_SH2A); - const int align_mask = mov_insn_alignment_mask (mode, TARGET_SH2A); + const int max_disp = max_mov_insn_displacement (mode, consider_sh2a); + const int align_mask = mov_insn_alignment_mask (mode, consider_sh2a); /* If the mode does not support any displacement always return false. Even though an index of '0' is actually always valid, it will cause troubles when e.g. a DFmode move is split into two SFmode moves, where one SFmode move will have index '0' and the other move will have index '4'. */ - if (max_disp < 1) + if (!allow_zero && max_disp < 1) return false; return offset >= 0 && offset <= max_disp && (offset & align_mask) == 0; @@ -9728,7 +9734,7 @@ sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) if (GET_MODE_SIZE (mode) <= 8 && MAYBE_BASE_REGISTER_RTX_P (xop0, strict) - && sh_legitimate_index_p (mode, xop1)) + && sh_legitimate_index_p (mode, xop1, TARGET_SH2A, false)) return true; if ((ALLOW_INDEXED_ADDRESS || GET_MODE (x) == DImode @@ -9875,11 +9881,6 @@ sh_find_mov_disp_adjust (enum machine_mode mode, HOST_WIDE_INT offset) if (mode_sz < 1 || mode_sz > 8 || max_disp < 1) return res; - /* FIXME: HImode with displacement addressing is not supported yet. - Make it purposefully fail for now. */ - if (mov_insn_sz == 2) - return res; - /* Keeps the previous behavior for QImode displacement addressing. This just decides how the offset is re-based. Removing this special case will result in slightly bigger code on average, but it's not that @@ -12566,12 +12567,14 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, if (rclass == FPUL_REGS && true_regnum (x) == -1) return GENERAL_REGS; - /* Force mov.b displacement addressing insn to use R0 as the other operand. + /* Force mov.b / mov.w displacement addressing insn to use R0 as + the other operand. On SH2A could also just leave it alone here, which would result in a 4 byte move insn being generated instead. However, for this to work the insns must have the appropriate alternatives. */ - if (mode == QImode && rclass != R0_REGS - && DISP_ADDR_P (x) && DISP_ADDR_OFFSET (x) < 16) + if ((mode == QImode || mode == HImode) && rclass != R0_REGS + && satisfies_constraint_Sdd (x) + && disp_addr_displacement (x) <= max_mov_insn_displacement (mode, false)) return R0_REGS; /* When reload is trying to address a QImode or HImode subreg on the stack, diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 498109a..1ee0d01 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -1210,24 +1210,12 @@ extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER]; ((HOST_BITS_PER_WIDE_INT >= 64 && (VALUE) == (HOST_WIDE_INT) 0xffffffff) \ || (HOST_BITS_PER_WIDE_INT >= 64 && (VALUE) == (HOST_WIDE_INT) -1 << 32)) -#define CONST_OK_FOR_K04(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \ - && ((HOST_WIDE_INT)(VALUE)) <= 15) - #define CONST_OK_FOR_K08(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \ && ((HOST_WIDE_INT)(VALUE)) <= 255) -#define CONST_OK_FOR_K12(VALUE) (((HOST_WIDE_INT)(VALUE))>= 0 \ - && ((HOST_WIDE_INT)(VALUE)) <= 4095) - #define ZERO_EXTRACT_ANDMASK(EXTRACT_SZ_RTX, EXTRACT_POS_RTX)\ (((1 << INTVAL (EXTRACT_SZ_RTX)) - 1) << INTVAL (EXTRACT_POS_RTX)) -#define DISP_ADDR_P(X) (MEM_P (X) && GET_CODE (XEXP (X, 0)) == PLUS \ - && REG_P (XEXP (XEXP (X, 0), 0)) \ - && CONST_INT_P (XEXP (XEXP (X, 0), 1))) - -#define DISP_ADDR_OFFSET(X) (INTVAL (XEXP (XEXP (X, 0), 1))) - #if 0 #define SECONDARY_INOUT_RELOAD_CLASS(CLASS,MODE,X,ELSE) \ ((((REGCLASS_HAS_FP_REG (CLASS) \ diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index d6ae799..45a5edf 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -4743,20 +4743,18 @@ label: operands[1] = XEXP (operands[1], 0); }) +;; FIXME: Maybe fold HImode and QImode stuff with mode iterator? (define_expand "extendhisi2" - [(set (match_operand:SI 0 "arith_reg_dest" "=r,r") - (sign_extend:SI (match_operand:HI 1 "general_extend_operand" "r,m")))] + [(set (match_operand:SI 0 "arith_reg_dest" "") + (sign_extend:SI (match_operand:HI 1 "general_extend_operand" "")))] "" "") -(define_insn "*extendhisi2_compact" - [(set (match_operand:SI 0 "arith_reg_dest" "=r,r") - (sign_extend:SI (match_operand:HI 1 "general_movsrc_operand" "r,m")))] - "TARGET_SH1" - "@ - exts.w %1,%0 - mov.w %1,%0" - [(set_attr "type" "arith,load")]) +(define_expand "extendqisi2" + [(set (match_operand:SI 0 "arith_reg_dest" "") + (sign_extend:SI (match_operand:QI 1 "general_extend_operand" "")))] + "" + "") (define_insn "*extendhisi2_media" [(set (match_operand:SI 0 "register_operand" "=r,r") @@ -4786,12 +4784,6 @@ label: subreg_lowpart_offset (SImode, GET_MODE (op1))); }) -(define_expand "extendqisi2" - [(set (match_operand:SI 0 "arith_reg_dest" "") - (sign_extend:SI (match_operand:QI 1 "general_extend_operand" "")))] - "" - "") - (define_insn "*extendqisi2_compact_reg" [(set (match_operand:SI 0 "arith_reg_dest" "=r,r") (sign_extend:SI (match_operand:QI 1 "register_operand" "r,t")))] @@ -4801,6 +4793,15 @@ label: movt %0" [(set_attr "type" "arith,arith")]) +(define_insn "*extendhisi2_compact_reg" + [(set (match_operand:SI 0 "arith_reg_dest" "=r,r") + (sign_extend:SI (match_operand:HI 1 "register_operand" "r,t")))] + "TARGET_SH1" + "@ + exts.w %1,%0 + movt %0" + [(set_attr "type" "arith,arith")]) + ;; FIXME: Fold non-SH2A and SH2A alternatives with "enabled" attribute. ;; See movqi insns. (define_insn "*extendqisi2_compact_mem_disp" @@ -4808,20 +4809,31 @@ label: (sign_extend:SI (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r") (match_operand:SI 2 "const_int_operand" "K04,N")))))] - "TARGET_SH1 && ! TARGET_SH2A && CONST_OK_FOR_K04 (INTVAL (operands[2]))" + "TARGET_SH1 && ! TARGET_SH2A + && sh_legitimate_index_p (QImode, operands[2], false, true)" "@ mov.b @(%O2,%1),%0 mov.b @%1,%0" [(set_attr "type" "load")]) +(define_insn "*extendhisi2_compact_mem_disp" + [(set (match_operand:SI 0 "arith_reg_dest" "=z,r") + (sign_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r") + (match_operand:SI 2 "const_int_operand" "K05,N")))))] + "TARGET_SH1 && ! TARGET_SH2A + && sh_legitimate_index_p (HImode, operands[2], false, true)" + "@ + mov.w @(%O2,%1),%0 + mov.w @%1,%0" + [(set_attr "type" "load")]) + (define_insn "*extendqisi2_compact_mem_disp" [(set (match_operand:SI 0 "arith_reg_dest" "=z,r,r") (sign_extend:SI (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r") (match_operand:SI 2 "const_int_operand" "K04,N,K12")))))] - "TARGET_SH2A - && (CONST_OK_FOR_K04 (INTVAL (operands[2])) - || (CONST_OK_FOR_K12 (INTVAL (operands[2]))))" + "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[2], true, true)" "@ mov.b @(%O2,%1),%0 mov.b @%1,%0 @@ -4829,8 +4841,23 @@ label: [(set_attr "type" "load") (set_attr "length" "2,2,4")]) -;; This will take care of other QImode addressing modes than displacement -;; addressing. +(define_insn "*extendhisi2_compact_mem_disp" + [(set (match_operand:SI 0 "arith_reg_dest" "=z,r,r") + (sign_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r") + (match_operand:SI 2 "const_int_operand" "K05,N,K13")))))] + "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[2], true, true)" + "@ + mov.w @(%O2,%1),%0 + mov.w @%1,%0 + mov.w @(%O2,%1),%0" + [(set_attr "type" "load") + (set_attr "length" "2,2,4")]) + +;; The *_snd patterns will take care of other QImode/HImode addressing +;; modes than displacement addressing. They must be defined _after_ the +;; displacement addressing patterns. Otherwise the displacement addressing +;; patterns will not be picked. (define_insn "*extendqisi2_compact_snd" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (sign_extend:SI (match_operand:QI 1 "movsrc_no_disp_mem_operand" "Snd")))] @@ -4838,6 +4865,13 @@ label: "mov.b %1,%0" [(set_attr "type" "load")]) +(define_insn "*extendhisi2_compact_snd" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (sign_extend:SI (match_operand:HI 1 "movsrc_no_disp_mem_operand" "Snd")))] + "TARGET_SH1" + "mov.w %1,%0" + [(set_attr "type" "load")]) + (define_insn "*extendqisi2_media" [(set (match_operand:SI 0 "register_operand" "=r,r") (sign_extend:SI (match_operand:QI 1 "general_extend_operand" "r,m")))] @@ -5416,6 +5450,14 @@ label: [(set_attr "type" "sfunc") (set_attr "needs_delay_slot" "yes")]) +(define_expand "movhi" + [(set (match_operand:HI 0 "general_movdst_operand" "") + (match_operand:HI 1 "general_movsrc_operand" ""))] + "" +{ + prepare_move_operands (operands, HImode); +}) + (define_expand "movqi" [(set (match_operand:QI 0 "general_operand" "") (match_operand:QI 1 "general_operand" ""))] @@ -5431,6 +5473,7 @@ label: ;; With the movqi_reg_reg being specified before movqi it will be intially ;; picked to load/store regs. If the regs regs are on the stack reload will ;; try other insns and not stick to movqi_reg_reg. +;; The same applies to the movhi variants. (define_insn "*movqi_reg_reg" [(set (match_operand:QI 0 "arith_reg_dest" "=r,r") (match_operand:QI 1 "register_operand" "r,t"))] @@ -5440,44 +5483,82 @@ label: movt %0" [(set_attr "type" "move,arith")]) +(define_insn "*movhi_reg_reg" + [(set (match_operand:HI 0 "arith_reg_dest" "=r,r") + (match_operand:HI 1 "register_operand" "r,t"))] + "TARGET_SH1" + "@ + mov %1,%0 + movt %0" + [(set_attr "type" "move,arith")]) + ;; FIXME: The non-SH2A and SH2A variants should be combined by adding ;; "enabled" attribute as it is done in other targets. (define_insn "*movqi_store_mem_disp04" [(set (mem:QI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r,r") (match_operand:SI 1 "const_int_operand" "K04,N"))) (match_operand:QI 2 "arith_reg_operand" "z,r"))] - "TARGET_SH1 && CONST_OK_FOR_K04 (INTVAL (operands[1]))" + "TARGET_SH1 && sh_legitimate_index_p (QImode, operands[1], false, true)" "@ mov.b %2,@(%O1,%0) mov.b %2,@%0" [(set_attr "type" "store")]) +(define_insn "*movhi_store_mem_disp05" + [(set (mem:HI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r,r") + (match_operand:SI 1 "const_int_operand" "K05,N"))) + (match_operand:HI 2 "arith_reg_operand" "z,r"))] + "TARGET_SH1 && sh_legitimate_index_p (HImode, operands[1], false, true)" + "@ + mov.w %2,@(%O1,%0) + mov.w %2,@%0" + [(set_attr "type" "store")]) + (define_insn "*movqi_store_mem_disp12" [(set (mem:QI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r") (match_operand:SI 1 "const_int_operand" "K12"))) (match_operand:QI 2 "arith_reg_operand" "r"))] - "TARGET_SH2A && CONST_OK_FOR_K12 (INTVAL (operands[1]))" + "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[1], true, true)" "mov.b %2,@(%O1,%0)" [(set_attr "type" "store") (set_attr "length" "4")]) +(define_insn "*movhi_store_mem_disp13" + [(set (mem:HI (plus:SI (match_operand:SI 0 "arith_reg_operand" "%r") + (match_operand:SI 1 "const_int_operand" "K13"))) + (match_operand:HI 2 "arith_reg_operand" "r"))] + "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[1], true, true)" + "mov.w %2,@(%O1,%0)" + [(set_attr "type" "store") + (set_attr "length" "4")]) + (define_insn "*movqi_load_mem_disp" [(set (match_operand:QI 0 "arith_reg_dest" "=z,r") (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r") (match_operand:SI 2 "const_int_operand" "K04,N"))))] - "TARGET_SH1 && ! TARGET_SH2A && CONST_OK_FOR_K04 (INTVAL (operands[2]))" + "TARGET_SH1 && ! TARGET_SH2A + && sh_legitimate_index_p (QImode, operands[2], false, true)" "@ mov.b @(%O2,%1),%0 mov.b @%1,%0" [(set_attr "type" "load")]) +(define_insn "*movhi_load_mem_disp" + [(set (match_operand:HI 0 "arith_reg_dest" "=z,r") + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r") + (match_operand:SI 2 "const_int_operand" "K05,N"))))] + "TARGET_SH1 && ! TARGET_SH2A + && sh_legitimate_index_p (HImode, operands[2], false, true)" + "@ + mov.w @(%O2,%1),%0 + mov.w @%1,%0" + [(set_attr "type" "load")]) + (define_insn "*movqi_load_mem_disp" [(set (match_operand:QI 0 "arith_reg_dest" "=z,r,r") (mem:QI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r") (match_operand:SI 2 "const_int_operand" "K04,N,K12"))))] - "TARGET_SH2A - && (CONST_OK_FOR_K04 (INTVAL (operands[2])) - || CONST_OK_FOR_K12 (INTVAL (operands[2])))" + "TARGET_SH2A && sh_legitimate_index_p (QImode, operands[2], true, true)" "@ mov.b @(%O2,%1),%0 mov.b @%1,%0 @@ -5485,6 +5566,18 @@ label: [(set_attr "type" "load") (set_attr "length" "2,2,4")]) +(define_insn "*movhi_load_mem_disp" + [(set (match_operand:HI 0 "arith_reg_dest" "=z,r,r") + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "%r,r,r") + (match_operand:SI 2 "const_int_operand" "K05,N,K13"))))] + "TARGET_SH2A && sh_legitimate_index_p (HImode, operands[2], true, true)" + "@ + mov.w @(%O2,%1),%0 + mov.w @%1,%0 + mov.w @(%O2,%1),%0" + [(set_attr "type" "load") + (set_attr "length" "2,2,4")]) + ;; The m constraints basically allow any kind of addresses to be used with any ;; source/target register as the other operand. This is not true for ;; displacement addressing modes on anything but SH2A. That's why the @@ -5503,6 +5596,21 @@ label: lds %1,%0" [(set_attr "type" "movi8,load,store,prget,prset")]) +(define_insn "*movhi" + [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,m,r,l") + (match_operand:HI 1 "general_movsrc_operand" "Q,i,m,r,l,r"))] + "TARGET_SH1 + && (arith_reg_operand (operands[0], HImode) + || arith_reg_operand (operands[1], HImode))" + "@ + mov.w %1,%0 + mov %1,%0 + mov.w %1,%0 + mov.w %1,%0 + sts %1,%0 + lds %1,%0" + [(set_attr "type" "pcload,movi8,load,store,prget,prset")]) + (define_insn "*movqi_media" [(set (match_operand:QI 0 "general_movdst_operand" "=r,r,r,m") (match_operand:QI 1 "general_movsrc_operand" "r,I16Css,m,rZ"))] @@ -5535,28 +5643,6 @@ label: operands[3] = gen_rtx_REG (DImode, REGNO (operands[2])); }) -;; When storing r0, we have to avoid reg+reg addressing. -(define_insn "movhi_i" - [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,r,m,r,l,r") - (match_operand:HI 1 "general_movsrc_operand" "Q,rI08,m,t,r,l,r,i"))] - "TARGET_SH1 - && (arith_reg_operand (operands[0], HImode) - || arith_reg_operand (operands[1], HImode)) - && (!MEM_P (operands[0]) - || GET_CODE (XEXP (operands[0], 0)) != PLUS - || !REG_P (XEXP (XEXP (operands[0], 0), 1)) - || ! refers_to_regno_p (R0_REG, R0_REG + 1, operands[1], (rtx *)0))" - "@ - mov.w %1,%0 - mov %1,%0 - mov.w %1,%0 - movt %0 - mov.w %1,%0 - sts %1,%0 - lds %1,%0 - fake %1,%0" - [(set_attr "type" "pcload,move,load,move,store,move,move,pcload")]) - (define_insn "*movhi_media" [(set (match_operand:HI 0 "general_movdst_operand" "=r,r,r,r,m") (match_operand:HI 1 "general_movsrc_operand" "r,I16Css,n,m,rZ"))] @@ -5582,14 +5668,6 @@ label: && ! satisfies_constraint_I16 (operands[1])" [(set (subreg:DI (match_dup 0) 0) (match_dup 1))]) -(define_expand "movhi" - [(set (match_operand:HI 0 "general_movdst_operand" "") - (match_operand:HI 1 "general_movsrc_operand" ""))] - "" -{ - prepare_move_operands (operands, HImode); -}) - (define_expand "reload_inhi" [(set (match_operand:SI 2 "" "=&r") (match_operand:HI 1 "inqhi_operand" "")) @@ -11538,10 +11616,10 @@ label: ;; Fold sequence: ;; mov #54,r0 -;; mov.b @(r0,r15),r0 +;; mov.{b,w} @(r0,r15),r0 ;; mov r0,r3 ;; into: -;; mov.b @(54,r15),r3 +;; mov.{b,w} @(54,r15),r3 ;; (define_peephole2 [(set (match_operand:SI 0 "arith_reg_dest" "") @@ -11553,17 +11631,33 @@ label: (set (match_operand:QI 4 "arith_reg_dest" "") (match_operand:QI 5 "arith_reg_operand" ""))] "TARGET_SH2A - && CONST_OK_FOR_K12 (INTVAL (operands[1])) + && sh_legitimate_index_p (QImode, operands[1], true, true) && REGNO (operands[2]) == REGNO (operands[5]) && peep2_reg_dead_p (3, operands[5])" [(set (match_dup 4) (mem:QI (plus:SI (match_dup 3) (match_dup 1))))] "") +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (match_operand:SI 2 "arith_reg_dest" "") + (sign_extend:SI + (mem:HI (plus:SI (match_dup 0) + (match_operand:SI 3 "arith_reg_operand" ""))))) + (set (match_operand:HI 4 "arith_reg_dest" "") + (match_operand:HI 5 "arith_reg_operand" ""))] + "TARGET_SH2A + && sh_legitimate_index_p (HImode, operands[1], true, true) + && REGNO (operands[2]) == REGNO (operands[5]) + && peep2_reg_dead_p (3, operands[5])" + [(set (match_dup 4) (mem:HI (plus:SI (match_dup 3) (match_dup 1))))] + "") + ;; Fold sequence: ;; mov #54,r0 -;; mov.b @(r0,r15),r1 +;; mov.{b,w} @(r0,r15),r1 ;; into: -;; mov.b @(54,r15),r1 +;; mov.{b,w} @(54,r15),r1 ;; (define_peephole2 [(set (match_operand:SI 0 "arith_reg_dest" "") @@ -11573,19 +11667,37 @@ label: (mem:QI (plus:SI (match_dup 0) (match_operand:SI 3 "arith_reg_operand" "")))))] "TARGET_SH2A - && CONST_OK_FOR_K12 (INTVAL (operands[1])) + && sh_legitimate_index_p (QImode, operands[1], true, true) && (peep2_reg_dead_p (2, operands[0]) || REGNO (operands[0]) == REGNO (operands[2]))" [(set (match_dup 2) (sign_extend:SI (mem:QI (plus:SI (match_dup 3) (match_dup 1)))))] "") +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest" "") + (match_operand:SI 1 "const_int_operand" "")) + (set (match_operand:SI 2 "arith_reg_dest" "") + (sign_extend:SI + (mem:HI (plus:SI (match_dup 0) + (match_operand:SI 3 "arith_reg_operand" "")))))] + "TARGET_SH2A + && sh_legitimate_index_p (HImode, operands[1], true, true) + && (peep2_reg_dead_p (2, operands[0]) + || REGNO (operands[0]) == REGNO (operands[2]))" + [(set (match_dup 2) + (sign_extend:SI (mem:HI (plus:SI (match_dup 3) (match_dup 1)))))] + "") + ;; Fold sequence: -;; mov.b @(r0,r15),r0 +;; mov.{b,w} @(r0,r15),r0 ;; mov r0,r3 ;; into: -;; mov.b @(r0,r15),r3 +;; mov.{b,w} @(r0,r15),r3 ;; +;; This can happen when initially a displacement address is picked, where +;; the destination reg is fixed to r0, and then the address is transformed +;; into 'r0 + reg'. (define_peephole2 [(set (match_operand:SI 0 "arith_reg_dest" "") (sign_extend:SI @@ -11600,6 +11712,20 @@ label: (mem:QI (plus:SI (match_dup 1) (match_dup 2))))] "") +(define_peephole2 + [(set (match_operand:SI 0 "arith_reg_dest" "") + (sign_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "arith_reg_operand" "") + (match_operand:SI 2 "arith_reg_operand" ""))))) + (set (match_operand:HI 3 "arith_reg_dest" "") + (match_operand:HI 4 "arith_reg_operand" ""))] + "TARGET_SH1 + && REGNO (operands[0]) == REGNO (operands[4]) + && peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 3) + (mem:HI (plus:SI (match_dup 1) (match_dup 2))))] + "") + ;; These convert sequences such as `mov #k,r0; add r15,r0; mov.l @r0,rn' ;; to `mov #k,r0; mov.l @(r0,r15),rn'. These sequences are generated by ;; reload when the constant is too large for a reg+offset address. -- 2.7.4