; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
; RUN: llc < %s -mtriple=i686-- -mattr=-bmi,+sse2 | FileCheck %s --check-prefixes=X86,X86-NOBMI
; RUN: llc < %s -mtriple=i686-- -mattr=+bmi,+sse2 | FileCheck %s --check-prefixes=X86,X86-BMI
; RUN: llc < %s -mtriple=x86_64-- -mattr=-bmi | FileCheck %s --check-prefixes=X64,X64-NOBMI
; RUN: llc < %s -mtriple=x86_64-- -mattr=+bmi | FileCheck %s --check-prefixes=X64,X64-BMI

declare void @use(i32)

define i32 @fold_and_xor_neg_v1_32(i32 %x, i32 %y) nounwind {
; X86-NOBMI-LABEL: fold_and_xor_neg_v1_32:
; X86-NOBMI:       # %bb.0:
; X86-NOBMI-NEXT:    movl {{[0-9]+}}(%esp), %ecx
; X86-NOBMI-NEXT:    movl %ecx, %eax
; X86-NOBMI-NEXT:    negl %eax
; X86-NOBMI-NEXT:    xorl %ecx, %eax
; X86-NOBMI-NEXT:    andl {{[0-9]+}}(%esp), %eax
; X86-NOBMI-NEXT:    retl
;
; X86-BMI-LABEL: fold_and_xor_neg_v1_32:
; X86-BMI:       # %bb.0:
; X86-BMI-NEXT:    blsmskl {{[0-9]+}}(%esp), %eax
; X86-BMI-NEXT:    andnl {{[0-9]+}}(%esp), %eax, %eax
; X86-BMI-NEXT:    retl
;
; X64-NOBMI-LABEL: fold_and_xor_neg_v1_32:
; X64-NOBMI:       # %bb.0:
; X64-NOBMI-NEXT:    movl %edi, %eax
; X64-NOBMI-NEXT:    negl %eax
; X64-NOBMI-NEXT:    xorl %edi, %eax
; X64-NOBMI-NEXT:    andl %esi, %eax
; X64-NOBMI-NEXT:    retq
;
; X64-BMI-LABEL: fold_and_xor_neg_v1_32:
; X64-BMI:       # %bb.0:
; X64-BMI-NEXT:    blsmskl %edi, %eax
; X64-BMI-NEXT:    andnl %esi, %eax, %eax
; X64-BMI-NEXT:    retq
  %neg = sub i32 0, %x
  %xor = xor i32 %x, %neg
  %and = and i32 %xor, %y
  ret i32 %and
}

define i32 @fold_and_xor_neg_v2_32(i32 %x, i32 %y) nounwind {
; X86-NOBMI-LABEL: fold_and_xor_neg_v2_32:
; X86-NOBMI:       # %bb.0:
; X86-NOBMI-NEXT:    movl {{[0-9]+}}(%esp), %ecx
; X86-NOBMI-NEXT:    movl %ecx, %eax
; X86-NOBMI-NEXT:    negl %eax
; X86-NOBMI-NEXT:    xorl %ecx, %eax
; X86-NOBMI-NEXT:    andl {{[0-9]+}}(%esp), %eax
; X86-NOBMI-NEXT:    retl
;
; X86-BMI-LABEL: fold_and_xor_neg_v2_32:
; X86-BMI:       # %bb.0:
; X86-BMI-NEXT:    blsmskl {{[0-9]+}}(%esp), %eax
; X86-BMI-NEXT:    andnl {{[0-9]+}}(%esp), %eax, %eax
; X86-BMI-NEXT:    retl
;
; X64-NOBMI-LABEL: fold_and_xor_neg_v2_32:
; X64-NOBMI:       # %bb.0:
; X64-NOBMI-NEXT:    movl %edi, %eax
; X64-NOBMI-NEXT:    negl %eax
; X64-NOBMI-NEXT:    xorl %edi, %eax
; X64-NOBMI-NEXT:    andl %esi, %eax
; X64-NOBMI-NEXT:    retq
;
; X64-BMI-LABEL: fold_and_xor_neg_v2_32:
; X64-BMI:       # %bb.0:
; X64-BMI-NEXT:    blsmskl %edi, %eax
; X64-BMI-NEXT:    andnl %esi, %eax, %eax
; X64-BMI-NEXT:    retq
  %neg = sub i32 0, %x
  %xor = xor i32 %x, %neg
  %and = and i32 %y, %xor
  ret i32 %and
}

define i32 @fold_and_xor_neg_v3_32(i32 %x, i32 %y) nounwind {
; X86-NOBMI-LABEL: fold_and_xor_neg_v3_32:
; X86-NOBMI:       # %bb.0:
; X86-NOBMI-NEXT:    movl {{[0-9]+}}(%esp), %ecx
; X86-NOBMI-NEXT:    movl %ecx, %eax
; X86-NOBMI-NEXT:    negl %eax
; X86-NOBMI-NEXT:    xorl %ecx, %eax
; X86-NOBMI-NEXT:    andl {{[0-9]+}}(%esp), %eax
; X86-NOBMI-NEXT:    retl
;
; X86-BMI-LABEL: fold_and_xor_neg_v3_32:
; X86-BMI:       # %bb.0:
; X86-BMI-NEXT:    blsmskl {{[0-9]+}}(%esp), %eax
; X86-BMI-NEXT:    andnl {{[0-9]+}}(%esp), %eax, %eax
; X86-BMI-NEXT:    retl
;
; X64-NOBMI-LABEL: fold_and_xor_neg_v3_32:
; X64-NOBMI:       # %bb.0:
; X64-NOBMI-NEXT:    movl %edi, %eax
; X64-NOBMI-NEXT:    negl %eax
; X64-NOBMI-NEXT:    xorl %edi, %eax
; X64-NOBMI-NEXT:    andl %esi, %eax
; X64-NOBMI-NEXT:    retq
;
; X64-BMI-LABEL: fold_and_xor_neg_v3_32:
; X64-BMI:       # %bb.0:
; X64-BMI-NEXT:    blsmskl %edi, %eax
; X64-BMI-NEXT:    andnl %esi, %eax, %eax
; X64-BMI-NEXT:    retq
  %neg = sub i32 0, %x
  %xor = xor i32 %neg, %x
  %and = and i32 %xor, %y
  ret i32 %and
}

define i32 @fold_and_xor_neg_v4_32(i32 %x, i32 %y) nounwind {
; X86-NOBMI-LABEL: fold_and_xor_neg_v4_32:
; X86-NOBMI:       # %bb.0:
; X86-NOBMI-NEXT:    movl {{[0-9]+}}(%esp), %ecx
; X86-NOBMI-NEXT:    movl %ecx, %eax
; X86-NOBMI-NEXT:    negl %eax
; X86-NOBMI-NEXT:    xorl %ecx, %eax
; X86-NOBMI-NEXT:    andl {{[0-9]+}}(%esp), %eax
; X86-NOBMI-NEXT:    retl
;
; X86-BMI-LABEL: fold_and_xor_neg_v4_32:
; X86-BMI:       # %bb.0:
; X86-BMI-NEXT:    blsmskl {{[0-9]+}}(%esp), %eax
; X86-BMI-NEXT:    andnl {{[0-9]+}}(%esp), %eax, %eax
; X86-BMI-NEXT:    retl
;
; X64-NOBMI-LABEL: fold_and_xor_neg_v4_32:
; X64-NOBMI:       # %bb.0:
; X64-NOBMI-NEXT:    movl %edi, %eax
; X64-NOBMI-NEXT:    negl %eax
; X64-NOBMI-NEXT:    xorl %edi, %eax
; X64-NOBMI-NEXT:    andl %esi, %eax
; X64-NOBMI-NEXT:    retq
;
; X64-BMI-LABEL: fold_and_xor_neg_v4_32:
; X64-BMI:       # %bb.0:
; X64-BMI-NEXT:    blsmskl %edi, %eax
; X64-BMI-NEXT:    andnl %esi, %eax, %eax
; X64-BMI-NEXT:    retq
  %neg = sub i32 0, %x
  %xor = xor i32 %neg, %x
  %and = and i32 %y, %xor
  ret i32 %and
}

define i64 @fold_and_xor_neg_v1_64(i64 %x, i64 %y) nounwind {
; X86-LABEL: fold_and_xor_neg_v1_64:
; 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:    xorl %esi, %edx
; X86-NEXT:    xorl %ecx, %eax
; X86-NEXT:    andl {{[0-9]+}}(%esp), %edx
; X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
; X86-NEXT:    popl %esi
; X86-NEXT:    retl
;
; X64-NOBMI-LABEL: fold_and_xor_neg_v1_64:
; X64-NOBMI:       # %bb.0:
; X64-NOBMI-NEXT:    movq %rdi, %rax
; X64-NOBMI-NEXT:    negq %rax
; X64-NOBMI-NEXT:    xorq %rdi, %rax
; X64-NOBMI-NEXT:    andq %rsi, %rax
; X64-NOBMI-NEXT:    retq
;
; X64-BMI-LABEL: fold_and_xor_neg_v1_64:
; X64-BMI:       # %bb.0:
; X64-BMI-NEXT:    blsmskq %rdi, %rax
; X64-BMI-NEXT:    andnq %rsi, %rax, %rax
; X64-BMI-NEXT:    retq
  %neg = sub i64 0, %x
  %xor = xor i64 %x, %neg
  %and = and i64 %xor, %y
  ret i64 %and
}

; Negative test
define i16 @fold_and_xor_neg_v1_16_negative(i16 %x, i16 %y) nounwind {
; X86-LABEL: fold_and_xor_neg_v1_16_negative:
; X86:       # %bb.0:
; X86-NEXT:    movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT:    movl %ecx, %eax
; X86-NEXT:    negl %eax
; X86-NEXT:    xorl %ecx, %eax
; X86-NEXT:    andw {{[0-9]+}}(%esp), %ax
; X86-NEXT:    # kill: def $ax killed $ax killed $eax
; X86-NEXT:    retl
;
; X64-LABEL: fold_and_xor_neg_v1_16_negative:
; X64:       # %bb.0:
; X64-NEXT:    movl %edi, %eax
; X64-NEXT:    negl %eax
; X64-NEXT:    xorl %edi, %eax
; X64-NEXT:    andl %esi, %eax
; X64-NEXT:    # kill: def $ax killed $ax killed $eax
; X64-NEXT:    retq
  %neg = sub i16 0, %x
  %xor = xor i16 %x, %neg
  %and = and i16 %xor, %y
  ret i16 %and
}

; Negative test
define <4 x i32> @fold_and_xor_neg_v1_v4x32_negative(<4 x i32> %x, <4 x i32> %y) nounwind {
; X86-LABEL: fold_and_xor_neg_v1_v4x32_negative:
; X86:       # %bb.0:
; X86-NEXT:    pxor %xmm2, %xmm2
; X86-NEXT:    psubd %xmm0, %xmm2
; X86-NEXT:    pxor %xmm2, %xmm0
; X86-NEXT:    pand %xmm1, %xmm0
; X86-NEXT:    retl
;
; X64-LABEL: fold_and_xor_neg_v1_v4x32_negative:
; X64:       # %bb.0:
; X64-NEXT:    pxor %xmm2, %xmm2
; X64-NEXT:    psubd %xmm0, %xmm2
; X64-NEXT:    pxor %xmm2, %xmm0
; X64-NEXT:    pand %xmm1, %xmm0
; X64-NEXT:    retq
  %neg = sub <4 x i32> zeroinitializer, %x
  %xor = xor <4 x i32> %x, %neg
  %and = and <4 x i32> %xor, %y
  ret <4 x i32> %and
}

; Negative test
define i32 @fold_and_xor_neg_v1_32_two_uses_xor_negative(i32 %x, i32 %y) nounwind {
; X86-LABEL: fold_and_xor_neg_v1_32_two_uses_xor_negative:
; X86:       # %bb.0:
; X86-NEXT:    pushl %esi
; X86-NEXT:    movl {{[0-9]+}}(%esp), %eax
; X86-NEXT:    movl %eax, %ecx
; X86-NEXT:    negl %ecx
; X86-NEXT:    xorl %eax, %ecx
; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
; X86-NEXT:    andl %ecx, %esi
; X86-NEXT:    pushl %ecx
; X86-NEXT:    calll use@PLT
; X86-NEXT:    addl $4, %esp
; X86-NEXT:    movl %esi, %eax
; X86-NEXT:    popl %esi
; X86-NEXT:    retl
;
; X64-LABEL: fold_and_xor_neg_v1_32_two_uses_xor_negative:
; X64:       # %bb.0:
; X64-NEXT:    pushq %rbx
; X64-NEXT:    movl %esi, %ebx
; X64-NEXT:    movl %edi, %eax
; X64-NEXT:    negl %eax
; X64-NEXT:    xorl %eax, %edi
; X64-NEXT:    andl %edi, %ebx
; X64-NEXT:    callq use@PLT
; X64-NEXT:    movl %ebx, %eax
; X64-NEXT:    popq %rbx
; X64-NEXT:    retq
  %neg = sub i32 0, %x
  %xor = xor i32 %x, %neg
  %and = and i32 %xor, %y
  call void @use(i32 %xor)
  ret i32 %and
}

; Negative test
define i32 @fold_and_xor_neg_v1_32_two_uses_sub_negative(i32 %x, i32 %y) nounwind {
; X86-LABEL: fold_and_xor_neg_v1_32_two_uses_sub_negative:
; X86:       # %bb.0:
; X86-NEXT:    pushl %esi
; X86-NEXT:    movl {{[0-9]+}}(%esp), %esi
; X86-NEXT:    movl %esi, %eax
; X86-NEXT:    negl %eax
; X86-NEXT:    xorl %eax, %esi
; X86-NEXT:    andl {{[0-9]+}}(%esp), %esi
; X86-NEXT:    pushl %eax
; X86-NEXT:    calll use@PLT
; X86-NEXT:    addl $4, %esp
; X86-NEXT:    movl %esi, %eax
; X86-NEXT:    popl %esi
; X86-NEXT:    retl
;
; X64-LABEL: fold_and_xor_neg_v1_32_two_uses_sub_negative:
; X64:       # %bb.0:
; X64-NEXT:    pushq %rbx
; X64-NEXT:    movl %edi, %ebx
; X64-NEXT:    negl %edi
; X64-NEXT:    xorl %edi, %ebx
; X64-NEXT:    andl %esi, %ebx
; X64-NEXT:    callq use@PLT
; X64-NEXT:    movl %ebx, %eax
; X64-NEXT:    popq %rbx
; X64-NEXT:    retq
  %neg = sub i32 0, %x
  %xor = xor i32 %x, %neg
  %and = and i32 %xor, %y
  call void @use(i32 %neg)
  ret i32 %and
}

; Negative test
define i32 @fold_and_xor_neg_v1_32_no_blsmsk_negative(i32 %x, i32 %y, i32 %z) nounwind {
; X86-LABEL: fold_and_xor_neg_v1_32_no_blsmsk_negative:
; X86:       # %bb.0:
; X86-NEXT:    xorl %eax, %eax
; X86-NEXT:    subl {{[0-9]+}}(%esp), %eax
; X86-NEXT:    xorl {{[0-9]+}}(%esp), %eax
; X86-NEXT:    andl {{[0-9]+}}(%esp), %eax
; X86-NEXT:    retl
;
; X64-LABEL: fold_and_xor_neg_v1_32_no_blsmsk_negative:
; X64:       # %bb.0:
; X64-NEXT:    movl %edx, %eax
; X64-NEXT:    negl %eax
; X64-NEXT:    xorl %edi, %eax
; X64-NEXT:    andl %esi, %eax
; X64-NEXT:    retq
  %neg = sub i32 0, %z
  %xor = xor i32 %x, %neg
  %and = and i32 %xor, %y
  ret i32 %and
}
