https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/106542
>From bb76990f184c59abfcaa7c5f9409ec8d9b309636 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov <baranniko...@gmail.com> Date: Wed, 28 Aug 2024 16:09:44 +0300 Subject: [PATCH] [SimplifyLibCalls] Add initial support for non-8-bit bytes The patch makes CharWidth argument of `getStringLength` mandatory and ensures the correct values are passed in most cases. This is *not* a complete support for unusual byte widths in SimplifyLibCalls since `getConstantStringInfo` returns false for those. The code guarded by `getConstantStringInfo` returning true is unchanged because the changes are currently not testable. --- llvm/include/llvm/Analysis/ValueTracking.h | 4 +- .../llvm/Transforms/Utils/SimplifyLibCalls.h | 4 +- llvm/lib/Analysis/MemoryBuiltins.cpp | 3 +- llvm/lib/Analysis/ValueTracking.cpp | 40 ++-- .../InstCombine/InstCombineCalls.cpp | 12 +- .../InstCombine/InstructionCombining.cpp | 5 +- .../lib/Transforms/Utils/SimplifyLibCalls.cpp | 191 ++++++++++++------ .../InstCombine/SimplifyLibCalls/fputs-b16.ll | 19 ++ .../SimplifyLibCalls/fwrite-b16.ll | 19 ++ .../SimplifyLibCalls/memchr-b16.ll | 34 ++++ .../SimplifyLibCalls/memcmp-b32.ll | 32 +++ .../SimplifyLibCalls/memcpy-b16.ll | 69 +++++++ .../SimplifyLibCalls/memcpy_chk-b16.ll | 17 ++ .../SimplifyLibCalls/mempcpy-b16.ll | 17 ++ .../SimplifyLibCalls/memrchr-b16.ll | 20 ++ .../SimplifyLibCalls/memset-b16.ll | 66 ++++++ .../SimplifyLibCalls/stpcpy-b16.ll | 31 +++ .../SimplifyLibCalls/stpcpy_chk-b16.ll | 44 ++++ .../SimplifyLibCalls/stpncpy-b16.ll | 47 +++++ .../SimplifyLibCalls/strcat-b16.ll | 20 ++ .../SimplifyLibCalls/strchr-b16.ll | 45 +++++ .../SimplifyLibCalls/strcmp-b32.ll | 50 +++++ .../SimplifyLibCalls/strcpy-b16.ll | 18 ++ .../SimplifyLibCalls/strcpy_chk-b16.ll | 30 +++ .../SimplifyLibCalls/strlcpy-b16.ll | 18 ++ .../SimplifyLibCalls/strlen-b16.ll | 16 ++ .../SimplifyLibCalls/strncat-b16.ll | 20 ++ .../SimplifyLibCalls/strncmp-b32.ll | 34 ++++ .../SimplifyLibCalls/strncpy-b16.ll | 43 ++++ .../SimplifyLibCalls/strndup-b16.ll | 17 ++ .../SimplifyLibCalls/strnlen-b16.ll | 18 ++ .../SimplifyLibCalls/wcslen-b16.ll | 19 ++ llvm/test/Transforms/InstCombine/bcmp-1.ll | 2 +- llvm/test/Transforms/InstCombine/memcmp-1.ll | 2 +- llvm/test/Transforms/InstCombine/strncmp-1.ll | 2 +- 35 files changed, 928 insertions(+), 100 deletions(-) create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/fputs-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/fwrite-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/memchr-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcmp-b32.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcpy-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcpy_chk-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/mempcpy-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/memrchr-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/memset-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpcpy-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpcpy_chk-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpncpy-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcat-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strchr-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcmp-b32.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcpy-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcpy_chk-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strlcpy-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strlen-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncat-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncmp-b32.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncpy-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strndup-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/strnlen-b16.ll create mode 100644 llvm/test/Transforms/InstCombine/SimplifyLibCalls/wcslen-b16.ll diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h index 51d0712a243fb..be6f8f7f305f8 100644 --- a/llvm/include/llvm/Analysis/ValueTracking.h +++ b/llvm/include/llvm/Analysis/ValueTracking.h @@ -404,7 +404,7 @@ struct ConstantDataArraySlice { /// If successful \p Slice will point to a ConstantDataArray info object /// with an appropriate offset. bool getConstantDataArrayInfo(const Value *V, ConstantDataArraySlice &Slice, - unsigned ElementSize, uint64_t Offset = 0); + unsigned ElementBitWidth, uint64_t Offset = 0); /// This function computes the length of a null-terminated C string pointed to /// by V. If successful, it returns true and returns the string in Str. If @@ -417,7 +417,7 @@ bool getConstantStringInfo(const Value *V, StringRef &Str, unsigned CharWidth, /// If we can compute the length of the string pointed to by the specified /// pointer, return 'len+1'. If we can't, return 0. -uint64_t GetStringLength(const Value *V, unsigned CharSize = 8); +uint64_t getStringLength(const Value *V, unsigned CharWidth); /// This function returns call pointer argument that is considered the same by /// aliasing rules. You CAN'T use it to replace one value with another. If diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h index 128502b99d9a3..9168a00d5cc50 100644 --- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -260,8 +260,8 @@ class LibCallSimplifier { bool hasFloatVersion(const Module *M, StringRef FuncName); /// Shared code to optimize strlen+wcslen and strnlen+wcsnlen. - Value *optimizeStringLength(CallInst *CI, IRBuilderBase &B, unsigned CharSize, - Value *Bound = nullptr); + Value *optimizeStringLength(CallInst *CI, IRBuilderBase &B, + unsigned CharWidth, Value *Bound = nullptr); }; } // End llvm namespace diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index 6b7a3e1ffe347..970efcdee1de3 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -379,7 +379,8 @@ llvm::getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, // Handle strdup-like functions separately. if (FnData->AllocTy == StrDupLike) { - APInt Size(IntTyBits, GetStringLength(Mapper(CB->getArgOperand(0)))); + APInt Size(IntTyBits, getStringLength(Mapper(CB->getArgOperand(0)), + DL.getByteWidth())); if (!Size) return std::nullopt; diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 472e44b0b8ea5..e2abe7eab57dc 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -6637,17 +6637,14 @@ bool llvm::isGEPBasedOnPointerToString(const GEPOperator *GEP, } // If V refers to an initialized global constant, set Slice either to -// its initializer if the size of its elements equals ElementSize, or, -// for ElementSize == 8, to its representation as an array of unsiged -// char. Return true on success. -// Offset is in the unit "nr of ElementSize sized elements". +// its initializer if the bit width of its elements equals ElementBitWidth, +// or, for ElementBitWidth == CHAR_BIT, to its representation as an array +// of unsigned char. Return true on success. +// Offset is in the unit "nr of ElementBitWidth sized elements". bool llvm::getConstantDataArrayInfo(const Value *V, ConstantDataArraySlice &Slice, - unsigned ElementSize, uint64_t Offset) { + unsigned ElementBitWidth, uint64_t Offset) { assert(V && "V should not be null."); - assert((ElementSize % 8) == 0 && - "ElementSize expected to be a multiple of the size of a byte."); - unsigned ElementSizeInBytes = ElementSize / 8; // Drill down into the pointer expression V, ignoring any intervening // casts, and determine the identity of the object it references along @@ -6659,6 +6656,11 @@ bool llvm::getConstantDataArrayInfo(const Value *V, return false; const DataLayout &DL = GV->getDataLayout(); + unsigned ByteWidth = DL.getByteWidth(); + assert((ElementBitWidth % ByteWidth) == 0 && + "ElementBitWidth is expected to be a multiple of the byte width"); + unsigned ElementSizeInBytes = ElementBitWidth / ByteWidth; + APInt Off(DL.getIndexTypeSizeInBits(V->getType()), 0); if (GV != V->stripAndAccumulateConstantOffsets(DL, Off, @@ -6698,7 +6700,7 @@ bool llvm::getConstantDataArrayInfo(const Value *V, auto *Init = const_cast<Constant *>(GV->getInitializer()); if (auto *ArrayInit = dyn_cast<ConstantDataArray>(Init)) { Type *InitElTy = ArrayInit->getElementType(); - if (InitElTy->isIntegerTy(ElementSize)) { + if (InitElTy->isIntegerTy(ElementBitWidth)) { // If Init is an initializer for an array of the expected type // and size, use it as is. Array = ArrayInit; @@ -6707,7 +6709,7 @@ bool llvm::getConstantDataArrayInfo(const Value *V, } if (!Array) { - if (ElementSize != 8) + if (ElementBitWidth != CHAR_BIT) // TODO: Handle conversions to larger integral types. return false; @@ -6785,9 +6787,9 @@ bool llvm::getConstantStringInfo(const Value *V, StringRef &Str, /// If we can compute the length of the string pointed to by /// the specified pointer, return 'len+1'. If we can't, return 0. -static uint64_t GetStringLengthH(const Value *V, - SmallPtrSetImpl<const PHINode*> &PHIs, - unsigned CharSize) { +static uint64_t getStringLength(const Value *V, + SmallPtrSetImpl<const PHINode *> &PHIs, + unsigned CharWidth) { // Look through noop bitcast instructions. V = V->stripPointerCasts(); @@ -6800,7 +6802,7 @@ static uint64_t GetStringLengthH(const Value *V, // If it was new, see if all the input strings are the same length. uint64_t LenSoFar = ~0ULL; for (Value *IncValue : PN->incoming_values()) { - uint64_t Len = GetStringLengthH(IncValue, PHIs, CharSize); + uint64_t Len = getStringLength(IncValue, PHIs, CharWidth); if (Len == 0) return 0; // Unknown length -> unknown. if (Len == ~0ULL) continue; @@ -6816,9 +6818,9 @@ static uint64_t GetStringLengthH(const Value *V, // strlen(select(c,x,y)) -> strlen(x) ^ strlen(y) if (const SelectInst *SI = dyn_cast<SelectInst>(V)) { - uint64_t Len1 = GetStringLengthH(SI->getTrueValue(), PHIs, CharSize); + uint64_t Len1 = getStringLength(SI->getTrueValue(), PHIs, CharWidth); if (Len1 == 0) return 0; - uint64_t Len2 = GetStringLengthH(SI->getFalseValue(), PHIs, CharSize); + uint64_t Len2 = getStringLength(SI->getFalseValue(), PHIs, CharWidth); if (Len2 == 0) return 0; if (Len1 == ~0ULL) return Len2; if (Len2 == ~0ULL) return Len1; @@ -6828,7 +6830,7 @@ static uint64_t GetStringLengthH(const Value *V, // Otherwise, see if we can read the string. ConstantDataArraySlice Slice; - if (!getConstantDataArrayInfo(V, Slice, CharSize)) + if (!getConstantDataArrayInfo(V, Slice, CharWidth)) return 0; if (Slice.Array == nullptr) @@ -6850,12 +6852,12 @@ static uint64_t GetStringLengthH(const Value *V, /// If we can compute the length of the string pointed to by /// the specified pointer, return 'len+1'. If we can't, return 0. -uint64_t llvm::GetStringLength(const Value *V, unsigned CharSize) { +uint64_t llvm::getStringLength(const Value *V, unsigned CharWidth) { if (!V->getType()->isPointerTy()) return 0; SmallPtrSet<const PHINode*, 32> PHIs; - uint64_t Len = GetStringLengthH(V, PHIs, CharSize); + uint64_t Len = ::getStringLength(V, PHIs, CharWidth); // If Len is ~0ULL, we had an infinite phi cycle: this is dead code, so return // an empty string as a length. return Len == ~0ULL ? 1 : Len; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index 38519d81fce8d..c64e5a29050e2 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -157,7 +157,8 @@ Instruction *InstCombinerImpl::SimplifyAnyMemTransfer(AnyMemTransferInst *MI) { uint64_t Size = MemOpLength->getLimitedValue(); assert(Size && "0-sized memory transferring should be removed already."); - if (Size > 8 || (Size&(Size-1))) + uint64_t MemOpWidth = Size * DL.getByteWidth(); + if (MemOpWidth > 64 || (Size & (Size - 1))) return nullptr; // If not 1/2/4/8 bytes, exit. // If it is an atomic and alignment is less than the size then we will @@ -169,7 +170,7 @@ Instruction *InstCombinerImpl::SimplifyAnyMemTransfer(AnyMemTransferInst *MI) { return nullptr; // Use an integer load+store unless we can find something better. - IntegerType* IntType = IntegerType::get(MI->getContext(), Size<<3); + IntegerType *IntType = IntegerType::get(MI->getContext(), MemOpWidth); // If the memcpy has metadata describing the members, see if we can get the // TBAA, scope and noalias tags describing our copy. @@ -245,7 +246,7 @@ Instruction *InstCombinerImpl::SimplifyAnyMemSet(AnyMemSetInst *MI) { // Extract the length and alignment and fill if they are constant. ConstantInt *LenC = dyn_cast<ConstantInt>(MI->getLength()); ConstantInt *FillC = dyn_cast<ConstantInt>(MI->getValue()); - if (!LenC || !FillC || !FillC->getType()->isIntegerTy(8)) + if (!LenC || !FillC || !FillC->getType()->isIntegerTy(DL.getByteWidth())) return nullptr; const uint64_t Len = LenC->getLimitedValue(); assert(Len && "0-sized memory setting should be removed already."); @@ -260,12 +261,13 @@ Instruction *InstCombinerImpl::SimplifyAnyMemSet(AnyMemSetInst *MI) { return nullptr; // memset(s,c,n) -> store s, c (for n=1,2,4,8) - if (Len <= 8 && isPowerOf2_32((uint32_t)Len)) { + uint64_t MemOpWidth = Len * DL.getByteWidth(); + if (MemOpWidth <= 64 && isPowerOf2_32((uint32_t)Len)) { Value *Dest = MI->getDest(); // Extract the fill value and store. Constant *FillVal = ConstantInt::get( - MI->getContext(), APInt::getSplat(Len * 8, FillC->getValue())); + MI->getContext(), APInt::getSplat(MemOpWidth, FillC->getValue())); StoreInst *S = Builder.CreateStore(FillVal, Dest, MI->isVolatile()); S->copyMetadata(*MI, LLVMContext::MD_DIAssignID); auto replaceOpForAssignmentMarkers = [FillC, FillVal](auto *DbgAssign) { diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index fc2945d415722..4d0e884e65e5b 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -2972,8 +2972,9 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) { if (MadeChange) return &GEP; - // Canonicalize constant GEPs to i8 type. - if (!GEPEltType->isIntegerTy(8) && GEP.hasAllConstantIndices()) { + // Canonicalize constant GEPs to byte type. + if (!GEPEltType->isIntegerTy(DL.getByteWidth()) && + GEP.hasAllConstantIndices()) { APInt Offset(DL.getIndexTypeSizeInBits(GEPType), 0); if (GEP.accumulateConstantOffset(DL, Offset)) return replaceInstUsesWith( diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index ab25b81448f00..534c428efccca 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -364,13 +364,15 @@ static StringRef substr(StringRef Str, uint64_t Len) { //===----------------------------------------------------------------------===// Value *LibCallSimplifier::optimizeStrCat(CallInst *CI, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); + // Extract some information from the instruction Value *Dst = CI->getArgOperand(0); Value *Src = CI->getArgOperand(1); annotateNonNullNoUndefBasedOnAccess(CI, {0, 1}); // See if we can get the length of the input string. - uint64_t Len = GetStringLength(Src); + uint64_t Len = getStringLength(Src, CharWidth); if (Len) annotateDereferenceableBytes(CI, 1, Len); else @@ -386,6 +388,8 @@ Value *LibCallSimplifier::optimizeStrCat(CallInst *CI, IRBuilderBase &B) { Value *LibCallSimplifier::emitStrLenMemCpy(Value *Src, Value *Dst, uint64_t Len, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); + // We need to find the end of the destination string. That's where the // memory is to be moved to. We just generate a call to strlen. Value *DstLen = emitStrLen(Dst, B, DL, TLI); @@ -395,7 +399,8 @@ Value *LibCallSimplifier::emitStrLenMemCpy(Value *Src, Value *Dst, uint64_t Len, // Now that we have the destination's length, we must index into the // destination's pointer to get the actual memcpy destination (end of // the string .. we're concatenating). - Value *CpyDst = B.CreateInBoundsGEP(B.getInt8Ty(), Dst, DstLen, "endptr"); + Value *CpyDst = + B.CreateInBoundsGEP(B.getIntNTy(CharWidth), Dst, DstLen, "endptr"); // We have enough information to now generate the memcpy call to do the // concatenation for us. Make a memcpy to copy the nul byte with align = 1. @@ -405,6 +410,8 @@ Value *LibCallSimplifier::emitStrLenMemCpy(Value *Src, Value *Dst, uint64_t Len, } Value *LibCallSimplifier::optimizeStrNCat(CallInst *CI, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); + // Extract some information from the instruction. Value *Dst = CI->getArgOperand(0); Value *Src = CI->getArgOperand(1); @@ -426,7 +433,7 @@ Value *LibCallSimplifier::optimizeStrNCat(CallInst *CI, IRBuilderBase &B) { } // See if we can get the length of the input string. - uint64_t SrcLen = GetStringLength(Src); + uint64_t SrcLen = getStringLength(Src, CharWidth); if (SrcLen) { annotateDereferenceableBytes(CI, 1, SrcLen); --SrcLen; // Unbias length. @@ -457,7 +464,7 @@ static Value* memChrToCharCompare(CallInst *CI, Value *NBytes, Value *CharVal = CI->getArgOperand(1); // Fold memchr(A, C, N) == A to N && *A == C. - Type *CharTy = B.getInt8Ty(); + Type *CharTy = B.getIntNTy(DL.getByteWidth()); Value *Char0 = B.CreateLoad(CharTy, Src); CharVal = B.CreateTrunc(CharVal, CharTy); Value *Cmp = B.CreateICmpEQ(Char0, CharVal, "char0cmp"); @@ -485,7 +492,7 @@ Value *LibCallSimplifier::optimizeStrChr(CallInst *CI, IRBuilderBase &B) { // of the input string and turn this into memchr. ConstantInt *CharC = dyn_cast<ConstantInt>(CharVal); if (!CharC) { - uint64_t Len = GetStringLength(SrcStr); + uint64_t Len = getStringLength(SrcStr, CharWidth); if (Len) annotateDereferenceableBytes(CI, 0, Len); else @@ -519,7 +526,8 @@ Value *LibCallSimplifier::optimizeStrChr(CallInst *CI, IRBuilderBase &B) { if (!getConstantStringInfo(SrcStr, Str, CharWidth)) { if (CharC->isZero()) // strchr(p, 0) -> p + strlen(p) if (Value *StrLen = emitStrLen(SrcStr, B, DL, TLI)) - return B.CreateInBoundsGEP(B.getInt8Ty(), SrcStr, StrLen, "strchr"); + return B.CreateInBoundsGEP(B.getIntNTy(CharWidth), SrcStr, StrLen, + "strchr"); return nullptr; } @@ -576,19 +584,30 @@ Value *LibCallSimplifier::optimizeStrCmp(CallInst *CI, IRBuilderBase &B) { return ConstantInt::get(CI->getType(), std::clamp(Str1.compare(Str2), -1, 1)); - if (HasStr1 && Str1.empty()) // strcmp("", x) -> -*x - return B.CreateNeg(B.CreateZExt( - B.CreateLoad(B.getInt8Ty(), Str2P, "strcmpload"), CI->getType())); + uint64_t Len1 = getStringLength(Str1P, CharWidth); + uint64_t Len2 = getStringLength(Str2P, CharWidth); - if (HasStr2 && Str2.empty()) // strcmp(x,"") -> *x - return B.CreateZExt(B.CreateLoad(B.getInt8Ty(), Str1P, "strcmpload"), - CI->getType()); + if (Len1 == 1) { + Value *RHS0 = B.CreateLoad(B.getIntNTy(CharWidth), Str2P, "strcmpload"); + // strcmp("", x) -> -*x + if (CharWidth < CI->getType()->getIntegerBitWidth()) + return B.CreateNeg(B.CreateZExt(RHS0, CI->getType())); + // strcmp("", x) -> sext(*x != '\0') + return B.CreateSExt(B.CreateIsNotNull(RHS0), CI->getType()); + } + + if (Len2 == 1) { + Value *LHS0 = B.CreateLoad(B.getIntNTy(CharWidth), Str1P, "strcmpload"); + // strcmp(x, "") -> *x + if (CharWidth < CI->getType()->getIntegerBitWidth()) + return B.CreateZExt(LHS0, CI->getType()); + // strcmp(x, "") -> zext(*x != '\0') + return B.CreateZExt(B.CreateIsNotNull(LHS0), CI->getType()); + } // strcmp(P, "x") -> memcmp(P, "x", 2) - uint64_t Len1 = GetStringLength(Str1P); if (Len1) annotateDereferenceableBytes(CI, 0, Len1); - uint64_t Len2 = GetStringLength(Str2P); if (Len2) annotateDereferenceableBytes(CI, 1, Len2); @@ -658,18 +677,29 @@ Value *LibCallSimplifier::optimizeStrNCmp(CallInst *CI, IRBuilderBase &B) { std::clamp(SubStr1.compare(SubStr2), -1, 1)); } - if (HasStr1 && Str1.empty()) // strncmp("", x, n) -> -*x - return B.CreateNeg(B.CreateZExt( - B.CreateLoad(B.getInt8Ty(), Str2P, "strcmpload"), CI->getType())); + uint64_t Len1 = getStringLength(Str1P, CharWidth); + uint64_t Len2 = getStringLength(Str2P, CharWidth); - if (HasStr2 && Str2.empty()) // strncmp(x, "", n) -> *x - return B.CreateZExt(B.CreateLoad(B.getInt8Ty(), Str1P, "strcmpload"), - CI->getType()); + if (Len1 == 1) { + Value *RHS0 = B.CreateLoad(B.getIntNTy(CharWidth), Str2P, "strcmpload"); + // strncmp("", x, n) -> -*x + if (CharWidth < CI->getType()->getIntegerBitWidth()) + return B.CreateNeg(B.CreateZExt(RHS0, CI->getType())); + // strncmp("", x, n) -> sext(*x != '\0') + return B.CreateSExt(B.CreateIsNotNull(RHS0), CI->getType()); + } + + if (Len2 == 1) { + // strncmp(x, "", n) -> *x + Value *LHS0 = B.CreateLoad(B.getIntNTy(CharWidth), Str1P, "strcmpload"); + if (CharWidth < CI->getType()->getIntegerBitWidth()) + return B.CreateZExt(LHS0, CI->getType()); + // strncmp(x, "", n) -> zext(*x != '\0') + return B.CreateZExt(B.CreateIsNotNull(LHS0), CI->getType()); + } - uint64_t Len1 = GetStringLength(Str1P); if (Len1) annotateDereferenceableBytes(CI, 0, Len1); - uint64_t Len2 = GetStringLength(Str2P); if (Len2) annotateDereferenceableBytes(CI, 1, Len2); @@ -692,9 +722,11 @@ Value *LibCallSimplifier::optimizeStrNCmp(CallInst *CI, IRBuilderBase &B) { } Value *LibCallSimplifier::optimizeStrNDup(CallInst *CI, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); Value *Src = CI->getArgOperand(0); ConstantInt *Size = dyn_cast<ConstantInt>(CI->getArgOperand(1)); - uint64_t SrcLen = GetStringLength(Src); + + uint64_t SrcLen = getStringLength(Src, CharWidth); if (SrcLen && Size) { annotateDereferenceableBytes(CI, 0, SrcLen); if (SrcLen <= Size->getZExtValue() + 1) @@ -705,13 +737,15 @@ Value *LibCallSimplifier::optimizeStrNDup(CallInst *CI, IRBuilderBase &B) { } Value *LibCallSimplifier::optimizeStrCpy(CallInst *CI, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); + Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1); if (Dst == Src) // strcpy(x,x) -> x return Src; annotateNonNullNoUndefBasedOnAccess(CI, {0, 1}); // See if we can get the length of the input string. - uint64_t Len = GetStringLength(Src); + uint64_t Len = getStringLength(Src, CharWidth); if (Len) annotateDereferenceableBytes(CI, 1, Len); else @@ -726,6 +760,7 @@ Value *LibCallSimplifier::optimizeStrCpy(CallInst *CI, IRBuilderBase &B) { } Value *LibCallSimplifier::optimizeStpCpy(CallInst *CI, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1); // stpcpy(d,s) -> strcpy(d,s) if the result is not used. @@ -734,11 +769,12 @@ Value *LibCallSimplifier::optimizeStpCpy(CallInst *CI, IRBuilderBase &B) { if (Dst == Src) { // stpcpy(x,x) -> x+strlen(x) Value *StrLen = emitStrLen(Src, B, DL, TLI); - return StrLen ? B.CreateInBoundsGEP(B.getInt8Ty(), Dst, StrLen) : nullptr; + return StrLen ? B.CreateInBoundsGEP(B.getIntNTy(CharWidth), Dst, StrLen) + : nullptr; } // See if we can get the length of the input string. - uint64_t Len = GetStringLength(Src); + uint64_t Len = getStringLength(Src, CharWidth); if (Len) annotateDereferenceableBytes(CI, 1, Len); else @@ -746,7 +782,7 @@ Value *LibCallSimplifier::optimizeStpCpy(CallInst *CI, IRBuilderBase &B) { Value *LenV = TLI->getAsSizeT(Len, *CI->getModule()); Value *DstEnd = B.CreateInBoundsGEP( - B.getInt8Ty(), Dst, TLI->getAsSizeT(Len - 1, *CI->getModule())); + B.getIntNTy(CharWidth), Dst, TLI->getAsSizeT(Len - 1, *CI->getModule())); // We have enough information to now generate the memcpy call to do the // copy for us. Make a memcpy to copy the nul byte with align = 1. @@ -780,7 +816,7 @@ Value *LibCallSimplifier::optimizeStrLCpy(CallInst *CI, IRBuilderBase &B) { if (NBytes <= 1) { if (NBytes == 1) // For a call to strlcpy(D, S, 1) first store a nul in *D. - B.CreateStore(B.getInt8(0), Dst); + B.CreateStore(B.getIntN(CharWidth, 0), Dst); // Transform strlcpy(D, S, 0) to a call to strlen(S). return copyFlags(*CI, emitStrLen(Src, B, DL, TLI)); @@ -861,7 +897,7 @@ Value *LibCallSimplifier::optimizeStringNCpy(CallInst *CI, bool RetEnd, return Dst; if (N == 1) { - Type *CharTy = B.getInt8Ty(); + Type *CharTy = B.getIntNTy(CharWidth); Value *CharVal = B.CreateLoad(CharTy, Src, "stxncpy.char0"); B.CreateStore(CharVal, Dst); if (!RetEnd) @@ -878,7 +914,7 @@ Value *LibCallSimplifier::optimizeStringNCpy(CallInst *CI, bool RetEnd, } // If the length of the input string is known set SrcLen to it. - uint64_t SrcLen = GetStringLength(Src); + uint64_t SrcLen = getStringLength(Src, CharWidth); if (SrcLen) annotateDereferenceableBytes(CI, 1, SrcLen); else @@ -890,7 +926,8 @@ Value *LibCallSimplifier::optimizeStringNCpy(CallInst *CI, bool RetEnd, // Transform st{p,r}ncpy(D, "", N) to memset(D, '\0', N) for any N. Align MemSetAlign = CI->getAttributes().getParamAttrs(0).getAlignment().valueOrOne(); - CallInst *NewCI = B.CreateMemSet(Dst, B.getInt8('\0'), Size, MemSetAlign); + CallInst *NewCI = + B.CreateMemSet(Dst, B.getIntN(CharWidth, 0), Size, MemSetAlign); AttrBuilder ArgAttrs(CI->getContext(), CI->getAttributes().getParamAttrs(0)); NewCI->setAttributes(NewCI->getAttributes().addParamAttributes( CI->getContext(), 0, ArgAttrs)); @@ -926,14 +963,14 @@ Value *LibCallSimplifier::optimizeStringNCpy(CallInst *CI, bool RetEnd, // stpncpy(D, S, N) returns the address of the first null in D if it writes // one, otherwise D + N. Value *Off = B.getInt64(std::min(SrcLen, N)); - return B.CreateInBoundsGEP(B.getInt8Ty(), Dst, Off, "endptr"); + return B.CreateInBoundsGEP(B.getIntNTy(CharWidth), Dst, Off, "endptr"); } Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B, - unsigned CharSize, + unsigned CharWidth, Value *Bound) { Value *Src = CI->getArgOperand(0); - Type *CharTy = B.getIntNTy(CharSize); + Type *CharTy = B.getIntNTy(CharWidth); if (isOnlyUsedInZeroEqualityComparison(CI) && (!Bound || isKnownNonZero(Bound, DL))) { @@ -963,7 +1000,7 @@ Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B, } } - if (uint64_t Len = GetStringLength(Src, CharSize)) { + if (uint64_t Len = getStringLength(Src, CharWidth)) { Value *LenC = ConstantInt::get(CI->getType(), Len - 1); // Fold strlen("xyz") -> 3 and strnlen("xyz", 2) -> 2 // and strnlen("xyz", Bound) -> min(3, Bound) for nonconstant Bound. @@ -986,11 +1023,11 @@ Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B, // very uncommon. if (GEPOperator *GEP = dyn_cast<GEPOperator>(Src)) { // TODO: Handle subobjects. - if (!isGEPBasedOnPointerToString(GEP, CharSize)) + if (!isGEPBasedOnPointerToString(GEP, CharWidth)) return nullptr; ConstantDataArraySlice Slice; - if (getConstantDataArrayInfo(GEP->getOperand(0), Slice, CharSize)) { + if (getConstantDataArrayInfo(GEP->getOperand(0), Slice, CharWidth)) { uint64_t NullTermIdx; if (Slice.Array == nullptr) { NullTermIdx = 0; @@ -1029,8 +1066,8 @@ Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B, // strlen(x?"foo":"bars") --> x ? 3 : 4 if (SelectInst *SI = dyn_cast<SelectInst>(Src)) { - uint64_t LenTrue = GetStringLength(SI->getTrueValue(), CharSize); - uint64_t LenFalse = GetStringLength(SI->getFalseValue(), CharSize); + uint64_t LenTrue = getStringLength(SI->getTrueValue(), CharWidth); + uint64_t LenFalse = getStringLength(SI->getFalseValue(), CharWidth); if (LenTrue && LenFalse) { ORE.emit([&]() { return OptimizationRemark("instcombine", "simplify-libcalls", CI) @@ -1046,7 +1083,7 @@ Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B, } Value *LibCallSimplifier::optimizeStrLen(CallInst *CI, IRBuilderBase &B) { - if (Value *V = optimizeStringLength(CI, B, 8)) + if (Value *V = optimizeStringLength(CI, B, DL.getByteWidth())) return V; annotateNonNullNoUndefBasedOnAccess(CI, 0); return nullptr; @@ -1054,7 +1091,7 @@ Value *LibCallSimplifier::optimizeStrLen(CallInst *CI, IRBuilderBase &B) { Value *LibCallSimplifier::optimizeStrNLen(CallInst *CI, IRBuilderBase &B) { Value *Bound = CI->getArgOperand(1); - if (Value *V = optimizeStringLength(CI, B, 8, Bound)) + if (Value *V = optimizeStringLength(CI, B, DL.getByteWidth(), Bound)) return V; if (isKnownNonZero(Bound, DL)) @@ -1064,12 +1101,12 @@ Value *LibCallSimplifier::optimizeStrNLen(CallInst *CI, IRBuilderBase &B) { Value *LibCallSimplifier::optimizeWcslen(CallInst *CI, IRBuilderBase &B) { Module &M = *CI->getModule(); - unsigned WCharSize = TLI->getWCharSize(M) * 8; + unsigned WCharWidth = TLI->getWCharSize(M) * DL.getByteWidth(); // We cannot perform this optimization without wchar_size metadata. - if (WCharSize == 0) + if (WCharWidth == 0) return nullptr; - return optimizeStringLength(CI, B, WCharSize); + return optimizeStringLength(CI, B, WCharWidth); } Value *LibCallSimplifier::optimizeStrPBrk(CallInst *CI, IRBuilderBase &B) { @@ -1238,9 +1275,10 @@ Value *LibCallSimplifier::optimizeMemRChr(CallInst *CI, IRBuilderBase &B) { if (LenC->isOne()) { // Fold memrchr(x, y, 1) --> *x == y ? x : null for any x and y, // constant or otherwise. - Value *Val = B.CreateLoad(B.getInt8Ty(), SrcStr, "memrchr.char0"); + Type *CharTy = B.getIntNTy(CharWidth); + Value *Val = B.CreateLoad(CharTy, SrcStr, "memrchr.char0"); // Slice off the character's high end bits. - CharVal = B.CreateTrunc(CharVal, B.getInt8Ty()); + CharVal = B.CreateTrunc(CharVal, CharTy); Value *Cmp = B.CreateICmpEQ(Val, CharVal, "memrchr.char0cmp"); return B.CreateSelect(Cmp, SrcStr, NullPtr, "memrchr.sel"); } @@ -1334,9 +1372,10 @@ Value *LibCallSimplifier::optimizeMemChr(CallInst *CI, IRBuilderBase &B) { if (LenC->isOne()) { // Fold memchr(x, y, 1) --> *x == y ? x : null for any x and y, // constant or otherwise. - Value *Val = B.CreateLoad(B.getInt8Ty(), SrcStr, "memchr.char0"); + Type *CharTy = B.getIntNTy(CharWidth); + Value *Val = B.CreateLoad(CharTy, SrcStr, "memchr.char0"); // Slice off the character's high end bits. - CharVal = B.CreateTrunc(CharVal, B.getInt8Ty()); + CharVal = B.CreateTrunc(CharVal, CharTy); Value *Cmp = B.CreateICmpEQ(Val, CharVal, "memchr.char0cmp"); return B.CreateSelect(Cmp, SrcStr, NullPtr, "memchr.sel"); } @@ -1553,23 +1592,33 @@ static Value *optimizeMemCmpVarSize(CallInst *CI, Value *LHS, Value *RHS, static Value *optimizeMemCmpConstantSize(CallInst *CI, Value *LHS, Value *RHS, uint64_t Len, IRBuilderBase &B, const DataLayout &DL) { + unsigned CharWidth = DL.getByteWidth(); + if (Len == 0) // memcmp(s1,s2,0) -> 0 return Constant::getNullValue(CI->getType()); - // memcmp(S1,S2,1) -> *(unsigned char*)LHS - *(unsigned char*)RHS if (Len == 1) { - Value *LHSV = B.CreateZExt(B.CreateLoad(B.getInt8Ty(), LHS, "lhsc"), - CI->getType(), "lhsv"); - Value *RHSV = B.CreateZExt(B.CreateLoad(B.getInt8Ty(), RHS, "rhsc"), - CI->getType(), "rhsv"); - return B.CreateSub(LHSV, RHSV, "chardiff"); + Type *CharTy = B.getIntNTy(CharWidth); + Value *LHSC = B.CreateLoad(CharTy, LHS, "lhsc"); + Value *RHSC = B.CreateLoad(CharTy, RHS, "rhsc"); + + // memcmp(S1,S2,1) -> *(unsigned char*)LHS - *(unsigned char*)RHS + if (CharWidth < CI->getType()->getIntegerBitWidth()) { + Value *LHSV = B.CreateZExt(LHSC, CI->getType(), "lhsv"); + Value *RHSV = B.CreateZExt(RHSC, CI->getType(), "rhsv"); + return B.CreateSub(LHSV, RHSV, "chardiff"); + } + + // memcmp(LHS, RHS, 1) -> *(unsigned char *)LHS <=> *(unsigned char *)RHS + return B.CreateIntrinsic(CI->getType(), Intrinsic::ucmp, {LHSC, RHSC}); } // memcmp(S1,S2,N/8)==0 -> (*(intN_t*)S1 != *(intN_t*)S2)==0 // TODO: The case where both inputs are constants does not need to be limited // to legal integers or equality comparison. See block below this. - if (DL.isLegalInteger(Len * 8) && isOnlyUsedInZeroEqualityComparison(CI)) { - IntegerType *IntType = IntegerType::get(CI->getContext(), Len * 8); + if (DL.isLegalInteger(Len * CharWidth) && + isOnlyUsedInZeroEqualityComparison(CI)) { + IntegerType *IntType = IntegerType::get(CI->getContext(), Len * CharWidth); Align PrefAlignment = DL.getPrefTypeAlign(IntType); // First, see if we can fold either argument to a constant. @@ -1693,6 +1742,7 @@ Value *LibCallSimplifier::optimizeMemCCpy(CallInst *CI, IRBuilderBase &B) { } Value *LibCallSimplifier::optimizeMemPCpy(CallInst *CI, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); Value *Dst = CI->getArgOperand(0); Value *N = CI->getArgOperand(2); // mempcpy(x, y, n) -> llvm.memcpy(align 1 x, align 1 y, n), x + n @@ -1702,7 +1752,7 @@ Value *LibCallSimplifier::optimizeMemPCpy(CallInst *CI, IRBuilderBase &B) { // any return attributes are compliant. // TODO: Attach return value attributes to the 1st operand to preserve them? mergeAttributesAndFlags(NewCI, *CI); - return B.CreateInBoundsGEP(B.getInt8Ty(), Dst, N); + return B.CreateInBoundsGEP(B.getIntNTy(CharWidth), Dst, N); } Value *LibCallSimplifier::optimizeMemMove(CallInst *CI, IRBuilderBase &B) { @@ -1719,13 +1769,14 @@ Value *LibCallSimplifier::optimizeMemMove(CallInst *CI, IRBuilderBase &B) { } Value *LibCallSimplifier::optimizeMemSet(CallInst *CI, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); Value *Size = CI->getArgOperand(2); annotateNonNullAndDereferenceable(CI, 0, Size, DL); if (isa<IntrinsicInst>(CI)) return nullptr; // memset(p, v, n) -> llvm.memset(align 1 p, v, n) - Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false); + Value *Val = B.CreateTrunc(CI->getArgOperand(1), B.getIntNTy(CharWidth)); CallInst *NewCI = B.CreateMemSet(CI->getArgOperand(0), Val, Size, Align(1)); mergeAttributesAndFlags(NewCI, *CI); return CI->getArgOperand(0); @@ -3477,7 +3528,7 @@ Value *LibCallSimplifier::optimizeSPrintFString(CallInst *CI, // sprintf(dest, "%s", str) -> strcpy(dest, str) return copyFlags(*CI, emitStrCpy(Dest, CI->getArgOperand(2), B, TLI)); - uint64_t SrcLen = GetStringLength(CI->getArgOperand(2)); + uint64_t SrcLen = getStringLength(CI->getArgOperand(2), /*CharWidth=*/8); if (SrcLen) { B.CreateMemCpy(Dest, Align(1), CI->getArgOperand(2), Align(1), TLI->getAsSizeT(SrcLen, *CI->getModule())); @@ -3768,6 +3819,7 @@ Value *LibCallSimplifier::optimizeFPrintF(CallInst *CI, IRBuilderBase &B) { } Value *LibCallSimplifier::optimizeFWrite(CallInst *CI, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); optimizeErrorReporting(CI, B, 3); // Get the element size and count. @@ -3783,7 +3835,8 @@ Value *LibCallSimplifier::optimizeFWrite(CallInst *CI, IRBuilderBase &B) { // If this is writing one byte, turn it into fputc. // This optimisation is only valid, if the return value is unused. if (Bytes == 1 && CI->use_empty()) { // fwrite(S,1,1,F) -> fputc(S[0],F) - Value *Char = B.CreateLoad(B.getInt8Ty(), CI->getArgOperand(0), "char"); + Value *Char = + B.CreateLoad(B.getIntNTy(CharWidth), CI->getArgOperand(0), "char"); Type *IntTy = B.getIntNTy(TLI->getIntSize()); Value *Cast = B.CreateIntCast(Char, IntTy, /*isSigned*/ true, "chari"); Value *NewCI = emitFPutC(Cast, CI->getArgOperand(3), B, TLI); @@ -3795,6 +3848,8 @@ Value *LibCallSimplifier::optimizeFWrite(CallInst *CI, IRBuilderBase &B) { } Value *LibCallSimplifier::optimizeFPuts(CallInst *CI, IRBuilderBase &B) { + unsigned CharWidth = DL.getByteWidth(); + optimizeErrorReporting(CI, B, 1); // Don't rewrite fputs to fwrite when optimising for size because fwrite @@ -3808,7 +3863,7 @@ Value *LibCallSimplifier::optimizeFPuts(CallInst *CI, IRBuilderBase &B) { return nullptr; // fputs(s,F) --> fwrite(s,strlen(s),1,F) - uint64_t Len = GetStringLength(CI->getArgOperand(0)); + uint64_t Len = getStringLength(CI->getArgOperand(0), CharWidth); if (!Len) return nullptr; @@ -4329,7 +4384,8 @@ bool FortifiedLibCallSimplifier::isFortifiedCallFoldable( if (OnlyLowerUnknownSize) return false; if (StrOp) { - uint64_t Len = GetStringLength(CI->getArgOperand(*StrOp)); + uint64_t Len = getStringLength(CI->getArgOperand(*StrOp), + CI->getDataLayout().getByteWidth()); // If the length is 0 we don't know how long it is and so we can't // remove the check. if (Len) @@ -4375,7 +4431,8 @@ Value *FortifiedLibCallSimplifier::optimizeMemMoveChk(CallInst *CI, Value *FortifiedLibCallSimplifier::optimizeMemSetChk(CallInst *CI, IRBuilderBase &B) { if (isFortifiedCallFoldable(CI, 3, 2)) { - Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false); + Type *CharTy = B.getIntNTy(CI->getDataLayout().getByteWidth()); + Value *Val = B.CreateIntCast(CI->getArgOperand(1), CharTy, false); CallInst *NewCI = B.CreateMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), Align(1)); mergeAttributesAndFlags(NewCI, *CI); @@ -4399,13 +4456,15 @@ Value *FortifiedLibCallSimplifier::optimizeStrpCpyChk(CallInst *CI, IRBuilderBase &B, LibFunc Func) { const DataLayout &DL = CI->getDataLayout(); + unsigned CharWidth = DL.getByteWidth(); Value *Dst = CI->getArgOperand(0), *Src = CI->getArgOperand(1), *ObjSize = CI->getArgOperand(2); // __stpcpy_chk(x,x,...) -> x+strlen(x) if (Func == LibFunc_stpcpy_chk && !OnlyLowerUnknownSize && Dst == Src) { Value *StrLen = emitStrLen(Src, B, DL, TLI); - return StrLen ? B.CreateInBoundsGEP(B.getInt8Ty(), Dst, StrLen) : nullptr; + return StrLen ? B.CreateInBoundsGEP(B.getIntNTy(CharWidth), Dst, StrLen) + : nullptr; } // If a) we don't have any length information, or b) we know this will @@ -4424,7 +4483,7 @@ Value *FortifiedLibCallSimplifier::optimizeStrpCpyChk(CallInst *CI, return nullptr; // Maybe we can stil fold __st[rp]cpy_chk to __memcpy_chk. - uint64_t Len = GetStringLength(Src); + uint64_t Len = getStringLength(Src, CharWidth); if (Len) annotateDereferenceableBytes(CI, 1, Len); else @@ -4437,7 +4496,7 @@ Value *FortifiedLibCallSimplifier::optimizeStrpCpyChk(CallInst *CI, // If the function was an __stpcpy_chk, and we were able to fold it into // a __memcpy_chk, we still need to return the correct end pointer. if (Ret && Func == LibFunc_stpcpy_chk) - return B.CreateInBoundsGEP(B.getInt8Ty(), Dst, + return B.CreateInBoundsGEP(B.getIntNTy(CharWidth), Dst, ConstantInt::get(SizeTTy, Len - 1)); return copyFlags(*CI, cast<CallInst>(Ret)); } diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/fputs-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/fputs-b16.ll new file mode 100644 index 0000000000000..cc841c6f9c5a0 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/fputs-b16.ll @@ -0,0 +1,19 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare i32 @fputs(ptr, ptr) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +; fputs(str, stream) -> fwrite(str, strlen(str), 1, stream) +define void @test(ptr %stream) { +; CHECK-LABEL: define void @test( +; CHECK-SAME: ptr [[STREAM:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call i32 @fwrite(ptr nonnull @hello, i32 5, i32 1, ptr [[STREAM]]) +; CHECK-NEXT: ret void +; + call i32 @fputs(ptr @hello, ptr %stream) + ret void +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/fwrite-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/fwrite-b16.ll new file mode 100644 index 0000000000000..07c2468da4358 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/fwrite-b16.ll @@ -0,0 +1,19 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare i32 @fwrite(ptr, i32, i32, ptr) + +; fwrite(str, 1, 1, stream) -> fputc(*str, stream) +define void @test(ptr %str, ptr %stream) { +; CHECK-LABEL: define void @test( +; CHECK-SAME: ptr [[STR:%.*]], ptr [[STREAM:%.*]]) { +; CHECK-NEXT: [[CHAR:%.*]] = load i16, ptr [[STR]], align 1 +; CHECK-NEXT: [[CHARI:%.*]] = sext i16 [[CHAR]] to i32 +; CHECK-NEXT: [[FPUTC:%.*]] = call i32 @fputc(i32 [[CHARI]], ptr [[STREAM]]) +; CHECK-NEXT: ret void +; + call i32 @fwrite(ptr %str, i32 1, i32 1, ptr %stream) + ret void +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memchr-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memchr-b16.ll new file mode 100644 index 0000000000000..0b48dac2c719f --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memchr-b16.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32-n64" + +declare ptr @memchr(ptr, i32, i32) + +; memchr(str, c, n) == str -> (unsigned char)*str == (unsigned char)c +define i1 @test_eq(ptr %str, i32 %c) { +; CHECK-LABEL: define i1 @test_eq( +; CHECK-SAME: ptr [[STR:%.*]], i32 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[STR]], align 1 +; CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[C]] to i16 +; CHECK-NEXT: [[CHAR0CMP:%.*]] = icmp eq i16 [[TMP1]], [[TMP2]] +; CHECK-NEXT: ret i1 [[CHAR0CMP]] +; + %call = call ptr @memchr(ptr %str, i32 %c, i32 42) + %cmp = icmp eq ptr %call, %str + ret i1 %cmp +} + +; memchr(str, c, 1) -> (unsigned char)*str == (unsigned char)c ? str : null +define ptr @test_n_1(ptr %str, i32 %c) { +; CHECK-LABEL: define ptr @test_n_1( +; CHECK-SAME: ptr [[STR:%.*]], i32 [[C:%.*]]) { +; CHECK-NEXT: [[MEMCHR_CHAR0:%.*]] = load i16, ptr [[STR]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C]] to i16 +; CHECK-NEXT: [[MEMCHR_CHAR0CMP:%.*]] = icmp eq i16 [[MEMCHR_CHAR0]], [[TMP1]] +; CHECK-NEXT: [[MEMCHR_SEL:%.*]] = select i1 [[MEMCHR_CHAR0CMP]], ptr [[STR]], ptr null +; CHECK-NEXT: ret ptr [[MEMCHR_SEL]] +; + %call = call ptr @memchr(ptr %str, i32 %c, i32 1) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcmp-b32.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcmp-b32.ll new file mode 100644 index 0000000000000..a21e9b1cadde1 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcmp-b32.ll @@ -0,0 +1,32 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:32-p:32:32-n64" + +declare i32 @memcmp(ptr, ptr, i32) + +; memcmp(lhs, rhs, 1) -> *(unsigned char *)lhs <=> *(unsigned char *)rhs +define i32 @test_size_1(ptr %lhs, ptr %rhs) { +; CHECK-LABEL: define i32 @test_size_1( +; CHECK-SAME: ptr [[LHS:%.*]], ptr [[RHS:%.*]]) { +; CHECK-NEXT: [[MEMCMP_LHS0:%.*]] = load i32, ptr [[LHS]], align 1 +; CHECK-NEXT: [[MEMCMP_RHS0:%.*]] = load i32, ptr [[RHS]], align 1 +; CHECK-NEXT: [[MEMCMP_CHAR0CMP:%.*]] = call i32 @llvm.ucmp.i32.i32(i32 [[MEMCMP_LHS0]], i32 [[MEMCMP_RHS0]]) +; CHECK-NEXT: ret i32 [[MEMCMP_CHAR0CMP]] +; + %call = call i32 @memcmp(ptr %lhs, ptr %rhs, i32 1) ret i32 %call +} + +; memcmp(lhs, rhs, 2) == 0 -> (*(uint64_t *)lhs != *(uint64_t *)rhs) == 0 +define i1 @test_eq_size_2(ptr %lhs, ptr %rhs) { +; CHECK-LABEL: define i1 @test_eq_size_2( +; CHECK-SAME: ptr [[LHS:%.*]], ptr [[RHS:%.*]]) { +; CHECK-NEXT: [[LHSV:%.*]] = load i64, ptr [[LHS]], align 1 +; CHECK-NEXT: [[RHSV:%.*]] = load i64, ptr [[RHS]], align 1 +; CHECK-NEXT: [[DOTNOT:%.*]] = icmp eq i64 [[LHSV]], [[RHSV]] +; CHECK-NEXT: ret i1 [[DOTNOT]] +; + %call = call i32 @memcmp(ptr %lhs, ptr %rhs, i32 2) + %cmp = icmp eq i32 %call, 0 + ret i1 %cmp +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcpy-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcpy-b16.ll new file mode 100644 index 0000000000000..2c59132a8a6ec --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcpy-b16.ll @@ -0,0 +1,69 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @memcpy(ptr, ptr, i32) + +define ptr @test_size_1(ptr %dst, ptr %src) { +; CHECK-LABEL: define ptr @test_size_1( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[SRC]], align 1 +; CHECK-NEXT: store i16 [[TMP1]], ptr [[DST]], align 1 +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memcpy(ptr %dst, ptr %src, i32 1) + ret ptr %call +} + +define ptr @test_size_2(ptr %dst, ptr %src) { +; CHECK-LABEL: define ptr @test_size_2( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[SRC]], align 1 +; CHECK-NEXT: store i32 [[TMP1]], ptr [[DST]], align 1 +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memcpy(ptr %dst, ptr %src, i32 2) + ret ptr %call +} + +define ptr @test_size_3(ptr %dst, ptr %src) { +; CHECK-LABEL: define ptr @test_size_3( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) { +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], ptr noundef nonnull align 1 dereferenceable(3) [[SRC]], i32 3, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memcpy(ptr %dst, ptr %src, i32 3) + ret ptr %call +} + +define ptr @test_size_4(ptr %dst, ptr %src) { +; CHECK-LABEL: define ptr @test_size_4( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[SRC]], align 1 +; CHECK-NEXT: store i64 [[TMP1]], ptr [[DST]], align 1 +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memcpy(ptr %dst, ptr %src, i32 4) + ret ptr %call +} + +define ptr @test_size_5(ptr %dst, ptr %src) { +; CHECK-LABEL: define ptr @test_size_5( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) { +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], ptr noundef nonnull align 1 dereferenceable(5) [[SRC]], i32 5, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memcpy(ptr %dst, ptr %src, i32 5) + ret ptr %call +} + +define ptr @test_size_8(ptr %dst, ptr %src) { +; CHECK-LABEL: define ptr @test_size_8( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) { +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(8) [[DST]], ptr noundef nonnull align 1 dereferenceable(8) [[SRC]], i32 8, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memcpy(ptr %dst, ptr %src, i32 8) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcpy_chk-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcpy_chk-b16.ll new file mode 100644 index 0000000000000..f40e5fc7205f3 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memcpy_chk-b16.ll @@ -0,0 +1,17 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @__memset_chk(ptr, i32, i32, i32) + +define ptr @test(ptr %dst, i32 %c, i32 %n) { +; CHECK-LABEL: define ptr @test( +; CHECK-SAME: ptr [[DST:%.*]], i32 [[C:%.*]], i32 [[N:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C]] to i16 +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 1 [[DST]], i16 [[TMP1]], i32 [[N]], i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @__memset_chk(ptr %dst, i32 %c, i32 %n, i32 -1) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/mempcpy-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/mempcpy-b16.ll new file mode 100644 index 0000000000000..fd6bdcd423785 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/mempcpy-b16.ll @@ -0,0 +1,17 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @mempcpy(ptr, ptr, i32) + +define ptr @test(ptr %dst, ptr %src, i32 %n) { +; CHECK-LABEL: define ptr @test( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]], i32 [[N:%.*]]) { +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 1 [[DST]], ptr align 1 [[SRC]], i32 [[N]], i1 false) +; CHECK-NEXT: [[CALL:%.*]] = getelementptr inbounds i16, ptr [[DST]], i32 [[N]] +; CHECK-NEXT: ret ptr [[CALL]] +; + %call = call ptr @mempcpy(ptr %dst, ptr %src, i32 %n) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memrchr-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memrchr-b16.ll new file mode 100644 index 0000000000000..985dc3c249c0e --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memrchr-b16.ll @@ -0,0 +1,20 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32-n64" + +declare ptr @memrchr(ptr, i32, i32) + +; memrchr(str, c, 1) -> (unsigned char)*str == (unsigned char)c ? str : null +define ptr @test_n_1(ptr %str, i32 %c) { +; CHECK-LABEL: define ptr @test_n_1( +; CHECK-SAME: ptr [[STR:%.*]], i32 [[C:%.*]]) { +; CHECK-NEXT: [[MEMRCHR_CHAR0:%.*]] = load i16, ptr [[STR]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[C]] to i16 +; CHECK-NEXT: [[MEMRCHR_CHAR0CMP:%.*]] = icmp eq i16 [[MEMRCHR_CHAR0]], [[TMP1]] +; CHECK-NEXT: [[MEMRCHR_SEL:%.*]] = select i1 [[MEMRCHR_CHAR0CMP]], ptr [[STR]], ptr null +; CHECK-NEXT: ret ptr [[MEMRCHR_SEL]] +; + %call = call ptr @memrchr(ptr %str, i32 %c, i32 1) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memset-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memset-b16.ll new file mode 100644 index 0000000000000..83bd0c84ae93b --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/memset-b16.ll @@ -0,0 +1,66 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @memset(ptr, i32, i32) + +define ptr @test_size_1(ptr %dst) { +; CHECK-LABEL: define ptr @test_size_1( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: store i16 42, ptr [[DST]], align 1 +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memset(ptr %dst, i32 42, i32 1) + ret ptr %call +} + +define ptr @test_size_2(ptr %dst) { +; CHECK-LABEL: define ptr @test_size_2( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: store i32 2752554, ptr [[DST]], align 1 +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memset(ptr %dst, i32 42, i32 2) + ret ptr %call +} + +define ptr @test_size_3(ptr %dst) { +; CHECK-LABEL: define ptr @test_size_3( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr noundef nonnull align 1 dereferenceable(3) [[DST]], i16 42, i32 3, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memset(ptr %dst, i32 42, i32 3) + ret ptr %call +} + +define ptr @test_size_4(ptr %dst) { +; CHECK-LABEL: define ptr @test_size_4( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: store i64 11822129413226538, ptr [[DST]], align 1 +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memset(ptr %dst, i32 42, i32 4) + ret ptr %call +} + +define ptr @test_size_5(ptr %dst) { +; CHECK-LABEL: define ptr @test_size_5( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr noundef nonnull align 1 dereferenceable(5) [[DST]], i16 42, i32 5, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memset(ptr %dst, i32 42, i32 5) + ret ptr %call +} + +define ptr @test_size_8(ptr %dst) { +; CHECK-LABEL: define ptr @test_size_8( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr noundef nonnull align 1 dereferenceable(8) [[DST]], i16 42, i32 8, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @memset(ptr %dst, i32 42, i32 8) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpcpy-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpcpy-b16.ll new file mode 100644 index 0000000000000..42b9ec7d4653e --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpcpy-b16.ll @@ -0,0 +1,31 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @stpcpy(ptr, ptr) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +; stpcpy(x, x) -> x + strlen(x) +define ptr @test_1(ptr %str) { +; CHECK-LABEL: define ptr @test_1( +; CHECK-SAME: ptr [[STR:%.*]]) { +; CHECK-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[STR]]) +; CHECK-NEXT: [[CALL:%.*]] = getelementptr inbounds i16, ptr [[STR]], i32 [[STRLEN]] +; CHECK-NEXT: ret ptr [[CALL]] +; + %call = call ptr @stpcpy(ptr %str, ptr %str) + ret ptr %call +} + +define ptr @test_2(ptr %dst) { +; CHECK-LABEL: define ptr @test_2( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: [[CALL:%.*]] = getelementptr inbounds i16, ptr [[DST]], i32 5 +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(6) [[DST]], ptr noundef nonnull align 1 dereferenceable(6) @hello, i32 6, i1 false) +; CHECK-NEXT: ret ptr [[CALL]] +; + %call = call ptr @stpcpy(ptr %dst, ptr @hello) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpcpy_chk-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpcpy_chk-b16.ll new file mode 100644 index 0000000000000..8262f94c58a39 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpcpy_chk-b16.ll @@ -0,0 +1,44 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @__stpcpy_chk(ptr, ptr, i32) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +; __stpcpy_chk(str, str, n) -> str + strlen(x) +define ptr @test_1(ptr %str, i32 %n) { +; CHECK-LABEL: define ptr @test_1( +; CHECK-SAME: ptr [[STR:%.*]], i32 [[N:%.*]]) { +; CHECK-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[STR]]) +; CHECK-NEXT: [[CALL:%.*]] = getelementptr inbounds i16, ptr [[STR]], i32 [[STRLEN]] +; CHECK-NEXT: ret ptr [[CALL]] +; + %call = call ptr @__stpcpy_chk(ptr %str, ptr %str, i32 %n) + ret ptr %call +} + +; __stpcpy_chk(dst, src, n) -> stpcpy(dst, src) +define ptr @test_2(ptr %dst) { +; CHECK-LABEL: define ptr @test_2( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: [[STPCPY:%.*]] = getelementptr inbounds i16, ptr [[DST]], i32 5 +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(6) [[DST]], ptr noundef nonnull align 1 dereferenceable(6) @hello, i32 6, i1 false) +; CHECK-NEXT: ret ptr [[STPCPY]] +; + %call = call ptr @__stpcpy_chk(ptr %dst, ptr @hello, i32 42) + ret ptr %call +} + +; __stpcpy_chk(dst, src, n) -> __memcpy_chk(dst, src, strlen(src), n), dst + strlen(src) +define ptr @test_3(ptr %dst, i32 %n) { +; CHECK-LABEL: define ptr @test_3( +; CHECK-SAME: ptr [[DST:%.*]], i32 [[N:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call ptr @__memcpy_chk(ptr [[DST]], ptr nonnull @hello, i32 6, i32 [[N]]) +; CHECK-NEXT: [[CALL:%.*]] = getelementptr inbounds i16, ptr [[DST]], i32 5 +; CHECK-NEXT: ret ptr [[CALL]] +; + %call = call ptr @__stpcpy_chk(ptr %dst, ptr @hello, i32 %n) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpncpy-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpncpy-b16.ll new file mode 100644 index 0000000000000..799ef8315ce12 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/stpncpy-b16.ll @@ -0,0 +1,47 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @stpncpy(ptr, ptr, i32) + +@empty = constant [1 x i16] [i16 0] +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +; stpncpy(dst, src, 1) -> (*dst = *src) ? dst + 1 : dst +define ptr @test_1(ptr %dst, ptr %src) { +; CHECK-LABEL: define ptr @test_1( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) { +; CHECK-NEXT: [[STXNCPY_CHAR0:%.*]] = load i16, ptr [[SRC]], align 1 +; CHECK-NEXT: store i16 [[STXNCPY_CHAR0]], ptr [[DST]], align 1 +; CHECK-NEXT: [[STPNCPY_CHAR0CMP:%.*]] = icmp ne i16 [[STXNCPY_CHAR0]], 0 +; CHECK-NEXT: [[STPNCPY_SEL_IDX:%.*]] = zext i1 [[STPNCPY_CHAR0CMP]] to i32 +; CHECK-NEXT: [[STPNCPY_SEL:%.*]] = getelementptr inbounds i16, ptr [[DST]], i32 [[STPNCPY_SEL_IDX]] +; CHECK-NEXT: ret ptr [[STPNCPY_SEL]] +; + %call = call ptr @stpncpy(ptr %dst, ptr %src, i32 1) + ret ptr %call +} + +; stpncpy(dst, "", n) -> memset(dst, '\0', n), dst +define ptr @test_2(ptr %dst, i32 %n) { +; CHECK-LABEL: define ptr @test_2( +; CHECK-SAME: ptr [[DST:%.*]], i32 [[N:%.*]]) { +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 1 [[DST]], i16 0, i32 [[N]], i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @stpncpy(ptr %dst, ptr @empty, i32 %n) + ret ptr %call +} + +; stpncpy(dst, src, n) -> memcpy(dst, src, n), dst + min(strlen(src), n) +define ptr @test_3(ptr %dst) { +; CHECK-LABEL: define ptr @test_3( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(6) [[DST]], ptr noundef nonnull align 1 dereferenceable(6) @hello, i32 6, i1 false) +; CHECK-NEXT: [[ENDPTR:%.*]] = getelementptr inbounds i16, ptr [[DST]], i32 5 +; CHECK-NEXT: ret ptr [[ENDPTR]] +; + %call = call ptr @stpncpy(ptr %dst, ptr @hello, i32 6) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcat-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcat-b16.ll new file mode 100644 index 0000000000000..643357157548c --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcat-b16.ll @@ -0,0 +1,20 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @strcat(ptr, ptr) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +define ptr @test(ptr %dst) { +; CHECK-LABEL: define ptr @test( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[DST]]) +; CHECK-NEXT: [[ENDPTR:%.*]] = getelementptr inbounds i16, ptr [[DST]], i32 [[STRLEN]] +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(6) [[ENDPTR]], ptr noundef nonnull align 1 dereferenceable(6) @hello, i32 6, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @strcat(ptr %dst, ptr @hello) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strchr-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strchr-b16.ll new file mode 100644 index 0000000000000..98c45b3bf1926 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strchr-b16.ll @@ -0,0 +1,45 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32-n64" + +declare ptr @strchr(ptr, i32) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +; strchr(str, c) == str -> (unsigned char)str[0] == (unsigned char)c +define i1 @test_1(ptr %str, i32 %c) { +; CHECK-LABEL: define i1 @test_1( +; CHECK-SAME: ptr [[STR:%.*]], i32 [[C:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = load i16, ptr [[STR]], align 1 +; CHECK-NEXT: [[TMP2:%.*]] = trunc i32 [[C]] to i16 +; CHECK-NEXT: [[CHAR0CMP:%.*]] = icmp eq i16 [[TMP1]], [[TMP2]] +; CHECK-NEXT: ret i1 [[CHAR0CMP]] +; + %call = call ptr @strchr(ptr %str, i32 %c) + %cmp = icmp eq ptr %call, %str + ret i1 %cmp +} + +; strchr(str, c) -> memchr(str, c, strlen(str) + 1) +define ptr @test_2(i32 %c) { +; CHECK-LABEL: define ptr @test_2( +; CHECK-SAME: i32 [[C:%.*]]) { +; CHECK-NEXT: [[STRCHR:%.*]] = call ptr @memchr(ptr noundef nonnull dereferenceable(1) @hello, i32 [[C]], i32 6) +; CHECK-NEXT: ret ptr [[STRCHR]] +; + %call = call ptr @strchr(ptr @hello, i32 %c) + ret ptr %call +} + +; strchr(str, '\0') -> len = strlen(str), str + len +define ptr @test_3(ptr %str) { +; CHECK-LABEL: define ptr @test_3( +; CHECK-SAME: ptr [[STR:%.*]]) { +; CHECK-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[STR]]) +; CHECK-NEXT: [[STRCHR:%.*]] = getelementptr inbounds i16, ptr [[STR]], i32 [[STRLEN]] +; CHECK-NEXT: ret ptr [[STRCHR]] +; + %call = call ptr @strchr(ptr %str, i32 0) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcmp-b32.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcmp-b32.ll new file mode 100644 index 0000000000000..d292ff4cfe514 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcmp-b32.ll @@ -0,0 +1,50 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:32-p:32:32" + +declare i32 @strcmp(ptr, ptr) + +@empty = constant [1 x i32] [i32 0] +@hello = constant [6 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 0] +@bell = constant [5 x i32] [i32 98, i32 101, i32 108, i32 108, i32 0] +@cell = constant [5 x i32] [i32 99, i32 101, i32 108, i32 108, i32 0] + +; strcmp("", rhs) -> sext(rhs[0] != '\0') +define i32 @test_1(ptr %rhs) { +; CHECK-LABEL: define i32 @test_1( +; CHECK-SAME: ptr [[RHS:%.*]]) { +; CHECK-NEXT: [[STRCMPLOAD:%.*]] = load i32, ptr [[RHS]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[STRCMPLOAD]], 0 +; CHECK-NEXT: [[CALL:%.*]] = sext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[CALL]] +; + %call = call i32 @strcmp(ptr @empty, ptr %rhs) + ret i32 %call +} + +; strcmp(lhs, "") -> zext(lhs[0] != '\0') +define i32 @test_2(ptr %lhs) { +; CHECK-LABEL: define i32 @test_2( +; CHECK-SAME: ptr [[LHS:%.*]]) { +; CHECK-NEXT: [[STRCMPLOAD:%.*]] = load i32, ptr [[LHS]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[STRCMPLOAD]], 0 +; CHECK-NEXT: [[CALL:%.*]] = zext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[CALL]] +; + %call = call i32 @strcmp(ptr %lhs, ptr @empty) + ret i32 %call +} + +; strcmp(lhs, rhs) -> memcmp(lhs, rhs, min(strlen(lhs), strlen(rhs)) + 1) +define i32 @test_3(i1 %b) { +; CHECK-LABEL: define i32 @test_3( +; CHECK-SAME: i1 [[B:%.*]]) { +; CHECK-NEXT: [[RHS:%.*]] = select i1 [[B]], ptr @bell, ptr @cell +; CHECK-NEXT: [[MEMCMP:%.*]] = call i32 @memcmp(ptr noundef nonnull dereferenceable(5) @hello, ptr noundef nonnull dereferenceable(5) [[RHS]], i32 5) +; CHECK-NEXT: ret i32 [[MEMCMP]] +; + %rhs = select i1 %b, ptr @bell, ptr @cell + %call = call i32 @strcmp(ptr @hello, ptr %rhs) + ret i32 %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcpy-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcpy-b16.ll new file mode 100644 index 0000000000000..5f718a12d5b47 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcpy-b16.ll @@ -0,0 +1,18 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @strcpy(ptr, ptr) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +define ptr @test(ptr %dst) { +; CHECK-LABEL: define ptr @test( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(6) [[DST]], ptr noundef nonnull align 1 dereferenceable(6) @hello, i32 6, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @strcpy(ptr %dst, ptr @hello) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcpy_chk-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcpy_chk-b16.ll new file mode 100644 index 0000000000000..593c65dc1c618 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strcpy_chk-b16.ll @@ -0,0 +1,30 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @__strcpy_chk(ptr, ptr, i32) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +; __strcpy_chk(dst, src, n) -> strcpy(dst, src) +define ptr @test_2(ptr %dst) { +; CHECK-LABEL: define ptr @test_2( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(6) [[DST]], ptr noundef nonnull align 1 dereferenceable(6) @hello, i32 6, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @__strcpy_chk(ptr %dst, ptr @hello, i32 42) + ret ptr %call +} + +; __strcpy_chk(dst, src, n) -> __memcpy_chk(dst, src, strlen(src), n) +define ptr @test_3(ptr %dst, i32 %n) { +; CHECK-LABEL: define ptr @test_3( +; CHECK-SAME: ptr [[DST:%.*]], i32 [[N:%.*]]) { +; CHECK-NEXT: [[TMP1:%.*]] = call ptr @__memcpy_chk(ptr [[DST]], ptr nonnull @hello, i32 6, i32 [[N]]) +; CHECK-NEXT: ret ptr [[TMP1]] +; + %call = call ptr @__strcpy_chk(ptr %dst, ptr @hello, i32 %n) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strlcpy-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strlcpy-b16.ll new file mode 100644 index 0000000000000..82e0558b28e8c --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strlcpy-b16.ll @@ -0,0 +1,18 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare i32 @strlcpy(ptr, ptr, i32) + +; strlcpy(dst, src, 1) -> *dst = 0, strlen(src) +define i32 @test_1(ptr %dst, ptr %src) { +; CHECK-LABEL: define i32 @test_1( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) { +; CHECK-NEXT: store i16 0, ptr [[DST]], align 1 +; CHECK-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[SRC]]) +; CHECK-NEXT: ret i32 [[STRLEN]] +; + %call = call i32 @strlcpy(ptr %dst, ptr %src, i32 1) + ret i32 %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strlen-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strlen-b16.ll new file mode 100644 index 0000000000000..228802c7ee607 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strlen-b16.ll @@ -0,0 +1,16 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare i32 @strlen(ptr) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +define i32 @test() { +; CHECK-LABEL: define i32 @test() { +; CHECK-NEXT: ret i32 5 +; + %call = call i32 @strlen(ptr @hello) + ret i32 %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncat-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncat-b16.ll new file mode 100644 index 0000000000000..d6fddabe91426 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncat-b16.ll @@ -0,0 +1,20 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @strncat(ptr, ptr, i32) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +define ptr @test(ptr %dst) { +; CHECK-LABEL: define ptr @test( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: [[STRLEN:%.*]] = call i32 @strlen(ptr noundef nonnull dereferenceable(1) [[DST]]) +; CHECK-NEXT: [[ENDPTR:%.*]] = getelementptr inbounds i16, ptr [[DST]], i32 [[STRLEN]] +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(6) [[ENDPTR]], ptr noundef nonnull align 1 dereferenceable(6) @hello, i32 6, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @strncat(ptr %dst, ptr @hello, i32 42) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncmp-b32.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncmp-b32.ll new file mode 100644 index 0000000000000..1363af4965969 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncmp-b32.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:32-p:32:32" + +declare i32 @strncmp(ptr, ptr, i32) + +@empty = constant [1 x i32] [i32 0] + +; strncmp("", rhs, n) -> sext(rhs[0] != '\0') +define i32 @test_1(ptr %rhs) { +; CHECK-LABEL: define i32 @test_1( +; CHECK-SAME: ptr [[RHS:%.*]]) { +; CHECK-NEXT: [[STRCMPLOAD:%.*]] = load i32, ptr [[RHS]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[STRCMPLOAD]], 0 +; CHECK-NEXT: [[CALL:%.*]] = sext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[CALL]] +; + %call = call i32 @strncmp(ptr @empty, ptr %rhs, i32 42) + ret i32 %call +} + +; strncmp(lhs, "", n) -> zext(lhs[0] != '\0') +define i32 @test_2(ptr %lhs) { +; CHECK-LABEL: define i32 @test_2( +; CHECK-SAME: ptr [[LHS:%.*]]) { +; CHECK-NEXT: [[STRCMPLOAD:%.*]] = load i32, ptr [[LHS]], align 1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i32 [[STRCMPLOAD]], 0 +; CHECK-NEXT: [[CALL:%.*]] = zext i1 [[TMP1]] to i32 +; CHECK-NEXT: ret i32 [[CALL]] +; + %call = call i32 @strncmp(ptr %lhs, ptr @empty, i32 42) + ret i32 %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncpy-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncpy-b16.ll new file mode 100644 index 0000000000000..ca8ff2bea59a7 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strncpy-b16.ll @@ -0,0 +1,43 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @strncpy(ptr, ptr, i32) + +@empty = constant [1 x i16] [i16 0] +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +; strncpy(dst, src, 1) -> (*dst = *src), dst +define ptr @test_1(ptr %dst, ptr %src) { +; CHECK-LABEL: define ptr @test_1( +; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]]) { +; CHECK-NEXT: [[STXNCPY_CHAR0:%.*]] = load i16, ptr [[SRC]], align 1 +; CHECK-NEXT: store i16 [[STXNCPY_CHAR0]], ptr [[DST]], align 1 +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @strncpy(ptr %dst, ptr %src, i32 1) + ret ptr %call +} + +; strncpy(dst, "", n) -> memset(dst, '\0', n), dst +define ptr @test_2(ptr %dst, i32 %n) { +; CHECK-LABEL: define ptr @test_2( +; CHECK-SAME: ptr [[DST:%.*]], i32 [[N:%.*]]) { +; CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 1 [[DST]], i16 0, i32 [[N]], i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @strncpy(ptr %dst, ptr @empty, i32 %n) + ret ptr %call +} + +; strncpy(dst, src, n) -> memcpy(dst, src, n), dst +define ptr @test_3(ptr %dst) { +; CHECK-LABEL: define ptr @test_3( +; CHECK-SAME: ptr [[DST:%.*]]) { +; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr noundef nonnull align 1 dereferenceable(6) [[DST]], ptr noundef nonnull align 1 dereferenceable(6) @hello, i32 6, i1 false) +; CHECK-NEXT: ret ptr [[DST]] +; + %call = call ptr @strncpy(ptr %dst, ptr @hello, i32 6) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strndup-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strndup-b16.ll new file mode 100644 index 0000000000000..8294bf668f454 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strndup-b16.ll @@ -0,0 +1,17 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare ptr @strndup(ptr, i32) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +define ptr @test() { +; CHECK-LABEL: define ptr @test() { +; CHECK-NEXT: [[STRDUP:%.*]] = call dereferenceable_or_null(6) ptr @strdup(ptr nonnull @hello) +; CHECK-NEXT: ret ptr [[STRDUP]] +; + %call = call ptr @strndup(ptr @hello, i32 6) + ret ptr %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strnlen-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strnlen-b16.ll new file mode 100644 index 0000000000000..641022838ff7a --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/strnlen-b16.ll @@ -0,0 +1,18 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare i32 @strnlen(ptr, i32) + +@hello = constant [6 x i16] [i16 104, i16 101, i16 108, i16 108, i16 111, i16 0] + +define i32 @test(i32 %n) { +; CHECK-LABEL: define i32 @test( +; CHECK-SAME: i32 [[N:%.*]]) { +; CHECK-NEXT: [[CALL:%.*]] = call i32 @llvm.umin.i32(i32 [[N]], i32 5) +; CHECK-NEXT: ret i32 [[CALL]] +; + %call = call i32 @strnlen(ptr @hello, i32 %n) + ret i32 %call +} diff --git a/llvm/test/Transforms/InstCombine/SimplifyLibCalls/wcslen-b16.ll b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/wcslen-b16.ll new file mode 100644 index 0000000000000..5cb31257336b5 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/SimplifyLibCalls/wcslen-b16.ll @@ -0,0 +1,19 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -p instcombine -S %s | FileCheck %s + +target datalayout = "b:16-p:32:32" + +declare i32 @wcslen(ptr) + +@hello = constant [6 x i32] [i32 104, i32 101, i32 108, i32 108, i32 111, i32 0] + +define i32 @test() { +; CHECK-LABEL: define i32 @test() { +; CHECK-NEXT: ret i32 5 +; + %call = call i32 @wcslen(ptr @hello) + ret i32 %call +} + +!0 = !{i32 1, !"wchar_size", i32 2} +!llvm.module.flags = !{!0} diff --git a/llvm/test/Transforms/InstCombine/bcmp-1.ll b/llvm/test/Transforms/InstCombine/bcmp-1.ll index 73daae44d020d..b62adcd4f0385 100644 --- a/llvm/test/Transforms/InstCombine/bcmp-1.ll +++ b/llvm/test/Transforms/InstCombine/bcmp-1.ll @@ -36,8 +36,8 @@ define i32 @test_simplify2(ptr %mem1, ptr %mem2) { define i32 @test_simplify3(ptr %mem1, ptr %mem2) { ; CHECK-LABEL: @test_simplify3( ; CHECK-NEXT: [[LHSC:%.*]] = load i8, ptr [[MEM1:%.*]], align 1 -; CHECK-NEXT: [[LHSV:%.*]] = zext i8 [[LHSC]] to i32 ; CHECK-NEXT: [[RHSC:%.*]] = load i8, ptr [[MEM2:%.*]], align 1 +; CHECK-NEXT: [[LHSV:%.*]] = zext i8 [[LHSC]] to i32 ; CHECK-NEXT: [[RHSV:%.*]] = zext i8 [[RHSC]] to i32 ; CHECK-NEXT: [[CHARDIFF:%.*]] = sub nsw i32 [[LHSV]], [[RHSV]] ; CHECK-NEXT: ret i32 [[CHARDIFF]] diff --git a/llvm/test/Transforms/InstCombine/memcmp-1.ll b/llvm/test/Transforms/InstCombine/memcmp-1.ll index 054896647b518..956cb39c08da1 100644 --- a/llvm/test/Transforms/InstCombine/memcmp-1.ll +++ b/llvm/test/Transforms/InstCombine/memcmp-1.ll @@ -36,8 +36,8 @@ define i32 @test_simplify2(ptr %mem1, ptr %mem2) { define i32 @test_simplify3(ptr %mem1, ptr %mem2) { ; CHECK-LABEL: @test_simplify3( ; CHECK-NEXT: [[LHSC:%.*]] = load i8, ptr %mem1, align 1 -; CHECK-NEXT: [[LHSV:%.*]] = zext i8 [[LHSC]] to i32 ; CHECK-NEXT: [[RHSC:%.*]] = load i8, ptr %mem2, align 1 +; CHECK-NEXT: [[LHSV:%.*]] = zext i8 [[LHSC]] to i32 ; CHECK-NEXT: [[RHSV:%.*]] = zext i8 [[RHSC]] to i32 ; CHECK-NEXT: [[CHARDIFF:%.*]] = sub nsw i32 [[LHSV]], [[RHSV]] ; CHECK-NEXT: ret i32 [[CHARDIFF]] diff --git a/llvm/test/Transforms/InstCombine/strncmp-1.ll b/llvm/test/Transforms/InstCombine/strncmp-1.ll index 9a33b85a4049c..d5e11ca8da1f2 100644 --- a/llvm/test/Transforms/InstCombine/strncmp-1.ll +++ b/llvm/test/Transforms/InstCombine/strncmp-1.ll @@ -68,8 +68,8 @@ define i32 @test5() { define i32 @test6(ptr %str1, ptr %str2) { ; CHECK-LABEL: @test6( ; CHECK-NEXT: [[LHSC:%.*]] = load i8, ptr [[STR1:%.*]], align 1 -; CHECK-NEXT: [[LHSV:%.*]] = zext i8 [[LHSC]] to i32 ; CHECK-NEXT: [[RHSC:%.*]] = load i8, ptr [[STR2:%.*]], align 1 +; CHECK-NEXT: [[LHSV:%.*]] = zext i8 [[LHSC]] to i32 ; CHECK-NEXT: [[RHSV:%.*]] = zext i8 [[RHSC]] to i32 ; CHECK-NEXT: [[CHARDIFF:%.*]] = sub nsw i32 [[LHSV]], [[RHSV]] ; CHECK-NEXT: ret i32 [[CHARDIFF]] _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits