Skip to content

Commit eb98b65

Browse files
authored
[ValueTracking] Check across single predecessors in willNotFreeBetween. (llvm#167965)
Extend willNotFreeBetween to perform simple checking across blocks to support the case where CtxI is in a successor of the block that contains the assume, but the assume's parent is the single predecessor of CtxI's block. This enables using _builtin_assume_dereferenceable to vectorize std::find_if and co in practice. End-to-end reproducer: https://godbolt.org/z/6jbsd4EjT PR: llvm#167965
1 parent ca26cf8 commit eb98b65

File tree

2 files changed

+306
-16
lines changed

2 files changed

+306
-16
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -704,25 +704,44 @@ bool llvm::isValidAssumeForContext(const Instruction *Inv,
704704

705705
bool llvm::willNotFreeBetween(const Instruction *Assume,
706706
const Instruction *CtxI) {
707-
if (CtxI->getParent() != Assume->getParent() || !Assume->comesBefore(CtxI))
708-
return false;
707+
// Helper to check if there are any calls in the range that may free memory.
708+
auto hasNoFreeCalls = [](auto Range) {
709+
for (const auto &[Idx, I] : enumerate(Range)) {
710+
if (Idx > MaxInstrsToCheckForFree)
711+
return false;
712+
if (const auto *CB = dyn_cast<CallBase>(&I))
713+
if (!CB->hasFnAttr(Attribute::NoFree))
714+
return false;
715+
}
716+
return true;
717+
};
718+
709719
// Make sure the current function cannot arrange for another thread to free on
710720
// its behalf.
711721
if (!CtxI->getFunction()->hasNoSync())
712722
return false;
713723

714-
// Check if there are any calls between the assume and CtxI that may
715-
// free memory.
716-
for (const auto &[Idx, I] :
717-
enumerate(make_range(Assume->getIterator(), CtxI->getIterator()))) {
718-
// Limit number of instructions to walk.
719-
if (Idx > MaxInstrsToCheckForFree)
724+
// Handle cross-block case: CtxI in a successor of Assume's block.
725+
const BasicBlock *CtxBB = CtxI->getParent();
726+
const BasicBlock *AssumeBB = Assume->getParent();
727+
BasicBlock::const_iterator CtxIter = CtxI->getIterator();
728+
if (CtxBB != AssumeBB) {
729+
if (CtxBB->getSinglePredecessor() != AssumeBB)
730+
return false;
731+
732+
if (!hasNoFreeCalls(make_range(CtxBB->begin(), CtxBB->end())))
733+
return false;
734+
735+
CtxIter = AssumeBB->end();
736+
} else {
737+
// Same block case: check that Assume comes before CtxI.
738+
if (!Assume->comesBefore(CtxI))
720739
return false;
721-
if (const auto *CB = dyn_cast<CallBase>(&I))
722-
if (!CB->hasFnAttr(Attribute::NoFree))
723-
return false;
724740
}
725-
return true;
741+
742+
// Check if there are any calls between Assume and CtxIter that may free
743+
// memory.
744+
return hasNoFreeCalls(make_range(Assume->getIterator(), CtxIter));
726745
}
727746

728747
// TODO: cmpExcludesZero misses many cases where `RHS` is non-constant but

llvm/test/Transforms/LoopVectorize/single-early-exit-deref-assumptions.ll

Lines changed: 275 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,66 @@ loop.end:
633633
ret i64 %retval
634634
}
635635

636+
; Test with an invoke terminator between the block containing the assume and loop.
637+
; This should NOT vectorize because the invoke could free memory.
638+
define i64 @early_exit_alignment_and_deref_known_via_assumption_with_constant_size_invoke_may_free(ptr noalias %p1, ptr noalias %p2) nosync personality ptr @__gxx_personality_v0 {
639+
; CHECK-LABEL: define i64 @early_exit_alignment_and_deref_known_via_assumption_with_constant_size_invoke_may_free(
640+
; CHECK-SAME: ptr noalias [[P1:%.*]], ptr noalias [[P2:%.*]]) #[[ATTR1]] personality ptr @__gxx_personality_v0 {
641+
; CHECK-NEXT: [[ENTRY:.*:]]
642+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P1]], i64 4), "dereferenceable"(ptr [[P1]], i64 1024) ]
643+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 4), "dereferenceable"(ptr [[P2]], i64 1024) ]
644+
; CHECK-NEXT: invoke void @may_free()
645+
; CHECK-NEXT: to label %[[LOOP_PREHEADER:.*]] unwind label %[[LPAD:.*]]
646+
; CHECK: [[LOOP_PREHEADER]]:
647+
; CHECK-NEXT: br label %[[LOOP:.*]]
648+
; CHECK: [[LOOP]]:
649+
; CHECK-NEXT: [[INDEX1:%.*]] = phi i64 [ [[INDEX_NEXT:%.*]], %[[LOOP_INC:.*]] ], [ 0, %[[LOOP_PREHEADER]] ]
650+
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[INDEX1]]
651+
; CHECK-NEXT: [[LD1:%.*]] = load i8, ptr [[TMP0]], align 1
652+
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P2]], i64 [[INDEX1]]
653+
; CHECK-NEXT: [[LD2:%.*]] = load i8, ptr [[TMP1]], align 1
654+
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i8 [[LD1]], [[LD2]]
655+
; CHECK-NEXT: br i1 [[CMP3]], label %[[LOOP_INC]], label %[[LOOP_END:.*]]
656+
; CHECK: [[LOOP_INC]]:
657+
; CHECK-NEXT: [[INDEX_NEXT]] = add i64 [[INDEX1]], 1
658+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[INDEX_NEXT]], 1024
659+
; CHECK-NEXT: br i1 [[EXITCOND]], label %[[LOOP]], label %[[LOOP_END]]
660+
; CHECK: [[LOOP_END]]:
661+
; CHECK-NEXT: [[RETVAL:%.*]] = phi i64 [ [[INDEX1]], %[[LOOP]] ], [ -1, %[[LOOP_INC]] ]
662+
; CHECK-NEXT: ret i64 [[RETVAL]]
663+
; CHECK: [[LPAD]]:
664+
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
665+
; CHECK-NEXT: cleanup
666+
; CHECK-NEXT: resume { ptr, i32 } [[LP]]
667+
;
668+
entry:
669+
call void @llvm.assume(i1 true) [ "align"(ptr %p1, i64 4), "dereferenceable"(ptr %p1, i64 1024) ]
670+
call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 4), "dereferenceable"(ptr %p2, i64 1024) ]
671+
invoke void @may_free() to label %loop unwind label %lpad
672+
673+
loop:
674+
%index = phi i64 [ %index.next, %loop.inc ], [ 0, %entry ]
675+
%arrayidx = getelementptr inbounds i8, ptr %p1, i64 %index
676+
%ld1 = load i8, ptr %arrayidx, align 1
677+
%arrayidx1 = getelementptr inbounds i8, ptr %p2, i64 %index
678+
%ld2 = load i8, ptr %arrayidx1, align 1
679+
%cmp3 = icmp eq i8 %ld1, %ld2
680+
br i1 %cmp3, label %loop.inc, label %loop.end
681+
682+
loop.inc:
683+
%index.next = add i64 %index, 1
684+
%exitcond = icmp ne i64 %index.next, 1024
685+
br i1 %exitcond, label %loop, label %loop.end
686+
687+
loop.end:
688+
%retval = phi i64 [ %index, %loop ], [ -1, %loop.inc ]
689+
ret i64 %retval
690+
691+
lpad:
692+
%lp = landingpad { ptr, i32 } cleanup
693+
resume { ptr, i32 } %lp
694+
}
695+
636696
define i64 @find_if_pointer_distance_deref_via_assumption(ptr %vec) nofree nosync {
637697
; CHECK-LABEL: define i64 @find_if_pointer_distance_deref_via_assumption(
638698
; CHECK-SAME: ptr [[VEC:%.*]]) #[[ATTR0]] {
@@ -650,18 +710,55 @@ define i64 @find_if_pointer_distance_deref_via_assumption(ptr %vec) nofree nosyn
650710
; CHECK-NEXT: br i1 [[IS_EMPTY]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
651711
; CHECK: [[LOOP_PREHEADER]]:
652712
; CHECK-NEXT: [[END_PTR:%.*]] = getelementptr i8, ptr [[BEGIN]], i64 [[DISTANCE]]
713+
; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[END_INT]], -2
714+
; CHECK-NEXT: [[TMP1:%.*]] = sub i64 [[TMP0]], [[BEGIN_INT]]
715+
; CHECK-NEXT: [[TMP2:%.*]] = lshr i64 [[TMP1]], 1
716+
; CHECK-NEXT: [[TMP3:%.*]] = add nuw i64 [[TMP2]], 1
717+
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP3]], 4
718+
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
719+
; CHECK: [[VECTOR_PH]]:
720+
; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[TMP3]], 4
721+
; CHECK-NEXT: [[N_VEC:%.*]] = sub i64 [[TMP3]], [[N_MOD_VF]]
722+
; CHECK-NEXT: [[TMP4:%.*]] = mul i64 [[N_VEC]], 2
723+
; CHECK-NEXT: [[TMP5:%.*]] = getelementptr i8, ptr [[BEGIN]], i64 [[TMP4]]
724+
; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
725+
; CHECK: [[VECTOR_BODY]]:
726+
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
727+
; CHECK-NEXT: [[OFFSET_IDX:%.*]] = mul i64 [[INDEX]], 2
728+
; CHECK-NEXT: [[NEXT_GEP:%.*]] = getelementptr i8, ptr [[BEGIN]], i64 [[OFFSET_IDX]]
729+
; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i16>, ptr [[NEXT_GEP]], align 2
730+
; CHECK-NEXT: [[TMP6:%.*]] = icmp eq <4 x i16> [[WIDE_LOAD]], splat (i16 1)
731+
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
732+
; CHECK-NEXT: [[TMP7:%.*]] = freeze <4 x i1> [[TMP6]]
733+
; CHECK-NEXT: [[TMP8:%.*]] = call i1 @llvm.vector.reduce.or.v4i1(<4 x i1> [[TMP7]])
734+
; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
735+
; CHECK-NEXT: [[TMP10:%.*]] = or i1 [[TMP8]], [[TMP9]]
736+
; CHECK-NEXT: br i1 [[TMP10]], label %[[MIDDLE_SPLIT:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP12:![0-9]+]]
737+
; CHECK: [[MIDDLE_SPLIT]]:
738+
; CHECK-NEXT: br i1 [[TMP8]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[MIDDLE_BLOCK:.*]]
739+
; CHECK: [[MIDDLE_BLOCK]]:
740+
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[TMP3]], [[N_VEC]]
741+
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT_LOOPEXIT:.*]], label %[[SCALAR_PH]]
742+
; CHECK: [[VECTOR_EARLY_EXIT]]:
743+
; CHECK-NEXT: [[TMP11:%.*]] = call i64 @llvm.experimental.cttz.elts.i64.v4i1(<4 x i1> [[TMP6]], i1 true)
744+
; CHECK-NEXT: [[TMP12:%.*]] = add i64 [[INDEX]], [[TMP11]]
745+
; CHECK-NEXT: [[TMP13:%.*]] = mul i64 [[TMP12]], 2
746+
; CHECK-NEXT: [[TMP14:%.*]] = getelementptr i8, ptr [[BEGIN]], i64 [[TMP13]]
747+
; CHECK-NEXT: br label %[[EXIT_LOOPEXIT]]
748+
; CHECK: [[SCALAR_PH]]:
749+
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi ptr [ [[TMP5]], %[[MIDDLE_BLOCK]] ], [ [[BEGIN]], %[[LOOP_PREHEADER]] ]
653750
; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
654751
; CHECK: [[LOOP_HEADER]]:
655-
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[PTR_NEXT:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BEGIN]], %[[LOOP_PREHEADER]] ]
752+
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[PTR_NEXT:%.*]], %[[LOOP_LATCH:.*]] ], [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ]
656753
; CHECK-NEXT: [[VAL:%.*]] = load i16, ptr [[PTR]], align 2
657754
; CHECK-NEXT: [[FOUND:%.*]] = icmp eq i16 [[VAL]], 1
658-
; CHECK-NEXT: br i1 [[FOUND]], label %[[EXIT_LOOPEXIT:.*]], label %[[LOOP_LATCH]]
755+
; CHECK-NEXT: br i1 [[FOUND]], label %[[EXIT_LOOPEXIT]], label %[[LOOP_LATCH]]
659756
; CHECK: [[LOOP_LATCH]]:
660757
; CHECK-NEXT: [[PTR_NEXT]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 2
661758
; CHECK-NEXT: [[DONE:%.*]] = icmp eq ptr [[PTR_NEXT]], [[END]]
662-
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT_LOOPEXIT]], label %[[LOOP_HEADER]]
759+
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT_LOOPEXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP13:![0-9]+]]
663760
; CHECK: [[EXIT_LOOPEXIT]]:
664-
; CHECK-NEXT: [[RESULT_PH:%.*]] = phi ptr [ [[END_PTR]], %[[LOOP_LATCH]] ], [ [[PTR]], %[[LOOP_HEADER]] ]
761+
; CHECK-NEXT: [[RESULT_PH:%.*]] = phi ptr [ [[END_PTR]], %[[LOOP_LATCH]] ], [ [[PTR]], %[[LOOP_HEADER]] ], [ [[END_PTR]], %[[MIDDLE_BLOCK]] ], [ [[TMP14]], %[[VECTOR_EARLY_EXIT]] ]
665762
; CHECK-NEXT: [[DOTRESULT_INT:%.*]] = ptrtoint ptr [[RESULT_PH]] to i64
666763
; CHECK-NEXT: br label %[[EXIT]]
667764
; CHECK: [[EXIT]]:
@@ -782,3 +879,177 @@ exit:
782879
%result.int = phi i64 [ %.result.int, %exit.loopexit ], [ %begin.int, %entry ]
783880
ret i64 %result.int
784881
}
882+
883+
; Test with an invoke terminator between the block containing the assume and loop.
884+
; This should NOT vectorize because the invoke could free memory.
885+
define i64 @find_if_deref_via_assumption_invoke_may_free_in_assume_block(ptr %vec) nofree nosync personality ptr @__gxx_personality_v0 {
886+
; CHECK-LABEL: define i64 @find_if_deref_via_assumption_invoke_may_free_in_assume_block(
887+
; CHECK-SAME: ptr [[VEC:%.*]]) #[[ATTR0]] personality ptr @__gxx_personality_v0 {
888+
; CHECK-NEXT: [[ENTRY:.*:]]
889+
; CHECK-NEXT: [[BEGIN:%.*]] = load ptr, ptr [[VEC]], align 8
890+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[BEGIN]], i64 2) ]
891+
; CHECK-NEXT: [[BEGIN_INT:%.*]] = ptrtoint ptr [[BEGIN]] to i64
892+
; CHECK-NEXT: [[END_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[VEC]], i64 8
893+
; CHECK-NEXT: [[END:%.*]] = load ptr, ptr [[END_GEP]], align 8
894+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[END]], i64 2) ]
895+
; CHECK-NEXT: [[END_INT:%.*]] = ptrtoint ptr [[END]] to i64
896+
; CHECK-NEXT: [[DISTANCE:%.*]] = sub i64 [[END_INT]], [[BEGIN_INT]]
897+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[BEGIN]], i64 [[DISTANCE]]) ]
898+
; CHECK-NEXT: [[NOT_EMPTY:%.*]] = icmp ne ptr [[BEGIN]], [[END]]
899+
; CHECK-NEXT: call void @llvm.assume(i1 [[NOT_EMPTY]])
900+
; CHECK-NEXT: invoke void @may_free()
901+
; CHECK-NEXT: to label %[[LOOP_PREHEADER:.*]] unwind label %[[LPAD:.*]]
902+
; CHECK: [[LOOP_PREHEADER]]:
903+
; CHECK-NEXT: [[END_PTR:%.*]] = getelementptr i8, ptr [[BEGIN]], i64 [[DISTANCE]]
904+
; CHECK-NEXT: br label %[[LOOP:.*]]
905+
; CHECK: [[LOOP]]:
906+
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[PTR_NEXT:%.*]], %[[LOOP_INC:.*]] ], [ [[BEGIN]], %[[LOOP_PREHEADER]] ]
907+
; CHECK-NEXT: [[VAL:%.*]] = load i16, ptr [[PTR]], align 2
908+
; CHECK-NEXT: [[FOUND:%.*]] = icmp eq i16 [[VAL]], 1
909+
; CHECK-NEXT: br i1 [[FOUND]], label %[[EXIT_LOOPEXIT:.*]], label %[[LOOP_INC]]
910+
; CHECK: [[LOOP_INC]]:
911+
; CHECK-NEXT: [[PTR_NEXT]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 2
912+
; CHECK-NEXT: [[DONE:%.*]] = icmp eq ptr [[PTR_NEXT]], [[END]]
913+
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT_LOOPEXIT]], label %[[LOOP]]
914+
; CHECK: [[LPAD]]:
915+
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
916+
; CHECK-NEXT: cleanup
917+
; CHECK-NEXT: resume { ptr, i32 } [[LP]]
918+
; CHECK: [[EXIT_LOOPEXIT]]:
919+
; CHECK-NEXT: [[RESULT_PH:%.*]] = phi ptr [ [[END_PTR]], %[[LOOP_INC]] ], [ [[PTR]], %[[LOOP]] ]
920+
; CHECK-NEXT: [[DOTRESULT_INT:%.*]] = ptrtoint ptr [[RESULT_PH]] to i64
921+
; CHECK-NEXT: br label %[[EXIT:.*]]
922+
; CHECK: [[EXIT]]:
923+
; CHECK-NEXT: [[RESULT_INT:%.*]] = phi i64 [ [[DOTRESULT_INT]], %[[EXIT_LOOPEXIT]] ]
924+
; CHECK-NEXT: ret i64 [[RESULT_INT]]
925+
;
926+
entry:
927+
%begin = load ptr, ptr %vec, align 8
928+
call void @llvm.assume(i1 true) [ "align"(ptr %begin, i64 2) ]
929+
%begin.int = ptrtoint ptr %begin to i64
930+
%end.gep = getelementptr inbounds nuw i8, ptr %vec, i64 8
931+
%end = load ptr, ptr %end.gep, align 8
932+
call void @llvm.assume(i1 true) [ "align"(ptr %end, i64 2) ]
933+
%end.int = ptrtoint ptr %end to i64
934+
%distance = sub i64 %end.int, %begin.int
935+
call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %begin, i64 %distance) ]
936+
%not.empty = icmp ne ptr %begin, %end
937+
call void @llvm.assume(i1 %not.empty)
938+
invoke void @may_free() to label %loop.preheader unwind label %lpad
939+
940+
loop.preheader:
941+
%end.ptr = getelementptr i8, ptr %begin, i64 %distance
942+
br label %loop
943+
944+
loop:
945+
%ptr = phi ptr [ %ptr.next, %loop.inc ], [ %begin, %loop.preheader ]
946+
%val = load i16, ptr %ptr, align 2
947+
%found = icmp eq i16 %val, 1
948+
br i1 %found, label %exit.loopexit, label %loop.inc
949+
950+
loop.inc:
951+
%ptr.next = getelementptr inbounds nuw i8, ptr %ptr, i64 2
952+
%done = icmp eq ptr %ptr.next, %end
953+
br i1 %done, label %exit.loopexit, label %loop
954+
955+
lpad:
956+
%lp = landingpad { ptr, i32 } cleanup
957+
resume { ptr, i32 } %lp
958+
959+
exit.loopexit:
960+
%result.ph = phi ptr [ %end.ptr, %loop.inc ], [ %ptr, %loop ]
961+
%.result.int = ptrtoint ptr %result.ph to i64
962+
br label %exit
963+
964+
exit:
965+
%result.int = phi i64 [ %.result.int, %exit.loopexit ]
966+
ret i64 %result.int
967+
}
968+
969+
; Test with an invoke terminator between the block containing the assume and loop.
970+
; This should NOT vectorize because the invoke could free memory.
971+
define i64 @find_if_deref_via_assumption_invoke_may_free_in_preheader(ptr %vec) nofree nosync personality ptr @__gxx_personality_v0 {
972+
; CHECK-LABEL: define i64 @find_if_deref_via_assumption_invoke_may_free_in_preheader(
973+
; CHECK-SAME: ptr [[VEC:%.*]]) #[[ATTR0]] personality ptr @__gxx_personality_v0 {
974+
; CHECK-NEXT: [[ENTRY:.*]]:
975+
; CHECK-NEXT: [[BEGIN:%.*]] = load ptr, ptr [[VEC]], align 8
976+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[BEGIN]], i64 2) ]
977+
; CHECK-NEXT: [[BEGIN_INT:%.*]] = ptrtoint ptr [[BEGIN]] to i64
978+
; CHECK-NEXT: [[END_GEP:%.*]] = getelementptr inbounds nuw i8, ptr [[VEC]], i64 8
979+
; CHECK-NEXT: [[END:%.*]] = load ptr, ptr [[END_GEP]], align 8
980+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[END]], i64 2) ]
981+
; CHECK-NEXT: [[END_INT:%.*]] = ptrtoint ptr [[END]] to i64
982+
; CHECK-NEXT: [[DISTANCE:%.*]] = sub i64 [[END_INT]], [[BEGIN_INT]]
983+
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[BEGIN]], i64 [[DISTANCE]]) ]
984+
; CHECK-NEXT: [[IS_EMPTY:%.*]] = icmp eq ptr [[BEGIN]], [[END]]
985+
; CHECK-NEXT: br i1 [[IS_EMPTY]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
986+
; CHECK: [[LOOP_PREHEADER]]:
987+
; CHECK-NEXT: [[END_PTR:%.*]] = getelementptr i8, ptr [[BEGIN]], i64 [[DISTANCE]]
988+
; CHECK-NEXT: invoke void @may_free()
989+
; CHECK-NEXT: to label %[[LOOP_PREHEADER1:.*]] unwind label %[[LPAD:.*]]
990+
; CHECK: [[LOOP_PREHEADER1]]:
991+
; CHECK-NEXT: br label %[[LOOP:.*]]
992+
; CHECK: [[LOOP]]:
993+
; CHECK-NEXT: [[PTR:%.*]] = phi ptr [ [[PTR_NEXT:%.*]], %[[LOOP_INC:.*]] ], [ [[BEGIN]], %[[LOOP_PREHEADER1]] ]
994+
; CHECK-NEXT: [[VAL:%.*]] = load i16, ptr [[PTR]], align 2
995+
; CHECK-NEXT: [[FOUND:%.*]] = icmp eq i16 [[VAL]], 1
996+
; CHECK-NEXT: br i1 [[FOUND]], label %[[EXIT_LOOPEXIT:.*]], label %[[LOOP_INC]]
997+
; CHECK: [[LOOP_INC]]:
998+
; CHECK-NEXT: [[PTR_NEXT]] = getelementptr inbounds nuw i8, ptr [[PTR]], i64 2
999+
; CHECK-NEXT: [[DONE:%.*]] = icmp eq ptr [[PTR_NEXT]], [[END]]
1000+
; CHECK-NEXT: br i1 [[DONE]], label %[[EXIT_LOOPEXIT]], label %[[LOOP]]
1001+
; CHECK: [[LPAD]]:
1002+
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
1003+
; CHECK-NEXT: cleanup
1004+
; CHECK-NEXT: resume { ptr, i32 } [[LP]]
1005+
; CHECK: [[EXIT_LOOPEXIT]]:
1006+
; CHECK-NEXT: [[RESULT_PH:%.*]] = phi ptr [ [[END_PTR]], %[[LOOP_INC]] ], [ [[PTR]], %[[LOOP]] ]
1007+
; CHECK-NEXT: [[DOTRESULT_INT:%.*]] = ptrtoint ptr [[RESULT_PH]] to i64
1008+
; CHECK-NEXT: br label %[[EXIT]]
1009+
; CHECK: [[EXIT]]:
1010+
; CHECK-NEXT: [[RESULT_INT:%.*]] = phi i64 [ [[DOTRESULT_INT]], %[[EXIT_LOOPEXIT]] ], [ [[BEGIN_INT]], %[[ENTRY]] ]
1011+
; CHECK-NEXT: ret i64 [[RESULT_INT]]
1012+
;
1013+
entry:
1014+
%begin = load ptr, ptr %vec, align 8
1015+
call void @llvm.assume(i1 true) [ "align"(ptr %begin, i64 2) ]
1016+
%begin.int = ptrtoint ptr %begin to i64
1017+
%end.gep = getelementptr inbounds nuw i8, ptr %vec, i64 8
1018+
%end = load ptr, ptr %end.gep, align 8
1019+
call void @llvm.assume(i1 true) [ "align"(ptr %end, i64 2) ]
1020+
%end.int = ptrtoint ptr %end to i64
1021+
%distance = sub i64 %end.int, %begin.int
1022+
call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %begin, i64 %distance) ]
1023+
%is.empty = icmp eq ptr %begin, %end
1024+
br i1 %is.empty, label %exit, label %loop.preheader
1025+
1026+
loop.preheader:
1027+
%end.ptr = getelementptr i8, ptr %begin, i64 %distance
1028+
invoke void @may_free() to label %loop unwind label %lpad
1029+
1030+
loop:
1031+
%ptr = phi ptr [ %ptr.next, %loop.inc ], [ %begin, %loop.preheader ]
1032+
%val = load i16, ptr %ptr, align 2
1033+
%found = icmp eq i16 %val, 1
1034+
br i1 %found, label %exit.loopexit, label %loop.inc
1035+
1036+
loop.inc:
1037+
%ptr.next = getelementptr inbounds nuw i8, ptr %ptr, i64 2
1038+
%done = icmp eq ptr %ptr.next, %end
1039+
br i1 %done, label %exit.loopexit, label %loop
1040+
1041+
lpad:
1042+
%lp = landingpad { ptr, i32 } cleanup
1043+
resume { ptr, i32 } %lp
1044+
1045+
exit.loopexit:
1046+
%result.ph = phi ptr [ %end.ptr, %loop.inc ], [ %ptr, %loop ]
1047+
%.result.int = ptrtoint ptr %result.ph to i64
1048+
br label %exit
1049+
1050+
exit:
1051+
%result.int = phi i64 [ %.result.int, %exit.loopexit ], [ %begin.int, %entry ]
1052+
ret i64 %result.int
1053+
}
1054+
1055+
declare i32 @__gxx_personality_v0(...)

0 commit comments

Comments
 (0)