https://gcc.gnu.org/g:05e70b322d9a5b3eda6f6ac5d255dbe6e1cf0d51

commit r17-1044-g05e70b322d9a5b3eda6f6ac5d255dbe6e1cf0d51
Author: Takayuki 'January June' Suwa <[email protected]>
Date:   Tue May 26 07:32:43 2026 +0900

    xtensa: Optimize 'insvsi' insn pattern if TARGET_DEPBITS is not configured
    
    By default, the RTX generation pass conservatively expands bit-field
    insertion to an insn sequence consisting of the bit mask and shift of
    the inserted value, the bit-inversion mask of the destination, and finally
    a logical-OR.
    
    However, if the logical-AND operation on an inverted bit-field mask is
    relatively expensive, it is more advantageous to shift the inserted value
    without masking it and then follow the idiom '(A & M) | (B & ~M)' ->
    '((A ^ B) & M) ^ B'.
    
         /* example */
         struct foo {
           unsigned int x:10;
           unsigned int y:11;
           unsigned int z:11;
         };
         struct foo test0(struct foo a, unsigned int b) {
           a.x = b;
           return a;
         }
         struct foo test1(struct foo a, unsigned int b) {
           a.y = b;
           return a;
         }
    
         ;; before (-Os ; !BITS_BIG_ENDIAN | !TARGET_DEPBITS)
         test0:
            entry   sp, 32
            movi    a8, -0x400      ;; = ~0x000003FF
            extui   a3, a3, 0, 10   ;; mask
            and     a2, a2, a8      ;; inverted mask
            or      a2, a2, a3      ;; logical-OR
            retw.n
            .literal_position
            .literal .LC0, -2096129 ;; = ~0x001FFC00
         test1:
            entry   sp, 32
            l32r    a8, .LC0
            extui   a3, a3, 0, 11   ;; mask
            slli    a3, a3, 10      ;;
            and     a2, a2, a8      ;; inverted mask
            or      a2, a2, a3      ;; logical-OR
            retw.n
    
         ;; after (-Os ; !BITS_BIG_ENDIAN | !TARGET_DEPBITS)
         test0:
            entry   sp, 32
            xor     a3, a2, a3
            extui   a3, a3, 0, 10   ;; mask
            xor     a2, a2, a3
            retw.n
         test1:
            entry   sp, 32
            slli    a3, a3, 10      ;; bit-position alignment
            xor     a3, a2, a3
            extui   a3, a3, 10, 11  ;; mask
            slli    a3, a3, 10      ;;
            xor     a2, a2, a3
            retw.n
    
    gcc/ChangeLog:
    
            * config/xtensa/xtensa.md (insvsi_intermal):
            Rename from 'insvsi'.
            (insvsi): New expansion pattern that also addresses situations
            where the DEPBITS machine instruction is unavailable.

Diff:
---
 gcc/config/xtensa/xtensa.md | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index 8354ab250a15..31abbc8aa2d1 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -1079,7 +1079,35 @@
    (set_attr "mode"    "SI")
    (set_attr "length"  "6")])
 
-(define_insn "insvsi"
+(define_expand "insvsi"
+  [(set (zero_extract:SI (match_operand:SI 0 "register_operand")
+                        (match_operand:SI 1 "extui_fldsz_operand")
+                        (match_operand:SI 2 "const_int_operand"))
+       (match_operand:SI 3 "register_operand"))]
+  ""
+{
+  if (TARGET_DEPBITS)
+    emit_insn (gen_insvsi_internal (operands[0], operands[1], operands[2],
+                                   operands[3]));
+  else
+    {
+      int fldsz = INTVAL (operands[1]), shift;
+      rtx temp = gen_reg_rtx (SImode), mask;
+      if (BITS_BIG_ENDIAN)
+       shift = (32 - (fldsz + INTVAL (operands[2]))) & 0x1f;
+      else
+       shift = INTVAL (operands[2]) & 0x1f;
+      mask = GEN_INT (((1 << fldsz) - 1) << shift);
+      emit_insn (shift ? gen_ashlsi3 (temp, operands[3], GEN_INT (shift))
+                      : gen_rtx_SET (temp, operands[3]));
+      emit_insn (gen_xorsi3 (temp, operands[0], temp));
+      emit_insn (gen_andsi3 (temp, temp, force_reg (SImode, mask)));
+      emit_insn (gen_xorsi3 (operands[0], operands[0], temp));
+    }
+  DONE;
+})
+
+(define_insn "insvsi_internal"
   [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+a")
                         (match_operand:SI 1 "extui_fldsz_operand" "")
                         (match_operand:SI 2 "const_int_operand" ""))

Reply via email to