1; RUN: opt -disable-output -passes='print-access-info' %s 2>&1 | FileCheck %s 2 3target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" 4 5; CHECK-LABEL: function 'forked_ptrs_simple': 6; CHECK-NEXT: loop: 7; CHECK-NEXT: Memory dependences are safe with run-time checks 8; CHECK-NEXT: Dependences: 9; CHECK-NEXT: Run-time memory checks: 10; CHECK-NEXT: Check 0: 11; CHECK-NEXT: Comparing group ([[G1:.+]]): 12; CHECK-NEXT: %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 13; CHECK-NEXT: %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 14; CHECK-NEXT: Against group ([[G2:.+]]): 15; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 16; CHECK-NEXT: Check 1: 17; CHECK-NEXT: Comparing group ([[G1]]): 18; CHECK-NEXT: %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 19; CHECK-NEXT: %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 20; CHECK-NEXT: Against group ([[G3:.+]]): 21; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 22; CHECK-NEXT: Grouped accesses: 23; CHECK-NEXT: Group [[G1]] 24; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) 25; CHECK-NEXT: Member: {%Dest,+,4}<nuw><%loop> 26; CHECK-NEXT: Member: {%Dest,+,4}<nuw><%loop> 27; CHECK-NEXT: Group [[G2]]: 28; CHECK-NEXT: (Low: %Base1 High: (400 + %Base1)) 29; CHECK-NEXT: Member: {%Base1,+,4}<nw><%loop> 30; CHECK-NEXT: Group [[G3]]: 31; CHECK-NEXT: (Low: %Base2 High: (400 + %Base2)) 32; CHECK-NEXT: Member: {%Base2,+,4}<nw><%loop> 33; CHECK-EMPTY: 34; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 35; CHECK-NEXT: SCEV assumptions: 36; CHECK-EMPTY: 37; CHECK-NEXT: Expressions re-written: 38 39define void @forked_ptrs_simple(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr %Dest) { 40entry: 41 br label %loop 42 43loop: 44 %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] 45 %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 46 %l.Dest = load float, ptr %gep.Dest 47 %cmp = fcmp une float %l.Dest, 0.0 48 %gep.1 = getelementptr inbounds float, ptr %Base1, i64 %iv 49 %gep.2 = getelementptr inbounds float, ptr %Base2, i64 %iv 50 %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 51 %sink = load float, ptr %select, align 4 52 store float %sink, ptr %gep.Dest, align 4 53 %iv.next = add nuw nsw i64 %iv, 1 54 %exitcond.not = icmp eq i64 %iv.next, 100 55 br i1 %exitcond.not, label %exit, label %loop 56 57exit: 58 ret void 59} 60 61; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset': 62; CHECK-NEXT: for.body: 63; CHECK-NEXT: Report: cannot identify array bounds 64; CHECK-NEXT: Dependences: 65; CHECK-NEXT: Run-time memory checks: 66; CHECK-NEXT: Grouped accesses: 67; CHECK-EMPTY: 68; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 69; CHECK-NEXT: SCEV assumptions: 70; CHECK-EMPTY: 71; CHECK-NEXT: Expressions re-written: 72 73;;;; Derived from the following C code 74;; void forked_ptrs_different_base_same_offset(float *A, float *B, float *C, int *D) { 75;; for (int i=0; i<100; i++) { 76;; if (D[i] != 0) { 77;; C[i] = A[i]; 78;; } else { 79;; C[i] = B[i]; 80;; } 81;; } 82;; } 83 84define dso_local void @forked_ptrs_different_base_same_offset(ptr nocapture readonly nonnull %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 85entry: 86 br label %for.body 87 88for.cond.cleanup: 89 ret void 90 91for.body: 92 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 93 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 94 %0 = load i32, ptr %arrayidx, align 4 95 %cmp1.not = icmp eq i32 %0, 0 96 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 97 %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv 98 %.sink = load float, ptr %.sink.in, align 4 99 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 100 store float %.sink, ptr %1, align 4 101 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 102 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 103 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 104} 105 106; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_possible_poison': 107; CHECK-NEXT: for.body: 108; CHECK-NEXT: Report: cannot identify array bounds 109; CHECK-NEXT: Dependences: 110; CHECK-NEXT: Run-time memory checks: 111; CHECK-NEXT: Grouped accesses: 112; CHECK-EMPTY: 113; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 114; CHECK-NEXT: SCEV assumptions: 115; CHECK-EMPTY: 116; CHECK-NEXT: Expressions re-written: 117 118define dso_local void @forked_ptrs_different_base_same_offset_possible_poison(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds, i1 %c) { 119entry: 120 br label %for.body 121 122for.cond.cleanup: 123 ret void 124 125for.body: 126 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %latch ] 127 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 128 %0 = load i32, ptr %arrayidx, align 4 129 %cmp1.not = icmp eq i32 %0, 0 130 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 131 %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv 132 %.sink = load float, ptr %.sink.in, align 4 133 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 134 br i1 %c, label %then, label %latch 135 136then: 137 store float %.sink, ptr %1, align 4 138 br label %latch 139 140latch: 141 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 142 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 143 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 144} 145 146; CHECK-LABEL: function 'forked_ptrs_same_base_different_offset': 147; CHECK-NEXT: for.body: 148; CHECK-NEXT: Report: cannot identify array bounds 149; CHECK-NEXT: Dependences: 150; CHECK-NEXT: Run-time memory checks: 151; CHECK-NEXT: Grouped accesses: 152; CHECK-EMPTY: 153; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 154; CHECK-NEXT: SCEV assumptions: 155; CHECK-EMPTY: 156; CHECK-NEXT: Expressions re-written: 157 158;;;; Derived from the following C code 159;; void forked_ptrs_same_base_different_offset(float *A, float *B, int *C) { 160;; int offset; 161;; for (int i = 0; i < 100; i++) { 162;; if (C[i] != 0) 163;; offset = i; 164;; else 165;; offset = i+1; 166;; B[i] = A[offset]; 167;; } 168;; } 169 170define dso_local void @forked_ptrs_same_base_different_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 171entry: 172 br label %for.body 173 174for.cond.cleanup: ; preds = %for.body 175 ret void 176 177for.body: ; preds = %entry, %for.body 178 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 179 %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ] 180 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 181 %0 = load i32, ptr %arrayidx, align 4 182 %cmp1.not = icmp eq i32 %0, 0 183 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 184 %add = add nuw nsw i32 %i.014, 1 185 %1 = trunc i64 %indvars.iv to i32 186 %offset.0 = select i1 %cmp1.not, i32 %add, i32 %1 187 %idxprom213 = zext i32 %offset.0 to i64 188 %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %idxprom213 189 %2 = load float, ptr %arrayidx3, align 4 190 %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 191 store float %2, ptr %arrayidx5, align 4 192 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 193 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 194} 195 196;;;; Cases that can be handled by a forked pointer but are not currently allowed. 197 198; CHECK-LABEL: function 'forked_ptrs_uniform_and_strided_forks': 199; CHECK-NEXT: for.body: 200; CHECK-NEXT: Report: cannot identify array bounds 201; CHECK-NEXT: Dependences: 202; CHECK-NEXT: Run-time memory checks: 203; CHECK-NEXT: Grouped accesses: 204; CHECK-EMPTY: 205; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 206; CHECK-NEXT: SCEV assumptions: 207; CHECK-EMPTY: 208; CHECK-NEXT: Expressions re-written: 209 210;;;; Derived from forked_ptrs_same_base_different_offset with a manually 211;;;; added uniform offset and a mul to provide a stride 212 213define dso_local void @forked_ptrs_uniform_and_strided_forks(float* nocapture readonly %Base, float* nocapture %Dest, i32* nocapture readonly %Preds) { 214entry: 215 br label %for.body 216 217for.cond.cleanup: ; preds = %for.body 218 ret void 219 220for.body: ; preds = %entry, %for.body 221 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 222 %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ] 223 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 224 %0 = load i32, ptr %arrayidx, align 4 225 %cmp1.not = icmp eq i32 %0, 0 226 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 227 %add = add nuw nsw i32 %i.014, 1 228 %1 = trunc i64 %indvars.iv to i32 229 %mul = mul i32 %1, 3 230 %offset.0 = select i1 %cmp1.not, i32 4, i32 %mul 231 %idxprom213 = sext i32 %offset.0 to i64 232 %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %idxprom213 233 %2 = load float, ptr %arrayidx3, align 4 234 %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 235 store float %2, ptr %arrayidx5, align 4 236 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 237 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 238} 239 240; CHECK-LABEL: function 'forked_ptrs_gather_and_contiguous_forks': 241; CHECK-NEXT: for.body: 242; CHECK-NEXT: Report: cannot identify array bounds 243; CHECK-NEXT: Dependences: 244; CHECK-NEXT: Run-time memory checks: 245; CHECK-NEXT: Grouped accesses: 246; CHECK-EMPTY: 247; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 248; CHECK-NEXT: SCEV assumptions: 249; CHECK-EMPTY: 250; CHECK-NEXT: Expressions re-written: 251 252;;;; Derived from forked_ptrs_same_base_different_offset with a gather 253;;;; added using Preds as an index array in addition to the per-iteration 254;;;; condition. 255 256define dso_local void @forked_ptrs_gather_and_contiguous_forks(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 257entry: 258 br label %for.body 259 260for.cond.cleanup: ; preds = %for.body 261 ret void 262 263for.body: ; preds = %entry, %for.body 264 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 265 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 266 %0 = load i32, ptr %arrayidx, align 4 267 %cmp1.not = icmp eq i32 %0, 0 268 %arrayidx9 = getelementptr inbounds float, ptr %Base2, i64 %indvars.iv 269 %idxprom4 = sext i32 %0 to i64 270 %arrayidx5 = getelementptr inbounds float, ptr %Base1, i64 %idxprom4 271 %.sink.in = select i1 %cmp1.not, ptr %arrayidx9, ptr %arrayidx5 272 %.sink = load float, ptr %.sink.in, align 4 273 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 274 store float %.sink, ptr %1, align 4 275 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 276 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 277 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 278} 279 280;; We don't currently handle a fork in both the base and the offset of a 281;; GEP instruction. 282 283; CHECK-LABEL: Loop access info in function 'forked_ptrs_two_forks_gep': 284; CHECK-NEXT: for.body: 285; CHECK-NEXT: Report: cannot identify array bounds 286; CHECK-NEXT: Dependences: 287; CHECK-NEXT: Run-time memory checks: 288; CHECK-NEXT: Grouped accesses: 289; CHECK-EMPTY: 290; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 291; CHECK-NEXT: SCEV assumptions: 292; CHECK-EMPTY: 293; CHECK-NEXT: Expressions re-written: 294 295define dso_local void @forked_ptrs_two_forks_gep(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 296entry: 297 br label %for.body 298 299for.cond.cleanup: 300 ret void 301 302for.body: 303 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 304 %arrayidx = getelementptr inbounds i32, i32* %Preds, i64 %indvars.iv 305 %0 = load i32, ptr %arrayidx, align 4 306 %cmp1.not = icmp eq i32 %0, 0 307 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 308 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 309 %offset = select i1 %cmp1.not, i64 %indvars.iv.next, i64 %indvars.iv 310 %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %offset 311 %.sink = load float, ptr %.sink.in, align 4 312 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 313 store float %.sink, ptr %1, align 4 314 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 315 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 316} 317 318;; We don't handle forks as children of a select 319 320; CHECK-LABEL: Loop access info in function 'forked_ptrs_two_select': 321; CHECK-NEXT: loop: 322; CHECK-NEXT: Report: cannot identify array bounds 323; CHECK-NEXT: Dependences: 324; CHECK-NEXT: Run-time memory checks: 325; CHECK-NEXT: Grouped accesses: 326; CHECK-EMPTY: 327; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 328; CHECK-NEXT: SCEV assumptions: 329; CHECK-EMPTY: 330; CHECK-NEXT: Expressions re-written: 331 332define void @forked_ptrs_two_select(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture readonly %Base3, ptr %Dest) { 333entry: 334 br label %loop 335 336loop: 337 %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] 338 %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 339 %l.Dest = load float, ptr %gep.Dest 340 %cmp = fcmp une float %l.Dest, 0.0 341 %cmp1 = fcmp une float %l.Dest, 1.0 342 %gep.1 = getelementptr inbounds float, ptr %Base1, i64 %iv 343 %gep.2 = getelementptr inbounds float, ptr %Base2, i64 %iv 344 %gep.3 = getelementptr inbounds float, ptr %Base3, i64 %iv 345 %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 346 %select1 = select i1 %cmp1, ptr %select, ptr %gep.3 347 %sink = load float, ptr %select1, align 4 348 store float %sink, ptr %gep.Dest, align 4 349 %iv.next = add nuw nsw i64 %iv, 1 350 %exitcond.not = icmp eq i64 %iv.next, 100 351 br i1 %exitcond.not, label %exit, label %loop 352 353exit: 354 ret void 355} 356 357;; We don't yet handle geps with more than 2 operands 358; CHECK-LABEL: Loop access info in function 'forked_ptrs_too_many_gep_ops': 359; CHECK-NEXT: for.body: 360; CHECK-NEXT: Report: cannot identify array bounds 361; CHECK-NEXT: Dependences: 362; CHECK-NEXT: Run-time memory checks: 363; CHECK-NEXT: Grouped accesses: 364; CHECK-EMPTY: 365; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 366; CHECK-NEXT: SCEV assumptions: 367; CHECK-EMPTY: 368; CHECK-NEXT: Expressions re-written: 369 370define void @forked_ptrs_too_many_gep_ops(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 371entry: 372 br label %for.body 373 374for.body: 375 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 376 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 377 %0 = load i32, ptr %arrayidx, align 4 378 %cmp1.not = icmp eq i32 %0, 0 379 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 380 %.sink.in = getelementptr inbounds [1000 x float], ptr %spec.select, i64 0, i64 %indvars.iv 381 %.sink = load float, ptr %.sink.in, align 4 382 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 383 store float %.sink, ptr %1, align 4 384 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 385 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 386 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 387 388for.cond.cleanup: 389 ret void 390} 391 392;; We don't currently handle vector GEPs 393; CHECK-LABEL: Loop access info in function 'forked_ptrs_vector_gep': 394; CHECK-NEXT: for.body: 395; CHECK-NEXT: Report: cannot identify array bounds 396; CHECK-NEXT: Dependences: 397; CHECK-NEXT: Run-time memory checks: 398; CHECK-NEXT: Grouped accesses: 399; CHECK-EMPTY: 400; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 401; CHECK-NEXT: SCEV assumptions: 402; CHECK-EMPTY: 403; CHECK-NEXT: Expressions re-written: 404 405define void @forked_ptrs_vector_gep(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 406entry: 407 br label %for.body 408 409for.body: 410 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 411 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 412 %0 = load i32, ptr %arrayidx, align 4 413 %cmp1.not = icmp eq i32 %0, 0 414 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 415 %.sink.in = getelementptr inbounds <4 x float>, ptr %spec.select, i64 %indvars.iv 416 %.sink = load <4 x float>, ptr %.sink.in, align 4 417 %1 = getelementptr inbounds <4 x float>, ptr %Dest, i64 %indvars.iv 418 store <4 x float> %.sink, ptr %1, align 4 419 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 4 420 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 421 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 422 423for.cond.cleanup: 424 ret void 425} 426