| ; 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 |
| } |