The x86 backend misses an optimization for a zero-extended HImode
unsigned minimum with a constant. Add an HImode conditional-move
pattern that preserves the flags dependency and use it in a new
zero-extension splitter.

This allows x86-64 to use a HImode conditional move and avoids the
redundant zero-extension instruction.

Will be working on the tree-level fold that makes the zero-extend
redundancy visible to all optimizers.

Regression tested on x86_64-linux with no new failures.

gcc/ChangeLog:

        PR target/94543
        * config/i386/i386.md (*movhicc_noc_flags_use): New insn
        pattern.
        (*zero_extend_uminhisi2): New insn-and-split pattern.

gcc/testsuite/ChangeLog:

        PR target/94543
        * gcc.target/i386/pr94543.c: New test.

Signed-off-by: Naveen <[email protected]>
---
 gcc/config/i386/i386.md                 | 39 +++++++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr94543.c | 11 +++++++
 2 files changed, 50 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/i386/pr94543.c

diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index d5b90291fc9..a800dafda29 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -27513,6 +27513,20 @@
    (set (match_dup 0)
        (neg:SWI (ltu:SWI (reg:CCC FLAGS_REG) (const_int 0))))])
 
+(define_insn "*movhicc_noc_flags_use"
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (if_then_else:HI (match_operator 1 "ix86_comparison_operator"
+                              [(reg FLAGS_REG) (const_int 0)])
+         (match_operand:HI 2 "nonimmediate_operand" "rm,0")
+         (match_operand:HI 3 "nonimmediate_operand" "0,rm")))
+   (use (reg:CC FLAGS_REG))]
+  "TARGET_CMOVE && !(MEM_P (operands[2]) && MEM_P (operands[3]))"
+  "@
+   cmov%O2%C1\t{%2, %0|%0, %2}
+   cmov%O2%c1\t{%3, %0|%0, %3}"
+  [(set_attr "type" "icmov")
+   (set_attr "mode" "HI")])
+
 (define_insn "*mov<mode>cc_noc"
   [(set (match_operand:SWI248 0 "register_operand" "=r,r,r,r,r")
        (if_then_else:SWI248 (match_operator 1 "ix86_comparison_operator"
@@ -28098,6 +28112,31 @@
 
 ;; min/max patterns
 
+(define_insn_and_split "*zero_extend_uminhisi2"
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (zero_extend:SI
+         (umin:HI (match_operand:HI 1 "register_operand")
+                   (match_operand:HI 2 "const_int_operand"))))]
+  "TARGET_64BIT && TARGET_CMOVE && !TARGET_PARTIAL_REG_STALL
+   && INTVAL (operands[2]) >= 0
+   && (unsigned HOST_WIDE_INT) INTVAL (operands[2])
+      <= GET_MODE_MASK (HImode)"
+  "#"
+  "&& 1"
+  [(set (match_dup 0) (match_dup 2))
+   (set (reg:CC FLAGS_REG)
+       (compare:CC (match_dup 1) (match_dup 3)))
+   (parallel
+    [(set (match_dup 4)
+         (if_then_else:HI (leu (reg:CC FLAGS_REG) (const_int 0))
+           (match_dup 1)
+           (match_dup 3)))
+     (use (reg:CC FLAGS_REG))])]
+{
+  operands[3] = lowpart_subreg (HImode, operands[0], SImode);
+  operands[4] = operands[3];
+})
+
 (define_code_attr maxmin_rel
   [(smax "GE") (smin "LE") (umax "GEU") (umin "LEU")])
 
diff --git a/gcc/testsuite/gcc.target/i386/pr94543.c 
b/gcc/testsuite/gcc.target/i386/pr94543.c
new file mode 100644
index 00000000000..d8458171e7b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr94543.c
@@ -0,0 +1,11 @@
+/* PR target/94543 */
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -march=x86-64" } */
+/* { dg-final { scan-assembler "cmovbe\[ \t\]+%di, %ax" } } */
+/* { dg-final { scan-assembler-not "movzwl" } } */
+
+unsigned
+f (unsigned short x)
+{
+  return (x > 0xff ? 0xff : x) & 0xff;
+}
-- 
2.34.1

Reply via email to