diff options
author | Oleg Endo <olegendo@gcc.gnu.org> | 2016-05-06 09:52:35 +0000 |
---|---|---|
committer | Oleg Endo <olegendo@gcc.gnu.org> | 2016-05-06 09:52:35 +0000 |
commit | 765d7b5470cbf6e46d1982726e44c962d9c6516c (patch) | |
tree | 321e082db475892c24122dedc28a608744f1f8f8 /gcc/config/sh | |
parent | 29c94e65e1be846e8a71a3d24450c4cf1d1d5b41 (diff) | |
download | gcc-765d7b5470cbf6e46d1982726e44c962d9c6516c.zip gcc-765d7b5470cbf6e46d1982726e44c962d9c6516c.tar.gz gcc-765d7b5470cbf6e46d1982726e44c962d9c6516c.tar.bz2 |
re PR target/52933 (SH Target: Use div0s for integer sign comparisons)
gcc/
PR target/52933
* config/sh/sh.md (*cmp_div0s_7, *cmp_div0s_8): Add div0s variants.
* config/sh/sh.c (sh_rtx_costs): Add another div0s case.
gcc/testsuite/
PR target/52933
* gcc.target/sh/pr52933-1.c (test_31, test_32, test_33, test_34,
test_35, test_36, test_37, test_38, test_39, test_40): New sub-tests.
Adjust expected instruction counts.
* gcc.target/sh/pr52933-2.c: Adjust expected instruction counts.
From-SVN: r235952
Diffstat (limited to 'gcc/config/sh')
-rw-r--r-- | gcc/config/sh/sh.c | 9 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 91 |
2 files changed, 100 insertions, 0 deletions
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index ebdb523..809f679 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -3209,6 +3209,15 @@ sh_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED, int outer_code, *total = 1; //COSTS_N_INSNS (1); return true; } + + /* div0s variant. */ + if (GET_CODE (XEXP (x, 0)) == XOR + && GET_CODE (XEXP (XEXP (x, 0), 0)) == XOR + && CONST_INT_P (XEXP (XEXP (x, 0), 1))) + { + *total = 1; + return true; + } return false; /* The cost of a sign or zero extend depends on whether the source is a diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 0ab76b5..e704e2a 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -1103,6 +1103,97 @@ (lshiftrt:SI (xor:SI (match_dup 0) (match_dup 1)) (const_int 31))) (set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))]) +;; In some cases, it might be shorter to get a tested bit into bit 31 and +;; use div0s. Otherwise it's usually better to just leave the xor and tst +;; sequence. The only thing we can try to do here is avoiding the large +;; tst constant. +(define_insn_and_split "*cmp_div0s_7" + [(set (reg:SI T_REG) + (zero_extract:SI (xor:SI (match_operand:SI 0 "arith_reg_operand") + (match_operand:SI 1 "arith_reg_operand")) + (const_int 1) + (match_operand 2 "const_int_operand")))] + "TARGET_SH1 && can_create_pseudo_p () + && (INTVAL (operands[2]) == 7 || INTVAL (operands[2]) == 15 + || INTVAL (operands[2]) == 23 || INTVAL (operands[2]) == 29 + || INTVAL (operands[2]) == 30 || INTVAL (operands[2]) == 31)" + "#" + "&& 1" + [(const_int 0)] +{ + const int bitpos = INTVAL (operands[2]); + + rtx op0 = gen_reg_rtx (SImode); + rtx op1 = gen_reg_rtx (SImode); + + if (bitpos == 23 || bitpos == 30 || bitpos == 29) + { + emit_insn (gen_ashlsi3 (op0, operands[0], GEN_INT (31 - bitpos))); + emit_insn (gen_ashlsi3 (op1, operands[1], GEN_INT (31 - bitpos))); + } + else if (bitpos == 15) + { + emit_insn (gen_extendhisi2 (op0, gen_lowpart (HImode, operands[0]))); + emit_insn (gen_extendhisi2 (op1, gen_lowpart (HImode, operands[1]))); + } + else if (bitpos == 7) + { + emit_insn (gen_extendqisi2 (op0, gen_lowpart (QImode, operands[0]))); + emit_insn (gen_extendqisi2 (op1, gen_lowpart (QImode, operands[1]))); + } + else if (bitpos == 31) + { + op0 = operands[0]; + op1 = operands[1]; + } + else + gcc_unreachable (); + + emit_insn (gen_cmp_div0s (op0, op1)); + DONE; +}) + +;; For bits 0..7 using a xor and tst #imm,r0 sequence seems to be better. +;; Thus allow the following patterns only for higher bit positions where +;; we it's more likely to save the large tst constant. +(define_insn_and_split "*cmp_div0s_8" + [(set (reg:SI T_REG) + (eq:SI (zero_extract:SI (match_operand:SI 0 "arith_reg_operand") + (const_int 1) + (match_operand 2 "const_int_operand")) + (zero_extract:SI (match_operand:SI 1 "arith_reg_operand") + (const_int 1) + (match_dup 2))))] + "TARGET_SH1 && can_create_pseudo_p () + && (INTVAL (operands[2]) == 15 + || INTVAL (operands[2]) == 23 || INTVAL (operands[2]) == 29 + || INTVAL (operands[2]) == 30 || INTVAL (operands[2]) == 31)" + "#" + "&& 1" + [(set (reg:SI T_REG) + (zero_extract:SI (xor:SI (match_dup 0) (match_dup 1)) + (const_int 1) (match_dup 2))) + (set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))]) + +(define_insn_and_split "*cmp_div0s_9" + [(set (reg:SI T_REG) + (zero_extract:SI (xor:SI (xor:SI (match_operand:SI 0 "arith_reg_operand") + (match_operand:SI 1 "arith_reg_operand")) + (match_operand 2 "const_int_operand")) + (const_int 1) + (match_operand 3 "const_int_operand")))] + "TARGET_SH1 && can_create_pseudo_p () + && (INTVAL (operands[2]) & 0xFFFFFFFF) == (1U << INTVAL (operands[3])) + && (INTVAL (operands[3]) == 15 + || INTVAL (operands[3]) == 23 || INTVAL (operands[3]) == 29 + || INTVAL (operands[3]) == 30 || INTVAL (operands[3]) == 31)" + "#" + "&& 1" + [(set (reg:SI T_REG) + (zero_extract:SI (xor:SI (match_dup 0) (match_dup 1)) + (const_int 1) (match_dup 3))) + (set (reg:SI T_REG) (xor:SI (reg:SI T_REG) (const_int 1)))]) + ;; ------------------------------------------------------------------------- ;; SImode compare and branch ;; ------------------------------------------------------------------------- |