[Bug middle-end/91202] Unnecessary promotion of shift operands

jakub at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Fri Jul 19 10:49:00 GMT 2019


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91202

--- Comment #10 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
I've tried:
--- gcc/config/i386/i386.md.jj  2019-07-19 11:56:10.475964435 +0200
+++ gcc/config/i386/i386.md     2019-07-19 12:43:52.461469500 +0200
@@ -10661,6 +10661,43 @@
   "ix86_split_<shift_insn> (operands, NULL_RTX, <MODE>mode); DONE;"
   [(set_attr "type" "multi")])

+(define_insn_and_split "*shrqi3_3"
+  [(set (match_operand:SI 0 "register_operand")
+       (ashiftrt:SI
+         (zero_extend:SI (match_operand:QI 1 "register_operand"))
+         (match_operand:QI 2 "nonmemory_operand")))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "#"
+  "&& 1"
+  [(parallel
+     [(set (match_dup 3)
+          (subreg:QI (ashiftrt:SI
+                       (zero_extend:SI (match_dup 1))
+                       (match_dup 2)) 0))
+      (clobber (reg:CC FLAGS_REG))])
+   (set (match_dup 0) (zero_extend:SI (match_dup 3)))]
+{
+  operands[3] = (can_create_pseudo_p ()
+                ? gen_reg_rtx (QImode) : gen_lowpart (QImode, operands[0]));
+})
+
+(define_insn "*shrqi3_4"
+  [(set (match_operand:QI 0 "register_operand" "=q")
+       (subreg:QI
+         (ashiftrt:SI
+           (zero_extend:SI (match_operand:QI 1 "register_operand" "0"))
+           (match_operand:QI 2 "nonmemory_operand" "cI")) 0))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+{
+  if (operands[2] == const1_rtx
+      && (TARGET_SHIFT1 || optimize_function_for_size_p (cfun)))
+    return "shr{q}\t%0";
+  else
+    return "shr{q}\t{%2, %0|%0, %2}";
+})
+
 ;; By default we don't ask for a scratch register, because when DWImode
 ;; values are manipulated, registers are already at a premium.  But if
 ;; we have one handy, we won't turn it away.
and surprisingly, not just before RA, but even after it nothing will optimize
away the extra zero extend.
unsigned char foo (unsigned char a, unsigned char b) { return a >> b; }
void bar (unsigned char a, unsigned char b, unsigned char *c) { *c = a >> b; }
changes with the patch as:
-       movzbl  %dil, %eax
        movl    %esi, %ecx
-       sarl    %cl, %eax
+       shrq    %cl, %dil
+       movzbl  %dil, %eax
and:
-       movzbl  %dil, %edi
        movl    %esi, %ecx
-       sarl    %cl, %edi
+       shrq    %cl, %dil
+       movzbl  %dil, %edi
        movb    %dil, (%rdx)


More information about the Gcc-bugs mailing list