1; REQUIRES: asserts 2; RUN: opt %s -passes=loop-vectorize,instcombine -force-vector-width=4 -force-vector-interleave=1 -debug-only=loop-vectorize -disable-output -print-after=instcombine 2>&1 | FileCheck %s 3; RUN: opt %s -passes=loop-vectorize,instcombine -force-vector-width=4 -force-vector-interleave=1 -enable-interleaved-mem-accesses -debug-only=loop-vectorize -disable-output -print-after=instcombine 2>&1 | FileCheck %s --check-prefix=INTER 4 5target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128" 6 7%pair = type { i32, i32 } 8 9; CHECK-LABEL: consecutive_ptr_forward 10; 11; Check that a forward consecutive pointer is recognized as uniform and remains 12; uniform after vectorization. 13; 14; CHECK: LV: Found uniform instruction: %tmp1 = getelementptr inbounds i32, ptr %a, i64 %i 15; CHECK: vector.body 16; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 17; CHECK-NOT: getelementptr 18; CHECK: getelementptr inbounds i32, ptr %a, i64 %index 19; CHECK-NOT: getelementptr 20; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body 21; 22define i32 @consecutive_ptr_forward(ptr %a, i64 %n) { 23entry: 24 br label %for.body 25 26for.body: 27 %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ] 28 %tmp0 = phi i32 [ %tmp3, %for.body ], [ 0, %entry ] 29 %tmp1 = getelementptr inbounds i32, ptr %a, i64 %i 30 %tmp2 = load i32, ptr %tmp1, align 8 31 %tmp3 = add i32 %tmp0, %tmp2 32 %i.next = add nuw nsw i64 %i, 1 33 %cond = icmp slt i64 %i.next, %n 34 br i1 %cond, label %for.body, label %for.end 35 36for.end: 37 %tmp4 = phi i32 [ %tmp3, %for.body ] 38 ret i32 %tmp4 39} 40 41; CHECK-LABEL: consecutive_ptr_reverse 42; 43; Check that a reverse consecutive pointer is recognized as uniform and remains 44; uniform after vectorization. 45; 46; CHECK: LV: Found uniform instruction: %tmp1 = getelementptr inbounds i32, ptr %a, i64 %i 47; CHECK: vector.body 48; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 49; CHECK: [[OFFSET_IDX:%.+]] = sub i64 %n, %index 50; CHECK-NOT: getelementptr 51; CHECK: %[[G0:.+]] = getelementptr inbounds i32, ptr %a, i64 [[OFFSET_IDX]] 52; CHECK: getelementptr inbounds i8, ptr %[[G0]], i64 -12 53; CHECK-NOT: getelementptr 54; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body 55; 56define i32 @consecutive_ptr_reverse(ptr %a, i64 %n) { 57entry: 58 br label %for.body 59 60for.body: 61 %i = phi i64 [ %i.next, %for.body ], [ %n, %entry ] 62 %tmp0 = phi i32 [ %tmp3, %for.body ], [ 0, %entry ] 63 %tmp1 = getelementptr inbounds i32, ptr %a, i64 %i 64 %tmp2 = load i32, ptr %tmp1, align 8 65 %tmp3 = add i32 %tmp0, %tmp2 66 %i.next = add nsw i64 %i, -1 67 %cond = icmp sgt i64 %i.next, 0 68 br i1 %cond, label %for.body, label %for.end 69 70for.end: 71 %tmp4 = phi i32 [ %tmp3, %for.body ] 72 ret i32 %tmp4 73} 74 75; CHECK-LABEL: interleaved_access_forward 76; INTER-LABEL: interleaved_access_forward 77; 78; Check that a consecutive-like pointer used by a forward interleaved group is 79; recognized as uniform and remains uniform after vectorization. When 80; interleaved memory accesses aren't enabled, the pointer should not be 81; recognized as uniform, and it should not be uniform after vectorization. 82; 83; CHECK-NOT: LV: Found uniform instruction: %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0 84; CHECK-NOT: LV: Found uniform instruction: %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1 85; CHECK: vector.body 86; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 87; CHECK: %[[I1:.+]] = or disjoint i64 %index, 1 88; CHECK: %[[I2:.+]] = or disjoint i64 %index, 2 89; CHECK: %[[I3:.+]] = or disjoint i64 %index, 3 90; CHECK: getelementptr inbounds %pair, ptr %p, i64 %index, i32 0 91; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 0 92; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 0 93; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 0 94; CHECK: getelementptr inbounds %pair, ptr %p, i64 %index, i32 1 95; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 1 96; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 1 97; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 1 98; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body 99; 100; INTER: LV: Found uniform instruction: %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0 101; INTER: LV: Found uniform instruction: %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1 102; INTER: vector.body 103; INTER: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 104; INTER-NOT: getelementptr 105; INTER: getelementptr inbounds %pair, ptr %p, i64 %index, i32 0 106; INTER-NOT: getelementptr 107; INTER: br i1 {{.*}}, label %middle.block, label %vector.body 108; 109define i32 @interleaved_access_forward(ptr %p, i64 %n) { 110entry: 111 br label %for.body 112 113for.body: 114 %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ] 115 %tmp0 = phi i32 [ %tmp6, %for.body ], [ 0, %entry ] 116 %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0 117 %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1 118 %tmp3 = load i32, ptr %tmp1, align 8 119 %tmp4 = load i32, ptr %tmp2, align 8 120 %tmp5 = add i32 %tmp3, %tmp4 121 %tmp6 = add i32 %tmp0, %tmp5 122 %i.next = add nuw nsw i64 %i, 1 123 %cond = icmp slt i64 %i.next, %n 124 br i1 %cond, label %for.body, label %for.end 125 126for.end: 127 %tmp14 = phi i32 [ %tmp6, %for.body ] 128 ret i32 %tmp14 129} 130 131; CHECK-LABEL: interleaved_access_reverse 132; INTER-LABEL: interleaved_access_reverse 133; 134; Check that a consecutive-like pointer used by a reverse interleaved group is 135; recognized as uniform and remains uniform after vectorization. When 136; interleaved memory accesses aren't enabled, the pointer should not be 137; recognized as uniform, and it should not be uniform after vectorization. 138; 139; recognized as uniform, and it should not be uniform after vectorization. 140; CHECK-NOT: LV: Found uniform instruction: %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0 141; CHECK-NOT: LV: Found uniform instruction: %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1 142; CHECK: vector.body 143; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 144; CHECK: [[OFFSET_IDX:%.+]] = sub i64 %n, %index 145; CHECK: %[[I1:.+]] = add i64 [[OFFSET_IDX]], -1 146; CHECK: %[[I2:.+]] = add i64 [[OFFSET_IDX]], -2 147; CHECK: %[[I3:.+]] = add i64 [[OFFSET_IDX]], -3 148; CHECK: getelementptr inbounds %pair, ptr %p, i64 [[OFFSET_IDX]], i32 0 149; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 0 150; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 0 151; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 0 152; CHECK: getelementptr inbounds %pair, ptr %p, i64 [[OFFSET_IDX]], i32 1 153; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 1 154; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 1 155; CHECK: getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 1 156; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body 157; 158; INTER: LV: Found uniform instruction: %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0 159; INTER: LV: Found uniform instruction: %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1 160; INTER: vector.body 161; INTER: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 162; INTER: [[OFFSET_IDX:%.+]] = sub i64 %n, %index 163; INTER-NOT: getelementptr 164; INTER: %[[G0:.+]] = getelementptr inbounds %pair, ptr %p, i64 [[OFFSET_IDX]], i32 0 165; INTER: getelementptr inbounds i8, ptr %[[G0]], i64 -24 166; INTER-NOT: getelementptr 167; INTER: br i1 {{.*}}, label %middle.block, label %vector.body 168; 169define i32 @interleaved_access_reverse(ptr %p, i64 %n) { 170entry: 171 br label %for.body 172 173for.body: 174 %i = phi i64 [ %i.next, %for.body ], [ %n, %entry ] 175 %tmp0 = phi i32 [ %tmp6, %for.body ], [ 0, %entry ] 176 %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0 177 %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1 178 %tmp3 = load i32, ptr %tmp1, align 8 179 %tmp4 = load i32, ptr %tmp2, align 8 180 %tmp5 = add i32 %tmp3, %tmp4 181 %tmp6 = add i32 %tmp0, %tmp5 182 %i.next = add nsw i64 %i, -1 183 %cond = icmp sgt i64 %i.next, 0 184 br i1 %cond, label %for.body, label %for.end 185 186for.end: 187 %tmp14 = phi i32 [ %tmp6, %for.body ] 188 ret i32 %tmp14 189} 190 191; INTER-LABEL: predicated_store 192; 193; Check that a consecutive-like pointer used by a forward interleaved group and 194; scalarized store is not recognized as uniform and is not uniform after 195; vectorization. The store is scalarized because it's in a predicated block. 196; Even though the load in this example is vectorized and only uses the pointer 197; as if it were uniform, the store is scalarized, making the pointer 198; non-uniform. 199; 200; INTER-NOT: LV: Found uniform instruction: %tmp0 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0 201; INTER: vector.body 202; INTER: %index = phi i64 [ 0, %vector.ph ], [ %index.next, {{.*}} ] 203; INTER: %[[G0:.+]] = getelementptr inbounds %pair, ptr %p, i64 %index, i32 0 204; INTER: %wide.vec = load <8 x i32>, ptr %[[G0]], align 8 205; INTER: %[[I1:.+]] = or disjoint i64 %index, 1 206; INTER: getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 0 207; INTER: %[[I2:.+]] = or disjoint i64 %index, 2 208; INTER: getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 0 209; INTER: %[[I3:.+]] = or disjoint i64 %index, 3 210; INTER: getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 0 211; INTER: br i1 {{.*}}, label %middle.block, label %vector.body 212; 213define void @predicated_store(ptr %p, i32 %x, i64 %n) { 214entry: 215 br label %for.body 216 217for.body: 218 %i = phi i64 [ %i.next, %if.merge ], [ 0, %entry ] 219 %tmp0 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0 220 %tmp1 = load i32, ptr %tmp0, align 8 221 %tmp2 = icmp eq i32 %tmp1, %x 222 br i1 %tmp2, label %if.then, label %if.merge 223 224if.then: 225 store i32 %tmp1, ptr %tmp0, align 8 226 br label %if.merge 227 228if.merge: 229 %i.next = add nuw nsw i64 %i, 1 230 %cond = icmp slt i64 %i.next, %n 231 br i1 %cond, label %for.body, label %for.end 232 233for.end: 234 ret void 235} 236 237; CHECK-LABEL: irregular_type 238; 239; Check that a consecutive pointer used by a scalarized store is not recognized 240; as uniform and is not uniform after vectorization. The store is scalarized 241; because the stored type may required padding. 242; 243; CHECK-NOT: LV: Found uniform instruction: %tmp1 = getelementptr inbounds x86_fp80, ptr %a, i64 %i 244; CHECK: vector.body 245; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 246; CHECK: %[[I1:.+]] = or disjoint i64 %index, 1 247; CHECK: %[[I2:.+]] = or disjoint i64 %index, 2 248; CHECK: %[[I3:.+]] = or disjoint i64 %index, 3 249; CHECK: getelementptr inbounds x86_fp80, ptr %a, i64 %index 250; CHECK: getelementptr inbounds x86_fp80, ptr %a, i64 %[[I1]] 251; CHECK: getelementptr inbounds x86_fp80, ptr %a, i64 %[[I2]] 252; CHECK: getelementptr inbounds x86_fp80, ptr %a, i64 %[[I3]] 253; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body 254; 255define void @irregular_type(ptr %a, i64 %n) { 256entry: 257 br label %for.body 258 259for.body: 260 %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] 261 %tmp0 = sitofp i32 1 to x86_fp80 262 %tmp1 = getelementptr inbounds x86_fp80, ptr %a, i64 %i 263 store x86_fp80 %tmp0, ptr %tmp1, align 16 264 %i.next = add i64 %i, 1 265 %cond = icmp slt i64 %i.next, %n 266 br i1 %cond, label %for.body, label %for.end 267 268for.end: 269 ret void 270} 271 272; CHECK-LABEL: pointer_iv_uniform 273; 274; Check that a pointer induction variable is recognized as uniform and remains 275; uniform after vectorization. 276; 277; CHECK: LV: Found uniform instruction: %p = phi ptr [ %tmp03, %for.body ], [ %a, %entry ] 278; CHECK: vector.body 279; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 280; CHECK-NOT: getelementptr 281; CHECK: [[SHL:%.+]] = shl i64 %index, 2 282; CHECK: %next.gep = getelementptr i8, ptr %a, i64 [[SHL]] 283; CHECK-NOT: getelementptr 284; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body 285; 286define void @pointer_iv_uniform(ptr %a, i32 %x, i64 %n) { 287entry: 288 br label %for.body 289 290for.body: 291 %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ] 292 %p = phi ptr [ %tmp03, %for.body ], [ %a, %entry ] 293 store i32 %x, ptr %p, align 8 294 %tmp03 = getelementptr inbounds i32, ptr %p, i32 1 295 %i.next = add nuw nsw i64 %i, 1 296 %cond = icmp slt i64 %i.next, %n 297 br i1 %cond, label %for.body, label %for.end 298 299for.end: 300 ret void 301} 302 303; INTER-LABEL: pointer_iv_non_uniform_0 304; 305; Check that a pointer induction variable with a non-uniform user is not 306; recognized as uniform and is not uniform after vectorization. The pointer 307; induction variable is used by getelementptr instructions that are non-uniform 308; due to scalarization of the stores. 309; 310; INTER-NOT: LV: Found uniform instruction: %p = phi ptr [ %tmp03, %for.body ], [ %a, %entry ] 311; INTER: vector.body 312; INTER: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 313; INTER: %[[I0:.+]] = shl i64 %index, 4 314; INTER: %[[I1:.+]] = or disjoint i64 %[[I0]], 16 315; INTER: %[[I2:.+]] = or disjoint i64 %[[I0]], 32 316; INTER: %[[I3:.+]] = or disjoint i64 %[[I0]], 48 317; INTER: %next.gep = getelementptr i8, ptr %a, i64 %[[I0]] 318; INTER-NEXT: = getelementptr i8, ptr %a, i64 %[[I1]] 319; INTER-NEXT: = getelementptr i8, ptr %a, i64 %[[I2]] 320; INTER-NEXT: = getelementptr i8, ptr %a, i64 %[[I3]] 321; INTER: br i1 {{.*}}, label %middle.block, label %vector.body 322; 323define void @pointer_iv_non_uniform_0(ptr %a, i64 %n) { 324entry: 325 br label %for.body 326 327for.body: 328 %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ] 329 %p = phi ptr [ %tmp03, %for.body ], [ %a, %entry ] 330 %tmp00 = load i32, ptr %p, align 8 331 %tmp01 = getelementptr inbounds i32, ptr %p, i32 1 332 %tmp02 = load i32, ptr %tmp01, align 8 333 %tmp03 = getelementptr inbounds i32, ptr %p, i32 4 334 %tmp04 = load i32, ptr %tmp03, align 8 335 %tmp05 = getelementptr inbounds i32, ptr %p, i32 5 336 %tmp06 = load i32, ptr %tmp05, align 8 337 %tmp07 = sub i32 %tmp04, %tmp00 338 %tmp08 = sub i32 %tmp02, %tmp02 339 %tmp09 = getelementptr inbounds i32, ptr %p, i32 2 340 store i32 %tmp07, ptr %tmp09, align 8 341 %tmp10 = getelementptr inbounds i32, ptr %p, i32 3 342 store i32 %tmp08, ptr %tmp10, align 8 343 %i.next = add nuw nsw i64 %i, 1 344 %cond = icmp slt i64 %i.next, %n 345 br i1 %cond, label %for.body, label %for.end 346 347for.end: 348 ret void 349} 350 351; CHECK-LABEL: pointer_iv_non_uniform_1 352; 353; Check that a pointer induction variable with a non-uniform user is not 354; recognized as uniform and is not uniform after vectorization. The pointer 355; induction variable is used by a store that will be scalarized. 356; 357; CHECK-NOT: LV: Found uniform instruction: %p = phi ptr [%tmp1, %for.body], [%a, %entry] 358; CHECK: vector.body 359; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 360; CHECK: [[SHL1:%.+]] = shl i64 %index, 4 361; CHECK: %[[I1:.+]] = or disjoint i64 [[SHL1]], 16 362; CHECK: %[[I2:.+]] = or disjoint i64 [[SHL1]], 32 363; CHECK: %[[I3:.+]] = or disjoint i64 [[SHL1]], 48 364; CHECK: %next.gep = getelementptr i8, ptr %a, i64 [[SHL1]] 365; CHECK: = getelementptr i8, ptr %a, i64 %[[I1]] 366; CHECK: = getelementptr i8, ptr %a, i64 %[[I2]] 367; CHECK: = getelementptr i8, ptr %a, i64 %[[I3]] 368; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body 369; 370define void @pointer_iv_non_uniform_1(ptr %a, i64 %n) { 371entry: 372 br label %for.body 373 374for.body: 375 %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ] 376 %p = phi ptr [%tmp1, %for.body], [%a, %entry] 377 %tmp0 = sitofp i32 1 to x86_fp80 378 store x86_fp80 %tmp0, ptr %p, align 16 379 %tmp1 = getelementptr inbounds x86_fp80, ptr %p, i32 1 380 %i.next = add i64 %i, 1 381 %cond = icmp slt i64 %i.next, %n 382 br i1 %cond, label %for.body, label %for.end 383 384for.end: 385 ret void 386} 387 388; CHECK-LABEL: pointer_iv_mixed 389; 390; Check multiple pointer induction variables where only one is recognized as 391; uniform and remains uniform after vectorization. The other pointer induction 392; variable is not recognized as uniform and is not uniform after vectorization 393; because it is stored to memory. 394; 395; CHECK-NOT: LV: Found uniform instruction: %p = phi ptr [ %tmp3, %for.body ], [ %a, %entry ] 396; CHECK: LV: Found uniform instruction: %q = phi ptr [ %tmp4, %for.body ], [ %b, %entry ] 397; CHECK: vector.body 398; CHECK: %pointer.phi = phi ptr [ %a, %vector.ph ], [ %ptr.ind, %vector.body ] 399; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 400; CHECK: %[[PTRVEC:.+]] = getelementptr i8, ptr %pointer.phi, <4 x i64> <i64 0, i64 4, i64 8, i64 12> 401; CHECK: [[SHL:%.+]] = shl i64 %index, 3 402; CHECK: %next.gep = getelementptr i8, ptr %b, i64 [[SHL]] 403; CHECK: store <4 x ptr> %[[PTRVEC]], ptr %next.gep, align 8 404; CHECK: %ptr.ind = getelementptr i8, ptr %pointer.phi, i64 16 405; CHECK: br i1 {{.*}}, label %middle.block, label %vector.body 406; 407define i32 @pointer_iv_mixed(ptr %a, ptr %b, i64 %n) { 408entry: 409 br label %for.body 410 411for.body: 412 %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ] 413 %p = phi ptr [ %tmp3, %for.body ], [ %a, %entry ] 414 %q = phi ptr [ %tmp4, %for.body ], [ %b, %entry ] 415 %tmp0 = phi i32 [ %tmp2, %for.body ], [ 0, %entry ] 416 %tmp1 = load i32, ptr %p, align 8 417 %tmp2 = add i32 %tmp1, %tmp0 418 store ptr %p, ptr %q, align 8 419 %tmp3 = getelementptr inbounds i32, ptr %p, i32 1 420 %tmp4 = getelementptr inbounds ptr, ptr %q, i32 1 421 %i.next = add nuw nsw i64 %i, 1 422 %cond = icmp slt i64 %i.next, %n 423 br i1 %cond, label %for.body, label %for.end 424 425for.end: 426 %tmp5 = phi i32 [ %tmp2, %for.body ] 427 ret i32 %tmp5 428} 429 430; INTER-LABEL: pointer_operand_geps_with_different_indexed_types 431; 432; Check that a pointer operand having a user other than a memory access is 433; recognized as uniform after vectorization. In this test case, %tmp0 is a 434; GEP that is used by a load and a getelementptr instruction (%tmp2). Once 435; %tmp2 is marked uniform, %tmp0 should be marked uniform as well. 436; 437; INTER: LV: Found uniform instruction: %cond = icmp slt i64 %i.next, %n 438; INTER-NEXT: LV: Found uniform instruction: %tmp2 = getelementptr inbounds i8, ptr %tmp0, i64 3 439; INTER-NEXT: LV: Found uniform instruction: %tmp6 = getelementptr inbounds i8, ptr %B, i64 %i 440; INTER-NEXT: LV: Found uniform instruction: %tmp0 = getelementptr inbounds i64, ptr %A, i64 %i 441; INTER-NEXT: LV: Found uniform instruction: %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] 442; INTER-NEXT: LV: Found uniform instruction: %i.next = add nuw nsw i64 %i, 1 443; INTER: define void @pointer_operand_geps_with_different_indexed_types( 444; INTER: vector.body: 445; INTER-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %vector.ph ], [ [[INDEX_NEXT:%.*]], %vector.body ] 446; INTER-NEXT: [[TMP4:%.*]] = getelementptr inbounds i64, ptr %A, i64 [[INDEX]] 447; INTER-NEXT: [[WIDE_VEC:%.*]] = load <32 x i8>, ptr [[TMP4]], align 1 448; INTER-NEXT: [[STRIDED_VEC:%.*]] = shufflevector <32 x i8> [[WIDE_VEC]], <32 x i8> poison, <4 x i32> <i32 0, i32 8, i32 16, i32 24> 449; INTER-NEXT: [[STRIDED_VEC3:%.*]] = shufflevector <32 x i8> [[WIDE_VEC]], <32 x i8> poison, <4 x i32> <i32 3, i32 11, i32 19, i32 27> 450; INTER-NEXT: [[TMP5:%.*]] = xor <4 x i8> [[STRIDED_VEC3]], [[STRIDED_VEC]] 451; INTER-NEXT: [[TMP6:%.*]] = getelementptr inbounds i8, ptr %B, i64 [[INDEX]] 452; INTER-NEXT: store <4 x i8> [[TMP5]], ptr [[TMP6]], align 1 453; INTER-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4 454; INTER: br i1 {{.*}}, label %middle.block, label %vector.body 455; 456define void @pointer_operand_geps_with_different_indexed_types(ptr %A, ptr %B, i64 %n) { 457entry: 458 br label %for.body 459 460for.body: 461 %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ] 462 %tmp0 = getelementptr inbounds i64, ptr %A, i64 %i 463 %tmp2 = getelementptr inbounds i8, ptr %tmp0, i64 3 464 %tmp3 = load i8, ptr %tmp2, align 1 465 %tmp4 = load i8, ptr %tmp0, align 1 466 %tmp5 = xor i8 %tmp3, %tmp4 467 %tmp6 = getelementptr inbounds i8, ptr %B, i64 %i 468 store i8 %tmp5, ptr %tmp6 469 %i.next = add nuw nsw i64 %i, 1 470 %cond = icmp slt i64 %i.next, %n 471 br i1 %cond, label %for.body, label %for.end 472 473for.end: 474 ret void 475} 476 477; CHECK-LABEL: pr61396_pointer_used_as_both_stored_value_and_pointer_operand_by_store 478; CHECK-NOT: LV: Found uniform instruction: %cur.ptr = getelementptr inbounds ptr, ptr %ary, i64 %iv 479 480; CHECK: define void @pr61396_pointer_used_as_both_stored_value_and_pointer_operand_by_store( 481; CHECK: vector.body: 482; CHECK-NEXT: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ] 483; CHECK-NEXT: [[VEC_IND:%.+]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, %vector.ph ], [ %vec.ind.next, %vector.body ] 484; CHECK-NEXT: [[GEP:%.+]] = getelementptr inbounds ptr, ptr %ary, <4 x i64> [[VEC_IND]] 485; CHECK-NEXT: [[EXT:%.+]] = extractelement <4 x ptr> [[GEP]], i64 0 486; CHECK-NEXT: store <4 x ptr> [[GEP]], ptr [[EXT]], align 8 487; 488 489define void @pr61396_pointer_used_as_both_stored_value_and_pointer_operand_by_store(ptr %ary) { 490entry: 491 br label %loop 492 493loop: 494 %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] 495 %cur.ptr = getelementptr inbounds ptr, ptr %ary, i64 %iv 496 store ptr %cur.ptr, ptr %cur.ptr, align 8 497 %iv.next = add nuw nsw i64 %iv, 1 498 %done = icmp eq i64 %iv, 10240 499 br i1 %done, label %exit, label %loop 500 501exit: 502 ret void 503} 504