[llvm] 9405b67 - [X86] Add test coverage for PR33879 (Issue #33226)

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 20 07:38:08 PDT 2023


Author: Simon Pilgrim
Date: 2023-08-20T15:32:46+01:00
New Revision: 9405b67a9ef93f23f4d287b2ef67a2c6d7758615

URL: https://github.com/llvm/llvm-project/commit/9405b67a9ef93f23f4d287b2ef67a2c6d7758615
DIFF: https://github.com/llvm/llvm-project/commit/9405b67a9ef93f23f4d287b2ef67a2c6d7758615.diff

LOG: [X86] Add test coverage for PR33879 (Issue #33226)

Ensure we only use the eflags results from shift instructions when it won't cause stalls

shift by variable causes stalls as it has to preserve eflags when the shift amount was zero, so we're better off using a separate test

Added: 
    llvm/test/CodeGen/X86/shift-eflags.ll

Modified: 
    

Removed: 
    


################################################################################
diff  --git a/llvm/test/CodeGen/X86/shift-eflags.ll b/llvm/test/CodeGen/X86/shift-eflags.ll
new file mode 100644
index 00000000000000..8d4597ec21bcdd
--- /dev/null
+++ b/llvm/test/CodeGen/X86/shift-eflags.ll
@@ -0,0 +1,388 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-- | FileCheck %s
+
+; PR33879 - use shift eflags result when it won't cause stalls
+
+; ashr by constant - use sarl eflags result
+define i32 @ashr_const(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: ashr_const:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edx, %eax
+; CHECK-NEXT:    sarl $14, %edi
+; CHECK-NEXT:    cmovnel %ecx, %eax
+; CHECK-NEXT:    retq
+  %s = ashr i32 %a0, 14
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; lshr by constant - simplify to test
+define i32 @lshr_const(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: lshr_const:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edx, %eax
+; CHECK-NEXT:    testl $-16384, %edi # imm = 0xC000
+; CHECK-NEXT:    cmovnel %ecx, %eax
+; CHECK-NEXT:    retq
+  %s = lshr i32 %a0, 14
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; shl by constant - simplify to test
+define i32 @shl_const(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: shl_const:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edx, %eax
+; CHECK-NEXT:    testl $262143, %edi # imm = 0x3FFFF
+; CHECK-NEXT:    cmovnel %ecx, %eax
+; CHECK-NEXT:    retq
+  %s = shl i32 %a0, 14
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; ashr by constant and using shift result - use sarl eflags result
+define i32 @ashr_const_self_select(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: ashr_const_self_select:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    sarl $14, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = ashr i32 %a0, 14
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; lshr by constant and using shift result - use shrl eflags result
+define i32 @lshr_const_self_select(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: lshr_const_self_select:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    shrl $14, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = lshr i32 %a0, 14
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; lshr by constant and using result - use shll eflags result
+define i32 @shl_const_self_select(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: shl_const_self_select:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    shll $14, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = shl i32 %a0, 14
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; ashr by 1 - use sarl eflags result
+define i32 @ashr_const1(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: ashr_const1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edx, %eax
+; CHECK-NEXT:    sarl %edi
+; CHECK-NEXT:    cmovnel %ecx, %eax
+; CHECK-NEXT:    retq
+  %s = ashr i32 %a0, 1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; lshr by 1 - simplify to test
+define i32 @lshr_const1(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: lshr_const1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edx, %eax
+; CHECK-NEXT:    testl $-2, %edi
+; CHECK-NEXT:    cmovnel %ecx, %eax
+; CHECK-NEXT:    retq
+  %s = lshr i32 %a0, 1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; shl by 1 - simplify to test
+define i32 @shl_const1(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: shl_const1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edx, %eax
+; CHECK-NEXT:    testl $2147483647, %edi # imm = 0x7FFFFFFF
+; CHECK-NEXT:    cmovnel %ecx, %eax
+; CHECK-NEXT:    retq
+  %s = shl i32 %a0, 1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; ashr by 1 and using shift result - use sarl eflags result
+define i32 @ashr_const1_self_select(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: ashr_const1_self_select:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    sarl %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = ashr i32 %a0, 1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; lshr by 1 and using shift result - use shrl eflags result
+define i32 @lshr_const1_self_select(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: lshr_const1_self_select:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    shrl %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = lshr i32 %a0, 1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; lshr by 1 and using result - use addl eflags result
+define i32 @shl_const1_self_select(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: shl_const1_self_select:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    addl %edi, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = shl i32 %a0, 1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; ashr by variable - use seperate test
+define i32 @ashr_var(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: ashr_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %ecx, %eax
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    sarl %cl, %edi
+; CHECK-NEXT:    testl %edi, %edi
+; CHECK-NEXT:    cmovel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = ashr i32 %a0, %a1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; lshr by variable - use seperate test
+define i32 @lshr_var(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: lshr_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %ecx, %eax
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shrl %cl, %edi
+; CHECK-NEXT:    testl %edi, %edi
+; CHECK-NEXT:    cmovel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = lshr i32 %a0, %a1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; shl by variable - use seperate test
+define i32 @shl_var(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: shl_var:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %ecx, %eax
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shll %cl, %edi
+; CHECK-NEXT:    testl %edi, %edi
+; CHECK-NEXT:    cmovel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = shl i32 %a0, %a1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; ashr by variable and using result - use seperate test
+define i32 @ashr_var_self_select(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: ashr_var_self_select:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    sarl %cl, %eax
+; CHECK-NEXT:    testl %eax, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = ashr i32 %a0, %a1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; lshr by variable and using result - use seperate test
+define i32 @lshr_var_self_select(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: lshr_var_self_select:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shrl %cl, %eax
+; CHECK-NEXT:    testl %eax, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = lshr i32 %a0, %a1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; shl by variable and using result - use seperate test
+define i32 @shl_var_self_select(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: shl_var_self_select:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shll %cl, %eax
+; CHECK-NEXT:    testl %eax, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %s = shl i32 %a0, %a1
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; ashr by non-zero variable - use seperate test
+define i32 @ashr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: ashr_var_amt_never_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %ecx, %eax
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    orb $1, %cl
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    sarl %cl, %edi
+; CHECK-NEXT:    testl %edi, %edi
+; CHECK-NEXT:    cmovel %edx, %eax
+; CHECK-NEXT:    retq
+  %a = or i32 %a1, 1
+  %s = ashr i32 %a0, %a
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; lshr by non-zero variable - use seperate test
+define i32 @lshr_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: lshr_var_amt_never_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %ecx, %eax
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    orb $1, %cl
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shrl %cl, %edi
+; CHECK-NEXT:    testl %edi, %edi
+; CHECK-NEXT:    cmovel %edx, %eax
+; CHECK-NEXT:    retq
+  %a = or i32 %a1, 1
+  %s = lshr i32 %a0, %a
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; shl by non-zero variable - use seperate test
+define i32 @shl_var_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: shl_var_amt_never_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %ecx, %eax
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    orb $1, %cl
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shll %cl, %edi
+; CHECK-NEXT:    testl %edi, %edi
+; CHECK-NEXT:    cmovel %edx, %eax
+; CHECK-NEXT:    retq
+  %a = or i32 %a1, 1
+  %s = shl i32 %a0, %a
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %a2, i32 %a3
+  ret i32 %r
+}
+
+; ashr by non-zero variable and using result - use seperate test
+define i32 @ashr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: ashr_var_self_select_amt_never_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    orb $1, %cl
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shrl %cl, %eax
+; CHECK-NEXT:    testl %eax, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %a = or i32 %a1, 1
+  %s = lshr i32 %a0, %a
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; lshr by non-zero variable and using result - use seperate test
+define i32 @lshr_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: lshr_var_self_select_amt_never_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    orb $1, %cl
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shrl %cl, %eax
+; CHECK-NEXT:    testl %eax, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %a = or i32 %a1, 1
+  %s = lshr i32 %a0, %a
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}
+
+; shl by non-zero variable and using result - use seperate test
+define i32 @shl_var_self_select_amt_never_zero(i32 %a0, i32 %a1, i32 %a2, i32 %a3) {
+; CHECK-LABEL: shl_var_self_select_amt_never_zero:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    movl %esi, %ecx
+; CHECK-NEXT:    movl %edi, %eax
+; CHECK-NEXT:    orb $1, %cl
+; CHECK-NEXT:    # kill: def $cl killed $cl killed $ecx
+; CHECK-NEXT:    shrl %cl, %eax
+; CHECK-NEXT:    testl %eax, %eax
+; CHECK-NEXT:    cmovnel %edx, %eax
+; CHECK-NEXT:    retq
+  %a = or i32 %a1, 1
+  %s = lshr i32 %a0, %a
+  %c = icmp eq i32 %s, 0
+  %r = select i1 %c, i32 %s, i32 %a2
+  ret i32 %r
+}


        


More information about the llvm-commits mailing list