[LoopIdiom] BCmp: loop exit count must not be wider than size_t that bcmp takes

As reported by Joerg Sonnenberger in IRC, for 32-bit systems,
where pointer and size_t are 32-bit, if you use 64-bit-wide variable
in the loop, you could end up with loop exit count being of the type
wider than the size_t. Now, i'm not sure if we can produce `bcmp`
from that (just truncate?), but we certainly should not assert/miscompile.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@374811 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Roman Lebedev 2019-10-14 19:46:34 +00:00
parent 04e2fd09d5
commit da8e68c8aa
2 changed files with 65 additions and 0 deletions

View File

@ -2080,6 +2080,10 @@ bool LoopIdiomRecognize::recognizeBCmpLoopSCEV(uint64_t BCmpTyBytes,
LLVM_DEBUG(dbgs() << "SCEV expressions for loads are acceptable.\n");
// bcmp / memcmp take length argument as size_t, so let's conservatively
// assume that the iteration count should be not wider than that.
Type *CmpFuncSizeTy = DL->getIntPtrType(SE->getContext());
// For how many iterations is loop guaranteed not to exit via LoopLatch?
// This is one less than the maximal number of comparisons,and is: n + -1
const SCEV *LoopExitCount =
@ -2089,6 +2093,8 @@ bool LoopIdiomRecognize::recognizeBCmpLoopSCEV(uint64_t BCmpTyBytes,
// Exit count, similarly, must be loop-invant that dominates the loop header.
if (LoopExitCount == SE->getCouldNotCompute() ||
!LoopExitCount->getType()->isIntOrPtrTy() ||
LoopExitCount->getType()->getScalarSizeInBits() >
CmpFuncSizeTy->getScalarSizeInBits() ||
!SE->isAvailableAtLoopEntry(LoopExitCount, CurLoop)) {
LLVM_DEBUG(dbgs() << "Unsupported SCEV expression for loop latch exit.\n");
return false;

View File

@ -1758,3 +1758,62 @@ cleanup:
%res = phi i1 [ false, %for.body ], [ true, %for.cond ], [ false, %entry ]
ret i1 %res
}
; With -m32:
; int index_wider_than_pointer(int* a, int* b, long long num) {
; for(long long i = 0; i < num; ++i) {
; if(a[i] != b[i])
; return 1;
; }
; return 0;
; }
define dso_local i64 @test(i64* %a, i64* %b, i128 %num) {
; CHECK-LABEL: @test(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[CMP9:%.*]] = icmp sgt i128 [[NUM:%.*]], 0
; CHECK-NEXT: br i1 [[CMP9]], label [[FOR_BODY_PREHEADER:%.*]], label [[CLEANUP:%.*]]
; CHECK: for.body.preheader:
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.cond:
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i128 [[INC:%.*]], [[NUM]]
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[CLEANUP_LOOPEXIT:%.*]]
; CHECK: for.body:
; CHECK-NEXT: [[I_010:%.*]] = phi i128 [ [[INC]], [[FOR_COND:%.*]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
; CHECK-NEXT: [[IDXPROM:%.*]] = trunc i128 [[I_010]] to i64
; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i64, i64* [[A:%.*]], i64 [[IDXPROM]]
; CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* [[ARRAYIDX]]
; CHECK-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds i64, i64* [[B:%.*]], i64 [[IDXPROM]]
; CHECK-NEXT: [[TMP1:%.*]] = load i64, i64* [[ARRAYIDX2]]
; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i64 [[TMP0]], [[TMP1]]
; CHECK-NEXT: [[INC]] = add nuw nsw i128 [[I_010]], 1
; CHECK-NEXT: br i1 [[CMP3]], label [[FOR_COND]], label [[CLEANUP_LOOPEXIT]]
; CHECK: cleanup.loopexit:
; CHECK-NEXT: [[DOTPH:%.*]] = phi i64 [ 1, [[FOR_BODY]] ], [ 0, [[FOR_COND]] ]
; CHECK-NEXT: br label [[CLEANUP]]
; CHECK: cleanup:
; CHECK-NEXT: [[TMP2:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[DOTPH]], [[CLEANUP_LOOPEXIT]] ]
; CHECK-NEXT: ret i64 [[TMP2]]
;
entry:
%cmp9 = icmp sgt i128 %num, 0
br i1 %cmp9, label %for.body, label %cleanup
for.cond: ; preds = %for.body
%cmp = icmp slt i128 %inc, %num
br i1 %cmp, label %for.body, label %cleanup
for.body: ; preds = %entry, %for.cond
%i.010 = phi i128 [ %inc, %for.cond ], [ 0, %entry ]
%idxprom = trunc i128 %i.010 to i64
%arrayidx = getelementptr inbounds i64, i64* %a, i64 %idxprom
%0 = load i64, i64* %arrayidx
%arrayidx2 = getelementptr inbounds i64, i64* %b, i64 %idxprom
%1 = load i64, i64* %arrayidx2
%cmp3 = icmp eq i64 %0, %1
%inc = add nuw nsw i128 %i.010, 1
br i1 %cmp3, label %for.cond, label %cleanup
cleanup: ; preds = %for.body, %for.cond, %entry
%2 = phi i64 [ 0, %entry ], [ 0, %for.cond ], [ 1, %for.body ]
ret i64 %2
}