diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 5a8c4361784..75ec87b8851 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -3271,6 +3271,25 @@ operands[3] = get_t_reg_rtx (); }) +(define_insn_and_split "*rotcl" + [(set (match_operand:SI 0 "arith_reg_dest") + (xor:SI (rotate:SI (match_operand:SI 1 "arith_reg_operand") + (const_int 1)) + (const_int 1))) + (clobber (reg:SI T_REG))] + "TARGET_SH1 && can_create_pseudo_p ()" + "#" + "&& 1" + [(parallel [(set (match_dup 0) + (ior:SI (ashift:SI (match_dup 1) (const_int 1)) + (and:SI (match_dup 3) (const_int 1)))) + (clobber (reg:SI T_REG))])] +{ + rtx t = gen_rtx_GE (SImode, operands[1], const0_rtx); + sh_split_treg_set_expr (t, curr_insn); + operands[3] = get_t_reg_rtx (); +}) + (define_insn_and_split "*rotcl" [(set (match_operand:SI 0 "arith_reg_dest") (ior:SI (and:SI (match_operand:SI 1 "arith_reg_or_t_reg_operand") diff --git a/gcc/match.pd b/gcc/match.pd index f73f66d19a9..492d88514fc 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -12172,3 +12172,27 @@ and, (simplify (IFN_VEC_SHL_INSERT (vec_duplicate@1 @0) @0) @1) + +/* In this case the XOR flips bits that originate from the result of the + right shift and do not impact the result of the left shift. We can + reassociate the XOR to work on the final result and simplify the rest + to a rotate. */ +(simplify + (bit_ior:c (lshift @0 INTEGER_CST@1) + (bit_xor (rshift @2 INTEGER_CST@3) INTEGER_CST@4)) + (if (((~((HOST_WIDE_INT_1U << tree_to_uhwi (@1)) - 1)) & tree_to_uhwi (@4)) == 0 + && (tree_to_uhwi (@1) + tree_to_uhwi (@3)) == TYPE_PRECISION (type) + && TYPE_UNSIGNED (type) + && @0 == @2) + (bit_xor (rrotate @0 @3) @4))) + +/* Similarly, but in this case the XOR flips bits that originate from the + result of the left shift. */ +(simplify + (bit_ior:c (bit_xor (lshift @0 INTEGER_CST@1) INTEGER_CST@2) + (rshift @3 INTEGER_CST@4)) + (if ((((((HOST_WIDE_INT_1U << tree_to_uhwi (@1)) - 1)) & tree_to_uhwi (@2)) == 0) + && (tree_to_uhwi (@1) + tree_to_uhwi (@4)) == TYPE_PRECISION (type) + && TYPE_UNSIGNED (type) + && @0 == @3) + (bit_xor (rrotate @0 @4) @2))) diff --git a/gcc/testsuite/gcc.target/riscv/pr121778.c b/gcc/testsuite/gcc.target/riscv/pr121778.c new file mode 100644 index 00000000000..87da9c3cd96 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr121778.c @@ -0,0 +1,94 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=rv64gcb -mabi=lp64d" { target rv64} } */ +/* { dg-options "-O2 -march=rv32gcb -mabi=ilp32" { target rv32} } */ + +/* We need to adjust the constant so this works for rv32 and rv64. */ +#if __riscv_xlen == 32 +#define ONE 1U +#define TYPE unsigned int +#else +#define ONE 1UL +#define TYPE unsigned long +#endif + +#define F1(C) TYPE test_01##C (TYPE a) { return (a << (__riscv_xlen - C)) | ((a >> C) ^ 1); } +#define F2(C) TYPE test_02##C (TYPE a) { return ((a >> (__riscv_xlen - C)) ^ 1) | (a << C); } +#define F3(C) TYPE test_03##C (TYPE a) { return ((a << (__riscv_xlen - C)) ^ (ONE << (__riscv_xlen - 1))) | (a >> C); } +#define F4(C) TYPE test_04##C (TYPE a) { return (a >> (__riscv_xlen - C)) | ((a << C) ^ (ONE << (__riscv_xlen - 1))); } + +#define F(C) F1(C) F2(C) F3(C) F4(C) + + +F (1) +F (2) +F (3) +F (4) +F (5) +F (6) +F (7) +F (8) +F (9) +F (10) +F (11) +F (12) +F (13) +F (14) +F (15) +F (16) +F (17) +F (18) +F (19) +F (20) +F (21) +F (22) +F (23) +F (24) +F (25) +F (26) +F (27) +F (28) +F (29) +F (30) +F (31) +#if __riscv_xlen == 64 +F (32) +F (33) +F (34) +F (35) +F (36) +F (37) +F (38) +F (39) +F (40) +F (41) +F (42) +F (43) +F (44) +F (45) +F (46) +F (47) +F (48) +F (49) +F (50) +F (51) +F (52) +F (53) +F (54) +F (55) +F (56) +F (57) +F (58) +F (59) +F (60) +F (61) +F (62) +F (63) + +/* { dg-final { scan-assembler-times "\trori" 252 { target { rv64 } } } } */ +/* { dg-final { scan-assembler-times "\txori" 126 { target { rv64 } } } } */ +/* { dg-final { scan-assembler-times "\tbinv" 126 { target { rv64 } } } } */ + +/* { dg-final { scan-assembler-times "\trori" 124 { target { rv32 } } } } */ +/* { dg-final { scan-assembler-times "\txori" 62 { target { rv32 } } } } */ +/* { dg-final { scan-assembler-times "\tbinv" 62 { target { rv32 } } } } */ +#endif