[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
This commit is contained in:
Simon Pilgrim 2023-08-20 14:53:12 +01:00
parent 71a7192d69
commit 9405b67a9e

View File

@ -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
}