diff options
author | Oleg Endo <olegendo@gcc.gnu.org> | 2012-08-20 20:54:20 +0000 |
---|---|---|
committer | Oleg Endo <olegendo@gcc.gnu.org> | 2012-08-20 20:54:20 +0000 |
commit | 5592815a885e6101054be5b7fbac7a223b698815 (patch) | |
tree | 1735ecce6bebefc95e794764b6a81b5216e2b0ac /gcc | |
parent | 6774855070fac75d8ea3b4814a3c4a81d23d1811 (diff) | |
download | gcc-5592815a885e6101054be5b7fbac7a223b698815.zip gcc-5592815a885e6101054be5b7fbac7a223b698815.tar.gz gcc-5592815a885e6101054be5b7fbac7a223b698815.tar.bz2 |
re PR rtl-optimization/50489 ([UPC/IA64] mis-schedule of MEM ref with -ftree-vectorize and -fschedule-insns2)
PR target/50489
* config/sh/sh.md (rotcr, *rotcr, shar, shlr): New insns and splits.
(ashrdi3_k, lshrdi3_k): Rewrite as insn_and_split.
* config/sh/sh.c (sh_lshrsi_clobbers_t_reg_p): New function.
* config/sh/sh-protos.h (sh_lshrsi_clobbers_t_reg_p): Declare it.
PR target/50489
* gcc.target/sh/pr54089-1.c: New.
From-SVN: r190545
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/config/sh/sh-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 8 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 146 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr54089-1.c | 83 |
6 files changed, 241 insertions, 10 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 03a2afe..b284ae2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,13 @@ 2012-08-20 Oleg Endo <olegendo@gcc.gnu.org> + PR target/50489 + * config/sh/sh.md (rotcr, *rotcr, shar, shlr): New insns and splits. + (ashrdi3_k, lshrdi3_k): Rewrite as insn_and_split. + * config/sh/sh.c (sh_lshrsi_clobbers_t_reg_p): New function. + * config/sh/sh-protos.h (sh_lshrsi_clobbers_t_reg_p): Declare it. + +2012-08-20 Oleg Endo <olegendo@gcc.gnu.org> + PR target/51244 * config/sh/sh.md (*cset_zero): New insns. diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index db5f975..8cc5cc6 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -74,6 +74,7 @@ extern rtx sh_emit_cheap_store_flag (enum machine_mode, enum rtx_code, rtx, rtx) extern void sh_emit_compare_and_branch (rtx *, enum machine_mode); extern void sh_emit_compare_and_set (rtx *, enum machine_mode); extern bool sh_ashlsi_clobbers_t_reg_p (rtx); +extern bool sh_lshrsi_clobbers_t_reg_p (rtx); extern void gen_shifty_op (int, rtx *); extern void gen_shifty_hi_op (int, rtx *); extern bool expand_ashiftrt (rtx *); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 263ea3a..0760cbc 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -2892,6 +2892,14 @@ sh_ashlsi_clobbers_t_reg_p (rtx shift_amount) & ASHL_CLOBBERS_T) != 0; } +bool +sh_lshrsi_clobbers_t_reg_p (rtx shift_amount) +{ + gcc_assert (CONST_INT_P (shift_amount)); + return (ashl_lshr_seq[INTVAL (shift_amount) & 31].clobbers_t + & LSHR_CLOBBERS_T) != 0; +} + /* Assuming we have a value that has been sign-extended by at least one bit, can we use the ext_shift_amounts with the last shift turned to an arithmetic shift to shift it by N without data loss, and quicker than by other means? */ diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 9a58f8a..d38fd20 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -3827,6 +3827,100 @@ label: FAIL; }) +;; The rotcr insn is used primarily in DImode right shifts (arithmetic +;; and logical). It can also be used to implement things like +;; bool t = a == b; +;; int x = (y >> 1) | (t << 31); +(define_insn "rotcr" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (ior:SI (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") + (const_int 1)) + (ashift:SI (match_operand:SI 2 "t_reg_operand") + (const_int 31)))) + (set (reg:SI T_REG) + (and:SI (match_dup 1) (const_int 1)))] + "TARGET_SH1" + "rotcr %0" + [(set_attr "type" "arith")]) + +;; Simplified rotcr version for combine, which allows arbitrary shift +;; amounts for the reg. If the shift amount is '1' rotcr can be used +;; directly. Otherwise we have to insert a shift in between. +(define_insn_and_split "*rotcr" + [(set (match_operand:SI 0 "arith_reg_dest") + (ior:SI (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand") + (match_operand:SI 2 "const_int_operand")) + (ashift:SI (match_operand:SI 3 "t_reg_operand") + (const_int 31)))) + (clobber (reg:SI T_REG))] + "TARGET_SH1" + "#" + "&& can_create_pseudo_p ()" + [(const_int 0)] +{ + if (INTVAL (operands[2]) > 1) + { + /* use plus_constant function ?? */ + const int shift_count = INTVAL (operands[2]) - 1; + const rtx shift_count_rtx = GEN_INT (shift_count); + rtx shift_res = gen_reg_rtx (SImode); + + rtx prev_set_t_insn = NULL_RTX; + rtx tmp_t_reg = NULL_RTX; + + /* If we're going to emit a shift sequence that clobbers the T_REG, + try to find the previous insn that sets the T_REG and emit the + shift insn before that insn, to remove the T_REG dependency. + If the insn that sets the T_REG cannot be found, store the T_REG + in a temporary reg and restore it after the shift. */ + if (sh_lshrsi_clobbers_t_reg_p (shift_count_rtx) + && ! sh_dynamicalize_shift_p (shift_count_rtx)) + { + prev_set_t_insn = prev_nonnote_insn_bb (curr_insn); + if (! (prev_set_t_insn != NULL_RTX + && reg_set_p (get_t_reg_rtx (), prev_set_t_insn) + && ! reg_referenced_p (get_t_reg_rtx (), + PATTERN (prev_set_t_insn)))) + { + prev_set_t_insn = NULL_RTX; + tmp_t_reg = gen_reg_rtx (SImode); + emit_insn (gen_move_insn (tmp_t_reg, get_t_reg_rtx ())); + } + } + + rtx shift_rtx = gen_lshrsi3 (shift_res, operands[1], shift_count_rtx); + operands[1] = shift_res; + + /* Emit the shift insn before the insn that sets T_REG, if possible. */ + if (prev_set_t_insn != NULL_RTX) + emit_insn_before (shift_rtx, prev_set_t_insn); + else + emit_insn (shift_rtx); + + /* Restore T_REG if it has been saved before. */ + if (tmp_t_reg != NULL_RTX) + emit_insn (gen_cmpgtsi_t (tmp_t_reg, const0_rtx)); + } + + emit_insn (gen_rotcr (operands[0], operands[1], operands[3])); + DONE; +}) + +;; rotcr combine bridge pattern which will make combine try out more +;; complex patterns. +(define_insn_and_split "*rotcr" + [(set (match_operand:SI 0 "arith_reg_dest") + (ashift:SI (match_operand:SI 1 "t_reg_operand") (const_int 31)))] + "TARGET_SH1" + "#" + "&& 1" + [(set (match_dup 0) (match_dup 1)) + (parallel [(set (match_dup 0) + (ior:SI (lshiftrt:SI (match_dup 0) (const_int 1)) + (ashift:SI (match_dup 1) (const_int 31)))) + (set (reg:SI T_REG) + (and:SI (match_dup 0) (const_int 1)))])]) + ;; . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ;; SImode shift left @@ -4146,6 +4240,16 @@ label: FAIL; }) +(define_insn "shar" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") + (const_int 1))) + (set (reg:SI T_REG) + (and:SI (match_dup 1) (const_int 1)))] + "TARGET_SH1" + "shar %0" + [(set_attr "type" "arith")]) + (define_insn "ashrsi3_k" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (ashiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") @@ -4233,16 +4337,22 @@ label: FAIL; }) -;; This should be a define_insn_and_split -(define_insn "ashrdi3_k" +(define_insn_and_split "ashrdi3_k" [(set (match_operand:DI 0 "arith_reg_dest" "=r") (ashiftrt:DI (match_operand:DI 1 "arith_reg_operand" "0") (const_int 1))) (clobber (reg:SI T_REG))] "TARGET_SH1" - "shar %S0\;rotcr %R0" - [(set_attr "length" "4") - (set_attr "type" "arith")]) + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx high = gen_highpart (SImode, operands[0]); + rtx low = gen_lowpart (SImode, operands[0]); + emit_insn (gen_shar (high, high)); + emit_insn (gen_rotcr (low, low, get_t_reg_rtx ())); + DONE; +}) (define_insn "ashrdi3_media" [(set (match_operand:DI 0 "ext_dest_operand" "=r,r") @@ -4322,6 +4432,16 @@ label: "shld %2,%0" [(set_attr "type" "dyn_shift")]) +(define_insn "shlr" + [(set (match_operand:SI 0 "arith_reg_dest" "=r") + (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") + (const_int 1))) + (set (reg:SI T_REG) + (and:SI (match_dup 1) (const_int 1)))] + "TARGET_SH1" + "shlr %0" + [(set_attr "type" "arith")]) + (define_insn "lshrsi3_m" [(set (match_operand:SI 0 "arith_reg_dest" "=r") (lshiftrt:SI (match_operand:SI 1 "arith_reg_operand" "0") @@ -4384,16 +4504,22 @@ label: FAIL; }) -;; This should be a define_insn_and_split -(define_insn "lshrdi3_k" +(define_insn_and_split "lshrdi3_k" [(set (match_operand:DI 0 "arith_reg_dest" "=r") (lshiftrt:DI (match_operand:DI 1 "arith_reg_operand" "0") (const_int 1))) (clobber (reg:SI T_REG))] "TARGET_SH1" - "shlr %S0\;rotcr %R0" - [(set_attr "length" "4") - (set_attr "type" "arith")]) + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx high = gen_highpart (SImode, operands[0]); + rtx low = gen_lowpart (SImode, operands[0]); + emit_insn (gen_shlr (high, high)); + emit_insn (gen_rotcr (low, low, get_t_reg_rtx ())); + DONE; +}) (define_insn "lshrdi3_media" [(set (match_operand:DI 0 "ext_dest_operand" "=r,r") diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ecff56c..0db9e17 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,10 @@ 2012-08-20 Oleg Endo <olegendo@gcc.gnu.org> + PR target/50489 + * gcc.target/sh/pr54089-1.c: New. + +2012-08-20 Oleg Endo <olegendo@gcc.gnu.org> + PR target/51244 * gcc.target/sh/pr51244-11.c: New. diff --git a/gcc/testsuite/gcc.target/sh/pr54089-1.c b/gcc/testsuite/gcc.target/sh/pr54089-1.c new file mode 100644 index 0000000..2101c53 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr54089-1.c @@ -0,0 +1,83 @@ +/* Check that the rotcr instruction is generated. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ +/* { dg-final { scan-assembler-times "rotcr" 11 } } */ + +typedef char bool; + +long long +test_00 (long long a) +{ + return a >> 1; +} + +unsigned int +test_01 (unsigned int a, int b, int c) +{ + bool r = b == c; + return ((a >> 1) | (r << 31)); +} + +unsigned int +test_02 (unsigned int a, int b, int c) +{ + bool r = b == c; + return ((a >> 2) | (r << 31)); +} + +unsigned int +test_03 (unsigned int a, int b, int c) +{ + bool r = b == c; + return ((a >> 3) | (r << 31)); +} + +unsigned int +test_04 (unsigned int a, int b, int c) +{ + bool r = b == c; + return ((a >> 4) | (r << 31)); +} + +unsigned int +test_05 (unsigned int a, int b, int c) +{ + bool r = b == c; + return ((a >> 5) | (r << 31)); +} + +unsigned int +test_06 (unsigned int a, int b, int c) +{ + bool r = b == c; + return ((a >> 6) | (r << 31)); +} + +unsigned int +test_07 (unsigned int a, int b, int c) +{ + bool r = b == c; + return ((a >> 7) | (r << 31)); +} + +unsigned int +test_08 (unsigned int a, int b, int c) +{ + bool r = b == c; + return ((a >> 8) | (r << 31)); +} + +unsigned int +test_09 (unsigned int a, int b, int c) +{ + bool r = b == c; + return ((a >> 31) | (r << 31)); +} + +int +test_10 (int a, int b) +{ + bool r = a == b; + return r << 31; +} |