From da8e68c8aa7f2446de1aef389eb230ac588d24bd Mon Sep 17 00:00:00 2001 From: Roman Lebedev Date: Mon, 14 Oct 2019 19:46:34 +0000 Subject: [PATCH] [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 --- lib/Transforms/Scalar/LoopIdiomRecognize.cpp | 6 ++ test/Transforms/LoopIdiom/bcmp-basic.ll | 59 ++++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/lib/Transforms/Scalar/LoopIdiomRecognize.cpp index 116bdd7470f..4f5ae5000a9 100644 --- a/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +++ b/lib/Transforms/Scalar/LoopIdiomRecognize.cpp @@ -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; diff --git a/test/Transforms/LoopIdiom/bcmp-basic.ll b/test/Transforms/LoopIdiom/bcmp-basic.ll index 1ab61da09aa..f3b18e9c756 100644 --- a/test/Transforms/LoopIdiom/bcmp-basic.ll +++ b/test/Transforms/LoopIdiom/bcmp-basic.ll @@ -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 +}