In the case where the target supports extension instructions, it is preferable to use that instead of doing the same in other ways. For the following case
void foo (unsigned long a, unsigned long* ptr) { ptr[0] = a & 0xffffffffUL; ptr[1] &= 0xffffffffUL; } GCC generates foo: li a5,-1 srli a5,a5,32 and a0,a0,a5 sd a0,0(a1) ld a4,8(a1) and a5,a4,a5 sd a5,8(a1) ret but it will be profitable to generate this one foo: zext.w a0,a0 sd a0,0(a1) lwu a5,8(a1) sd a5,8(a1) ret This patch fixes mentioned issue. It supports HI -> DI, HI->SI and SI -> DI extensions. gcc/ChangeLog: * config/riscv/riscv.md (and<mode>3): New expander. (*and<mode>3) New pattern. * config/riscv/predicates.md (arith_operand_or_mode_mask): New predicate. gcc/testsuite/ChangeLog: * gcc.target/riscv/and-extend-1.c: New test * gcc.target/riscv/and-extend-2.c: New test -- With the best regards Jivan Hakobyan
diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index ffcbb9a7589..70f570153ae 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -27,6 +27,12 @@ (ior (match_operand 0 "const_arith_operand") (match_operand 0 "register_operand"))) +(define_predicate "arith_operand_or_mode_mask" + (ior (match_operand 0 "arith_operand") + (and (match_code "const_int") + (match_test "INTVAL (op) == GET_MODE_MASK (HImode) + || INTVAL (op) == GET_MODE_MASK (SImode)")))) + (define_predicate "lui_operand" (and (match_code "const_int") (match_test "LUI_OPERAND (INTVAL (op))"))) diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 124d8c95804..33336492812 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -1342,9 +1342,46 @@ ;; For RV64, we don't expose the SImode operations to the rtl expanders, ;; but SImode versions exist for combine. +(define_expand "and<mode>3" + [(set (match_operand:X 0 "register_operand") + (and:X (match_operand:X 1 "register_operand") + (match_operand:X 2 "arith_operand_or_mode_mask")))] + "" +{ + if (CONST_INT_P (operands[2])) + { + enum machine_mode tmode = VOIDmode; + if (INTVAL (operands[2]) == GET_MODE_MASK (HImode)) + tmode = HImode; + else if (INTVAL (operands[2]) == GET_MODE_MASK (SImode)) + tmode = SImode; + + if (tmode != VOIDmode) + { + rtx tmp = gen_lowpart (tmode, operands[1]); + emit_insn (gen_extend_insn (operands[0], tmp, <MODE>mode, tmode, 1)); + DONE; + } + } + else + { + emit_move_insn (operands[0], gen_rtx_AND (<MODE>mode, operands[1], operands[2])); + DONE; + } +}) + +(define_insn "*and<mode>3" + [(set (match_operand:X 0 "register_operand" "=r,r") + (and:X (match_operand:X 1 "register_operand" "%r,r") + (match_operand:X 2 "arith_operand" " r,I")))] + "" + "and%i2\t%0,%1,%2" + [(set_attr "type" "logical") + (set_attr "mode" "<MODE>")]) + (define_insn "<optab><mode>3" [(set (match_operand:X 0 "register_operand" "=r,r") - (any_bitwise:X (match_operand:X 1 "register_operand" "%r,r") + (any_or:X (match_operand:X 1 "register_operand" "%r,r") (match_operand:X 2 "arith_operand" " r,I")))] "" "<insn>%i2\t%0,%1,%2" diff --git a/gcc/testsuite/gcc.target/riscv/and-extend-1.c b/gcc/testsuite/gcc.target/riscv/and-extend-1.c new file mode 100644 index 00000000000..a270d287374 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/and-extend-1.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zba_zbb -mabi=lp64" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +void +foo(unsigned long a, unsigned long* ptr) +{ + ptr[0] = a & 0xffffffffUL; + ptr[1] &= 0xffffffffUL; +} + +void +foo2(unsigned long a, unsigned long* ptr) +{ + ptr[0] = a & 0xffff; + ptr[1] &= 0xffff; +} + +void +foo3(unsigned int a, unsigned int* ptr) +{ + ptr[0] = a & 0xffff; + ptr[1] &= 0xffff; +} + +/* { dg-final { scan-assembler-times "zext.w" 1 } } */ +/* { dg-final { scan-assembler-times "zext.h" 2 } } */ +/* { dg-final { scan-assembler-times "lwu" 1 } } */ +/* { dg-final { scan-assembler-times "lhu" 2 } } */ +/* { dg-final { scan-assembler-not "and\t" } } */ diff --git a/gcc/testsuite/gcc.target/riscv/and-extend-2.c b/gcc/testsuite/gcc.target/riscv/and-extend-2.c new file mode 100644 index 00000000000..fe639cd1e82 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/and-extend-2.c @@ -0,0 +1,28 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv32gc_zba_zbb -mabi=ilp32" } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } } */ + +void +foo(unsigned long a, unsigned long* ptr) +{ + ptr[0] = a & 0xffffffffUL; + ptr[1] &= 0xffffffffUL; +} + +void +foo2(unsigned long a, unsigned long* ptr) +{ + ptr[0] = a & 0xffff; + ptr[1] &= 0xffff; +} + +void +foo3(unsigned int a, unsigned int* ptr) +{ + ptr[0] = a & 0xffff; + ptr[1] &= 0xffff; +} + +/* { dg-final { scan-assembler-times "zext.h" 2 } } */ +/* { dg-final { scan-assembler-times "lhu" 2 } } */ +/* { dg-final { scan-assembler-not "and\t" } } */