Avoid andb %dil when optimizing for size.
authorRoger Sayle <roger@nextmovesoftware.com>
Tue, 10 May 2022 08:44:34 +0000 (09:44 +0100)
committerRoger Sayle <roger@nextmovesoftware.com>
Tue, 10 May 2022 08:44:34 +0000 (09:44 +0100)
The simple test case below has the unfortunate property that on x86_64,
it is larger when compiled with -Os than when compiled with -O2.

int foo(char x)
{
  return (x & 123) != 0;
}

The issue is x86's complex instruction encoding, where andb $XX,%dil
requires more bytes than andl $XX,%edi.  This patch adds logic to
i386.md's *testqi_1_maybe_si and *andqi_2_maybe_si define_insn patterns
to prefer the shorter SImode alternative when optimizing for size.

2022-05-10  Uroš Bizjak  <ubizjak@gmail.com>
    Roger Sayle  <roger@nextmovesoftware.com>

gcc/ChangeLog
* config/i386/i386.md (*testqi_1_maybe_si): Prefer shorter SImode
alternative when optimizing for size and the immediate operand is
const_0_to_127_operand.
(*andqi_2_maybe_si): Likewise.
* config/i386/predicates.md (const_0_to_127_operand): New predicate.

gcc/testsuite/ChangeLog
* gcc.target/i386/and-1.c: New test case.

gcc/config/i386/i386.md
gcc/config/i386/predicates.md
gcc/testsuite/gcc.target/i386/and-1.c [new file with mode: 0644]

index b321cda..f9c06ff 100644 (file)
   [(set (reg FLAGS_REG)
        (compare
          (and:QI
-           (match_operand:QI 0 "nonimmediate_operand" "%qm,*a,qm,r")
-           (match_operand:QI 1 "nonmemory_operand" "q,n,n,n"))
+           (match_operand:QI 0 "nonimmediate_operand" "%qm,qm,r")
+           (match_operand:QI 1 "nonmemory_operand" "q,n,n"))
          (const_int 0)))]
   "ix86_match_ccmode (insn,
                      CONST_INT_P (operands[1])
                      && INTVAL (operands[1]) >= 0 ? CCNOmode : CCZmode)"
 {
-  if (which_alternative == 3)
+  if (get_attr_mode (insn) == MODE_SI)
     {
       if (CONST_INT_P (operands[1]) && INTVAL (operands[1]) < 0)
        operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff);
   return "test{b}\t{%1, %0|%0, %1}";
 }
   [(set_attr "type" "test")
-   (set_attr "mode" "QI,QI,QI,SI")
-   (set_attr "pent_pair" "uv,uv,np,np")])
+   (set (attr "mode")
+     (cond [(eq_attr "alternative" "2")
+             (const_string "SI")
+           (and (match_test "optimize_insn_for_size_p ()")
+                (and (match_operand 0 "ext_QIreg_operand")
+                     (match_operand 1 "const_0_to_127_operand")))
+             (const_string "SI")
+          ]
+          (const_string "QI")))
+   (set_attr "pent_pair" "uv,np,np")])
 
 (define_insn "*test<mode>_1"
   [(set (reg FLAGS_REG)
                         CONST_INT_P (operands[2])
                         && INTVAL (operands[2]) >= 0 ? CCNOmode : CCZmode)"
 {
-  if (which_alternative == 2)
+  if (get_attr_mode (insn) == MODE_SI)
     {
       if (CONST_INT_P (operands[2]) && INTVAL (operands[2]) < 0)
         operands[2] = GEN_INT (INTVAL (operands[2]) & 0xff);
   return "and{b}\t{%2, %0|%0, %2}";
 }
   [(set_attr "type" "alu")
-   (set_attr "mode" "QI,QI,SI")
+   (set (attr "mode")
+     (cond [(eq_attr "alternative" "2")
+             (const_string "SI")
+           (and (match_test "optimize_insn_for_size_p ()")
+                (and (match_operand 0 "ext_QIreg_operand")
+                     (match_operand 2 "const_0_to_127_operand")))
+             (const_string "SI")
+          ]
+          (const_string "QI")))
    ;; Potential partial reg stall on alternative 2.
    (set (attr "preferred_for_speed")
      (cond [(eq_attr "alternative" "2")
index a8cc17a..848a79a 100644 (file)
   (and (match_code "const_int")
        (match_test "IN_RANGE (INTVAL (op), 0, 63)")))
 
+;; Match 0 to 127.
+(define_predicate "const_0_to_127_operand"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 127)")))
+
 ;; Match 0 to 255.
 (define_predicate "const_0_to_255_operand"
   (and (match_code "const_int")
diff --git a/gcc/testsuite/gcc.target/i386/and-1.c b/gcc/testsuite/gcc.target/i386/and-1.c
new file mode 100644 (file)
index 0000000..11890d8
--- /dev/null
@@ -0,0 +1,9 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-Os" } */
+
+int foo(char x)
+{
+  return (x & 123) != 0;
+}
+
+/* { dg-final { scan-assembler-not "%dil" } } */