Files
clang-p2996/llvm/test/CodeGen/X86/dagcombine-select.ll
Craig Topper c985d42903 [X86] Canonicalize the pattern for __builtin_ffs in a similar way to '__builtin_ffs + 5'
We now emit a move of -1 before the cmov and do the addition after the cmov just like the case with an extra addition.

This may be slightly worse for code size, but is more consistent with other compilers. And we might be able to hoist the mov -1 outside of loops.

llvm-svn: 338613
2018-08-01 18:38:46 +00:00

430 lines
12 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=x86_64-unknown-unknown -verify-machineinstrs | FileCheck %s --check-prefixes=CHECK,NOBMI -enable-var-scope
; RUN: llc < %s -mtriple=x86_64-unknown-unknown -verify-machineinstrs -mattr=+bmi | FileCheck %s -check-prefixes=CHECK,BMI -enable-var-scope
define i32 @select_and1(i32 %x, i32 %y) {
; CHECK-LABEL: select_and1:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpl $11, %edi
; CHECK-NEXT: cmovgel %esi, %eax
; CHECK-NEXT: retq
%c = icmp slt i32 %x, 11
%s = select i1 %c, i32 0, i32 -1
%a = and i32 %y, %s
ret i32 %a
}
define i32 @select_and2(i32 %x, i32 %y) {
; CHECK-LABEL: select_and2:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpl $11, %edi
; CHECK-NEXT: cmovgel %esi, %eax
; CHECK-NEXT: retq
%c = icmp slt i32 %x, 11
%s = select i1 %c, i32 0, i32 -1
%a = and i32 %s, %y
ret i32 %a
}
define i32 @select_and3(i32 %x, i32 %y) {
; CHECK-LABEL: select_and3:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: cmpl $11, %edi
; CHECK-NEXT: cmovll %esi, %eax
; CHECK-NEXT: retq
%c = icmp slt i32 %x, 11
%s = select i1 %c, i32 -1, i32 0
%a = and i32 %y, %s
ret i32 %a
}
define <4 x i32> @select_and_v4(i32 %x, <4 x i32> %y) {
; CHECK-LABEL: select_and_v4:
; CHECK: # %bb.0:
; CHECK-NEXT: cmpl $11, %edi
; CHECK-NEXT: xorps %xmm1, %xmm1
; CHECK-NEXT: jl .LBB3_2
; CHECK-NEXT: # %bb.1:
; CHECK-NEXT: movaps %xmm0, %xmm1
; CHECK-NEXT: .LBB3_2:
; CHECK-NEXT: movaps %xmm1, %xmm0
; CHECK-NEXT: retq
%c = icmp slt i32 %x, 11
%s = select i1 %c, <4 x i32> zeroinitializer, <4 x i32><i32 -1, i32 -1, i32 -1, i32 -1>
%a = and <4 x i32> %s, %y
ret <4 x i32> %a
}
define i32 @select_or1(i32 %x, i32 %y) {
; CHECK-LABEL: select_or1:
; CHECK: # %bb.0:
; CHECK-NEXT: cmpl $11, %edi
; CHECK-NEXT: movl $-1, %eax
; CHECK-NEXT: cmovll %esi, %eax
; CHECK-NEXT: retq
%c = icmp slt i32 %x, 11
%s = select i1 %c, i32 0, i32 -1
%a = or i32 %y, %s
ret i32 %a
}
define i32 @select_or2(i32 %x, i32 %y) {
; CHECK-LABEL: select_or2:
; CHECK: # %bb.0:
; CHECK-NEXT: cmpl $11, %edi
; CHECK-NEXT: movl $-1, %eax
; CHECK-NEXT: cmovll %esi, %eax
; CHECK-NEXT: retq
%c = icmp slt i32 %x, 11
%s = select i1 %c, i32 0, i32 -1
%a = or i32 %s, %y
ret i32 %a
}
define i32 @select_or3(i32 %x, i32 %y) {
; CHECK-LABEL: select_or3:
; CHECK: # %bb.0:
; CHECK-NEXT: cmpl $11, %edi
; CHECK-NEXT: movl $-1, %eax
; CHECK-NEXT: cmovgel %esi, %eax
; CHECK-NEXT: retq
%c = icmp slt i32 %x, 11
%s = select i1 %c, i32 -1, i32 0
%a = or i32 %y, %s
ret i32 %a
}
define <4 x i32> @select_or_v4(i32 %x, <4 x i32> %y) {
; CHECK-LABEL: select_or_v4:
; CHECK: # %bb.0:
; CHECK-NEXT: cmpl $11, %edi
; CHECK-NEXT: jl .LBB7_2
; CHECK-NEXT: # %bb.1:
; CHECK-NEXT: pcmpeqd %xmm0, %xmm0
; CHECK-NEXT: .LBB7_2:
; CHECK-NEXT: retq
%c = icmp slt i32 %x, 11
%s = select i1 %c, <4 x i32> zeroinitializer, <4 x i32><i32 -1, i32 -1, i32 -1, i32 -1>
%a = or <4 x i32> %s, %y
ret <4 x i32> %a
}
define i32 @sel_constants_sub_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: sel_constants_sub_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: testb $1, %dil
; CHECK-NEXT: movl $9, %ecx
; CHECK-NEXT: movl $2, %eax
; CHECK-NEXT: cmovnel %ecx, %eax
; CHECK-NEXT: retq
%sel = select i1 %cond, i32 -4, i32 3
%bo = sub i32 5, %sel
ret i32 %bo
}
define i32 @sdiv_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: sdiv_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: notb %dil
; CHECK-NEXT: movzbl %dil, %eax
; CHECK-NEXT: andl $1, %eax
; CHECK-NEXT: leal (%rax,%rax,4), %eax
; CHECK-NEXT: retq
%sel = select i1 %cond, i32 121, i32 23
%bo = sdiv i32 120, %sel
ret i32 %bo
}
define i32 @udiv_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: udiv_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: notb %dil
; CHECK-NEXT: movzbl %dil, %eax
; CHECK-NEXT: andl $1, %eax
; CHECK-NEXT: leal (%rax,%rax,4), %eax
; CHECK-NEXT: retq
%sel = select i1 %cond, i32 -4, i32 23
%bo = udiv i32 120, %sel
ret i32 %bo
}
define i32 @srem_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: srem_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: testb $1, %dil
; CHECK-NEXT: movl $120, %ecx
; CHECK-NEXT: movl $5, %eax
; CHECK-NEXT: cmovnel %ecx, %eax
; CHECK-NEXT: retq
%sel = select i1 %cond, i32 121, i32 23
%bo = srem i32 120, %sel
ret i32 %bo
}
define i32 @urem_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: urem_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: testb $1, %dil
; CHECK-NEXT: movl $120, %ecx
; CHECK-NEXT: movl $5, %eax
; CHECK-NEXT: cmovnel %ecx, %eax
; CHECK-NEXT: retq
%sel = select i1 %cond, i32 -4, i32 23
%bo = urem i32 120, %sel
ret i32 %bo
}
define i32 @sel_constants_shl_constant(i1 %cond) {
; CHECK-LABEL: sel_constants_shl_constant:
; CHECK: # %bb.0:
; CHECK-NEXT: notb %dil
; CHECK-NEXT: movzbl %dil, %eax
; CHECK-NEXT: andl $1, %eax
; CHECK-NEXT: orl $2, %eax
; CHECK-NEXT: shll $8, %eax
; CHECK-NEXT: retq
%sel = select i1 %cond, i32 2, i32 3
%bo = shl i32 %sel, 8
ret i32 %bo
}
define i32 @shl_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: shl_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: andb $1, %dil
; CHECK-NEXT: xorb $3, %dil
; CHECK-NEXT: movl $1, %eax
; CHECK-NEXT: movl %edi, %ecx
; CHECK-NEXT: shll %cl, %eax
; CHECK-NEXT: retq
%sel = select i1 %cond, i32 2, i32 3
%bo = shl i32 1, %sel
ret i32 %bo
}
define i32 @lshr_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: lshr_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: andb $1, %dil
; CHECK-NEXT: xorb $3, %dil
; CHECK-NEXT: movl $64, %eax
; CHECK-NEXT: movl %edi, %ecx
; CHECK-NEXT: shrl %cl, %eax
; CHECK-NEXT: retq
%sel = select i1 %cond, i32 2, i32 3
%bo = lshr i32 64, %sel
ret i32 %bo
}
define i32 @ashr_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: ashr_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: andb $1, %dil
; CHECK-NEXT: xorb $3, %dil
; CHECK-NEXT: movl $128, %eax
; CHECK-NEXT: movl %edi, %ecx
; CHECK-NEXT: shrl %cl, %eax
; CHECK-NEXT: retq
%sel = select i1 %cond, i32 2, i32 3
%bo = ashr i32 128, %sel
ret i32 %bo
}
define double @fsub_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: fsub_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: testb $1, %dil
; CHECK-NEXT: jne .LBB17_1
; CHECK-NEXT: # %bb.2:
; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB17_1:
; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; CHECK-NEXT: retq
%sel = select i1 %cond, double -4.0, double 23.3
%bo = fsub double 5.1, %sel
ret double %bo
}
define double @fdiv_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: fdiv_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: testb $1, %dil
; CHECK-NEXT: jne .LBB18_1
; CHECK-NEXT: # %bb.2:
; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB18_1:
; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; CHECK-NEXT: retq
%sel = select i1 %cond, double -4.0, double 23.3
%bo = fdiv double 5.1, %sel
ret double %bo
}
define double @frem_constant_sel_constants(i1 %cond) {
; CHECK-LABEL: frem_constant_sel_constants:
; CHECK: # %bb.0:
; CHECK-NEXT: testb $1, %dil
; CHECK-NEXT: jne .LBB19_1
; CHECK-NEXT: # %bb.2:
; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; CHECK-NEXT: retq
; CHECK-NEXT: .LBB19_1:
; CHECK-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; CHECK-NEXT: retq
%sel = select i1 %cond, double -4.0, double 23.3
%bo = frem double 5.1, %sel
ret double %bo
}
declare i64 @llvm.cttz.i64(i64, i1)
define i64 @cttz_64_eq_select(i64 %v) nounwind {
; NOBMI-LABEL: cttz_64_eq_select:
; NOBMI: # %bb.0:
; NOBMI-NEXT: bsfq %rdi, %rcx
; NOBMI-NEXT: movq $-1, %rax
; NOBMI-NEXT: cmovneq %rcx, %rax
; NOBMI-NEXT: addq $6, %rax
; NOBMI-NEXT: retq
;
; BMI-LABEL: cttz_64_eq_select:
; BMI: # %bb.0:
; BMI-NEXT: tzcntq %rdi, %rcx
; BMI-NEXT: movq $-1, %rax
; BMI-NEXT: cmovaeq %rcx, %rax
; BMI-NEXT: addq $6, %rax
; BMI-NEXT: retq
%cnt = tail call i64 @llvm.cttz.i64(i64 %v, i1 true)
%tobool = icmp eq i64 %v, 0
%.op = add nuw nsw i64 %cnt, 6
%add = select i1 %tobool, i64 5, i64 %.op
ret i64 %add
}
define i64 @cttz_64_ne_select(i64 %v) nounwind {
; NOBMI-LABEL: cttz_64_ne_select:
; NOBMI: # %bb.0:
; NOBMI-NEXT: bsfq %rdi, %rcx
; NOBMI-NEXT: movq $-1, %rax
; NOBMI-NEXT: cmovneq %rcx, %rax
; NOBMI-NEXT: addq $6, %rax
; NOBMI-NEXT: retq
;
; BMI-LABEL: cttz_64_ne_select:
; BMI: # %bb.0:
; BMI-NEXT: tzcntq %rdi, %rcx
; BMI-NEXT: movq $-1, %rax
; BMI-NEXT: cmovaeq %rcx, %rax
; BMI-NEXT: addq $6, %rax
; BMI-NEXT: retq
%cnt = tail call i64 @llvm.cttz.i64(i64 %v, i1 true)
%tobool = icmp ne i64 %v, 0
%.op = add nuw nsw i64 %cnt, 6
%add = select i1 %tobool, i64 %.op, i64 5
ret i64 %add
}
declare i32 @llvm.cttz.i32(i32, i1)
define i32 @cttz_32_eq_select(i32 %v) nounwind {
; NOBMI-LABEL: cttz_32_eq_select:
; NOBMI: # %bb.0:
; NOBMI-NEXT: bsfl %edi, %ecx
; NOBMI-NEXT: movl $-1, %eax
; NOBMI-NEXT: cmovnel %ecx, %eax
; NOBMI-NEXT: addl $6, %eax
; NOBMI-NEXT: retq
;
; BMI-LABEL: cttz_32_eq_select:
; BMI: # %bb.0:
; BMI-NEXT: tzcntl %edi, %ecx
; BMI-NEXT: movl $-1, %eax
; BMI-NEXT: cmovael %ecx, %eax
; BMI-NEXT: addl $6, %eax
; BMI-NEXT: retq
%cnt = tail call i32 @llvm.cttz.i32(i32 %v, i1 true)
%tobool = icmp eq i32 %v, 0
%.op = add nuw nsw i32 %cnt, 6
%add = select i1 %tobool, i32 5, i32 %.op
ret i32 %add
}
define i32 @cttz_32_ne_select(i32 %v) nounwind {
; NOBMI-LABEL: cttz_32_ne_select:
; NOBMI: # %bb.0:
; NOBMI-NEXT: bsfl %edi, %ecx
; NOBMI-NEXT: movl $-1, %eax
; NOBMI-NEXT: cmovnel %ecx, %eax
; NOBMI-NEXT: addl $6, %eax
; NOBMI-NEXT: retq
;
; BMI-LABEL: cttz_32_ne_select:
; BMI: # %bb.0:
; BMI-NEXT: tzcntl %edi, %ecx
; BMI-NEXT: movl $-1, %eax
; BMI-NEXT: cmovael %ecx, %eax
; BMI-NEXT: addl $6, %eax
; BMI-NEXT: retq
%cnt = tail call i32 @llvm.cttz.i32(i32 %v, i1 true)
%tobool = icmp ne i32 %v, 0
%.op = add nuw nsw i32 %cnt, 6
%add = select i1 %tobool, i32 %.op, i32 5
ret i32 %add
}
; This matches the pattern emitted for __builtin_ffs
define i32 @cttz_32_eq_select_ffs(i32 %v) nounwind {
; NOBMI-LABEL: cttz_32_eq_select_ffs:
; NOBMI: # %bb.0:
; NOBMI-NEXT: bsfl %edi, %ecx
; NOBMI-NEXT: movl $-1, %eax
; NOBMI-NEXT: cmovnel %ecx, %eax
; NOBMI-NEXT: incl %eax
; NOBMI-NEXT: retq
;
; BMI-LABEL: cttz_32_eq_select_ffs:
; BMI: # %bb.0:
; BMI-NEXT: tzcntl %edi, %ecx
; BMI-NEXT: movl $-1, %eax
; BMI-NEXT: cmovael %ecx, %eax
; BMI-NEXT: incl %eax
; BMI-NEXT: retq
%cnt = tail call i32 @llvm.cttz.i32(i32 %v, i1 true)
%tobool = icmp eq i32 %v, 0
%.op = add nuw nsw i32 %cnt, 1
%add = select i1 %tobool, i32 0, i32 %.op
ret i32 %add
}
define i32 @cttz_32_ne_select_ffs(i32 %v) nounwind {
; NOBMI-LABEL: cttz_32_ne_select_ffs:
; NOBMI: # %bb.0:
; NOBMI-NEXT: bsfl %edi, %ecx
; NOBMI-NEXT: movl $-1, %eax
; NOBMI-NEXT: cmovnel %ecx, %eax
; NOBMI-NEXT: incl %eax
; NOBMI-NEXT: retq
;
; BMI-LABEL: cttz_32_ne_select_ffs:
; BMI: # %bb.0:
; BMI-NEXT: tzcntl %edi, %ecx
; BMI-NEXT: movl $-1, %eax
; BMI-NEXT: cmovael %ecx, %eax
; BMI-NEXT: incl %eax
; BMI-NEXT: retq
%cnt = tail call i32 @llvm.cttz.i32(i32 %v, i1 true)
%tobool = icmp ne i32 %v, 0
%.op = add nuw nsw i32 %cnt, 1
%add = select i1 %tobool, i32 %.op, i32 0
ret i32 %add
}