From 47b757cf31fffb2ae5fdb93f9f031890080504a8 Mon Sep 17 00:00:00 2001 From: Dimitar Dimitrov Date: Sun, 19 Nov 2023 12:20:08 +0200 Subject: 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): Make it an expand pattern, handle efficiently zero-positioned bit-fields. (insv): 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 --- gcc/config/pru/pru.md | 104 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 95 insertions(+), 9 deletions(-) (limited to 'gcc/config/pru/pru.md') 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" - [(set (match_operand:QISI 0 "register_operand" "=r") +(define_expand "extzv" + [(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) - nbits - bitpos; + + if (bitpos == 0 && nbits <= 7) + { + emit_insn (gen_and3 (operands[0], + operands[1], + gen_int_mode ((HOST_WIDE_INT_1U << nbits) - 1, + mode))); + DONE; + } + + rtx src = operands[1]; + if (trailing_bits != 0) + { + emit_insn (gen_ashl3 (operands[0], + operands[1], + GEN_INT (trailing_bits))); + src = operands[0]; + } + emit_insn (gen_lshr3 (operands[0], + src, + GEN_INT (trailing_bits + bitpos))); + DONE; +}) + +;; Bit-field insert. +(define_expand "insv" + [(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); + rtx dst = operands[0]; + + emit_move_insn (src, operands[3]); + + emit_insn (gen_and3 (dst, + dst, + gen_int_mode (~(HOST_WIDE_INT_1U << bitpos), + mode))); + + rtx_code_label *skip_set_label = gen_label_rtx (); + j = emit_jump_insn (gen_cbranch_qbbx_eq4 ( + src, + GEN_INT (0), + skip_set_label)); + JUMP_LABEL (j) = skip_set_label; + LABEL_NUSES (skip_set_label)++; + + emit_insn (gen_ior3 (dst, + dst, + gen_int_mode (HOST_WIDE_INT_1U << bitpos, + 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); + emit_insn (gen_and3 (src, + force_reg (mode, operands[3]), + gen_int_mode ((HOST_WIDE_INT_1U << nbits) - 1, + mode))); + if (bitpos > 0) + emit_insn (gen_ashl3 (src, src, gen_int_mode (bitpos, mode))); + + HOST_WIDE_INT vmask = ~(((HOST_WIDE_INT_1U << nbits) - 1) << bitpos); + emit_insn (gen_and3 (dst, + dst, + gen_int_mode (vmask, mode))); + + emit_insn (gen_ior3 (dst, dst, src)); + + DONE; +}) ;; Arithmetic Operations -- cgit v1.1