; 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"
; This is a collection of tests checking whether we can prove pointers
; derived from two allocas as inequal *via offset checks*. Note that
; instcombine has alternate approaches (one cmp rule, and compare
; bases of common offset) that also handles these, but with different
; logic.
; %a follows %b, derived equal
define i1 @adjacent_alloca() {
; CHECK-LABEL: @adjacent_alloca(
; CHECK-NEXT: [[A:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[B:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 4
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A]], [[B_OFF]]
; CHECK-NEXT: ret i1 [[RES]]
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%b.off = getelementptr i8, ptr %b, i64 4
%res = icmp ne ptr %a, %b.off
ret i1 %res
}
; %b follows %a, derived equal
define i1 @adjacent_alloca2() {
; CHECK-LABEL: @adjacent_alloca2(
; CHECK-NEXT: [[A:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[B:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 4
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B]]
; CHECK-NEXT: ret i1 [[RES]]
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 4
%res = icmp ne ptr %a.off, %b
ret i1 %res
}
define i1 @positive_non_equal_end() {
; CHECK-LABEL: @positive_non_equal_end(
; CHECK-NEXT: ret i1 true
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 4
%b.off = getelementptr i8, ptr %b, i64 4
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
; %b follows %a, derived equal
define i1 @positive_equal_past_end() {
; CHECK-LABEL: @positive_equal_past_end(
; CHECK-NEXT: [[A:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[B:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 8
; CHECK-NEXT: [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 12
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
; CHECK-NEXT: ret i1 [[RES]]
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 8
%b.off = getelementptr i8, ptr %b, i64 12
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
define i1 @positive_non_equal() {
; CHECK-LABEL: @positive_non_equal(
; CHECK-NEXT: ret i1 true
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 3
%b.off = getelementptr i8, ptr %b, i64 3
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
; %a follows %b, derived equal
define i1 @one_neg_equal1() {
; CHECK-LABEL: @one_neg_equal1(
; CHECK-NEXT: [[A:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[B:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -1
; CHECK-NEXT: [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 3
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
; CHECK-NEXT: ret i1 [[RES]]
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 -1
%b.off = getelementptr i8, ptr %b, i64 3
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
; %b follows %a, derived equal
define i1 @one_neg_equal2() {
; CHECK-LABEL: @one_neg_equal2(
; CHECK-NEXT: [[A:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[B:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 3
; CHECK-NEXT: [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -1
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
; CHECK-NEXT: ret i1 [[RES]]
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 3
%b.off = getelementptr i8, ptr %b, i64 -1
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
; %b follows %a, derived equal
define i1 @both_neg_equal() {
; CHECK-LABEL: @both_neg_equal(
; CHECK-NEXT: [[A:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[B:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -4
; CHECK-NEXT: [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -8
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
; CHECK-NEXT: ret i1 [[RES]]
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 -4
%b.off = getelementptr i8, ptr %b, i64 -8
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
define i1 @mixed_offsets1() {
; CHECK-LABEL: @mixed_offsets1(
; CHECK-NEXT: ret i1 true
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 -1
%b.off = getelementptr i8, ptr %b, i64 2
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
define i1 @mixed_offsets2() {
; CHECK-LABEL: @mixed_offsets2(
; CHECK-NEXT: ret i1 true
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 1
%b.off = getelementptr i8, ptr %b, i64 -2
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
define i1 @negative_in_other() {
; CHECK-LABEL: @negative_in_other(
; CHECK-NEXT: ret i1 true
;
%a = alloca i8, i32 4
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 -3
%b.off = getelementptr i8, ptr %b, i64 -2
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
define i1 @mixed_alloca_size1() {
; CHECK-LABEL: @mixed_alloca_size1(
; CHECK-NEXT: ret i1 true
;
%a = alloca i8, i32 2
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 1
%b.off = getelementptr i8, ptr %b, i64 3
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
define i1 @mixed_alloca_size2() {
; CHECK-LABEL: @mixed_alloca_size2(
; CHECK-NEXT: [[A:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[B:%.*]] = alloca i8, i32 2, align 1
; CHECK-NEXT: [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 1
; CHECK-NEXT: [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 3
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
; CHECK-NEXT: ret i1 [[RES]]
;
%a = alloca i8, i32 4
%b = alloca i8, i32 2
%a.off = getelementptr i8, ptr %a, i64 1
%b.off = getelementptr i8, ptr %b, i64 3
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
define i1 @mixed_alloca_size3() {
; CHECK-LABEL: @mixed_alloca_size3(
; CHECK-NEXT: [[A:%.*]] = alloca i8, i32 2, align 1
; CHECK-NEXT: [[B:%.*]] = alloca i8, i32 4, align 1
; CHECK-NEXT: [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -1
; CHECK-NEXT: [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -3
; CHECK-NEXT: [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
; CHECK-NEXT: ret i1 [[RES]]
;
%a = alloca i8, i32 2
%b = alloca i8, i32 4
%a.off = getelementptr i8, ptr %a, i64 -1
%b.off = getelementptr i8, ptr %b, i64 -3
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
define i1 @mixed_alloca_size4() {
; CHECK-LABEL: @mixed_alloca_size4(
; CHECK-NEXT: ret i1 true
;
%a = alloca i8, i32 4
%b = alloca i8, i32 2
%a.off = getelementptr i8, ptr %a, i64 -1
%b.off = getelementptr i8, ptr %b, i64 -3
%res = icmp ne ptr %a.off, %b.off
ret i1 %res
}
attributes #0 = { null_pointer_is_valid }