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