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