; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes='gvn' -basic-aa-separate-storage -S | FileCheck %s
declare void @llvm.assume(i1)
; Test basic queries.
define i8 @simple_no(ptr %p1, ptr %p2) {
; CHECK-LABEL: @simple_no(
; CHECK-NEXT: entry:
; CHECK-NEXT: store i8 0, ptr [[P1:%.*]], align 1
; CHECK-NEXT: store i8 1, ptr [[P2:%.*]], align 1
; CHECK-NEXT: [[LOADOFSTORE:%.*]] = load i8, ptr [[P1]], align 1
; CHECK-NEXT: ret i8 [[LOADOFSTORE]]
;
entry:
store i8 0, ptr %p1
store i8 1, ptr %p2
%loadofstore = load i8, ptr %p1
ret i8 %loadofstore
}
define i8 @simple_yes(ptr %p1, ptr %p2) {
; CHECK-LABEL: @simple_yes(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P1:%.*]], ptr [[P2:%.*]]) ]
; CHECK-NEXT: store i8 0, ptr [[P1]], align 1
; CHECK-NEXT: store i8 1, ptr [[P2]], align 1
; CHECK-NEXT: ret i8 0
;
entry:
call void @llvm.assume(i1 1) ["separate_storage"(ptr %p1, ptr %p2)]
store i8 0, ptr %p1
store i8 1, ptr %p2
%loadofstore = load i8, ptr %p1
ret i8 %loadofstore
}
define i8 @ptr_to_ptr_no(ptr %pp) {
; CHECK-LABEL: @ptr_to_ptr_no(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P_BASE:%.*]] = load ptr, ptr [[PP:%.*]], align 8
; CHECK-NEXT: store i8 0, ptr [[P_BASE]], align 1
; CHECK-NEXT: [[P_BASE2:%.*]] = load ptr, ptr [[PP]], align 8
; CHECK-NEXT: [[LOADOFSTORE:%.*]] = load i8, ptr [[P_BASE2]], align 1
; CHECK-NEXT: ret i8 [[LOADOFSTORE]]
;
entry:
%p_base = load ptr, ptr %pp
store i8 0, ptr %p_base
%p_base2 = load ptr, ptr %pp
%loadofstore = load i8, ptr %p_base2
ret i8 %loadofstore
}
define i8 @ptr_to_ptr_yes(ptr %pp) {
; CHECK-LABEL: @ptr_to_ptr_yes(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[P_BASE:%.*]] = load ptr, ptr [[PP:%.*]], align 8
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P_BASE]], ptr [[PP]]) ]
; CHECK-NEXT: store i8 0, ptr [[P_BASE]], align 1
; CHECK-NEXT: ret i8 0
;
entry:
%p_base = load ptr, ptr %pp
call void @llvm.assume(i1 1) ["separate_storage"(ptr %p_base, ptr %pp)]
store i8 0, ptr %p_base
%p_base2 = load ptr, ptr %pp
%loadofstore = load i8, ptr %p_base2
ret i8 %loadofstore
}
; The analysis should only kick in if executed (or will be executed) at the
; given program point.
define i8 @flow_sensitive(ptr %p1, ptr %p2, i1 %cond) {
; CHECK-LABEL: @flow_sensitive(
; CHECK-NEXT: entry:
; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BRANCH:%.*]], label [[FALSE_BRANCH:%.*]]
; CHECK: true_branch:
; CHECK-NEXT: store i8 11, ptr [[P1:%.*]], align 1
; CHECK-NEXT: store i8 22, ptr [[P2:%.*]], align 1
; CHECK-NEXT: [[LOADOFSTORE_TRUE:%.*]] = load i8, ptr [[P1]], align 1
; CHECK-NEXT: br label [[ENDIF:%.*]]
; CHECK: false_branch:
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P1]], ptr [[P2]]) ]
; CHECK-NEXT: store i8 33, ptr [[P1]], align 1
; CHECK-NEXT: store i8 44, ptr [[P2]], align 1
; CHECK-NEXT: br label [[ENDIF]]
; CHECK: endif:
; CHECK-NEXT: [[LOADOFSTORE:%.*]] = phi i8 [ [[LOADOFSTORE_TRUE]], [[TRUE_BRANCH]] ], [ 33, [[FALSE_BRANCH]] ]
; CHECK-NEXT: ret i8 [[LOADOFSTORE]]
;
entry:
br i1 %cond, label %true_branch, label %false_branch
true_branch:
store i8 11, ptr %p1
store i8 22, ptr %p2
%loadofstore_true = load i8, ptr %p1
br label %endif
false_branch:
call void @llvm.assume(i1 1) ["separate_storage"(ptr %p1, ptr %p2)]
store i8 33, ptr %p1
store i8 44, ptr %p2
%loadofstore_false = load i8, ptr %p1
br label %endif
endif:
%loadofstore = phi i8 [ %loadofstore_true, %true_branch ], [ %loadofstore_false, %false_branch ]
ret i8 %loadofstore
}
define i8 @flow_sensitive_with_dominator(ptr %p1, ptr %p2, i1 %cond) {
; CHECK-LABEL: @flow_sensitive_with_dominator(
; CHECK-NEXT: entry:
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P1:%.*]], ptr [[P2:%.*]]) ]
; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BRANCH:%.*]], label [[FALSE_BRANCH:%.*]]
; CHECK: true_branch:
; CHECK-NEXT: store i8 11, ptr [[P1]], align 1
; CHECK-NEXT: store i8 22, ptr [[P2]], align 1
; CHECK-NEXT: br label [[ENDIF:%.*]]
; CHECK: false_branch:
; CHECK-NEXT: store i8 33, ptr [[P1]], align 1
; CHECK-NEXT: store i8 44, ptr [[P2]], align 1
; CHECK-NEXT: br label [[ENDIF]]
; CHECK: endif:
; CHECK-NEXT: [[LOADOFSTORE:%.*]] = phi i8 [ 11, [[TRUE_BRANCH]] ], [ 33, [[FALSE_BRANCH]] ]
; CHECK-NEXT: ret i8 [[LOADOFSTORE]]
;
entry:
call void @llvm.assume(i1 1) ["separate_storage"(ptr %p1, ptr %p2)]
br i1 %cond, label %true_branch, label %false_branch
true_branch:
store i8 11, ptr %p1
store i8 22, ptr %p2
%loadofstore_true = load i8, ptr %p1
br label %endif
false_branch:
store i8 33, ptr %p1
store i8 44, ptr %p2
%loadofstore_false = load i8, ptr %p1
br label %endif
endif:
%loadofstore = phi i8 [ %loadofstore_true, %true_branch ], [ %loadofstore_false, %false_branch ]
ret i8 %loadofstore
}
; Hints are relative to entire regions of storage, not particular pointers
; inside them. We should know that the whole ranges are disjoint given hints at
; offsets.
define i8 @offset_agnostic(ptr %p1, ptr %p2) {
; CHECK-LABEL: @offset_agnostic(
; CHECK-NEXT: [[ACCESS1:%.*]] = getelementptr inbounds i8, ptr [[P1:%.*]], i64 12
; CHECK-NEXT: [[ACCESS2:%.*]] = getelementptr inbounds i8, ptr [[P2:%.*]], i64 34
; CHECK-NEXT: [[HINT1:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 56
; CHECK-NEXT: [[HINT2:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 78
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[HINT1]], ptr [[HINT2]]) ]
; CHECK-NEXT: store i8 0, ptr [[ACCESS1]], align 1
; CHECK-NEXT: store i8 1, ptr [[ACCESS2]], align 1
; CHECK-NEXT: ret i8 0
;
%access1 = getelementptr inbounds i8, ptr %p1, i64 12
%access2 = getelementptr inbounds i8, ptr %p2, i64 34
%hint1 = getelementptr inbounds i8, ptr %p1, i64 56
%hint2 = getelementptr inbounds i8, ptr %p2, i64 78
call void @llvm.assume(i1 1) ["separate_storage"(ptr %hint1, ptr %hint2)]
store i8 0, ptr %access1
store i8 1, ptr %access2
%loadofstore = load i8, ptr %access1
ret i8 %loadofstore
}