1; RUN: opt -disable-output -passes='print-access-info' %s 2>&1 | FileCheck %s 2; RUN: opt -disable-output -passes='print-access-info' -max-forked-scev-depth=2 %s 2>&1 | FileCheck -check-prefix=RECURSE %s 3 4target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" 5 6; CHECK-LABEL: function 'forked_ptrs_simple': 7; CHECK-NEXT: loop: 8; CHECK-NEXT: Memory dependences are safe with run-time checks 9; CHECK-NEXT: Dependences: 10; CHECK-NEXT: Run-time memory checks: 11; CHECK-NEXT: Check 0: 12; CHECK-NEXT: Comparing group ([[G1:.+]]): 13; CHECK-NEXT: %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 14; CHECK-NEXT: %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 15; CHECK-NEXT: Against group ([[G2:.+]]): 16; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 17; CHECK-NEXT: Check 1: 18; CHECK-NEXT: Comparing group ([[G1]]): 19; CHECK-NEXT: %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 20; CHECK-NEXT: %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 21; CHECK-NEXT: Against group ([[G3:.+]]): 22; CHECK-NEXT: %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 23; CHECK-NEXT: Grouped accesses: 24; CHECK-NEXT: Group [[G1]] 25; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) 26; CHECK-NEXT: Member: {%Dest,+,4}<nuw><%loop> 27; CHECK-NEXT: Member: {%Dest,+,4}<nuw><%loop> 28; CHECK-NEXT: Group [[G2]]: 29; CHECK-NEXT: (Low: %Base1 High: (400 + %Base1)) 30; CHECK-NEXT: Member: {%Base1,+,4}<nw><%loop> 31; CHECK-NEXT: Group [[G3]]: 32; CHECK-NEXT: (Low: %Base2 High: (400 + %Base2)) 33; CHECK-NEXT: Member: {%Base2,+,4}<nw><%loop> 34; CHECK-EMPTY: 35; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 36; CHECK-NEXT: SCEV assumptions: 37; CHECK-EMPTY: 38; CHECK-NEXT: Expressions re-written: 39 40define void @forked_ptrs_simple(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr %Dest) { 41entry: 42 br label %loop 43 44loop: 45 %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] 46 %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 47 %l.Dest = load float, ptr %gep.Dest 48 %cmp = fcmp une float %l.Dest, 0.0 49 %gep.1 = getelementptr inbounds float, ptr %Base1, i64 %iv 50 %gep.2 = getelementptr inbounds float, ptr %Base2, i64 %iv 51 %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 52 %sink = load float, ptr %select, align 4 53 store float %sink, ptr %gep.Dest, align 4 54 %iv.next = add nuw nsw i64 %iv, 1 55 %exitcond.not = icmp eq i64 %iv.next, 100 56 br i1 %exitcond.not, label %exit, label %loop 57 58exit: 59 ret void 60} 61 62; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset': 63; CHECK-NEXT: for.body: 64; CHECK-NEXT: Memory dependences are safe with run-time checks 65; CHECK-NEXT: Dependences: 66; CHECK-NEXT: Run-time memory checks: 67; CHECK-NEXT: Check 0: 68; CHECK-NEXT: Comparing group ([[G1:.+]]): 69; CHECK-NEXT: %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 70; CHECK-NEXT: Against group ([[G2:.+]]): 71; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 72; CHECK-NEXT: Check 1: 73; CHECK-NEXT: Comparing group ([[G1]]): 74; CHECK-NEXT: %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 75; CHECK-NEXT: Against group ([[G3:.+]]): 76; CHECK-NEXT: %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv 77; CHECK-NEXT: Check 2: 78; CHECK-NEXT: Comparing group ([[G1]]): 79; CHECK-NEXT: %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 80; CHECK-NEXT: Against group ([[G4:.+]]): 81; CHECK-NEXT: %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv 82; CHECK-NEXT: Grouped accesses: 83; CHECK-NEXT: Group [[G1]]: 84; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) 85; CHECK-NEXT: Member: {%Dest,+,4}<nuw><%for.body> 86; CHECK-NEXT: Group [[G2]]: 87; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) 88; CHECK-NEXT: Member: {%Preds,+,4}<nuw><%for.body> 89; CHECK-NEXT: Group [[G3]]: 90; CHECK-NEXT: (Low: %Base2 High: (400 + %Base2)) 91; CHECK-NEXT: Member: {%Base2,+,4}<nw><%for.body> 92; CHECK-NEXT: Group [[G4]]: 93; CHECK-NEXT: (Low: %Base1 High: (400 + %Base1)) 94; CHECK-NEXT: Member: {%Base1,+,4}<nw><%for.body> 95; CHECK-EMPTY: 96; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 97; CHECK-NEXT: SCEV assumptions: 98; CHECK-EMPTY: 99; CHECK-NEXT: Expressions re-written: 100 101;; We have a limit on the recursion depth for finding a loop invariant or 102;; addrec term; confirm we won't exceed that depth by forcing a lower 103;; limit via -max-forked-scev-depth=2 104; RECURSE-LABEL: Loop access info in function 'forked_ptrs_same_base_different_offset': 105; RECURSE-NEXT: for.body: 106; RECURSE-NEXT: Report: cannot identify array bounds 107; RECURSE-NEXT: Dependences: 108; RECURSE-NEXT: Run-time memory checks: 109; RECURSE-NEXT: Grouped accesses: 110; RECURSE-EMPTY: 111; RECURSE-NEXT: Non vectorizable stores to invariant address were not found in loop. 112; RECURSE-NEXT: SCEV assumptions: 113; RECURSE-EMPTY: 114; RECURSE-NEXT: Expressions re-written: 115 116;;;; Derived from the following C code 117;; void forked_ptrs_different_base_same_offset(float *A, float *B, float *C, int *D) { 118;; for (int i=0; i<100; i++) { 119;; if (D[i] != 0) { 120;; C[i] = A[i]; 121;; } else { 122;; C[i] = B[i]; 123;; } 124;; } 125;; } 126 127define 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) { 128entry: 129 br label %for.body 130 131for.cond.cleanup: 132 ret void 133 134for.body: 135 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 136 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 137 %0 = load i32, ptr %arrayidx, align 4 138 %cmp1.not = icmp eq i32 %0, 0 139 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 140 %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv 141 %.sink = load float, ptr %.sink.in, align 4 142 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 143 store float %.sink, ptr %1, align 4 144 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 145 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 146 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 147} 148 149; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_64b': 150; CHECK-NEXT: for.body: 151; CHECK-NEXT: Memory dependences are safe with run-time checks 152; CHECK-NEXT: Dependences: 153; CHECK-NEXT: Run-time memory checks: 154; CHECK-NEXT: Check 0: 155; CHECK-NEXT: Comparing group ([[G1:.+]]): 156; CHECK-NEXT: %1 = getelementptr inbounds double, ptr %Dest, i64 %indvars.iv 157; CHECK-NEXT: Against group ([[G2:.+]]): 158; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 159; CHECK-NEXT: Check 1: 160; CHECK-NEXT: Comparing group ([[G1]]): 161; CHECK-NEXT: %1 = getelementptr inbounds double, ptr %Dest, i64 %indvars.iv 162; CHECK-NEXT: Against group ([[G3:.+]]): 163; CHECK-NEXT: %.sink.in = getelementptr inbounds double, ptr %spec.select, i64 %indvars.iv 164; CHECK-NEXT: Check 2: 165; CHECK-NEXT: Comparing group ([[G1]]): 166; CHECK-NEXT: %1 = getelementptr inbounds double, ptr %Dest, i64 %indvars.iv 167; CHECK-NEXT: Against group ([[G4:.+]]): 168; CHECK-NEXT: %.sink.in = getelementptr inbounds double, ptr %spec.select, i64 %indvars.iv 169; CHECK-NEXT: Grouped accesses: 170; CHECK-NEXT: Group [[G1]]: 171; CHECK-NEXT: (Low: %Dest High: (800 + %Dest)) 172; CHECK-NEXT: Member: {%Dest,+,8}<nuw><%for.body> 173; CHECK-NEXT: Group [[G2]]: 174; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) 175; CHECK-NEXT: Member: {%Preds,+,4}<nuw><%for.body> 176; CHECK-NEXT: Group [[G3]]: 177; CHECK-NEXT: (Low: %Base2 High: (800 + %Base2)) 178; CHECK-NEXT: Member: {%Base2,+,8}<nw><%for.body> 179; CHECK-NEXT: Group [[G4]]: 180; CHECK-NEXT: (Low: %Base1 High: (800 + %Base1)) 181; CHECK-NEXT: Member: {%Base1,+,8}<nw><%for.body> 182; CHECK-EMPTY: 183; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 184; CHECK-NEXT: SCEV assumptions: 185; CHECK-EMPTY: 186; CHECK-NEXT: Expressions re-written: 187 188define dso_local void @forked_ptrs_different_base_same_offset_64b(ptr nocapture readonly nonnull %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 189entry: 190 br label %for.body 191 192for.cond.cleanup: 193 ret void 194 195for.body: 196 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 197 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 198 %0 = load i32, ptr %arrayidx, align 4 199 %cmp1.not = icmp eq i32 %0, 0 200 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 201 %.sink.in = getelementptr inbounds double, ptr %spec.select, i64 %indvars.iv 202 %.sink = load double, ptr %.sink.in, align 8 203 %1 = getelementptr inbounds double, ptr %Dest, i64 %indvars.iv 204 store double %.sink, ptr %1, align 8 205 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 206 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 207 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 208} 209 210; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_23b': 211; CHECK-NEXT: for.body: 212; CHECK-NEXT: Memory dependences are safe with run-time checks 213; CHECK-NEXT: Dependences: 214; CHECK-NEXT: Run-time memory checks: 215; CHECK-NEXT: Check 0: 216; CHECK-NEXT: Comparing group ([[G1:.+]]): 217; CHECK-NEXT: %1 = getelementptr inbounds i23, ptr %Dest, i64 %indvars.iv 218; CHECK-NEXT: Against group ([[G2:.+]]): 219; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 220; CHECK-NEXT: Check 1: 221; CHECK-NEXT: Comparing group ([[G1]]): 222; CHECK-NEXT: %1 = getelementptr inbounds i23, ptr %Dest, i64 %indvars.iv 223; CHECK-NEXT: Against group ([[G3:.+]]): 224; CHECK-NEXT: %.sink.in = getelementptr inbounds i23, ptr %spec.select, i64 %indvars.iv 225; CHECK-NEXT: Check 2: 226; CHECK-NEXT: Comparing group ([[G1]]): 227; CHECK-NEXT: %1 = getelementptr inbounds i23, ptr %Dest, i64 %indvars.iv 228; CHECK-NEXT: Against group ([[G4:.+]]): 229; CHECK-NEXT: %.sink.in = getelementptr inbounds i23, ptr %spec.select, i64 %indvars.iv 230; CHECK-NEXT: Grouped accesses: 231; CHECK-NEXT: Group [[G1]]: 232; CHECK-NEXT: (Low: %Dest High: (399 + %Dest)) 233; CHECK-NEXT: Member: {%Dest,+,4}<nuw><%for.body> 234; CHECK-NEXT: Group [[G2]]: 235; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) 236; CHECK-NEXT: Member: {%Preds,+,4}<nuw><%for.body> 237; CHECK-NEXT: Group [[G3]]: 238; CHECK-NEXT: (Low: %Base2 High: (399 + %Base2)) 239; CHECK-NEXT: Member: {%Base2,+,4}<nw><%for.body> 240; CHECK-NEXT: Group [[G4]]: 241; CHECK-NEXT: (Low: %Base1 High: (399 + %Base1)) 242; CHECK-NEXT: Member: {%Base1,+,4}<nw><%for.body> 243; CHECK-EMPTY: 244; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 245; CHECK-NEXT: SCEV assumptions: 246; CHECK-EMPTY: 247; CHECK-NEXT: Expressions re-written: 248 249define dso_local void @forked_ptrs_different_base_same_offset_23b(ptr nocapture readonly nonnull %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 250entry: 251 br label %for.body 252 253for.cond.cleanup: 254 ret void 255 256for.body: 257 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 258 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 259 %0 = load i32, ptr %arrayidx, align 4 260 %cmp1.not = icmp eq i32 %0, 0 261 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 262 %.sink.in = getelementptr inbounds i23, ptr %spec.select, i64 %indvars.iv 263 %.sink = load i23, ptr %.sink.in 264 %1 = getelementptr inbounds i23, ptr %Dest, i64 %indvars.iv 265 store i23 %.sink, ptr %1 266 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 267 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 268 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 269} 270 271; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_6b': 272; CHECK-NEXT: for.body: 273; CHECK-NEXT: Memory dependences are safe with run-time checks 274; CHECK-NEXT: Dependences: 275; CHECK-NEXT: Run-time memory checks: 276; CHECK-NEXT: Check 0: 277; CHECK-NEXT: Comparing group ([[G1:.+]]): 278; CHECK-NEXT: %1 = getelementptr inbounds i6, ptr %Dest, i64 %indvars.iv 279; CHECK-NEXT: Against group ([[G2:.+]]): 280; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 281; CHECK-NEXT: Check 1: 282; CHECK-NEXT: Comparing group ([[G1]]): 283; CHECK-NEXT: %1 = getelementptr inbounds i6, ptr %Dest, i64 %indvars.iv 284; CHECK-NEXT: Against group ([[G3:.+]]): 285; CHECK-NEXT: %.sink.in = getelementptr inbounds i6, ptr %spec.select, i64 %indvars.iv 286; CHECK-NEXT: Check 2: 287; CHECK-NEXT: Comparing group ([[G1]]): 288; CHECK-NEXT: %1 = getelementptr inbounds i6, ptr %Dest, i64 %indvars.iv 289; CHECK-NEXT: Against group ([[G4:.+]]): 290; CHECK-NEXT: %.sink.in = getelementptr inbounds i6, ptr %spec.select, i64 %indvars.iv 291; CHECK-NEXT: Grouped accesses: 292; CHECK-NEXT: Group [[G1]]: 293; CHECK-NEXT: (Low: %Dest High: (100 + %Dest)) 294; CHECK-NEXT: Member: {%Dest,+,1}<nuw><%for.body> 295; CHECK-NEXT: Group [[G2]]: 296; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) 297; CHECK-NEXT: Member: {%Preds,+,4}<nuw><%for.body> 298; CHECK-NEXT: Group [[G3]]: 299; CHECK-NEXT: (Low: %Base2 High: (100 + %Base2)) 300; CHECK-NEXT: Member: {%Base2,+,1}<nw><%for.body> 301; CHECK-NEXT: Group [[G4]]: 302; CHECK-NEXT: (Low: %Base1 High: (100 + %Base1)) 303; CHECK-NEXT: Member: {%Base1,+,1}<nw><%for.body> 304; CHECK-EMPTY: 305; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 306; CHECK-NEXT: SCEV assumptions: 307; CHECK-EMPTY: 308; CHECK-NEXT: Expressions re-written: 309 310define dso_local void @forked_ptrs_different_base_same_offset_6b(ptr nocapture readonly nonnull %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 311entry: 312 br label %for.body 313 314for.cond.cleanup: 315 ret void 316 317for.body: 318 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 319 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 320 %0 = load i32, ptr %arrayidx, align 4 321 %cmp1.not = icmp eq i32 %0, 0 322 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 323 %.sink.in = getelementptr inbounds i6, ptr %spec.select, i64 %indvars.iv 324 %.sink = load i6, ptr %.sink.in 325 %1 = getelementptr inbounds i6, ptr %Dest, i64 %indvars.iv 326 store i6 %.sink, ptr %1 327 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 328 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 329 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 330} 331 332; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_possible_poison': 333; CHECK-NEXT: for.body: 334; CHECK-NEXT: Memory dependences are safe with run-time checks 335; CHECK-NEXT: Dependences: 336; CHECK-NEXT: Run-time memory checks: 337; CHECK-NEXT: Check 0: 338; CHECK-NEXT: Comparing group ([[G1:.+]]): 339; CHECK-NEXT: %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 340; CHECK-NEXT: Against group ([[G2:.+]]): 341; CHECK-NEXT: %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 342; CHECK-NEXT: Check 1: 343; CHECK-NEXT: Comparing group ([[G1]]): 344; CHECK-NEXT: %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 345; CHECK-NEXT: Against group ([[G3:.+]]): 346; CHECK-NEXT: %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv 347; CHECK-NEXT: Check 2: 348; CHECK-NEXT: Comparing group ([[G1]]): 349; CHECK-NEXT: %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 350; CHECK-NEXT: Against group ([[G4:.+]]): 351; CHECK-NEXT: %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv 352; CHECK-NEXT: Grouped accesses: 353; CHECK-NEXT: Group [[G1]]: 354; CHECK-NEXT: (Low: %Dest High: (400 + %Dest)) 355; CHECK-NEXT: Member: {%Dest,+,4}<nw><%for.body> 356; CHECK-NEXT: Group [[G2]]: 357; CHECK-NEXT: (Low: %Preds High: (400 + %Preds)) 358; CHECK-NEXT: Member: {%Preds,+,4}<nuw><%for.body> 359; CHECK-NEXT: Group [[G3]]: 360; CHECK-NEXT: (Low: %Base2 High: (400 + %Base2)) 361; CHECK-NEXT: Member: {%Base2,+,4}<nw><%for.body> 362; CHECK-NEXT: Group [[G4]]: 363; CHECK-NEXT: (Low: %Base1 High: (400 + %Base1)) 364; CHECK-NEXT: Member: {%Base1,+,4}<nw><%for.body> 365; CHECK-EMPTY: 366; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 367; CHECK-NEXT: SCEV assumptions: 368; CHECK-EMPTY: 369; CHECK-NEXT: Expressions re-written: 370 371define 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) { 372entry: 373 br label %for.body 374 375for.cond.cleanup: 376 ret void 377 378for.body: 379 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %latch ] 380 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 381 %0 = load i32, ptr %arrayidx, align 4 382 %cmp1.not = icmp eq i32 %0, 0 383 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 384 %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv 385 %.sink = load float, ptr %.sink.in, align 4 386 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 387 br i1 %c, label %then, label %latch 388 389then: 390 store float %.sink, ptr %1, align 4 391 br label %latch 392 393latch: 394 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 395 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 396 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 397} 398 399; CHECK-LABEL: function 'forked_ptrs_same_base_different_offset': 400; CHECK-NEXT: for.body: 401; CHECK-NEXT: Report: cannot identify array bounds 402; CHECK-NEXT: Dependences: 403; CHECK-NEXT: Run-time memory checks: 404; CHECK-NEXT: Grouped accesses: 405; CHECK-EMPTY: 406; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 407; CHECK-NEXT: SCEV assumptions: 408; CHECK-EMPTY: 409; CHECK-NEXT: Expressions re-written: 410 411;;;; Derived from the following C code 412;; void forked_ptrs_same_base_different_offset(float *A, float *B, int *C) { 413;; int offset; 414;; for (int i = 0; i < 100; i++) { 415;; if (C[i] != 0) 416;; offset = i; 417;; else 418;; offset = i+1; 419;; B[i] = A[offset]; 420;; } 421;; } 422 423define dso_local void @forked_ptrs_same_base_different_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 424entry: 425 br label %for.body 426 427for.cond.cleanup: ; preds = %for.body 428 ret void 429 430for.body: ; preds = %entry, %for.body 431 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 432 %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ] 433 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 434 %0 = load i32, ptr %arrayidx, align 4 435 %cmp1.not = icmp eq i32 %0, 0 436 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 437 %add = add nuw nsw i32 %i.014, 1 438 %1 = trunc i64 %indvars.iv to i32 439 %offset.0 = select i1 %cmp1.not, i32 %add, i32 %1 440 %idxprom213 = zext i32 %offset.0 to i64 441 %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %idxprom213 442 %2 = load float, ptr %arrayidx3, align 4 443 %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 444 store float %2, ptr %arrayidx5, align 4 445 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 446 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 447} 448 449; CHECK-LABEL: function 'forked_ptrs_add_to_offset' 450; CHECK-NEXT: for.body: 451; CHECK-NEXT: Report: cannot identify array bounds 452; CHECK-NEXT: Dependences: 453; CHECK-NEXT: Run-time memory checks: 454; CHECK-NEXT: Grouped accesses: 455; CHECK-EMPTY: 456; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 457; CHECK-NEXT: SCEV assumptions: 458; CHECK-EMPTY: 459; CHECK-NEXT: Expressions re-written: 460 461define dso_local void @forked_ptrs_add_to_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds, i64 %extra_offset) { 462entry: 463 br label %for.body 464 465for.cond.cleanup: ; preds = %for.body 466 ret void 467 468for.body: ; preds = %entry, %for.body 469 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 470 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 471 %0 = load i32, ptr %arrayidx, align 4 472 %cmp.not = icmp eq i32 %0, 0 473 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 474 %sel = select i1 %cmp.not, i64 %indvars.iv.next, i64 %indvars.iv 475 %offset = add nuw nsw i64 %sel, %extra_offset 476 %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset 477 %1 = load float, ptr %arrayidx3, align 4 478 %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 479 store float %1, ptr %arrayidx5, align 4 480 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 481 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 482} 483 484; CHECK-LABEL: function 'forked_ptrs_sub_from_offset' 485; CHECK-NEXT: for.body: 486; CHECK-NEXT: Report: cannot identify array bounds 487; CHECK-NEXT: Dependences: 488; CHECK-NEXT: Run-time memory checks: 489; CHECK-NEXT: Grouped accesses: 490; CHECK-EMPTY: 491; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 492; CHECK-NEXT: SCEV assumptions: 493; CHECK-EMPTY: 494; CHECK-NEXT: Expressions re-written: 495 496define dso_local void @forked_ptrs_sub_from_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds, i64 %extra_offset) { 497entry: 498 br label %for.body 499 500for.cond.cleanup: ; preds = %for.body 501 ret void 502 503for.body: ; preds = %entry, %for.body 504 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 505 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 506 %0 = load i32, ptr %arrayidx, align 4 507 %cmp.not = icmp eq i32 %0, 0 508 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 509 %sel = select i1 %cmp.not, i64 %indvars.iv.next, i64 %indvars.iv 510 %offset = sub nuw nsw i64 %sel, %extra_offset 511 %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset 512 %1 = load float, ptr %arrayidx3, align 4 513 %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 514 store float %1, ptr %arrayidx5, align 4 515 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 516 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 517} 518 519; CHECK-LABEL: function 'forked_ptrs_add_sub_offset' 520; CHECK-NEXT: for.body: 521; CHECK-NEXT: Report: cannot identify array bounds 522; CHECK-NEXT: Dependences: 523; CHECK-NEXT: Run-time memory checks: 524; CHECK-NEXT: Grouped accesses: 525; CHECK-EMPTY: 526; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 527; CHECK-NEXT: SCEV assumptions: 528; CHECK-EMPTY: 529; CHECK-NEXT: Expressions re-written: 530 531define dso_local void @forked_ptrs_add_sub_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds, i64 %to_add, i64 %to_sub) { 532entry: 533 br label %for.body 534 535for.cond.cleanup: ; preds = %for.body 536 ret void 537 538for.body: ; preds = %entry, %for.body 539 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 540 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 541 %0 = load i32, ptr %arrayidx, align 4 542 %cmp.not = icmp eq i32 %0, 0 543 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 544 %sel = select i1 %cmp.not, i64 %indvars.iv.next, i64 %indvars.iv 545 %add = add nuw nsw i64 %sel, %to_add 546 %offset = sub nuw nsw i64 %add, %to_sub 547 %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset 548 %1 = load float, ptr %arrayidx3, align 4 549 %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 550 store float %1, ptr %arrayidx5, align 4 551 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 552 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 553} 554 555;;;; Cases that can be handled by a forked pointer but are not currently allowed. 556 557; CHECK-LABEL: function 'forked_ptrs_mul_by_offset' 558; CHECK-NEXT: for.body: 559; CHECK-NEXT: Report: cannot identify array bounds 560; CHECK-NEXT: Dependences: 561; CHECK-NEXT: Run-time memory checks: 562; CHECK-NEXT: Grouped accesses: 563; CHECK-EMPTY: 564; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 565; CHECK-NEXT: SCEV assumptions: 566; CHECK-EMPTY: 567; CHECK-NEXT: Expressions re-written: 568 569define dso_local void @forked_ptrs_mul_by_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds, i64 %extra_offset) { 570entry: 571 br label %for.body 572 573for.cond.cleanup: ; preds = %for.body 574 ret void 575 576for.body: ; preds = %entry, %for.body 577 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 578 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 579 %0 = load i32, ptr %arrayidx, align 4 580 %cmp.not = icmp eq i32 %0, 0 581 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 582 %sel = select i1 %cmp.not, i64 %indvars.iv.next, i64 %indvars.iv 583 %offset = mul nuw nsw i64 %sel, %extra_offset 584 %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset 585 %1 = load float, ptr %arrayidx3, align 4 586 %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 587 store float %1, ptr %arrayidx5, align 4 588 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 589 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 590} 591 592; CHECK-LABEL: function 'forked_ptrs_uniform_and_strided_forks': 593; CHECK-NEXT: for.body: 594; CHECK-NEXT: Report: cannot identify array bounds 595; CHECK-NEXT: Dependences: 596; CHECK-NEXT: Run-time memory checks: 597; CHECK-NEXT: Grouped accesses: 598; CHECK-EMPTY: 599; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 600; CHECK-NEXT: SCEV assumptions: 601; CHECK-EMPTY: 602; CHECK-NEXT: Expressions re-written: 603 604;;;; Derived from forked_ptrs_same_base_different_offset with a manually 605;;;; added uniform offset and a mul to provide a stride 606 607define dso_local void @forked_ptrs_uniform_and_strided_forks(float* nocapture readonly %Base, float* nocapture %Dest, i32* nocapture readonly %Preds) { 608entry: 609 br label %for.body 610 611for.cond.cleanup: ; preds = %for.body 612 ret void 613 614for.body: ; preds = %entry, %for.body 615 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 616 %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ] 617 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 618 %0 = load i32, ptr %arrayidx, align 4 619 %cmp1.not = icmp eq i32 %0, 0 620 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 621 %add = add nuw nsw i32 %i.014, 1 622 %1 = trunc i64 %indvars.iv to i32 623 %mul = mul i32 %1, 3 624 %offset.0 = select i1 %cmp1.not, i32 4, i32 %mul 625 %idxprom213 = sext i32 %offset.0 to i64 626 %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %idxprom213 627 %2 = load float, ptr %arrayidx3, align 4 628 %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 629 store float %2, ptr %arrayidx5, align 4 630 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 631 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 632} 633 634; CHECK-LABEL: function 'forked_ptrs_gather_and_contiguous_forks': 635; CHECK-NEXT: for.body: 636; CHECK-NEXT: Report: cannot identify array bounds 637; CHECK-NEXT: Dependences: 638; CHECK-NEXT: Run-time memory checks: 639; CHECK-NEXT: Grouped accesses: 640; CHECK-EMPTY: 641; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 642; CHECK-NEXT: SCEV assumptions: 643; CHECK-EMPTY: 644; CHECK-NEXT: Expressions re-written: 645 646;;;; Derived from forked_ptrs_same_base_different_offset with a gather 647;;;; added using Preds as an index array in addition to the per-iteration 648;;;; condition. 649 650define dso_local void @forked_ptrs_gather_and_contiguous_forks(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 651entry: 652 br label %for.body 653 654for.cond.cleanup: ; preds = %for.body 655 ret void 656 657for.body: ; preds = %entry, %for.body 658 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 659 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 660 %0 = load i32, ptr %arrayidx, align 4 661 %cmp1.not = icmp eq i32 %0, 0 662 %arrayidx9 = getelementptr inbounds float, ptr %Base2, i64 %indvars.iv 663 %idxprom4 = sext i32 %0 to i64 664 %arrayidx5 = getelementptr inbounds float, ptr %Base1, i64 %idxprom4 665 %.sink.in = select i1 %cmp1.not, ptr %arrayidx9, ptr %arrayidx5 666 %.sink = load float, ptr %.sink.in, align 4 667 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 668 store float %.sink, ptr %1, align 4 669 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 670 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 671 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 672} 673 674;; We don't currently handle a fork in both the base and the offset of a 675;; GEP instruction. 676 677; CHECK-LABEL: Loop access info in function 'forked_ptrs_two_forks_gep': 678; CHECK-NEXT: for.body: 679; CHECK-NEXT: Report: cannot identify array bounds 680; CHECK-NEXT: Dependences: 681; CHECK-NEXT: Run-time memory checks: 682; CHECK-NEXT: Grouped accesses: 683; CHECK-EMPTY: 684; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 685; CHECK-NEXT: SCEV assumptions: 686; CHECK-EMPTY: 687; CHECK-NEXT: Expressions re-written: 688 689define dso_local void @forked_ptrs_two_forks_gep(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 690entry: 691 br label %for.body 692 693for.cond.cleanup: 694 ret void 695 696for.body: 697 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 698 %arrayidx = getelementptr inbounds i32, i32* %Preds, i64 %indvars.iv 699 %0 = load i32, ptr %arrayidx, align 4 700 %cmp1.not = icmp eq i32 %0, 0 701 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 702 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 703 %offset = select i1 %cmp1.not, i64 %indvars.iv.next, i64 %indvars.iv 704 %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %offset 705 %.sink = load float, ptr %.sink.in, align 4 706 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 707 store float %.sink, ptr %1, align 4 708 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 709 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 710} 711 712;; We don't handle forks as children of a select 713 714; CHECK-LABEL: Loop access info in function 'forked_ptrs_two_select': 715; CHECK-NEXT: loop: 716; CHECK-NEXT: Report: cannot identify array bounds 717; CHECK-NEXT: Dependences: 718; CHECK-NEXT: Run-time memory checks: 719; CHECK-NEXT: Grouped accesses: 720; CHECK-EMPTY: 721; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 722; CHECK-NEXT: SCEV assumptions: 723; CHECK-EMPTY: 724; CHECK-NEXT: Expressions re-written: 725 726define void @forked_ptrs_two_select(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture readonly %Base3, ptr %Dest) { 727entry: 728 br label %loop 729 730loop: 731 %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] 732 %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv 733 %l.Dest = load float, ptr %gep.Dest 734 %cmp = fcmp une float %l.Dest, 0.0 735 %cmp1 = fcmp une float %l.Dest, 1.0 736 %gep.1 = getelementptr inbounds float, ptr %Base1, i64 %iv 737 %gep.2 = getelementptr inbounds float, ptr %Base2, i64 %iv 738 %gep.3 = getelementptr inbounds float, ptr %Base3, i64 %iv 739 %select = select i1 %cmp, ptr %gep.1, ptr %gep.2 740 %select1 = select i1 %cmp1, ptr %select, ptr %gep.3 741 %sink = load float, ptr %select1, align 4 742 store float %sink, ptr %gep.Dest, align 4 743 %iv.next = add nuw nsw i64 %iv, 1 744 %exitcond.not = icmp eq i64 %iv.next, 100 745 br i1 %exitcond.not, label %exit, label %loop 746 747exit: 748 ret void 749} 750 751;; We don't yet handle geps with more than 2 operands 752; CHECK-LABEL: Loop access info in function 'forked_ptrs_too_many_gep_ops': 753; CHECK-NEXT: for.body: 754; CHECK-NEXT: Report: cannot identify array bounds 755; CHECK-NEXT: Dependences: 756; CHECK-NEXT: Run-time memory checks: 757; CHECK-NEXT: Grouped accesses: 758; CHECK-EMPTY: 759; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 760; CHECK-NEXT: SCEV assumptions: 761; CHECK-EMPTY: 762; CHECK-NEXT: Expressions re-written: 763 764define void @forked_ptrs_too_many_gep_ops(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 765entry: 766 br label %for.body 767 768for.body: 769 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 770 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 771 %0 = load i32, ptr %arrayidx, align 4 772 %cmp1.not = icmp eq i32 %0, 0 773 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 774 %.sink.in = getelementptr inbounds [1000 x float], ptr %spec.select, i64 0, i64 %indvars.iv 775 %.sink = load float, ptr %.sink.in, align 4 776 %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv 777 store float %.sink, ptr %1, align 4 778 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1 779 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 780 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 781 782for.cond.cleanup: 783 ret void 784} 785 786;; We don't currently handle vector GEPs 787; CHECK-LABEL: Loop access info in function 'forked_ptrs_vector_gep': 788; CHECK-NEXT: for.body: 789; CHECK-NEXT: Report: cannot identify array bounds 790; CHECK-NEXT: Dependences: 791; CHECK-NEXT: Run-time memory checks: 792; CHECK-NEXT: Grouped accesses: 793; CHECK-EMPTY: 794; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop. 795; CHECK-NEXT: SCEV assumptions: 796; CHECK-EMPTY: 797; CHECK-NEXT: Expressions re-written: 798 799define void @forked_ptrs_vector_gep(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) { 800entry: 801 br label %for.body 802 803for.body: 804 %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ] 805 %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv 806 %0 = load i32, ptr %arrayidx, align 4 807 %cmp1.not = icmp eq i32 %0, 0 808 %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1 809 %.sink.in = getelementptr inbounds <4 x float>, ptr %spec.select, i64 %indvars.iv 810 %.sink = load <4 x float>, ptr %.sink.in, align 4 811 %1 = getelementptr inbounds <4 x float>, ptr %Dest, i64 %indvars.iv 812 store <4 x float> %.sink, ptr %1, align 4 813 %indvars.iv.next = add nuw nsw i64 %indvars.iv, 4 814 %exitcond.not = icmp eq i64 %indvars.iv.next, 100 815 br i1 %exitcond.not, label %for.cond.cleanup, label %for.body 816 817for.cond.cleanup: 818 ret void 819} 820