| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+cmov,+sse2,+bmi | FileCheck %s --check-prefixes=X86 |
| ; RUN: llc < %s -mtriple=i686-unknown-unknown -mattr=+cmov,+sse2,+bmi,+bmi2 | FileCheck %s --check-prefixes=X86 |
| ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+bmi | FileCheck %s --check-prefixes=X64 |
| ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+bmi,+bmi2 | FileCheck %s --check-prefixes=X64 |
| |
| ; PR131587 |
| define i32 @and_select_neg_to_blsi1(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_neg_to_blsi1: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsil %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_neg_to_blsi1: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsil %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = sub i32 0, %a1 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; PR131587 |
| define i32 @and_select_neg_to_blsi2(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_neg_to_blsi2: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsil %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_neg_to_blsi2: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsil %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = sub i32 0, %a1 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = and i32 %bls, %a1 |
| ret i32 %ret |
| } |
| |
| ; PR131587 |
| define i32 @and_select_neg_to_blsi3(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_neg_to_blsi3: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsil %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_neg_to_blsi3: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsil %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovnel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = sub i32 0, %a1 |
| %bls = select i1 %a0, i32 -1, i32 %sub |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; PR131587 |
| define i64 @and_select_neg_to_blsi_i64(i1 %a0, i64 %a1) nounwind { |
| ; X86-LABEL: and_select_neg_to_blsi_i64: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pushl %esi |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %esi |
| ; X86-NEXT: xorl %edx, %edx |
| ; X86-NEXT: movl %ecx, %eax |
| ; X86-NEXT: negl %eax |
| ; X86-NEXT: sbbl %esi, %edx |
| ; X86-NEXT: andl %esi, %edx |
| ; X86-NEXT: andl %ecx, %eax |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovel %esi, %edx |
| ; X86-NEXT: cmovel %ecx, %eax |
| ; X86-NEXT: popl %esi |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_neg_to_blsi_i64: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsiq %rsi, %rax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmoveq %rsi, %rax |
| ; X64-NEXT: retq |
| %sub = sub i64 0, %a1 |
| %bls = select i1 %a0, i64 %sub, i64 -1 |
| %ret = and i64 %a1, %bls |
| ret i64 %ret |
| } |
| |
| ; The transformation also applies to the following test although we do not emit a BLSI instruction |
| ; here because the negation instruction is used more than once. |
| define i32 @and_neg_select_pos_i32(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_neg_select_pos_i32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl %eax, %ecx |
| ; X86-NEXT: negl %ecx |
| ; X86-NEXT: andl %ecx, %eax |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_neg_select_pos_i32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: movl %esi, %eax |
| ; X64-NEXT: negl %eax |
| ; X64-NEXT: andl %eax, %esi |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovnel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = sub i32 0, %a1 |
| %bls = select i1 %a0, i32 %a1, i32 -1 |
| %ret = and i32 %sub, %bls |
| ret i32 %ret |
| } |
| |
| ; Negative test |
| define i16 @and_select_neg_i16(i1 %a0, i16 %a1) nounwind { |
| ; X86-LABEL: and_select_neg_i16: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pushl %esi |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: andb $1, %cl |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %edx |
| ; X86-NEXT: movl %edx, %esi |
| ; X86-NEXT: negl %esi |
| ; X86-NEXT: xorl %eax, %eax |
| ; X86-NEXT: cmpb $1, %cl |
| ; X86-NEXT: sbbl %eax, %eax |
| ; X86-NEXT: orl %esi, %eax |
| ; X86-NEXT: andl %edx, %eax |
| ; X86-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X86-NEXT: popl %esi |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_neg_i16: |
| ; X64: # %bb.0: |
| ; X64-NEXT: andb $1, %dil |
| ; X64-NEXT: movl %esi, %ecx |
| ; X64-NEXT: negl %ecx |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: cmpb $1, %dil |
| ; X64-NEXT: sbbl %eax, %eax |
| ; X64-NEXT: orl %ecx, %eax |
| ; X64-NEXT: andl %esi, %eax |
| ; X64-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X64-NEXT: retq |
| %sub = sub i16 0, %a1 |
| %bls = select i1 %a0, i16 %sub, i16 -1 |
| %ret = and i16 %a1, %bls |
| ret i16 %ret |
| } |
| |
| ; Negative test |
| define <4 x i32> @and_select_neg_v4xi32(i1 %a0, <4 x i32> %a1) nounwind { |
| ; X86-LABEL: and_select_neg_v4xi32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: jne .LBB6_1 |
| ; X86-NEXT: # %bb.2: |
| ; X86-NEXT: pcmpeqd %xmm1, %xmm1 |
| ; X86-NEXT: pand %xmm1, %xmm0 |
| ; X86-NEXT: retl |
| ; X86-NEXT: .LBB6_1: |
| ; X86-NEXT: pxor %xmm1, %xmm1 |
| ; X86-NEXT: psubd %xmm0, %xmm1 |
| ; X86-NEXT: pand %xmm1, %xmm0 |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_neg_v4xi32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: jne .LBB6_1 |
| ; X64-NEXT: # %bb.2: |
| ; X64-NEXT: pcmpeqd %xmm1, %xmm1 |
| ; X64-NEXT: pand %xmm1, %xmm0 |
| ; X64-NEXT: retq |
| ; X64-NEXT: .LBB6_1: |
| ; X64-NEXT: pxor %xmm1, %xmm1 |
| ; X64-NEXT: psubd %xmm0, %xmm1 |
| ; X64-NEXT: pand %xmm1, %xmm0 |
| ; X64-NEXT: retq |
| %sub = sub <4 x i32> zeroinitializer, %a1 |
| %bls = select i1 %a0, <4 x i32> %sub, <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1> |
| %ret = and <4 x i32> %a1, %bls |
| ret <4 x i32> %ret |
| } |
| |
| ; Negative test |
| define i32 @and_select_no_neg(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_no_neg: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: andb $1, %cl |
| ; X86-NEXT: xorl %edx, %edx |
| ; X86-NEXT: cmpb $1, %cl |
| ; X86-NEXT: sbbl %edx, %edx |
| ; X86-NEXT: orl %eax, %edx |
| ; X86-NEXT: andl %edx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_no_neg: |
| ; X64: # %bb.0: |
| ; X64-NEXT: andb $1, %dil |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: cmpb $1, %dil |
| ; X64-NEXT: sbbl %eax, %eax |
| ; X64-NEXT: orl %esi, %eax |
| ; X64-NEXT: andl %esi, %eax |
| ; X64-NEXT: retq |
| %sub = sub i32 %a1, 0 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; Negative test |
| define i32 @and_select_neg_wrong_const(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_neg_wrong_const: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl %eax, %ecx |
| ; X86-NEXT: negl %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: movl $1, %edx |
| ; X86-NEXT: cmovnel %ecx, %edx |
| ; X86-NEXT: andl %edx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_neg_wrong_const: |
| ; X64: # %bb.0: |
| ; X64-NEXT: movl %esi, %ecx |
| ; X64-NEXT: negl %ecx |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: movl $1, %eax |
| ; X64-NEXT: cmovnel %ecx, %eax |
| ; X64-NEXT: andl %esi, %eax |
| ; X64-NEXT: retq |
| %sub = sub i32 0, %a1 |
| %bls = select i1 %a0, i32 %sub, i32 1 |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; Negative test |
| define i32 @and_select_neg_different_op(i1 %a0, i32 inreg %a1, i32 inreg %a2) nounwind { |
| ; X86-LABEL: and_select_neg_different_op: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pushl %esi |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: andb $1, %cl |
| ; X86-NEXT: negl %edx |
| ; X86-NEXT: xorl %esi, %esi |
| ; X86-NEXT: cmpb $1, %cl |
| ; X86-NEXT: sbbl %esi, %esi |
| ; X86-NEXT: orl %edx, %esi |
| ; X86-NEXT: andl %esi, %eax |
| ; X86-NEXT: popl %esi |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_neg_different_op: |
| ; X64: # %bb.0: |
| ; X64-NEXT: andb $1, %dil |
| ; X64-NEXT: negl %edx |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: cmpb $1, %dil |
| ; X64-NEXT: sbbl %eax, %eax |
| ; X64-NEXT: orl %edx, %eax |
| ; X64-NEXT: andl %esi, %eax |
| ; X64-NEXT: retq |
| %sub = sub i32 0, %a2 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; PR133848 |
| define i32 @and_select_sub_1_to_blsr1(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_sub_1_to_blsr1: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsrl %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_sub_1_to_blsr1: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsrl %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; PR133848 |
| define i32 @and_select_sub_1_to_blsr2(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_sub_1_to_blsr2: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsrl %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_sub_1_to_blsr2: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsrl %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = and i32 %bls, %a1 |
| ret i32 %ret |
| } |
| |
| ; PR133848 |
| define i32 @and_select_sub_1_to_blsr3(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_sub_1_to_blsr3: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsrl %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_sub_1_to_blsr3: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsrl %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovnel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 -1, i32 %sub |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; PR133848 |
| define i32 @and_select_sub_1_to_blsr4(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_sub_1_to_blsr4: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsrl %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_sub_1_to_blsr4: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsrl %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = sub i32 %a1, 1 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; The transformation also applies to the following test although we do not emit a BLSR instruction |
| ; here because the subtraction instruction is used more than once. |
| define i32 @and_sub_1_select_orig(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_sub_1_select_orig: |
| ; X86: # %bb.0: |
| ; X86-NEXT: leal -1(%eax), %ecx |
| ; X86-NEXT: andl %ecx, %eax |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_sub_1_select_orig: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $esi killed $esi def $rsi |
| ; X64-NEXT: leal -1(%rsi), %eax |
| ; X64-NEXT: andl %eax, %esi |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovnel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 %a1, i32 -1 |
| %ret = and i32 %sub, %bls |
| ret i32 %ret |
| } |
| |
| ; PR133848 |
| define i64 @and_select_sub_1_to_blsr_i64(i1 %a0, i64 %a1) nounwind { |
| ; X86-LABEL: and_select_sub_1_to_blsr_i64: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pushl %esi |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %esi |
| ; X86-NEXT: movl %ecx, %eax |
| ; X86-NEXT: addl $-1, %eax |
| ; X86-NEXT: movl %esi, %edx |
| ; X86-NEXT: adcl $-1, %edx |
| ; X86-NEXT: andl %esi, %edx |
| ; X86-NEXT: andl %ecx, %eax |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovel %ecx, %eax |
| ; X86-NEXT: cmovel %esi, %edx |
| ; X86-NEXT: popl %esi |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_sub_1_to_blsr_i64: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsrq %rsi, %rax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmoveq %rsi, %rax |
| ; X64-NEXT: retq |
| %sub = add i64 %a1, -1 |
| %bls = select i1 %a0, i64 %sub, i64 -1 |
| %ret = and i64 %a1, %bls |
| ret i64 %ret |
| } |
| |
| ; Negative test |
| define i16 @and_select_sub_1_i16(i1 %a0, i16 %a1) nounwind { |
| ; X86-LABEL: and_select_sub_1_i16: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pushl %esi |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: andb $1, %cl |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %edx |
| ; X86-NEXT: leal -1(%edx), %esi |
| ; X86-NEXT: xorl %eax, %eax |
| ; X86-NEXT: cmpb $1, %cl |
| ; X86-NEXT: sbbl %eax, %eax |
| ; X86-NEXT: orl %esi, %eax |
| ; X86-NEXT: andl %edx, %eax |
| ; X86-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X86-NEXT: popl %esi |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_sub_1_i16: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $esi killed $esi def $rsi |
| ; X64-NEXT: andb $1, %dil |
| ; X64-NEXT: leal -1(%rsi), %ecx |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: cmpb $1, %dil |
| ; X64-NEXT: sbbl %eax, %eax |
| ; X64-NEXT: orl %ecx, %eax |
| ; X64-NEXT: andl %esi, %eax |
| ; X64-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X64-NEXT: retq |
| %sub = add i16 %a1, -1 |
| %bls = select i1 %a0, i16 %sub, i16 -1 |
| %ret = and i16 %a1, %bls |
| ret i16 %ret |
| } |
| |
| ; Negative test |
| define <4 x i32> @and_select_sub_1_v4xi32(i1 %a0, <4 x i32> %a1) nounwind { |
| ; X86-LABEL: and_select_sub_1_v4xi32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pcmpeqd %xmm1, %xmm1 |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: je .LBB17_2 |
| ; X86-NEXT: # %bb.1: |
| ; X86-NEXT: paddd %xmm0, %xmm1 |
| ; X86-NEXT: .LBB17_2: |
| ; X86-NEXT: pand %xmm1, %xmm0 |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_sub_1_v4xi32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: pcmpeqd %xmm1, %xmm1 |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: je .LBB17_2 |
| ; X64-NEXT: # %bb.1: |
| ; X64-NEXT: paddd %xmm0, %xmm1 |
| ; X64-NEXT: .LBB17_2: |
| ; X64-NEXT: pand %xmm1, %xmm0 |
| ; X64-NEXT: retq |
| %sub = add <4 x i32> %a1, <i32 -1, i32 -1, i32 -1, i32 -1> |
| %bls = select i1 %a0, <4 x i32> %sub, <4 x i32> <i32 -1, i32 -1, i32 -1, i32 -1> |
| %ret = and <4 x i32> %a1, %bls |
| ret <4 x i32> %ret |
| } |
| |
| ; Negative test |
| define i32 @and_select_no_sub_1(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_no_sub_1: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pushl %esi |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: andb $1, %cl |
| ; X86-NEXT: leal -2(%eax), %edx |
| ; X86-NEXT: xorl %esi, %esi |
| ; X86-NEXT: cmpb $1, %cl |
| ; X86-NEXT: sbbl %esi, %esi |
| ; X86-NEXT: orl %edx, %esi |
| ; X86-NEXT: andl %esi, %eax |
| ; X86-NEXT: popl %esi |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_no_sub_1: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $esi killed $esi def $rsi |
| ; X64-NEXT: andb $1, %dil |
| ; X64-NEXT: leal -2(%rsi), %ecx |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: cmpb $1, %dil |
| ; X64-NEXT: sbbl %eax, %eax |
| ; X64-NEXT: orl %ecx, %eax |
| ; X64-NEXT: andl %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -2 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; Negative test |
| define i32 @and_select_sub_1_wrong_const(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: and_select_sub_1_wrong_const: |
| ; X86: # %bb.0: |
| ; X86-NEXT: leal -1(%eax), %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: movl $1, %edx |
| ; X86-NEXT: cmovnel %ecx, %edx |
| ; X86-NEXT: andl %edx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_sub_1_wrong_const: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $esi killed $esi def $rsi |
| ; X64-NEXT: leal -1(%rsi), %ecx |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: movl $1, %eax |
| ; X64-NEXT: cmovnel %ecx, %eax |
| ; X64-NEXT: andl %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 %sub, i32 1 |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; Negative test |
| define i32 @and_select_sub_1_different_op(i1 %a0, i32 inreg %a1, i32 inreg %a2) nounwind { |
| ; X86-LABEL: and_select_sub_1_different_op: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pushl %esi |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: andb $1, %cl |
| ; X86-NEXT: decl %edx |
| ; X86-NEXT: xorl %esi, %esi |
| ; X86-NEXT: cmpb $1, %cl |
| ; X86-NEXT: sbbl %esi, %esi |
| ; X86-NEXT: orl %edx, %esi |
| ; X86-NEXT: andl %esi, %eax |
| ; X86-NEXT: popl %esi |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: and_select_sub_1_different_op: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edx killed $edx def $rdx |
| ; X64-NEXT: andb $1, %dil |
| ; X64-NEXT: leal -1(%rdx), %ecx |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: cmpb $1, %dil |
| ; X64-NEXT: sbbl %eax, %eax |
| ; X64-NEXT: orl %ecx, %eax |
| ; X64-NEXT: andl %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a2, -1 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = and i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| define i32 @xor_select_sub_1_to_blsmsk1(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: xor_select_sub_1_to_blsmsk1: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsmskl %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_sub_1_to_blsmsk1: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsmskl %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 %sub, i32 0 |
| %ret = xor i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| define i32 @xor_select_sub_1_to_blsmsk2(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: xor_select_sub_1_to_blsmsk2: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsmskl %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_sub_1_to_blsmsk2: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsmskl %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 %sub, i32 0 |
| %ret = xor i32 %bls, %a1 |
| ret i32 %ret |
| } |
| |
| define i32 @xor_select_sub_1_to_blsmsk3(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: xor_select_sub_1_to_blsmsk3: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsmskl %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_sub_1_to_blsmsk3: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsmskl %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovnel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 0, i32 %sub |
| %ret = xor i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| define i32 @xor_select_sub_1_to_blsmsk4(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: xor_select_sub_1_to_blsmsk4: |
| ; X86: # %bb.0: |
| ; X86-NEXT: blsmskl %eax, %ecx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_sub_1_to_blsmsk4: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsmskl %esi, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = sub i32 %a1, 1 |
| %bls = select i1 %a0, i32 %sub, i32 0 |
| %ret = xor i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; The transformation also applies to the following test although we do not emit a BLSMSK instruction |
| ; here because the subtraction instruction is used more than once. |
| define i32 @xor_sub_1_select_orig(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: xor_sub_1_select_orig: |
| ; X86: # %bb.0: |
| ; X86-NEXT: leal -1(%eax), %ecx |
| ; X86-NEXT: xorl %ecx, %eax |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovel %ecx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_sub_1_select_orig: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $esi killed $esi def $rsi |
| ; X64-NEXT: leal -1(%rsi), %eax |
| ; X64-NEXT: xorl %eax, %esi |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovnel %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 %a1, i32 0 |
| %ret = xor i32 %sub, %bls |
| ret i32 %ret |
| } |
| |
| define i64 @xor_select_sub_1_to_blsmsk_i64(i1 %a0, i64 %a1) nounwind { |
| ; X86-LABEL: xor_select_sub_1_to_blsmsk_i64: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pushl %esi |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %esi |
| ; X86-NEXT: movl %ecx, %eax |
| ; X86-NEXT: addl $-1, %eax |
| ; X86-NEXT: movl %esi, %edx |
| ; X86-NEXT: adcl $-1, %edx |
| ; X86-NEXT: xorl %esi, %edx |
| ; X86-NEXT: xorl %ecx, %eax |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovel %ecx, %eax |
| ; X86-NEXT: cmovel %esi, %edx |
| ; X86-NEXT: popl %esi |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_sub_1_to_blsmsk_i64: |
| ; X64: # %bb.0: |
| ; X64-NEXT: blsmskq %rsi, %rax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmoveq %rsi, %rax |
| ; X64-NEXT: retq |
| %sub = add i64 %a1, -1 |
| %bls = select i1 %a0, i64 %sub, i64 0 |
| %ret = xor i64 %a1, %bls |
| ret i64 %ret |
| } |
| |
| ; Negative test |
| define i16 @xor_select_sub_1_i16(i1 %a0, i16 %a1) nounwind { |
| ; X86-LABEL: xor_select_sub_1_i16: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: leal -1(%ecx), %edx |
| ; X86-NEXT: xorl %eax, %eax |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %edx, %eax |
| ; X86-NEXT: xorl %ecx, %eax |
| ; X86-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_sub_1_i16: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $esi killed $esi def $rsi |
| ; X64-NEXT: leal -1(%rsi), %ecx |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovnel %ecx, %eax |
| ; X64-NEXT: xorl %esi, %eax |
| ; X64-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X64-NEXT: retq |
| %sub = add i16 %a1, -1 |
| %bls = select i1 %a0, i16 %sub, i16 0 |
| %ret = xor i16 %a1, %bls |
| ret i16 %ret |
| } |
| |
| ; Negative test |
| define <4 x i32> @xor_select_sub_1_v4xi32(i1 %a0, <4 x i32> %a1) nounwind { |
| ; X86-LABEL: xor_select_sub_1_v4xi32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: jne .LBB28_1 |
| ; X86-NEXT: # %bb.2: |
| ; X86-NEXT: xorps %xmm1, %xmm1 |
| ; X86-NEXT: xorps %xmm1, %xmm0 |
| ; X86-NEXT: retl |
| ; X86-NEXT: .LBB28_1: |
| ; X86-NEXT: pcmpeqd %xmm1, %xmm1 |
| ; X86-NEXT: paddd %xmm0, %xmm1 |
| ; X86-NEXT: pxor %xmm1, %xmm0 |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_sub_1_v4xi32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: jne .LBB28_1 |
| ; X64-NEXT: # %bb.2: |
| ; X64-NEXT: xorps %xmm1, %xmm1 |
| ; X64-NEXT: xorps %xmm1, %xmm0 |
| ; X64-NEXT: retq |
| ; X64-NEXT: .LBB28_1: |
| ; X64-NEXT: pcmpeqd %xmm1, %xmm1 |
| ; X64-NEXT: paddd %xmm0, %xmm1 |
| ; X64-NEXT: pxor %xmm1, %xmm0 |
| ; X64-NEXT: retq |
| %sub = add <4 x i32> %a1, <i32 -1, i32 -1, i32 -1, i32 -1> |
| %bls = select i1 %a0, <4 x i32> %sub, <4 x i32> zeroinitializer |
| %ret = xor <4 x i32> %a1, %bls |
| ret <4 x i32> %ret |
| } |
| |
| ; Negative test |
| define i32 @xor_select_no_sub_1(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: xor_select_no_sub_1: |
| ; X86: # %bb.0: |
| ; X86-NEXT: leal 1(%eax), %ecx |
| ; X86-NEXT: xorl %edx, %edx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %edx |
| ; X86-NEXT: xorl %edx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_no_sub_1: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $esi killed $esi def $rsi |
| ; X64-NEXT: leal 1(%rsi), %ecx |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovnel %ecx, %eax |
| ; X64-NEXT: xorl %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, 1 |
| %bls = select i1 %a0, i32 %sub, i32 0 |
| %ret = xor i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; Negative test |
| define i32 @xor_select_sub_1_wrong_const(i1 %a0, i32 inreg %a1) nounwind { |
| ; X86-LABEL: xor_select_sub_1_wrong_const: |
| ; X86: # %bb.0: |
| ; X86-NEXT: pushl %esi |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %ecx |
| ; X86-NEXT: andb $1, %cl |
| ; X86-NEXT: leal -1(%eax), %edx |
| ; X86-NEXT: xorl %esi, %esi |
| ; X86-NEXT: cmpb $1, %cl |
| ; X86-NEXT: sbbl %esi, %esi |
| ; X86-NEXT: orl %edx, %esi |
| ; X86-NEXT: xorl %esi, %eax |
| ; X86-NEXT: popl %esi |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_sub_1_wrong_const: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $esi killed $esi def $rsi |
| ; X64-NEXT: andb $1, %dil |
| ; X64-NEXT: leal -1(%rsi), %ecx |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: cmpb $1, %dil |
| ; X64-NEXT: sbbl %eax, %eax |
| ; X64-NEXT: orl %ecx, %eax |
| ; X64-NEXT: xorl %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a1, -1 |
| %bls = select i1 %a0, i32 %sub, i32 -1 |
| %ret = xor i32 %a1, %bls |
| ret i32 %ret |
| } |
| |
| ; Negative test |
| define i32 @xor_select_sub_1_different_op(i1 %a0, i32 inreg %a1, i32 inreg %a2) nounwind { |
| ; X86-LABEL: xor_select_sub_1_different_op: |
| ; X86: # %bb.0: |
| ; X86-NEXT: leal -1(%edx), %ecx |
| ; X86-NEXT: xorl %edx, %edx |
| ; X86-NEXT: testb $1, {{[0-9]+}}(%esp) |
| ; X86-NEXT: cmovnel %ecx, %edx |
| ; X86-NEXT: xorl %edx, %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_select_sub_1_different_op: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edx killed $edx def $rdx |
| ; X64-NEXT: leal -1(%rdx), %ecx |
| ; X64-NEXT: xorl %eax, %eax |
| ; X64-NEXT: testb $1, %dil |
| ; X64-NEXT: cmovnel %ecx, %eax |
| ; X64-NEXT: xorl %esi, %eax |
| ; X64-NEXT: retq |
| %sub = add i32 %a2, -1 |
| %bls = select i1 %a0, i32 %sub, i32 0 |
| %ret = xor i32 %a1, %bls |
| ret i32 %ret |
| } |