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
354ba319b5SDimitry Andric static cl::opt<unsigned> MemCmpEqZeroNumLoadsPerBlock(
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;
594ba319b5SDimitry Andric const uint64_t NumLoadsPerBlockForZeroCmp;
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 struct LoadEntry {
LoadEntry__anon24fd12780111::MemCmpExpansion::LoadEntry702cab237bSDimitry Andric LoadEntry(unsigned LoadSize, uint64_t Offset)
712cab237bSDimitry Andric : LoadSize(LoadSize), Offset(Offset) {
722cab237bSDimitry Andric }
732cab237bSDimitry Andric
742cab237bSDimitry Andric // The size of the load for this block, in bytes.
75*b5893f02SDimitry Andric unsigned LoadSize;
76*b5893f02SDimitry Andric // The offset of this load from the base pointer, in bytes.
77*b5893f02SDimitry Andric uint64_t Offset;
782cab237bSDimitry Andric };
79*b5893f02SDimitry Andric using LoadEntryVector = SmallVector<LoadEntry, 8>;
80*b5893f02SDimitry Andric LoadEntryVector LoadSequence;
812cab237bSDimitry Andric
822cab237bSDimitry Andric void createLoadCmpBlocks();
832cab237bSDimitry Andric void createResultBlock();
842cab237bSDimitry Andric void setupResultBlockPHINodes();
852cab237bSDimitry Andric void setupEndBlockPHINodes();
862cab237bSDimitry Andric Value *getCompareLoadPairs(unsigned BlockIndex, unsigned &LoadIndex);
872cab237bSDimitry Andric void emitLoadCompareBlock(unsigned BlockIndex);
882cab237bSDimitry Andric void emitLoadCompareBlockMultipleLoads(unsigned BlockIndex,
892cab237bSDimitry Andric unsigned &LoadIndex);
90*b5893f02SDimitry Andric void emitLoadCompareByteBlock(unsigned BlockIndex, unsigned OffsetBytes);
912cab237bSDimitry Andric void emitMemCmpResultBlock();
922cab237bSDimitry Andric Value *getMemCmpExpansionZeroCase();
932cab237bSDimitry Andric Value *getMemCmpEqZeroOneBlock();
942cab237bSDimitry Andric Value *getMemCmpOneBlock();
95*b5893f02SDimitry Andric Value *getPtrToElementAtOffset(Value *Source, Type *LoadSizeType,
96*b5893f02SDimitry Andric uint64_t OffsetBytes);
97*b5893f02SDimitry Andric
98*b5893f02SDimitry Andric static LoadEntryVector
99*b5893f02SDimitry Andric computeGreedyLoadSequence(uint64_t Size, llvm::ArrayRef<unsigned> LoadSizes,
100*b5893f02SDimitry Andric unsigned MaxNumLoads, unsigned &NumLoadsNonOneByte);
101*b5893f02SDimitry Andric static LoadEntryVector
102*b5893f02SDimitry Andric computeOverlappingLoadSequence(uint64_t Size, unsigned MaxLoadSize,
103*b5893f02SDimitry Andric unsigned MaxNumLoads,
104*b5893f02SDimitry Andric unsigned &NumLoadsNonOneByte);
1052cab237bSDimitry Andric
1062cab237bSDimitry Andric public:
1072cab237bSDimitry Andric MemCmpExpansion(CallInst *CI, uint64_t Size,
1082cab237bSDimitry Andric const TargetTransformInfo::MemCmpExpansionOptions &Options,
1092cab237bSDimitry Andric unsigned MaxNumLoads, const bool IsUsedForZeroCmp,
1104ba319b5SDimitry Andric unsigned MaxLoadsPerBlockForZeroCmp, const DataLayout &TheDataLayout);
1112cab237bSDimitry Andric
1122cab237bSDimitry Andric unsigned getNumBlocks();
getNumLoads() const1132cab237bSDimitry Andric uint64_t getNumLoads() const { return LoadSequence.size(); }
1142cab237bSDimitry Andric
1152cab237bSDimitry Andric Value *getMemCmpExpansion();
1162cab237bSDimitry Andric };
1172cab237bSDimitry Andric
computeGreedyLoadSequence(uint64_t Size,llvm::ArrayRef<unsigned> LoadSizes,const unsigned MaxNumLoads,unsigned & NumLoadsNonOneByte)118*b5893f02SDimitry Andric MemCmpExpansion::LoadEntryVector MemCmpExpansion::computeGreedyLoadSequence(
119*b5893f02SDimitry Andric uint64_t Size, llvm::ArrayRef<unsigned> LoadSizes,
120*b5893f02SDimitry Andric const unsigned MaxNumLoads, unsigned &NumLoadsNonOneByte) {
121*b5893f02SDimitry Andric NumLoadsNonOneByte = 0;
122*b5893f02SDimitry Andric LoadEntryVector LoadSequence;
123*b5893f02SDimitry Andric uint64_t Offset = 0;
124*b5893f02SDimitry Andric while (Size && !LoadSizes.empty()) {
125*b5893f02SDimitry Andric const unsigned LoadSize = LoadSizes.front();
126*b5893f02SDimitry Andric const uint64_t NumLoadsForThisSize = Size / LoadSize;
127*b5893f02SDimitry Andric if (LoadSequence.size() + NumLoadsForThisSize > MaxNumLoads) {
128*b5893f02SDimitry Andric // Do not expand if the total number of loads is larger than what the
129*b5893f02SDimitry Andric // target allows. Note that it's important that we exit before completing
130*b5893f02SDimitry Andric // the expansion to avoid using a ton of memory to store the expansion for
131*b5893f02SDimitry Andric // large sizes.
132*b5893f02SDimitry Andric return {};
133*b5893f02SDimitry Andric }
134*b5893f02SDimitry Andric if (NumLoadsForThisSize > 0) {
135*b5893f02SDimitry Andric for (uint64_t I = 0; I < NumLoadsForThisSize; ++I) {
136*b5893f02SDimitry Andric LoadSequence.push_back({LoadSize, Offset});
137*b5893f02SDimitry Andric Offset += LoadSize;
138*b5893f02SDimitry Andric }
139*b5893f02SDimitry Andric if (LoadSize > 1)
140*b5893f02SDimitry Andric ++NumLoadsNonOneByte;
141*b5893f02SDimitry Andric Size = Size % LoadSize;
142*b5893f02SDimitry Andric }
143*b5893f02SDimitry Andric LoadSizes = LoadSizes.drop_front();
144*b5893f02SDimitry Andric }
145*b5893f02SDimitry Andric return LoadSequence;
146*b5893f02SDimitry Andric }
147*b5893f02SDimitry Andric
148*b5893f02SDimitry Andric MemCmpExpansion::LoadEntryVector
computeOverlappingLoadSequence(uint64_t Size,const unsigned MaxLoadSize,const unsigned MaxNumLoads,unsigned & NumLoadsNonOneByte)149*b5893f02SDimitry Andric MemCmpExpansion::computeOverlappingLoadSequence(uint64_t Size,
150*b5893f02SDimitry Andric const unsigned MaxLoadSize,
151*b5893f02SDimitry Andric const unsigned MaxNumLoads,
152*b5893f02SDimitry Andric unsigned &NumLoadsNonOneByte) {
153*b5893f02SDimitry Andric // These are already handled by the greedy approach.
154*b5893f02SDimitry Andric if (Size < 2 || MaxLoadSize < 2)
155*b5893f02SDimitry Andric return {};
156*b5893f02SDimitry Andric
157*b5893f02SDimitry Andric // We try to do as many non-overlapping loads as possible starting from the
158*b5893f02SDimitry Andric // beginning.
159*b5893f02SDimitry Andric const uint64_t NumNonOverlappingLoads = Size / MaxLoadSize;
160*b5893f02SDimitry Andric assert(NumNonOverlappingLoads && "there must be at least one load");
161*b5893f02SDimitry Andric // There remain 0 to (MaxLoadSize - 1) bytes to load, this will be done with
162*b5893f02SDimitry Andric // an overlapping load.
163*b5893f02SDimitry Andric Size = Size - NumNonOverlappingLoads * MaxLoadSize;
164*b5893f02SDimitry Andric // Bail if we do not need an overloapping store, this is already handled by
165*b5893f02SDimitry Andric // the greedy approach.
166*b5893f02SDimitry Andric if (Size == 0)
167*b5893f02SDimitry Andric return {};
168*b5893f02SDimitry Andric // Bail if the number of loads (non-overlapping + potential overlapping one)
169*b5893f02SDimitry Andric // is larger than the max allowed.
170*b5893f02SDimitry Andric if ((NumNonOverlappingLoads + 1) > MaxNumLoads)
171*b5893f02SDimitry Andric return {};
172*b5893f02SDimitry Andric
173*b5893f02SDimitry Andric // Add non-overlapping loads.
174*b5893f02SDimitry Andric LoadEntryVector LoadSequence;
175*b5893f02SDimitry Andric uint64_t Offset = 0;
176*b5893f02SDimitry Andric for (uint64_t I = 0; I < NumNonOverlappingLoads; ++I) {
177*b5893f02SDimitry Andric LoadSequence.push_back({MaxLoadSize, Offset});
178*b5893f02SDimitry Andric Offset += MaxLoadSize;
179*b5893f02SDimitry Andric }
180*b5893f02SDimitry Andric
181*b5893f02SDimitry Andric // Add the last overlapping load.
182*b5893f02SDimitry Andric assert(Size > 0 && Size < MaxLoadSize && "broken invariant");
183*b5893f02SDimitry Andric LoadSequence.push_back({MaxLoadSize, Offset - (MaxLoadSize - Size)});
184*b5893f02SDimitry Andric NumLoadsNonOneByte = 1;
185*b5893f02SDimitry Andric return LoadSequence;
186*b5893f02SDimitry Andric }
187*b5893f02SDimitry Andric
1882cab237bSDimitry Andric // Initialize the basic block structure required for expansion of memcmp call
1892cab237bSDimitry Andric // with given maximum load size and memcmp size parameter.
1902cab237bSDimitry Andric // This structure includes:
1912cab237bSDimitry Andric // 1. A list of load compare blocks - LoadCmpBlocks.
1922cab237bSDimitry Andric // 2. An EndBlock, split from original instruction point, which is the block to
1932cab237bSDimitry Andric // return from.
1942cab237bSDimitry Andric // 3. ResultBlock, block to branch to for early exit when a
1952cab237bSDimitry Andric // LoadCmpBlock finds a difference.
MemCmpExpansion(CallInst * const CI,uint64_t Size,const TargetTransformInfo::MemCmpExpansionOptions & Options,const unsigned MaxNumLoads,const bool IsUsedForZeroCmp,const unsigned MaxLoadsPerBlockForZeroCmp,const DataLayout & TheDataLayout)1962cab237bSDimitry Andric MemCmpExpansion::MemCmpExpansion(
1972cab237bSDimitry Andric CallInst *const CI, uint64_t Size,
1982cab237bSDimitry Andric const TargetTransformInfo::MemCmpExpansionOptions &Options,
1992cab237bSDimitry Andric const unsigned MaxNumLoads, const bool IsUsedForZeroCmp,
2004ba319b5SDimitry Andric const unsigned MaxLoadsPerBlockForZeroCmp, const DataLayout &TheDataLayout)
2012cab237bSDimitry Andric : CI(CI),
2022cab237bSDimitry Andric Size(Size),
2032cab237bSDimitry Andric MaxLoadSize(0),
2042cab237bSDimitry Andric NumLoadsNonOneByte(0),
2054ba319b5SDimitry Andric NumLoadsPerBlockForZeroCmp(MaxLoadsPerBlockForZeroCmp),
2062cab237bSDimitry Andric IsUsedForZeroCmp(IsUsedForZeroCmp),
2072cab237bSDimitry Andric DL(TheDataLayout),
2082cab237bSDimitry Andric Builder(CI) {
2092cab237bSDimitry Andric assert(Size > 0 && "zero blocks");
2102cab237bSDimitry Andric // Scale the max size down if the target can load more bytes than we need.
211*b5893f02SDimitry Andric llvm::ArrayRef<unsigned> LoadSizes(Options.LoadSizes);
212*b5893f02SDimitry Andric while (!LoadSizes.empty() && LoadSizes.front() > Size) {
213*b5893f02SDimitry Andric LoadSizes = LoadSizes.drop_front();
2142cab237bSDimitry Andric }
215*b5893f02SDimitry Andric assert(!LoadSizes.empty() && "cannot load Size bytes");
216*b5893f02SDimitry Andric MaxLoadSize = LoadSizes.front();
2172cab237bSDimitry Andric // Compute the decomposition.
218*b5893f02SDimitry Andric unsigned GreedyNumLoadsNonOneByte = 0;
219*b5893f02SDimitry Andric LoadSequence = computeGreedyLoadSequence(Size, LoadSizes, MaxNumLoads,
220*b5893f02SDimitry Andric GreedyNumLoadsNonOneByte);
221*b5893f02SDimitry Andric NumLoadsNonOneByte = GreedyNumLoadsNonOneByte;
222*b5893f02SDimitry Andric assert(LoadSequence.size() <= MaxNumLoads && "broken invariant");
223*b5893f02SDimitry Andric // If we allow overlapping loads and the load sequence is not already optimal,
224*b5893f02SDimitry Andric // use overlapping loads.
225*b5893f02SDimitry Andric if (Options.AllowOverlappingLoads &&
226*b5893f02SDimitry Andric (LoadSequence.empty() || LoadSequence.size() > 2)) {
227*b5893f02SDimitry Andric unsigned OverlappingNumLoadsNonOneByte = 0;
228*b5893f02SDimitry Andric auto OverlappingLoads = computeOverlappingLoadSequence(
229*b5893f02SDimitry Andric Size, MaxLoadSize, MaxNumLoads, OverlappingNumLoadsNonOneByte);
230*b5893f02SDimitry Andric if (!OverlappingLoads.empty() &&
231*b5893f02SDimitry Andric (LoadSequence.empty() ||
232*b5893f02SDimitry Andric OverlappingLoads.size() < LoadSequence.size())) {
233*b5893f02SDimitry Andric LoadSequence = OverlappingLoads;
234*b5893f02SDimitry Andric NumLoadsNonOneByte = OverlappingNumLoadsNonOneByte;
2352cab237bSDimitry Andric }
2362cab237bSDimitry Andric }
2372cab237bSDimitry Andric assert(LoadSequence.size() <= MaxNumLoads && "broken invariant");
2382cab237bSDimitry Andric }
2392cab237bSDimitry Andric
getNumBlocks()2402cab237bSDimitry Andric unsigned MemCmpExpansion::getNumBlocks() {
2412cab237bSDimitry Andric if (IsUsedForZeroCmp)
2424ba319b5SDimitry Andric return getNumLoads() / NumLoadsPerBlockForZeroCmp +
2434ba319b5SDimitry Andric (getNumLoads() % NumLoadsPerBlockForZeroCmp != 0 ? 1 : 0);
2442cab237bSDimitry Andric return getNumLoads();
2452cab237bSDimitry Andric }
2462cab237bSDimitry Andric
createLoadCmpBlocks()2472cab237bSDimitry Andric void MemCmpExpansion::createLoadCmpBlocks() {
2482cab237bSDimitry Andric for (unsigned i = 0; i < getNumBlocks(); i++) {
2492cab237bSDimitry Andric BasicBlock *BB = BasicBlock::Create(CI->getContext(), "loadbb",
2502cab237bSDimitry Andric EndBlock->getParent(), EndBlock);
2512cab237bSDimitry Andric LoadCmpBlocks.push_back(BB);
2522cab237bSDimitry Andric }
2532cab237bSDimitry Andric }
2542cab237bSDimitry Andric
createResultBlock()2552cab237bSDimitry Andric void MemCmpExpansion::createResultBlock() {
2562cab237bSDimitry Andric ResBlock.BB = BasicBlock::Create(CI->getContext(), "res_block",
2572cab237bSDimitry Andric EndBlock->getParent(), EndBlock);
2582cab237bSDimitry Andric }
2592cab237bSDimitry Andric
260*b5893f02SDimitry Andric /// Return a pointer to an element of type `LoadSizeType` at offset
261*b5893f02SDimitry Andric /// `OffsetBytes`.
getPtrToElementAtOffset(Value * Source,Type * LoadSizeType,uint64_t OffsetBytes)262*b5893f02SDimitry Andric Value *MemCmpExpansion::getPtrToElementAtOffset(Value *Source,
263*b5893f02SDimitry Andric Type *LoadSizeType,
264*b5893f02SDimitry Andric uint64_t OffsetBytes) {
265*b5893f02SDimitry Andric if (OffsetBytes > 0) {
266*b5893f02SDimitry Andric auto *ByteType = Type::getInt8Ty(CI->getContext());
267*b5893f02SDimitry Andric Source = Builder.CreateGEP(
268*b5893f02SDimitry Andric ByteType, Builder.CreateBitCast(Source, ByteType->getPointerTo()),
269*b5893f02SDimitry Andric ConstantInt::get(ByteType, OffsetBytes));
270*b5893f02SDimitry Andric }
271*b5893f02SDimitry Andric return Builder.CreateBitCast(Source, LoadSizeType->getPointerTo());
272*b5893f02SDimitry Andric }
273*b5893f02SDimitry Andric
2742cab237bSDimitry Andric // This function creates the IR instructions for loading and comparing 1 byte.
2752cab237bSDimitry Andric // It loads 1 byte from each source of the memcmp parameters with the given
2762cab237bSDimitry Andric // GEPIndex. It then subtracts the two loaded values and adds this result to the
2772cab237bSDimitry Andric // final phi node for selecting the memcmp result.
emitLoadCompareByteBlock(unsigned BlockIndex,unsigned OffsetBytes)2782cab237bSDimitry Andric void MemCmpExpansion::emitLoadCompareByteBlock(unsigned BlockIndex,
279*b5893f02SDimitry Andric unsigned OffsetBytes) {
2802cab237bSDimitry Andric Builder.SetInsertPoint(LoadCmpBlocks[BlockIndex]);
2812cab237bSDimitry Andric Type *LoadSizeType = Type::getInt8Ty(CI->getContext());
282*b5893f02SDimitry Andric Value *Source1 =
283*b5893f02SDimitry Andric getPtrToElementAtOffset(CI->getArgOperand(0), LoadSizeType, OffsetBytes);
284*b5893f02SDimitry Andric Value *Source2 =
285*b5893f02SDimitry Andric getPtrToElementAtOffset(CI->getArgOperand(1), LoadSizeType, OffsetBytes);
2862cab237bSDimitry Andric
2872cab237bSDimitry Andric Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
2882cab237bSDimitry Andric Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
2892cab237bSDimitry Andric
2902cab237bSDimitry Andric LoadSrc1 = Builder.CreateZExt(LoadSrc1, Type::getInt32Ty(CI->getContext()));
2912cab237bSDimitry Andric LoadSrc2 = Builder.CreateZExt(LoadSrc2, Type::getInt32Ty(CI->getContext()));
2922cab237bSDimitry Andric Value *Diff = Builder.CreateSub(LoadSrc1, LoadSrc2);
2932cab237bSDimitry Andric
2942cab237bSDimitry Andric PhiRes->addIncoming(Diff, LoadCmpBlocks[BlockIndex]);
2952cab237bSDimitry Andric
2962cab237bSDimitry Andric if (BlockIndex < (LoadCmpBlocks.size() - 1)) {
2972cab237bSDimitry Andric // Early exit branch if difference found to EndBlock. Otherwise, continue to
2982cab237bSDimitry Andric // next LoadCmpBlock,
2992cab237bSDimitry Andric Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_NE, Diff,
3002cab237bSDimitry Andric ConstantInt::get(Diff->getType(), 0));
3012cab237bSDimitry Andric BranchInst *CmpBr =
3022cab237bSDimitry Andric BranchInst::Create(EndBlock, LoadCmpBlocks[BlockIndex + 1], Cmp);
3032cab237bSDimitry Andric Builder.Insert(CmpBr);
3042cab237bSDimitry Andric } else {
3052cab237bSDimitry Andric // The last block has an unconditional branch to EndBlock.
3062cab237bSDimitry Andric BranchInst *CmpBr = BranchInst::Create(EndBlock);
3072cab237bSDimitry Andric Builder.Insert(CmpBr);
3082cab237bSDimitry Andric }
3092cab237bSDimitry Andric }
3102cab237bSDimitry Andric
3112cab237bSDimitry Andric /// Generate an equality comparison for one or more pairs of loaded values.
3122cab237bSDimitry Andric /// This is used in the case where the memcmp() call is compared equal or not
3132cab237bSDimitry Andric /// equal to zero.
getCompareLoadPairs(unsigned BlockIndex,unsigned & LoadIndex)3142cab237bSDimitry Andric Value *MemCmpExpansion::getCompareLoadPairs(unsigned BlockIndex,
3152cab237bSDimitry Andric unsigned &LoadIndex) {
3162cab237bSDimitry Andric assert(LoadIndex < getNumLoads() &&
3172cab237bSDimitry Andric "getCompareLoadPairs() called with no remaining loads");
3182cab237bSDimitry Andric std::vector<Value *> XorList, OrList;
3192cab237bSDimitry Andric Value *Diff;
3202cab237bSDimitry Andric
3212cab237bSDimitry Andric const unsigned NumLoads =
3224ba319b5SDimitry Andric std::min(getNumLoads() - LoadIndex, NumLoadsPerBlockForZeroCmp);
3232cab237bSDimitry Andric
3242cab237bSDimitry Andric // For a single-block expansion, start inserting before the memcmp call.
3252cab237bSDimitry Andric if (LoadCmpBlocks.empty())
3262cab237bSDimitry Andric Builder.SetInsertPoint(CI);
3272cab237bSDimitry Andric else
3282cab237bSDimitry Andric Builder.SetInsertPoint(LoadCmpBlocks[BlockIndex]);
3292cab237bSDimitry Andric
3302cab237bSDimitry Andric Value *Cmp = nullptr;
3312cab237bSDimitry Andric // If we have multiple loads per block, we need to generate a composite
3322cab237bSDimitry Andric // comparison using xor+or. The type for the combinations is the largest load
3332cab237bSDimitry Andric // type.
3342cab237bSDimitry Andric IntegerType *const MaxLoadType =
3352cab237bSDimitry Andric NumLoads == 1 ? nullptr
3362cab237bSDimitry Andric : IntegerType::get(CI->getContext(), MaxLoadSize * 8);
3372cab237bSDimitry Andric for (unsigned i = 0; i < NumLoads; ++i, ++LoadIndex) {
3382cab237bSDimitry Andric const LoadEntry &CurLoadEntry = LoadSequence[LoadIndex];
3392cab237bSDimitry Andric
3402cab237bSDimitry Andric IntegerType *LoadSizeType =
3412cab237bSDimitry Andric IntegerType::get(CI->getContext(), CurLoadEntry.LoadSize * 8);
3422cab237bSDimitry Andric
343*b5893f02SDimitry Andric Value *Source1 = getPtrToElementAtOffset(CI->getArgOperand(0), LoadSizeType,
344*b5893f02SDimitry Andric CurLoadEntry.Offset);
345*b5893f02SDimitry Andric Value *Source2 = getPtrToElementAtOffset(CI->getArgOperand(1), LoadSizeType,
346*b5893f02SDimitry Andric CurLoadEntry.Offset);
3472cab237bSDimitry Andric
3482cab237bSDimitry Andric // Get a constant or load a value for each source address.
3492cab237bSDimitry Andric Value *LoadSrc1 = nullptr;
3502cab237bSDimitry Andric if (auto *Source1C = dyn_cast<Constant>(Source1))
3512cab237bSDimitry Andric LoadSrc1 = ConstantFoldLoadFromConstPtr(Source1C, LoadSizeType, DL);
3522cab237bSDimitry Andric if (!LoadSrc1)
3532cab237bSDimitry Andric LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
3542cab237bSDimitry Andric
3552cab237bSDimitry Andric Value *LoadSrc2 = nullptr;
3562cab237bSDimitry Andric if (auto *Source2C = dyn_cast<Constant>(Source2))
3572cab237bSDimitry Andric LoadSrc2 = ConstantFoldLoadFromConstPtr(Source2C, LoadSizeType, DL);
3582cab237bSDimitry Andric if (!LoadSrc2)
3592cab237bSDimitry Andric LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
3602cab237bSDimitry Andric
3612cab237bSDimitry Andric if (NumLoads != 1) {
3622cab237bSDimitry Andric if (LoadSizeType != MaxLoadType) {
3632cab237bSDimitry Andric LoadSrc1 = Builder.CreateZExt(LoadSrc1, MaxLoadType);
3642cab237bSDimitry Andric LoadSrc2 = Builder.CreateZExt(LoadSrc2, MaxLoadType);
3652cab237bSDimitry Andric }
3662cab237bSDimitry Andric // If we have multiple loads per block, we need to generate a composite
3672cab237bSDimitry Andric // comparison using xor+or.
3682cab237bSDimitry Andric Diff = Builder.CreateXor(LoadSrc1, LoadSrc2);
3692cab237bSDimitry Andric Diff = Builder.CreateZExt(Diff, MaxLoadType);
3702cab237bSDimitry Andric XorList.push_back(Diff);
3712cab237bSDimitry Andric } else {
3722cab237bSDimitry Andric // If there's only one load per block, we just compare the loaded values.
3732cab237bSDimitry Andric Cmp = Builder.CreateICmpNE(LoadSrc1, LoadSrc2);
3742cab237bSDimitry Andric }
3752cab237bSDimitry Andric }
3762cab237bSDimitry Andric
3772cab237bSDimitry Andric auto pairWiseOr = [&](std::vector<Value *> &InList) -> std::vector<Value *> {
3782cab237bSDimitry Andric std::vector<Value *> OutList;
3792cab237bSDimitry Andric for (unsigned i = 0; i < InList.size() - 1; i = i + 2) {
3802cab237bSDimitry Andric Value *Or = Builder.CreateOr(InList[i], InList[i + 1]);
3812cab237bSDimitry Andric OutList.push_back(Or);
3822cab237bSDimitry Andric }
3832cab237bSDimitry Andric if (InList.size() % 2 != 0)
3842cab237bSDimitry Andric OutList.push_back(InList.back());
3852cab237bSDimitry Andric return OutList;
3862cab237bSDimitry Andric };
3872cab237bSDimitry Andric
3882cab237bSDimitry Andric if (!Cmp) {
3892cab237bSDimitry Andric // Pairwise OR the XOR results.
3902cab237bSDimitry Andric OrList = pairWiseOr(XorList);
3912cab237bSDimitry Andric
3922cab237bSDimitry Andric // Pairwise OR the OR results until one result left.
3932cab237bSDimitry Andric while (OrList.size() != 1) {
3942cab237bSDimitry Andric OrList = pairWiseOr(OrList);
3952cab237bSDimitry Andric }
3962cab237bSDimitry Andric Cmp = Builder.CreateICmpNE(OrList[0], ConstantInt::get(Diff->getType(), 0));
3972cab237bSDimitry Andric }
3982cab237bSDimitry Andric
3992cab237bSDimitry Andric return Cmp;
4002cab237bSDimitry Andric }
4012cab237bSDimitry Andric
emitLoadCompareBlockMultipleLoads(unsigned BlockIndex,unsigned & LoadIndex)4022cab237bSDimitry Andric void MemCmpExpansion::emitLoadCompareBlockMultipleLoads(unsigned BlockIndex,
4032cab237bSDimitry Andric unsigned &LoadIndex) {
4042cab237bSDimitry Andric Value *Cmp = getCompareLoadPairs(BlockIndex, LoadIndex);
4052cab237bSDimitry Andric
4062cab237bSDimitry Andric BasicBlock *NextBB = (BlockIndex == (LoadCmpBlocks.size() - 1))
4072cab237bSDimitry Andric ? EndBlock
4082cab237bSDimitry Andric : LoadCmpBlocks[BlockIndex + 1];
4092cab237bSDimitry Andric // Early exit branch if difference found to ResultBlock. Otherwise,
4102cab237bSDimitry Andric // continue to next LoadCmpBlock or EndBlock.
4112cab237bSDimitry Andric BranchInst *CmpBr = BranchInst::Create(ResBlock.BB, NextBB, Cmp);
4122cab237bSDimitry Andric Builder.Insert(CmpBr);
4132cab237bSDimitry Andric
4142cab237bSDimitry Andric // Add a phi edge for the last LoadCmpBlock to Endblock with a value of 0
4152cab237bSDimitry Andric // since early exit to ResultBlock was not taken (no difference was found in
4162cab237bSDimitry Andric // any of the bytes).
4172cab237bSDimitry Andric if (BlockIndex == LoadCmpBlocks.size() - 1) {
4182cab237bSDimitry Andric Value *Zero = ConstantInt::get(Type::getInt32Ty(CI->getContext()), 0);
4192cab237bSDimitry Andric PhiRes->addIncoming(Zero, LoadCmpBlocks[BlockIndex]);
4202cab237bSDimitry Andric }
4212cab237bSDimitry Andric }
4222cab237bSDimitry Andric
4232cab237bSDimitry Andric // This function creates the IR intructions for loading and comparing using the
4242cab237bSDimitry Andric // given LoadSize. It loads the number of bytes specified by LoadSize from each
4252cab237bSDimitry Andric // source of the memcmp parameters. It then does a subtract to see if there was
4262cab237bSDimitry Andric // a difference in the loaded values. If a difference is found, it branches
4272cab237bSDimitry Andric // with an early exit to the ResultBlock for calculating which source was
4282cab237bSDimitry Andric // larger. Otherwise, it falls through to the either the next LoadCmpBlock or
4292cab237bSDimitry Andric // the EndBlock if this is the last LoadCmpBlock. Loading 1 byte is handled with
4302cab237bSDimitry Andric // a special case through emitLoadCompareByteBlock. The special handling can
4312cab237bSDimitry Andric // simply subtract the loaded values and add it to the result phi node.
emitLoadCompareBlock(unsigned BlockIndex)4322cab237bSDimitry Andric void MemCmpExpansion::emitLoadCompareBlock(unsigned BlockIndex) {
4332cab237bSDimitry Andric // There is one load per block in this case, BlockIndex == LoadIndex.
4342cab237bSDimitry Andric const LoadEntry &CurLoadEntry = LoadSequence[BlockIndex];
4352cab237bSDimitry Andric
4362cab237bSDimitry Andric if (CurLoadEntry.LoadSize == 1) {
437*b5893f02SDimitry Andric MemCmpExpansion::emitLoadCompareByteBlock(BlockIndex, CurLoadEntry.Offset);
4382cab237bSDimitry Andric return;
4392cab237bSDimitry Andric }
4402cab237bSDimitry Andric
4412cab237bSDimitry Andric Type *LoadSizeType =
4422cab237bSDimitry Andric IntegerType::get(CI->getContext(), CurLoadEntry.LoadSize * 8);
4432cab237bSDimitry Andric Type *MaxLoadType = IntegerType::get(CI->getContext(), MaxLoadSize * 8);
4442cab237bSDimitry Andric assert(CurLoadEntry.LoadSize <= MaxLoadSize && "Unexpected load type");
4452cab237bSDimitry Andric
4462cab237bSDimitry Andric Builder.SetInsertPoint(LoadCmpBlocks[BlockIndex]);
4472cab237bSDimitry Andric
448*b5893f02SDimitry Andric Value *Source1 = getPtrToElementAtOffset(CI->getArgOperand(0), LoadSizeType,
449*b5893f02SDimitry Andric CurLoadEntry.Offset);
450*b5893f02SDimitry Andric Value *Source2 = getPtrToElementAtOffset(CI->getArgOperand(1), LoadSizeType,
451*b5893f02SDimitry Andric CurLoadEntry.Offset);
4522cab237bSDimitry Andric
4532cab237bSDimitry Andric // Load LoadSizeType from the base address.
4542cab237bSDimitry Andric Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
4552cab237bSDimitry Andric Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
4562cab237bSDimitry Andric
4572cab237bSDimitry Andric if (DL.isLittleEndian()) {
4582cab237bSDimitry Andric Function *Bswap = Intrinsic::getDeclaration(CI->getModule(),
4592cab237bSDimitry Andric Intrinsic::bswap, LoadSizeType);
4602cab237bSDimitry Andric LoadSrc1 = Builder.CreateCall(Bswap, LoadSrc1);
4612cab237bSDimitry Andric LoadSrc2 = Builder.CreateCall(Bswap, LoadSrc2);
4622cab237bSDimitry Andric }
4632cab237bSDimitry Andric
4642cab237bSDimitry Andric if (LoadSizeType != MaxLoadType) {
4652cab237bSDimitry Andric LoadSrc1 = Builder.CreateZExt(LoadSrc1, MaxLoadType);
4662cab237bSDimitry Andric LoadSrc2 = Builder.CreateZExt(LoadSrc2, MaxLoadType);
4672cab237bSDimitry Andric }
4682cab237bSDimitry Andric
4692cab237bSDimitry Andric // Add the loaded values to the phi nodes for calculating memcmp result only
4702cab237bSDimitry Andric // if result is not used in a zero equality.
4712cab237bSDimitry Andric if (!IsUsedForZeroCmp) {
4722cab237bSDimitry Andric ResBlock.PhiSrc1->addIncoming(LoadSrc1, LoadCmpBlocks[BlockIndex]);
4732cab237bSDimitry Andric ResBlock.PhiSrc2->addIncoming(LoadSrc2, LoadCmpBlocks[BlockIndex]);
4742cab237bSDimitry Andric }
4752cab237bSDimitry Andric
4762cab237bSDimitry Andric Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_EQ, LoadSrc1, LoadSrc2);
4772cab237bSDimitry Andric BasicBlock *NextBB = (BlockIndex == (LoadCmpBlocks.size() - 1))
4782cab237bSDimitry Andric ? EndBlock
4792cab237bSDimitry Andric : LoadCmpBlocks[BlockIndex + 1];
4802cab237bSDimitry Andric // Early exit branch if difference found to ResultBlock. Otherwise, continue
4812cab237bSDimitry Andric // to next LoadCmpBlock or EndBlock.
4822cab237bSDimitry Andric BranchInst *CmpBr = BranchInst::Create(NextBB, ResBlock.BB, Cmp);
4832cab237bSDimitry Andric Builder.Insert(CmpBr);
4842cab237bSDimitry Andric
4852cab237bSDimitry Andric // Add a phi edge for the last LoadCmpBlock to Endblock with a value of 0
4862cab237bSDimitry Andric // since early exit to ResultBlock was not taken (no difference was found in
4872cab237bSDimitry Andric // any of the bytes).
4882cab237bSDimitry Andric if (BlockIndex == LoadCmpBlocks.size() - 1) {
4892cab237bSDimitry Andric Value *Zero = ConstantInt::get(Type::getInt32Ty(CI->getContext()), 0);
4902cab237bSDimitry Andric PhiRes->addIncoming(Zero, LoadCmpBlocks[BlockIndex]);
4912cab237bSDimitry Andric }
4922cab237bSDimitry Andric }
4932cab237bSDimitry Andric
4942cab237bSDimitry Andric // This function populates the ResultBlock with a sequence to calculate the
4952cab237bSDimitry Andric // memcmp result. It compares the two loaded source values and returns -1 if
4962cab237bSDimitry Andric // src1 < src2 and 1 if src1 > src2.
emitMemCmpResultBlock()4972cab237bSDimitry Andric void MemCmpExpansion::emitMemCmpResultBlock() {
4982cab237bSDimitry Andric // Special case: if memcmp result is used in a zero equality, result does not
4992cab237bSDimitry Andric // need to be calculated and can simply return 1.
5002cab237bSDimitry Andric if (IsUsedForZeroCmp) {
5012cab237bSDimitry Andric BasicBlock::iterator InsertPt = ResBlock.BB->getFirstInsertionPt();
5022cab237bSDimitry Andric Builder.SetInsertPoint(ResBlock.BB, InsertPt);
5032cab237bSDimitry Andric Value *Res = ConstantInt::get(Type::getInt32Ty(CI->getContext()), 1);
5042cab237bSDimitry Andric PhiRes->addIncoming(Res, ResBlock.BB);
5052cab237bSDimitry Andric BranchInst *NewBr = BranchInst::Create(EndBlock);
5062cab237bSDimitry Andric Builder.Insert(NewBr);
5072cab237bSDimitry Andric return;
5082cab237bSDimitry Andric }
5092cab237bSDimitry Andric BasicBlock::iterator InsertPt = ResBlock.BB->getFirstInsertionPt();
5102cab237bSDimitry Andric Builder.SetInsertPoint(ResBlock.BB, InsertPt);
5112cab237bSDimitry Andric
5122cab237bSDimitry Andric Value *Cmp = Builder.CreateICmp(ICmpInst::ICMP_ULT, ResBlock.PhiSrc1,
5132cab237bSDimitry Andric ResBlock.PhiSrc2);
5142cab237bSDimitry Andric
5152cab237bSDimitry Andric Value *Res =
5162cab237bSDimitry Andric Builder.CreateSelect(Cmp, ConstantInt::get(Builder.getInt32Ty(), -1),
5172cab237bSDimitry Andric ConstantInt::get(Builder.getInt32Ty(), 1));
5182cab237bSDimitry Andric
5192cab237bSDimitry Andric BranchInst *NewBr = BranchInst::Create(EndBlock);
5202cab237bSDimitry Andric Builder.Insert(NewBr);
5212cab237bSDimitry Andric PhiRes->addIncoming(Res, ResBlock.BB);
5222cab237bSDimitry Andric }
5232cab237bSDimitry Andric
setupResultBlockPHINodes()5242cab237bSDimitry Andric void MemCmpExpansion::setupResultBlockPHINodes() {
5252cab237bSDimitry Andric Type *MaxLoadType = IntegerType::get(CI->getContext(), MaxLoadSize * 8);
5262cab237bSDimitry Andric Builder.SetInsertPoint(ResBlock.BB);
5272cab237bSDimitry Andric // Note: this assumes one load per block.
5282cab237bSDimitry Andric ResBlock.PhiSrc1 =
5292cab237bSDimitry Andric Builder.CreatePHI(MaxLoadType, NumLoadsNonOneByte, "phi.src1");
5302cab237bSDimitry Andric ResBlock.PhiSrc2 =
5312cab237bSDimitry Andric Builder.CreatePHI(MaxLoadType, NumLoadsNonOneByte, "phi.src2");
5322cab237bSDimitry Andric }
5332cab237bSDimitry Andric
setupEndBlockPHINodes()5342cab237bSDimitry Andric void MemCmpExpansion::setupEndBlockPHINodes() {
5352cab237bSDimitry Andric Builder.SetInsertPoint(&EndBlock->front());
5362cab237bSDimitry Andric PhiRes = Builder.CreatePHI(Type::getInt32Ty(CI->getContext()), 2, "phi.res");
5372cab237bSDimitry Andric }
5382cab237bSDimitry Andric
getMemCmpExpansionZeroCase()5392cab237bSDimitry Andric Value *MemCmpExpansion::getMemCmpExpansionZeroCase() {
5402cab237bSDimitry Andric unsigned LoadIndex = 0;
5412cab237bSDimitry Andric // This loop populates each of the LoadCmpBlocks with the IR sequence to
5422cab237bSDimitry Andric // handle multiple loads per block.
5432cab237bSDimitry Andric for (unsigned I = 0; I < getNumBlocks(); ++I) {
5442cab237bSDimitry Andric emitLoadCompareBlockMultipleLoads(I, LoadIndex);
5452cab237bSDimitry Andric }
5462cab237bSDimitry Andric
5472cab237bSDimitry Andric emitMemCmpResultBlock();
5482cab237bSDimitry Andric return PhiRes;
5492cab237bSDimitry Andric }
5502cab237bSDimitry Andric
5512cab237bSDimitry Andric /// A memcmp expansion that compares equality with 0 and only has one block of
5522cab237bSDimitry Andric /// load and compare can bypass the compare, branch, and phi IR that is required
5532cab237bSDimitry Andric /// in the general case.
getMemCmpEqZeroOneBlock()5542cab237bSDimitry Andric Value *MemCmpExpansion::getMemCmpEqZeroOneBlock() {
5552cab237bSDimitry Andric unsigned LoadIndex = 0;
5562cab237bSDimitry Andric Value *Cmp = getCompareLoadPairs(0, LoadIndex);
5572cab237bSDimitry Andric assert(LoadIndex == getNumLoads() && "some entries were not consumed");
5582cab237bSDimitry Andric return Builder.CreateZExt(Cmp, Type::getInt32Ty(CI->getContext()));
5592cab237bSDimitry Andric }
5602cab237bSDimitry Andric
5612cab237bSDimitry Andric /// A memcmp expansion that only has one block of load and compare can bypass
5622cab237bSDimitry Andric /// the compare, branch, and phi IR that is required in the general case.
getMemCmpOneBlock()5632cab237bSDimitry Andric Value *MemCmpExpansion::getMemCmpOneBlock() {
5642cab237bSDimitry Andric Type *LoadSizeType = IntegerType::get(CI->getContext(), Size * 8);
5652cab237bSDimitry Andric Value *Source1 = CI->getArgOperand(0);
5662cab237bSDimitry Andric Value *Source2 = CI->getArgOperand(1);
5672cab237bSDimitry Andric
5682cab237bSDimitry Andric // Cast source to LoadSizeType*.
5692cab237bSDimitry Andric if (Source1->getType() != LoadSizeType)
5702cab237bSDimitry Andric Source1 = Builder.CreateBitCast(Source1, LoadSizeType->getPointerTo());
5712cab237bSDimitry Andric if (Source2->getType() != LoadSizeType)
5722cab237bSDimitry Andric Source2 = Builder.CreateBitCast(Source2, LoadSizeType->getPointerTo());
5732cab237bSDimitry Andric
5742cab237bSDimitry Andric // Load LoadSizeType from the base address.
5752cab237bSDimitry Andric Value *LoadSrc1 = Builder.CreateLoad(LoadSizeType, Source1);
5762cab237bSDimitry Andric Value *LoadSrc2 = Builder.CreateLoad(LoadSizeType, Source2);
5772cab237bSDimitry Andric
5782cab237bSDimitry Andric if (DL.isLittleEndian() && Size != 1) {
5792cab237bSDimitry Andric Function *Bswap = Intrinsic::getDeclaration(CI->getModule(),
5802cab237bSDimitry Andric Intrinsic::bswap, LoadSizeType);
5812cab237bSDimitry Andric LoadSrc1 = Builder.CreateCall(Bswap, LoadSrc1);
5822cab237bSDimitry Andric LoadSrc2 = Builder.CreateCall(Bswap, LoadSrc2);
5832cab237bSDimitry Andric }
5842cab237bSDimitry Andric
5852cab237bSDimitry Andric if (Size < 4) {
5862cab237bSDimitry Andric // The i8 and i16 cases don't need compares. We zext the loaded values and
5872cab237bSDimitry Andric // subtract them to get the suitable negative, zero, or positive i32 result.
5882cab237bSDimitry Andric LoadSrc1 = Builder.CreateZExt(LoadSrc1, Builder.getInt32Ty());
5892cab237bSDimitry Andric LoadSrc2 = Builder.CreateZExt(LoadSrc2, Builder.getInt32Ty());
5902cab237bSDimitry Andric return Builder.CreateSub(LoadSrc1, LoadSrc2);
5912cab237bSDimitry Andric }
5922cab237bSDimitry Andric
5932cab237bSDimitry Andric // The result of memcmp is negative, zero, or positive, so produce that by
5942cab237bSDimitry Andric // subtracting 2 extended compare bits: sub (ugt, ult).
5952cab237bSDimitry Andric // If a target prefers to use selects to get -1/0/1, they should be able
5962cab237bSDimitry Andric // to transform this later. The inverse transform (going from selects to math)
5972cab237bSDimitry Andric // may not be possible in the DAG because the selects got converted into
5982cab237bSDimitry Andric // branches before we got there.
5992cab237bSDimitry Andric Value *CmpUGT = Builder.CreateICmpUGT(LoadSrc1, LoadSrc2);
6002cab237bSDimitry Andric Value *CmpULT = Builder.CreateICmpULT(LoadSrc1, LoadSrc2);
6012cab237bSDimitry Andric Value *ZextUGT = Builder.CreateZExt(CmpUGT, Builder.getInt32Ty());
6022cab237bSDimitry Andric Value *ZextULT = Builder.CreateZExt(CmpULT, Builder.getInt32Ty());
6032cab237bSDimitry Andric return Builder.CreateSub(ZextUGT, ZextULT);
6042cab237bSDimitry Andric }
6052cab237bSDimitry Andric
6062cab237bSDimitry Andric // This function expands the memcmp call into an inline expansion and returns
6072cab237bSDimitry Andric // the memcmp result.
getMemCmpExpansion()6082cab237bSDimitry Andric Value *MemCmpExpansion::getMemCmpExpansion() {
6094ba319b5SDimitry Andric // Create the basic block framework for a multi-block expansion.
6104ba319b5SDimitry Andric if (getNumBlocks() != 1) {
6112cab237bSDimitry Andric BasicBlock *StartBlock = CI->getParent();
6122cab237bSDimitry Andric EndBlock = StartBlock->splitBasicBlock(CI, "endblock");
6132cab237bSDimitry Andric setupEndBlockPHINodes();
6142cab237bSDimitry Andric createResultBlock();
6152cab237bSDimitry Andric
6162cab237bSDimitry Andric // If return value of memcmp is not used in a zero equality, we need to
6172cab237bSDimitry Andric // calculate which source was larger. The calculation requires the
6182cab237bSDimitry Andric // two loaded source values of each load compare block.
6192cab237bSDimitry Andric // These will be saved in the phi nodes created by setupResultBlockPHINodes.
6202cab237bSDimitry Andric if (!IsUsedForZeroCmp) setupResultBlockPHINodes();
6212cab237bSDimitry Andric
6222cab237bSDimitry Andric // Create the number of required load compare basic blocks.
6232cab237bSDimitry Andric createLoadCmpBlocks();
6242cab237bSDimitry Andric
6252cab237bSDimitry Andric // Update the terminator added by splitBasicBlock to branch to the first
6262cab237bSDimitry Andric // LoadCmpBlock.
6272cab237bSDimitry Andric StartBlock->getTerminator()->setSuccessor(0, LoadCmpBlocks[0]);
6282cab237bSDimitry Andric }
6292cab237bSDimitry Andric
6302cab237bSDimitry Andric Builder.SetCurrentDebugLocation(CI->getDebugLoc());
6312cab237bSDimitry Andric
6322cab237bSDimitry Andric if (IsUsedForZeroCmp)
6332cab237bSDimitry Andric return getNumBlocks() == 1 ? getMemCmpEqZeroOneBlock()
6342cab237bSDimitry Andric : getMemCmpExpansionZeroCase();
6352cab237bSDimitry Andric
6364ba319b5SDimitry Andric if (getNumBlocks() == 1)
6374ba319b5SDimitry Andric return getMemCmpOneBlock();
6382cab237bSDimitry Andric
6392cab237bSDimitry Andric for (unsigned I = 0; I < getNumBlocks(); ++I) {
6402cab237bSDimitry Andric emitLoadCompareBlock(I);
6412cab237bSDimitry Andric }
6422cab237bSDimitry Andric
6432cab237bSDimitry Andric emitMemCmpResultBlock();
6442cab237bSDimitry Andric return PhiRes;
6452cab237bSDimitry Andric }
6462cab237bSDimitry Andric
6472cab237bSDimitry Andric // This function checks to see if an expansion of memcmp can be generated.
6482cab237bSDimitry Andric // It checks for constant compare size that is less than the max inline size.
6492cab237bSDimitry Andric // If an expansion cannot occur, returns false to leave as a library call.
6502cab237bSDimitry Andric // Otherwise, the library call is replaced with a new IR instruction sequence.
6512cab237bSDimitry Andric /// We want to transform:
6522cab237bSDimitry Andric /// %call = call signext i32 @memcmp(i8* %0, i8* %1, i64 15)
6532cab237bSDimitry Andric /// To:
6542cab237bSDimitry Andric /// loadbb:
6552cab237bSDimitry Andric /// %0 = bitcast i32* %buffer2 to i8*
6562cab237bSDimitry Andric /// %1 = bitcast i32* %buffer1 to i8*
6572cab237bSDimitry Andric /// %2 = bitcast i8* %1 to i64*
6582cab237bSDimitry Andric /// %3 = bitcast i8* %0 to i64*
6592cab237bSDimitry Andric /// %4 = load i64, i64* %2
6602cab237bSDimitry Andric /// %5 = load i64, i64* %3
6612cab237bSDimitry Andric /// %6 = call i64 @llvm.bswap.i64(i64 %4)
6622cab237bSDimitry Andric /// %7 = call i64 @llvm.bswap.i64(i64 %5)
6632cab237bSDimitry Andric /// %8 = sub i64 %6, %7
6642cab237bSDimitry Andric /// %9 = icmp ne i64 %8, 0
6652cab237bSDimitry Andric /// br i1 %9, label %res_block, label %loadbb1
6662cab237bSDimitry Andric /// res_block: ; preds = %loadbb2,
6672cab237bSDimitry Andric /// %loadbb1, %loadbb
6682cab237bSDimitry Andric /// %phi.src1 = phi i64 [ %6, %loadbb ], [ %22, %loadbb1 ], [ %36, %loadbb2 ]
6692cab237bSDimitry Andric /// %phi.src2 = phi i64 [ %7, %loadbb ], [ %23, %loadbb1 ], [ %37, %loadbb2 ]
6702cab237bSDimitry Andric /// %10 = icmp ult i64 %phi.src1, %phi.src2
6712cab237bSDimitry Andric /// %11 = select i1 %10, i32 -1, i32 1
6722cab237bSDimitry Andric /// br label %endblock
6732cab237bSDimitry Andric /// loadbb1: ; preds = %loadbb
6742cab237bSDimitry Andric /// %12 = bitcast i32* %buffer2 to i8*
6752cab237bSDimitry Andric /// %13 = bitcast i32* %buffer1 to i8*
6762cab237bSDimitry Andric /// %14 = bitcast i8* %13 to i32*
6772cab237bSDimitry Andric /// %15 = bitcast i8* %12 to i32*
6782cab237bSDimitry Andric /// %16 = getelementptr i32, i32* %14, i32 2
6792cab237bSDimitry Andric /// %17 = getelementptr i32, i32* %15, i32 2
6802cab237bSDimitry Andric /// %18 = load i32, i32* %16
6812cab237bSDimitry Andric /// %19 = load i32, i32* %17
6822cab237bSDimitry Andric /// %20 = call i32 @llvm.bswap.i32(i32 %18)
6832cab237bSDimitry Andric /// %21 = call i32 @llvm.bswap.i32(i32 %19)
6842cab237bSDimitry Andric /// %22 = zext i32 %20 to i64
6852cab237bSDimitry Andric /// %23 = zext i32 %21 to i64
6862cab237bSDimitry Andric /// %24 = sub i64 %22, %23
6872cab237bSDimitry Andric /// %25 = icmp ne i64 %24, 0
6882cab237bSDimitry Andric /// br i1 %25, label %res_block, label %loadbb2
6892cab237bSDimitry Andric /// loadbb2: ; preds = %loadbb1
6902cab237bSDimitry Andric /// %26 = bitcast i32* %buffer2 to i8*
6912cab237bSDimitry Andric /// %27 = bitcast i32* %buffer1 to i8*
6922cab237bSDimitry Andric /// %28 = bitcast i8* %27 to i16*
6932cab237bSDimitry Andric /// %29 = bitcast i8* %26 to i16*
6942cab237bSDimitry Andric /// %30 = getelementptr i16, i16* %28, i16 6
6952cab237bSDimitry Andric /// %31 = getelementptr i16, i16* %29, i16 6
6962cab237bSDimitry Andric /// %32 = load i16, i16* %30
6972cab237bSDimitry Andric /// %33 = load i16, i16* %31
6982cab237bSDimitry Andric /// %34 = call i16 @llvm.bswap.i16(i16 %32)
6992cab237bSDimitry Andric /// %35 = call i16 @llvm.bswap.i16(i16 %33)
7002cab237bSDimitry Andric /// %36 = zext i16 %34 to i64
7012cab237bSDimitry Andric /// %37 = zext i16 %35 to i64
7022cab237bSDimitry Andric /// %38 = sub i64 %36, %37
7032cab237bSDimitry Andric /// %39 = icmp ne i64 %38, 0
7042cab237bSDimitry Andric /// br i1 %39, label %res_block, label %loadbb3
7052cab237bSDimitry Andric /// loadbb3: ; preds = %loadbb2
7062cab237bSDimitry Andric /// %40 = bitcast i32* %buffer2 to i8*
7072cab237bSDimitry Andric /// %41 = bitcast i32* %buffer1 to i8*
7082cab237bSDimitry Andric /// %42 = getelementptr i8, i8* %41, i8 14
7092cab237bSDimitry Andric /// %43 = getelementptr i8, i8* %40, i8 14
7102cab237bSDimitry Andric /// %44 = load i8, i8* %42
7112cab237bSDimitry Andric /// %45 = load i8, i8* %43
7122cab237bSDimitry Andric /// %46 = zext i8 %44 to i32
7132cab237bSDimitry Andric /// %47 = zext i8 %45 to i32
7142cab237bSDimitry Andric /// %48 = sub i32 %46, %47
7152cab237bSDimitry Andric /// br label %endblock
7162cab237bSDimitry Andric /// endblock: ; preds = %res_block,
7172cab237bSDimitry Andric /// %loadbb3
7182cab237bSDimitry Andric /// %phi.res = phi i32 [ %48, %loadbb3 ], [ %11, %res_block ]
7192cab237bSDimitry Andric /// ret i32 %phi.res
expandMemCmp(CallInst * CI,const TargetTransformInfo * TTI,const TargetLowering * TLI,const DataLayout * DL)7202cab237bSDimitry Andric static bool expandMemCmp(CallInst *CI, const TargetTransformInfo *TTI,
7212cab237bSDimitry Andric const TargetLowering *TLI, const DataLayout *DL) {
7222cab237bSDimitry Andric NumMemCmpCalls++;
7232cab237bSDimitry Andric
7242cab237bSDimitry Andric // Early exit from expansion if -Oz.
7252cab237bSDimitry Andric if (CI->getFunction()->optForMinSize())
7262cab237bSDimitry Andric return false;
7272cab237bSDimitry Andric
7282cab237bSDimitry Andric // Early exit from expansion if size is not a constant.
7292cab237bSDimitry Andric ConstantInt *SizeCast = dyn_cast<ConstantInt>(CI->getArgOperand(2));
7302cab237bSDimitry Andric if (!SizeCast) {
7312cab237bSDimitry Andric NumMemCmpNotConstant++;
7322cab237bSDimitry Andric return false;
7332cab237bSDimitry Andric }
7342cab237bSDimitry Andric const uint64_t SizeVal = SizeCast->getZExtValue();
7352cab237bSDimitry Andric
7362cab237bSDimitry Andric if (SizeVal == 0) {
7372cab237bSDimitry Andric return false;
7382cab237bSDimitry Andric }
7392cab237bSDimitry Andric // TTI call to check if target would like to expand memcmp. Also, get the
7402cab237bSDimitry Andric // available load sizes.
7412cab237bSDimitry Andric const bool IsUsedForZeroCmp = isOnlyUsedInZeroEqualityComparison(CI);
7422cab237bSDimitry Andric const auto *const Options = TTI->enableMemCmpExpansion(IsUsedForZeroCmp);
7432cab237bSDimitry Andric if (!Options) return false;
7442cab237bSDimitry Andric
7452cab237bSDimitry Andric const unsigned MaxNumLoads =
7462cab237bSDimitry Andric TLI->getMaxExpandSizeMemcmp(CI->getFunction()->optForSize());
7472cab237bSDimitry Andric
7484ba319b5SDimitry Andric unsigned NumLoadsPerBlock = MemCmpEqZeroNumLoadsPerBlock.getNumOccurrences()
7494ba319b5SDimitry Andric ? MemCmpEqZeroNumLoadsPerBlock
7504ba319b5SDimitry Andric : TLI->getMemcmpEqZeroLoadsPerBlock();
7514ba319b5SDimitry Andric
7522cab237bSDimitry Andric MemCmpExpansion Expansion(CI, SizeVal, *Options, MaxNumLoads,
7534ba319b5SDimitry Andric IsUsedForZeroCmp, NumLoadsPerBlock, *DL);
7542cab237bSDimitry Andric
7552cab237bSDimitry Andric // Don't expand if this will require more loads than desired by the target.
7562cab237bSDimitry Andric if (Expansion.getNumLoads() == 0) {
7572cab237bSDimitry Andric NumMemCmpGreaterThanMax++;
7582cab237bSDimitry Andric return false;
7592cab237bSDimitry Andric }
7602cab237bSDimitry Andric
7612cab237bSDimitry Andric NumMemCmpInlined++;
7622cab237bSDimitry Andric
7632cab237bSDimitry Andric Value *Res = Expansion.getMemCmpExpansion();
7642cab237bSDimitry Andric
7652cab237bSDimitry Andric // Replace call with result of expansion and erase call.
7662cab237bSDimitry Andric CI->replaceAllUsesWith(Res);
7672cab237bSDimitry Andric CI->eraseFromParent();
7682cab237bSDimitry Andric
7692cab237bSDimitry Andric return true;
7702cab237bSDimitry Andric }
7712cab237bSDimitry Andric
7722cab237bSDimitry Andric
7732cab237bSDimitry Andric
7742cab237bSDimitry Andric class ExpandMemCmpPass : public FunctionPass {
7752cab237bSDimitry Andric public:
7762cab237bSDimitry Andric static char ID;
7772cab237bSDimitry Andric
ExpandMemCmpPass()7782cab237bSDimitry Andric ExpandMemCmpPass() : FunctionPass(ID) {
7792cab237bSDimitry Andric initializeExpandMemCmpPassPass(*PassRegistry::getPassRegistry());
7802cab237bSDimitry Andric }
7812cab237bSDimitry Andric
runOnFunction(Function & F)7822cab237bSDimitry Andric bool runOnFunction(Function &F) override {
7832cab237bSDimitry Andric if (skipFunction(F)) return false;
7842cab237bSDimitry Andric
7852cab237bSDimitry Andric auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
7862cab237bSDimitry Andric if (!TPC) {
7872cab237bSDimitry Andric return false;
7882cab237bSDimitry Andric }
7892cab237bSDimitry Andric const TargetLowering* TL =
7902cab237bSDimitry Andric TPC->getTM<TargetMachine>().getSubtargetImpl(F)->getTargetLowering();
7912cab237bSDimitry Andric
7922cab237bSDimitry Andric const TargetLibraryInfo *TLI =
7932cab237bSDimitry Andric &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI();
7942cab237bSDimitry Andric const TargetTransformInfo *TTI =
7952cab237bSDimitry Andric &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
7962cab237bSDimitry Andric auto PA = runImpl(F, TLI, TTI, TL);
7972cab237bSDimitry Andric return !PA.areAllPreserved();
7982cab237bSDimitry Andric }
7992cab237bSDimitry Andric
8002cab237bSDimitry Andric private:
getAnalysisUsage(AnalysisUsage & AU) const8012cab237bSDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
8022cab237bSDimitry Andric AU.addRequired<TargetLibraryInfoWrapperPass>();
8032cab237bSDimitry Andric AU.addRequired<TargetTransformInfoWrapperPass>();
8042cab237bSDimitry Andric FunctionPass::getAnalysisUsage(AU);
8052cab237bSDimitry Andric }
8062cab237bSDimitry Andric
8072cab237bSDimitry Andric PreservedAnalyses runImpl(Function &F, const TargetLibraryInfo *TLI,
8082cab237bSDimitry Andric const TargetTransformInfo *TTI,
8092cab237bSDimitry Andric const TargetLowering* TL);
8102cab237bSDimitry Andric // Returns true if a change was made.
8112cab237bSDimitry Andric bool runOnBlock(BasicBlock &BB, const TargetLibraryInfo *TLI,
8122cab237bSDimitry Andric const TargetTransformInfo *TTI, const TargetLowering* TL,
8132cab237bSDimitry Andric const DataLayout& DL);
8142cab237bSDimitry Andric };
8152cab237bSDimitry Andric
runOnBlock(BasicBlock & BB,const TargetLibraryInfo * TLI,const TargetTransformInfo * TTI,const TargetLowering * TL,const DataLayout & DL)8162cab237bSDimitry Andric bool ExpandMemCmpPass::runOnBlock(
8172cab237bSDimitry Andric BasicBlock &BB, const TargetLibraryInfo *TLI,
8182cab237bSDimitry Andric const TargetTransformInfo *TTI, const TargetLowering* TL,
8192cab237bSDimitry Andric const DataLayout& DL) {
8202cab237bSDimitry Andric for (Instruction& I : BB) {
8212cab237bSDimitry Andric CallInst *CI = dyn_cast<CallInst>(&I);
8222cab237bSDimitry Andric if (!CI) {
8232cab237bSDimitry Andric continue;
8242cab237bSDimitry Andric }
8252cab237bSDimitry Andric LibFunc Func;
8262cab237bSDimitry Andric if (TLI->getLibFunc(ImmutableCallSite(CI), Func) &&
8272cab237bSDimitry Andric Func == LibFunc_memcmp && expandMemCmp(CI, TTI, TL, &DL)) {
8282cab237bSDimitry Andric return true;
8292cab237bSDimitry Andric }
8302cab237bSDimitry Andric }
8312cab237bSDimitry Andric return false;
8322cab237bSDimitry Andric }
8332cab237bSDimitry Andric
8342cab237bSDimitry Andric
runImpl(Function & F,const TargetLibraryInfo * TLI,const TargetTransformInfo * TTI,const TargetLowering * TL)8352cab237bSDimitry Andric PreservedAnalyses ExpandMemCmpPass::runImpl(
8362cab237bSDimitry Andric Function &F, const TargetLibraryInfo *TLI, const TargetTransformInfo *TTI,
8372cab237bSDimitry Andric const TargetLowering* TL) {
8382cab237bSDimitry Andric const DataLayout& DL = F.getParent()->getDataLayout();
8392cab237bSDimitry Andric bool MadeChanges = false;
8402cab237bSDimitry Andric for (auto BBIt = F.begin(); BBIt != F.end();) {
8412cab237bSDimitry Andric if (runOnBlock(*BBIt, TLI, TTI, TL, DL)) {
8422cab237bSDimitry Andric MadeChanges = true;
8432cab237bSDimitry Andric // If changes were made, restart the function from the beginning, since
8442cab237bSDimitry Andric // the structure of the function was changed.
8452cab237bSDimitry Andric BBIt = F.begin();
8462cab237bSDimitry Andric } else {
8472cab237bSDimitry Andric ++BBIt;
8482cab237bSDimitry Andric }
8492cab237bSDimitry Andric }
8502cab237bSDimitry Andric return MadeChanges ? PreservedAnalyses::none() : PreservedAnalyses::all();
8512cab237bSDimitry Andric }
8522cab237bSDimitry Andric
8532cab237bSDimitry Andric } // namespace
8542cab237bSDimitry Andric
8552cab237bSDimitry Andric char ExpandMemCmpPass::ID = 0;
8562cab237bSDimitry Andric INITIALIZE_PASS_BEGIN(ExpandMemCmpPass, "expandmemcmp",
8572cab237bSDimitry Andric "Expand memcmp() to load/stores", false, false)
INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)8582cab237bSDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass)
8592cab237bSDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
8602cab237bSDimitry Andric INITIALIZE_PASS_END(ExpandMemCmpPass, "expandmemcmp",
8612cab237bSDimitry Andric "Expand memcmp() to load/stores", false, false)
8622cab237bSDimitry Andric
8632cab237bSDimitry Andric FunctionPass *llvm::createExpandMemCmpPass() {
8642cab237bSDimitry Andric return new ExpandMemCmpPass();
8652cab237bSDimitry Andric }
866