1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes='gvn' -basic-aa-separate-storage -S | FileCheck %s 3 4declare void @llvm.assume(i1) 5 6; Test basic queries. 7 8define i8 @simple_no(ptr %p1, ptr %p2) { 9; CHECK-LABEL: @simple_no( 10; CHECK-NEXT: entry: 11; CHECK-NEXT: store i8 0, ptr [[P1:%.*]], align 1 12; CHECK-NEXT: store i8 1, ptr [[P2:%.*]], align 1 13; CHECK-NEXT: [[LOADOFSTORE:%.*]] = load i8, ptr [[P1]], align 1 14; CHECK-NEXT: ret i8 [[LOADOFSTORE]] 15; 16entry: 17 store i8 0, ptr %p1 18 store i8 1, ptr %p2 19 %loadofstore = load i8, ptr %p1 20 ret i8 %loadofstore 21} 22 23define i8 @simple_yes(ptr %p1, ptr %p2) { 24; CHECK-LABEL: @simple_yes( 25; CHECK-NEXT: entry: 26; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P1:%.*]], ptr [[P2:%.*]]) ] 27; CHECK-NEXT: store i8 0, ptr [[P1]], align 1 28; CHECK-NEXT: store i8 1, ptr [[P2]], align 1 29; CHECK-NEXT: ret i8 0 30; 31entry: 32 call void @llvm.assume(i1 1) ["separate_storage"(ptr %p1, ptr %p2)] 33 store i8 0, ptr %p1 34 store i8 1, ptr %p2 35 %loadofstore = load i8, ptr %p1 36 ret i8 %loadofstore 37} 38 39define i8 @ptr_to_ptr_no(ptr %pp) { 40; CHECK-LABEL: @ptr_to_ptr_no( 41; CHECK-NEXT: entry: 42; CHECK-NEXT: [[P_BASE:%.*]] = load ptr, ptr [[PP:%.*]], align 8 43; CHECK-NEXT: store i8 0, ptr [[P_BASE]], align 1 44; CHECK-NEXT: [[P_BASE2:%.*]] = load ptr, ptr [[PP]], align 8 45; CHECK-NEXT: [[LOADOFSTORE:%.*]] = load i8, ptr [[P_BASE2]], align 1 46; CHECK-NEXT: ret i8 [[LOADOFSTORE]] 47; 48entry: 49 %p_base = load ptr, ptr %pp 50 store i8 0, ptr %p_base 51 %p_base2 = load ptr, ptr %pp 52 %loadofstore = load i8, ptr %p_base2 53 ret i8 %loadofstore 54} 55 56define i8 @ptr_to_ptr_yes(ptr %pp) { 57; CHECK-LABEL: @ptr_to_ptr_yes( 58; CHECK-NEXT: entry: 59; CHECK-NEXT: [[P_BASE:%.*]] = load ptr, ptr [[PP:%.*]], align 8 60; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P_BASE]], ptr [[PP]]) ] 61; CHECK-NEXT: store i8 0, ptr [[P_BASE]], align 1 62; CHECK-NEXT: ret i8 0 63; 64entry: 65 %p_base = load ptr, ptr %pp 66 call void @llvm.assume(i1 1) ["separate_storage"(ptr %p_base, ptr %pp)] 67 store i8 0, ptr %p_base 68 %p_base2 = load ptr, ptr %pp 69 %loadofstore = load i8, ptr %p_base2 70 ret i8 %loadofstore 71} 72 73; The analysis should only kick in if executed (or will be executed) at the 74; given program point. 75 76define i8 @flow_sensitive(ptr %p1, ptr %p2, i1 %cond) { 77; CHECK-LABEL: @flow_sensitive( 78; CHECK-NEXT: entry: 79; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BRANCH:%.*]], label [[FALSE_BRANCH:%.*]] 80; CHECK: true_branch: 81; CHECK-NEXT: store i8 11, ptr [[P1:%.*]], align 1 82; CHECK-NEXT: store i8 22, ptr [[P2:%.*]], align 1 83; CHECK-NEXT: [[LOADOFSTORE_TRUE:%.*]] = load i8, ptr [[P1]], align 1 84; CHECK-NEXT: br label [[ENDIF:%.*]] 85; CHECK: false_branch: 86; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P1]], ptr [[P2]]) ] 87; CHECK-NEXT: store i8 33, ptr [[P1]], align 1 88; CHECK-NEXT: store i8 44, ptr [[P2]], align 1 89; CHECK-NEXT: br label [[ENDIF]] 90; CHECK: endif: 91; CHECK-NEXT: [[LOADOFSTORE:%.*]] = phi i8 [ [[LOADOFSTORE_TRUE]], [[TRUE_BRANCH]] ], [ 33, [[FALSE_BRANCH]] ] 92; CHECK-NEXT: ret i8 [[LOADOFSTORE]] 93; 94entry: 95 br i1 %cond, label %true_branch, label %false_branch 96 97true_branch: 98 store i8 11, ptr %p1 99 store i8 22, ptr %p2 100 %loadofstore_true = load i8, ptr %p1 101 br label %endif 102 103false_branch: 104 call void @llvm.assume(i1 1) ["separate_storage"(ptr %p1, ptr %p2)] 105 store i8 33, ptr %p1 106 store i8 44, ptr %p2 107 %loadofstore_false = load i8, ptr %p1 108 br label %endif 109 110endif: 111 %loadofstore = phi i8 [ %loadofstore_true, %true_branch ], [ %loadofstore_false, %false_branch ] 112 ret i8 %loadofstore 113} 114 115define i8 @flow_sensitive_with_dominator(ptr %p1, ptr %p2, i1 %cond) { 116; CHECK-LABEL: @flow_sensitive_with_dominator( 117; CHECK-NEXT: entry: 118; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[P1:%.*]], ptr [[P2:%.*]]) ] 119; CHECK-NEXT: br i1 [[COND:%.*]], label [[TRUE_BRANCH:%.*]], label [[FALSE_BRANCH:%.*]] 120; CHECK: true_branch: 121; CHECK-NEXT: store i8 11, ptr [[P1]], align 1 122; CHECK-NEXT: store i8 22, ptr [[P2]], align 1 123; CHECK-NEXT: br label [[ENDIF:%.*]] 124; CHECK: false_branch: 125; CHECK-NEXT: store i8 33, ptr [[P1]], align 1 126; CHECK-NEXT: store i8 44, ptr [[P2]], align 1 127; CHECK-NEXT: br label [[ENDIF]] 128; CHECK: endif: 129; CHECK-NEXT: [[LOADOFSTORE:%.*]] = phi i8 [ 11, [[TRUE_BRANCH]] ], [ 33, [[FALSE_BRANCH]] ] 130; CHECK-NEXT: ret i8 [[LOADOFSTORE]] 131; 132entry: 133 call void @llvm.assume(i1 1) ["separate_storage"(ptr %p1, ptr %p2)] 134 br i1 %cond, label %true_branch, label %false_branch 135 136true_branch: 137 store i8 11, ptr %p1 138 store i8 22, ptr %p2 139 %loadofstore_true = load i8, ptr %p1 140 br label %endif 141 142false_branch: 143 store i8 33, ptr %p1 144 store i8 44, ptr %p2 145 %loadofstore_false = load i8, ptr %p1 146 br label %endif 147 148endif: 149 %loadofstore = phi i8 [ %loadofstore_true, %true_branch ], [ %loadofstore_false, %false_branch ] 150 ret i8 %loadofstore 151} 152 153; Hints are relative to entire regions of storage, not particular pointers 154; inside them. We should know that the whole ranges are disjoint given hints at 155; offsets. 156 157define i8 @offset_agnostic(ptr %p1, ptr %p2) { 158; CHECK-LABEL: @offset_agnostic( 159; CHECK-NEXT: [[ACCESS1:%.*]] = getelementptr inbounds i8, ptr [[P1:%.*]], i64 12 160; CHECK-NEXT: [[ACCESS2:%.*]] = getelementptr inbounds i8, ptr [[P2:%.*]], i64 34 161; CHECK-NEXT: [[HINT1:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 56 162; CHECK-NEXT: [[HINT2:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 78 163; CHECK-NEXT: call void @llvm.assume(i1 true) [ "separate_storage"(ptr [[HINT1]], ptr [[HINT2]]) ] 164; CHECK-NEXT: store i8 0, ptr [[ACCESS1]], align 1 165; CHECK-NEXT: store i8 1, ptr [[ACCESS2]], align 1 166; CHECK-NEXT: ret i8 0 167; 168 %access1 = getelementptr inbounds i8, ptr %p1, i64 12 169 %access2 = getelementptr inbounds i8, ptr %p2, i64 34 170 171 %hint1 = getelementptr inbounds i8, ptr %p1, i64 56 172 %hint2 = getelementptr inbounds i8, ptr %p2, i64 78 173 call void @llvm.assume(i1 1) ["separate_storage"(ptr %hint1, ptr %hint2)] 174 175 store i8 0, ptr %access1 176 store i8 1, ptr %access2 177 %loadofstore = load i8, ptr %access1 178 ret i8 %loadofstore 179} 180