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