From: Uros Bizjak Date: Mon, 4 May 2020 11:49:14 +0000 (+0200) Subject: i386: Use SHR to compare with large power-of-two constants [PR94650] X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8ea03e9016cbca5a7ee2b4befa4d5c32467b0982;p=gcc.git i386: Use SHR to compare with large power-of-two constants [PR94650] Convert unsigned compares where m >= LARGE_POWER_OF_TWO and LARGE_POWER_OF_TWO represent an immediate where bit 33+ is set to use a SHR instruction and compare the result to 0. This avoids loading a large immediate with MOVABS insn. movabsq $1099511627775, %rax cmpq %rax, %rdi ja .L5 gets converted to: shrq $40, %rdi jne .L5 PR target/94650 * config/i386/predicates.md (shr_comparison_operator): New predicate. * config/i386/i386.md (compare->shr splitter): New splitters. testsuite/ChangeLog: PR target/94650 * gcc.targeti/i386/pr94650.c: New test. --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fae7ece376a..a549d453731 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2020-05-04 Uroš Bizjak + + PR target/94650 + * config/i386/predicates.md (shr_comparison_operator): New predicate. + * config/i386/i386.md (compare->shr splitter): New splitters. + 2020-05-04 Jakub Jelinek PR tree-optimization/94718 diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 6f3ac3ad555..bd144ab3d5e 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -12310,6 +12310,36 @@ ;; Store-flag instructions. +(define_split + [(set (match_operand:QI 0 "nonimmediate_operand") + (match_operator:QI 1 "shr_comparison_operator" + [(match_operand:DI 2 "register_operand") + (match_operand 3 "const_int_operand")]))] + "TARGET_64BIT + && IN_RANGE (exact_log2 (UINTVAL (operands[3]) + 1), 32, 63)" + [(parallel + [(set (reg:CCZ FLAGS_REG) + (compare:CCZ + (lshiftrt:DI (match_dup 2) (match_dup 4)) + (const_int 0))) + (clobber (scratch:DI))]) + (set (match_dup 0) + (match_op_dup 1 [(reg:CCZ FLAGS_REG) (const_int 0)]))] +{ + enum rtx_code new_code; + + operands[1] = shallow_copy_rtx (operands[1]); + switch (GET_CODE (operands[1])) + { + case GTU: new_code = NE; break; + case LEU: new_code = EQ; break; + default: gcc_unreachable (); + } + PUT_CODE (operands[1], new_code); + + operands[4] = GEN_INT (exact_log2 (UINTVAL (operands[3]) + 1)); +}) + ;; For all sCOND expanders, also expand the compare or test insn that ;; generates cc0. Generate an equality comparison if `seq' or `sne'. @@ -12473,6 +12503,42 @@ (set_attr "mode" "")]) ;; Basic conditional jump instructions. + +(define_split + [(set (pc) + (if_then_else + (match_operator 1 "shr_comparison_operator" + [(match_operand:DI 2 "register_operand") + (match_operand 3 "const_int_operand")]) + (label_ref (match_operand 0)) + (pc)))] + "TARGET_64BIT + && IN_RANGE (exact_log2 (UINTVAL (operands[3]) + 1), 32, 63)" + [(parallel + [(set (reg:CCZ FLAGS_REG) + (compare:CCZ + (lshiftrt:DI (match_dup 2) (match_dup 4)) + (const_int 0))) + (clobber (scratch:DI))]) + (set (pc) + (if_then_else (match_op_dup 1 [(reg:CCZ FLAGS_REG) (const_int 0)]) + (label_ref (match_operand 0)) + (pc)))] +{ + enum rtx_code new_code; + + operands[1] = shallow_copy_rtx (operands[1]); + switch (GET_CODE (operands[1])) + { + case GTU: new_code = NE; break; + case LEU: new_code = EQ; break; + default: gcc_unreachable (); + } + PUT_CODE (operands[1], new_code); + + operands[4] = GEN_INT (exact_log2 (UINTVAL (operands[3]) + 1)); +}) + ;; We ignore the overflow flag for signed branch instructions. (define_insn "*jcc" diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index 71f4cb1193c..1a5e2210eca 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -1290,6 +1290,9 @@ (define_predicate "bt_comparison_operator" (match_code "ne,eq")) +(define_predicate "shr_comparison_operator" + (match_code "gtu,leu")) + ;; Return true if OP is a valid comparison operator in valid mode. (define_predicate "ix86_comparison_operator" (match_operand 0 "comparison_operator") diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 2fedff399fb..bbdd51a33f9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2020-05-04 Uroš Bizjak + + PR target/94650 + * gcc.targeti/i386/pr94650.c: New test. + 2020-05-04 Jakub Jelinek PR tree-optimization/94718 diff --git a/gcc/testsuite/gcc.target/i386/pr94650.c b/gcc/testsuite/gcc.target/i386/pr94650.c new file mode 100644 index 00000000000..49d8b6e7f8c --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr94650.c @@ -0,0 +1,30 @@ +/* PR target/94650 */ +/* { dg-do compile { target { ! ia32 } } } */ +/* { dg-options "-O2" } */ + +#define LARGE_POWER_OF_TWO (1ULL << 40) + +int +check (unsigned long long m) +{ + return m >= LARGE_POWER_OF_TWO; +} + +void g (int); + +void +test0 (unsigned long long m) +{ + if (m >= LARGE_POWER_OF_TWO) + g (0); +} + +void +test1 (unsigned long long m) +{ + if (m >= LARGE_POWER_OF_TWO) + g (m); +} + +/* { dg-final { scan-assembler-not "movabs" } } */ +/* { dg-final { scan-assembler-times "shr" 3 } } */