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 | |
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')
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 9 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 91 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr52933-1.c | 78 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr52933-2.c | 6 |
6 files changed, 192 insertions, 6 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1c6c42c..b575931 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2016-05-06 Oleg Endo <olegendo@gcc.gnu.org> + + 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. + 2016-05-06 Marek Polacek <polacek@redhat.com> PR sanitizer/70875 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 ;; ------------------------------------------------------------------------- diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index aaf3e00..762c2a8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2016-05-06 Oleg Endo <olegendo@gcc.gnu.org> + + 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. + 2016-05-06 Marek Polacek <polacek@redhat.com> PR sanitizer/70875 diff --git a/gcc/testsuite/gcc.target/sh/pr52933-1.c b/gcc/testsuite/gcc.target/sh/pr52933-1.c index 138de7f..81aa94f 100644 --- a/gcc/testsuite/gcc.target/sh/pr52933-1.c +++ b/gcc/testsuite/gcc.target/sh/pr52933-1.c @@ -4,13 +4,13 @@ logic usually show up as redundant tst insns. */ /* { dg-do compile } */ /* { dg-options "-O2" } */ -/* { dg-final { scan-assembler-times "div0s" 32 } } */ +/* { dg-final { scan-assembler-times "div0s" 42 } } */ /* { dg-final { scan-assembler-not "tst" } } */ /* { dg-final { scan-assembler-not "not\t" } } */ /* { dg-final { scan-assembler-not "nott" } } */ -/* { dg-final { scan-assembler-times "negc" 9 { target { ! sh2a } } } } */ -/* { dg-final { scan-assembler-times "movrt" 9 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "negc" 10 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "movrt" 10 { target { sh2a } } } } */ typedef unsigned char bool; @@ -212,3 +212,75 @@ test_30 (int a, int b) { return ((a >> 31) ^ (b >> 31)) & 1; } + +// ------------------------------------------------------- + +bool +test_31 (int a, int b) +{ + /* 2x exts.w, div0s */ + return ((a & 0x8000) ^ (b & 0x8000)) != 0; +} + +bool +test_32 (int a, int b) +{ + /* 2x exts.w, div0s */ + return (a & 0x8000) != (b & 0x8000); +} + +bool +test_33 (int a, int b) +{ + /* 2x add/shll, div0s */ + return ((a & (1<<30)) ^ (b & (1<<30))) != 0; +} + +bool +test_34 (int a, int b) +{ + /* 2x exts.b, div0s */ + return (a & 0x80) != (b & 0x80); +} + +bool +test_35 (signed char a, signed char b) +{ + /* 2x exts.b, div0s */ + return (a < 0) != (b < 0); +} + +bool +test_36 (short a, short b) +{ + /* 2x exts.w, div0s */ + return (a < 0) != (b < 0); +} + +int +test_37 (short a, short b) +{ + /* 2x exts.w, div0s */ + return (a < 0) != (b < 0) ? 40 : -10; +} + +bool +test_38 (int a, int b) +{ + /* 2x shll8, div0s */ + return ((a & (1<<23)) ^ (b & (1<<23))) != 0; +} + +bool +test_39 (int a, int b) +{ + /* 2x shll2, div0s */ + return ((a & (1<<29)) ^ (b & (1<<29))) != 0; +} + +bool +test_40 (short a, short b) +{ + /* 2x exts.w, div0s, negc */ + return (a < 0) == (b < 0); +} diff --git a/gcc/testsuite/gcc.target/sh/pr52933-2.c b/gcc/testsuite/gcc.target/sh/pr52933-2.c index 4637f0e..2b5d09a 100644 --- a/gcc/testsuite/gcc.target/sh/pr52933-2.c +++ b/gcc/testsuite/gcc.target/sh/pr52933-2.c @@ -5,12 +5,12 @@ logic usually show up as redundant tst insns. */ /* { dg-do compile } */ /* { dg-options "-O2 -mpretend-cmove" } */ -/* { dg-final { scan-assembler-times "div0s" 32 } } */ +/* { dg-final { scan-assembler-times "div0s" 42 } } */ /* { dg-final { scan-assembler-not "tst" } } */ /* { dg-final { scan-assembler-not "not\t" } } */ /* { dg-final { scan-assembler-not "nott" } } */ -/* { dg-final { scan-assembler-times "negc" 9 { target { ! sh2a } } } } */ -/* { dg-final { scan-assembler-times "movrt" 9 { target { sh2a } } } } */ +/* { dg-final { scan-assembler-times "negc" 10 { target { ! sh2a } } } } */ +/* { dg-final { scan-assembler-times "movrt" 10 { target { sh2a } } } } */ #include "pr52933-1.c" |