220 changes: 220 additions & 0 deletions llvm/test/Analysis/ValueTracking/knownbits-div.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=instsimplify -S < %s | FileCheck %s

define i1 @sdiv_neg_neg_high_bits(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_neg_neg_high_bits(
; CHECK-NEXT: ret i1 false
;
%num = or i8 %x, 128
%denum = or i8 %y, 131
%div = sdiv i8 %num, %denum
%and = and i8 %div, 128
%r = icmp eq i8 %and, 128
ret i1 %r
}

define i1 @sdiv_pos_neg_high_bits(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_pos_neg_high_bits(
; CHECK-NEXT: ret i1 false
;
%xx = and i8 %x, 127
%num = or i8 %xx, 49
%denum = or i8 %y, 241
%div = sdiv i8 %num, %denum
%and = and i8 %div, 128
%r = icmp eq i8 %and, 0
ret i1 %r
}

define i1 @sdiv_pos_neg_high_bits_fail_maybez(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_pos_neg_high_bits_fail_maybez(
; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], 127
; CHECK-NEXT: [[NUM:%.*]] = or i8 [[XX]], 49
; CHECK-NEXT: [[DENUM:%.*]] = or i8 [[Y:%.*]], -64
; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[NUM]], [[DENUM]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DIV]], -128
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0
; CHECK-NEXT: ret i1 [[R]]
;
%xx = and i8 %x, 127
%num = or i8 %xx, 49
%denum = or i8 %y, 192
%div = sdiv i8 %num, %denum
%and = and i8 %div, 128
%r = icmp eq i8 %and, 0
ret i1 %r
}

define i1 @sdiv_exact_pos_neg_high_bits(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_exact_pos_neg_high_bits(
; CHECK-NEXT: ret i1 false
;
%xx = and i8 %x, 127
%num = or i8 %xx, 49
%denum = or i8 %y, 192
%div = sdiv exact i8 %num, %denum
%and = and i8 %div, 128
%r = icmp eq i8 %and, 0
ret i1 %r
}

define i1 @sdiv_neg_pos_high_bits(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_neg_pos_high_bits(
; CHECK-NEXT: ret i1 false
;
%xx = and i8 %x, 159
%num = or i8 %xx, 129
%yy = and i8 %y, 15
%denum = or i8 %yy, 9
%div = sdiv i8 %num, %denum
%and = and i8 %div, 128
%r = icmp eq i8 %and, 0
ret i1 %r
}

define i1 @sdiv_neg_pos_high_bits_fail_maybez(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_neg_pos_high_bits_fail_maybez(
; CHECK-NEXT: [[NUM:%.*]] = or i8 [[X:%.*]], -128
; CHECK-NEXT: [[YY:%.*]] = and i8 [[Y:%.*]], 15
; CHECK-NEXT: [[DENUM:%.*]] = or i8 [[YY]], 9
; CHECK-NEXT: [[DIV:%.*]] = sdiv i8 [[NUM]], [[DENUM]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DIV]], -128
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0
; CHECK-NEXT: ret i1 [[R]]
;
%num = or i8 %x, 128
%yy = and i8 %y, 15
%denum = or i8 %yy, 9
%div = sdiv i8 %num, %denum
%and = and i8 %div, 128
%r = icmp eq i8 %and, 0
ret i1 %r
}

define i1 @sdiv_exact_odd_odd(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_exact_odd_odd(
; CHECK-NEXT: ret i1 false
;
%num = or i8 %x, 1
%denum = or i8 %y, 1
%div = sdiv exact i8 %num, %denum
%and = and i8 %div, 1
%r = icmp eq i8 %and, 0
ret i1 %r
}

define i1 @sdiv_exact_even_odd(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_exact_even_odd(
; CHECK-NEXT: ret i1 false
;
%num = and i8 %x, -2
%denum = or i8 %y, 1
%div = sdiv exact i8 %num, %denum
%and = and i8 %div, 1
%r = icmp eq i8 %and, 1
ret i1 %r
}

define i1 @sdiv_exact_even_even_fail_unknown(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_exact_even_even_fail_unknown(
; CHECK-NEXT: [[NUM:%.*]] = and i8 [[X:%.*]], -2
; CHECK-NEXT: [[DENUM:%.*]] = and i8 [[Y:%.*]], -2
; CHECK-NEXT: [[DIV:%.*]] = sdiv exact i8 [[NUM]], [[DENUM]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DIV]], 1
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 1
; CHECK-NEXT: ret i1 [[R]]
;
%num = and i8 %x, -2
%denum = and i8 %y, -2
%div = sdiv exact i8 %num, %denum
%and = and i8 %div, 1
%r = icmp eq i8 %and, 1
ret i1 %r
}

define i1 @sdiv_exact_even_even_fail_unknown2(i8 %x, i8 %y) {
; CHECK-LABEL: @sdiv_exact_even_even_fail_unknown2(
; CHECK-NEXT: [[NUM:%.*]] = and i8 [[X:%.*]], -2
; CHECK-NEXT: [[DENUM:%.*]] = and i8 [[Y:%.*]], -2
; CHECK-NEXT: [[DIV:%.*]] = sdiv exact i8 [[NUM]], [[DENUM]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DIV]], 1
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0
; CHECK-NEXT: ret i1 [[R]]
;
%num = and i8 %x, -2
%denum = and i8 %y, -2
%div = sdiv exact i8 %num, %denum
%and = and i8 %div, 1
%r = icmp eq i8 %and, 0
ret i1 %r
}

define i1 @udiv_high_bits(i8 %x, i8 %y) {
; CHECK-LABEL: @udiv_high_bits(
; CHECK-NEXT: ret i1 false
;
%num = and i8 %x, 129
%denum = or i8 %y, 31
%div = udiv i8 %num, %denum
%and = and i8 %div, 8
%r = icmp eq i8 %and, 8
ret i1 %r
}

define i1 @udiv_exact_odd_odd(i8 %x, i8 %y) {
; CHECK-LABEL: @udiv_exact_odd_odd(
; CHECK-NEXT: ret i1 false
;
%num = or i8 %x, 1
%denum = or i8 %y, 1
%div = udiv exact i8 %num, %denum
%and = and i8 %div, 1
%r = icmp eq i8 %and, 0
ret i1 %r
}

define i1 @udiv_exact_even_odd(i8 %x, i8 %y) {
; CHECK-LABEL: @udiv_exact_even_odd(
; CHECK-NEXT: ret i1 false
;
%num = and i8 %x, -2
%denum = or i8 %y, 1
%div = udiv exact i8 %num, %denum
%and = and i8 %div, 1
%r = icmp eq i8 %and, 1
ret i1 %r
}

define i1 @udiv_exact_even_even_fail_unknown(i8 %x, i8 %y) {
; CHECK-LABEL: @udiv_exact_even_even_fail_unknown(
; CHECK-NEXT: [[NUM:%.*]] = and i8 [[X:%.*]], -2
; CHECK-NEXT: [[DENUM:%.*]] = and i8 [[Y:%.*]], -2
; CHECK-NEXT: [[DIV:%.*]] = udiv exact i8 [[NUM]], [[DENUM]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DIV]], 1
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 1
; CHECK-NEXT: ret i1 [[R]]
;
%num = and i8 %x, -2
%denum = and i8 %y, -2
%div = udiv exact i8 %num, %denum
%and = and i8 %div, 1
%r = icmp eq i8 %and, 1
ret i1 %r
}

define i1 @udiv_exact_even_even_fail_unknown2(i8 %x, i8 %y) {
; CHECK-LABEL: @udiv_exact_even_even_fail_unknown2(
; CHECK-NEXT: [[NUM:%.*]] = and i8 [[X:%.*]], -2
; CHECK-NEXT: [[DENUM:%.*]] = and i8 [[Y:%.*]], -2
; CHECK-NEXT: [[DIV:%.*]] = udiv exact i8 [[NUM]], [[DENUM]]
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DIV]], 1
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0
; CHECK-NEXT: ret i1 [[R]]
;
%num = and i8 %x, -2
%denum = and i8 %y, -2
%div = udiv exact i8 %num, %denum
%and = and i8 %div, 1
%r = icmp eq i8 %and, 0
ret i1 %r
}
112 changes: 112 additions & 0 deletions llvm/test/CodeGen/ARM/combine-bitreverse.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=thumbv7m-none-eabi -mattr=v7 | FileCheck %s --check-prefixes=CHECK

declare i16 @llvm.bswap.i16(i16) readnone
declare i32 @llvm.bswap.i32(i32) readnone
declare i32 @llvm.bitreverse.i32(i32) readnone

define i32 @brev_and_lhs_brev32(i32 %a, i32 %b) #0 {
; CHECK-LABEL: brev_and_lhs_brev32:
; CHECK: @ %bb.0:
; CHECK-NEXT: rbit r0, r0
; CHECK-NEXT: ands r0, r1
; CHECK-NEXT: rbit r0, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bitreverse.i32(i32 %a)
%2 = and i32 %1, %b
%3 = tail call i32 @llvm.bitreverse.i32(i32 %2)
ret i32 %3
}

define i32 @brev_or_lhs_brev32(i32 %a, i32 %b) #0 {
; CHECK-LABEL: brev_or_lhs_brev32:
; CHECK: @ %bb.0:
; CHECK-NEXT: rbit r0, r0
; CHECK-NEXT: orrs r0, r1
; CHECK-NEXT: rbit r0, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bitreverse.i32(i32 %a)
%2 = or i32 %1, %b
%3 = tail call i32 @llvm.bitreverse.i32(i32 %2)
ret i32 %3
}

define i32 @brev_xor_rhs_brev32(i32 %a, i32 %b) #0 {
; CHECK-LABEL: brev_xor_rhs_brev32:
; CHECK: @ %bb.0:
; CHECK-NEXT: rbit r1, r1
; CHECK-NEXT: eors r0, r1
; CHECK-NEXT: rbit r0, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bitreverse.i32(i32 %b)
%2 = xor i32 %a, %1
%3 = tail call i32 @llvm.bitreverse.i32(i32 %2)
ret i32 %3
}

define i32 @brev_and_all_operand_multiuse(i32 %a, i32 %b) #0 {
; CHECK-LABEL: brev_and_all_operand_multiuse:
; CHECK: @ %bb.0:
; CHECK-NEXT: rbit r1, r1
; CHECK-NEXT: rbit r0, r0
; CHECK-NEXT: and.w r2, r0, r1
; CHECK-NEXT: rbit r2, r2
; CHECK-NEXT: muls r0, r2, r0
; CHECK-NEXT: muls r0, r1, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bitreverse.i32(i32 %a)
%2 = tail call i32 @llvm.bitreverse.i32(i32 %b)
%3 = and i32 %1, %2
%4 = tail call i32 @llvm.bitreverse.i32(i32 %3)
%5 = mul i32 %1, %4 ;increase use of left bitreverse
%6 = mul i32 %2, %5 ;increase use of right bitreverse

ret i32 %6
}

; negative test
define i32 @brev_and_rhs_brev32_multiuse1(i32 %a, i32 %b) #0 {
; CHECK-LABEL: brev_and_rhs_brev32_multiuse1:
; CHECK: @ %bb.0:
; CHECK-NEXT: rbit r1, r1
; CHECK-NEXT: ands r0, r1
; CHECK-NEXT: rbit r1, r0
; CHECK-NEXT: muls r0, r1, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bitreverse.i32(i32 %b)
%2 = and i32 %1, %a
%3 = tail call i32 @llvm.bitreverse.i32(i32 %2)
%4 = mul i32 %2, %3 ;increase use of logical op
ret i32 %4
}

; negative test
define i32 @brev_and_rhs_brev32_multiuse2(i32 %a, i32 %b) #0 {
; CHECK-LABEL: brev_and_rhs_brev32_multiuse2:
; CHECK: @ %bb.0:
; CHECK-NEXT: rbit r1, r1
; CHECK-NEXT: ands r0, r1
; CHECK-NEXT: rbit r0, r0
; CHECK-NEXT: muls r0, r1, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bitreverse.i32(i32 %b)
%2 = and i32 %1, %a
%3 = tail call i32 @llvm.bitreverse.i32(i32 %2)
%4 = mul i32 %1, %3 ;increase use of inner bitreverse
ret i32 %4
}

; negative test
define i32 @brev_xor_rhs_bs32(i32 %a, i32 %b) #0 {
; CHECK-LABEL: brev_xor_rhs_bs32:
; CHECK: @ %bb.0:
; CHECK-NEXT: rev r1, r1
; CHECK-NEXT: eors r0, r1
; CHECK-NEXT: rbit r0, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bswap.i32(i32 %b)
%2 = xor i32 %a, %1
%3 = tail call i32 @llvm.bitreverse.i32(i32 %2)
ret i32 %3
}

83 changes: 83 additions & 0 deletions llvm/test/CodeGen/ARM/combine-bswap.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=thumbv7m-none-eabi -mattr=v7 | FileCheck %s --check-prefixes=CHECK

declare i32 @llvm.bswap.i32(i32) readnone
declare i64 @llvm.bswap.i64(i64) readnone
declare i32 @llvm.bitreverse.i32(i32) readnone

define i32 @bs_and_lhs_bs32(i32 %a, i32 %b) #0 {
; CHECK-LABEL: bs_and_lhs_bs32:
; CHECK: @ %bb.0:
; CHECK-NEXT: rev r1, r1
; CHECK-NEXT: ands r0, r1
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bswap.i32(i32 %a)
%2 = and i32 %1, %b
%3 = tail call i32 @llvm.bswap.i32(i32 %2)
ret i32 %3
}

define i64 @bs_or_rhs_bs64(i64 %a, i64 %b) #0 {
; CHECK-LABEL: bs_or_rhs_bs64:
; CHECK: @ %bb.0:
; CHECK-NEXT: rev r1, r1
; CHECK-NEXT: rev r0, r0
; CHECK-NEXT: orrs r2, r1
; CHECK-NEXT: orr.w r1, r0, r3
; CHECK-NEXT: mov r0, r2
; CHECK-NEXT: bx lr
%1 = tail call i64 @llvm.bswap.i64(i64 %b)
%2 = or i64 %a, %1
%3 = tail call i64 @llvm.bswap.i64(i64 %2)
ret i64 %3
}

define i32 @bs_and_all_operand_multiuse(i32 %a, i32 %b) #0 {
; CHECK-LABEL: bs_and_all_operand_multiuse:
; CHECK: @ %bb.0:
; CHECK-NEXT: and.w r2, r0, r1
; CHECK-NEXT: rev r0, r0
; CHECK-NEXT: rev r1, r1
; CHECK-NEXT: muls r0, r2, r0
; CHECK-NEXT: muls r0, r1, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bswap.i32(i32 %a)
%2 = tail call i32 @llvm.bswap.i32(i32 %b)
%3 = and i32 %1, %2
%4 = tail call i32 @llvm.bswap.i32(i32 %3)
%5 = mul i32 %1, %4 ;increase use of left bswap
%6 = mul i32 %2, %5 ;increase use of right bswap

ret i32 %6
}

; negative test
define i32 @bs_and_rhs_bs32_multiuse1(i32 %a, i32 %b) #0 {
; CHECK-LABEL: bs_and_rhs_bs32_multiuse1:
; CHECK: @ %bb.0:
; CHECK-NEXT: rev r1, r1
; CHECK-NEXT: ands r0, r1
; CHECK-NEXT: rev r1, r0
; CHECK-NEXT: muls r0, r1, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bswap.i32(i32 %b)
%2 = and i32 %1, %a
%3 = tail call i32 @llvm.bswap.i32(i32 %2)
%4 = mul i32 %2, %3 ;increase use of logical op
ret i32 %4
}

; negative test
define i32 @bs_xor_rhs_brev32(i32 %a, i32 %b) #0 {
; CHECK-LABEL: bs_xor_rhs_brev32:
; CHECK: @ %bb.0:
; CHECK-NEXT: rbit r1, r1
; CHECK-NEXT: eors r0, r1
; CHECK-NEXT: rev r0, r0
; CHECK-NEXT: bx lr
%1 = tail call i32 @llvm.bitreverse.i32(i32 %b)
%2 = xor i32 %a, %1
%3 = tail call i32 @llvm.bswap.i32(i32 %2)
ret i32 %3
}

9 changes: 6 additions & 3 deletions llvm/test/CodeGen/ARM/select-imm.ll
Original file line number Diff line number Diff line change
Expand Up @@ -657,9 +657,12 @@ define i1 @t10() {
; V8MBASE-NEXT: movs r0, #7
; V8MBASE-NEXT: mvns r0, r0
; V8MBASE-NEXT: str r0, [sp]
; V8MBASE-NEXT: adds r0, r0, #5
; V8MBASE-NEXT: str r0, [sp, #4]
; V8MBASE-NEXT: movs r1, #0
; V8MBASE-NEXT: adds r1, r0, #5
; V8MBASE-NEXT: str r1, [sp, #4]
; V8MBASE-NEXT: sdiv r2, r1, r0
; V8MBASE-NEXT: muls r2, r0, r2
; V8MBASE-NEXT: subs r0, r1, r2
; V8MBASE-NEXT: subs r1, r0, r1
; V8MBASE-NEXT: rsbs r0, r1, #0
; V8MBASE-NEXT: adcs r0, r1
; V8MBASE-NEXT: add sp, #8
Expand Down
1 change: 1 addition & 0 deletions llvm/test/CodeGen/X86/combine-bitreverse.ll
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
declare i32 @llvm.bitreverse.i32(i32) readnone
declare i64 @llvm.bitreverse.i64(i64) readnone
declare <4 x i32> @llvm.bitreverse.v4i32(<4 x i32>) readnone
declare i32 @llvm.bswap.i32(i32) readnone

; fold (bitreverse undef) -> undef
define i32 @test_undef() nounwind {
Expand Down
152 changes: 152 additions & 0 deletions llvm/test/CodeGen/X86/combine-bswap.ll
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,158 @@ define i32 @test_bswap32_shift17(i32 %a0) {
ret i32 %b
}

define i32 @bs_and_lhs_bs32(i32 %a, i32 %b) #0 {
; X86-LABEL: bs_and_lhs_bs32:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: bswapl %eax
; X86-NEXT: andl {{[0-9]+}}(%esp), %eax
; X86-NEXT: retl
;
; X64-LABEL: bs_and_lhs_bs32:
; X64: # %bb.0:
; X64-NEXT: movl %esi, %eax
; X64-NEXT: bswapl %eax
; X64-NEXT: andl %edi, %eax
; X64-NEXT: retq
%1 = tail call i32 @llvm.bswap.i32(i32 %a)
%2 = and i32 %1, %b
%3 = tail call i32 @llvm.bswap.i32(i32 %2)
ret i32 %3
}

define i64 @bs_or_lhs_bs64(i64 %a, i64 %b) #0 {
; X86-LABEL: bs_or_lhs_bs64:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: bswapl %eax
; X86-NEXT: orl {{[0-9]+}}(%esp), %eax
; X86-NEXT: bswapl %edx
; X86-NEXT: orl {{[0-9]+}}(%esp), %edx
; X86-NEXT: retl
;
; X64-LABEL: bs_or_lhs_bs64:
; X64: # %bb.0:
; X64-NEXT: movq %rsi, %rax
; X64-NEXT: bswapq %rax
; X64-NEXT: orq %rdi, %rax
; X64-NEXT: retq
%1 = tail call i64 @llvm.bswap.i64(i64 %a)
%2 = or i64 %1, %b
%3 = tail call i64 @llvm.bswap.i64(i64 %2)
ret i64 %3
}

define i64 @bs_xor_rhs_bs64(i64 %a, i64 %b) #0 {
; X86-LABEL: bs_xor_rhs_bs64:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: bswapl %eax
; X86-NEXT: xorl {{[0-9]+}}(%esp), %eax
; X86-NEXT: bswapl %edx
; X86-NEXT: xorl {{[0-9]+}}(%esp), %edx
; X86-NEXT: retl
;
; X64-LABEL: bs_xor_rhs_bs64:
; X64: # %bb.0:
; X64-NEXT: movq %rdi, %rax
; X64-NEXT: bswapq %rax
; X64-NEXT: xorq %rsi, %rax
; X64-NEXT: retq
%1 = tail call i64 @llvm.bswap.i64(i64 %b)
%2 = xor i64 %a, %1
%3 = tail call i64 @llvm.bswap.i64(i64 %2)
ret i64 %3
}

define i32 @bs_and_all_operand_multiuse(i32 %a, i32 %b) #0 {
; X86-LABEL: bs_and_all_operand_multiuse:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: movl %eax, %edx
; X86-NEXT: bswapl %edx
; X86-NEXT: andl %ecx, %eax
; X86-NEXT: bswapl %ecx
; X86-NEXT: imull %edx, %eax
; X86-NEXT: imull %ecx, %eax
; X86-NEXT: retl
;
; X64-LABEL: bs_and_all_operand_multiuse:
; X64: # %bb.0:
; X64-NEXT: movl %edi, %eax
; X64-NEXT: bswapl %eax
; X64-NEXT: andl %esi, %edi
; X64-NEXT: bswapl %esi
; X64-NEXT: imull %edi, %eax
; X64-NEXT: imull %esi, %eax
; X64-NEXT: retq
%1 = tail call i32 @llvm.bswap.i32(i32 %a)
%2 = tail call i32 @llvm.bswap.i32(i32 %b)
%3 = and i32 %1, %2
%4 = tail call i32 @llvm.bswap.i32(i32 %3)
%5 = mul i32 %1, %4 ;increase use of left bswap
%6 = mul i32 %2, %5 ;increase use of right bswap

ret i32 %6
}

; negative test
define i32 @bs_and_rhs_bs32_multiuse1(i32 %a, i32 %b) #0 {
; X86-LABEL: bs_and_rhs_bs32_multiuse1:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: bswapl %ecx
; X86-NEXT: andl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: movl %ecx, %eax
; X86-NEXT: bswapl %eax
; X86-NEXT: imull %ecx, %eax
; X86-NEXT: retl
;
; X64-LABEL: bs_and_rhs_bs32_multiuse1:
; X64: # %bb.0:
; X64-NEXT: bswapl %esi
; X64-NEXT: andl %edi, %esi
; X64-NEXT: movl %esi, %eax
; X64-NEXT: bswapl %eax
; X64-NEXT: imull %esi, %eax
; X64-NEXT: retq
%1 = tail call i32 @llvm.bswap.i32(i32 %b)
%2 = and i32 %1, %a
%3 = tail call i32 @llvm.bswap.i32(i32 %2)
%4 = mul i32 %2, %3 ;increase use of logical op
ret i32 %4
}

; negative test
define i32 @bs_and_rhs_bs32_multiuse2(i32 %a, i32 %b) #0 {
; X86-LABEL: bs_and_rhs_bs32_multiuse2:
; X86: # %bb.0:
; X86-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X86-NEXT: bswapl %ecx
; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
; X86-NEXT: andl %ecx, %eax
; X86-NEXT: bswapl %eax
; X86-NEXT: imull %ecx, %eax
; X86-NEXT: retl
;
; X64-LABEL: bs_and_rhs_bs32_multiuse2:
; X64: # %bb.0:
; X64-NEXT: movl %edi, %eax
; X64-NEXT: bswapl %esi
; X64-NEXT: andl %esi, %eax
; X64-NEXT: bswapl %eax
; X64-NEXT: imull %esi, %eax
; X64-NEXT: retq
%1 = tail call i32 @llvm.bswap.i32(i32 %b)
%2 = and i32 %1, %a
%3 = tail call i32 @llvm.bswap.i32(i32 %2)
%4 = mul i32 %1, %3 ;increase use of inner bswap
ret i32 %4
}

; negative test
define i64 @test_bswap64_shift17(i64 %a0) {
; X86-LABEL: test_bswap64_shift17:
Expand Down
70 changes: 70 additions & 0 deletions llvm/test/CodeGen/X86/knownbits-div.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=x86_64-unknown | FileCheck %s

define i8 @sdiv_neg_neg_high_bits(i8 %x, i8 %y) {
; CHECK-LABEL: sdiv_neg_neg_high_bits:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: retq
%num = or i8 %x, 128
%denum = or i8 %y, 131
%div = sdiv i8 %num, %denum
%r = and i8 %div, 128
ret i8 %r
}

define i8 @sdiv_exact_odd_odd(i8 %x, i8 %y) {
; CHECK-LABEL: sdiv_exact_odd_odd:
; CHECK: # %bb.0:
; CHECK-NEXT: movb $1, %al
; CHECK-NEXT: retq
%num = or i8 %x, 1
%denum = or i8 %y, 1
%div = sdiv exact i8 %num, %denum
%r = and i8 %div, 1
ret i8 %r
}

define i8 @sdiv_exact_even_even_fail_unknown(i8 %x, i8 %y) {
; CHECK-LABEL: sdiv_exact_even_even_fail_unknown:
; CHECK: # %bb.0:
; CHECK-NEXT: andb $-2, %dil
; CHECK-NEXT: andb $-2, %sil
; CHECK-NEXT: movsbl %dil, %eax
; CHECK-NEXT: idivb %sil
; CHECK-NEXT: andb $1, %al
; CHECK-NEXT: retq
%num = and i8 %x, -2
%denum = and i8 %y, -2
%div = sdiv exact i8 %num, %denum
%r = and i8 %div, 1
ret i8 %r
}

define i8 @udiv_exact_even_odd(i8 %x, i8 %y) {
; CHECK-LABEL: udiv_exact_even_odd:
; CHECK: # %bb.0:
; CHECK-NEXT: xorl %eax, %eax
; CHECK-NEXT: retq
%num = and i8 %x, -2
%denum = or i8 %y, 1
%div = udiv exact i8 %num, %denum
%r = and i8 %div, 1
ret i8 %r
}

define i8 @udiv_exact_even_even_fail_unknown(i8 %x, i8 %y) {
; CHECK-LABEL: udiv_exact_even_even_fail_unknown:
; CHECK: # %bb.0:
; CHECK-NEXT: andb $-2, %dil
; CHECK-NEXT: andb $-2, %sil
; CHECK-NEXT: movzbl %dil, %eax
; CHECK-NEXT: divb %sil
; CHECK-NEXT: andb $1, %al
; CHECK-NEXT: retq
%num = and i8 %x, -2
%denum = and i8 %y, -2
%div = udiv exact i8 %num, %denum
%r = and i8 %div, 1
ret i8 %r
}
140 changes: 77 additions & 63 deletions llvm/test/Transforms/InstCombine/bswap-fold.ll
Original file line number Diff line number Diff line change
Expand Up @@ -543,10 +543,9 @@ define i64 @bs_and64i_multiuse(i64 %a, i64 %b) #0 {
; Fold: BSWAP( OP( BSWAP(x), y ) ) -> OP( x, BSWAP(y) )
define i16 @bs_and_lhs_bs16(i16 %a, i16 %b) #0 {
; CHECK-LABEL: @bs_and_lhs_bs16(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and i16 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[TMP2]])
; CHECK-NEXT: ret i16 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.bswap.i16(i16 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and i16 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: ret i16 [[TMP2]]
;
%1 = tail call i16 @llvm.bswap.i16(i16 %a)
%2 = and i16 %1, %b
Expand All @@ -556,10 +555,9 @@ define i16 @bs_and_lhs_bs16(i16 %a, i16 %b) #0 {

define i16 @bs_or_lhs_bs16(i16 %a, i16 %b) #0 {
; CHECK-LABEL: @bs_or_lhs_bs16(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or i16 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[TMP2]])
; CHECK-NEXT: ret i16 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.bswap.i16(i16 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or i16 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: ret i16 [[TMP2]]
;
%1 = tail call i16 @llvm.bswap.i16(i16 %a)
%2 = or i16 %1, %b
Expand All @@ -569,10 +567,9 @@ define i16 @bs_or_lhs_bs16(i16 %a, i16 %b) #0 {

define i16 @bs_xor_lhs_bs16(i16 %a, i16 %b) #0 {
; CHECK-LABEL: @bs_xor_lhs_bs16(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor i16 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[TMP2]])
; CHECK-NEXT: ret i16 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.bswap.i16(i16 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor i16 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: ret i16 [[TMP2]]
;
%1 = tail call i16 @llvm.bswap.i16(i16 %a)
%2 = xor i16 %1, %b
Expand All @@ -582,10 +579,9 @@ define i16 @bs_xor_lhs_bs16(i16 %a, i16 %b) #0 {

define i16 @bs_and_rhs_bs16(i16 %a, i16 %b) #0 {
; CHECK-LABEL: @bs_and_rhs_bs16(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and i16 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[TMP2]])
; CHECK-NEXT: ret i16 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.bswap.i16(i16 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and i16 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i16 [[TMP2]]
;
%1 = tail call i16 @llvm.bswap.i16(i16 %b)
%2 = and i16 %a, %1
Expand All @@ -595,10 +591,9 @@ define i16 @bs_and_rhs_bs16(i16 %a, i16 %b) #0 {

define i16 @bs_or_rhs_bs16(i16 %a, i16 %b) #0 {
; CHECK-LABEL: @bs_or_rhs_bs16(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or i16 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[TMP2]])
; CHECK-NEXT: ret i16 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.bswap.i16(i16 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or i16 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i16 [[TMP2]]
;
%1 = tail call i16 @llvm.bswap.i16(i16 %b)
%2 = or i16 %a, %1
Expand All @@ -608,10 +603,9 @@ define i16 @bs_or_rhs_bs16(i16 %a, i16 %b) #0 {

define i16 @bs_xor_rhs_bs16(i16 %a, i16 %b) #0 {
; CHECK-LABEL: @bs_xor_rhs_bs16(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor i16 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i16 @llvm.bswap.i16(i16 [[TMP2]])
; CHECK-NEXT: ret i16 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i16 @llvm.bswap.i16(i16 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor i16 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i16 [[TMP2]]
;
%1 = tail call i16 @llvm.bswap.i16(i16 %b)
%2 = xor i16 %a, %1
Expand All @@ -621,10 +615,9 @@ define i16 @bs_xor_rhs_bs16(i16 %a, i16 %b) #0 {

define i32 @bs_and_rhs_bs32(i32 %a, i32 %b) #0 {
; CHECK-LABEL: @bs_and_rhs_bs32(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[TMP2]])
; CHECK-NEXT: ret i32 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.bswap.i32(i32 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[TMP2]]
;
%1 = tail call i32 @llvm.bswap.i32(i32 %b)
%2 = and i32 %a, %1
Expand All @@ -634,10 +627,9 @@ define i32 @bs_and_rhs_bs32(i32 %a, i32 %b) #0 {

define i32 @bs_or_rhs_bs32(i32 %a, i32 %b) #0 {
; CHECK-LABEL: @bs_or_rhs_bs32(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[TMP2]])
; CHECK-NEXT: ret i32 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.bswap.i32(i32 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[TMP2]]
;
%1 = tail call i32 @llvm.bswap.i32(i32 %b)
%2 = or i32 %a, %1
Expand All @@ -647,10 +639,9 @@ define i32 @bs_or_rhs_bs32(i32 %a, i32 %b) #0 {

define i32 @bs_xor_rhs_bs32(i32 %a, i32 %b) #0 {
; CHECK-LABEL: @bs_xor_rhs_bs32(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i32 @llvm.bswap.i32(i32 [[TMP2]])
; CHECK-NEXT: ret i32 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.bswap.i32(i32 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i32 [[TMP2]]
;
%1 = tail call i32 @llvm.bswap.i32(i32 %b)
%2 = xor i32 %a, %1
Expand All @@ -660,10 +651,9 @@ define i32 @bs_xor_rhs_bs32(i32 %a, i32 %b) #0 {

define i64 @bs_and_rhs_bs64(i64 %a, i64 %b) #0 {
; CHECK-LABEL: @bs_and_rhs_bs64(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP2]])
; CHECK-NEXT: ret i64 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.bswap.i64(i64 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i64 [[TMP2]]
;
%1 = tail call i64 @llvm.bswap.i64(i64 %b)
%2 = and i64 %a, %1
Expand All @@ -673,10 +663,9 @@ define i64 @bs_and_rhs_bs64(i64 %a, i64 %b) #0 {

define i64 @bs_or_rhs_bs64(i64 %a, i64 %b) #0 {
; CHECK-LABEL: @bs_or_rhs_bs64(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or i64 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP2]])
; CHECK-NEXT: ret i64 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.bswap.i64(i64 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or i64 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i64 [[TMP2]]
;
%1 = tail call i64 @llvm.bswap.i64(i64 %b)
%2 = or i64 %a, %1
Expand All @@ -686,10 +675,9 @@ define i64 @bs_or_rhs_bs64(i64 %a, i64 %b) #0 {

define i64 @bs_xor_rhs_bs64(i64 %a, i64 %b) #0 {
; CHECK-LABEL: @bs_xor_rhs_bs64(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor i64 [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP2]])
; CHECK-NEXT: ret i64 [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.bswap.i64(i64 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor i64 [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret i64 [[TMP2]]
;
%1 = tail call i64 @llvm.bswap.i64(i64 %b)
%2 = xor i64 %a, %1
Expand All @@ -699,10 +687,9 @@ define i64 @bs_xor_rhs_bs64(i64 %a, i64 %b) #0 {

define <2 x i32> @bs_and_rhs_i32vec(<2 x i32> %a, <2 x i32> %b) #0 {
; CHECK-LABEL: @bs_and_rhs_i32vec(
; CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> [[TMP2]])
; CHECK-NEXT: ret <2 x i32> [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.bswap.v2i32(<2 x i32> [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret <2 x i32> [[TMP2]]
;
%1 = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> %b)
%2 = and <2 x i32> %a, %1
Expand All @@ -712,10 +699,9 @@ define <2 x i32> @bs_and_rhs_i32vec(<2 x i32> %a, <2 x i32> %b) #0 {

define <2 x i32> @bs_or_rhs_i32vec(<2 x i32> %a, <2 x i32> %b) #0 {
; CHECK-LABEL: @bs_or_rhs_i32vec(
; CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or <2 x i32> [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> [[TMP2]])
; CHECK-NEXT: ret <2 x i32> [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.bswap.v2i32(<2 x i32> [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = or <2 x i32> [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret <2 x i32> [[TMP2]]
;
%1 = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> %b)
%2 = or <2 x i32> %a, %1
Expand All @@ -725,10 +711,9 @@ define <2 x i32> @bs_or_rhs_i32vec(<2 x i32> %a, <2 x i32> %b) #0 {

define <2 x i32> @bs_xor_rhs_i32vec(<2 x i32> %a, <2 x i32> %b) #0 {
; CHECK-LABEL: @bs_xor_rhs_i32vec(
; CHECK-NEXT: [[TMP1:%.*]] = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> [[B:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i32> [[TMP1]], [[A:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> [[TMP2]])
; CHECK-NEXT: ret <2 x i32> [[TMP3]]
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x i32> @llvm.bswap.v2i32(<2 x i32> [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = xor <2 x i32> [[TMP1]], [[B:%.*]]
; CHECK-NEXT: ret <2 x i32> [[TMP2]]
;
%1 = tail call <2 x i32> @llvm.bswap.v2i32(<2 x i32> %b)
%2 = xor <2 x i32> %a, %1
Expand Down Expand Up @@ -782,11 +767,10 @@ define i64 @bs_all_operand64_multiuse_both(i64 %a, i64 %b) #0 {
; CHECK-LABEL: @bs_all_operand64_multiuse_both(
; CHECK-NEXT: [[TMP1:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[A:%.*]])
; CHECK-NEXT: [[TMP2:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[B:%.*]])
; CHECK-NEXT: [[TMP3:%.*]] = and i64 [[TMP1]], [[TMP2]]
; CHECK-NEXT: [[TMP4:%.*]] = tail call i64 @llvm.bswap.i64(i64 [[TMP3]])
; CHECK-NEXT: [[TMP3:%.*]] = and i64 [[A]], [[B]]
; CHECK-NEXT: call void @use.i64(i64 [[TMP1]])
; CHECK-NEXT: call void @use.i64(i64 [[TMP2]])
; CHECK-NEXT: ret i64 [[TMP4]]
; CHECK-NEXT: ret i64 [[TMP3]]
;
%1 = tail call i64 @llvm.bswap.i64(i64 %a)
%2 = tail call i64 @llvm.bswap.i64(i64 %b)
Expand All @@ -798,6 +782,36 @@ define i64 @bs_all_operand64_multiuse_both(i64 %a, i64 %b) #0 {
ret i64 %4
}

@gp = external global [0 x i8]

define void @bs_and_constexpr(ptr %out, i64 %a) {
; CHECK-LABEL: @bs_and_constexpr(
; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.bswap.i64(i64 and (i64 ptrtoint (ptr @gp to i64), i64 4095))
; CHECK-NEXT: store i64 [[RES]], ptr [[OUT:%.*]], align 8
; CHECK-NEXT: ret void
;
%gpi = ptrtoint ptr @gp to i64
%exp = and i64 %gpi, 4095
%res = call i64 @llvm.bswap.i64(i64 %exp)
store i64 %res, ptr %out, align 8
ret void
}


define void @bs_and_bs_constexpr(ptr %out, i64 %a) {
; CHECK-LABEL: @bs_and_bs_constexpr(
; CHECK-NEXT: store i64 and (i64 ptrtoint (ptr @gp to i64), i64 -67835469387268096), ptr [[OUT:%.*]], align 8
; CHECK-NEXT: ret void
;
%gpi = ptrtoint ptr @gp to i64
%bs_gpi = call i64 @llvm.bswap.i64(i64 %gpi)
%exp = and i64 %bs_gpi, 4095
%res = call i64 @llvm.bswap.i64(i64 %exp)
store i64 %res, ptr %out, align 8
ret void
}


define i64 @bs_active_high8(i64 %0) {
; CHECK-LABEL: @bs_active_high8(
; CHECK-NEXT: [[TMP2:%.*]] = and i64 [[TMP0:%.*]], 255
Expand Down
31 changes: 31 additions & 0 deletions llvm/unittests/Support/KnownBitsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,37 @@ TEST(KnownBitsTest, BinaryExhaustive) {
return N1.udiv(N2);
},
checkCorrectnessOnlyBinary);
testBinaryOpExhaustive(
[](const KnownBits &Known1, const KnownBits &Known2) {
return KnownBits::udiv(Known1, Known2, /*Exact*/ true);
},
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
if (N2.isZero() || !N1.urem(N2).isZero())
return std::nullopt;
return N1.udiv(N2);
},
checkCorrectnessOnlyBinary);
testBinaryOpExhaustive(
[](const KnownBits &Known1, const KnownBits &Known2) {
return KnownBits::sdiv(Known1, Known2);
},
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
if (N2.isZero() || (N1.isMinSignedValue() && N2.isAllOnes()))
return std::nullopt;
return N1.sdiv(N2);
},
checkCorrectnessOnlyBinary);
testBinaryOpExhaustive(
[](const KnownBits &Known1, const KnownBits &Known2) {
return KnownBits::sdiv(Known1, Known2, /*Exact*/ true);
},
[](const APInt &N1, const APInt &N2) -> std::optional<APInt> {
if (N2.isZero() || (N1.isMinSignedValue() && N2.isAllOnes()) ||
!N1.srem(N2).isZero())
return std::nullopt;
return N1.sdiv(N2);
},
checkCorrectnessOnlyBinary);
testBinaryOpExhaustive(
[](const KnownBits &Known1, const KnownBits &Known2) {
return KnownBits::urem(Known1, Known2);
Expand Down