| ; 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 |
| |
| 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> [[TMP2]], 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 |
| } |