diff options
author | Dimitar Dimitrov <dimitar@dinux.eu> | 2023-11-19 12:20:08 +0200 |
---|---|---|
committer | Dimitar Dimitrov <dimitar@dinux.eu> | 2024-05-07 10:17:27 +0300 |
commit | 47b757cf31fffb2ae5fdb93f9f031890080504a8 (patch) | |
tree | ec44b2c0228b6ff7b84c529d92dc1d985c1705f2 | |
parent | ca7d6d729183685279a0d9dcd39aed11021f1dfa (diff) | |
download | gcc-47b757cf31fffb2ae5fdb93f9f031890080504a8.zip gcc-47b757cf31fffb2ae5fdb93f9f031890080504a8.tar.gz gcc-47b757cf31fffb2ae5fdb93f9f031890080504a8.tar.bz2 |
pru: Optimize the extzv and insv patterns
Optimize the generated code for the bit-field extract and insert
patterns:
- Use bit-set and bit-clear instructions for 1-bit fields.
- Expand to SImode operations instead of relying on the default
expansion to word (QI) mode.
gcc/ChangeLog:
* config/pru/pru.md (extzv<mode>): Make it an expand pattern,
handle efficiently zero-positioned bit-fields.
(insv<mode>): New expand pattern.
gcc/testsuite/ChangeLog:
* gcc.target/pru/ashiftrt.c: Minor update due to new (but
equivalent) generated code sequence.
* gcc.target/pru/extzv-1.c: New test.
* gcc.target/pru/extzv-2.c: New test.
* gcc.target/pru/extzv-3.c: New test.
* gcc.target/pru/insv-1.c: New test.
* gcc.target/pru/insv-2.c: New test.
* gcc.target/pru/insv-3.c: New test.
* gcc.target/pru/insv-4.c: New test.
Signed-off-by: Dimitar Dimitrov <dimitar@dinux.eu>
-rw-r--r-- | gcc/config/pru/pru.md | 104 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/pru/ashiftrt.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/pru/extzv-1.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/pru/extzv-2.c | 15 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/pru/extzv-3.c | 13 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/pru/insv-1.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/pru/insv-2.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/pru/insv-3.c | 14 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/pru/insv-4.c | 14 |
9 files changed, 194 insertions, 10 deletions
diff --git a/gcc/config/pru/pru.md b/gcc/config/pru/pru.md index 0123952..2ceea2e 100644 --- a/gcc/config/pru/pru.md +++ b/gcc/config/pru/pru.md @@ -486,22 +486,108 @@ }) ;; Bit extraction -;; We define it solely to allow combine to choose SImode +;; One reason to define it is to allow combine to choose SImode ;; for word mode when trying to match our cbranch_qbbx_* insn. ;; ;; Check how combine.cc:make_extraction() uses ;; get_best_reg_extraction_insn() to select the op size. -(define_insn "extzv<mode>" - [(set (match_operand:QISI 0 "register_operand" "=r") +(define_expand "extzv<mode>" + [(set (match_operand:QISI 0 "register_operand") (zero_extract:QISI - (match_operand:QISI 1 "register_operand" "r") - (match_operand:QISI 2 "const_int_operand" "i") - (match_operand:QISI 3 "const_int_operand" "i")))] + (match_operand:QISI 1 "register_operand") + (match_operand:QISI 2 "const_int_operand") + (match_operand:QISI 3 "const_int_operand")))] "" - "lsl\\t%0, %1, (%S0 * 8 - %2 - %3)\;lsr\\t%0, %0, (%S0 * 8 - %2)" - [(set_attr "type" "complex") - (set_attr "length" "8")]) +{ + const int nbits = INTVAL (operands[2]); + const int bitpos = INTVAL (operands[3]); + const int trailing_bits = GET_MODE_BITSIZE (<MODE>mode) - nbits - bitpos; + + if (bitpos == 0 && nbits <= 7) + { + emit_insn (gen_and<mode>3 (operands[0], + operands[1], + gen_int_mode ((HOST_WIDE_INT_1U << nbits) - 1, + <MODE>mode))); + DONE; + } + + rtx src = operands[1]; + if (trailing_bits != 0) + { + emit_insn (gen_ashl<mode>3 (operands[0], + operands[1], + GEN_INT (trailing_bits))); + src = operands[0]; + } + emit_insn (gen_lshr<mode>3 (operands[0], + src, + GEN_INT (trailing_bits + bitpos))); + DONE; +}) + +;; Bit-field insert. +(define_expand "insv<mode>" + [(set (zero_extract:QISI + (match_operand:QISI 0 "register_operand") + (match_operand:QISI 1 "const_int_operand") + (match_operand:QISI 2 "const_int_operand")) + (match_operand:QISI 3 "reg_or_ubyte_operand"))] + "" +{ + const int nbits = INTVAL (operands[1]); + const int bitpos = INTVAL (operands[2]); + if (nbits == 1) + { + rtx j; + rtx src = gen_reg_rtx (<MODE>mode); + rtx dst = operands[0]; + + emit_move_insn (src, operands[3]); + + emit_insn (gen_and<mode>3 (dst, + dst, + gen_int_mode (~(HOST_WIDE_INT_1U << bitpos), + <MODE>mode))); + + rtx_code_label *skip_set_label = gen_label_rtx (); + j = emit_jump_insn (gen_cbranch_qbbx_eq<mode><mode><mode>4 ( + src, + GEN_INT (0), + skip_set_label)); + JUMP_LABEL (j) = skip_set_label; + LABEL_NUSES (skip_set_label)++; + + emit_insn (gen_ior<mode>3 (dst, + dst, + gen_int_mode (HOST_WIDE_INT_1U << bitpos, + <MODE>mode))); + emit_label (skip_set_label); + + DONE; + } + + /* Explicitly expand in order to avoid using word_mode for PRU, and instead + use SI and HI modes as applicable. */ + rtx dst = operands[0]; + rtx src = gen_reg_rtx (<MODE>mode); + emit_insn (gen_and<mode>3 (src, + force_reg (<MODE>mode, operands[3]), + gen_int_mode ((HOST_WIDE_INT_1U << nbits) - 1, + <MODE>mode))); + if (bitpos > 0) + emit_insn (gen_ashl<mode>3 (src, src, gen_int_mode (bitpos, <MODE>mode))); + + HOST_WIDE_INT vmask = ~(((HOST_WIDE_INT_1U << nbits) - 1) << bitpos); + emit_insn (gen_and<mode>3 (dst, + dst, + gen_int_mode (vmask, <MODE>mode))); + + emit_insn (gen_ior<mode>3 (dst, dst, src)); + + DONE; +}) ;; Arithmetic Operations diff --git a/gcc/testsuite/gcc.target/pru/ashiftrt.c b/gcc/testsuite/gcc.target/pru/ashiftrt.c index ee8d55d..fb8e475 100644 --- a/gcc/testsuite/gcc.target/pru/ashiftrt.c +++ b/gcc/testsuite/gcc.target/pru/ashiftrt.c @@ -8,6 +8,6 @@ extern void func2(unsigned char); void test(unsigned char v) { - /* { dg-final { scan-assembler "lsl\tr14.b0, r14.b0, .\+\n\tlsr\tr14.b0, r14.b0" } } */ + /* { dg-final { scan-assembler "lsr\tr14(.b0)?, r14.b0, .\+\n\tand\tr14.b0, r14.b0" } } */ func2((v & 2) ? 1 : 0); } diff --git a/gcc/testsuite/gcc.target/pru/extzv-1.c b/gcc/testsuite/gcc.target/pru/extzv-1.c new file mode 100644 index 0000000..573ded9 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/extzv-1.c @@ -0,0 +1,14 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 12 } } */ + +struct S { + unsigned int a : 5; + unsigned int b : 1; + unsigned int c : 1; +}; + +unsigned int test(struct S s) +{ + return s.a; +} diff --git a/gcc/testsuite/gcc.target/pru/extzv-2.c b/gcc/testsuite/gcc.target/pru/extzv-2.c new file mode 100644 index 0000000..e34ba13 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/extzv-2.c @@ -0,0 +1,15 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 12 } } */ + +struct S { + unsigned int a : 5; + unsigned int b : 1; + unsigned int c : 24; + unsigned int d : 2; +}; + +unsigned int test(struct S s) +{ + return s.d; +} diff --git a/gcc/testsuite/gcc.target/pru/extzv-3.c b/gcc/testsuite/gcc.target/pru/extzv-3.c new file mode 100644 index 0000000..66f4f37 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/extzv-3.c @@ -0,0 +1,13 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 16 } } */ + +struct S { + unsigned int a : 9; + unsigned int b : 4; +}; + +unsigned int test(struct S s) +{ + return s.b; +} diff --git a/gcc/testsuite/gcc.target/pru/insv-1.c b/gcc/testsuite/gcc.target/pru/insv-1.c new file mode 100644 index 0000000..50e29a1 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/insv-1.c @@ -0,0 +1,14 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 16 } } */ + +struct S { + unsigned int a : 5; + unsigned int b : 1; + unsigned int c : 1; +}; + +void test(struct S *s) +{ + s->b = 1; +} diff --git a/gcc/testsuite/gcc.target/pru/insv-2.c b/gcc/testsuite/gcc.target/pru/insv-2.c new file mode 100644 index 0000000..50272b7 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/insv-2.c @@ -0,0 +1,14 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 16 } } */ + +struct S { + unsigned int a : 5; + unsigned int b : 1; + unsigned int c : 1; +}; + +void test(struct S *s) +{ + s->b = 0; +} diff --git a/gcc/testsuite/gcc.target/pru/insv-3.c b/gcc/testsuite/gcc.target/pru/insv-3.c new file mode 100644 index 0000000..5ff0feb --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/insv-3.c @@ -0,0 +1,14 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 24 } } */ + +struct S { + unsigned int a : 5; + unsigned int b : 1; + unsigned int c : 1; +}; + +void test(struct S *s, unsigned int val) +{ + s->b = val; +} diff --git a/gcc/testsuite/gcc.target/pru/insv-4.c b/gcc/testsuite/gcc.target/pru/insv-4.c new file mode 100644 index 0000000..4eaa733 --- /dev/null +++ b/gcc/testsuite/gcc.target/pru/insv-4.c @@ -0,0 +1,14 @@ +/* { dg-do assemble } */ +/* { dg-options "-Os" } */ +/* { dg-final { object-size text <= 28 } } */ + +struct S { + unsigned int a : 3; + unsigned int b : 3; + unsigned int c : 3; +}; + +void test(struct S *s, unsigned int val) +{ + s->b = val; +} |