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 /gcc/config/pru/pru.md | |
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>
Diffstat (limited to 'gcc/config/pru/pru.md')
-rw-r--r-- | gcc/config/pru/pru.md | 104 |
1 files changed, 95 insertions, 9 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 |