avoid splitting small constants in bcrli_nottwobits patterns

I have noticed that in the case when we try to clear two bits through a
small constant,
and ZBS is enabled then GCC split it into two "andi" instructions.
For example for the following C code:
  int foo(int a) {
    return a & ~ 0x101;
  }

GCC generates the following:
  foo:
     andi a0,a0,-2
     andi a0,a0,-257
     ret

but should be this one:
  foo:
     andi a0,a0,-258
     ret

This patch solves the mentioned issue.

gcc/ChangeLog
	* config/riscv/bitmanip.md: Updated predicates of bclri<mode>_nottwobits
	and bclridisi_nottwobits patterns.
	* config/riscv/predicates.md: (not_uimm_extra_bit_or_nottwobits): Adjust
	predicate to avoid splitting arith constants.
	(const_nottwobits_not_arith_operand): New predicate.

gcc/testsuite
	* gcc.target/riscv/zbs-bclri-nottwobits.c: New test.
This commit is contained in:
Jivan Hakobyan 2023-04-25 20:41:02 -06:00 committed by Jeff Law
parent 68201409bc
commit 392200f807
3 changed files with 22 additions and 3 deletions

View file

@ -508,7 +508,7 @@
(define_insn_and_split "*bclri<mode>_nottwobits"
[(set (match_operand:X 0 "register_operand" "=r")
(and:X (match_operand:X 1 "register_operand" "r")
(match_operand:X 2 "const_nottwobits_operand" "i")))]
(match_operand:X 2 "const_nottwobits_not_arith_operand" "i")))]
"TARGET_ZBS && !paradoxical_subreg_p (operands[1])"
"#"
"&& reload_completed"
@ -527,7 +527,7 @@
(define_insn_and_split "*bclridisi_nottwobits"
[(set (match_operand:DI 0 "register_operand" "=r")
(and:DI (match_operand:DI 1 "register_operand" "r")
(match_operand:DI 2 "const_nottwobits_operand" "i")))]
(match_operand:DI 2 "const_nottwobits_not_arith_operand" "i")))]
"TARGET_64BIT && TARGET_ZBS
&& clz_hwi (~UINTVAL (operands[2])) > 33"
"#"

View file

@ -366,6 +366,11 @@
(and (match_code "const_int")
(match_test "popcount_hwi (~UINTVAL (op)) == 2")))
(define_predicate "const_nottwobits_not_arith_operand"
(and (match_code "const_int")
(and (not (match_operand 0 "arith_operand"))
(match_operand 0 "const_nottwobits_operand"))))
;; A CONST_INT operand that consists of a single run of 32 consecutive
;; set bits.
(define_predicate "consecutive_bits32_operand"
@ -411,4 +416,4 @@
(define_predicate "not_uimm_extra_bit_or_nottwobits"
(and (match_code "const_int")
(ior (match_operand 0 "not_uimm_extra_bit_operand")
(match_operand 0 "const_nottwobits_operand"))))
(match_operand 0 "const_nottwobits_not_arith_operand"))))

View file

@ -0,0 +1,14 @@
/* { dg-do compile } */
/* { dg-options "-march=rv64gc_zbs -mabi=lp64" } */
/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
int and_two_bit(int idx) {
return idx & ~3;
}
int and_bclr_two_bit(int idx) {
return idx & ~(0x4001);
}
/* { dg-final { scan-assembler-times "\tandi\t" 2 } } */
/* { dg-final { scan-assembler-times "\tbclri\t" 1 } } */