diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -124,10 +124,6 @@ const DominatorTree *DT = nullptr, bool UseInstrInfo = true); -/// Return true if the given instruction is only used in zero comparison -bool isOnlyUsedInZeroComparison(const Instruction *CxtI); - -/// Return true if the given instruction is only used in zero equality comparison bool isOnlyUsedInZeroEqualityComparison(const Instruction *CxtI); /// Return true if the given value is known to be non-zero when defined. For diff --git a/llvm/include/llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h b/llvm/include/llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h --- a/llvm/include/llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h +++ b/llvm/include/llvm/Transforms/AggressiveInstCombine/AggressiveInstCombine.h @@ -8,7 +8,7 @@ /// \file /// /// AggressiveInstCombiner - Combine expression patterns to form expressions -/// with fewer, simple instructions. +/// with fewer, simple instructions. This pass does not modify the CFG. /// //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -261,13 +261,6 @@ return KnownBits::haveNoCommonBitsSet(LHSKnown, RHSKnown); } -bool llvm::isOnlyUsedInZeroComparison(const Instruction *I) { - return !I->user_empty() && all_of(I->users(), [](const User *U) { - ICmpInst::Predicate P; - return match(U, m_ICmp(P, m_Value(), m_Zero())); - }); -} - bool llvm::isOnlyUsedInZeroEqualityComparison(const Instruction *I) { return !I->user_empty() && all_of(I->users(), [](const User *U) { ICmpInst::Predicate P; diff --git a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp --- a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp +++ b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp @@ -19,7 +19,6 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/ConstantFolding.h" -#include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" @@ -29,7 +28,6 @@ #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/PatternMatch.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/BuildLibCalls.h" #include "llvm/Transforms/Utils/Local.h" @@ -398,6 +396,54 @@ return true; } +/// Try to replace a mathlib call to sqrt with the LLVM intrinsic. This avoids +/// pessimistic codegen that has to account for setting errno and can enable +/// vectorization. +static bool foldSqrt(Instruction &I, TargetTransformInfo &TTI, + TargetLibraryInfo &TLI, AssumptionCache &AC, + DominatorTree &DT) { + // Match a call to sqrt mathlib function. + auto *Call = dyn_cast(&I); + if (!Call) + return false; + + Module *M = Call->getModule(); + LibFunc Func; + if (!TLI.getLibFunc(*Call, Func) || !isLibFuncEmittable(M, &TLI, Func)) + return false; + + if (Func != LibFunc_sqrt && Func != LibFunc_sqrtf && Func != LibFunc_sqrtl) + return false; + + // If (1) this is a sqrt libcall, (2) we can assume that NAN is not created + // (because NNAN or the operand arg must not be less than -0.0) and (2) we + // would not end up lowering to a libcall anyway (which could change the value + // of errno), then: + // (1) errno won't be set. + // (2) it is safe to convert this to an intrinsic call. + Type *Ty = Call->getType(); + Value *Arg = Call->getArgOperand(0); + if (TTI.haveFastSqrt(Ty) && + (Call->hasNoNaNs() || + cannotBeOrderedLessThanZero(Arg, M->getDataLayout(), &TLI, 0, &AC, &I, + &DT))) { + IRBuilder<> Builder(&I); + IRBuilderBase::FastMathFlagGuard Guard(Builder); + Builder.setFastMathFlags(Call->getFastMathFlags()); + + Function *Sqrt = Intrinsic::getDeclaration(M, Intrinsic::sqrt, Ty); + Value *NewSqrt = Builder.CreateCall(Sqrt, Arg, "sqrt"); + I.replaceAllUsesWith(NewSqrt); + + // Explicitly erase the old call because a call with side effects is not + // trivially dead. + I.eraseFromParent(); + return true; + } + + return false; +} + // Check if this array of constants represents a cttz table. // Iterate over the elements from \p Table by trying to find/match all // the numbers from 0 to \p InputBits that should represent cttz results. @@ -869,199 +915,13 @@ return true; } -/// Try to replace a mathlib call to sqrt with the LLVM intrinsic. This avoids -/// pessimistic codegen that has to account for setting errno and can enable -/// vectorization. -static bool foldSqrt(CallInst *Call, TargetTransformInfo &TTI, - TargetLibraryInfo &TLI, AssumptionCache &AC, - DominatorTree &DT) { - Module *M = Call->getModule(); - - // If (1) this is a sqrt libcall, (2) we can assume that NAN is not created - // (because NNAN or the operand arg must not be less than -0.0) and (2) we - // would not end up lowering to a libcall anyway (which could change the value - // of errno), then: - // (1) errno won't be set. - // (2) it is safe to convert this to an intrinsic call. - Type *Ty = Call->getType(); - Value *Arg = Call->getArgOperand(0); - if (TTI.haveFastSqrt(Ty) && - (Call->hasNoNaNs() || - cannotBeOrderedLessThanZero(Arg, M->getDataLayout(), &TLI, 0, &AC, Call, - &DT))) { - IRBuilder<> Builder(Call); - IRBuilderBase::FastMathFlagGuard Guard(Builder); - Builder.setFastMathFlags(Call->getFastMathFlags()); - - Function *Sqrt = Intrinsic::getDeclaration(M, Intrinsic::sqrt, Ty); - Value *NewSqrt = Builder.CreateCall(Sqrt, Arg, "sqrt"); - Call->replaceAllUsesWith(NewSqrt); - - // Explicitly erase the old call because a call with side effects is not - // trivially dead. - Call->eraseFromParent(); - return true; - } - - return false; -} - -/// Try to expand strcmp(P, string_literal) where string_literal size is 1 or 2 -static bool expandStrcmp(CallInst *CI, DominatorTree &DT, bool &MadeCFGChange) { - Value *Str1P = CI->getArgOperand(0), *Str2P = CI->getArgOperand(1); - - // Trivial cases are optimized during inst combine - if (Str1P == Str2P) - return false; - - StringRef Str1, Str2; - bool HasStr1 = getConstantStringInfo(Str1P, Str1); - bool HasStr2 = getConstantStringInfo(Str2P, Str2); - - Value *NonConstantP = nullptr; - StringRef ConstantStr; - - if (!HasStr1 && HasStr2) { - NonConstantP = Str1P; - ConstantStr = Str2; - } else if (!HasStr2 && HasStr1) { - NonConstantP = Str2P; - ConstantStr = Str1; - } else { - return false; - } - - size_t ConstantStrSize = ConstantStr.size(); - - // Trivial cases are optimized during inst combine - if (ConstantStrSize == 0 || ConstantStrSize > 2) - return false; - - // Check if strcmp result is only used in a comparison with zero - if (!isOnlyUsedInZeroComparison(CI)) - return false; - - // For strcmp(P, "x") do the following transformation: - // - // (before) - // dst = strcmp(P, "x") - // - // (after) - // v0 = P[0] - 'x' - // [if v0 == 0] - // v1 = P[1] - // dst = phi(v0, v1) - // - // For strcmp(P, "xy") do the following transformation: - // - // (before) - // dst = strcmp(P, "xy") - // - // (after) - // v0 = P[0] - 'x' - // [if v0 == 0] - // v1 = P[1] - 'y' - // [if v1 == 0] - // v2 = P[2] - // dst = phi(v0, v1, v2) - // - - IRBuilder<> B(CI->getParent()); - DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy); - - Type *RetType = CI->getType(); - - BasicBlock *InitialBB = CI->getParent(); - BasicBlock *JoinBlock = SplitBlock(InitialBB, CI, &DTU); - JoinBlock->setName("strcmp_expand_sub_join"); - - B.SetInsertPoint(CI); - PHINode *ResultPHI = B.CreatePHI(RetType, ConstantStrSize + 1); - - B.SetInsertPoint(InitialBB); - InitialBB->getTerminator()->eraseFromParent(); - - SmallVector DTUpdates; - - size_t CharacterIndexToCheck = 0; - for (; CharacterIndexToCheck < ConstantStrSize; ++CharacterIndexToCheck) { - Value *StrCharacterValue = B.CreateZExt( - B.CreateLoad(B.getInt8Ty(), - B.CreateConstInBoundsGEP1_64(B.getInt8Ty(), NonConstantP, - CharacterIndexToCheck)), - RetType); - Value *ConstantStrCharacterValue = ConstantInt::get( - RetType, - static_cast(ConstantStr[CharacterIndexToCheck])); - Value *CharacterSub = - B.CreateNSWSub(StrCharacterValue, ConstantStrCharacterValue); - Value *CharacterSubIsZero = - B.CreateICmpEQ(CharacterSub, ConstantInt::get(RetType, 0)); - BasicBlock *CharacterSubIsZeroBB = - BasicBlock::Create(B.getContext(), "strcmp_expand_sub_is_zero", - InitialBB->getParent(), JoinBlock); - B.CreateCondBr(CharacterSubIsZero, CharacterSubIsZeroBB, JoinBlock); - - ResultPHI->addIncoming(CharacterSub, B.GetInsertBlock()); - DTUpdates.emplace_back(DominatorTree::Insert, B.GetInsertBlock(), - CharacterSubIsZeroBB); - - B.SetInsertPoint(CharacterSubIsZeroBB); - DTUpdates.emplace_back(DominatorTree::Insert, CharacterSubIsZeroBB, - JoinBlock); - } - - Value *StrLastCharacterValue = B.CreateZExt( - B.CreateLoad(B.getInt8Ty(), - B.CreateConstInBoundsGEP1_64(B.getInt8Ty(), NonConstantP, - CharacterIndexToCheck)), - RetType); - ResultPHI->addIncoming(StrLastCharacterValue, B.GetInsertBlock()); - B.CreateBr(JoinBlock); - - DTU.applyUpdates(DTUpdates); - - CI->replaceAllUsesWith(ResultPHI); - CI->eraseFromParent(); - - MadeCFGChange = true; - - return true; -} - -static bool foldLibraryCalls(Instruction &I, TargetTransformInfo &TTI, - TargetLibraryInfo &TLI, DominatorTree &DT, - AssumptionCache &AC, bool &MadeCFGChange) { - CallInst *CI = dyn_cast(&I); - if (!CI) - return false; - - LibFunc Func; - Module *M = I.getModule(); - if (!TLI.getLibFunc(*CI, Func) || !isLibFuncEmittable(M, &TLI, Func)) - return false; - - switch (Func) { - case LibFunc_sqrt: - case LibFunc_sqrtf: - case LibFunc_sqrtl: - return foldSqrt(CI, TTI, TLI, AC, DT); - case LibFunc_strcmp: - return expandStrcmp(CI, DT, MadeCFGChange); - default: - break; - } - - return false; -} - /// This is the entry point for folds that could be implemented in regular /// InstCombine, but they are separated because they are not expected to /// occur frequently and/or have more than a constant-length pattern match. static bool foldUnusualPatterns(Function &F, DominatorTree &DT, TargetTransformInfo &TTI, TargetLibraryInfo &TLI, AliasAnalysis &AA, - AssumptionCache &AC, bool &MadeCFGChange) { + AssumptionCache &AC) { bool MadeChange = false; for (BasicBlock &BB : F) { // Ignore unreachable basic blocks. @@ -1086,7 +946,7 @@ // NOTE: This function introduces erasing of the instruction `I`, so it // needs to be called at the end of this sequence, otherwise we may make // bugs. - MadeChange |= foldLibraryCalls(I, TTI, TLI, DT, AC, MadeCFGChange); + MadeChange |= foldSqrt(I, TTI, TLI, AC, DT); } } @@ -1102,12 +962,12 @@ /// handled in the callers of this function. static bool runImpl(Function &F, AssumptionCache &AC, TargetTransformInfo &TTI, TargetLibraryInfo &TLI, DominatorTree &DT, - AliasAnalysis &AA, bool &ChangedCFG) { + AliasAnalysis &AA) { bool MadeChange = false; const DataLayout &DL = F.getParent()->getDataLayout(); TruncInstCombine TIC(AC, TLI, DL, DT); MadeChange |= TIC.run(F); - MadeChange |= foldUnusualPatterns(F, DT, TTI, TLI, AA, AC, ChangedCFG); + MadeChange |= foldUnusualPatterns(F, DT, TTI, TLI, AA, AC); return MadeChange; } @@ -1118,21 +978,12 @@ auto &DT = AM.getResult(F); auto &TTI = AM.getResult(F); auto &AA = AM.getResult(F); - - bool MadeCFGChange = false; - - if (!runImpl(F, AC, TTI, TLI, DT, AA, MadeCFGChange)) { + if (!runImpl(F, AC, TTI, TLI, DT, AA)) { // No changes, all analyses are preserved. return PreservedAnalyses::all(); } - // Mark all the analyses that instcombine updates as preserved. PreservedAnalyses PA; - - if (MadeCFGChange) - PA.preserve(); - else - PA.preserveSet(); - + PA.preserveSet(); return PA; } diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -227,9 +227,21 @@ return ConstantInt::get(RetTy, Result); } +static bool isOnlyUsedInComparisonWithZero(Value *V) { + for (User *U : V->users()) { + if (ICmpInst *IC = dyn_cast(U)) + if (Constant *C = dyn_cast(IC->getOperand(1))) + if (C->isNullValue()) + continue; + // Unknown instruction. + return false; + } + return true; +} + static bool canTransformToMemCmp(CallInst *CI, Value *Str, uint64_t Len, const DataLayout &DL) { - if (!isOnlyUsedInZeroComparison(CI)) + if (!isOnlyUsedInComparisonWithZero(CI)) return false; if (!isDereferenceableAndAlignedPointer(Str, Align(1), APInt(64, Len), DL)) diff --git a/llvm/test/Transforms/AggressiveInstCombine/strcmp.ll b/llvm/test/Transforms/AggressiveInstCombine/strcmp.ll --- a/llvm/test/Transforms/AggressiveInstCombine/strcmp.ll +++ b/llvm/test/Transforms/AggressiveInstCombine/strcmp.ll @@ -24,19 +24,8 @@ define i1 @expand_strcmp_eq_s1(ptr %C) { ; CHECK-LABEL: @expand_strcmp_eq_s1( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP7]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s1) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s1) @@ -46,19 +35,8 @@ define i1 @expand_strcmp_eq_s1_commuted(ptr %C) { ; CHECK-LABEL: @expand_strcmp_eq_s1_commuted( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP7]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP8]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr @s1, ptr [[C:%.*]]) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr @s1, ptr %C) @@ -68,19 +46,8 @@ define i1 @expand_strcmp_ne_s1(ptr %C) { ; CHECK-LABEL: @expand_strcmp_ne_s1( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP7]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP8]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s1) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s1) @@ -90,19 +57,8 @@ define i1 @expand_strcmp_sgt_s1(ptr %C) { ; CHECK-LABEL: @expand_strcmp_sgt_s1( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP7]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP8]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s1) +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s1) @@ -112,19 +68,8 @@ define i1 @expand_strcmp_sge_s1(ptr %C) { ; CHECK-LABEL: @expand_strcmp_sge_s1( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP7]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[TMP8]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s1) +; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s1) @@ -134,19 +79,8 @@ define i1 @expand_strcmp_slt_s1(ptr %C) { ; CHECK-LABEL: @expand_strcmp_slt_s1( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP7]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP8]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s1) +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s1) @@ -156,19 +90,8 @@ define i1 @expand_strcmp_sle_s1(ptr %C) { ; CHECK-LABEL: @expand_strcmp_sle_s1( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP8:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP7]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[TMP8]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s1) +; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s1) @@ -209,26 +132,8 @@ define i1 @expand_strcmp_eq_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_eq_s2( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 -; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 -; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_is_zero1: -; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 -; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 -; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP13]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -238,26 +143,8 @@ define i1 @expand_strcmp_ne_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_ne_s2( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 -; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 -; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_is_zero1: -; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 -; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 -; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP13]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -267,26 +154,8 @@ define i1 @expand_strcmp_sgt_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_sgt_s2( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 -; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 -; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_is_zero1: -; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 -; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 -; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP13]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -296,26 +165,8 @@ define i1 @expand_strcmp_sge_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_sge_s2( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 -; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 -; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_is_zero1: -; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 -; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 -; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[TMP13]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) +; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -325,26 +176,8 @@ define i1 @expand_strcmp_slt_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_slt_s2( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 -; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 -; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_is_zero1: -; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 -; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 -; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[TMP13]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2) @@ -354,26 +187,8 @@ define i1 @expand_strcmp_sle_s2(ptr %C) { ; CHECK-LABEL: @expand_strcmp_sle_s2( -; CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[C:%.*]], align 1 -; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i32 -; CHECK-NEXT: [[TMP3:%.*]] = sub nsw i32 [[TMP2]], 48 -; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i32 [[TMP3]], 0 -; CHECK-NEXT: br i1 [[TMP4]], label [[STRCMP_EXPAND_SUB_IS_ZERO:%.*]], label [[STRCMP_EXPAND_SUB_JOIN:%.*]] -; CHECK: strcmp_expand_sub_is_zero: -; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 1 -; CHECK-NEXT: [[TMP6:%.*]] = load i8, ptr [[TMP5]], align 1 -; CHECK-NEXT: [[TMP7:%.*]] = zext i8 [[TMP6]] to i32 -; CHECK-NEXT: [[TMP8:%.*]] = sub nsw i32 [[TMP7]], 49 -; CHECK-NEXT: [[TMP9:%.*]] = icmp eq i32 [[TMP8]], 0 -; CHECK-NEXT: br i1 [[TMP9]], label [[STRCMP_EXPAND_SUB_IS_ZERO1:%.*]], label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_is_zero1: -; CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 2 -; CHECK-NEXT: [[TMP11:%.*]] = load i8, ptr [[TMP10]], align 1 -; CHECK-NEXT: [[TMP12:%.*]] = zext i8 [[TMP11]] to i32 -; CHECK-NEXT: br label [[STRCMP_EXPAND_SUB_JOIN]] -; CHECK: strcmp_expand_sub_join: -; CHECK-NEXT: [[TMP13:%.*]] = phi i32 [ [[TMP3]], [[TMP0:%.*]] ], [ [[TMP8]], [[STRCMP_EXPAND_SUB_IS_ZERO]] ], [ [[TMP12]], [[STRCMP_EXPAND_SUB_IS_ZERO1]] ] -; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[TMP13]], 0 +; CHECK-NEXT: [[CALL:%.*]] = call i32 @strcmp(ptr [[C:%.*]], ptr @s2) +; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[CALL]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %call = call i32 @strcmp(ptr %C, ptr @s2)