| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 6 | |
| ; RUN: opt -passes=loop-vectorize -force-vector-width=4 -S %s | FileCheck %s | |
| ; RUN: opt -passes=loop-vectorize -force-vector-width=4 -use-dereferenceable-at-point-semantics -S %s | FileCheck %s | |
| define i32 @early_exit_with_extractvalue(ptr dereferenceable(1024) align 8 %src, i32 noundef %x) { | |
| ; CHECK-LABEL: define i32 @early_exit_with_extractvalue( | |
| ; CHECK-SAME: ptr align 8 dereferenceable(1024) [[SRC:%.*]], i32 noundef [[X:%.*]]) { | |
| ; CHECK-NEXT: [[LOOP_PREHEADER:.*:]] | |
| ; CHECK-NEXT: br label %[[LOOP:.*]] | |
| ; CHECK: [[LOOP]]: | |
| ; CHECK-NEXT: [[BROADCAST_SPLATINSERT:%.*]] = insertelement <4 x i32> poison, i32 [[X]], i64 0 | |
| ; CHECK-NEXT: [[BROADCAST_SPLAT:%.*]] = shufflevector <4 x i32> [[BROADCAST_SPLATINSERT]], <4 x i32> poison, <4 x i32> zeroinitializer | |
| ; CHECK-NEXT: br label %[[LATCH:.*]] | |
| ; CHECK: [[LATCH]]: | |
| ; CHECK-NEXT: [[INDEX:%.*]] = phi i32 [ 0, %[[LOOP]] ], [ [[IV_NEXT:%.*]], %[[EARLY_EXIT:.*]] ] | |
| ; CHECK-NEXT: [[VEC_IND:%.*]] = phi <4 x i32> [ <i32 0, i32 1, i32 2, i32 3>, %[[LOOP]] ], [ [[VEC_IND_NEXT:%.*]], %[[EARLY_EXIT]] ] | |
| ; CHECK-NEXT: [[TMP1:%.*]] = call { <4 x i32>, <4 x i1> } @llvm.smul.with.overflow.v4i32(<4 x i32> [[VEC_IND]], <4 x i32> [[BROADCAST_SPLAT]]) | |
| ; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { <4 x i32>, <4 x i1> } [[TMP1]], 1 | |
| ; CHECK-NEXT: [[TMP3:%.*]] = freeze <4 x i1> [[TMP2]] | |
| ; CHECK-NEXT: [[TMP4:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP3]]) | |
| ; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[INDEX]], 4 | |
| ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[IV_NEXT]], 60 | |
| ; CHECK-NEXT: [[VEC_IND_NEXT]] = add nuw nsw <4 x i32> [[VEC_IND]], splat (i32 4) | |
| ; CHECK-NEXT: br i1 [[TMP4]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[EARLY_EXIT]] | |
| ; CHECK: [[EARLY_EXIT]]: | |
| ; CHECK-NEXT: br i1 [[TMP5]], label %[[MIDDLE_BLOCK:.*]], label %[[LATCH]], !llvm.loop [[LOOP0:![0-9]+]] | |
| ; CHECK: [[MIDDLE_BLOCK]]: | |
| ; CHECK-NEXT: br label %[[EXIT_LOOPEXIT:.*]] | |
| ; CHECK: [[VECTOR_EARLY_EXIT]]: | |
| ; CHECK-NEXT: [[TMP7:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1> [[TMP3]], i1 false) | |
| ; CHECK-NEXT: [[TMP8:%.*]] = trunc i64 [[TMP7]] to i32 | |
| ; CHECK-NEXT: [[IV_LCSSA1:%.*]] = add i32 [[INDEX]], [[TMP8]] | |
| ; CHECK-NEXT: br label %[[EARLY_EXIT1:.*]] | |
| ; CHECK: [[EXIT_LOOPEXIT]]: | |
| ; CHECK-NEXT: br label %[[LOOP_HEADER:.*]] | |
| ; CHECK: [[LOOP_HEADER]]: | |
| ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 60, %[[EXIT_LOOPEXIT]] ], [ [[IV_NEXT1:%.*]], %[[LOOP_LATCH:.*]] ] | |
| ; CHECK-NEXT: [[MUL_OV:%.*]] = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 [[IV]], i32 [[X]]) | |
| ; CHECK-NEXT: [[MUL_OV_OVERFLOW:%.*]] = extractvalue { i32, i1 } [[MUL_OV]], 1 | |
| ; CHECK-NEXT: br i1 [[MUL_OV_OVERFLOW]], label %[[EARLY_EXIT1]], label %[[LOOP_LATCH]] | |
| ; CHECK: [[LOOP_LATCH]]: | |
| ; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds i32, ptr [[SRC]], i32 [[IV]] | |
| ; CHECK-NEXT: [[VAL:%.*]] = load i32, ptr [[GEP]], align 4 | |
| ; CHECK-NEXT: [[IV_NEXT1]] = add nuw nsw i32 [[IV]], 1 | |
| ; CHECK-NEXT: [[EC:%.*]] = icmp eq i32 [[IV_NEXT1]], 63 | |
| ; CHECK-NEXT: br i1 [[EC]], label %[[EXIT:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP3:![0-9]+]] | |
| ; CHECK: [[EARLY_EXIT1]]: | |
| ; CHECK-NEXT: [[IV_LCSSA2:%.*]] = phi i32 [ [[IV]], %[[LOOP_HEADER]] ], [ [[IV_LCSSA1]], %[[VECTOR_EARLY_EXIT]] ] | |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA2]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: [[IV_LCSSA:%.*]] = phi i32 [ [[VAL]], %[[LOOP_LATCH]] ] | |
| ; CHECK-NEXT: ret i32 [[IV_LCSSA]] | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| %mul.ov = call { i32, i1 } @llvm.smul.with.overflow.i32(i32 %iv, i32 %x) | |
| %mul.ov.overflow = extractvalue { i32, i1 } %mul.ov, 1 | |
| br i1 %mul.ov.overflow, label %early.exit, label %loop.latch | |
| loop.latch: | |
| %gep = getelementptr inbounds i32, ptr %src, i32 %iv | |
| %val = load i32, ptr %gep, align 4 | |
| %iv.next = add nuw nsw i32 %iv, 1 | |
| %ec = icmp eq i32 %iv.next, 63 | |
| br i1 %ec, label %exit, label %loop.header | |
| early.exit: | |
| ret i32 %iv | |
| exit: | |
| ret i32 %val | |
| } | |
| define void @readnone_call_site_non_deref_load(ptr dereferenceable(1024) %a, ptr %b) { | |
| ; CHECK-LABEL: define void @readnone_call_site_non_deref_load( | |
| ; CHECK-SAME: ptr dereferenceable(1024) [[A:%.*]], ptr [[B:%.*]]) { | |
| ; CHECK-NEXT: [[SCALAR_PH:.*]]: | |
| ; CHECK-NEXT: br label %[[LOOP:.*]] | |
| ; CHECK: [[LOOP]]: | |
| ; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LATCH:.*]] ] | |
| ; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr i8, ptr [[A]], i64 [[IV]] | |
| ; CHECK-NEXT: [[L_A:%.*]] = load i8, ptr [[GEP_A]], align 1 | |
| ; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr float, ptr [[B]], i64 [[IV]] | |
| ; CHECK-NEXT: [[L_B:%.*]] = load float, ptr [[GEP_B]], align 4 | |
| ; CHECK-NEXT: [[C:%.*]] = call float @fabsf(float [[L_B]]) #[[ATTR3:[0-9]+]] | |
| ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[L_A]], 0 | |
| ; CHECK-NEXT: br i1 [[CMP]], label %[[EXIT:.*]], label %[[LATCH]] | |
| ; CHECK: [[LATCH]]: | |
| ; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1 | |
| ; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], 1024 | |
| ; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP]] | |
| ; CHECK: [[EXIT]]: | |
| ; CHECK-NEXT: ret void | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ] | |
| %gep.a = getelementptr i8, ptr %a, i64 %iv | |
| %l.a = load i8, ptr %gep.a | |
| %gep.b = getelementptr float, ptr %b, i64 %iv | |
| %l.b = load float, ptr %gep.b | |
| %c = call float @fabsf(float %l.b) nounwind memory(none) | |
| %cmp = icmp eq i8 %l.a, 0 | |
| br i1 %cmp, label %exit, label %latch | |
| latch: | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| declare float @fabsf(float) speculatable |