12cab237bSDimitry Andric //===--- ExpandMemCmp.cpp - Expand memcmp() to load/stores ----------------===//
22cab237bSDimitry Andric //
32cab237bSDimitry Andric //                     The LLVM Compiler Infrastructure
42cab237bSDimitry Andric //
52cab237bSDimitry Andric // This file is distributed under the University of Illinois Open Source
62cab237bSDimitry Andric // License. See LICENSE.TXT for details.
72cab237bSDimitry Andric //
82cab237bSDimitry Andric //===----------------------------------------------------------------------===//
92cab237bSDimitry Andric //
102cab237bSDimitry Andric // This pass tries to expand memcmp() calls into optimally-sized loads and
112cab237bSDimitry Andric // compares for the target.
122cab237bSDimitry Andric //
132cab237bSDimitry Andric //===----------------------------------------------------------------------===//
142cab237bSDimitry Andric 
152cab237bSDimitry Andric #include "llvm/ADT/Statistic.h"
162cab237bSDimitry Andric #include "llvm/Analysis/ConstantFolding.h"
172cab237bSDimitry Andric #include "llvm/Analysis/TargetLibraryInfo.h"
182cab237bSDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
192cab237bSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
202cab237bSDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
212cab237bSDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
222cab237bSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
232cab237bSDimitry Andric #include "llvm/IR/IRBuilder.h"
242cab237bSDimitry Andric 
252cab237bSDimitry Andric using namespace llvm;
262cab237bSDimitry Andric 
272cab237bSDimitry Andric #define DEBUG_TYPE "expandmemcmp"
282cab237bSDimitry Andric 
292cab237bSDimitry Andric STATISTIC(NumMemCmpCalls, "Number of memcmp calls");
302cab237bSDimitry Andric STATISTIC(NumMemCmpNotConstant, "Number of memcmp calls without constant size");
312cab237bSDimitry Andric STATISTIC(NumMemCmpGreaterThanMax,
322cab237bSDimitry Andric           "Number of memcmp calls with size greater than max size");
332cab237bSDimitry Andric STATISTIC(NumMemCmpInlined, "Number of inlined memcmp calls");
342cab237bSDimitry Andric 
352cab237bSDimitry Andric static cl::opt<unsigned> MemCmpNumLoadsPerBlock(
362cab237bSDimitry Andric     "memcmp-num-loads-per-block", cl::Hidden, cl::init(1),
372cab237bSDimitry Andric     cl::desc("The number of loads per basic block for inline expansion of "
382cab237bSDimitry Andric              "memcmp that is only being compared against zero."));
392cab237bSDimitry Andric 
402cab237bSDimitry Andric namespace {
412cab237bSDimitry Andric 
422cab237bSDimitry Andric 
432cab237bSDimitry Andric // This class provides helper functions to expand a memcmp library call into an
442cab237bSDimitry Andric // inline expansion.
452cab237bSDimitry Andric class MemCmpExpansion {
462cab237bSDimitry Andric   struct ResultBlock {
472cab237bSDimitry Andric     BasicBlock *BB = nullptr;
482cab237bSDimitry Andric     PHINode *PhiSrc1 = nullptr;
492cab237bSDimitry Andric     PHINode *PhiSrc2 = nullptr;
502cab237bSDimitry Andric 
512cab237bSDimitry Andric     ResultBlock() = default;
522cab237bSDimitry Andric   };
532cab237bSDimitry Andric 
542cab237bSDimitry Andric   CallInst *const CI;
552cab237bSDimitry Andric   ResultBlock ResBlock;
562cab237bSDimitry Andric   const uint64_t Size;
572cab237bSDimitry Andric   unsigned MaxLoadSize;
582cab237bSDimitry Andric   uint64_t NumLoadsNonOneByte;
592cab237bSDimitry Andric   const uint64_t NumLoadsPerBlock;
602cab237bSDimitry Andric   std::vector<BasicBlock *> LoadCmpBlocks;
612cab237bSDimitry Andric   BasicBlock *EndBlock;
622cab237bSDimitry Andric   PHINode *PhiRes;
632cab237bSDimitry Andric   const bool IsUsedForZeroCmp;
642cab237bSDimitry Andric   const DataLayout &DL;
652cab237bSDimitry Andric   IRBuilder<> Builder;
662cab237bSDimitry Andric   // Represents the decomposition in blocks of the expansion. For example,
672cab237bSDimitry Andric   // comparing 33 bytes on X86+sse can be done with 2x16-byte loads and
682cab237bSDimitry Andric   // 1x1-byte load, which would be represented as [{16, 0}, {16, 16}, {32, 1}.
692cab237bSDimitry Andric   // TODO(courbet): Involve the target more in this computation. On X86, 7
702cab237bSDimitry Andric   // bytes can be done more efficiently with two overlaping 4-byte loads than
712cab237bSDimitry Andric   // covering the interval with [{4, 0},{2, 4},{1, 6}}.
722cab237bSDimitry Andric   struct LoadEntry {
732cab237bSDimitry Andric     LoadEntry(unsigned LoadSize, uint64_t Offset)
742cab237bSDimitry Andric         : LoadSize(LoadSize), Offset(Offset) {
752cab237bSDimitry Andric       assert(Offset % LoadSize == 0 && "invalid load entry");
762cab237bSDimitry Andric     }
772cab237bSDimitry Andric 
782cab237bSDimitry Andric     uint64_t getGEPIndex() const { return Offset / LoadSize; }
792cab237bSDimitry Andric 
802cab237bSDimitry Andric     // The size of the load for this block, in bytes.
812cab237bSDimitry Andric     const unsigned LoadSize;
822cab237bSDimitry Andric     // The offset of this load WRT the base pointer, in bytes.
832cab237bSDimitry Andric     const uint64_t Offset;
842cab237bSDimitry Andric   };
852cab237bSDimitry Andric   SmallVector<LoadEntry, 8> LoadSequence;
862cab237bSDimitry Andric 
872cab237bSDimitry Andric   void createLoadCmpBlocks();
882cab237bSDimitry Andric   void createResultBlock();
892cab237bSDimitry Andric   void setupResultBlockPHINodes();
902cab237bSDimitry Andric   void setupEndBlockPHINodes();
912cab237bSDimitry Andric   Value *getCompareLoadPairs(unsigned BlockIndex, unsigned &LoadIndex);
922cab237bSDimitry Andric   void emitLoadCompareBlock(unsigned BlockIndex);
932cab237bSDimitry Andric   void emitLoadCompareBlockMultipleLoads(unsigned BlockIndex,
942cab237bSDimitry Andric                                          unsigned &LoadIndex);
952cab237bSDimitry Andric   void emitLoadCompareByteBlock(unsigned BlockIndex, unsigned GEPIndex);
962cab237bSDimitry Andric   void emitMemCmpResultBlock();
972cab237bSDimitry Andric   Value *getMemCmpExpansionZeroCase();
982cab237bSDimitry Andric   Value *getMemCmpEqZeroOneBlock();
992cab237bSDimitry Andric   Value *getMemCmpOneBlock();
1002cab237bSDimitry Andric 
1012cab237bSDimitry Andric  public:
1022cab237bSDimitry Andric   MemCmpExpansion(CallInst *CI, uint64_t Size,
1032cab237bSDimitry Andric                   const TargetTransformInfo::MemCmpExpansionOptions &Options,
1042cab237bSDimitry Andric                   unsigned MaxNumLoads, const bool IsUsedForZeroCmp,
1052cab237bSDimitry Andric                   unsigned NumLoadsPerBlock, const DataLayout &DL);
1062cab237bSDimitry Andric 
1072cab237bSDimitry Andric   unsigned getNumBlocks();
1082cab237bSDimitry Andric   uint64_t getNumLoads() const { return LoadSequence.size(); }
1092cab237bSDimitry Andric 
1102cab237bSDimitry Andric   Value *getMemCmpExpansion();
1112cab237bSDimitry Andric };
1122cab237bSDimitry Andric 
1132cab237bSDimitry Andric // Initialize the basic block structure required for expansion of memcmp call
1142cab237bSDimitry Andric // with given maximum load size and memcmp size parameter.
1152cab237bSDimitry Andric // This structure includes:
1162cab237bSDimitry Andric // 1. A list of load compare blocks - LoadCmpBlocks.
1172cab237bSDimitry Andric // 2. An EndBlock, split from original instruction point, which is the block to
1182cab237bSDimitry Andric // return from.
1192cab237bSDimitry Andric // 3. ResultBlock, block to branch to for early exit when a
1202cab237bSDimitry Andric // LoadCmpBlock finds a difference.
1212cab237bSDimitry Andric MemCmpExpansion::MemCmpExpansion(
1222cab237bSDimitry Andric     CallInst *const CI, uint64_t Size,
1232cab237bSDimitry Andric     const TargetTransformInfo::MemCmpExpansionOptions &Options,
1242cab237bSDimitry Andric     const unsigned MaxNumLoads, const bool IsUsedForZeroCmp,
1252cab237bSDimitry Andric     const unsigned NumLoadsPerBlock, const DataLayout &TheDataLayout)
1262cab237bSDimitry Andric     : CI(CI),
1272cab237bSDimitry Andric       Size(Size),
1282cab237bSDimitry Andric       MaxLoadSize(0),
1292cab237bSDimitry Andric       NumLoadsNonOneByte(0),
1302cab237bSDimitry Andric       NumLoadsPerBlock(NumLoadsPerBlock),
1312cab237bSDimitry Andric       IsUsedForZeroCmp(IsUsedForZeroCmp),
1322cab237bSDimitry Andric       DL(TheDataLayout),
1332cab237bSDimitry Andric       Builder(CI) {
1342cab237bSDimitry Andric   assert(Size > 0 && "zero blocks");
1352cab237bSDimitry Andric   // Scale the max size down if the target can load more bytes than we need.
1362cab237bSDimitry Andric   size_t LoadSizeIndex = 0;
1372cab237bSDimitry Andric   while (LoadSizeIndex < Options.LoadSizes.size() &&
1382cab237bSDimitry Andric          Options.LoadSizes[LoadSizeIndex] > Size) {
1392cab237bSDimitry Andric     ++LoadSizeIndex;
1402cab237bSDimitry Andric   }
1412cab237bSDimitry Andric   this->MaxLoadSize = Options.LoadSizes[LoadSizeIndex];
1422cab237bSDimitry Andric   // Compute the decomposition.
1432cab237bSDimitry Andric   uint64_t CurSize = Size;
1442cab237bSDimitry Andric   uint64_t Offset = 0;
1452cab237bSDimitry Andric   while (CurSize && LoadSizeIndex < Options.LoadSizes.size()) {
1462cab237bSDimitry Andric     const unsigned LoadSize = Options.LoadSizes[LoadSizeIndex];
1472cab237bSDimitry Andric     assert(LoadSize > 0 && "zero load size");
1482cab237bSDimitry Andric     const uint64_t NumLoadsForThisSize = CurSize / LoadSize;
1492cab237bSDimitry Andric     if (LoadSequence.size() + NumLoadsForThisSize > MaxNumLoads) {
1502cab237bSDimitry Andric       // Do not expand if the total number of loads is larger than what the
1512cab237bSDimitry Andric       // target allows. Note that it's important that we exit before completing
1522cab237bSDimitry Andric       // the expansion to avoid using a ton of memory to store the expansion for
1532cab237bSDimitry Andric       // large sizes.
1542cab237bSDimitry Andric       LoadSequence.clear();
1552cab237bSDimitry Andric       return;
1562cab237bSDimitry Andric     }
1572cab237bSDimitry Andric     if (NumLoadsForThisSize > 0) {
1582cab237bSDimitry Andric       for (uint64_t I = 0; I < NumLoadsForThisSize; ++I) {
1592cab237bSDimitry Andric         LoadSequence.push_back({LoadSize, Offset});
1602cab237bSDimitry Andric         Offset += LoadSize;
1612cab237bSDimitry Andric       }
1622cab237bSDimitry Andric       if (LoadSize > 1) {
1632cab237bSDimitry Andric         ++NumLoadsNonOneByte;
1642cab237bSDimitry Andric       }
1652cab237bSDimitry Andric       CurSize = CurSize % LoadSize;
1662cab237bSDimitry Andric     }
1672cab237bSDimitry Andric     ++LoadSizeIndex;
1682cab237bSDimitry Andric   }
1692cab237bSDimitry Andric   assert(LoadSequence.size() <= MaxNumLoads && "broken invariant");
1702cab237bSDimitry Andric }
1712cab237bSDimitry Andric 
1722cab237bSDimitry Andric unsigned MemCmpExpansion::getNumBlocks() {
1732cab237bSDimitry Andric   if (IsUsedForZeroCmp)
1742cab237bSDimitry Andric     return getNumLoads() / NumLoadsPerBlock +
1752cab237bSDimitry Andric            (getNumLoads() % NumLoadsPerBlock != 0 ? 1 : 0);
1762cab237bSDimitry Andric   return getNumLoads();
1772cab237bSDimitry Andric }
1782cab237bSDimitry Andric 
1792cab237bSDimitry Andric void MemCmpExpansion::createLoadCmpBlocks() {
1802cab237bSDimitry Andric   for (unsigned i = 0; i < getNumBlocks(); i++) {
1812cab237bSDimitry Andric     BasicBlock *BB = BasicBlock::Create(CI->getContext(), "loadbb",
1822cab237bSDimitry Andric                                         EndBlock->getParent(), EndBlock);
1832cab237bSDimitry Andric     LoadCmpBlocks.push_back(BB);
1842cab237bSDimitry Andric   }
1852cab237bSDimitry Andric }
1862cab237bSDimitry Andric 
1872cab237bSDimitry Andric void MemCmpExpansion::createResultBlock() {
1882cab237bSDimitry Andric   ResBlock.BB = BasicBlock::Create(CI->getContext(), "res_block",
1892cab237bSDimitry Andric                                    EndBlock->getParent(), EndBlock);
1902cab237bSDimitry Andric }
1912cab237bSDimitry Andric 
1922cab237bSDimitry Andric // This function creates the IR instructions for loading and comparing 1 byte.
1932cab237bSDimitry Andric // It loads 1 byte from each source of the memcmp parameters with the given
1942cab237bSDimitry Andric // GEPIndex. It then subtracts the two loaded values and adds this result to the
1952cab237bSDimitry Andric // final phi node for selecting the memcmp result.
1962cab237bSDimitry Andric void MemCmpExpansion::emitLoadCompareByteBlock(unsigned BlockIndex,
1972cab237bSDimitry Andric                                                unsigned GEPIndex) {
1982cab237bSDimitry Andric   Value *Source1 = CI->getArgOperand(0);
1992cab237bSDimitry Andric   Value *Source2 = CI->getArgOperand(1);
2002cab237bSDimitry Andric 
2012cab237bSDimitry Andric   Builder.SetInsertPoint(LoadCmpBlocks[BlockIndex]);
2022cab237bSDimitry Andric   Type *LoadSizeType = Type::getInt8Ty(CI->getContext());
2032cab237bSDimitry Andric   // Cast source to LoadSizeType*.
2042cab237bSDimitry Andric   if (Source1->getType() != LoadSizeType)
2052cab237bSDimitry Andric     Source1 = Builder.CreateBitCast(Source1, LoadSizeType->getPointerTo());
2062cab237bSDimitry Andric   if (Source2->getType() != LoadSizeType)
2072cab237bSDimitry Andric     Source2 = Builder.CreateBitCast(Source2, LoadSizeType->getPointerTo());
2082cab237bSDimitry Andric 
2092cab237bSDimitry Andric   // Get the base address using the GEPIndex.
2102cab237bSDimitry Andric   if (GEPIndex != 0) {
2112cab237bSDimitry Andric     Source1 = Builder.CreateGEP(LoadSizeType, Source1,
2122cab237bSDimitry Andric                                 ConstantInt::get(LoadSizeType, GEPIndex));
2132cab237bSDimitry Andric     Source2 = Builder.CreateGEP(LoadSizeType, Source2,
2142cab237bSDimitry Andric                                 ConstantInt::get(LoadSizeType, GEPIndex));
2152cab237bSDimitry Andric   }
2162cab237bSDimitry Andric 
2172cab237bSDimitry Andric   Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
2182cab237bSDimitry Andric   Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
2192cab237bSDimitry Andric 
2202cab237bSDimitry Andric   LoadSrc1 = Builder.CreateZExt(LoadSrc1, Type::getInt32Ty(CI->getContext()));
2212cab237bSDimitry Andric   LoadSrc2 = Builder.CreateZExt(LoadSrc2, Type::getInt32Ty(CI->getContext()));
2222cab237bSDimitry Andric   Value *Diff = Builder.CreateSub(LoadSrc1, LoadSrc2);
2232cab237bSDimitry Andric 
2242cab237bSDimitry Andric   PhiRes->addIncoming(Diff, LoadCmpBlocks[BlockIndex]);
2252cab237bSDimitry Andric 
2262cab237bSDimitry Andric   if (BlockIndex < (LoadCmpBlocks.size() - 1)) {
2272cab237bSDimitry Andric     // Early exit branch if difference found to EndBlock. Otherwise, continue to
2282cab237bSDimitry Andric     // next LoadCmpBlock,
2292cab237bSDimitry Andric     Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_NE, Diff,
2302cab237bSDimitry Andric                                     ConstantInt::get(Diff->getType(), 0));
2312cab237bSDimitry Andric     BranchInst *CmpBr =
2322cab237bSDimitry Andric         BranchInst::Create(EndBlock, LoadCmpBlocks[BlockIndex + 1], Cmp);
2332cab237bSDimitry Andric     Builder.Insert(CmpBr);
2342cab237bSDimitry Andric   } else {
2352cab237bSDimitry Andric     // The last block has an unconditional branch to EndBlock.
2362cab237bSDimitry Andric     BranchInst *CmpBr = BranchInst::Create(EndBlock);
2372cab237bSDimitry Andric     Builder.Insert(CmpBr);
2382cab237bSDimitry Andric   }
2392cab237bSDimitry Andric }
2402cab237bSDimitry Andric 
2412cab237bSDimitry Andric /// Generate an equality comparison for one or more pairs of loaded values.
2422cab237bSDimitry Andric /// This is used in the case where the memcmp() call is compared equal or not
2432cab237bSDimitry Andric /// equal to zero.
2442cab237bSDimitry Andric Value *MemCmpExpansion::getCompareLoadPairs(unsigned BlockIndex,
2452cab237bSDimitry Andric                                             unsigned &LoadIndex) {
2462cab237bSDimitry Andric   assert(LoadIndex < getNumLoads() &&
2472cab237bSDimitry Andric          "getCompareLoadPairs() called with no remaining loads");
2482cab237bSDimitry Andric   std::vector<Value *> XorList, OrList;
2492cab237bSDimitry Andric   Value *Diff;
2502cab237bSDimitry Andric 
2512cab237bSDimitry Andric   const unsigned NumLoads =
2522cab237bSDimitry Andric       std::min(getNumLoads() - LoadIndex, NumLoadsPerBlock);
2532cab237bSDimitry Andric 
2542cab237bSDimitry Andric   // For a single-block expansion, start inserting before the memcmp call.
2552cab237bSDimitry Andric   if (LoadCmpBlocks.empty())
2562cab237bSDimitry Andric     Builder.SetInsertPoint(CI);
2572cab237bSDimitry Andric   else
2582cab237bSDimitry Andric     Builder.SetInsertPoint(LoadCmpBlocks[BlockIndex]);
2592cab237bSDimitry Andric 
2602cab237bSDimitry Andric   Value *Cmp = nullptr;
2612cab237bSDimitry Andric   // If we have multiple loads per block, we need to generate a composite
2622cab237bSDimitry Andric   // comparison using xor+or. The type for the combinations is the largest load
2632cab237bSDimitry Andric   // type.
2642cab237bSDimitry Andric   IntegerType *const MaxLoadType =
2652cab237bSDimitry Andric       NumLoads == 1 ? nullptr
2662cab237bSDimitry Andric                     : IntegerType::get(CI->getContext(), MaxLoadSize * 8);
2672cab237bSDimitry Andric   for (unsigned i = 0; i < NumLoads; ++i, ++LoadIndex) {
2682cab237bSDimitry Andric     const LoadEntry &CurLoadEntry = LoadSequence[LoadIndex];
2692cab237bSDimitry Andric 
2702cab237bSDimitry Andric     IntegerType *LoadSizeType =
2712cab237bSDimitry Andric         IntegerType::get(CI->getContext(), CurLoadEntry.LoadSize * 8);
2722cab237bSDimitry Andric 
2732cab237bSDimitry Andric     Value *Source1 = CI->getArgOperand(0);
2742cab237bSDimitry Andric     Value *Source2 = CI->getArgOperand(1);
2752cab237bSDimitry Andric 
2762cab237bSDimitry Andric     // Cast source to LoadSizeType*.
2772cab237bSDimitry Andric     if (Source1->getType() != LoadSizeType)
2782cab237bSDimitry Andric       Source1 = Builder.CreateBitCast(Source1, LoadSizeType->getPointerTo());
2792cab237bSDimitry Andric     if (Source2->getType() != LoadSizeType)
2802cab237bSDimitry Andric       Source2 = Builder.CreateBitCast(Source2, LoadSizeType->getPointerTo());
2812cab237bSDimitry Andric 
2822cab237bSDimitry Andric     // Get the base address using a GEP.
2832cab237bSDimitry Andric     if (CurLoadEntry.Offset != 0) {
2842cab237bSDimitry Andric       Source1 = Builder.CreateGEP(
2852cab237bSDimitry Andric           LoadSizeType, Source1,
2862cab237bSDimitry Andric           ConstantInt::get(LoadSizeType, CurLoadEntry.getGEPIndex()));
2872cab237bSDimitry Andric       Source2 = Builder.CreateGEP(
2882cab237bSDimitry Andric           LoadSizeType, Source2,
2892cab237bSDimitry Andric           ConstantInt::get(LoadSizeType, CurLoadEntry.getGEPIndex()));
2902cab237bSDimitry Andric     }
2912cab237bSDimitry Andric 
2922cab237bSDimitry Andric     // Get a constant or load a value for each source address.
2932cab237bSDimitry Andric     Value *LoadSrc1 = nullptr;
2942cab237bSDimitry Andric     if (auto *Source1C = dyn_cast<Constant>(Source1))
2952cab237bSDimitry Andric       LoadSrc1 = ConstantFoldLoadFromConstPtr(Source1C, LoadSizeType, DL);
2962cab237bSDimitry Andric     if (!LoadSrc1)
2972cab237bSDimitry Andric       LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
2982cab237bSDimitry Andric 
2992cab237bSDimitry Andric     Value *LoadSrc2 = nullptr;
3002cab237bSDimitry Andric     if (auto *Source2C = dyn_cast<Constant>(Source2))
3012cab237bSDimitry Andric       LoadSrc2 = ConstantFoldLoadFromConstPtr(Source2C, LoadSizeType, DL);
3022cab237bSDimitry Andric     if (!LoadSrc2)
3032cab237bSDimitry Andric       LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
3042cab237bSDimitry Andric 
3052cab237bSDimitry Andric     if (NumLoads != 1) {
3062cab237bSDimitry Andric       if (LoadSizeType != MaxLoadType) {
3072cab237bSDimitry Andric         LoadSrc1 = Builder.CreateZExt(LoadSrc1, MaxLoadType);
3082cab237bSDimitry Andric         LoadSrc2 = Builder.CreateZExt(LoadSrc2, MaxLoadType);
3092cab237bSDimitry Andric       }
3102cab237bSDimitry Andric       // If we have multiple loads per block, we need to generate a composite
3112cab237bSDimitry Andric       // comparison using xor+or.
3122cab237bSDimitry Andric       Diff = Builder.CreateXor(LoadSrc1, LoadSrc2);
3132cab237bSDimitry Andric       Diff = Builder.CreateZExt(Diff, MaxLoadType);
3142cab237bSDimitry Andric       XorList.push_back(Diff);
3152cab237bSDimitry Andric     } else {
3162cab237bSDimitry Andric       // If there's only one load per block, we just compare the loaded values.
3172cab237bSDimitry Andric       Cmp = Builder.CreateICmpNE(LoadSrc1, LoadSrc2);
3182cab237bSDimitry Andric     }
3192cab237bSDimitry Andric   }
3202cab237bSDimitry Andric 
3212cab237bSDimitry Andric   auto pairWiseOr = [&](std::vector<Value *> &InList) -> std::vector<Value *> {
3222cab237bSDimitry Andric     std::vector<Value *> OutList;
3232cab237bSDimitry Andric     for (unsigned i = 0; i < InList.size() - 1; i = i + 2) {
3242cab237bSDimitry Andric       Value *Or = Builder.CreateOr(InList[i], InList[i + 1]);
3252cab237bSDimitry Andric       OutList.push_back(Or);
3262cab237bSDimitry Andric     }
3272cab237bSDimitry Andric     if (InList.size() % 2 != 0)
3282cab237bSDimitry Andric       OutList.push_back(InList.back());
3292cab237bSDimitry Andric     return OutList;
3302cab237bSDimitry Andric   };
3312cab237bSDimitry Andric 
3322cab237bSDimitry Andric   if (!Cmp) {
3332cab237bSDimitry Andric     // Pairwise OR the XOR results.
3342cab237bSDimitry Andric     OrList = pairWiseOr(XorList);
3352cab237bSDimitry Andric 
3362cab237bSDimitry Andric     // Pairwise OR the OR results until one result left.
3372cab237bSDimitry Andric     while (OrList.size() != 1) {
3382cab237bSDimitry Andric       OrList = pairWiseOr(OrList);
3392cab237bSDimitry Andric     }
3402cab237bSDimitry Andric     Cmp = Builder.CreateICmpNE(OrList[0], ConstantInt::get(Diff->getType(), 0));
3412cab237bSDimitry Andric   }
3422cab237bSDimitry Andric 
3432cab237bSDimitry Andric   return Cmp;
3442cab237bSDimitry Andric }
3452cab237bSDimitry Andric 
3462cab237bSDimitry Andric void MemCmpExpansion::emitLoadCompareBlockMultipleLoads(unsigned BlockIndex,
3472cab237bSDimitry Andric                                                         unsigned &LoadIndex) {
3482cab237bSDimitry Andric   Value *Cmp = getCompareLoadPairs(BlockIndex, LoadIndex);
3492cab237bSDimitry Andric 
3502cab237bSDimitry Andric   BasicBlock *NextBB = (BlockIndex == (LoadCmpBlocks.size() - 1))
3512cab237bSDimitry Andric                            ? EndBlock
3522cab237bSDimitry Andric                            : LoadCmpBlocks[BlockIndex + 1];
3532cab237bSDimitry Andric   // Early exit branch if difference found to ResultBlock. Otherwise,
3542cab237bSDimitry Andric   // continue to next LoadCmpBlock or EndBlock.
3552cab237bSDimitry Andric   BranchInst *CmpBr = BranchInst::Create(ResBlock.BB, NextBB, Cmp);
3562cab237bSDimitry Andric   Builder.Insert(CmpBr);
3572cab237bSDimitry Andric 
3582cab237bSDimitry Andric   // Add a phi edge for the last LoadCmpBlock to Endblock with a value of 0
3592cab237bSDimitry Andric   // since early exit to ResultBlock was not taken (no difference was found in
3602cab237bSDimitry Andric   // any of the bytes).
3612cab237bSDimitry Andric   if (BlockIndex == LoadCmpBlocks.size() - 1) {
3622cab237bSDimitry Andric     Value *Zero = ConstantInt::get(Type::getInt32Ty(CI->getContext()), 0);
3632cab237bSDimitry Andric     PhiRes->addIncoming(Zero, LoadCmpBlocks[BlockIndex]);
3642cab237bSDimitry Andric   }
3652cab237bSDimitry Andric }
3662cab237bSDimitry Andric 
3672cab237bSDimitry Andric // This function creates the IR intructions for loading and comparing using the
3682cab237bSDimitry Andric // given LoadSize. It loads the number of bytes specified by LoadSize from each
3692cab237bSDimitry Andric // source of the memcmp parameters. It then does a subtract to see if there was
3702cab237bSDimitry Andric // a difference in the loaded values. If a difference is found, it branches
3712cab237bSDimitry Andric // with an early exit to the ResultBlock for calculating which source was
3722cab237bSDimitry Andric // larger. Otherwise, it falls through to the either the next LoadCmpBlock or
3732cab237bSDimitry Andric // the EndBlock if this is the last LoadCmpBlock. Loading 1 byte is handled with
3742cab237bSDimitry Andric // a special case through emitLoadCompareByteBlock. The special handling can
3752cab237bSDimitry Andric // simply subtract the loaded values and add it to the result phi node.
3762cab237bSDimitry Andric void MemCmpExpansion::emitLoadCompareBlock(unsigned BlockIndex) {
3772cab237bSDimitry Andric   // There is one load per block in this case, BlockIndex == LoadIndex.
3782cab237bSDimitry Andric   const LoadEntry &CurLoadEntry = LoadSequence[BlockIndex];
3792cab237bSDimitry Andric 
3802cab237bSDimitry Andric   if (CurLoadEntry.LoadSize == 1) {
3812cab237bSDimitry Andric     MemCmpExpansion::emitLoadCompareByteBlock(BlockIndex,
3822cab237bSDimitry Andric                                               CurLoadEntry.getGEPIndex());
3832cab237bSDimitry Andric     return;
3842cab237bSDimitry Andric   }
3852cab237bSDimitry Andric 
3862cab237bSDimitry Andric   Type *LoadSizeType =
3872cab237bSDimitry Andric       IntegerType::get(CI->getContext(), CurLoadEntry.LoadSize * 8);
3882cab237bSDimitry Andric   Type *MaxLoadType = IntegerType::get(CI->getContext(), MaxLoadSize * 8);
3892cab237bSDimitry Andric   assert(CurLoadEntry.LoadSize <= MaxLoadSize && "Unexpected load type");
3902cab237bSDimitry Andric 
3912cab237bSDimitry Andric   Value *Source1 = CI->getArgOperand(0);
3922cab237bSDimitry Andric   Value *Source2 = CI->getArgOperand(1);
3932cab237bSDimitry Andric 
3942cab237bSDimitry Andric   Builder.SetInsertPoint(LoadCmpBlocks[BlockIndex]);
3952cab237bSDimitry Andric   // Cast source to LoadSizeType*.
3962cab237bSDimitry Andric   if (Source1->getType() != LoadSizeType)
3972cab237bSDimitry Andric     Source1 = Builder.CreateBitCast(Source1, LoadSizeType->getPointerTo());
3982cab237bSDimitry Andric   if (Source2->getType() != LoadSizeType)
3992cab237bSDimitry Andric     Source2 = Builder.CreateBitCast(Source2, LoadSizeType->getPointerTo());
4002cab237bSDimitry Andric 
4012cab237bSDimitry Andric   // Get the base address using a GEP.
4022cab237bSDimitry Andric   if (CurLoadEntry.Offset != 0) {
4032cab237bSDimitry Andric     Source1 = Builder.CreateGEP(
4042cab237bSDimitry Andric         LoadSizeType, Source1,
4052cab237bSDimitry Andric         ConstantInt::get(LoadSizeType, CurLoadEntry.getGEPIndex()));
4062cab237bSDimitry Andric     Source2 = Builder.CreateGEP(
4072cab237bSDimitry Andric         LoadSizeType, Source2,
4082cab237bSDimitry Andric         ConstantInt::get(LoadSizeType, CurLoadEntry.getGEPIndex()));
4092cab237bSDimitry Andric   }
4102cab237bSDimitry Andric 
4112cab237bSDimitry Andric   // Load LoadSizeType from the base address.
4122cab237bSDimitry Andric   Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
4132cab237bSDimitry Andric   Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
4142cab237bSDimitry Andric 
4152cab237bSDimitry Andric   if (DL.isLittleEndian()) {
4162cab237bSDimitry Andric     Function *Bswap = Intrinsic::getDeclaration(CI->getModule(),
4172cab237bSDimitry Andric                                                 Intrinsic::bswap, LoadSizeType);
4182cab237bSDimitry Andric     LoadSrc1 = Builder.CreateCall(Bswap, LoadSrc1);
4192cab237bSDimitry Andric     LoadSrc2 = Builder.CreateCall(Bswap, LoadSrc2);
4202cab237bSDimitry Andric   }
4212cab237bSDimitry Andric 
4222cab237bSDimitry Andric   if (LoadSizeType != MaxLoadType) {
4232cab237bSDimitry Andric     LoadSrc1 = Builder.CreateZExt(LoadSrc1, MaxLoadType);
4242cab237bSDimitry Andric     LoadSrc2 = Builder.CreateZExt(LoadSrc2, MaxLoadType);
4252cab237bSDimitry Andric   }
4262cab237bSDimitry Andric 
4272cab237bSDimitry Andric   // Add the loaded values to the phi nodes for calculating memcmp result only
4282cab237bSDimitry Andric   // if result is not used in a zero equality.
4292cab237bSDimitry Andric   if (!IsUsedForZeroCmp) {
4302cab237bSDimitry Andric     ResBlock.PhiSrc1->addIncoming(LoadSrc1, LoadCmpBlocks[BlockIndex]);
4312cab237bSDimitry Andric     ResBlock.PhiSrc2->addIncoming(LoadSrc2, LoadCmpBlocks[BlockIndex]);
4322cab237bSDimitry Andric   }
4332cab237bSDimitry Andric 
4342cab237bSDimitry Andric   Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_EQ, LoadSrc1, LoadSrc2);
4352cab237bSDimitry Andric   BasicBlock *NextBB = (BlockIndex == (LoadCmpBlocks.size() - 1))
4362cab237bSDimitry Andric                            ? EndBlock
4372cab237bSDimitry Andric                            : LoadCmpBlocks[BlockIndex + 1];
4382cab237bSDimitry Andric   // Early exit branch if difference found to ResultBlock. Otherwise, continue
4392cab237bSDimitry Andric   // to next LoadCmpBlock or EndBlock.
4402cab237bSDimitry Andric   BranchInst *CmpBr = BranchInst::Create(NextBB, ResBlock.BB, Cmp);
4412cab237bSDimitry Andric   Builder.Insert(CmpBr);
4422cab237bSDimitry Andric 
4432cab237bSDimitry Andric   // Add a phi edge for the last LoadCmpBlock to Endblock with a value of 0
4442cab237bSDimitry Andric   // since early exit to ResultBlock was not taken (no difference was found in
4452cab237bSDimitry Andric   // any of the bytes).
4462cab237bSDimitry Andric   if (BlockIndex == LoadCmpBlocks.size() - 1) {
4472cab237bSDimitry Andric     Value *Zero = ConstantInt::get(Type::getInt32Ty(CI->getContext()), 0);
4482cab237bSDimitry Andric     PhiRes->addIncoming(Zero, LoadCmpBlocks[BlockIndex]);
4492cab237bSDimitry Andric   }
4502cab237bSDimitry Andric }
4512cab237bSDimitry Andric 
4522cab237bSDimitry Andric // This function populates the ResultBlock with a sequence to calculate the
4532cab237bSDimitry Andric // memcmp result. It compares the two loaded source values and returns -1 if
4542cab237bSDimitry Andric // src1 < src2 and 1 if src1 > src2.
4552cab237bSDimitry Andric void MemCmpExpansion::emitMemCmpResultBlock() {
4562cab237bSDimitry Andric   // Special case: if memcmp result is used in a zero equality, result does not
4572cab237bSDimitry Andric   // need to be calculated and can simply return 1.
4582cab237bSDimitry Andric   if (IsUsedForZeroCmp) {
4592cab237bSDimitry Andric     BasicBlock::iterator InsertPt = ResBlock.BB->getFirstInsertionPt();
4602cab237bSDimitry Andric     Builder.SetInsertPoint(ResBlock.BB, InsertPt);
4612cab237bSDimitry Andric     Value *Res = ConstantInt::get(Type::getInt32Ty(CI->getContext()), 1);
4622cab237bSDimitry Andric     PhiRes->addIncoming(Res, ResBlock.BB);
4632cab237bSDimitry Andric     BranchInst *NewBr = BranchInst::Create(EndBlock);
4642cab237bSDimitry Andric     Builder.Insert(NewBr);
4652cab237bSDimitry Andric     return;
4662cab237bSDimitry Andric   }
4672cab237bSDimitry Andric   BasicBlock::iterator InsertPt = ResBlock.BB->getFirstInsertionPt();
4682cab237bSDimitry Andric   Builder.SetInsertPoint(ResBlock.BB, InsertPt);
4692cab237bSDimitry Andric 
4702cab237bSDimitry Andric   Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_ULT, ResBlock.PhiSrc1,
4712cab237bSDimitry Andric                                   ResBlock.PhiSrc2);
4722cab237bSDimitry Andric 
4732cab237bSDimitry Andric   Value *Res =
4742cab237bSDimitry Andric       Builder.CreateSelect(Cmp, ConstantInt::get(Builder.getInt32Ty(), -1),
4752cab237bSDimitry Andric                            ConstantInt::get(Builder.getInt32Ty(), 1));
4762cab237bSDimitry Andric 
4772cab237bSDimitry Andric   BranchInst *NewBr = BranchInst::Create(EndBlock);
4782cab237bSDimitry Andric   Builder.Insert(NewBr);
4792cab237bSDimitry Andric   PhiRes->addIncoming(Res, ResBlock.BB);
4802cab237bSDimitry Andric }
4812cab237bSDimitry Andric 
4822cab237bSDimitry Andric void MemCmpExpansion::setupResultBlockPHINodes() {
4832cab237bSDimitry Andric   Type *MaxLoadType = IntegerType::get(CI->getContext(), MaxLoadSize * 8);
4842cab237bSDimitry Andric   Builder.SetInsertPoint(ResBlock.BB);
4852cab237bSDimitry Andric   // Note: this assumes one load per block.
4862cab237bSDimitry Andric   ResBlock.PhiSrc1 =
4872cab237bSDimitry Andric       Builder.CreatePHI(MaxLoadType, NumLoadsNonOneByte, "phi.src1");
4882cab237bSDimitry Andric   ResBlock.PhiSrc2 =
4892cab237bSDimitry Andric       Builder.CreatePHI(MaxLoadType, NumLoadsNonOneByte, "phi.src2");
4902cab237bSDimitry Andric }
4912cab237bSDimitry Andric 
4922cab237bSDimitry Andric void MemCmpExpansion::setupEndBlockPHINodes() {
4932cab237bSDimitry Andric   Builder.SetInsertPoint(&EndBlock->front());
4942cab237bSDimitry Andric   PhiRes = Builder.CreatePHI(Type::getInt32Ty(CI->getContext()), 2, "phi.res");
4952cab237bSDimitry Andric }
4962cab237bSDimitry Andric 
4972cab237bSDimitry Andric Value *MemCmpExpansion::getMemCmpExpansionZeroCase() {
4982cab237bSDimitry Andric   unsigned LoadIndex = 0;
4992cab237bSDimitry Andric   // This loop populates each of the LoadCmpBlocks with the IR sequence to
5002cab237bSDimitry Andric   // handle multiple loads per block.
5012cab237bSDimitry Andric   for (unsigned I = 0; I < getNumBlocks(); ++I) {
5022cab237bSDimitry Andric     emitLoadCompareBlockMultipleLoads(I, LoadIndex);
5032cab237bSDimitry Andric   }
5042cab237bSDimitry Andric 
5052cab237bSDimitry Andric   emitMemCmpResultBlock();
5062cab237bSDimitry Andric   return PhiRes;
5072cab237bSDimitry Andric }
5082cab237bSDimitry Andric 
5092cab237bSDimitry Andric /// A memcmp expansion that compares equality with 0 and only has one block of
5102cab237bSDimitry Andric /// load and compare can bypass the compare, branch, and phi IR that is required
5112cab237bSDimitry Andric /// in the general case.
5122cab237bSDimitry Andric Value *MemCmpExpansion::getMemCmpEqZeroOneBlock() {
5132cab237bSDimitry Andric   unsigned LoadIndex = 0;
5142cab237bSDimitry Andric   Value *Cmp = getCompareLoadPairs(0, LoadIndex);
5152cab237bSDimitry Andric   assert(LoadIndex == getNumLoads() && "some entries were not consumed");
5162cab237bSDimitry Andric   return Builder.CreateZExt(Cmp, Type::getInt32Ty(CI->getContext()));
5172cab237bSDimitry Andric }
5182cab237bSDimitry Andric 
5192cab237bSDimitry Andric /// A memcmp expansion that only has one block of load and compare can bypass
5202cab237bSDimitry Andric /// the compare, branch, and phi IR that is required in the general case.
5212cab237bSDimitry Andric Value *MemCmpExpansion::getMemCmpOneBlock() {
5222cab237bSDimitry Andric   assert(NumLoadsPerBlock == 1 && "Only handles one load pair per block");
5232cab237bSDimitry Andric 
5242cab237bSDimitry Andric   Type *LoadSizeType = IntegerType::get(CI->getContext(), Size * 8);
5252cab237bSDimitry Andric   Value *Source1 = CI->getArgOperand(0);
5262cab237bSDimitry Andric   Value *Source2 = CI->getArgOperand(1);
5272cab237bSDimitry Andric 
5282cab237bSDimitry Andric   // Cast source to LoadSizeType*.
5292cab237bSDimitry Andric   if (Source1->getType() != LoadSizeType)
5302cab237bSDimitry Andric     Source1 = Builder.CreateBitCast(Source1, LoadSizeType->getPointerTo());
5312cab237bSDimitry Andric   if (Source2->getType() != LoadSizeType)
5322cab237bSDimitry Andric     Source2 = Builder.CreateBitCast(Source2, LoadSizeType->getPointerTo());
5332cab237bSDimitry Andric 
5342cab237bSDimitry Andric   // Load LoadSizeType from the base address.
5352cab237bSDimitry Andric   Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
5362cab237bSDimitry Andric   Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
5372cab237bSDimitry Andric 
5382cab237bSDimitry Andric   if (DL.isLittleEndian() && Size != 1) {
5392cab237bSDimitry Andric     Function *Bswap = Intrinsic::getDeclaration(CI->getModule(),
5402cab237bSDimitry Andric                                                 Intrinsic::bswap, LoadSizeType);
5412cab237bSDimitry Andric     LoadSrc1 = Builder.CreateCall(Bswap, LoadSrc1);
5422cab237bSDimitry Andric     LoadSrc2 = Builder.CreateCall(Bswap, LoadSrc2);
5432cab237bSDimitry Andric   }
5442cab237bSDimitry Andric 
5452cab237bSDimitry Andric   if (Size < 4) {
5462cab237bSDimitry Andric     // The i8 and i16 cases don't need compares. We zext the loaded values and
5472cab237bSDimitry Andric     // subtract them to get the suitable negative, zero, or positive i32 result.
5482cab237bSDimitry Andric     LoadSrc1 = Builder.CreateZExt(LoadSrc1, Builder.getInt32Ty());
5492cab237bSDimitry Andric     LoadSrc2 = Builder.CreateZExt(LoadSrc2, Builder.getInt32Ty());
5502cab237bSDimitry Andric     return Builder.CreateSub(LoadSrc1, LoadSrc2);
5512cab237bSDimitry Andric   }
5522cab237bSDimitry Andric 
5532cab237bSDimitry Andric   // The result of memcmp is negative, zero, or positive, so produce that by
5542cab237bSDimitry Andric   // subtracting 2 extended compare bits: sub (ugt, ult).
5552cab237bSDimitry Andric   // If a target prefers to use selects to get -1/0/1, they should be able
5562cab237bSDimitry Andric   // to transform this later. The inverse transform (going from selects to math)
5572cab237bSDimitry Andric   // may not be possible in the DAG because the selects got converted into
5582cab237bSDimitry Andric   // branches before we got there.
5592cab237bSDimitry Andric   Value *CmpUGT = Builder.CreateICmpUGT(LoadSrc1, LoadSrc2);
5602cab237bSDimitry Andric   Value *CmpULT = Builder.CreateICmpULT(LoadSrc1, LoadSrc2);
5612cab237bSDimitry Andric   Value *ZextUGT = Builder.CreateZExt(CmpUGT, Builder.getInt32Ty());
5622cab237bSDimitry Andric   Value *ZextULT = Builder.CreateZExt(CmpULT, Builder.getInt32Ty());
5632cab237bSDimitry Andric   return Builder.CreateSub(ZextUGT, ZextULT);
5642cab237bSDimitry Andric }
5652cab237bSDimitry Andric 
5662cab237bSDimitry Andric // This function expands the memcmp call into an inline expansion and returns
5672cab237bSDimitry Andric // the memcmp result.
5682cab237bSDimitry Andric Value *MemCmpExpansion::getMemCmpExpansion() {
5692cab237bSDimitry Andric   // A memcmp with zero-comparison with only one block of load and compare does
5702cab237bSDimitry Andric   // not need to set up any extra blocks. This case could be handled in the DAG,
5712cab237bSDimitry Andric   // but since we have all of the machinery to flexibly expand any memcpy here,
5722cab237bSDimitry Andric   // we choose to handle this case too to avoid fragmented lowering.
5732cab237bSDimitry Andric   if ((!IsUsedForZeroCmp && NumLoadsPerBlock != 1) || getNumBlocks() != 1) {
5742cab237bSDimitry Andric     BasicBlock *StartBlock = CI->getParent();
5752cab237bSDimitry Andric     EndBlock = StartBlock->splitBasicBlock(CI, "endblock");
5762cab237bSDimitry Andric     setupEndBlockPHINodes();
5772cab237bSDimitry Andric     createResultBlock();
5782cab237bSDimitry Andric 
5792cab237bSDimitry Andric     // If return value of memcmp is not used in a zero equality, we need to
5802cab237bSDimitry Andric     // calculate which source was larger. The calculation requires the
5812cab237bSDimitry Andric     // two loaded source values of each load compare block.
5822cab237bSDimitry Andric     // These will be saved in the phi nodes created by setupResultBlockPHINodes.
5832cab237bSDimitry Andric     if (!IsUsedForZeroCmp) setupResultBlockPHINodes();
5842cab237bSDimitry Andric 
5852cab237bSDimitry Andric     // Create the number of required load compare basic blocks.
5862cab237bSDimitry Andric     createLoadCmpBlocks();
5872cab237bSDimitry Andric 
5882cab237bSDimitry Andric     // Update the terminator added by splitBasicBlock to branch to the first
5892cab237bSDimitry Andric     // LoadCmpBlock.
5902cab237bSDimitry Andric     StartBlock->getTerminator()->setSuccessor(0, LoadCmpBlocks[0]);
5912cab237bSDimitry Andric   }
5922cab237bSDimitry Andric 
5932cab237bSDimitry Andric   Builder.SetCurrentDebugLocation(CI->getDebugLoc());
5942cab237bSDimitry Andric 
5952cab237bSDimitry Andric   if (IsUsedForZeroCmp)
5962cab237bSDimitry Andric     return getNumBlocks() == 1 ? getMemCmpEqZeroOneBlock()
5972cab237bSDimitry Andric                                : getMemCmpExpansionZeroCase();
5982cab237bSDimitry Andric 
5992cab237bSDimitry Andric   // TODO: Handle more than one load pair per block in getMemCmpOneBlock().
6002cab237bSDimitry Andric   if (getNumBlocks() == 1 && NumLoadsPerBlock == 1) return getMemCmpOneBlock();
6012cab237bSDimitry Andric 
6022cab237bSDimitry Andric   for (unsigned I = 0; I < getNumBlocks(); ++I) {
6032cab237bSDimitry Andric     emitLoadCompareBlock(I);
6042cab237bSDimitry Andric   }
6052cab237bSDimitry Andric 
6062cab237bSDimitry Andric   emitMemCmpResultBlock();
6072cab237bSDimitry Andric   return PhiRes;
6082cab237bSDimitry Andric }
6092cab237bSDimitry Andric 
6102cab237bSDimitry Andric // This function checks to see if an expansion of memcmp can be generated.
6112cab237bSDimitry Andric // It checks for constant compare size that is less than the max inline size.
6122cab237bSDimitry Andric // If an expansion cannot occur, returns false to leave as a library call.
6132cab237bSDimitry Andric // Otherwise, the library call is replaced with a new IR instruction sequence.
6142cab237bSDimitry Andric /// We want to transform:
6152cab237bSDimitry Andric /// %call = call signext i32 @memcmp(i8* %0, i8* %1, i64 15)
6162cab237bSDimitry Andric /// To:
6172cab237bSDimitry Andric /// loadbb:
6182cab237bSDimitry Andric ///  %0 = bitcast i32* %buffer2 to i8*
6192cab237bSDimitry Andric ///  %1 = bitcast i32* %buffer1 to i8*
6202cab237bSDimitry Andric ///  %2 = bitcast i8* %1 to i64*
6212cab237bSDimitry Andric ///  %3 = bitcast i8* %0 to i64*
6222cab237bSDimitry Andric ///  %4 = load i64, i64* %2
6232cab237bSDimitry Andric ///  %5 = load i64, i64* %3
6242cab237bSDimitry Andric ///  %6 = call i64 @llvm.bswap.i64(i64 %4)
6252cab237bSDimitry Andric ///  %7 = call i64 @llvm.bswap.i64(i64 %5)
6262cab237bSDimitry Andric ///  %8 = sub i64 %6, %7
6272cab237bSDimitry Andric ///  %9 = icmp ne i64 %8, 0
6282cab237bSDimitry Andric ///  br i1 %9, label %res_block, label %loadbb1
6292cab237bSDimitry Andric /// res_block:                                        ; preds = %loadbb2,
6302cab237bSDimitry Andric /// %loadbb1, %loadbb
6312cab237bSDimitry Andric ///  %phi.src1 = phi i64 [ %6, %loadbb ], [ %22, %loadbb1 ], [ %36, %loadbb2 ]
6322cab237bSDimitry Andric ///  %phi.src2 = phi i64 [ %7, %loadbb ], [ %23, %loadbb1 ], [ %37, %loadbb2 ]
6332cab237bSDimitry Andric ///  %10 = icmp ult i64 %phi.src1, %phi.src2
6342cab237bSDimitry Andric ///  %11 = select i1 %10, i32 -1, i32 1
6352cab237bSDimitry Andric ///  br label %endblock
6362cab237bSDimitry Andric /// loadbb1:                                          ; preds = %loadbb
6372cab237bSDimitry Andric ///  %12 = bitcast i32* %buffer2 to i8*
6382cab237bSDimitry Andric ///  %13 = bitcast i32* %buffer1 to i8*
6392cab237bSDimitry Andric ///  %14 = bitcast i8* %13 to i32*
6402cab237bSDimitry Andric ///  %15 = bitcast i8* %12 to i32*
6412cab237bSDimitry Andric ///  %16 = getelementptr i32, i32* %14, i32 2
6422cab237bSDimitry Andric ///  %17 = getelementptr i32, i32* %15, i32 2
6432cab237bSDimitry Andric ///  %18 = load i32, i32* %16
6442cab237bSDimitry Andric ///  %19 = load i32, i32* %17
6452cab237bSDimitry Andric ///  %20 = call i32 @llvm.bswap.i32(i32 %18)
6462cab237bSDimitry Andric ///  %21 = call i32 @llvm.bswap.i32(i32 %19)
6472cab237bSDimitry Andric ///  %22 = zext i32 %20 to i64
6482cab237bSDimitry Andric ///  %23 = zext i32 %21 to i64
6492cab237bSDimitry Andric ///  %24 = sub i64 %22, %23
6502cab237bSDimitry Andric ///  %25 = icmp ne i64 %24, 0
6512cab237bSDimitry Andric ///  br i1 %25, label %res_block, label %loadbb2
6522cab237bSDimitry Andric /// loadbb2:                                          ; preds = %loadbb1
6532cab237bSDimitry Andric ///  %26 = bitcast i32* %buffer2 to i8*
6542cab237bSDimitry Andric ///  %27 = bitcast i32* %buffer1 to i8*
6552cab237bSDimitry Andric ///  %28 = bitcast i8* %27 to i16*
6562cab237bSDimitry Andric ///  %29 = bitcast i8* %26 to i16*
6572cab237bSDimitry Andric ///  %30 = getelementptr i16, i16* %28, i16 6
6582cab237bSDimitry Andric ///  %31 = getelementptr i16, i16* %29, i16 6
6592cab237bSDimitry Andric ///  %32 = load i16, i16* %30
6602cab237bSDimitry Andric ///  %33 = load i16, i16* %31
6612cab237bSDimitry Andric ///  %34 = call i16 @llvm.bswap.i16(i16 %32)
6622cab237bSDimitry Andric ///  %35 = call i16 @llvm.bswap.i16(i16 %33)
6632cab237bSDimitry Andric ///  %36 = zext i16 %34 to i64
6642cab237bSDimitry Andric ///  %37 = zext i16 %35 to i64
6652cab237bSDimitry Andric ///  %38 = sub i64 %36, %37
6662cab237bSDimitry Andric ///  %39 = icmp ne i64 %38, 0
6672cab237bSDimitry Andric ///  br i1 %39, label %res_block, label %loadbb3
6682cab237bSDimitry Andric /// loadbb3:                                          ; preds = %loadbb2
6692cab237bSDimitry Andric ///  %40 = bitcast i32* %buffer2 to i8*
6702cab237bSDimitry Andric ///  %41 = bitcast i32* %buffer1 to i8*
6712cab237bSDimitry Andric ///  %42 = getelementptr i8, i8* %41, i8 14
6722cab237bSDimitry Andric ///  %43 = getelementptr i8, i8* %40, i8 14
6732cab237bSDimitry Andric ///  %44 = load i8, i8* %42
6742cab237bSDimitry Andric ///  %45 = load i8, i8* %43
6752cab237bSDimitry Andric ///  %46 = zext i8 %44 to i32
6762cab237bSDimitry Andric ///  %47 = zext i8 %45 to i32
6772cab237bSDimitry Andric ///  %48 = sub i32 %46, %47
6782cab237bSDimitry Andric ///  br label %endblock
6792cab237bSDimitry Andric /// endblock:                                         ; preds = %res_block,
6802cab237bSDimitry Andric /// %loadbb3
6812cab237bSDimitry Andric ///  %phi.res = phi i32 [ %48, %loadbb3 ], [ %11, %res_block ]
6822cab237bSDimitry Andric ///  ret i32 %phi.res
6832cab237bSDimitry Andric static bool expandMemCmp(CallInst *CI, const TargetTransformInfo *TTI,
6842cab237bSDimitry Andric                          const TargetLowering *TLI, const DataLayout *DL) {
6852cab237bSDimitry Andric   NumMemCmpCalls++;
6862cab237bSDimitry Andric 
6872cab237bSDimitry Andric   // Early exit from expansion if -Oz.
6882cab237bSDimitry Andric   if (CI->getFunction()->optForMinSize())
6892cab237bSDimitry Andric     return false;
6902cab237bSDimitry Andric 
6912cab237bSDimitry Andric   // Early exit from expansion if size is not a constant.
6922cab237bSDimitry Andric   ConstantInt *SizeCast = dyn_cast<ConstantInt>(CI->getArgOperand(2));
6932cab237bSDimitry Andric   if (!SizeCast) {
6942cab237bSDimitry Andric     NumMemCmpNotConstant++;
6952cab237bSDimitry Andric     return false;
6962cab237bSDimitry Andric   }
6972cab237bSDimitry Andric   const uint64_t SizeVal = SizeCast->getZExtValue();
6982cab237bSDimitry Andric 
6992cab237bSDimitry Andric   if (SizeVal == 0) {
7002cab237bSDimitry Andric     return false;
7012cab237bSDimitry Andric   }
7022cab237bSDimitry Andric 
7032cab237bSDimitry Andric   // TTI call to check if target would like to expand memcmp. Also, get the
7042cab237bSDimitry Andric   // available load sizes.
7052cab237bSDimitry Andric   const bool IsUsedForZeroCmp = isOnlyUsedInZeroEqualityComparison(CI);
7062cab237bSDimitry Andric   const auto *const Options = TTI->enableMemCmpExpansion(IsUsedForZeroCmp);
7072cab237bSDimitry Andric   if (!Options) return false;
7082cab237bSDimitry Andric 
7092cab237bSDimitry Andric   const unsigned MaxNumLoads =
7102cab237bSDimitry Andric       TLI->getMaxExpandSizeMemcmp(CI->getFunction()->optForSize());
7112cab237bSDimitry Andric 
7122cab237bSDimitry Andric   MemCmpExpansion Expansion(CI, SizeVal, *Options, MaxNumLoads,
7132cab237bSDimitry Andric                             IsUsedForZeroCmp, MemCmpNumLoadsPerBlock, *DL);
7142cab237bSDimitry Andric 
7152cab237bSDimitry Andric   // Don't expand if this will require more loads than desired by the target.
7162cab237bSDimitry Andric   if (Expansion.getNumLoads() == 0) {
7172cab237bSDimitry Andric     NumMemCmpGreaterThanMax++;
7182cab237bSDimitry Andric     return false;
7192cab237bSDimitry Andric   }
7202cab237bSDimitry Andric 
7212cab237bSDimitry Andric   NumMemCmpInlined++;
7222cab237bSDimitry Andric 
7232cab237bSDimitry Andric   Value *Res = Expansion.getMemCmpExpansion();
7242cab237bSDimitry Andric 
7252cab237bSDimitry Andric   // Replace call with result of expansion and erase call.
7262cab237bSDimitry Andric   CI->replaceAllUsesWith(Res);
7272cab237bSDimitry Andric   CI->eraseFromParent();
7282cab237bSDimitry Andric 
7292cab237bSDimitry Andric   return true;
7302cab237bSDimitry Andric }
7312cab237bSDimitry Andric 
7322cab237bSDimitry Andric 
7332cab237bSDimitry Andric 
7342cab237bSDimitry Andric class ExpandMemCmpPass : public FunctionPass {
7352cab237bSDimitry Andric public:
7362cab237bSDimitry Andric   static char ID;
7372cab237bSDimitry Andric 
7382cab237bSDimitry Andric   ExpandMemCmpPass() : FunctionPass(ID) {
7392cab237bSDimitry Andric     initializeExpandMemCmpPassPass(*PassRegistry::getPassRegistry());
7402cab237bSDimitry Andric   }
7412cab237bSDimitry Andric 
7422cab237bSDimitry Andric   bool runOnFunction(Function &F) override {
7432cab237bSDimitry Andric     if (skipFunction(F)) return false;
7442cab237bSDimitry Andric 
7452cab237bSDimitry Andric     auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
7462cab237bSDimitry Andric     if (!TPC) {
7472cab237bSDimitry Andric       return false;
7482cab237bSDimitry Andric     }
7492cab237bSDimitry Andric     const TargetLowering* TL =
7502cab237bSDimitry Andric         TPC->getTM<TargetMachine>().getSubtargetImpl(F)->getTargetLowering();
7512cab237bSDimitry Andric 
7522cab237bSDimitry Andric     const TargetLibraryInfo *TLI =
7532cab237bSDimitry Andric         &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
7542cab237bSDimitry Andric     const TargetTransformInfo *TTI =
7552cab237bSDimitry Andric         &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
7562cab237bSDimitry Andric     auto PA = runImpl(F, TLI, TTI, TL);
7572cab237bSDimitry Andric     return !PA.areAllPreserved();
7582cab237bSDimitry Andric   }
7592cab237bSDimitry Andric 
7602cab237bSDimitry Andric private:
7612cab237bSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
7622cab237bSDimitry Andric     AU.addRequired<TargetLibraryInfoWrapperPass>();
7632cab237bSDimitry Andric     AU.addRequired<TargetTransformInfoWrapperPass>();
7642cab237bSDimitry Andric     FunctionPass::getAnalysisUsage(AU);
7652cab237bSDimitry Andric   }
7662cab237bSDimitry Andric 
7672cab237bSDimitry Andric   PreservedAnalyses runImpl(Function &F, const TargetLibraryInfo *TLI,
7682cab237bSDimitry Andric                             const TargetTransformInfo *TTI,
7692cab237bSDimitry Andric                             const TargetLowering* TL);
7702cab237bSDimitry Andric   // Returns true if a change was made.
7712cab237bSDimitry Andric   bool runOnBlock(BasicBlock &BB, const TargetLibraryInfo *TLI,
7722cab237bSDimitry Andric                   const TargetTransformInfo *TTI, const TargetLowering* TL,
7732cab237bSDimitry Andric                   const DataLayout& DL);
7742cab237bSDimitry Andric };
7752cab237bSDimitry Andric 
7762cab237bSDimitry Andric bool ExpandMemCmpPass::runOnBlock(
7772cab237bSDimitry Andric     BasicBlock &BB, const TargetLibraryInfo *TLI,
7782cab237bSDimitry Andric     const TargetTransformInfo *TTI, const TargetLowering* TL,
7792cab237bSDimitry Andric     const DataLayout& DL) {
7802cab237bSDimitry Andric   for (Instruction& I : BB) {
7812cab237bSDimitry Andric     CallInst *CI = dyn_cast<CallInst>(&I);
7822cab237bSDimitry Andric     if (!CI) {
7832cab237bSDimitry Andric       continue;
7842cab237bSDimitry Andric     }
7852cab237bSDimitry Andric     LibFunc Func;
7862cab237bSDimitry Andric     if (TLI->getLibFunc(ImmutableCallSite(CI), Func) &&
7872cab237bSDimitry Andric         Func == LibFunc_memcmp && expandMemCmp(CI, TTI, TL, &DL)) {
7882cab237bSDimitry Andric       return true;
7892cab237bSDimitry Andric     }
7902cab237bSDimitry Andric   }
7912cab237bSDimitry Andric   return false;
7922cab237bSDimitry Andric }
7932cab237bSDimitry Andric 
7942cab237bSDimitry Andric 
7952cab237bSDimitry Andric PreservedAnalyses ExpandMemCmpPass::runImpl(
7962cab237bSDimitry Andric     Function &F, const TargetLibraryInfo *TLI, const TargetTransformInfo *TTI,
7972cab237bSDimitry Andric     const TargetLowering* TL) {
7982cab237bSDimitry Andric   const DataLayout& DL = F.getParent()->getDataLayout();
7992cab237bSDimitry Andric   bool MadeChanges = false;
8002cab237bSDimitry Andric   for (auto BBIt = F.begin(); BBIt != F.end();) {
8012cab237bSDimitry Andric     if (runOnBlock(*BBIt, TLI, TTI, TL, DL)) {
8022cab237bSDimitry Andric       MadeChanges = true;
8032cab237bSDimitry Andric       // If changes were made, restart the function from the beginning, since
8042cab237bSDimitry Andric       // the structure of the function was changed.
8052cab237bSDimitry Andric       BBIt = F.begin();
8062cab237bSDimitry Andric     } else {
8072cab237bSDimitry Andric       ++BBIt;
8082cab237bSDimitry Andric     }
8092cab237bSDimitry Andric   }
8102cab237bSDimitry Andric   return MadeChanges ? PreservedAnalyses::none() : PreservedAnalyses::all();
8112cab237bSDimitry Andric }
8122cab237bSDimitry Andric 
8132cab237bSDimitry Andric } // namespace
8142cab237bSDimitry Andric 
8152cab237bSDimitry Andric char ExpandMemCmpPass::ID = 0;
8162cab237bSDimitry Andric INITIALIZE_PASS_BEGIN(ExpandMemCmpPass, "expandmemcmp",
8172cab237bSDimitry Andric                       "Expand memcmp() to load/stores", false, false)
8182cab237bSDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
8192cab237bSDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
8202cab237bSDimitry Andric INITIALIZE_PASS_END(ExpandMemCmpPass, "expandmemcmp",
8212cab237bSDimitry Andric                     "Expand memcmp() to load/stores", false, false)
8222cab237bSDimitry Andric 
8232cab237bSDimitry Andric FunctionPass *llvm::createExpandMemCmpPass() {
8242cab237bSDimitry Andric   return new ExpandMemCmpPass();
8252cab237bSDimitry Andric }
826