If we're loading a constant value, print the constant (and the zero upper elements) instead of just the shuffle mask. This did require me to move the shuffle mask handling into addConstantComments as we can't handle this in the MC layer.
513 lines
14 KiB
LLVM
513 lines
14 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: notb %dil
|
|
; CHECK-NEXT: movzbl %dil, %eax
|
|
; CHECK-NEXT: andl $1, %eax
|
|
; CHECK-NEXT: leal 4(,%rax,4), %eax
|
|
; CHECK-NEXT: retq
|
|
%sel = select i1 %cond, i32 2, i32 3
|
|
%bo = shl i32 1, %sel
|
|
ret i32 %bo
|
|
}
|
|
|
|
define i32 @shl_constant_sel_setcc(i32 %a) {
|
|
; CHECK-LABEL: shl_constant_sel_setcc:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: xorl %eax, %eax
|
|
; CHECK-NEXT: testb $1, %dil
|
|
; CHECK-NEXT: sete %al
|
|
; CHECK-NEXT: leal 4(,%rax,4), %eax
|
|
; CHECK-NEXT: retq
|
|
%m = and i32 %a, 1
|
|
%cond = icmp ne i32 %m, 0
|
|
%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: # kill: def $edi killed $edi def $rdi
|
|
; CHECK-NEXT: andl $1, %edi
|
|
; CHECK-NEXT: leal 8(,%rdi,8), %eax
|
|
; CHECK-NEXT: retq
|
|
%sel = select i1 %cond, i32 2, i32 3
|
|
%bo = lshr i32 64, %sel
|
|
ret i32 %bo
|
|
}
|
|
|
|
define i32 @lshr_constant_sel_setcc(i32 %a) {
|
|
; CHECK-LABEL: lshr_constant_sel_setcc:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
|
|
; CHECK-NEXT: andl $1, %edi
|
|
; CHECK-NEXT: leal 8(,%rdi,8), %eax
|
|
; CHECK-NEXT: retq
|
|
%m = and i32 %a, 1
|
|
%cond = icmp ne i32 %m, 0
|
|
%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: # kill: def $edi killed $edi def $rdi
|
|
; CHECK-NEXT: andl $1, %edi
|
|
; CHECK-NEXT: shll $4, %edi
|
|
; CHECK-NEXT: leal 16(%rdi), %eax
|
|
; CHECK-NEXT: retq
|
|
%sel = select i1 %cond, i32 2, i32 3
|
|
%bo = ashr i32 128, %sel
|
|
ret i32 %bo
|
|
}
|
|
|
|
define i32 @ashr_constant_sel_setcc(i32 %a) {
|
|
; CHECK-LABEL: ashr_constant_sel_setcc:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: # kill: def $edi killed $edi def $rdi
|
|
; CHECK-NEXT: andl $1, %edi
|
|
; CHECK-NEXT: shll $4, %edi
|
|
; CHECK-NEXT: leal 16(%rdi), %eax
|
|
; CHECK-NEXT: retq
|
|
%m = and i32 %a, 1
|
|
%cond = icmp ne i32 %m, 0
|
|
%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 .LBB20_1
|
|
; CHECK-NEXT: # %bb.2:
|
|
; CHECK-NEXT: movsd {{.*#+}} xmm0 = [-1.8200000000000003E+1,0.0E+0]
|
|
; CHECK-NEXT: retq
|
|
; CHECK-NEXT: .LBB20_1:
|
|
; CHECK-NEXT: movsd {{.*#+}} xmm0 = [9.0999999999999996E+0,0.0E+0]
|
|
; 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 .LBB21_1
|
|
; CHECK-NEXT: # %bb.2:
|
|
; CHECK-NEXT: movsd {{.*#+}} xmm0 = [2.188841201716738E-1,0.0E+0]
|
|
; CHECK-NEXT: retq
|
|
; CHECK-NEXT: .LBB21_1:
|
|
; CHECK-NEXT: movsd {{.*#+}} xmm0 = [-1.2749999999999999E+0,0.0E+0]
|
|
; 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 .LBB22_1
|
|
; CHECK-NEXT: # %bb.2:
|
|
; CHECK-NEXT: movsd {{.*#+}} xmm0 = [5.0999999999999996E+0,0.0E+0]
|
|
; CHECK-NEXT: retq
|
|
; CHECK-NEXT: .LBB22_1:
|
|
; CHECK-NEXT: movsd {{.*#+}} xmm0 = [1.0999999999999996E+0,0.0E+0]
|
|
; 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
|
|
}
|
|
|
|
; This matches the pattern emitted for __builtin_ffs - 1
|
|
define i32 @cttz_32_eq_select_ffs_m1(i32 %v) nounwind {
|
|
; NOBMI-LABEL: cttz_32_eq_select_ffs_m1:
|
|
; NOBMI: # %bb.0:
|
|
; NOBMI-NEXT: bsfl %edi, %ecx
|
|
; NOBMI-NEXT: movl $-1, %eax
|
|
; NOBMI-NEXT: cmovnel %ecx, %eax
|
|
; NOBMI-NEXT: retq
|
|
;
|
|
; BMI-LABEL: cttz_32_eq_select_ffs_m1:
|
|
; BMI: # %bb.0:
|
|
; BMI-NEXT: tzcntl %edi, %ecx
|
|
; BMI-NEXT: movl $-1, %eax
|
|
; BMI-NEXT: cmovael %ecx, %eax
|
|
; BMI-NEXT: retq
|
|
|
|
%cnt = tail call i32 @llvm.cttz.i32(i32 %v, i1 true)
|
|
%tobool = icmp eq i32 %v, 0
|
|
%sel = select i1 %tobool, i32 -1, i32 %cnt
|
|
ret i32 %sel
|
|
}
|
|
|
|
define i32 @cttz_32_ne_select_ffs_m1(i32 %v) nounwind {
|
|
; NOBMI-LABEL: cttz_32_ne_select_ffs_m1:
|
|
; NOBMI: # %bb.0:
|
|
; NOBMI-NEXT: bsfl %edi, %ecx
|
|
; NOBMI-NEXT: movl $-1, %eax
|
|
; NOBMI-NEXT: cmovnel %ecx, %eax
|
|
; NOBMI-NEXT: retq
|
|
;
|
|
; BMI-LABEL: cttz_32_ne_select_ffs_m1:
|
|
; BMI: # %bb.0:
|
|
; BMI-NEXT: tzcntl %edi, %ecx
|
|
; BMI-NEXT: movl $-1, %eax
|
|
; BMI-NEXT: cmovael %ecx, %eax
|
|
; BMI-NEXT: retq
|
|
|
|
%cnt = tail call i32 @llvm.cttz.i32(i32 %v, i1 true)
|
|
%tobool = icmp ne i32 %v, 0
|
|
%sel = select i1 %tobool, i32 %cnt, i32 -1
|
|
ret i32 %sel
|
|
}
|