| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py |
| ; RUN: llc < %s -mtriple=i686-unknown-unknown | FileCheck %s --check-prefixes=X86 |
| ; RUN: llc < %s -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefixes=X64 |
| ; RUN: llc < %s -mtriple=x86_64-unknown-unknown -mattr=+bmi | FileCheck %s --check-prefixes=X64 |
| |
| ; PR52267 |
| ; InstCombine transforms an 'add' with min-signed-value into an 'xor'. |
| ; LEA instruction selection should be able to see through that |
| ; transform and reduce add/shift/xor instruction counts and moves. |
| |
| ; |
| ; XOR(X,MIN_SIGNED_VALUE) |
| ; |
| |
| define i8 @xor_sminval_i8(i8 %x) { |
| ; X86-LABEL: xor_sminval_i8: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: addb $-128, %al |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_sminval_i8: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal -128(%rdi), %eax |
| ; X64-NEXT: # kill: def $al killed $al killed $eax |
| ; X64-NEXT: retq |
| %r = xor i8 %x, 128 |
| ret i8 %r |
| } |
| |
| ; negative test |
| define i8 @xor_notsminval_i8(i8 %x) { |
| ; X86-LABEL: xor_notsminval_i8: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: xorb $127, %al |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_notsminval_i8: |
| ; X64: # %bb.0: |
| ; X64-NEXT: movl %edi, %eax |
| ; X64-NEXT: xorb $127, %al |
| ; X64-NEXT: # kill: def $al killed $al killed $eax |
| ; X64-NEXT: retq |
| %r = xor i8 %x, 127 |
| ret i8 %r |
| } |
| |
| define i16 @xor_sminval_i16(i16 %x) { |
| ; X86-LABEL: xor_sminval_i16: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl $32768, %eax # imm = 0x8000 |
| ; X86-NEXT: xorl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_sminval_i16: |
| ; X64: # %bb.0: |
| ; X64-NEXT: movl %edi, %eax |
| ; X64-NEXT: xorl $32768, %eax # imm = 0x8000 |
| ; X64-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X64-NEXT: retq |
| %r = xor i16 %x, 32768 |
| ret i16 %r |
| } |
| |
| define i32 @xor_sminval_i32(i32 %x) { |
| ; X86-LABEL: xor_sminval_i32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl $-2147483648, %eax # imm = 0x80000000 |
| ; X86-NEXT: xorl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_sminval_i32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal -2147483648(%rdi), %eax |
| ; X64-NEXT: retq |
| %r = xor i32 %x, 2147483648 |
| ret i32 %r |
| } |
| |
| ; negative test |
| define i32 @xor_notsminval_i32(i32 %x) { |
| ; X86-LABEL: xor_notsminval_i32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl $32768, %eax # imm = 0x8000 |
| ; X86-NEXT: xorl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_notsminval_i32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: movl %edi, %eax |
| ; X64-NEXT: xorl $32768, %eax # imm = 0x8000 |
| ; X64-NEXT: retq |
| %r = xor i32 %x, 32768 |
| ret i32 %r |
| } |
| |
| define i64 @xor_sminval_i64(i64 %x) { |
| ; X86-LABEL: xor_sminval_i64: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: movl $-2147483648, %edx # imm = 0x80000000 |
| ; X86-NEXT: xorl {{[0-9]+}}(%esp), %edx |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_sminval_i64: |
| ; X64: # %bb.0: |
| ; X64-NEXT: movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000 |
| ; X64-NEXT: xorq %rdi, %rax |
| ; X64-NEXT: retq |
| %r = xor i64 %x, -9223372036854775808 |
| ret i64 %r |
| } |
| |
| ; |
| ; XOR(ADD/SUB(X,C),MIN_SIGNED_VALUE) |
| ; |
| |
| define i8 @xor_add_sminval_i8(i8 %x, i8 %y) { |
| ; X86-LABEL: xor_add_sminval_i8: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: addb {{[0-9]+}}(%esp), %al |
| ; X86-NEXT: addb $-128, %al |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_add_sminval_i8: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $esi killed $esi def $rsi |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal (%rdi,%rsi), %eax |
| ; X64-NEXT: addb $-128, %al |
| ; X64-NEXT: # kill: def $al killed $al killed $eax |
| ; X64-NEXT: retq |
| %s = add i8 %x, %y |
| %r = xor i8 %s, 128 |
| ret i8 %r |
| } |
| |
| define i16 @xor_sub_sminval_i16(i16 %x) { |
| ; X86-LABEL: xor_sub_sminval_i16: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl $32766, %eax # imm = 0x7FFE |
| ; X86-NEXT: addl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_sub_sminval_i16: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal 32766(%rdi), %eax |
| ; X64-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X64-NEXT: retq |
| %s = sub i16 %x, 2 |
| %r = xor i16 %s, 32768 |
| ret i16 %r |
| } |
| |
| define i32 @xor_add_sminval_i32(i32 %x) { |
| ; X86-LABEL: xor_add_sminval_i32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl $-2147483136, %eax # imm = 0x80000200 |
| ; X86-NEXT: addl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_add_sminval_i32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal -2147483136(%rdi), %eax |
| ; X64-NEXT: retq |
| %s = add i32 %x, 512 |
| %r = xor i32 %s, 2147483648 |
| ret i32 %r |
| } |
| |
| define i64 @xor_add_sminval_i64(i64 %x, i64 %y) { |
| ; X86-LABEL: xor_add_sminval_i64: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %edx |
| ; X86-NEXT: addl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: adcl {{[0-9]+}}(%esp), %edx |
| ; X86-NEXT: addl $-2147483648, %edx # imm = 0x80000000 |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_add_sminval_i64: |
| ; X64: # %bb.0: |
| ; X64-NEXT: leaq (%rdi,%rsi), %rcx |
| ; X64-NEXT: movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000 |
| ; X64-NEXT: xorq %rcx, %rax |
| ; X64-NEXT: retq |
| %s = add i64 %x, %y |
| %r = xor i64 %s, -9223372036854775808 |
| ret i64 %r |
| } |
| |
| ; |
| ; ADD/SUB(XOR(X,MIN_SIGNED_VALUE),C) |
| ; |
| |
| define i8 @sub_xor_sminval_i8(i8 %x, i8 %y) { |
| ; X86-LABEL: sub_xor_sminval_i8: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: addb $-128, %al |
| ; X86-NEXT: subb {{[0-9]+}}(%esp), %al |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: sub_xor_sminval_i8: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal -128(%rdi), %eax |
| ; X64-NEXT: subb %sil, %al |
| ; X64-NEXT: # kill: def $al killed $al killed $eax |
| ; X64-NEXT: retq |
| %r = xor i8 %x, 128 |
| %s = sub i8 %r, %y |
| ret i8 %s |
| } |
| |
| define i16 @add_xor_sminval_i16(i16 %x) { |
| ; X86-LABEL: add_xor_sminval_i16: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl $-32766, %eax # imm = 0x8002 |
| ; X86-NEXT: addl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: add_xor_sminval_i16: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal -32766(%rdi), %eax |
| ; X64-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X64-NEXT: retq |
| %r = xor i16 %x, 32768 |
| %s = add i16 %r, 2 |
| ret i16 %s |
| } |
| |
| define i32 @sub_xor_sminval_i32(i32 %x) { |
| ; X86-LABEL: sub_xor_sminval_i32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl $2147483136, %eax # imm = 0x7FFFFE00 |
| ; X86-NEXT: addl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: sub_xor_sminval_i32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal 2147483136(%rdi), %eax |
| ; X64-NEXT: retq |
| %r = xor i32 %x, 2147483648 |
| %s = sub i32 %r, 512 |
| ret i32 %s |
| } |
| |
| define i64 @add_xor_sminval_i64(i64 %x, i64 %y) { |
| ; X86-LABEL: add_xor_sminval_i64: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %edx |
| ; X86-NEXT: addl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: adcl {{[0-9]+}}(%esp), %edx |
| ; X86-NEXT: addl $-2147483648, %edx # imm = 0x80000000 |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: add_xor_sminval_i64: |
| ; X64: # %bb.0: |
| ; X64-NEXT: movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000 |
| ; X64-NEXT: addq %rdi, %rax |
| ; X64-NEXT: addq %rsi, %rax |
| ; X64-NEXT: retq |
| %r = xor i64 %x, -9223372036854775808 |
| %s = add i64 %y, %r |
| ret i64 %s |
| } |
| |
| ; |
| ; XOR(SHL(X,C),MIN_SIGNED_VALUE) |
| ; |
| |
| define i8 @xor_shl_sminval_i8(i8 %x) { |
| ; X86-LABEL: xor_shl_sminval_i8: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movzbl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: addb %al, %al |
| ; X86-NEXT: addb $-128, %al |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_shl_sminval_i8: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal (%rdi,%rdi), %eax |
| ; X64-NEXT: addb $-128, %al |
| ; X64-NEXT: # kill: def $al killed $al killed $eax |
| ; X64-NEXT: retq |
| %s = shl i8 %x, 1 |
| %r = xor i8 %s, 128 |
| ret i8 %r |
| } |
| |
| define i16 @xor_shl_sminval_i16(i16 %x) { |
| ; X86-LABEL: xor_shl_sminval_i16: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: shll $2, %eax |
| ; X86-NEXT: xorl $32768, %eax # imm = 0x8000 |
| ; X86-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_shl_sminval_i16: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal (,%rdi,4), %eax |
| ; X64-NEXT: xorl $32768, %eax # imm = 0x8000 |
| ; X64-NEXT: # kill: def $ax killed $ax killed $eax |
| ; X64-NEXT: retq |
| %s = shl i16 %x, 2 |
| %r = xor i16 %s, 32768 |
| ret i16 %r |
| } |
| |
| define i32 @xor_shl_sminval_i32(i32 %x) { |
| ; X86-LABEL: xor_shl_sminval_i32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: leal -2147483648(,%eax,8), %eax |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_shl_sminval_i32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: leal -2147483648(,%rdi,8), %eax |
| ; X64-NEXT: retq |
| %s = shl i32 %x, 3 |
| %r = xor i32 %s, 2147483648 |
| ret i32 %r |
| } |
| |
| ; negative test |
| define i32 @xor_bigshl_sminval_i32(i32 %x) { |
| ; X86-LABEL: xor_bigshl_sminval_i32: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: shll $8, %eax |
| ; X86-NEXT: addl $-2147483648, %eax # imm = 0x80000000 |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_bigshl_sminval_i32: |
| ; X64: # %bb.0: |
| ; X64-NEXT: # kill: def $edi killed $edi def $rdi |
| ; X64-NEXT: shll $8, %edi |
| ; X64-NEXT: leal -2147483648(%rdi), %eax |
| ; X64-NEXT: retq |
| %s = shl i32 %x, 8 |
| %r = xor i32 %s, 2147483648 |
| ret i32 %r |
| } |
| |
| define i64 @xor_shl_sminval_i64(i64 %x) { |
| ; X86-LABEL: xor_shl_sminval_i64: |
| ; X86: # %bb.0: |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %eax |
| ; X86-NEXT: movl {{[0-9]+}}(%esp), %edx |
| ; X86-NEXT: shldl $2, %eax, %edx |
| ; X86-NEXT: shll $2, %eax |
| ; X86-NEXT: addl $-2147483648, %edx # imm = 0x80000000 |
| ; X86-NEXT: retl |
| ; |
| ; X64-LABEL: xor_shl_sminval_i64: |
| ; X64: # %bb.0: |
| ; X64-NEXT: movabsq $-9223372036854775808, %rax # imm = 0x8000000000000000 |
| ; X64-NEXT: leaq (%rax,%rdi,4), %rax |
| ; X64-NEXT: retq |
| %s = shl i64 %x, 2 |
| %r = xor i64 %s, -9223372036854775808 |
| ret i64 %r |
| } |