
gep nuw can be null if and only if both the base pointer and offset are null. Unlike the inbounds case this does not depend on whether the null pointer is valid. Proofs: https://alive2.llvm.org/ce/z/PLoqK5
3433 lines
89 KiB
LLVM
3433 lines
89 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
|
|
target datalayout = "p:32:32-p1:64:64"
|
|
|
|
declare void @llvm.assume(i1)
|
|
|
|
define i1 @ptrtoint() {
|
|
; CHECK-LABEL: @ptrtoint(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%a = alloca i8
|
|
%tmp = ptrtoint ptr %a to i32
|
|
%r = icmp eq i32 %tmp, 0
|
|
ret i1 %r
|
|
}
|
|
|
|
define i1 @bitcast() {
|
|
; CHECK-LABEL: @bitcast(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%a = alloca i32
|
|
%b = alloca i64
|
|
%cmp = icmp eq ptr %a, %b
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep() {
|
|
; CHECK-LABEL: @gep(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%a = alloca [3 x i8], align 8
|
|
%cmp = icmp eq ptr %a, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep2() {
|
|
; CHECK-LABEL: @gep2(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%a = alloca [3 x i8], align 8
|
|
%cmp = icmp eq ptr %a, %a
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; PR11238
|
|
%gept = type { i32, i32 }
|
|
@gepy = global %gept zeroinitializer, align 8
|
|
@gepz = extern_weak global %gept
|
|
|
|
define i1 @gep3() {
|
|
; CHECK-LABEL: @gep3(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x = alloca %gept, align 8
|
|
%b = getelementptr %gept, ptr %x, i64 0, i32 1
|
|
%equal = icmp eq ptr %x, %b
|
|
ret i1 %equal
|
|
}
|
|
|
|
define i1 @gep4() {
|
|
; CHECK-LABEL: @gep4(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x = alloca %gept, align 8
|
|
%b = getelementptr %gept, ptr @gepy, i64 0, i32 1
|
|
%equal = icmp eq ptr @gepy, %b
|
|
ret i1 %equal
|
|
}
|
|
|
|
@a = common global [1 x i32] zeroinitializer, align 4
|
|
|
|
define i1 @PR31262() {
|
|
; CHECK-LABEL: @PR31262(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%idx = getelementptr inbounds [1 x i32], ptr @a, i64 0, i64 undef
|
|
%cmp = icmp uge ptr %idx, @a
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep5() {
|
|
; CHECK-LABEL: @gep5(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x = alloca %gept, align 8
|
|
%a = getelementptr inbounds %gept, ptr %x, i64 0, i32 1
|
|
%equal = icmp eq ptr %a, @gepy
|
|
ret i1 %equal
|
|
}
|
|
|
|
define i1 @gep6(ptr %x) {
|
|
; Same as @gep3 but potentially null.
|
|
; CHECK-LABEL: @gep6(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%b = getelementptr %gept, ptr %x, i64 0, i32 1
|
|
%equal = icmp eq ptr %x, %b
|
|
ret i1 %equal
|
|
}
|
|
|
|
define i1 @gep7(ptr %x) {
|
|
; CHECK-LABEL: @gep7(
|
|
; CHECK-NEXT: [[EQUAL:%.*]] = icmp eq ptr [[X:%.*]], @gepz
|
|
; CHECK-NEXT: ret i1 [[EQUAL]]
|
|
;
|
|
%equal = icmp eq ptr %x, @gepz
|
|
ret i1 %equal
|
|
}
|
|
|
|
define i1 @gep8(ptr %x) {
|
|
; CHECK-LABEL: @gep8(
|
|
; CHECK-NEXT: [[A:%.*]] = getelementptr [[GEPT:%.*]], ptr [[X:%.*]], i32 1
|
|
; CHECK-NEXT: [[B:%.*]] = getelementptr [[GEPT]], ptr [[X]], i32 -1
|
|
; CHECK-NEXT: [[EQUAL:%.*]] = icmp ugt ptr [[A]], [[B]]
|
|
; CHECK-NEXT: ret i1 [[EQUAL]]
|
|
;
|
|
%a = getelementptr %gept, ptr %x, i32 1
|
|
%b = getelementptr %gept, ptr %x, i32 -1
|
|
%equal = icmp ugt ptr %a, %b
|
|
ret i1 %equal
|
|
}
|
|
|
|
define i1 @gep9(ptr %ptr) {
|
|
; CHECK-LABEL: @gep9(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
entry:
|
|
%first2 = getelementptr inbounds i8, ptr %ptr, i32 1
|
|
%first3 = getelementptr inbounds i8, ptr %first2, i32 2
|
|
%first4 = getelementptr inbounds i8, ptr %first3, i32 4
|
|
%last1 = getelementptr inbounds i8, ptr %first2, i32 48
|
|
%last2 = getelementptr inbounds i8, ptr %last1, i32 8
|
|
%last3 = getelementptr inbounds i8, ptr %last2, i32 -4
|
|
%last4 = getelementptr inbounds i8, ptr %last3, i32 -4
|
|
%first.int = ptrtoint ptr %first4 to i32
|
|
%last.int = ptrtoint ptr %last4 to i32
|
|
%cmp = icmp ne i32 %last.int, %first.int
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep10(ptr %ptr) {
|
|
; CHECK-LABEL: @gep10(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
entry:
|
|
%first1 = getelementptr inbounds i8, ptr %ptr, i32 -2
|
|
%first2 = getelementptr inbounds i8, ptr %first1, i32 44
|
|
%last1 = getelementptr inbounds i8, ptr %ptr, i32 48
|
|
%last2 = getelementptr inbounds i8, ptr %last1, i32 -6
|
|
%first.int = ptrtoint ptr %first2 to i32
|
|
%last.int = ptrtoint ptr %last2 to i32
|
|
%cmp = icmp eq i32 %last.int, %first.int
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep11(ptr %ptr) {
|
|
; CHECK-LABEL: @gep11(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
entry:
|
|
%first1 = getelementptr inbounds i8, ptr %ptr, i32 -2
|
|
%last1 = getelementptr inbounds i8, ptr %ptr, i32 48
|
|
%last2 = getelementptr inbounds i8, ptr %last1, i32 -6
|
|
%cmp = icmp ult ptr %first1, %last2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep12(ptr %ptr) {
|
|
; CHECK-LABEL: @gep12(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[FIRST1:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i32 -2
|
|
; CHECK-NEXT: [[LAST1:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i32 48
|
|
; CHECK-NEXT: [[LAST2:%.*]] = getelementptr inbounds i8, ptr [[LAST1]], i32 -6
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt ptr [[FIRST1]], [[LAST2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
entry:
|
|
%first1 = getelementptr inbounds i8, ptr %ptr, i32 -2
|
|
%last1 = getelementptr inbounds i8, ptr %ptr, i32 48
|
|
%last2 = getelementptr inbounds i8, ptr %last1, i32 -6
|
|
%cmp = icmp slt ptr %first1, %last2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep13(ptr %ptr) {
|
|
; CHECK-LABEL: @gep13(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
; We can prove this GEP is non-null because it is inbounds.
|
|
%x = getelementptr inbounds i8, ptr %ptr, i32 1
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep13_no_null_opt(ptr %ptr) #0 {
|
|
; We can't prove this GEP is non-null.
|
|
; CHECK-LABEL: @gep13_no_null_opt(
|
|
; CHECK-NEXT: [[X:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i32 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x = getelementptr inbounds i8, ptr %ptr, i32 1
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; We can prove this GEP is non-null because it is nuw.
|
|
define i1 @gep_nuw_not_null(ptr %ptr) {
|
|
; CHECK-LABEL: @gep_nuw_not_null(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x = getelementptr nuw i8, ptr %ptr, i32 1
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Unlike the inbounds case, this holds even if the null pointer is valid.
|
|
define i1 @gep_nuw_null_pointer_valid(ptr %ptr) null_pointer_is_valid {
|
|
; CHECK-LABEL: @gep_nuw_null_pointer_valid(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x = getelementptr nuw i8, ptr %ptr, i32 1
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; If the base pointer is non-null, the offset doesn't matter.
|
|
define i1 @gep_nuw_maybe_zero_offset(ptr nonnull %ptr, i32 %offset) {
|
|
; CHECK-LABEL: @gep_nuw_maybe_zero_offset(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x = getelementptr nuw i8, ptr %ptr, i32 %offset
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; We can not prove non-null if both the base pointer may be null and the
|
|
; offset zero.
|
|
define i1 @gep13_nuw_maybe_zero_offset(ptr %ptr, i32 %offset) {
|
|
; CHECK-LABEL: @gep13_nuw_maybe_zero_offset(
|
|
; CHECK-NEXT: [[X:%.*]] = getelementptr nuw i8, ptr [[PTR:%.*]], i32 [[OFFSET:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x = getelementptr nuw i8, ptr %ptr, i32 %offset
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; For gep nusw we don't have any non-null information.
|
|
define i1 @gep_nusw_may_be_null(ptr %ptr) {
|
|
; CHECK-LABEL: @gep_nusw_may_be_null(
|
|
; CHECK-NEXT: [[X:%.*]] = getelementptr nusw i8, ptr [[PTR:%.*]], i32 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x = getelementptr nusw i8, ptr %ptr, i32 1
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep14(ptr %ptr) {
|
|
; CHECK-LABEL: @gep14(
|
|
; CHECK-NEXT: [[X:%.*]] = getelementptr inbounds { {}, i8 }, ptr [[PTR:%.*]], i32 0, i32 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
; We can't simplify this because the offset of one in the GEP actually doesn't
|
|
; move the pointer.
|
|
%x = getelementptr inbounds { {}, i8 }, ptr %ptr, i32 0, i32 1
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep15(ptr %ptr, i32 %y) {
|
|
; CHECK-LABEL: @gep15(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
; We can prove this GEP is non-null even though there is a user value, as we
|
|
; would necessarily violate inbounds on one side or the other.
|
|
%x = getelementptr inbounds { {}, [4 x {i8, i8}]}, ptr %ptr, i32 0, i32 1, i32 %y, i32 1
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep15_no_null_opt(ptr %ptr, i32 %y) #0 {
|
|
; We can't prove this GEP is non-null.
|
|
; CHECK-LABEL: @gep15_no_null_opt(
|
|
; CHECK-NEXT: [[X:%.*]] = getelementptr inbounds { {}, [4 x { i8, i8 }] }, ptr [[PTR:%.*]], i32 0, i32 1, i32 [[Y:%.*]], i32 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x = getelementptr inbounds { {}, [4 x {i8, i8}]}, ptr %ptr, i32 0, i32 1, i32 %y, i32 1
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep16(ptr %ptr, i32 %a) {
|
|
; CHECK-LABEL: @gep16(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
; We can prove this GEP is non-null because it is inbounds and because we know
|
|
; %b is non-zero even though we don't know its value.
|
|
%b = or i32 %a, 1
|
|
%x = getelementptr inbounds i8, ptr %ptr, i32 %b
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep16_no_null_opt(ptr %ptr, i32 %a) #0 {
|
|
; We can't prove this GEP is non-null.
|
|
; CHECK-LABEL: @gep16_no_null_opt(
|
|
; CHECK-NEXT: [[B:%.*]] = or i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[X:%.*]] = getelementptr inbounds i8, ptr [[PTR:%.*]], i32 [[B]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%b = or i32 %a, 1
|
|
%x = getelementptr inbounds i8, ptr %ptr, i32 %b
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @gep17() {
|
|
; CHECK-LABEL: @gep17(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%alloca = alloca i32, align 4
|
|
%gep1 = getelementptr inbounds i32, ptr %alloca, i32 1
|
|
%pti1 = ptrtoint ptr %gep1 to i32
|
|
%gep2 = getelementptr inbounds [4 x i8], ptr %alloca, i32 0, i32 1
|
|
%pti2 = ptrtoint ptr %gep2 to i32
|
|
%cmp = icmp ugt i32 %pti1, %pti2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
@extern_weak = extern_weak global i8
|
|
|
|
define i1 @extern_weak_may_be_null() {
|
|
; CHECK-LABEL: @extern_weak_may_be_null(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr @extern_weak, null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp ne ptr @extern_weak, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Don't fold this. @A might really be allocated next to @B, in which case the
|
|
; icmp should return true. It's not valid to *dereference* in @B from a pointer
|
|
; based on @A, but icmp isn't a dereference.
|
|
define i1 @globals_might_be_adjacent() {
|
|
; CHECK-LABEL: @globals_might_be_adjacent(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr getelementptr inbounds (i32, ptr @A, i64 1), @B
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr getelementptr inbounds (i32, ptr @A, i64 1), @B
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @globals_might_be_adjacent2() {
|
|
; CHECK-LABEL: @globals_might_be_adjacent2(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr getelementptr inbounds (i64, ptr @A, i64 1), getelementptr inbounds (i64, ptr @B, i64 2)
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr getelementptr inbounds (i64, ptr @A, i64 1), getelementptr inbounds (i64, ptr @B, i64 2)
|
|
ret i1 %cmp
|
|
}
|
|
|
|
@weak = weak global i32 0
|
|
|
|
; An object with weak linkage cannot have it's identity determined at compile time.
|
|
define i1 @weak_comparison() {
|
|
; CHECK-LABEL: @weak_comparison(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr @weak, @A
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr @weak, @A
|
|
ret i1 %cmp
|
|
}
|
|
|
|
@empty.1 = external global [0 x i8], align 1
|
|
@empty.2 = external global [0 x i8], align 1
|
|
|
|
; Empty globals might end up anywhere, even on top of another global.
|
|
define i1 @empty_global_comparison() {
|
|
; CHECK-LABEL: @empty_global_comparison(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr @empty.1, @empty.2
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr @empty.1, @empty.2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
@unnamed.1 = unnamed_addr constant [5 x i8] c"asdf\00"
|
|
@unnamed.2 = unnamed_addr constant [5 x i8] c"asdf\00"
|
|
|
|
; Two unnamed_addr globals can share an address
|
|
define i1 @unnamed_addr_comparison() {
|
|
; CHECK-LABEL: @unnamed_addr_comparison(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr @unnamed.1, @unnamed.2
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr @unnamed.1, @unnamed.2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
@addrspace3 = internal addrspace(3) global i32 undef
|
|
|
|
define i1 @no.fold.addrspace.icmp.eq.gv.null() {
|
|
; CHECK-LABEL: @no.fold.addrspace.icmp.eq.gv.null(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr addrspace(3) @addrspace3, null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr addrspace(3) @addrspace3, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @no.fold.addrspace.icmp.eq.null.gv() {
|
|
; CHECK-LABEL: @no.fold.addrspace.icmp.eq.null.gv(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr addrspace(3) null, @addrspace3
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr addrspace(3) null, @addrspace3
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @no.fold.addrspace.icmp.ne.gv.null() {
|
|
; CHECK-LABEL: @no.fold.addrspace.icmp.ne.gv.null(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr addrspace(3) @addrspace3, null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp ne ptr addrspace(3) @addrspace3, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @no.fold.addrspace.icmp.ne.null.gv() {
|
|
; CHECK-LABEL: @no.fold.addrspace.icmp.ne.null.gv(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr addrspace(3) null, @addrspace3
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp ne ptr addrspace(3) null, @addrspace3
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test: GEP inbounds may cross sign boundary.
|
|
define i1 @gep_same_base_constant_indices(ptr %a) {
|
|
; CHECK-LABEL: @gep_same_base_constant_indices(
|
|
; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, ptr [[A:%.*]], i64 1
|
|
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 10
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt ptr [[ARRAYIDX1]], [[ARRAYIDX2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%arrayidx1 = getelementptr inbounds i8, ptr %a, i64 1
|
|
%arrayidx2 = getelementptr inbounds i8, ptr %a, i64 10
|
|
%cmp = icmp slt ptr %arrayidx1, %arrayidx2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @zext(i32 %x) {
|
|
; CHECK-LABEL: @zext(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%e1 = zext i32 %x to i64
|
|
%e2 = zext i32 %x to i64
|
|
%r = icmp eq i64 %e1, %e2
|
|
ret i1 %r
|
|
}
|
|
|
|
define i1 @zext2(i1 %x) {
|
|
; CHECK-LABEL: @zext2(
|
|
; CHECK-NEXT: ret i1 [[X:%.*]]
|
|
;
|
|
%e = zext i1 %x to i32
|
|
%c = icmp ne i32 %e, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @zext3() {
|
|
; CHECK-LABEL: @zext3(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%e = zext i1 1 to i32
|
|
%c = icmp ne i32 %e, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @sext(i32 %x) {
|
|
; CHECK-LABEL: @sext(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%e1 = sext i32 %x to i64
|
|
%e2 = sext i32 %x to i64
|
|
%r = icmp eq i64 %e1, %e2
|
|
ret i1 %r
|
|
}
|
|
|
|
define i1 @sext2(i1 %x) {
|
|
; CHECK-LABEL: @sext2(
|
|
; CHECK-NEXT: ret i1 [[X:%.*]]
|
|
;
|
|
%e = sext i1 %x to i32
|
|
%c = icmp ne i32 %e, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @sext3() {
|
|
; CHECK-LABEL: @sext3(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%e = sext i1 1 to i32
|
|
%c = icmp ne i32 %e, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @add(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @add(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%l = lshr i32 %x, 1
|
|
%q = lshr i32 %y, 1
|
|
%r = or i32 %q, 1
|
|
%s = add i32 %l, %r
|
|
%c = icmp eq i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @addv(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @addv(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%l = lshr <2 x i32> %x, <i32 1, i32 0>
|
|
%q = lshr <2 x i32> %y, <i32 1, i32 0>
|
|
%r = or <2 x i32> %q, <i32 1, i32 0>
|
|
%s = add <2 x i32> %l, %r
|
|
%e = extractelement <2 x i32> %s, i32 0
|
|
%c = icmp eq i32 %e, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @add2(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @add2(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%l = or i8 %x, 128
|
|
%r = or i8 %y, 129
|
|
%s = add i8 %l, %r
|
|
%c = icmp eq i8 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @add2v(<2 x i8> %x, <2 x i8> %y) {
|
|
; CHECK-LABEL: @add2v(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%l = or <2 x i8> %x, <i8 0, i8 128>
|
|
%r = or <2 x i8> %y, <i8 0, i8 129>
|
|
%s = add <2 x i8> %l, %r
|
|
%e = extractelement <2 x i8> %s, i32 1
|
|
%c = icmp eq i8 %e, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @add3(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @add3(
|
|
; CHECK-NEXT: [[L:%.*]] = zext i8 [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[R:%.*]] = zext i8 [[Y:%.*]] to i32
|
|
; CHECK-NEXT: [[S:%.*]] = add i32 [[L]], [[R]]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[S]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%l = zext i8 %x to i32
|
|
%r = zext i8 %y to i32
|
|
%s = add i32 %l, %r
|
|
%c = icmp eq i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @add4(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @add4(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%z = add nsw i32 %y, 1
|
|
%s1 = add nsw i32 %x, %y
|
|
%s2 = add nsw i32 %x, %z
|
|
%c = icmp slt i32 %s1, %s2
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @add5(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @add5(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%z = add nuw i32 %y, 1
|
|
%s1 = add nuw i32 %x, %z
|
|
%s2 = add nuw i32 %x, %y
|
|
%c = icmp ugt i32 %s1, %s2
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @add6(i64 %A, i64 %B) {
|
|
; CHECK-LABEL: @add6(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%s1 = add i64 %A, %B
|
|
%s2 = add i64 %B, %A
|
|
%cmp = icmp eq i64 %s1, %s2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @addpowtwo(i32 %x, i32 %y) {
|
|
; CHECK-LABEL: @addpowtwo(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%l = lshr i32 %x, 1
|
|
%r = shl i32 1, %y
|
|
%s = add i32 %l, %r
|
|
%c = icmp eq i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @addpowtwov(<2 x i32> %x, <2 x i32> %y) {
|
|
; CHECK-LABEL: @addpowtwov(
|
|
; CHECK-NEXT: [[L:%.*]] = lshr <2 x i32> [[X:%.*]], <i32 1, i32 0>
|
|
; CHECK-NEXT: [[R:%.*]] = shl <2 x i32> <i32 1, i32 0>, [[Y:%.*]]
|
|
; CHECK-NEXT: [[S:%.*]] = add <2 x i32> [[L]], [[R]]
|
|
; CHECK-NEXT: [[E:%.*]] = extractelement <2 x i32> [[S]], i32 0
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[E]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%l = lshr <2 x i32> %x, <i32 1, i32 0>
|
|
%r = shl <2 x i32> <i32 1, i32 0>, %y
|
|
%s = add <2 x i32> %l, %r
|
|
%e = extractelement <2 x i32> %s, i32 0
|
|
%c = icmp eq i32 %e, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @or(i32 %x) {
|
|
; CHECK-LABEL: @or(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%o = or i32 %x, 1
|
|
%c = icmp eq i32 %o, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
; Do not simplify if we cannot guarantee that the ConstantExpr is a non-zero
|
|
; constant.
|
|
@GV = common global ptr null
|
|
define i1 @or_constexp(i32 %x) {
|
|
; CHECK-LABEL: @or_constexp(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = and i32 ptrtoint (ptr @GV to i32), 32
|
|
; CHECK-NEXT: [[O:%.*]] = or i32 [[X:%.*]], [[TMP0]]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[O]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
entry:
|
|
%0 = and i32 ptrtoint (ptr @GV to i32), 32
|
|
%o = or i32 %x, %0
|
|
%c = icmp eq i32 %o, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @shl1(i32 %x) {
|
|
; CHECK-LABEL: @shl1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%s = shl i32 1, %x
|
|
%c = icmp eq i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @lshr1(i32 %x) {
|
|
; CHECK-LABEL: @lshr1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%s = lshr i32 -1, %x
|
|
%c = icmp eq i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @lshr3(i32 %x) {
|
|
; CHECK-LABEL: @lshr3(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%s = lshr i32 %x, %x
|
|
%c = icmp eq i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @lshr4(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @lshr4(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%A = lshr i32 %X, %Y
|
|
%C = icmp ule i32 %A, %X
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @lshr5(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @lshr5(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = lshr i32 %X, %Y
|
|
%C = icmp ugt i32 %A, %X
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @lshr6(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @lshr6(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = lshr i32 %X, %Y
|
|
%C = icmp ult i32 %X, %A
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @lshr7(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @lshr7(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%A = lshr i32 %X, %Y
|
|
%C = icmp uge i32 %X, %A
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @lshr_nonzero_eq(i32 %x) {
|
|
; CHECK-LABEL: @lshr_nonzero_eq(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = lshr i32 %x, 1
|
|
%cmp = icmp eq i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @lshr_nonzero_uge(i32 %x) {
|
|
; CHECK-LABEL: @lshr_nonzero_uge(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = lshr i32 %x, 1
|
|
%cmp = icmp uge i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @lshr_nonzero_ne(i32 %x) {
|
|
; CHECK-LABEL: @lshr_nonzero_ne(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = lshr i32 %x, 1
|
|
%cmp = icmp ne i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @lshr_nonzero_ult(i32 %x) {
|
|
; CHECK-LABEL: @lshr_nonzero_ult(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = lshr i32 %x, 1
|
|
%cmp = icmp ult i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test - unknown shift amount
|
|
define i1 @lshr_nonzero_neg_unknown(i32 %x, i32 %c) {
|
|
; CHECK-LABEL: @lshr_nonzero_neg_unknown(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], [[C:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = lshr i32 %x, %c
|
|
%cmp = icmp ult i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test - x may be zero
|
|
define i1 @lshr_nonzero_neg_maybe_zero(i32 %x) {
|
|
; CHECK-LABEL: @lshr_nonzero_neg_maybe_zero(
|
|
; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%lhs = lshr i32 %x, 1
|
|
%cmp = icmp ult i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test - signed pred
|
|
define i1 @lshr_nonzero_neg_signed(i32 %x, i32 %c) {
|
|
; CHECK-LABEL: @lshr_nonzero_neg_signed(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: [[LHS:%.*]] = lshr i32 [[X]], 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[LHS]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = lshr i32 %x, 1
|
|
%cmp = icmp slt i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @ashr1(i32 %x) {
|
|
; CHECK-LABEL: @ashr1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%s = ashr i32 -1, %x
|
|
%c = icmp eq i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @ashr3(i32 %x) {
|
|
; CHECK-LABEL: @ashr3(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%s = ashr i32 %x, %x
|
|
%c = icmp eq i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @select1(i1 %cond) {
|
|
; CHECK-LABEL: @select1(
|
|
; CHECK-NEXT: ret i1 [[COND:%.*]]
|
|
;
|
|
%s = select i1 %cond, i32 1, i32 0
|
|
%c = icmp eq i32 %s, 1
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @select2(i1 %cond) {
|
|
; CHECK-LABEL: @select2(
|
|
; CHECK-NEXT: ret i1 [[COND:%.*]]
|
|
;
|
|
%x = zext i1 %cond to i32
|
|
%s = select i1 %cond, i32 %x, i32 0
|
|
%c = icmp ne i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @select3(i1 %cond) {
|
|
; CHECK-LABEL: @select3(
|
|
; CHECK-NEXT: ret i1 [[COND:%.*]]
|
|
;
|
|
%x = zext i1 %cond to i32
|
|
%s = select i1 %cond, i32 1, i32 %x
|
|
%c = icmp ne i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @select4(i1 %cond) {
|
|
; CHECK-LABEL: @select4(
|
|
; CHECK-NEXT: ret i1 [[COND:%.*]]
|
|
;
|
|
%invert = xor i1 %cond, 1
|
|
%s = select i1 %invert, i32 0, i32 1
|
|
%c = icmp ne i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define i1 @select5(i32 %x) {
|
|
; CHECK-LABEL: @select5(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%c = icmp eq i32 %x, 0
|
|
%s = select i1 %c, i32 1, i32 %x
|
|
%c2 = icmp eq i32 %s, 0
|
|
ret i1 %c2
|
|
}
|
|
|
|
define i1 @select6(i32 %x) {
|
|
; CHECK-LABEL: @select6(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%c = icmp sgt i32 %x, 0
|
|
%s = select i1 %c, i32 %x, i32 4
|
|
%c2 = icmp eq i32 %s, 0
|
|
ret i1 %c2
|
|
}
|
|
|
|
define i1 @urem1(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @urem1(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%A = urem i32 %X, %Y
|
|
%B = icmp ult i32 %A, %Y
|
|
ret i1 %B
|
|
}
|
|
|
|
define i1 @urem2(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @urem2(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = urem i32 %X, %Y
|
|
%B = icmp eq i32 %A, %Y
|
|
ret i1 %B
|
|
}
|
|
|
|
define i1 @urem4(i32 %X) {
|
|
; CHECK-LABEL: @urem4(
|
|
; CHECK-NEXT: [[A:%.*]] = urem i32 [[X:%.*]], 15
|
|
; CHECK-NEXT: [[B:%.*]] = icmp ult i32 [[A]], 10
|
|
; CHECK-NEXT: ret i1 [[B]]
|
|
;
|
|
%A = urem i32 %X, 15
|
|
%B = icmp ult i32 %A, 10
|
|
ret i1 %B
|
|
}
|
|
|
|
define i1 @urem5(i16 %X, i32 %Y) {
|
|
; CHECK-LABEL: @urem5(
|
|
; CHECK-NEXT: [[A:%.*]] = zext i16 [[X:%.*]] to i32
|
|
; CHECK-NEXT: [[B:%.*]] = urem i32 [[A]], [[Y:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp slt i32 [[B]], [[Y]]
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%A = zext i16 %X to i32
|
|
%B = urem i32 %A, %Y
|
|
%C = icmp slt i32 %B, %Y
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @urem6(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @urem6(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%A = urem i32 %X, %Y
|
|
%B = icmp ugt i32 %Y, %A
|
|
ret i1 %B
|
|
}
|
|
|
|
define i1 @urem7(i32 %X) {
|
|
; CHECK-LABEL: @urem7(
|
|
; CHECK-NEXT: [[A:%.*]] = urem i32 1, [[X:%.*]]
|
|
; CHECK-NEXT: [[B:%.*]] = icmp sgt i32 [[A]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[B]]
|
|
;
|
|
%A = urem i32 1, %X
|
|
%B = icmp sgt i32 %A, %X
|
|
ret i1 %B
|
|
}
|
|
|
|
define i1 @urem8(i8 %X, i8 %Y) {
|
|
; CHECK-LABEL: @urem8(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%A = urem i8 %X, %Y
|
|
%B = icmp ule i8 %A, %X
|
|
ret i1 %B
|
|
}
|
|
|
|
define i1 @urem9(i8 %X, i8 %Y) {
|
|
; CHECK-LABEL: @urem9(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = urem i8 %X, %Y
|
|
%B = icmp ugt i8 %A, %X
|
|
ret i1 %B
|
|
}
|
|
|
|
define i1 @urem10(i8 %X, i8 %Y) {
|
|
; CHECK-LABEL: @urem10(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%A = urem i8 %X, %Y
|
|
%B = icmp uge i8 %X, %A
|
|
ret i1 %B
|
|
}
|
|
|
|
define i1 @urem11(i8 %X, i8 %Y) {
|
|
; CHECK-LABEL: @urem11(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = urem i8 %X, %Y
|
|
%B = icmp ult i8 %X, %A
|
|
ret i1 %B
|
|
}
|
|
|
|
; PR9343 #15
|
|
define i1 @srem2(i16 %X, i32 %Y) {
|
|
; CHECK-LABEL: @srem2(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = zext i16 %X to i32
|
|
%B = add nsw i32 %A, 1
|
|
%C = srem i32 %B, %Y
|
|
%D = icmp slt i32 %C, 0
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @srem2v(<2 x i16> %X, <2 x i32> %Y) {
|
|
; CHECK-LABEL: @srem2v(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = zext <2 x i16> %X to <2 x i32>
|
|
%B = add nsw <2 x i32> %A, <i32 1, i32 0>
|
|
%C = srem <2 x i32> %B, %Y
|
|
%D = extractelement <2 x i32> %C, i32 0
|
|
%E = icmp slt i32 %D, 0
|
|
ret i1 %E
|
|
}
|
|
|
|
define i1 @srem3(i16 %X, i32 %Y) {
|
|
; CHECK-LABEL: @srem3(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = zext i16 %X to i32
|
|
%B = or i32 2147483648, %A
|
|
%C = sub nsw i32 1, %B
|
|
%D = srem i32 %C, %Y
|
|
%E = icmp slt i32 %D, 0
|
|
ret i1 %E
|
|
}
|
|
|
|
define i1 @srem3v(<2 x i16> %X, <2 x i32> %Y) {
|
|
; CHECK-LABEL: @srem3v(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = zext <2 x i16> %X to <2 x i32>
|
|
%B = or <2 x i32> <i32 1, i32 2147483648>, %A
|
|
%C = sub nsw <2 x i32> <i32 0, i32 1>, %B
|
|
%D = srem <2 x i32> %C, %Y
|
|
%E = extractelement <2 x i32> %C, i32 1
|
|
%F = icmp slt i32 %E, 0
|
|
ret i1 %F
|
|
}
|
|
|
|
define i1 @udiv2(i32 %Z) {
|
|
; CHECK-LABEL: @udiv2(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%A = udiv exact i32 10, %Z
|
|
%B = udiv exact i32 20, %Z
|
|
%C = icmp ult i32 %A, %B
|
|
ret i1 %C
|
|
}
|
|
|
|
; Exact sdiv and equality preds can simplify.
|
|
|
|
define i1 @sdiv_exact_equality(i32 %Z) {
|
|
; CHECK-LABEL: @sdiv_exact_equality(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = sdiv exact i32 10, %Z
|
|
%B = sdiv exact i32 20, %Z
|
|
%C = icmp eq i32 %A, %B
|
|
ret i1 %C
|
|
}
|
|
|
|
; But not other preds: PR32949 - https://bugs.llvm.org/show_bug.cgi?id=32949
|
|
|
|
define i1 @sdiv_exact_not_equality(i32 %Z) {
|
|
; CHECK-LABEL: @sdiv_exact_not_equality(
|
|
; CHECK-NEXT: [[A:%.*]] = sdiv exact i32 10, [[Z:%.*]]
|
|
; CHECK-NEXT: [[B:%.*]] = sdiv exact i32 20, [[Z]]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ult i32 [[A]], [[B]]
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%A = sdiv exact i32 10, %Z
|
|
%B = sdiv exact i32 20, %Z
|
|
%C = icmp ult i32 %A, %B
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @udiv3(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @udiv3(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = udiv i32 %X, %Y
|
|
%C = icmp ugt i32 %A, %X
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @udiv4(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @udiv4(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%A = udiv i32 %X, %Y
|
|
%C = icmp ule i32 %A, %X
|
|
ret i1 %C
|
|
}
|
|
|
|
; PR11340
|
|
define i1 @udiv6(i32 %X) nounwind {
|
|
; CHECK-LABEL: @udiv6(
|
|
; CHECK-NEXT: [[A:%.*]] = udiv i32 1, [[X:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp eq i32 [[A]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%A = udiv i32 1, %X
|
|
%C = icmp eq i32 %A, 0
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @udiv7(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @udiv7(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%A = udiv i32 %X, %Y
|
|
%C = icmp ult i32 %X, %A
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @udiv8(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @udiv8(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%A = udiv i32 %X, %Y
|
|
%C = icmp uge i32 %X, %A
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @udiv_nonzero_eq(i32 %x) {
|
|
; CHECK-LABEL: @udiv_nonzero_eq(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = udiv i32 %x, 3
|
|
%cmp = icmp eq i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @udiv_nonzero_uge(i32 %x) {
|
|
; CHECK-LABEL: @udiv_nonzero_uge(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = udiv i32 %x, 3
|
|
%cmp = icmp uge i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @udiv_nonzero_ne(i32 %x) {
|
|
; CHECK-LABEL: @udiv_nonzero_ne(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = udiv i32 %x, 3
|
|
%cmp = icmp ne i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @udiv_nonzero_ult(i32 %x) {
|
|
; CHECK-LABEL: @udiv_nonzero_ult(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = udiv i32 %x, 3
|
|
%cmp = icmp ult i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test - unknown divisor
|
|
define i1 @udiv_nonzero_neg_unknown(i32 %x, i32 %c) {
|
|
; CHECK-LABEL: @udiv_nonzero_neg_unknown(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], [[C:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = udiv i32 %x, %c
|
|
%cmp = icmp ult i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test - x may be zero
|
|
define i1 @udiv_nonzero_neg_maybe_zero(i32 %x) {
|
|
; CHECK-LABEL: @udiv_nonzero_neg_maybe_zero(
|
|
; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X:%.*]], 3
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[LHS]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%lhs = udiv i32 %x, 3
|
|
%cmp = icmp ult i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test - signed pred
|
|
define i1 @udiv_nonzero_neg_signed(i32 %x) {
|
|
; CHECK-LABEL: @udiv_nonzero_neg_signed(
|
|
; CHECK-NEXT: [[X_NE_0:%.*]] = icmp ne i32 [[X:%.*]], 0
|
|
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NE_0]])
|
|
; CHECK-NEXT: [[LHS:%.*]] = udiv i32 [[X]], 3
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[LHS]], [[X]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x_ne_0 = icmp ne i32 %x, 0
|
|
call void @llvm.assume(i1 %x_ne_0)
|
|
%lhs = udiv i32 %x, 3
|
|
%cmp = icmp slt i32 %lhs, %x
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Square of a non-zero number is non-zero if there is no overflow.
|
|
define i1 @mul1(i32 %X) {
|
|
; CHECK-LABEL: @mul1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%Y = or i32 %X, 1
|
|
%M = mul nuw i32 %Y, %Y
|
|
%C = icmp eq i32 %M, 0
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @mul1v(<2 x i32> %X) {
|
|
; CHECK-LABEL: @mul1v(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%Y = or <2 x i32> %X, <i32 1, i32 0>
|
|
%M = mul nuw <2 x i32> %Y, %Y
|
|
%E = extractelement <2 x i32> %M, i32 0
|
|
%C = icmp eq i32 %E, 0
|
|
ret i1 %C
|
|
}
|
|
|
|
; Square of a non-zero number is positive if there is no signed overflow.
|
|
define i1 @mul2(i32 %X) {
|
|
; CHECK-LABEL: @mul2(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%Y = or i32 %X, 1
|
|
%M = mul nsw i32 %Y, %Y
|
|
%C = icmp sgt i32 %M, 0
|
|
ret i1 %C
|
|
}
|
|
|
|
define i1 @mul2v(<2 x i32> %X) {
|
|
; CHECK-LABEL: @mul2v(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%Y = or <2 x i32> %X, <i32 0, i32 1>
|
|
%M = mul nsw <2 x i32> %Y, %Y
|
|
%E = extractelement <2 x i32> %M, i32 1
|
|
%C = icmp sgt i32 %E, 0
|
|
ret i1 %C
|
|
}
|
|
|
|
; Product of non-negative numbers is non-negative if there is no signed overflow.
|
|
define i1 @mul3(i32 %X, i32 %Y) {
|
|
; CHECK-LABEL: @mul3(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%XX = mul nsw i32 %X, %X
|
|
%YY = mul nsw i32 %Y, %Y
|
|
%M = mul nsw i32 %XX, %YY
|
|
%C = icmp sge i32 %M, 0
|
|
ret i1 %C
|
|
}
|
|
|
|
define <2 x i1> @mul3v(<2 x i32> %X, <2 x i32> %Y) {
|
|
; CHECK-LABEL: @mul3v(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%XX = mul nsw <2 x i32> %X, %X
|
|
%YY = mul nsw <2 x i32> %Y, %Y
|
|
%M = mul nsw <2 x i32> %XX, %YY
|
|
%C = icmp sge <2 x i32> %M, zeroinitializer
|
|
ret <2 x i1> %C
|
|
}
|
|
|
|
define <2 x i1> @vectorselect1(<2 x i1> %cond) {
|
|
; CHECK-LABEL: @vectorselect1(
|
|
; CHECK-NEXT: ret <2 x i1> [[COND:%.*]]
|
|
;
|
|
%invert = xor <2 x i1> %cond, <i1 1, i1 1>
|
|
%s = select <2 x i1> %invert, <2 x i32> <i32 0, i32 0>, <2 x i32> <i32 1, i32 1>
|
|
%c = icmp ne <2 x i32> %s, <i32 0, i32 0>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
; PR11948
|
|
define <2 x i1> @vectorselectcrash(i32 %arg1) {
|
|
; CHECK-LABEL: @vectorselectcrash(
|
|
; CHECK-NEXT: [[TOBOOL40:%.*]] = icmp ne i32 [[ARG1:%.*]], 0
|
|
; CHECK-NEXT: [[COND43:%.*]] = select i1 [[TOBOOL40]], <2 x i16> <i16 -5, i16 66>, <2 x i16> <i16 46, i16 1>
|
|
; CHECK-NEXT: [[CMP45:%.*]] = icmp ugt <2 x i16> [[COND43]], <i16 73, i16 21>
|
|
; CHECK-NEXT: ret <2 x i1> [[CMP45]]
|
|
;
|
|
%tobool40 = icmp ne i32 %arg1, 0
|
|
%cond43 = select i1 %tobool40, <2 x i16> <i16 -5, i16 66>, <2 x i16> <i16 46, i16 1>
|
|
%cmp45 = icmp ugt <2 x i16> %cond43, <i16 73, i16 21>
|
|
ret <2 x i1> %cmp45
|
|
}
|
|
|
|
; PR12013
|
|
define i1 @alloca_compare(i64 %idx) {
|
|
; CHECK-LABEL: @alloca_compare(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%sv = alloca { i32, i32, [124 x i32] }
|
|
%1 = getelementptr inbounds { i32, i32, [124 x i32] }, ptr %sv, i32 0, i32 2, i64 %idx
|
|
%2 = icmp eq ptr %1, null
|
|
ret i1 %2
|
|
}
|
|
|
|
define i1 @alloca_compare_no_null_opt(i64 %idx) #0 {
|
|
; CHECK-LABEL: @alloca_compare_no_null_opt(
|
|
; CHECK-NEXT: [[SV:%.*]] = alloca { i32, i32, [124 x i32] }, align 8
|
|
; CHECK-NEXT: [[CMP:%.*]] = getelementptr inbounds { i32, i32, [124 x i32] }, ptr [[SV]], i32 0, i32 2, i64 [[IDX:%.*]]
|
|
; CHECK-NEXT: [[X:%.*]] = icmp eq ptr [[CMP]], null
|
|
; CHECK-NEXT: ret i1 [[X]]
|
|
;
|
|
%sv = alloca { i32, i32, [124 x i32] }
|
|
%cmp = getelementptr inbounds { i32, i32, [124 x i32] }, ptr %sv, i32 0, i32 2, i64 %idx
|
|
%X = icmp eq ptr %cmp, null
|
|
ret i1 %X
|
|
}
|
|
; PR12075
|
|
define i1 @infinite_gep() {
|
|
; CHECK-LABEL: @infinite_gep(
|
|
; CHECK-NEXT: ret i1 true
|
|
; CHECK: unreachableblock:
|
|
; CHECK-NEXT: [[X:%.*]] = getelementptr i32, ptr [[X]], i32 1
|
|
; CHECK-NEXT: [[Y:%.*]] = icmp eq ptr [[X]], null
|
|
; CHECK-NEXT: ret i1 [[Y]]
|
|
;
|
|
ret i1 1
|
|
|
|
unreachableblock:
|
|
%X = getelementptr i32, ptr%X, i32 1
|
|
%Y = icmp eq ptr %X, null
|
|
ret i1 %Y
|
|
}
|
|
|
|
; It's not valid to fold a comparison of an argument with an alloca, even though
|
|
; that's tempting. An argument can't *alias* an alloca, however the aliasing rule
|
|
; relies on restrictions against guessing an object's address and dereferencing.
|
|
; There are no restrictions against guessing an object's address and comparing.
|
|
|
|
define i1 @alloca_argument_compare(ptr %arg) {
|
|
; CHECK-LABEL: @alloca_argument_compare(
|
|
; CHECK-NEXT: [[ALLOC:%.*]] = alloca i64, align 8
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[ARG:%.*]], [[ALLOC]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%alloc = alloca i64
|
|
%cmp = icmp eq ptr %arg, %alloc
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; As above, but with the operands reversed.
|
|
|
|
define i1 @alloca_argument_compare_swapped(ptr %arg) {
|
|
; CHECK-LABEL: @alloca_argument_compare_swapped(
|
|
; CHECK-NEXT: [[ALLOC:%.*]] = alloca i64, align 8
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[ALLOC]], [[ARG:%.*]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%alloc = alloca i64
|
|
%cmp = icmp eq ptr %alloc, %arg
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Don't assume that a noalias argument isn't equal to a global variable's
|
|
; address. This is an example where AliasAnalysis' NoAlias concept is
|
|
; different from actual pointer inequality.
|
|
|
|
@y = external global i32
|
|
define zeroext i1 @external_compare(ptr noalias %x) {
|
|
; CHECK-LABEL: @external_compare(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X:%.*]], @y
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr %x, @y
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @alloca_gep(i64 %a, i64 %b) {
|
|
; CHECK-LABEL: @alloca_gep(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
; We can prove this GEP is non-null because it is inbounds and the pointer
|
|
; is non-null.
|
|
%strs = alloca [1000 x [1001 x i8]], align 16
|
|
%x = getelementptr inbounds [1000 x [1001 x i8]], ptr %strs, i64 0, i64 %a, i64 %b
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @alloca_gep_no_null_opt(i64 %a, i64 %b) #0 {
|
|
; CHECK-LABEL: @alloca_gep_no_null_opt(
|
|
; CHECK-NEXT: [[STRS:%.*]] = alloca [1000 x [1001 x i8]], align 16
|
|
; CHECK-NEXT: [[X:%.*]] = getelementptr inbounds [1000 x [1001 x i8]], ptr [[STRS]], i64 0, i64 [[A:%.*]], i64 [[B:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[X]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
; We can't prove this GEP is non-null.
|
|
%strs = alloca [1000 x [1001 x i8]], align 16
|
|
%x = getelementptr inbounds [1000 x [1001 x i8]], ptr %strs, i64 0, i64 %a, i64 %b
|
|
%cmp = icmp eq ptr %x, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @non_inbounds_gep_compare(ptr %a) {
|
|
; CHECK-LABEL: @non_inbounds_gep_compare(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
; Equality compares with non-inbounds GEPs can be folded.
|
|
%x = getelementptr i64, ptr %a, i64 42
|
|
%y = getelementptr inbounds i64, ptr %x, i64 -42
|
|
%z = getelementptr i64, ptr %a, i64 -42
|
|
%w = getelementptr inbounds i64, ptr %z, i64 42
|
|
%cmp = icmp eq ptr %y, %w
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @non_inbounds_gep_compare2(ptr %a) {
|
|
; CHECK-LABEL: @non_inbounds_gep_compare2(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
; Equality compares with non-inbounds GEPs can be folded.
|
|
%x = getelementptr i64, ptr %a, i64 4294967297
|
|
%y = getelementptr i64, ptr %a, i64 1
|
|
%cmp = icmp eq ptr %y, %y
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @compare_always_true_slt(i16 %a) {
|
|
; CHECK-LABEL: @compare_always_true_slt(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%t1 = zext i16 %a to i32
|
|
%t2 = sub i32 0, %t1
|
|
%t3 = icmp slt i32 %t2, 1
|
|
ret i1 %t3
|
|
}
|
|
|
|
define <2 x i1> @compare_always_true_slt_splat(<2 x i16> %a) {
|
|
; CHECK-LABEL: @compare_always_true_slt_splat(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%t1 = zext <2 x i16> %a to <2 x i32>
|
|
%t2 = sub <2 x i32> zeroinitializer, %t1
|
|
%t3 = icmp slt <2 x i32> %t2, <i32 1, i32 1>
|
|
ret <2 x i1> %t3
|
|
}
|
|
|
|
define i1 @compare_always_true_sle(i16 %a) {
|
|
; CHECK-LABEL: @compare_always_true_sle(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%t1 = zext i16 %a to i32
|
|
%t2 = sub i32 0, %t1
|
|
%t3 = icmp sle i32 %t2, 0
|
|
ret i1 %t3
|
|
}
|
|
|
|
define <2 x i1> @compare_always_true_sle_splat(<2 x i16> %a) {
|
|
; CHECK-LABEL: @compare_always_true_sle_splat(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%t1 = zext <2 x i16> %a to <2 x i32>
|
|
%t2 = sub <2 x i32> zeroinitializer, %t1
|
|
%t3 = icmp sle <2 x i32> %t2, zeroinitializer
|
|
ret <2 x i1> %t3
|
|
}
|
|
|
|
define i1 @compare_always_false_sgt(i16 %a) {
|
|
; CHECK-LABEL: @compare_always_false_sgt(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%t1 = zext i16 %a to i32
|
|
%t2 = sub i32 0, %t1
|
|
%t3 = icmp sgt i32 %t2, 0
|
|
ret i1 %t3
|
|
}
|
|
|
|
define <2 x i1> @compare_always_false_sgt_splat(<2 x i16> %a) {
|
|
; CHECK-LABEL: @compare_always_false_sgt_splat(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%t1 = zext <2 x i16> %a to <2 x i32>
|
|
%t2 = sub <2 x i32> zeroinitializer, %t1
|
|
%t3 = icmp sgt <2 x i32> %t2, zeroinitializer
|
|
ret <2 x i1> %t3
|
|
}
|
|
|
|
define i1 @compare_always_false_sge(i16 %a) {
|
|
; CHECK-LABEL: @compare_always_false_sge(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%t1 = zext i16 %a to i32
|
|
%t2 = sub i32 0, %t1
|
|
%t3 = icmp sge i32 %t2, 1
|
|
ret i1 %t3
|
|
}
|
|
|
|
define <2 x i1> @compare_always_false_sge_splat(<2 x i16> %a) {
|
|
; CHECK-LABEL: @compare_always_false_sge_splat(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%t1 = zext <2 x i16> %a to <2 x i32>
|
|
%t2 = sub <2 x i32> zeroinitializer, %t1
|
|
%t3 = icmp sge <2 x i32> %t2, <i32 1, i32 1>
|
|
ret <2 x i1> %t3
|
|
}
|
|
|
|
define i1 @compare_always_false_eq(i16 %a) {
|
|
; CHECK-LABEL: @compare_always_false_eq(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%t1 = zext i16 %a to i32
|
|
%t2 = sub i32 0, %t1
|
|
%t3 = icmp eq i32 %t2, 1
|
|
ret i1 %t3
|
|
}
|
|
|
|
define <2 x i1> @compare_always_false_eq_splat(<2 x i16> %a) {
|
|
; CHECK-LABEL: @compare_always_false_eq_splat(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%t1 = zext <2 x i16> %a to <2 x i32>
|
|
%t2 = sub <2 x i32> zeroinitializer, %t1
|
|
%t3 = icmp eq <2 x i32> %t2, <i32 1, i32 1>
|
|
ret <2 x i1> %t3
|
|
}
|
|
|
|
define i1 @compare_always_true_ne(i16 %a) {
|
|
; CHECK-LABEL: @compare_always_true_ne(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%t1 = zext i16 %a to i32
|
|
%t2 = sub i32 0, %t1
|
|
%t3 = icmp ne i32 %t2, 1
|
|
ret i1 %t3
|
|
}
|
|
|
|
define <2 x i1> @compare_always_true_ne_splat(<2 x i16> %a) {
|
|
; CHECK-LABEL: @compare_always_true_ne_splat(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%t1 = zext <2 x i16> %a to <2 x i32>
|
|
%t2 = sub <2 x i32> zeroinitializer, %t1
|
|
%t3 = icmp ne <2 x i32> %t2, <i32 1, i32 1>
|
|
ret <2 x i1> %t3
|
|
}
|
|
|
|
define i1 @lshr_ugt_false(i32 %a) {
|
|
; CHECK-LABEL: @lshr_ugt_false(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%shr = lshr i32 1, %a
|
|
%cmp = icmp ugt i32 %shr, 1
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @nonnull_arg(ptr nonnull %i) {
|
|
; CHECK-LABEL: @nonnull_arg(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%cmp = icmp eq ptr %i, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @nonnull_arg_no_null_opt(ptr nonnull %i) #0 {
|
|
; CHECK-LABEL: @nonnull_arg_no_null_opt(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%cmp = icmp eq ptr %i, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @nonnull_deref_arg(ptr dereferenceable(4) %i) {
|
|
; CHECK-LABEL: @nonnull_deref_arg(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%cmp = icmp eq ptr %i, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @nonnull_deref_arg_no_null_opt(ptr dereferenceable(4) %i) #0 {
|
|
; CHECK-LABEL: @nonnull_deref_arg_no_null_opt(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[I:%.*]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr %i, null
|
|
ret i1 %cmp
|
|
}
|
|
define i1 @nonnull_deref_as_arg(ptr addrspace(1) dereferenceable(4) %i) {
|
|
; CHECK-LABEL: @nonnull_deref_as_arg(
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr addrspace(1) [[I:%.*]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%cmp = icmp eq ptr addrspace(1) %i, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
declare nonnull ptr @returns_nonnull_helper()
|
|
define i1 @returns_nonnull() {
|
|
; CHECK-LABEL: @returns_nonnull(
|
|
; CHECK-NEXT: [[CALL:%.*]] = call nonnull ptr @returns_nonnull_helper()
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%call = call nonnull ptr @returns_nonnull_helper()
|
|
%cmp = icmp eq ptr %call, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
declare dereferenceable(4) ptr @returns_nonnull_deref_helper()
|
|
define i1 @returns_nonnull_deref() {
|
|
; CHECK-LABEL: @returns_nonnull_deref(
|
|
; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%call = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
|
|
%cmp = icmp eq ptr %call, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @returns_nonnull_deref_no_null_opt () #0 {
|
|
; CHECK-LABEL: @returns_nonnull_deref_no_null_opt(
|
|
; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[CALL]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%call = call dereferenceable(4) ptr @returns_nonnull_deref_helper()
|
|
%cmp = icmp eq ptr %call, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
declare dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
|
|
define i1 @returns_nonnull_as_deref() {
|
|
; CHECK-LABEL: @returns_nonnull_as_deref(
|
|
; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr addrspace(1) [[CALL]], null
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%call = call dereferenceable(4) ptr addrspace(1) @returns_nonnull_deref_as_helper()
|
|
%cmp = icmp eq ptr addrspace(1) %call, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @nonnull_load(ptr %addr) {
|
|
; CHECK-LABEL: @nonnull_load(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%ptr = load ptr, ptr %addr, !nonnull !{}
|
|
%cmp = icmp eq ptr %ptr, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @nonnull_load_as_outer(ptr addrspace(1) %addr) {
|
|
; CHECK-LABEL: @nonnull_load_as_outer(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%ptr = load ptr, ptr addrspace(1) %addr, !nonnull !{}
|
|
%cmp = icmp eq ptr %ptr, null
|
|
ret i1 %cmp
|
|
}
|
|
define i1 @nonnull_load_as_inner(ptr %addr) {
|
|
; CHECK-LABEL: @nonnull_load_as_inner(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%ptr = load ptr addrspace(1), ptr %addr, !nonnull !{}
|
|
%cmp = icmp eq ptr addrspace(1) %ptr, null
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; If a bit is known to be zero for A and known to be one for B,
|
|
; then A and B cannot be equal.
|
|
define i1 @icmp_eq_const(i32 %a) {
|
|
; CHECK-LABEL: @icmp_eq_const(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%b = mul nsw i32 %a, -2
|
|
%c = icmp eq i32 %b, 1
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @icmp_eq_const_vec(<2 x i32> %a) {
|
|
; CHECK-LABEL: @icmp_eq_const_vec(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%b = mul nsw <2 x i32> %a, <i32 -2, i32 -2>
|
|
%c = icmp eq <2 x i32> %b, <i32 1, i32 1>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define i1 @icmp_ne_const(i32 %a) {
|
|
; CHECK-LABEL: @icmp_ne_const(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%b = mul nsw i32 %a, -2
|
|
%c = icmp ne i32 %b, 1
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @icmp_ne_const_vec(<2 x i32> %a) {
|
|
; CHECK-LABEL: @icmp_ne_const_vec(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%b = mul nsw <2 x i32> %a, <i32 -2, i32 -2>
|
|
%c = icmp ne <2 x i32> %b, <i32 1, i32 1>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define i1 @icmp_sdiv_int_min(i32 %a) {
|
|
; CHECK-LABEL: @icmp_sdiv_int_min(
|
|
; CHECK-NEXT: [[DIV:%.*]] = sdiv i32 -2147483648, [[A:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[DIV]], -1073741824
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%div = sdiv i32 -2147483648, %a
|
|
%cmp = icmp ne i32 %div, -1073741824
|
|
ret i1 %cmp
|
|
|
|
}
|
|
|
|
define i1 @icmp_sdiv_pr20288(i64 %a) {
|
|
; CHECK-LABEL: @icmp_sdiv_pr20288(
|
|
; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 [[A:%.*]], -8589934592
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%div = sdiv i64 %a, -8589934592
|
|
%cmp = icmp ne i64 %div, 1073741824
|
|
ret i1 %cmp
|
|
|
|
}
|
|
|
|
define i1 @icmp_sdiv_neg1(i64 %a) {
|
|
; CHECK-LABEL: @icmp_sdiv_neg1(
|
|
; CHECK-NEXT: [[DIV:%.*]] = sdiv i64 [[A:%.*]], -1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%div = sdiv i64 %a, -1
|
|
%cmp = icmp ne i64 %div, 1073741824
|
|
ret i1 %cmp
|
|
|
|
}
|
|
|
|
define i1 @icmp_known_bits(i4 %x, i4 %y) {
|
|
; CHECK-LABEL: @icmp_known_bits(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%and1 = and i4 %y, -7
|
|
%and2 = and i4 %x, -7
|
|
%or1 = or i4 %and1, 2
|
|
%or2 = or i4 %and2, 2
|
|
%add = add i4 %or1, %or2
|
|
%cmp = icmp eq i4 %add, 0
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_known_bits_vec(<2 x i4> %x, <2 x i4> %y) {
|
|
; CHECK-LABEL: @icmp_known_bits_vec(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%and1 = and <2 x i4> %y, <i4 -7, i4 -1>
|
|
%and2 = and <2 x i4> %x, <i4 -7, i4 -1>
|
|
%or1 = or <2 x i4> %and1, <i4 2, i4 2>
|
|
%or2 = or <2 x i4> %and2, <i4 2, i4 2>
|
|
%add = add <2 x i4> %or1, %or2
|
|
%ext = extractelement <2 x i4> %add,i32 0
|
|
%cmp = icmp eq i4 %ext, 0
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_shl_nuw_1(i64 %a) {
|
|
; CHECK-LABEL: @icmp_shl_nuw_1(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%shl = shl nuw i64 1, %a
|
|
%cmp = icmp ne i64 %shl, 0
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_shl_1_V_ugt_2147483648(i32 %V) {
|
|
; CHECK-LABEL: @icmp_shl_1_V_ugt_2147483648(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%shl = shl i32 1, %V
|
|
%cmp = icmp ugt i32 %shl, 2147483648
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define <2 x i1> @icmp_shl_1_ugt_signmask(<2 x i8> %V) {
|
|
; CHECK-LABEL: @icmp_shl_1_ugt_signmask(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%shl = shl <2 x i8> <i8 1, i8 1>, %V
|
|
%cmp = icmp ugt <2 x i8> %shl, <i8 128, i8 128>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
define <2 x i1> @icmp_shl_1_ugt_signmask_poison(<2 x i8> %V) {
|
|
; CHECK-LABEL: @icmp_shl_1_ugt_signmask_poison(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%shl = shl <2 x i8> <i8 1, i8 1>, %V
|
|
%cmp = icmp ugt <2 x i8> %shl, <i8 128, i8 poison>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
define <2 x i1> @icmp_shl_1_ugt_signmask_poison2(<2 x i8> %V) {
|
|
; CHECK-LABEL: @icmp_shl_1_ugt_signmask_poison2(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%shl = shl <2 x i8> <i8 1, i8 poison>, %V
|
|
%cmp = icmp ugt <2 x i8> %shl, <i8 poison, i8 128>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
define i1 @icmp_shl_1_V_ule_2147483648(i32 %V) {
|
|
; CHECK-LABEL: @icmp_shl_1_V_ule_2147483648(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%shl = shl i32 1, %V
|
|
%cmp = icmp ule i32 %shl, 2147483648
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define <2 x i1> @icmp_shl_1_ule_signmask(<2 x i8> %V) {
|
|
; CHECK-LABEL: @icmp_shl_1_ule_signmask(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%shl = shl <2 x i8> <i8 1, i8 1>, %V
|
|
%cmp = icmp ule <2 x i8> %shl, <i8 128, i8 128>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
define <2 x i1> @icmp_shl_1_ule_signmask_poison(<2 x i8> %V) {
|
|
; CHECK-LABEL: @icmp_shl_1_ule_signmask_poison(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%shl = shl <2 x i8> <i8 1, i8 1>, %V
|
|
%cmp = icmp ule <2 x i8> %shl, <i8 128, i8 poison>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
define <2 x i1> @icmp_shl_1_ule_signmask_poison2(<2 x i8> %V) {
|
|
; CHECK-LABEL: @icmp_shl_1_ule_signmask_poison2(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%shl = shl <2 x i8> <i8 1, i8 poison>, %V
|
|
%cmp = icmp ule <2 x i8> %shl, <i8 poison, i8 128>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
define i1 @shl_1_cmp_eq_nonpow2(i32 %x) {
|
|
; CHECK-LABEL: @shl_1_cmp_eq_nonpow2(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%s = shl i32 1, %x
|
|
%c = icmp eq i32 %s, 31
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @shl_1_cmp_eq_nonpow2_splat(<2 x i32> %x) {
|
|
; CHECK-LABEL: @shl_1_cmp_eq_nonpow2_splat(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%s = shl <2 x i32> <i32 1, i32 1>, %x
|
|
%c = icmp eq <2 x i32> %s, <i32 31, i32 31>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define <2 x i1> @shl_1_cmp_eq_nonpow2_splat_poison(<2 x i32> %x) {
|
|
; CHECK-LABEL: @shl_1_cmp_eq_nonpow2_splat_poison(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%s = shl <2 x i32> <i32 1, i32 1>, %x
|
|
%c = icmp eq <2 x i32> %s, <i32 31, i32 poison>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define i1 @shl_1_cmp_ne_nonpow2(i32 %x) {
|
|
; CHECK-LABEL: @shl_1_cmp_ne_nonpow2(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%s = shl i32 1, %x
|
|
%c = icmp ne i32 %s, 42
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @shl_1_cmp_ne_nonpow2_splat(<2 x i32> %x) {
|
|
; CHECK-LABEL: @shl_1_cmp_ne_nonpow2_splat(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%s = shl <2 x i32> <i32 1, i32 1>, %x
|
|
%c = icmp ne <2 x i32> %s, <i32 42, i32 42>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define <2 x i1> @shl_1_cmp_ne_nonpow2_splat_poison(<2 x i32> %x) {
|
|
; CHECK-LABEL: @shl_1_cmp_ne_nonpow2_splat_poison(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%s = shl <2 x i32> <i32 poison, i32 1>, %x
|
|
%c = icmp ne <2 x i32> %s, <i32 42, i32 poison>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define i1 @shl_pow2_cmp_eq_nonpow2(i32 %x) {
|
|
; CHECK-LABEL: @shl_pow2_cmp_eq_nonpow2(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%s = shl i32 4, %x
|
|
%c = icmp eq i32 %s, 31
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @shl_pow21_cmp_ne_nonpow2_splat_poison(<2 x i32> %x) {
|
|
; CHECK-LABEL: @shl_pow21_cmp_ne_nonpow2_splat_poison(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%s = shl <2 x i32> <i32 poison, i32 4>, %x
|
|
%c = icmp ne <2 x i32> %s, <i32 31, i32 poison>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
; Negative test - overflowing shift could be zero.
|
|
|
|
define i1 @shl_pow2_cmp_ne_zero(i32 %x) {
|
|
; CHECK-LABEL: @shl_pow2_cmp_ne_zero(
|
|
; CHECK-NEXT: [[S:%.*]] = shl i32 16, [[X:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ne i32 [[S]], 0
|
|
; CHECK-NEXT: ret i1 [[C]]
|
|
;
|
|
%s = shl i32 16, %x
|
|
%c = icmp ne i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
; Negative test - overflowing shift could be zero.
|
|
|
|
define <2 x i1> @shl_pow2_cmp_ne_zero_splat(<2 x i32> %x) {
|
|
; CHECK-LABEL: @shl_pow2_cmp_ne_zero_splat(
|
|
; CHECK-NEXT: [[S:%.*]] = shl <2 x i32> <i32 16, i32 16>, [[X:%.*]]
|
|
; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i32> [[S]], zeroinitializer
|
|
; CHECK-NEXT: ret <2 x i1> [[C]]
|
|
;
|
|
%s = shl <2 x i32> <i32 16, i32 16>, %x
|
|
%c = icmp ne <2 x i32> %s, zeroinitializer
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define i1 @shl_pow2_cmp_eq_zero_nuw(i32 %x) {
|
|
; CHECK-LABEL: @shl_pow2_cmp_eq_zero_nuw(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%s = shl nuw i32 16, %x
|
|
%c = icmp eq i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @shl_pow2_cmp_ne_zero_nuw_splat_poison(<2 x i32> %x) {
|
|
; CHECK-LABEL: @shl_pow2_cmp_ne_zero_nuw_splat_poison(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%s = shl nuw <2 x i32> <i32 16, i32 poison>, %x
|
|
%c = icmp ne <2 x i32> %s, <i32 poison, i32 0>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define i1 @shl_pow2_cmp_ne_zero_nsw(i32 %x) {
|
|
; CHECK-LABEL: @shl_pow2_cmp_ne_zero_nsw(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%s = shl nsw i32 16, %x
|
|
%c = icmp ne i32 %s, 0
|
|
ret i1 %c
|
|
}
|
|
|
|
define <2 x i1> @shl_pow2_cmp_eq_zero_nsw_splat_poison(<2 x i32> %x) {
|
|
; CHECK-LABEL: @shl_pow2_cmp_eq_zero_nsw_splat_poison(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%s = shl nsw <2 x i32> <i32 poison, i32 16>, %x
|
|
%c = icmp eq <2 x i32> %s, <i32 0, i32 poison>
|
|
ret <2 x i1> %c
|
|
}
|
|
|
|
define i1 @tautological1(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @tautological1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C = and i32 %A, %B
|
|
%D = icmp ugt i32 %C, %A
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological2(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @tautological2(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C = and i32 %A, %B
|
|
%D = icmp ule i32 %C, %A
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological3(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @tautological3(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C = or i32 %A, %B
|
|
%D = icmp ule i32 %A, %C
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological4(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @tautological4(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C = or i32 %A, %B
|
|
%D = icmp ugt i32 %A, %C
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological5(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @tautological5(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C = or i32 %A, %B
|
|
%D = icmp ult i32 %C, %A
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological6(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @tautological6(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C = or i32 %A, %B
|
|
%D = icmp uge i32 %C, %A
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological7(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @tautological7(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C = and i32 %A, %B
|
|
%D = icmp uge i32 %A, %C
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological8(i32 %A, i32 %B) {
|
|
; CHECK-LABEL: @tautological8(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C = and i32 %A, %B
|
|
%D = icmp ult i32 %A, %C
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological9(i32 %A) {
|
|
; CHECK-LABEL: @tautological9(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 3
|
|
%D = icmp ugt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define <2 x i1> @tautological9_vec(<2 x i32> %A) {
|
|
; CHECK-LABEL: @tautological9_vec(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%C1 = and <2 x i32> %A, <i32 1, i32 1>
|
|
%C2 = and <2 x i32> %A, <i32 3, i32 3>
|
|
%D = icmp ugt <2 x i32> %C1, %C2
|
|
ret <2 x i1> %D
|
|
}
|
|
|
|
define i1 @tautological10(i32 %A) {
|
|
; CHECK-LABEL: @tautological10(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 3
|
|
%D = icmp ule i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological11(i32 %A) {
|
|
; CHECK-LABEL: @tautological11(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C1 = or i32 %A, 1
|
|
%C2 = or i32 %A, 3
|
|
%D = icmp ule i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological12(i32 %A) {
|
|
; CHECK-LABEL: @tautological12(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C1 = or i32 %A, 1
|
|
%C2 = or i32 %A, 3
|
|
%D = icmp ugt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological13(i32 %A) {
|
|
; CHECK-LABEL: @tautological13(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C1 = or i32 %A, 1
|
|
%C2 = or i32 %A, 3
|
|
%D = icmp ult i32 %C2, %C1
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological14(i32 %A) {
|
|
; CHECK-LABEL: @tautological14(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C1 = or i32 %A, 1
|
|
%C2 = or i32 %A, 3
|
|
%D = icmp uge i32 %C2, %C1
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological15(i32 %A) {
|
|
; CHECK-LABEL: @tautological15(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 3
|
|
%D = icmp uge i32 %C2, %C1
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological16(i32 %A) {
|
|
; CHECK-LABEL: @tautological16(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 3
|
|
%D = icmp ult i32 %C2, %C1
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological9_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological9_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 2
|
|
; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 2
|
|
%D = icmp ugt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological10_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological10_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 2
|
|
; CHECK-NEXT: [[D:%.*]] = icmp ule i32 [[C1]], [[C2]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 2
|
|
%D = icmp ule i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological11_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological11_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 2
|
|
; CHECK-NEXT: [[D:%.*]] = icmp ule i32 [[C1]], [[C2]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = or i32 %A, 1
|
|
%C2 = or i32 %A, 2
|
|
%D = icmp ule i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological12_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological12_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 2
|
|
; CHECK-NEXT: [[D:%.*]] = icmp ugt i32 [[C1]], [[C2]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = or i32 %A, 1
|
|
%C2 = or i32 %A, 2
|
|
%D = icmp ugt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological13_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological13_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 2
|
|
; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C2]], [[C1]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = or i32 %A, 1
|
|
%C2 = or i32 %A, 2
|
|
%D = icmp ult i32 %C2, %C1
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological14_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological14_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = or i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = or i32 [[A]], 2
|
|
; CHECK-NEXT: [[D:%.*]] = icmp uge i32 [[C2]], [[C1]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = or i32 %A, 1
|
|
%C2 = or i32 %A, 2
|
|
%D = icmp uge i32 %C2, %C1
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological15_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological15_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 2
|
|
; CHECK-NEXT: [[D:%.*]] = icmp uge i32 [[C2]], [[C1]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 2
|
|
%D = icmp uge i32 %C2, %C1
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological16_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological16_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], 2
|
|
; CHECK-NEXT: [[D:%.*]] = icmp ult i32 [[C2]], [[C1]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 2
|
|
%D = icmp ult i32 %C2, %C1
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological17_subset1(i32 %A) {
|
|
; CHECK-LABEL: @tautological17_subset1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 3
|
|
%D = icmp sgt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological17_subset2(i32 %A) {
|
|
; CHECK-LABEL: @tautological17_subset2(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C1 = and i32 %A, -4
|
|
%C2 = and i32 %A, -3
|
|
%D = icmp sgt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological17_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological17_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], -3
|
|
; CHECK-NEXT: [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, -3
|
|
%D = icmp sgt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological18_subset1(i32 %A) {
|
|
; CHECK-LABEL: @tautological18_subset1(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 3
|
|
%D = icmp sle i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological18_subset2(i32 %A) {
|
|
; CHECK-LABEL: @tautological18_subset2(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C1 = and i32 %A, -4
|
|
%C2 = and i32 %A, -3
|
|
%D = icmp sle i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological18_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological18_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], -3
|
|
; CHECK-NEXT: [[D:%.*]] = icmp sle i32 [[C1]], [[C2]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, -3
|
|
%D = icmp sle i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological19_subset1(i32 %A) {
|
|
; CHECK-LABEL: @tautological19_subset1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C1 = or i32 %A, 1
|
|
%C2 = or i32 %A, 3
|
|
%D = icmp sgt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological19_subset2(i32 %A) {
|
|
; CHECK-LABEL: @tautological19_subset2(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%C1 = and i32 %A, -4
|
|
%C2 = and i32 %A, -3
|
|
%D = icmp sgt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological19_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological19_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], -3
|
|
; CHECK-NEXT: [[D:%.*]] = icmp sgt i32 [[C1]], [[C2]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, -3
|
|
%D = icmp sgt i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological20_subset1(i32 %A) {
|
|
; CHECK-LABEL: @tautological20_subset1(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, 3
|
|
%D = icmp sle i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological20_subset2(i32 %A) {
|
|
; CHECK-LABEL: @tautological20_subset2(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%C1 = and i32 %A, -4
|
|
%C2 = and i32 %A, -3
|
|
%D = icmp sle i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
define i1 @tautological20_negative(i32 %A) {
|
|
; CHECK-LABEL: @tautological20_negative(
|
|
; CHECK-NEXT: [[C1:%.*]] = and i32 [[A:%.*]], 1
|
|
; CHECK-NEXT: [[C2:%.*]] = and i32 [[A]], -3
|
|
; CHECK-NEXT: [[D:%.*]] = icmp sle i32 [[C1]], [[C2]]
|
|
; CHECK-NEXT: ret i1 [[D]]
|
|
;
|
|
%C1 = and i32 %A, 1
|
|
%C2 = and i32 %A, -3
|
|
%D = icmp sle i32 %C1, %C2
|
|
ret i1 %D
|
|
}
|
|
|
|
declare void @helper_i1(i1)
|
|
; Series of tests for icmp s[lt|ge] (or A, B), A and icmp s[gt|le] A, (or A, B)
|
|
define void @icmp_slt_sge_or(i32 %Ax, i32 %Bx) {
|
|
; 'p' for positive, 'n' for negative, 'x' for potentially either.
|
|
; %D is 'icmp slt (or A, B), A'
|
|
; %E is 'icmp sge (or A, B), A' making it the not of %D
|
|
; %F is 'icmp sgt A, (or A, B)' making it the same as %D
|
|
; %G is 'icmp sle A, (or A, B)' making it the not of %D
|
|
; CHECK-LABEL: @icmp_slt_sge_or(
|
|
; CHECK-NEXT: [[APOS:%.*]] = and i32 [[AX:%.*]], 2147483647
|
|
; CHECK-NEXT: [[BNEG:%.*]] = or i32 [[BX:%.*]], -2147483648
|
|
; CHECK-NEXT: [[CPX:%.*]] = or i32 [[APOS]], [[BX]]
|
|
; CHECK-NEXT: [[DPX:%.*]] = icmp slt i32 [[CPX]], [[APOS]]
|
|
; CHECK-NEXT: [[EPX:%.*]] = icmp sge i32 [[CPX]], [[APOS]]
|
|
; CHECK-NEXT: [[FPX:%.*]] = icmp sgt i32 [[APOS]], [[CPX]]
|
|
; CHECK-NEXT: [[GPX:%.*]] = icmp sle i32 [[APOS]], [[CPX]]
|
|
; CHECK-NEXT: [[CXX:%.*]] = or i32 [[AX]], [[BX]]
|
|
; CHECK-NEXT: [[DXX:%.*]] = icmp slt i32 [[CXX]], [[AX]]
|
|
; CHECK-NEXT: [[EXX:%.*]] = icmp sge i32 [[CXX]], [[AX]]
|
|
; CHECK-NEXT: [[FXX:%.*]] = icmp sgt i32 [[AX]], [[CXX]]
|
|
; CHECK-NEXT: [[GXX:%.*]] = icmp sle i32 [[AX]], [[CXX]]
|
|
; CHECK-NEXT: [[CXN:%.*]] = or i32 [[AX]], [[BNEG]]
|
|
; CHECK-NEXT: [[DXN:%.*]] = icmp slt i32 [[CXN]], [[AX]]
|
|
; CHECK-NEXT: [[EXN:%.*]] = icmp sge i32 [[CXN]], [[AX]]
|
|
; CHECK-NEXT: [[FXN:%.*]] = icmp sgt i32 [[AX]], [[CXN]]
|
|
; CHECK-NEXT: [[GXN:%.*]] = icmp sle i32 [[AX]], [[CXN]]
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[DPX]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[EPX]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[FPX]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[GPX]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[DXX]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[EXX]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[FXX]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[GXX]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[DXN]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[EXN]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[FXN]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 [[GXN]])
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: call void @helper_i1(i1 false)
|
|
; CHECK-NEXT: call void @helper_i1(i1 true)
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%Aneg = or i32 %Ax, 2147483648
|
|
%Apos = and i32 %Ax, 2147483647
|
|
%Bneg = or i32 %Bx, 2147483648
|
|
%Bpos = and i32 %Bx, 2147483647
|
|
|
|
%Cpp = or i32 %Apos, %Bpos
|
|
%Dpp = icmp slt i32 %Cpp, %Apos
|
|
%Epp = icmp sge i32 %Cpp, %Apos
|
|
%Fpp = icmp sgt i32 %Apos, %Cpp
|
|
%Gpp = icmp sle i32 %Apos, %Cpp
|
|
%Cpx = or i32 %Apos, %Bx
|
|
%Dpx = icmp slt i32 %Cpx, %Apos
|
|
%Epx = icmp sge i32 %Cpx, %Apos
|
|
%Fpx = icmp sgt i32 %Apos, %Cpx
|
|
%Gpx = icmp sle i32 %Apos, %Cpx
|
|
%Cpn = or i32 %Apos, %Bneg
|
|
%Dpn = icmp slt i32 %Cpn, %Apos
|
|
%Epn = icmp sge i32 %Cpn, %Apos
|
|
%Fpn = icmp sgt i32 %Apos, %Cpn
|
|
%Gpn = icmp sle i32 %Apos, %Cpn
|
|
|
|
%Cxp = or i32 %Ax, %Bpos
|
|
%Dxp = icmp slt i32 %Cxp, %Ax
|
|
%Exp = icmp sge i32 %Cxp, %Ax
|
|
%Fxp = icmp sgt i32 %Ax, %Cxp
|
|
%Gxp = icmp sle i32 %Ax, %Cxp
|
|
%Cxx = or i32 %Ax, %Bx
|
|
%Dxx = icmp slt i32 %Cxx, %Ax
|
|
%Exx = icmp sge i32 %Cxx, %Ax
|
|
%Fxx = icmp sgt i32 %Ax, %Cxx
|
|
%Gxx = icmp sle i32 %Ax, %Cxx
|
|
%Cxn = or i32 %Ax, %Bneg
|
|
%Dxn = icmp slt i32 %Cxn, %Ax
|
|
%Exn = icmp sge i32 %Cxn, %Ax
|
|
%Fxn = icmp sgt i32 %Ax, %Cxn
|
|
%Gxn = icmp sle i32 %Ax, %Cxn
|
|
|
|
%Cnp = or i32 %Aneg, %Bpos
|
|
%Dnp = icmp slt i32 %Cnp, %Aneg
|
|
%Enp = icmp sge i32 %Cnp, %Aneg
|
|
%Fnp = icmp sgt i32 %Aneg, %Cnp
|
|
%Gnp = icmp sle i32 %Aneg, %Cnp
|
|
%Cnx = or i32 %Aneg, %Bx
|
|
%Dnx = icmp slt i32 %Cnx, %Aneg
|
|
%Enx = icmp sge i32 %Cnx, %Aneg
|
|
%Fnx = icmp sgt i32 %Aneg, %Cnx
|
|
%Gnx = icmp sle i32 %Aneg, %Cnx
|
|
%Cnn = or i32 %Aneg, %Bneg
|
|
%Dnn = icmp slt i32 %Cnn, %Aneg
|
|
%Enn = icmp sge i32 %Cnn, %Aneg
|
|
%Fnn = icmp sgt i32 %Aneg, %Cnn
|
|
%Gnn = icmp sle i32 %Aneg, %Cnn
|
|
|
|
call void @helper_i1(i1 %Dpp)
|
|
call void @helper_i1(i1 %Epp)
|
|
call void @helper_i1(i1 %Fpp)
|
|
call void @helper_i1(i1 %Gpp)
|
|
call void @helper_i1(i1 %Dpx)
|
|
call void @helper_i1(i1 %Epx)
|
|
call void @helper_i1(i1 %Fpx)
|
|
call void @helper_i1(i1 %Gpx)
|
|
call void @helper_i1(i1 %Dpn)
|
|
call void @helper_i1(i1 %Epn)
|
|
call void @helper_i1(i1 %Fpn)
|
|
call void @helper_i1(i1 %Gpn)
|
|
call void @helper_i1(i1 %Dxp)
|
|
call void @helper_i1(i1 %Exp)
|
|
call void @helper_i1(i1 %Fxp)
|
|
call void @helper_i1(i1 %Gxp)
|
|
call void @helper_i1(i1 %Dxx)
|
|
call void @helper_i1(i1 %Exx)
|
|
call void @helper_i1(i1 %Fxx)
|
|
call void @helper_i1(i1 %Gxx)
|
|
call void @helper_i1(i1 %Dxn)
|
|
call void @helper_i1(i1 %Exn)
|
|
call void @helper_i1(i1 %Fxn)
|
|
call void @helper_i1(i1 %Gxn)
|
|
call void @helper_i1(i1 %Dnp)
|
|
call void @helper_i1(i1 %Enp)
|
|
call void @helper_i1(i1 %Fnp)
|
|
call void @helper_i1(i1 %Gnp)
|
|
call void @helper_i1(i1 %Dnx)
|
|
call void @helper_i1(i1 %Enx)
|
|
call void @helper_i1(i1 %Fnx)
|
|
call void @helper_i1(i1 %Gnx)
|
|
call void @helper_i1(i1 %Dnn)
|
|
call void @helper_i1(i1 %Enn)
|
|
call void @helper_i1(i1 %Fnn)
|
|
call void @helper_i1(i1 %Gnn)
|
|
ret void
|
|
}
|
|
|
|
define i1 @constant_fold_inttoptr_null() {
|
|
; CHECK-LABEL: @constant_fold_inttoptr_null(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x = icmp eq ptr inttoptr (i64 32 to ptr), null
|
|
ret i1 %x
|
|
}
|
|
|
|
define i1 @constant_fold_null_inttoptr() {
|
|
; CHECK-LABEL: @constant_fold_null_inttoptr(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%x = icmp eq ptr null, inttoptr (i64 32 to ptr)
|
|
ret i1 %x
|
|
}
|
|
|
|
define i1 @cmp_through_addrspacecast(ptr addrspace(1) %p1) {
|
|
; CHECK-LABEL: @cmp_through_addrspacecast(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%p0 = addrspacecast ptr addrspace(1) %p1 to ptr
|
|
%p0.1 = getelementptr inbounds i32, ptr %p0, i64 1
|
|
%cmp = icmp ne ptr %p0, %p0.1
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Test simplifications for: icmp (X+Y), (X+Z) -> icmp Y,Z
|
|
; Test the overflow check when the RHS has NSW set and constant Z is greater
|
|
; than Y, then we know X+Y also can't overflow.
|
|
|
|
define i1 @icmp_nsw_1(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_1(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%add5 = add i32 %V, 5
|
|
%add6 = add nsw i32 %V, 6
|
|
%s1 = sext i32 %add5 to i64
|
|
%s2 = sext i32 %add6 to i64
|
|
%cmp = icmp slt i64 %s1, %s2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_2(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_2(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%add5 = add i32 %V, 5
|
|
%add6 = add nsw i32 %V, 6
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_22(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_22(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%add5 = add nsw i32 %V, 5
|
|
%add6 = add nsw i32 %V, 6
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_23(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_23(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
|
|
; CHECK-NEXT: [[ADD6:%.*]] = add i32 [[V]], 6
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add nsw i32 %V, 5
|
|
%add6 = add i32 %V, 6
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_false(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_false(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%add5 = add nsw i32 %V, 6
|
|
%add6 = add i32 %V, 5
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_false_2(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_false_2(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%add5 = add nsw i32 %V, 6
|
|
%add6 = add nsw i32 %V, 5
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_false_3(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_false_3(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
|
|
; CHECK-NEXT: [[ADD6:%.*]] = add i32 [[V]], 5
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add nsw i32 %V, 5
|
|
%add6 = add i32 %V, 5
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_false_4(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_false_4(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 6
|
|
; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], 5
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add i32 %V, 6
|
|
%add6 = add nsw i32 %V, 5
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_false_5(i8 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_false_5(
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[V:%.*]], 121
|
|
; CHECK-NEXT: [[ADDNSW:%.*]] = add nsw i8 [[V]], -104
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[ADD]], [[ADDNSW]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add = add i8 %V, 121
|
|
%addnsw = add nsw i8 %V, -104
|
|
%cmp = icmp slt i8 %add, %addnsw
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_i8(i8 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_i8(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%add5 = add i8 %V, 5
|
|
%add6 = add nsw i8 %V, 6
|
|
%cmp = icmp slt i8 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_i16(i16 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_i16(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%add5 = add i16 %V, 0
|
|
%add6 = add nsw i16 %V, 1
|
|
%cmp = icmp slt i16 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_i64(i64 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_i64(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%add5 = add i64 %V, 5
|
|
%add6 = add nsw i64 %V, 6
|
|
%cmp = icmp slt i64 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define <4 x i1> @icmp_nsw_vec(<4 x i32> %V) {
|
|
; CHECK-LABEL: @icmp_nsw_vec(
|
|
; CHECK-NEXT: ret <4 x i1> <i1 true, i1 true, i1 true, i1 true>
|
|
;
|
|
%add5 = add <4 x i32> %V, <i32 5, i32 5, i32 5, i32 5>
|
|
%add6 = add nsw <4 x i32> %V, <i32 6, i32 6, i32 6, i32 6>
|
|
%cmp = icmp slt <4 x i32> %add5, %add6
|
|
ret <4 x i1> %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_3(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_3(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 5
|
|
; CHECK-NEXT: [[ADD5_2:%.*]] = add nsw i32 [[V]], 5
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD5_2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add i32 %V, 5
|
|
%add5_2 = add nsw i32 %V, 5
|
|
%cmp = icmp slt i32 %add5, %add5_2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_4(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_4(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 5
|
|
; CHECK-NEXT: [[ADD4:%.*]] = add nsw i32 [[V]], 4
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD4]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add i32 %V, 5
|
|
%add4 = add nsw i32 %V, 4
|
|
%cmp = icmp slt i32 %add5, %add4
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_5(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_5(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
|
|
; CHECK-NEXT: [[ADD6:%.*]] = add i32 [[V]], 6
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add nsw i32 %V, 5
|
|
%add6 = add i32 %V, 6
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_7(i32 %V, i32 %arg) {
|
|
; CHECK-LABEL: @icmp_nsw_7(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 5
|
|
; CHECK-NEXT: [[ADDARG:%.*]] = add nsw i32 [[V]], [[ARG:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADDARG]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add i32 %V, 5
|
|
%addarg = add nsw i32 %V, %arg
|
|
%cmp = icmp slt i32 %add5, %addarg
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_8(i32 %V, i32 %arg) {
|
|
; CHECK-LABEL: @icmp_nsw_8(
|
|
; CHECK-NEXT: [[ADDARG:%.*]] = add i32 [[V:%.*]], [[ARG:%.*]]
|
|
; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], 5
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADDARG]], [[ADD6]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%addarg = add i32 %V, %arg
|
|
%add6 = add nsw i32 %V, 5
|
|
%cmp = icmp slt i32 %addarg, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_9(i32 %V1, i32 %V2) {
|
|
; CHECK-LABEL: @icmp_nsw_9(
|
|
; CHECK-NEXT: [[ADD_V1:%.*]] = add i32 [[V1:%.*]], 5
|
|
; CHECK-NEXT: [[ADD_V2:%.*]] = add nsw i32 [[V2:%.*]], 6
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD_V1]], [[ADD_V2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add_V1 = add i32 %V1, 5
|
|
%add_V2 = add nsw i32 %V2, 6
|
|
%cmp = icmp slt i32 %add_V1, %add_V2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_10(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_10(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 5
|
|
; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], 6
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[ADD6]], [[ADD5]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add i32 %V, 5
|
|
%add6 = add nsw i32 %V, 6
|
|
%cmp = icmp sgt i32 %add6, %add5
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_11(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_11(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], -125
|
|
; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], -99
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add i32 %V, -125
|
|
%add6 = add nsw i32 %V, -99
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_nonpos(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_nonpos(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%add5 = add i32 %V, 0
|
|
%add6 = add nsw i32 %V, -1
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_nsw_nonpos2(i32 %V) {
|
|
; CHECK-LABEL: @icmp_nsw_nonpos2(
|
|
; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[V]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%add5 = add i32 %V, 1
|
|
%add6 = add nsw i32 %V, 0
|
|
%cmp = icmp slt i32 %add5, %add6
|
|
ret i1 %cmp
|
|
}
|
|
|
|
declare i11 @llvm.ctpop.i11(i11)
|
|
declare i73 @llvm.ctpop.i73(i73)
|
|
declare <2 x i13> @llvm.ctpop.v2i13(<2 x i13>)
|
|
|
|
define i1 @ctpop_sgt_bitwidth(i11 %x) {
|
|
; CHECK-LABEL: @ctpop_sgt_bitwidth(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%pop = call i11 @llvm.ctpop.i11(i11 %x)
|
|
%cmp = icmp sgt i11 %pop, 11
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @ctpop_sle_minus1(i11 %x) {
|
|
; CHECK-LABEL: @ctpop_sle_minus1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%pop = call i11 @llvm.ctpop.i11(i11 %x)
|
|
%cmp = icmp sle i11 %pop, -1
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @ctpop_ugt_bitwidth(i73 %x) {
|
|
; CHECK-LABEL: @ctpop_ugt_bitwidth(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%pop = call i73 @llvm.ctpop.i73(i73 %x)
|
|
%cmp = icmp ugt i73 %pop, 73
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test - does not simplify, but instcombine could reduce this.
|
|
|
|
define i1 @ctpop_ugt_bitwidth_minus1(i73 %x) {
|
|
; CHECK-LABEL: @ctpop_ugt_bitwidth_minus1(
|
|
; CHECK-NEXT: [[POP:%.*]] = call i73 @llvm.ctpop.i73(i73 [[X:%.*]])
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i73 [[POP]], 72
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%pop = call i73 @llvm.ctpop.i73(i73 %x)
|
|
%cmp = icmp ugt i73 %pop, 72
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define <2 x i1> @ctpop_sgt_bitwidth_splat(<2 x i13> %x) {
|
|
; CHECK-LABEL: @ctpop_sgt_bitwidth_splat(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%pop = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> %x)
|
|
%cmp = icmp sgt <2 x i13> %pop, <i13 13, i13 13>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
define i1 @ctpop_ult_plus1_bitwidth(i11 %x) {
|
|
; CHECK-LABEL: @ctpop_ult_plus1_bitwidth(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%pop = call i11 @llvm.ctpop.i11(i11 %x)
|
|
%cmp = icmp ult i11 %pop, 12
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @ctpop_ne_big_bitwidth(i73 %x) {
|
|
; CHECK-LABEL: @ctpop_ne_big_bitwidth(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%pop = call i73 @llvm.ctpop.i73(i73 %x)
|
|
%cmp = icmp ne i73 %pop, 75
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define <2 x i1> @ctpop_slt_bitwidth_plus1_splat(<2 x i13> %x) {
|
|
; CHECK-LABEL: @ctpop_slt_bitwidth_plus1_splat(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%pop = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> %x)
|
|
%cmp = icmp slt <2 x i13> %pop, <i13 14, i13 14>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
; Negative test - does not simplify, but instcombine could reduce this.
|
|
|
|
define <2 x i1> @ctpop_slt_bitwidth_splat(<2 x i13> %x) {
|
|
; CHECK-LABEL: @ctpop_slt_bitwidth_splat(
|
|
; CHECK-NEXT: [[POP:%.*]] = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> [[X:%.*]])
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i13> [[POP]], <i13 13, i13 13>
|
|
; CHECK-NEXT: ret <2 x i1> [[CMP]]
|
|
;
|
|
%pop = call <2 x i13> @llvm.ctpop.v2i13(<2 x i13> %x)
|
|
%cmp = icmp slt <2 x i13> %pop, <i13 13, i13 13>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
declare i11 @llvm.ctlz.i11(i11)
|
|
declare i73 @llvm.ctlz.i73(i73)
|
|
declare <2 x i13> @llvm.ctlz.v2i13(<2 x i13>)
|
|
|
|
define i1 @ctlz_sgt_bitwidth(i11 %x) {
|
|
; CHECK-LABEL: @ctlz_sgt_bitwidth(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%pop = call i11 @llvm.ctlz.i11(i11 %x)
|
|
%cmp = icmp sgt i11 %pop, 11
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @ctlz_sle_minus1(i11 %x) {
|
|
; CHECK-LABEL: @ctlz_sle_minus1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%pop = call i11 @llvm.ctlz.i11(i11 %x)
|
|
%cmp = icmp sle i11 %pop, -1
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @ctlz_ugt_bitwidth(i73 %x) {
|
|
; CHECK-LABEL: @ctlz_ugt_bitwidth(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%pop = call i73 @llvm.ctlz.i73(i73 %x)
|
|
%cmp = icmp ugt i73 %pop, 73
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test - does not simplify, but instcombine could reduce this.
|
|
|
|
define i1 @ctlz_ugt_bitwidth_minus1(i73 %x) {
|
|
; CHECK-LABEL: @ctlz_ugt_bitwidth_minus1(
|
|
; CHECK-NEXT: [[POP:%.*]] = call i73 @llvm.ctlz.i73(i73 [[X:%.*]], i1 false)
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i73 [[POP]], 72
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%pop = call i73 @llvm.ctlz.i73(i73 %x)
|
|
%cmp = icmp ugt i73 %pop, 72
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define <2 x i1> @ctlz_sgt_bitwidth_splat(<2 x i13> %x) {
|
|
; CHECK-LABEL: @ctlz_sgt_bitwidth_splat(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%pop = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> %x)
|
|
%cmp = icmp sgt <2 x i13> %pop, <i13 13, i13 13>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
define i1 @ctlz_ult_plus1_bitwidth(i11 %x) {
|
|
; CHECK-LABEL: @ctlz_ult_plus1_bitwidth(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%pop = call i11 @llvm.ctlz.i11(i11 %x)
|
|
%cmp = icmp ult i11 %pop, 12
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @ctlz_ne_big_bitwidth(i73 %x) {
|
|
; CHECK-LABEL: @ctlz_ne_big_bitwidth(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%pop = call i73 @llvm.ctlz.i73(i73 %x)
|
|
%cmp = icmp ne i73 %pop, 75
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define <2 x i1> @ctlz_slt_bitwidth_plus1_splat(<2 x i13> %x) {
|
|
; CHECK-LABEL: @ctlz_slt_bitwidth_plus1_splat(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%pop = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> %x)
|
|
%cmp = icmp slt <2 x i13> %pop, <i13 14, i13 14>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
; Negative test - does not simplify, but instcombine could reduce this.
|
|
|
|
define <2 x i1> @ctlz_slt_bitwidth_splat(<2 x i13> %x) {
|
|
; CHECK-LABEL: @ctlz_slt_bitwidth_splat(
|
|
; CHECK-NEXT: [[POP:%.*]] = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> [[X:%.*]], i1 false)
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i13> [[POP]], <i13 13, i13 13>
|
|
; CHECK-NEXT: ret <2 x i1> [[CMP]]
|
|
;
|
|
%pop = call <2 x i13> @llvm.ctlz.v2i13(<2 x i13> %x)
|
|
%cmp = icmp slt <2 x i13> %pop, <i13 13, i13 13>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
declare i11 @llvm.cttz.i11(i11)
|
|
declare i73 @llvm.cttz.i73(i73)
|
|
declare <2 x i13> @llvm.cttz.v2i13(<2 x i13>)
|
|
|
|
define i1 @cttz_sgt_bitwidth(i11 %x) {
|
|
; CHECK-LABEL: @cttz_sgt_bitwidth(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%pop = call i11 @llvm.cttz.i11(i11 %x)
|
|
%cmp = icmp sgt i11 %pop, 11
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @cttz_sle_minus1(i11 %x) {
|
|
; CHECK-LABEL: @cttz_sle_minus1(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%pop = call i11 @llvm.cttz.i11(i11 %x)
|
|
%cmp = icmp sle i11 %pop, -1
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @cttz_ugt_bitwidth(i73 %x) {
|
|
; CHECK-LABEL: @cttz_ugt_bitwidth(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%pop = call i73 @llvm.cttz.i73(i73 %x)
|
|
%cmp = icmp ugt i73 %pop, 73
|
|
ret i1 %cmp
|
|
}
|
|
|
|
; Negative test - does not simplify, but instcombine could reduce this.
|
|
|
|
define i1 @cttz_ugt_bitwidth_minus1(i73 %x) {
|
|
; CHECK-LABEL: @cttz_ugt_bitwidth_minus1(
|
|
; CHECK-NEXT: [[POP:%.*]] = call i73 @llvm.cttz.i73(i73 [[X:%.*]], i1 false)
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i73 [[POP]], 72
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%pop = call i73 @llvm.cttz.i73(i73 %x)
|
|
%cmp = icmp ugt i73 %pop, 72
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define <2 x i1> @cttz_sgt_bitwidth_splat(<2 x i13> %x) {
|
|
; CHECK-LABEL: @cttz_sgt_bitwidth_splat(
|
|
; CHECK-NEXT: ret <2 x i1> zeroinitializer
|
|
;
|
|
%pop = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> %x)
|
|
%cmp = icmp sgt <2 x i13> %pop, <i13 13, i13 13>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
define i1 @cttz_ult_plus1_bitwidth(i11 %x) {
|
|
; CHECK-LABEL: @cttz_ult_plus1_bitwidth(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%pop = call i11 @llvm.cttz.i11(i11 %x)
|
|
%cmp = icmp ult i11 %pop, 12
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @cttz_ne_big_bitwidth(i73 %x) {
|
|
; CHECK-LABEL: @cttz_ne_big_bitwidth(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%pop = call i73 @llvm.cttz.i73(i73 %x)
|
|
%cmp = icmp ne i73 %pop, 75
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define <2 x i1> @cttz_slt_bitwidth_plus1_splat(<2 x i13> %x) {
|
|
; CHECK-LABEL: @cttz_slt_bitwidth_plus1_splat(
|
|
; CHECK-NEXT: ret <2 x i1> <i1 true, i1 true>
|
|
;
|
|
%pop = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> %x)
|
|
%cmp = icmp slt <2 x i13> %pop, <i13 14, i13 14>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
; Negative test - does not simplify, but instcombine could reduce this.
|
|
|
|
define <2 x i1> @cttz_slt_bitwidth_splat(<2 x i13> %x) {
|
|
; CHECK-LABEL: @cttz_slt_bitwidth_splat(
|
|
; CHECK-NEXT: [[POP:%.*]] = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> [[X:%.*]], i1 false)
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i13> [[POP]], <i13 13, i13 13>
|
|
; CHECK-NEXT: ret <2 x i1> [[CMP]]
|
|
;
|
|
%pop = call <2 x i13> @llvm.cttz.v2i13(<2 x i13> %x)
|
|
%cmp = icmp slt <2 x i13> %pop, <i13 13, i13 13>
|
|
ret <2 x i1> %cmp
|
|
}
|
|
|
|
; A zero sized alloca *can* be equal to another alloca
|
|
define i1 @zero_sized_alloca1() {
|
|
; CHECK-LABEL: @zero_sized_alloca1(
|
|
; CHECK-NEXT: [[A:%.*]] = alloca i32, i32 0, align 4
|
|
; CHECK-NEXT: [[B:%.*]] = alloca i32, i32 0, align 4
|
|
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A]], [[B]]
|
|
; CHECK-NEXT: ret i1 [[RES]]
|
|
;
|
|
%a = alloca i32, i32 0
|
|
%b = alloca i32, i32 0
|
|
%res = icmp ne ptr %a, %b
|
|
ret i1 %res
|
|
}
|
|
|
|
define i1 @zero_sized_alloca2() {
|
|
; CHECK-LABEL: @zero_sized_alloca2(
|
|
; CHECK-NEXT: [[A:%.*]] = alloca i32, i32 0, align 4
|
|
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A]], [[B]]
|
|
; CHECK-NEXT: ret i1 [[RES]]
|
|
;
|
|
%a = alloca i32, i32 0
|
|
%b = alloca i32
|
|
%res = icmp ne ptr %a, %b
|
|
ret i1 %res
|
|
}
|
|
|
|
define i1 @scalar_vectors_are_non_empty() {
|
|
; CHECK-LABEL: @scalar_vectors_are_non_empty(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%a = alloca <vscale x 2 x i32>
|
|
%b = alloca <vscale x 2 x i32>
|
|
%res = icmp ne ptr %a, %b
|
|
ret i1 %res
|
|
}
|
|
|
|
; Never equal
|
|
define i1 @byval_args_inequal(ptr byval(i32) %a, ptr byval(i32) %b) {
|
|
; CHECK-LABEL: @byval_args_inequal(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%res = icmp ne ptr %a, %b
|
|
ret i1 %res
|
|
}
|
|
|
|
; Arguments can be adjacent on the stack
|
|
define i1 @neg_args_adjacent(ptr byval(i32) %a, ptr byval(i32) %b) {
|
|
; CHECK-LABEL: @neg_args_adjacent(
|
|
; CHECK-NEXT: [[A_OFF:%.*]] = getelementptr i32, ptr [[A:%.*]], i32 1
|
|
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B:%.*]]
|
|
; CHECK-NEXT: ret i1 [[RES]]
|
|
;
|
|
%a.off = getelementptr i32, ptr %a, i32 1
|
|
%res = icmp ne ptr %a.off, %b
|
|
ret i1 %res
|
|
}
|
|
|
|
; Never equal
|
|
define i1 @test_byval_alloca_inequal(ptr byval(i32) %a) {
|
|
; CHECK-LABEL: @test_byval_alloca_inequal(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%b = alloca i32
|
|
%res = icmp ne ptr %a, %b
|
|
ret i1 %res
|
|
}
|
|
|
|
; Byval argument can be immediately before alloca, and crossing
|
|
; over is allowed.
|
|
define i1 @neg_byval_alloca_adjacent(ptr byval(i32) %a) {
|
|
; CHECK-LABEL: @neg_byval_alloca_adjacent(
|
|
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
|
|
; CHECK-NEXT: [[A_OFF:%.*]] = getelementptr i32, ptr [[A:%.*]], i32 1
|
|
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B]]
|
|
; CHECK-NEXT: ret i1 [[RES]]
|
|
;
|
|
%b = alloca i32
|
|
%a.off = getelementptr i32, ptr %a, i32 1
|
|
%res = icmp ne ptr %a.off, %b
|
|
ret i1 %res
|
|
}
|
|
|
|
@A = global i32 0
|
|
@B = global i32 0
|
|
@A.alias = alias i32, ptr @A
|
|
|
|
define i1 @globals_inequal() {
|
|
; CHECK-LABEL: @globals_inequal(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%res = icmp ne ptr @A, @B
|
|
ret i1 %res
|
|
}
|
|
|
|
; TODO: Never equal
|
|
define i1 @globals_offset_inequal() {
|
|
; CHECK-LABEL: @globals_offset_inequal(
|
|
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr getelementptr inbounds (i8, ptr @A, i32 1), getelementptr inbounds (i8, ptr @B, i32 1)
|
|
; CHECK-NEXT: ret i1 [[RES]]
|
|
;
|
|
%a.off = getelementptr i8, ptr @A, i32 1
|
|
%b.off = getelementptr i8, ptr @B, i32 1
|
|
%res = icmp ne ptr %a.off, %b.off
|
|
ret i1 %res
|
|
}
|
|
|
|
|
|
; Never equal
|
|
define i1 @test_byval_global_inequal(ptr byval(i32) %a) {
|
|
; CHECK-LABEL: @test_byval_global_inequal(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%b = alloca i32
|
|
%res = icmp ne ptr %a, @B
|
|
ret i1 %res
|
|
}
|
|
|
|
|
|
define i1 @neg_global_alias() {
|
|
; CHECK-LABEL: @neg_global_alias(
|
|
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr @A, @A.alias
|
|
; CHECK-NEXT: ret i1 [[RES]]
|
|
;
|
|
%res = icmp ne ptr @A, @A.alias
|
|
ret i1 %res
|
|
}
|
|
|
|
|
|
define i1 @icmp_lshr_known_non_zero_ult_true(i8 %x) {
|
|
; CHECK-LABEL: @icmp_lshr_known_non_zero_ult_true(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%or = or i8 %x, 1
|
|
%x1 = shl nuw i8 %or, 1
|
|
%x2 = shl nuw i8 %or, 2
|
|
%cmp = icmp ult i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_lshr_known_non_zero_ult_false(i8 %x) {
|
|
; CHECK-LABEL: @icmp_lshr_known_non_zero_ult_false(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%or = or i8 %x, 1
|
|
%x1 = shl nuw i8 %or, 1
|
|
%x2 = shl nuw i8 %or, 2
|
|
%cmp = icmp ugt i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_lshr_known_non_zero_slt_true(i8 %x) {
|
|
; CHECK-LABEL: @icmp_lshr_known_non_zero_slt_true(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%or = or i8 %x, 1
|
|
%x1 = shl nuw nsw i8 %or, 1
|
|
%x2 = shl nuw nsw i8 %or, 2
|
|
%cmp = icmp slt i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_lshr_known_non_zero_slt_false(i8 %x) {
|
|
; CHECK-LABEL: @icmp_lshr_known_non_zero_slt_false(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%or = or i8 %x, 1
|
|
%x1 = shl nuw nsw i8 %or, 2
|
|
%x2 = shl nuw nsw i8 %or, 1
|
|
%cmp = icmp slt i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @neg_icmp_lshr_known_non_zero_slt_no_nsw(i8 %x) {
|
|
; CHECK-LABEL: @neg_icmp_lshr_known_non_zero_slt_no_nsw(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[X1:%.*]] = shl nuw i8 [[OR]], 1
|
|
; CHECK-NEXT: [[X2:%.*]] = shl nuw i8 [[OR]], 2
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X1]], [[X2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%or = or i8 %x, 1
|
|
%x1 = shl nuw i8 %or, 1
|
|
%x2 = shl nuw i8 %or, 2
|
|
%cmp = icmp slt i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @neg_icmp_lshr_known_non_zero_ult_no_nuw(i8 %x) {
|
|
; CHECK-LABEL: @neg_icmp_lshr_known_non_zero_ult_no_nuw(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[X1:%.*]] = shl i8 [[OR]], 1
|
|
; CHECK-NEXT: [[X2:%.*]] = shl i8 [[OR]], 2
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X1]], [[X2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%or = or i8 %x, 1
|
|
%x1 = shl i8 %or, 1
|
|
%x2 = shl i8 %or, 2
|
|
%cmp = icmp ult i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @neg_icmp_lshr_known_non_zero_slt_no_nuw(i8 %x) {
|
|
; CHECK-LABEL: @neg_icmp_lshr_known_non_zero_slt_no_nuw(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[X1:%.*]] = shl nsw i8 [[OR]], 1
|
|
; CHECK-NEXT: [[X2:%.*]] = shl nsw i8 [[OR]], 2
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X1]], [[X2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%or = or i8 %x, 1
|
|
%x1 = shl nsw i8 %or, 1
|
|
%x2 = shl nsw i8 %or, 2
|
|
%cmp = icmp slt i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @neg_icmp_lshr_unknown_value(i8 %x) {
|
|
; CHECK-LABEL: @neg_icmp_lshr_unknown_value(
|
|
; CHECK-NEXT: [[X1:%.*]] = shl nuw i8 [[X:%.*]], 2
|
|
; CHECK-NEXT: [[X2:%.*]] = shl nuw i8 [[X]], 1
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X1]], [[X2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x1 = shl nuw i8 %x, 2
|
|
%x2 = shl nuw i8 %x, 1
|
|
%cmp = icmp ugt i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @neg_icmp_lshr_unknown_shift(i8 %x, i8 %C1) {
|
|
; CHECK-LABEL: @neg_icmp_lshr_unknown_shift(
|
|
; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[X1:%.*]] = shl nuw i8 [[OR]], 2
|
|
; CHECK-NEXT: [[X2:%.*]] = shl nuw i8 [[OR]], [[C1:%.*]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X1]], [[X2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%or = or i8 %x, 1
|
|
%x1 = shl nuw i8 %or, 2
|
|
%x2 = shl nuw i8 %or, %C1
|
|
%cmp = icmp ugt i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @neg_icmp_lshr_different_shift_values(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @neg_icmp_lshr_different_shift_values(
|
|
; CHECK-NEXT: [[X1:%.*]] = shl nuw nsw i8 [[X:%.*]], 1
|
|
; CHECK-NEXT: [[X2:%.*]] = shl nuw nsw i8 [[Y:%.*]], 2
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[X1]], [[X2]]
|
|
; CHECK-NEXT: ret i1 [[CMP]]
|
|
;
|
|
%x1 = shl nuw nsw i8 %x, 1
|
|
%x2 = shl nuw nsw i8 %y, 2
|
|
%cmp = icmp ult i8 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_ult_vscale_true(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @icmp_ult_vscale_true(
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%vscale = call i64 @llvm.vscale.i64()
|
|
%x1 = shl nuw nsw i64 %vscale, 1
|
|
%x2 = shl nuw nsw i64 %vscale, 2
|
|
%cmp = icmp ult i64 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
define i1 @icmp_ult_vscale_false(i8 %x, i8 %y) {
|
|
; CHECK-LABEL: @icmp_ult_vscale_false(
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
%vscale = call i64 @llvm.vscale.i64()
|
|
%x1 = shl nuw nsw i64 %vscale, 1
|
|
%x2 = shl nuw nsw i64 %vscale, 2
|
|
%cmp = icmp ugt i64 %x1, %x2
|
|
ret i1 %cmp
|
|
}
|
|
|
|
declare i64 @llvm.vscale.i64()
|
|
|
|
; TODO: Add coverage for global aliases, link once, etc..
|
|
|
|
|
|
attributes #0 = { null_pointer_is_valid }
|