Index: llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp =================================================================== --- llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +++ llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp @@ -1619,10 +1619,12 @@ BasicBlock *LoopBody = *(CurLoop->block_begin()); auto *LoopTerm = dyn_cast(LoopBody->getTerminator()); auto *LoopCond = matchCondition(LoopTerm, LoopBody); + if (!LoopCond) return false; auto *LoopLoad = dyn_cast(LoopCond); - if (!LoopLoad || LoopLoad->getPointerAddressSpace() != 0) + if (!LoopLoad || !LoopLoad->getType()->isIntegerTy(8) || + LoopLoad->getPointerAddressSpace() != 0) return false; // See if the pointer expression is an AddRec with step 1 ({n,+,1}) on @@ -1648,14 +1650,18 @@ PHINode *LCSSAPhi = dyn_cast(LoopExitBB->begin()); if (!LCSSAPhi || LCSSAPhi->getNumIncomingValues() != 1) return false; - const SCEVAddRecExpr *LCSSAEv = dyn_cast( - SE->getSCEV(LCSSAPhi->getIncomingValue(0))); + const SCEVAddRecExpr *LCSSAEv = + dyn_cast(SE->getSCEV(LCSSAPhi->getIncomingValue(0))); if (!LCSSAEv || !LCSSAEv->isAffine()) return false; auto *CleanupBB = - (PreCondBI->getSuccessor(0) == PH ? PreCondBI->getSuccessor(1) - : PreCondBI->getSuccessor(0)); + (PreCondBI->getSuccessor(0) == PH ? PreCondBI->getSuccessor(1) + : PreCondBI->getSuccessor(0)); + + // Finally, we find the phi node that corresponds to the distance between the + // pointers and replace it's uses by the call to strlen in the transformed + // code. Value *ResInst = nullptr; for (auto &Phi : CleanupBB->phis()) { if (Phi.getBasicBlockIndex(LoopExitBB) != 1) { @@ -1672,9 +1678,9 @@ IRBuilder<> Builder(PH->getTerminator()); Value *Expanded = Expander.expandCodeFor( - LCSSAEv->getStart(), - Builder.getInt8PtrTy(LoopLoad->getPointerAddressSpace()), - PH->getTerminator()); + LCSSAEv->getStart(), + Builder.getInt8PtrTy(LoopLoad->getPointerAddressSpace()), + PH->getTerminator()); EVC.add(Expanded); EVC.commit(); @@ -1682,7 +1688,7 @@ Value *Strlen = Builder.CreateZExtOrTrunc(LibCall, ResInst->getType()); ResInst->replaceAllUsesWith(Strlen); - // Remove the loop-exit branch and delete death instructions + // Remove the loop-exit branch and delete dead instructions RecursivelyDeleteTriviallyDeadInstructions(ResInst, TLI); ConstantInt *NewLoopCond = LoopTerm->getSuccessor(0) == LoopBody ? Builder.getFalse() Index: llvm/test/Transforms/LoopIdiom/recognize-strlen.ll =================================================================== --- llvm/test/Transforms/LoopIdiom/recognize-strlen.ll +++ llvm/test/Transforms/LoopIdiom/recognize-strlen.ll @@ -1,8 +1,31 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -loop-idiom < %s -S | FileCheck %s target datalayout = "e-m:e-i64:64-n32:64" target triple = "powerpc64le-unknown-linux-gnu" define i64 @valid_strlen1(i8* %Str) { +; CHECK-LABEL: @valid_strlen1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[STR:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL]], label [[CLEANUP:%.*]], label [[LOR_LHS_FALSE:%.*]] +; CHECK: lor.lhs.false: +; CHECK-NEXT: [[TMP0:%.*]] = load i8, i8* [[STR]], align 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP0]], 0 +; CHECK-NEXT: br i1 [[CMP]], label [[CLEANUP]], label [[FOR_INC_PREHEADER:%.*]] +; CHECK: for.inc.preheader: +; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, i8* [[STR]], i64 1 +; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(i8* [[SCEVGEP]]) +; CHECK-NEXT: br label [[FOR_INC:%.*]] +; CHECK: for.inc: +; CHECK-NEXT: [[SRC_09:%.*]] = phi i8* [ undef, [[FOR_INC]] ], [ [[STR]], [[FOR_INC_PREHEADER]] ] +; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp eq i8 undef, 0 +; CHECK-NEXT: br i1 true, label [[FOR_END:%.*]], label [[FOR_INC]] +; CHECK: for.end: +; CHECK-NEXT: br label [[CLEANUP]] +; CHECK: cleanup: +; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i64 [ [[STRLEN]], [[FOR_END]] ], [ 0, [[ENTRY:%.*]] ], [ 0, [[LOR_LHS_FALSE]] ] +; CHECK-NEXT: ret i64 [[RETVAL_0]] +; entry: %tobool = icmp eq i8* %Str, null br i1 %tobool, label %cleanup, label %lor.lhs.false @@ -12,8 +35,6 @@ %cmp = icmp eq i8 %0, 0 br i1 %cmp, label %cleanup, label %for.inc -; CHECK: call i64 @strlen(i8* %Str) -; CHECK: br i1 true for.inc: ; preds = %lor.lhs.false, %for.inc %Src.09 = phi i8* [ %incdec.ptr, %for.inc ], [ %Str, %lor.lhs.false ] %incdec.ptr = getelementptr inbounds i8, i8* %Src.09, i64 1 @@ -21,7 +42,6 @@ %tobool2 = icmp eq i8 %.pr, 0 br i1 %tobool2, label %for.end, label %for.inc -; CHECK-NOT: sub for.end: ; preds = %for.inc %sub.ptr.lhs.cast = ptrtoint i8* %incdec.ptr to i64 %sub.ptr.rhs.cast = ptrtoint i8* %Str to i64 @@ -35,12 +55,27 @@ define i64 @valid_strlen2(i8* %Str) { +; CHECK-LABEL: @valid_strlen2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i8* [[STR:%.*]], null +; CHECK-NEXT: br i1 [[TOBOOL]], label [[CLEANUP:%.*]], label [[FOR_COND_PREHEADER:%.*]] +; CHECK: for.cond.preheader: +; CHECK-NEXT: [[STRLEN:%.*]] = call i64 @strlen(i8* [[STR]]) +; CHECK-NEXT: br label [[FOR_COND:%.*]] +; CHECK: for.cond: +; CHECK-NEXT: [[TOBOOL1:%.*]] = icmp eq i8 undef, 0 +; CHECK-NEXT: [[INCDEC_PTR:%.*]] = getelementptr inbounds i8, i8* undef, i64 1 +; CHECK-NEXT: br i1 true, label [[FOR_END:%.*]], label [[FOR_COND]] +; CHECK: for.end: +; CHECK-NEXT: br label [[CLEANUP]] +; CHECK: cleanup: +; CHECK-NEXT: [[RETVAL_0:%.*]] = phi i64 [ [[STRLEN]], [[FOR_END]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i64 [[RETVAL_0]] +; entry: %tobool = icmp eq i8* %Str, null br i1 %tobool, label %cleanup, label %for.cond -; CHECK: call i64 @strlen(i8* %Str) -; CHECK: br i1 true for.cond: ; preds = %entry, %for.cond %Src.0 = phi i8* [ %incdec.ptr, %for.cond ], [ %Str, %entry ] %0 = load i8, i8* %Src.0, align 1 @@ -48,48 +83,13 @@ %incdec.ptr = getelementptr inbounds i8, i8* %Src.0, i64 1 br i1 %tobool1, label %for.end, label %for.cond -; CHECK-NOT: sub for.end: ; preds = %for.cond %sub.ptr.lhs.cast = ptrtoint i8* %Src.0 to i64 %sub.ptr.rhs.cast = ptrtoint i8* %Str to i64 %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast br label %cleanup - cleanup: ; preds = %entry, %for.end + cleanup: ; preds = %entry, %for.end %retval.0 = phi i64 [ %sub.ptr.sub, %for.end ], [ 0, %entry ] ret i64 %retval.0 } - - -define zeroext i32 @valid_strlen3(i8* %Str) { -entry: - %tobool = icmp eq i8* %Str, null - br i1 %tobool, label %cleanup, label %lor.lhs.false - -lor.lhs.false: ; preds = %entry - %0 = load i8, i8* %Str, align 1 - %cmp = icmp eq i8 %0, 0 - br i1 %cmp, label %cleanup, label %for.inc - -; CHECK: call i64 @strlen(i8* %Str) -; CHECK: br i1 true -for.inc: ; preds = %lor.lhs.false, %for.inc - %Src.010 = phi i8* [ %incdec.ptr, %for.inc ], [ %Str, %lor.lhs.false ] - %incdec.ptr = getelementptr inbounds i8, i8* %Src.010, i64 1 - %.pr = load i8, i8* %incdec.ptr, align 1 - %tobool2 = icmp eq i8 %.pr, 0 - br i1 %tobool2, label %for.end, label %for.inc - -; CHECK: trunc i64 %strlen to i32 -; CHECK-NOT: sub -for.end: ; preds = %for.inc - %sub.ptr.lhs.cast = ptrtoint i8* %incdec.ptr to i64 - %sub.ptr.rhs.cast = ptrtoint i8* %Str to i64 - %sub.ptr.sub = sub i64 %sub.ptr.lhs.cast, %sub.ptr.rhs.cast - %conv3 = trunc i64 %sub.ptr.sub to i32 - br label %cleanup - -cleanup: ; preds = %lor.lhs.false, %entry, %for.end - %retval.0 = phi i32 [ %conv3, %for.end ], [ 0, %entry ], [ 0, %lor.lhs.false ] - ret i32 %retval.0 -}