]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
AVR: Tweak 32-bit EQ and NE comparisons.
authorGeorg-Johann Lay <avr@gjlay.de>
Tue, 10 Sep 2024 15:51:58 +0000 (17:51 +0200)
committerGeorg-Johann Lay <avr@gjlay.de>
Fri, 13 Sep 2024 09:36:27 +0000 (11:36 +0200)
The order in which multi-byte EQ and NE comparisons are performing
the byte comparisons does not matter, and there are situations where
using SBIW on the high word can save an instruction.

gcc/
* config/avr/avr.cc (avr_out_compare): Tweak 32-bit EQ and NE
comparisons that can use SBIW for the hi16 part.

gcc/config/avr/avr.cc

index f743261c6adf3fe5bdf69b32ad46d296f2ee6d48..25220c3bc0c7de4414778c2f09182392ad7f2215 100644 (file)
@@ -5990,6 +5990,31 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen)
        }
     }
 
+  /* Comparisons == and != may change the order in which the sub-bytes are
+     being compared.  Start with the high 16 bits so we can use SBIW.  */
+
+  if (n_bytes == 4
+      && compare_eq_p (insn)
+      && AVR_HAVE_ADIW
+      && REGNO (xreg) >= REG_22)
+    {
+      if (xval == const0_rtx)
+       return avr_asm_len ("sbiw %C0,0"           CR_TAB
+                           "cpc %B0,__zero_reg__" CR_TAB
+                           "cpc %A0,__zero_reg__", xop, plen, 3);
+
+      rtx xhi16 = simplify_gen_subreg (HImode, xval, mode, 2);
+      if (IN_RANGE (UINTVAL (xhi16) & GET_MODE_MASK (HImode), 0, 63)
+         && reg_unused_after (insn, xreg))
+       {
+         xop[1] = xhi16;
+         avr_asm_len ("sbiw %C0,%1", xop, plen, 1);
+         xop[1] = xval;
+         return avr_asm_len ("sbci %B0,hi8(%1)" CR_TAB
+                             "sbci %A0,lo8(%1)", xop, plen, 2);
+       }
+    }
+
   for (int i = 0; i < n_bytes; i++)
     {
       /* We compare byte-wise.  */