1; RUN: opt < %s -inferattrs -S | FileCheck %s 2 3; Determine dereference-ability before unused loads get deleted: 4; https://bugs.llvm.org/show_bug.cgi?id=21780 5 6define <4 x double> @PR21780(double* %ptr) { 7; CHECK-LABEL: @PR21780(double* %ptr) 8 ; GEP of index 0 is simplified away. 9 %arrayidx1 = getelementptr inbounds double, double* %ptr, i64 1 10 %arrayidx2 = getelementptr inbounds double, double* %ptr, i64 2 11 %arrayidx3 = getelementptr inbounds double, double* %ptr, i64 3 12 13 %t0 = load double, double* %ptr, align 8 14 %t1 = load double, double* %arrayidx1, align 8 15 %t2 = load double, double* %arrayidx2, align 8 16 %t3 = load double, double* %arrayidx3, align 8 17 18 %vecinit0 = insertelement <4 x double> undef, double %t0, i32 0 19 %vecinit1 = insertelement <4 x double> %vecinit0, double %t1, i32 1 20 %vecinit2 = insertelement <4 x double> %vecinit1, double %t2, i32 2 21 %vecinit3 = insertelement <4 x double> %vecinit2, double %t3, i32 3 22 %shuffle = shufflevector <4 x double> %vecinit3, <4 x double> %vecinit3, <4 x i32> <i32 0, i32 0, i32 2, i32 2> 23 ret <4 x double> %shuffle 24} 25 26; Unsimplified, but still valid. Also, throw in some bogus arguments. 27 28define void @gep0(i8* %unused, i8* %other, i8* %ptr) { 29; CHECK-LABEL: @gep0(i8* %unused, i8* %other, i8* %ptr) 30 %arrayidx0 = getelementptr i8, i8* %ptr, i64 0 31 %arrayidx1 = getelementptr i8, i8* %ptr, i64 1 32 %arrayidx2 = getelementptr i8, i8* %ptr, i64 2 33 %t0 = load i8, i8* %arrayidx0 34 %t1 = load i8, i8* %arrayidx1 35 %t2 = load i8, i8* %arrayidx2 36 store i8 %t2, i8* %other 37 ret void 38} 39 40; Order of accesses does not change computation. 41; Multiple arguments may be dereferenceable. 42 43define void @ordering(i8* %ptr1, i32* %ptr2) { 44; CHECK-LABEL: @ordering(i8* %ptr1, i32* %ptr2) 45 %a20 = getelementptr i32, i32* %ptr2, i64 0 46 %a12 = getelementptr i8, i8* %ptr1, i64 2 47 %t12 = load i8, i8* %a12 48 %a11 = getelementptr i8, i8* %ptr1, i64 1 49 %t20 = load i32, i32* %a20 50 %a10 = getelementptr i8, i8* %ptr1, i64 0 51 %t10 = load i8, i8* %a10 52 %t11 = load i8, i8* %a11 53 %a21 = getelementptr i32, i32* %ptr2, i64 1 54 %t21 = load i32, i32* %a21 55 ret void 56} 57 58; Not in entry block. 59 60define void @not_entry_but_guaranteed_to_execute(i8* %ptr) { 61; CHECK-LABEL: @not_entry_but_guaranteed_to_execute(i8* %ptr) 62entry: 63 br label %exit 64exit: 65 %arrayidx0 = getelementptr i8, i8* %ptr, i64 0 66 %arrayidx1 = getelementptr i8, i8* %ptr, i64 1 67 %arrayidx2 = getelementptr i8, i8* %ptr, i64 2 68 %t0 = load i8, i8* %arrayidx0 69 %t1 = load i8, i8* %arrayidx1 70 %t2 = load i8, i8* %arrayidx2 71 ret void 72} 73 74; Not in entry block and not guaranteed to execute. 75 76define void @not_entry_not_guaranteed_to_execute(i8* %ptr, i1 %cond) { 77; CHECK-LABEL: @not_entry_not_guaranteed_to_execute(i8* %ptr, i1 %cond) 78entry: 79 br i1 %cond, label %loads, label %exit 80loads: 81 %arrayidx0 = getelementptr i8, i8* %ptr, i64 0 82 %arrayidx1 = getelementptr i8, i8* %ptr, i64 1 83 %arrayidx2 = getelementptr i8, i8* %ptr, i64 2 84 %t0 = load i8, i8* %arrayidx0 85 %t1 = load i8, i8* %arrayidx1 86 %t2 = load i8, i8* %arrayidx2 87 ret void 88exit: 89 ret void 90} 91 92; The last load may not execute, so derefenceable bytes only covers the 1st two loads. 93 94define void @partial_in_entry(i16* %ptr, i1 %cond) { 95; CHECK-LABEL: @partial_in_entry(i16* %ptr, i1 %cond) 96entry: 97 %arrayidx0 = getelementptr i16, i16* %ptr, i64 0 98 %arrayidx1 = getelementptr i16, i16* %ptr, i64 1 99 %arrayidx2 = getelementptr i16, i16* %ptr, i64 2 100 %t0 = load i16, i16* %arrayidx0 101 %t1 = load i16, i16* %arrayidx1 102 br i1 %cond, label %loads, label %exit 103loads: 104 %t2 = load i16, i16* %arrayidx2 105 ret void 106exit: 107 ret void 108} 109 110; The volatile load can't be used to prove a non-volatile access is allowed. 111; The 2nd and 3rd loads may never execute. 112 113define void @volatile_is_not_dereferenceable(i16* %ptr) { 114; CHECK-LABEL: @volatile_is_not_dereferenceable(i16* %ptr) 115 %arrayidx0 = getelementptr i16, i16* %ptr, i64 0 116 %arrayidx1 = getelementptr i16, i16* %ptr, i64 1 117 %arrayidx2 = getelementptr i16, i16* %ptr, i64 2 118 %t0 = load volatile i16, i16* %arrayidx0 119 %t1 = load i16, i16* %arrayidx1 120 %t2 = load i16, i16* %arrayidx2 121 ret void 122} 123 124declare void @may_not_return() 125 126define void @not_guaranteed_to_transfer_execution(i16* %ptr) { 127; CHECK-LABEL: @not_guaranteed_to_transfer_execution(i16* %ptr) 128 %arrayidx0 = getelementptr i16, i16* %ptr, i64 0 129 %arrayidx1 = getelementptr i16, i16* %ptr, i64 1 130 %arrayidx2 = getelementptr i16, i16* %ptr, i64 2 131 %t0 = load i16, i16* %arrayidx0 132 call void @may_not_return() 133 %t1 = load i16, i16* %arrayidx1 134 %t2 = load i16, i16* %arrayidx2 135 ret void 136} 137 138; We must have consecutive accesses. 139 140define void @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index) { 141; CHECK-LABEL: @variable_gep_index(i8* %unused, i8* %ptr, i64 %variable_index) 142 %arrayidx1 = getelementptr i8, i8* %ptr, i64 %variable_index 143 %arrayidx2 = getelementptr i8, i8* %ptr, i64 2 144 %t0 = load i8, i8* %ptr 145 %t1 = load i8, i8* %arrayidx1 146 %t2 = load i8, i8* %arrayidx2 147 ret void 148} 149 150; Deal with >1 GEP index. 151 152define void @multi_index_gep(<4 x i8>* %ptr) { 153; CHECK-LABEL: @multi_index_gep(<4 x i8>* %ptr) 154 %arrayidx00 = getelementptr <4 x i8>, <4 x i8>* %ptr, i64 0, i64 0 155 %t0 = load i8, i8* %arrayidx00 156 ret void 157} 158 159; Could round weird bitwidths down? 160 161define void @not_byte_multiple(i9* %ptr) { 162; CHECK-LABEL: @not_byte_multiple(i9* %ptr) 163 %arrayidx0 = getelementptr i9, i9* %ptr, i64 0 164 %t0 = load i9, i9* %arrayidx0 165 ret void 166} 167 168; Missing direct access from the pointer. 169 170define void @no_pointer_deref(i16* %ptr) { 171; CHECK-LABEL: @no_pointer_deref(i16* %ptr) 172 %arrayidx1 = getelementptr i16, i16* %ptr, i64 1 173 %arrayidx2 = getelementptr i16, i16* %ptr, i64 2 174 %t1 = load i16, i16* %arrayidx1 175 %t2 = load i16, i16* %arrayidx2 176 ret void 177} 178 179; Out-of-order is ok, but missing access concludes dereferenceable range. 180 181define void @non_consecutive(i32* %ptr) { 182; CHECK-LABEL: @non_consecutive(i32* %ptr) 183 %arrayidx1 = getelementptr i32, i32* %ptr, i64 1 184 %arrayidx0 = getelementptr i32, i32* %ptr, i64 0 185 %arrayidx3 = getelementptr i32, i32* %ptr, i64 3 186 %t1 = load i32, i32* %arrayidx1 187 %t0 = load i32, i32* %arrayidx0 188 %t3 = load i32, i32* %arrayidx3 189 ret void 190} 191 192; Improve on existing dereferenceable attribute. 193 194define void @more_bytes(i32* dereferenceable(8) %ptr) { 195; CHECK-LABEL: @more_bytes(i32* dereferenceable(8) %ptr) 196 %arrayidx3 = getelementptr i32, i32* %ptr, i64 3 197 %arrayidx1 = getelementptr i32, i32* %ptr, i64 1 198 %arrayidx0 = getelementptr i32, i32* %ptr, i64 0 199 %arrayidx2 = getelementptr i32, i32* %ptr, i64 2 200 %t3 = load i32, i32* %arrayidx3 201 %t1 = load i32, i32* %arrayidx1 202 %t2 = load i32, i32* %arrayidx2 203 %t0 = load i32, i32* %arrayidx0 204 ret void 205} 206 207; But don't pessimize existing dereferenceable attribute. 208 209define void @better_bytes(i32* dereferenceable(100) %ptr) { 210; CHECK-LABEL: @better_bytes(i32* dereferenceable(100) %ptr) 211 %arrayidx3 = getelementptr i32, i32* %ptr, i64 3 212 %arrayidx1 = getelementptr i32, i32* %ptr, i64 1 213 %arrayidx0 = getelementptr i32, i32* %ptr, i64 0 214 %arrayidx2 = getelementptr i32, i32* %ptr, i64 2 215 %t3 = load i32, i32* %arrayidx3 216 %t1 = load i32, i32* %arrayidx1 217 %t2 = load i32, i32* %arrayidx2 218 %t0 = load i32, i32* %arrayidx0 219 ret void 220} 221 222define void @bitcast(i32* %arg) { 223; CHECK-LABEL: @bitcast(i32* %arg) 224 %ptr = bitcast i32* %arg to float* 225 %arrayidx0 = getelementptr float, float* %ptr, i64 0 226 %arrayidx1 = getelementptr float, float* %ptr, i64 1 227 %t0 = load float, float* %arrayidx0 228 %t1 = load float, float* %arrayidx1 229 ret void 230} 231 232define void @bitcast_different_sizes(double* %arg1, i8* %arg2) { 233; CHECK-LABEL: @bitcast_different_sizes(double* %arg1, i8* %arg2) 234 %ptr1 = bitcast double* %arg1 to float* 235 %a10 = getelementptr float, float* %ptr1, i64 0 236 %a11 = getelementptr float, float* %ptr1, i64 1 237 %a12 = getelementptr float, float* %ptr1, i64 2 238 %ld10 = load float, float* %a10 239 %ld11 = load float, float* %a11 240 %ld12 = load float, float* %a12 241 242 %ptr2 = bitcast i8* %arg2 to i64* 243 %a20 = getelementptr i64, i64* %ptr2, i64 0 244 %a21 = getelementptr i64, i64* %ptr2, i64 1 245 %ld20 = load i64, i64* %a20 246 %ld21 = load i64, i64* %a21 247 ret void 248} 249 250define void @negative_offset(i32* %arg) { 251; CHECK-LABEL: @negative_offset(i32* %arg) 252 %ptr = bitcast i32* %arg to float* 253 %arrayidx0 = getelementptr float, float* %ptr, i64 0 254 %arrayidx1 = getelementptr float, float* %ptr, i64 -1 255 %t0 = load float, float* %arrayidx0 256 %t1 = load float, float* %arrayidx1 257 ret void 258} 259 260define void @stores(i32* %arg) { 261; CHECK-LABEL: @stores(i32* %arg) 262 %ptr = bitcast i32* %arg to float* 263 %arrayidx0 = getelementptr float, float* %ptr, i64 0 264 %arrayidx1 = getelementptr float, float* %ptr, i64 1 265 store float 1.0, float* %arrayidx0 266 store float 2.0, float* %arrayidx1 267 ret void 268} 269 270define void @load_store(i32* %arg) { 271; CHECK-LABEL: @load_store(i32* %arg) 272 %ptr = bitcast i32* %arg to float* 273 %arrayidx0 = getelementptr float, float* %ptr, i64 0 274 %arrayidx1 = getelementptr float, float* %ptr, i64 1 275 %t1 = load float, float* %arrayidx0 276 store float 2.0, float* %arrayidx1 277 ret void 278} 279