10b57cec5SDimitry Andric //===- LowerMemIntrinsics.cpp ----------------------------------*- C++ -*--===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 90b57cec5SDimitry Andric #include "llvm/Transforms/Utils/LowerMemIntrinsics.h" 1081ad6265SDimitry Andric #include "llvm/Analysis/ScalarEvolution.h" 110b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h" 120b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h" 130b57cec5SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 1481ad6265SDimitry Andric #include "llvm/IR/MDBuilder.h" 1506c3fb27SDimitry Andric #include "llvm/Support/Debug.h" 16*0fca6ea1SDimitry Andric #include "llvm/Support/MathExtras.h" 170b57cec5SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h" 18bdd1243dSDimitry Andric #include <optional> 190b57cec5SDimitry Andric 2006c3fb27SDimitry Andric #define DEBUG_TYPE "lower-mem-intrinsics" 2106c3fb27SDimitry Andric 220b57cec5SDimitry Andric using namespace llvm; 230b57cec5SDimitry Andric 24bdd1243dSDimitry Andric void llvm::createMemCpyLoopKnownSize( 25bdd1243dSDimitry Andric Instruction *InsertBefore, Value *SrcAddr, Value *DstAddr, 26bdd1243dSDimitry Andric ConstantInt *CopyLen, Align SrcAlign, Align DstAlign, bool SrcIsVolatile, 27bdd1243dSDimitry Andric bool DstIsVolatile, bool CanOverlap, const TargetTransformInfo &TTI, 28bdd1243dSDimitry Andric std::optional<uint32_t> AtomicElementSize) { 290b57cec5SDimitry Andric // No need to expand zero length copies. 300b57cec5SDimitry Andric if (CopyLen->isZero()) 310b57cec5SDimitry Andric return; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric BasicBlock *PreLoopBB = InsertBefore->getParent(); 340b57cec5SDimitry Andric BasicBlock *PostLoopBB = nullptr; 350b57cec5SDimitry Andric Function *ParentFunc = PreLoopBB->getParent(); 360b57cec5SDimitry Andric LLVMContext &Ctx = PreLoopBB->getContext(); 37*0fca6ea1SDimitry Andric const DataLayout &DL = ParentFunc->getDataLayout(); 3881ad6265SDimitry Andric MDBuilder MDB(Ctx); 3981ad6265SDimitry Andric MDNode *NewDomain = MDB.createAnonymousAliasScopeDomain("MemCopyDomain"); 4081ad6265SDimitry Andric StringRef Name = "MemCopyAliasScope"; 4181ad6265SDimitry Andric MDNode *NewScope = MDB.createAnonymousAliasScope(NewDomain, Name); 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric unsigned SrcAS = cast<PointerType>(SrcAddr->getType())->getAddressSpace(); 440b57cec5SDimitry Andric unsigned DstAS = cast<PointerType>(DstAddr->getType())->getAddressSpace(); 450b57cec5SDimitry Andric 465ffd83dbSDimitry Andric Type *TypeOfCopyLen = CopyLen->getType(); 475ffd83dbSDimitry Andric Type *LoopOpType = TTI.getMemcpyLoopLoweringType( 4881ad6265SDimitry Andric Ctx, CopyLen, SrcAS, DstAS, SrcAlign.value(), DstAlign.value(), 4981ad6265SDimitry Andric AtomicElementSize); 5081ad6265SDimitry Andric assert((!AtomicElementSize || !LoopOpType->isVectorTy()) && 5181ad6265SDimitry Andric "Atomic memcpy lowering is not supported for vector operand type"); 525ffd83dbSDimitry Andric 535ffd83dbSDimitry Andric unsigned LoopOpSize = DL.getTypeStoreSize(LoopOpType); 5481ad6265SDimitry Andric assert((!AtomicElementSize || LoopOpSize % *AtomicElementSize == 0) && 5581ad6265SDimitry Andric "Atomic memcpy lowering is not supported for selected operand size"); 5681ad6265SDimitry Andric 575ffd83dbSDimitry Andric uint64_t LoopEndCount = CopyLen->getZExtValue() / LoopOpSize; 585ffd83dbSDimitry Andric 590b57cec5SDimitry Andric if (LoopEndCount != 0) { 600b57cec5SDimitry Andric // Split 610b57cec5SDimitry Andric PostLoopBB = PreLoopBB->splitBasicBlock(InsertBefore, "memcpy-split"); 620b57cec5SDimitry Andric BasicBlock *LoopBB = 630b57cec5SDimitry Andric BasicBlock::Create(Ctx, "load-store-loop", ParentFunc, PostLoopBB); 640b57cec5SDimitry Andric PreLoopBB->getTerminator()->setSuccessor(0, LoopBB); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric IRBuilder<> PLBuilder(PreLoopBB->getTerminator()); 670b57cec5SDimitry Andric 685ffd83dbSDimitry Andric Align PartDstAlign(commonAlignment(DstAlign, LoopOpSize)); 695ffd83dbSDimitry Andric Align PartSrcAlign(commonAlignment(SrcAlign, LoopOpSize)); 705ffd83dbSDimitry Andric 710b57cec5SDimitry Andric IRBuilder<> LoopBuilder(LoopBB); 720b57cec5SDimitry Andric PHINode *LoopIndex = LoopBuilder.CreatePHI(TypeOfCopyLen, 2, "loop-index"); 730b57cec5SDimitry Andric LoopIndex->addIncoming(ConstantInt::get(TypeOfCopyLen, 0U), PreLoopBB); 740b57cec5SDimitry Andric // Loop Body 750b57cec5SDimitry Andric Value *SrcGEP = 760b57cec5SDimitry Andric LoopBuilder.CreateInBoundsGEP(LoopOpType, SrcAddr, LoopIndex); 7781ad6265SDimitry Andric LoadInst *Load = LoopBuilder.CreateAlignedLoad(LoopOpType, SrcGEP, 785ffd83dbSDimitry Andric PartSrcAlign, SrcIsVolatile); 7981ad6265SDimitry Andric if (!CanOverlap) { 8081ad6265SDimitry Andric // Set alias scope for loads. 8181ad6265SDimitry Andric Load->setMetadata(LLVMContext::MD_alias_scope, 8281ad6265SDimitry Andric MDNode::get(Ctx, NewScope)); 8381ad6265SDimitry Andric } 840b57cec5SDimitry Andric Value *DstGEP = 850b57cec5SDimitry Andric LoopBuilder.CreateInBoundsGEP(LoopOpType, DstAddr, LoopIndex); 8681ad6265SDimitry Andric StoreInst *Store = LoopBuilder.CreateAlignedStore( 8781ad6265SDimitry Andric Load, DstGEP, PartDstAlign, DstIsVolatile); 8881ad6265SDimitry Andric if (!CanOverlap) { 8981ad6265SDimitry Andric // Indicate that stores don't overlap loads. 9081ad6265SDimitry Andric Store->setMetadata(LLVMContext::MD_noalias, MDNode::get(Ctx, NewScope)); 9181ad6265SDimitry Andric } 9281ad6265SDimitry Andric if (AtomicElementSize) { 9381ad6265SDimitry Andric Load->setAtomic(AtomicOrdering::Unordered); 9481ad6265SDimitry Andric Store->setAtomic(AtomicOrdering::Unordered); 9581ad6265SDimitry Andric } 960b57cec5SDimitry Andric Value *NewIndex = 970b57cec5SDimitry Andric LoopBuilder.CreateAdd(LoopIndex, ConstantInt::get(TypeOfCopyLen, 1U)); 980b57cec5SDimitry Andric LoopIndex->addIncoming(NewIndex, LoopBB); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric // Create the loop branch condition. 1010b57cec5SDimitry Andric Constant *LoopEndCI = ConstantInt::get(TypeOfCopyLen, LoopEndCount); 1020b57cec5SDimitry Andric LoopBuilder.CreateCondBr(LoopBuilder.CreateICmpULT(NewIndex, LoopEndCI), 1030b57cec5SDimitry Andric LoopBB, PostLoopBB); 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric uint64_t BytesCopied = LoopEndCount * LoopOpSize; 1070b57cec5SDimitry Andric uint64_t RemainingBytes = CopyLen->getZExtValue() - BytesCopied; 1080b57cec5SDimitry Andric if (RemainingBytes) { 1090b57cec5SDimitry Andric IRBuilder<> RBuilder(PostLoopBB ? PostLoopBB->getFirstNonPHI() 1100b57cec5SDimitry Andric : InsertBefore); 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric SmallVector<Type *, 5> RemainingOps; 1130b57cec5SDimitry Andric TTI.getMemcpyLoopResidualLoweringType(RemainingOps, Ctx, RemainingBytes, 1145ffd83dbSDimitry Andric SrcAS, DstAS, SrcAlign.value(), 11581ad6265SDimitry Andric DstAlign.value(), AtomicElementSize); 1160b57cec5SDimitry Andric 117bdd1243dSDimitry Andric for (auto *OpTy : RemainingOps) { 1185ffd83dbSDimitry Andric Align PartSrcAlign(commonAlignment(SrcAlign, BytesCopied)); 1195ffd83dbSDimitry Andric Align PartDstAlign(commonAlignment(DstAlign, BytesCopied)); 1205ffd83dbSDimitry Andric 121bdd1243dSDimitry Andric // Calculate the new index 1225ffd83dbSDimitry Andric unsigned OperandSize = DL.getTypeStoreSize(OpTy); 12381ad6265SDimitry Andric assert( 12481ad6265SDimitry Andric (!AtomicElementSize || OperandSize % *AtomicElementSize == 0) && 12581ad6265SDimitry Andric "Atomic memcpy lowering is not supported for selected operand size"); 12681ad6265SDimitry Andric 1270b57cec5SDimitry Andric uint64_t GepIndex = BytesCopied / OperandSize; 1280b57cec5SDimitry Andric assert(GepIndex * OperandSize == BytesCopied && 1290b57cec5SDimitry Andric "Division should have no Remainder!"); 1305f757f3fSDimitry Andric 1310b57cec5SDimitry Andric Value *SrcGEP = RBuilder.CreateInBoundsGEP( 1325f757f3fSDimitry Andric OpTy, SrcAddr, ConstantInt::get(TypeOfCopyLen, GepIndex)); 13381ad6265SDimitry Andric LoadInst *Load = 1345ffd83dbSDimitry Andric RBuilder.CreateAlignedLoad(OpTy, SrcGEP, PartSrcAlign, SrcIsVolatile); 13581ad6265SDimitry Andric if (!CanOverlap) { 13681ad6265SDimitry Andric // Set alias scope for loads. 13781ad6265SDimitry Andric Load->setMetadata(LLVMContext::MD_alias_scope, 13881ad6265SDimitry Andric MDNode::get(Ctx, NewScope)); 13981ad6265SDimitry Andric } 1400b57cec5SDimitry Andric Value *DstGEP = RBuilder.CreateInBoundsGEP( 1415f757f3fSDimitry Andric OpTy, DstAddr, ConstantInt::get(TypeOfCopyLen, GepIndex)); 14281ad6265SDimitry Andric StoreInst *Store = RBuilder.CreateAlignedStore(Load, DstGEP, PartDstAlign, 14381ad6265SDimitry Andric DstIsVolatile); 14481ad6265SDimitry Andric if (!CanOverlap) { 14581ad6265SDimitry Andric // Indicate that stores don't overlap loads. 14681ad6265SDimitry Andric Store->setMetadata(LLVMContext::MD_noalias, MDNode::get(Ctx, NewScope)); 14781ad6265SDimitry Andric } 14881ad6265SDimitry Andric if (AtomicElementSize) { 14981ad6265SDimitry Andric Load->setAtomic(AtomicOrdering::Unordered); 15081ad6265SDimitry Andric Store->setAtomic(AtomicOrdering::Unordered); 15181ad6265SDimitry Andric } 1520b57cec5SDimitry Andric BytesCopied += OperandSize; 1530b57cec5SDimitry Andric } 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric assert(BytesCopied == CopyLen->getZExtValue() && 1560b57cec5SDimitry Andric "Bytes copied should match size in the call!"); 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 159*0fca6ea1SDimitry Andric // \returns \p Len udiv \p OpSize, checking for optimization opportunities. 160*0fca6ea1SDimitry Andric static Value *getRuntimeLoopCount(const DataLayout &DL, IRBuilderBase &B, 161*0fca6ea1SDimitry Andric Value *Len, Value *OpSize, 162*0fca6ea1SDimitry Andric unsigned OpSizeVal) { 163*0fca6ea1SDimitry Andric // For powers of 2, we can lshr by log2 instead of using udiv. 164*0fca6ea1SDimitry Andric if (isPowerOf2_32(OpSizeVal)) 165*0fca6ea1SDimitry Andric return B.CreateLShr(Len, Log2_32(OpSizeVal)); 166*0fca6ea1SDimitry Andric return B.CreateUDiv(Len, OpSize); 167*0fca6ea1SDimitry Andric } 168*0fca6ea1SDimitry Andric 169*0fca6ea1SDimitry Andric // \returns \p Len urem \p OpSize, checking for optimization opportunities. 170*0fca6ea1SDimitry Andric static Value *getRuntimeLoopRemainder(const DataLayout &DL, IRBuilderBase &B, 171*0fca6ea1SDimitry Andric Value *Len, Value *OpSize, 172*0fca6ea1SDimitry Andric unsigned OpSizeVal) { 173*0fca6ea1SDimitry Andric // For powers of 2, we can and by (OpSizeVal - 1) instead of using urem. 174*0fca6ea1SDimitry Andric if (isPowerOf2_32(OpSizeVal)) 175*0fca6ea1SDimitry Andric return B.CreateAnd(Len, OpSizeVal - 1); 176*0fca6ea1SDimitry Andric return B.CreateURem(Len, OpSize); 177*0fca6ea1SDimitry Andric } 178*0fca6ea1SDimitry Andric 179bdd1243dSDimitry Andric void llvm::createMemCpyLoopUnknownSize( 180bdd1243dSDimitry Andric Instruction *InsertBefore, Value *SrcAddr, Value *DstAddr, Value *CopyLen, 181bdd1243dSDimitry Andric Align SrcAlign, Align DstAlign, bool SrcIsVolatile, bool DstIsVolatile, 182bdd1243dSDimitry Andric bool CanOverlap, const TargetTransformInfo &TTI, 183bdd1243dSDimitry Andric std::optional<uint32_t> AtomicElementSize) { 1840b57cec5SDimitry Andric BasicBlock *PreLoopBB = InsertBefore->getParent(); 1850b57cec5SDimitry Andric BasicBlock *PostLoopBB = 1860b57cec5SDimitry Andric PreLoopBB->splitBasicBlock(InsertBefore, "post-loop-memcpy-expansion"); 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric Function *ParentFunc = PreLoopBB->getParent(); 189*0fca6ea1SDimitry Andric const DataLayout &DL = ParentFunc->getDataLayout(); 1900b57cec5SDimitry Andric LLVMContext &Ctx = PreLoopBB->getContext(); 19181ad6265SDimitry Andric MDBuilder MDB(Ctx); 19281ad6265SDimitry Andric MDNode *NewDomain = MDB.createAnonymousAliasScopeDomain("MemCopyDomain"); 19381ad6265SDimitry Andric StringRef Name = "MemCopyAliasScope"; 19481ad6265SDimitry Andric MDNode *NewScope = MDB.createAnonymousAliasScope(NewDomain, Name); 19581ad6265SDimitry Andric 1965ffd83dbSDimitry Andric unsigned SrcAS = cast<PointerType>(SrcAddr->getType())->getAddressSpace(); 1975ffd83dbSDimitry Andric unsigned DstAS = cast<PointerType>(DstAddr->getType())->getAddressSpace(); 1980b57cec5SDimitry Andric 1995ffd83dbSDimitry Andric Type *LoopOpType = TTI.getMemcpyLoopLoweringType( 20081ad6265SDimitry Andric Ctx, CopyLen, SrcAS, DstAS, SrcAlign.value(), DstAlign.value(), 20181ad6265SDimitry Andric AtomicElementSize); 20281ad6265SDimitry Andric assert((!AtomicElementSize || !LoopOpType->isVectorTy()) && 20381ad6265SDimitry Andric "Atomic memcpy lowering is not supported for vector operand type"); 2045ffd83dbSDimitry Andric unsigned LoopOpSize = DL.getTypeStoreSize(LoopOpType); 20581ad6265SDimitry Andric assert((!AtomicElementSize || LoopOpSize % *AtomicElementSize == 0) && 20681ad6265SDimitry Andric "Atomic memcpy lowering is not supported for selected operand size"); 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric IRBuilder<> PLBuilder(PreLoopBB->getTerminator()); 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric // Calculate the loop trip count, and remaining bytes to copy after the loop. 2110b57cec5SDimitry Andric Type *CopyLenType = CopyLen->getType(); 2120b57cec5SDimitry Andric IntegerType *ILengthType = dyn_cast<IntegerType>(CopyLenType); 2130b57cec5SDimitry Andric assert(ILengthType && 2140b57cec5SDimitry Andric "expected size argument to memcpy to be an integer type!"); 2150b57cec5SDimitry Andric Type *Int8Type = Type::getInt8Ty(Ctx); 2160b57cec5SDimitry Andric bool LoopOpIsInt8 = LoopOpType == Int8Type; 2170b57cec5SDimitry Andric ConstantInt *CILoopOpSize = ConstantInt::get(ILengthType, LoopOpSize); 218*0fca6ea1SDimitry Andric Value *RuntimeLoopCount = LoopOpIsInt8 219*0fca6ea1SDimitry Andric ? CopyLen 220*0fca6ea1SDimitry Andric : getRuntimeLoopCount(DL, PLBuilder, CopyLen, 221*0fca6ea1SDimitry Andric CILoopOpSize, LoopOpSize); 222*0fca6ea1SDimitry Andric 2230b57cec5SDimitry Andric BasicBlock *LoopBB = 2240b57cec5SDimitry Andric BasicBlock::Create(Ctx, "loop-memcpy-expansion", ParentFunc, PostLoopBB); 2250b57cec5SDimitry Andric IRBuilder<> LoopBuilder(LoopBB); 2260b57cec5SDimitry Andric 2275ffd83dbSDimitry Andric Align PartSrcAlign(commonAlignment(SrcAlign, LoopOpSize)); 2285ffd83dbSDimitry Andric Align PartDstAlign(commonAlignment(DstAlign, LoopOpSize)); 2295ffd83dbSDimitry Andric 2300b57cec5SDimitry Andric PHINode *LoopIndex = LoopBuilder.CreatePHI(CopyLenType, 2, "loop-index"); 2310b57cec5SDimitry Andric LoopIndex->addIncoming(ConstantInt::get(CopyLenType, 0U), PreLoopBB); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric Value *SrcGEP = LoopBuilder.CreateInBoundsGEP(LoopOpType, SrcAddr, LoopIndex); 23481ad6265SDimitry Andric LoadInst *Load = LoopBuilder.CreateAlignedLoad(LoopOpType, SrcGEP, 23581ad6265SDimitry Andric PartSrcAlign, SrcIsVolatile); 23681ad6265SDimitry Andric if (!CanOverlap) { 23781ad6265SDimitry Andric // Set alias scope for loads. 23881ad6265SDimitry Andric Load->setMetadata(LLVMContext::MD_alias_scope, MDNode::get(Ctx, NewScope)); 23981ad6265SDimitry Andric } 2400b57cec5SDimitry Andric Value *DstGEP = LoopBuilder.CreateInBoundsGEP(LoopOpType, DstAddr, LoopIndex); 24181ad6265SDimitry Andric StoreInst *Store = 2425ffd83dbSDimitry Andric LoopBuilder.CreateAlignedStore(Load, DstGEP, PartDstAlign, DstIsVolatile); 24381ad6265SDimitry Andric if (!CanOverlap) { 24481ad6265SDimitry Andric // Indicate that stores don't overlap loads. 24581ad6265SDimitry Andric Store->setMetadata(LLVMContext::MD_noalias, MDNode::get(Ctx, NewScope)); 24681ad6265SDimitry Andric } 24781ad6265SDimitry Andric if (AtomicElementSize) { 24881ad6265SDimitry Andric Load->setAtomic(AtomicOrdering::Unordered); 24981ad6265SDimitry Andric Store->setAtomic(AtomicOrdering::Unordered); 25081ad6265SDimitry Andric } 2510b57cec5SDimitry Andric Value *NewIndex = 2520b57cec5SDimitry Andric LoopBuilder.CreateAdd(LoopIndex, ConstantInt::get(CopyLenType, 1U)); 2530b57cec5SDimitry Andric LoopIndex->addIncoming(NewIndex, LoopBB); 2540b57cec5SDimitry Andric 25581ad6265SDimitry Andric bool requiresResidual = 25681ad6265SDimitry Andric !LoopOpIsInt8 && !(AtomicElementSize && LoopOpSize == AtomicElementSize); 25781ad6265SDimitry Andric if (requiresResidual) { 25881ad6265SDimitry Andric Type *ResLoopOpType = AtomicElementSize 25981ad6265SDimitry Andric ? Type::getIntNTy(Ctx, *AtomicElementSize * 8) 26081ad6265SDimitry Andric : Int8Type; 26181ad6265SDimitry Andric unsigned ResLoopOpSize = DL.getTypeStoreSize(ResLoopOpType); 26281ad6265SDimitry Andric assert((ResLoopOpSize == AtomicElementSize ? *AtomicElementSize : 1) && 26381ad6265SDimitry Andric "Store size is expected to match type size"); 26481ad6265SDimitry Andric 265*0fca6ea1SDimitry Andric Align ResSrcAlign(commonAlignment(PartSrcAlign, ResLoopOpSize)); 266*0fca6ea1SDimitry Andric Align ResDstAlign(commonAlignment(PartDstAlign, ResLoopOpSize)); 267*0fca6ea1SDimitry Andric 268*0fca6ea1SDimitry Andric Value *RuntimeResidual = getRuntimeLoopRemainder(DL, PLBuilder, CopyLen, 269*0fca6ea1SDimitry Andric CILoopOpSize, LoopOpSize); 2700b57cec5SDimitry Andric Value *RuntimeBytesCopied = PLBuilder.CreateSub(CopyLen, RuntimeResidual); 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric // Loop body for the residual copy. 2730b57cec5SDimitry Andric BasicBlock *ResLoopBB = BasicBlock::Create(Ctx, "loop-memcpy-residual", 2740b57cec5SDimitry Andric PreLoopBB->getParent(), 2750b57cec5SDimitry Andric PostLoopBB); 2760b57cec5SDimitry Andric // Residual loop header. 2770b57cec5SDimitry Andric BasicBlock *ResHeaderBB = BasicBlock::Create( 2780b57cec5SDimitry Andric Ctx, "loop-memcpy-residual-header", PreLoopBB->getParent(), nullptr); 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric // Need to update the pre-loop basic block to branch to the correct place. 2810b57cec5SDimitry Andric // branch to the main loop if the count is non-zero, branch to the residual 2820b57cec5SDimitry Andric // loop if the copy size is smaller then 1 iteration of the main loop but 2830b57cec5SDimitry Andric // non-zero and finally branch to after the residual loop if the memcpy 2840b57cec5SDimitry Andric // size is zero. 2850b57cec5SDimitry Andric ConstantInt *Zero = ConstantInt::get(ILengthType, 0U); 2860b57cec5SDimitry Andric PLBuilder.CreateCondBr(PLBuilder.CreateICmpNE(RuntimeLoopCount, Zero), 2870b57cec5SDimitry Andric LoopBB, ResHeaderBB); 2880b57cec5SDimitry Andric PreLoopBB->getTerminator()->eraseFromParent(); 2890b57cec5SDimitry Andric 2900b57cec5SDimitry Andric LoopBuilder.CreateCondBr( 2910b57cec5SDimitry Andric LoopBuilder.CreateICmpULT(NewIndex, RuntimeLoopCount), LoopBB, 2920b57cec5SDimitry Andric ResHeaderBB); 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric // Determine if we need to branch to the residual loop or bypass it. 2950b57cec5SDimitry Andric IRBuilder<> RHBuilder(ResHeaderBB); 2960b57cec5SDimitry Andric RHBuilder.CreateCondBr(RHBuilder.CreateICmpNE(RuntimeResidual, Zero), 2970b57cec5SDimitry Andric ResLoopBB, PostLoopBB); 2980b57cec5SDimitry Andric 2990b57cec5SDimitry Andric // Copy the residual with single byte load/store loop. 3000b57cec5SDimitry Andric IRBuilder<> ResBuilder(ResLoopBB); 3010b57cec5SDimitry Andric PHINode *ResidualIndex = 3020b57cec5SDimitry Andric ResBuilder.CreatePHI(CopyLenType, 2, "residual-loop-index"); 3030b57cec5SDimitry Andric ResidualIndex->addIncoming(Zero, ResHeaderBB); 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric Value *FullOffset = ResBuilder.CreateAdd(RuntimeBytesCopied, ResidualIndex); 3065f757f3fSDimitry Andric Value *SrcGEP = 3075f757f3fSDimitry Andric ResBuilder.CreateInBoundsGEP(ResLoopOpType, SrcAddr, FullOffset); 30881ad6265SDimitry Andric LoadInst *Load = ResBuilder.CreateAlignedLoad(ResLoopOpType, SrcGEP, 309*0fca6ea1SDimitry Andric ResSrcAlign, SrcIsVolatile); 31081ad6265SDimitry Andric if (!CanOverlap) { 31181ad6265SDimitry Andric // Set alias scope for loads. 31281ad6265SDimitry Andric Load->setMetadata(LLVMContext::MD_alias_scope, 31381ad6265SDimitry Andric MDNode::get(Ctx, NewScope)); 31481ad6265SDimitry Andric } 3155f757f3fSDimitry Andric Value *DstGEP = 3165f757f3fSDimitry Andric ResBuilder.CreateInBoundsGEP(ResLoopOpType, DstAddr, FullOffset); 317*0fca6ea1SDimitry Andric StoreInst *Store = 318*0fca6ea1SDimitry Andric ResBuilder.CreateAlignedStore(Load, DstGEP, ResDstAlign, DstIsVolatile); 31981ad6265SDimitry Andric if (!CanOverlap) { 32081ad6265SDimitry Andric // Indicate that stores don't overlap loads. 32181ad6265SDimitry Andric Store->setMetadata(LLVMContext::MD_noalias, MDNode::get(Ctx, NewScope)); 32281ad6265SDimitry Andric } 32381ad6265SDimitry Andric if (AtomicElementSize) { 32481ad6265SDimitry Andric Load->setAtomic(AtomicOrdering::Unordered); 32581ad6265SDimitry Andric Store->setAtomic(AtomicOrdering::Unordered); 32681ad6265SDimitry Andric } 32781ad6265SDimitry Andric Value *ResNewIndex = ResBuilder.CreateAdd( 32881ad6265SDimitry Andric ResidualIndex, ConstantInt::get(CopyLenType, ResLoopOpSize)); 3290b57cec5SDimitry Andric ResidualIndex->addIncoming(ResNewIndex, ResLoopBB); 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric // Create the loop branch condition. 3320b57cec5SDimitry Andric ResBuilder.CreateCondBr( 3330b57cec5SDimitry Andric ResBuilder.CreateICmpULT(ResNewIndex, RuntimeResidual), ResLoopBB, 3340b57cec5SDimitry Andric PostLoopBB); 3350b57cec5SDimitry Andric } else { 3360b57cec5SDimitry Andric // In this case the loop operand type was a byte, and there is no need for a 3370b57cec5SDimitry Andric // residual loop to copy the remaining memory after the main loop. 3380b57cec5SDimitry Andric // We do however need to patch up the control flow by creating the 3390b57cec5SDimitry Andric // terminators for the preloop block and the memcpy loop. 3400b57cec5SDimitry Andric ConstantInt *Zero = ConstantInt::get(ILengthType, 0U); 3410b57cec5SDimitry Andric PLBuilder.CreateCondBr(PLBuilder.CreateICmpNE(RuntimeLoopCount, Zero), 3420b57cec5SDimitry Andric LoopBB, PostLoopBB); 3430b57cec5SDimitry Andric PreLoopBB->getTerminator()->eraseFromParent(); 3440b57cec5SDimitry Andric LoopBuilder.CreateCondBr( 3450b57cec5SDimitry Andric LoopBuilder.CreateICmpULT(NewIndex, RuntimeLoopCount), LoopBB, 3460b57cec5SDimitry Andric PostLoopBB); 3470b57cec5SDimitry Andric } 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric // Lower memmove to IR. memmove is required to correctly copy overlapping memory 3510b57cec5SDimitry Andric // regions; therefore, it has to check the relative positions of the source and 3520b57cec5SDimitry Andric // destination pointers and choose the copy direction accordingly. 3530b57cec5SDimitry Andric // 3540b57cec5SDimitry Andric // The code below is an IR rendition of this C function: 3550b57cec5SDimitry Andric // 3560b57cec5SDimitry Andric // void* memmove(void* dst, const void* src, size_t n) { 3570b57cec5SDimitry Andric // unsigned char* d = dst; 3580b57cec5SDimitry Andric // const unsigned char* s = src; 3590b57cec5SDimitry Andric // if (s < d) { 3600b57cec5SDimitry Andric // // copy backwards 3610b57cec5SDimitry Andric // while (n--) { 3620b57cec5SDimitry Andric // d[n] = s[n]; 3630b57cec5SDimitry Andric // } 3640b57cec5SDimitry Andric // } else { 3650b57cec5SDimitry Andric // // copy forward 3660b57cec5SDimitry Andric // for (size_t i = 0; i < n; ++i) { 3670b57cec5SDimitry Andric // d[i] = s[i]; 3680b57cec5SDimitry Andric // } 3690b57cec5SDimitry Andric // } 3700b57cec5SDimitry Andric // return dst; 3710b57cec5SDimitry Andric // } 3725ffd83dbSDimitry Andric static void createMemMoveLoop(Instruction *InsertBefore, Value *SrcAddr, 3735ffd83dbSDimitry Andric Value *DstAddr, Value *CopyLen, Align SrcAlign, 3745ffd83dbSDimitry Andric Align DstAlign, bool SrcIsVolatile, 37506c3fb27SDimitry Andric bool DstIsVolatile, 37606c3fb27SDimitry Andric const TargetTransformInfo &TTI) { 3770b57cec5SDimitry Andric Type *TypeOfCopyLen = CopyLen->getType(); 3780b57cec5SDimitry Andric BasicBlock *OrigBB = InsertBefore->getParent(); 3790b57cec5SDimitry Andric Function *F = OrigBB->getParent(); 380*0fca6ea1SDimitry Andric const DataLayout &DL = F->getDataLayout(); 38181ad6265SDimitry Andric // TODO: Use different element type if possible? 38206c3fb27SDimitry Andric Type *EltTy = Type::getInt8Ty(F->getContext()); 3830b57cec5SDimitry Andric 3840b57cec5SDimitry Andric // Create the a comparison of src and dst, based on which we jump to either 3850b57cec5SDimitry Andric // the forward-copy part of the function (if src >= dst) or the backwards-copy 3860b57cec5SDimitry Andric // part (if src < dst). 3870b57cec5SDimitry Andric // SplitBlockAndInsertIfThenElse conveniently creates the basic if-then-else 3880b57cec5SDimitry Andric // structure. Its block terminators (unconditional branches) are replaced by 3890b57cec5SDimitry Andric // the appropriate conditional branches when the loop is built. 390*0fca6ea1SDimitry Andric ICmpInst *PtrCompare = new ICmpInst(InsertBefore->getIterator(), ICmpInst::ICMP_ULT, 3910b57cec5SDimitry Andric SrcAddr, DstAddr, "compare_src_dst"); 3920b57cec5SDimitry Andric Instruction *ThenTerm, *ElseTerm; 393*0fca6ea1SDimitry Andric SplitBlockAndInsertIfThenElse(PtrCompare, InsertBefore->getIterator(), &ThenTerm, 3940b57cec5SDimitry Andric &ElseTerm); 3950b57cec5SDimitry Andric 3960b57cec5SDimitry Andric // Each part of the function consists of two blocks: 3970b57cec5SDimitry Andric // copy_backwards: used to skip the loop when n == 0 3980b57cec5SDimitry Andric // copy_backwards_loop: the actual backwards loop BB 3990b57cec5SDimitry Andric // copy_forward: used to skip the loop when n == 0 4000b57cec5SDimitry Andric // copy_forward_loop: the actual forward loop BB 4010b57cec5SDimitry Andric BasicBlock *CopyBackwardsBB = ThenTerm->getParent(); 4020b57cec5SDimitry Andric CopyBackwardsBB->setName("copy_backwards"); 4030b57cec5SDimitry Andric BasicBlock *CopyForwardBB = ElseTerm->getParent(); 4040b57cec5SDimitry Andric CopyForwardBB->setName("copy_forward"); 4050b57cec5SDimitry Andric BasicBlock *ExitBB = InsertBefore->getParent(); 4060b57cec5SDimitry Andric ExitBB->setName("memmove_done"); 4070b57cec5SDimitry Andric 4085ffd83dbSDimitry Andric unsigned PartSize = DL.getTypeStoreSize(EltTy); 4095ffd83dbSDimitry Andric Align PartSrcAlign(commonAlignment(SrcAlign, PartSize)); 4105ffd83dbSDimitry Andric Align PartDstAlign(commonAlignment(DstAlign, PartSize)); 4115ffd83dbSDimitry Andric 4120b57cec5SDimitry Andric // Initial comparison of n == 0 that lets us skip the loops altogether. Shared 4130b57cec5SDimitry Andric // between both backwards and forward copy clauses. 4140b57cec5SDimitry Andric ICmpInst *CompareN = 415*0fca6ea1SDimitry Andric new ICmpInst(OrigBB->getTerminator()->getIterator(), ICmpInst::ICMP_EQ, CopyLen, 4160b57cec5SDimitry Andric ConstantInt::get(TypeOfCopyLen, 0), "compare_n_to_0"); 4170b57cec5SDimitry Andric 4180b57cec5SDimitry Andric // Copying backwards. 4190b57cec5SDimitry Andric BasicBlock *LoopBB = 4200b57cec5SDimitry Andric BasicBlock::Create(F->getContext(), "copy_backwards_loop", F, CopyForwardBB); 4210b57cec5SDimitry Andric IRBuilder<> LoopBuilder(LoopBB); 42206c3fb27SDimitry Andric 4230b57cec5SDimitry Andric PHINode *LoopPhi = LoopBuilder.CreatePHI(TypeOfCopyLen, 0); 4240b57cec5SDimitry Andric Value *IndexPtr = LoopBuilder.CreateSub( 4250b57cec5SDimitry Andric LoopPhi, ConstantInt::get(TypeOfCopyLen, 1), "index_ptr"); 4265ffd83dbSDimitry Andric Value *Element = LoopBuilder.CreateAlignedLoad( 4270b57cec5SDimitry Andric EltTy, LoopBuilder.CreateInBoundsGEP(EltTy, SrcAddr, IndexPtr), 428*0fca6ea1SDimitry Andric PartSrcAlign, SrcIsVolatile, "element"); 4295ffd83dbSDimitry Andric LoopBuilder.CreateAlignedStore( 4305ffd83dbSDimitry Andric Element, LoopBuilder.CreateInBoundsGEP(EltTy, DstAddr, IndexPtr), 431*0fca6ea1SDimitry Andric PartDstAlign, DstIsVolatile); 4320b57cec5SDimitry Andric LoopBuilder.CreateCondBr( 4330b57cec5SDimitry Andric LoopBuilder.CreateICmpEQ(IndexPtr, ConstantInt::get(TypeOfCopyLen, 0)), 4340b57cec5SDimitry Andric ExitBB, LoopBB); 4350b57cec5SDimitry Andric LoopPhi->addIncoming(IndexPtr, LoopBB); 4360b57cec5SDimitry Andric LoopPhi->addIncoming(CopyLen, CopyBackwardsBB); 437*0fca6ea1SDimitry Andric BranchInst::Create(ExitBB, LoopBB, CompareN, ThenTerm->getIterator()); 4380b57cec5SDimitry Andric ThenTerm->eraseFromParent(); 4390b57cec5SDimitry Andric 4400b57cec5SDimitry Andric // Copying forward. 4410b57cec5SDimitry Andric BasicBlock *FwdLoopBB = 4420b57cec5SDimitry Andric BasicBlock::Create(F->getContext(), "copy_forward_loop", F, ExitBB); 4430b57cec5SDimitry Andric IRBuilder<> FwdLoopBuilder(FwdLoopBB); 4440b57cec5SDimitry Andric PHINode *FwdCopyPhi = FwdLoopBuilder.CreatePHI(TypeOfCopyLen, 0, "index_ptr"); 4455ffd83dbSDimitry Andric Value *SrcGEP = FwdLoopBuilder.CreateInBoundsGEP(EltTy, SrcAddr, FwdCopyPhi); 446*0fca6ea1SDimitry Andric Value *FwdElement = FwdLoopBuilder.CreateAlignedLoad( 447*0fca6ea1SDimitry Andric EltTy, SrcGEP, PartSrcAlign, SrcIsVolatile, "element"); 4485ffd83dbSDimitry Andric Value *DstGEP = FwdLoopBuilder.CreateInBoundsGEP(EltTy, DstAddr, FwdCopyPhi); 449*0fca6ea1SDimitry Andric FwdLoopBuilder.CreateAlignedStore(FwdElement, DstGEP, PartDstAlign, 450*0fca6ea1SDimitry Andric DstIsVolatile); 4510b57cec5SDimitry Andric Value *FwdIndexPtr = FwdLoopBuilder.CreateAdd( 4520b57cec5SDimitry Andric FwdCopyPhi, ConstantInt::get(TypeOfCopyLen, 1), "index_increment"); 4530b57cec5SDimitry Andric FwdLoopBuilder.CreateCondBr(FwdLoopBuilder.CreateICmpEQ(FwdIndexPtr, CopyLen), 4540b57cec5SDimitry Andric ExitBB, FwdLoopBB); 4550b57cec5SDimitry Andric FwdCopyPhi->addIncoming(FwdIndexPtr, FwdLoopBB); 4560b57cec5SDimitry Andric FwdCopyPhi->addIncoming(ConstantInt::get(TypeOfCopyLen, 0), CopyForwardBB); 4570b57cec5SDimitry Andric 458*0fca6ea1SDimitry Andric BranchInst::Create(ExitBB, FwdLoopBB, CompareN, ElseTerm->getIterator()); 4590b57cec5SDimitry Andric ElseTerm->eraseFromParent(); 4600b57cec5SDimitry Andric } 4610b57cec5SDimitry Andric 4625ffd83dbSDimitry Andric static void createMemSetLoop(Instruction *InsertBefore, Value *DstAddr, 4635ffd83dbSDimitry Andric Value *CopyLen, Value *SetValue, Align DstAlign, 4645ffd83dbSDimitry Andric bool IsVolatile) { 4650b57cec5SDimitry Andric Type *TypeOfCopyLen = CopyLen->getType(); 4660b57cec5SDimitry Andric BasicBlock *OrigBB = InsertBefore->getParent(); 4670b57cec5SDimitry Andric Function *F = OrigBB->getParent(); 468*0fca6ea1SDimitry Andric const DataLayout &DL = F->getDataLayout(); 4690b57cec5SDimitry Andric BasicBlock *NewBB = 4700b57cec5SDimitry Andric OrigBB->splitBasicBlock(InsertBefore, "split"); 4710b57cec5SDimitry Andric BasicBlock *LoopBB 4720b57cec5SDimitry Andric = BasicBlock::Create(F->getContext(), "loadstoreloop", F, NewBB); 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric IRBuilder<> Builder(OrigBB->getTerminator()); 4750b57cec5SDimitry Andric 4760b57cec5SDimitry Andric Builder.CreateCondBr( 4770b57cec5SDimitry Andric Builder.CreateICmpEQ(ConstantInt::get(TypeOfCopyLen, 0), CopyLen), NewBB, 4780b57cec5SDimitry Andric LoopBB); 4790b57cec5SDimitry Andric OrigBB->getTerminator()->eraseFromParent(); 4800b57cec5SDimitry Andric 4815ffd83dbSDimitry Andric unsigned PartSize = DL.getTypeStoreSize(SetValue->getType()); 4825ffd83dbSDimitry Andric Align PartAlign(commonAlignment(DstAlign, PartSize)); 4835ffd83dbSDimitry Andric 4840b57cec5SDimitry Andric IRBuilder<> LoopBuilder(LoopBB); 4850b57cec5SDimitry Andric PHINode *LoopIndex = LoopBuilder.CreatePHI(TypeOfCopyLen, 0); 4860b57cec5SDimitry Andric LoopIndex->addIncoming(ConstantInt::get(TypeOfCopyLen, 0), OrigBB); 4870b57cec5SDimitry Andric 4885ffd83dbSDimitry Andric LoopBuilder.CreateAlignedStore( 4890b57cec5SDimitry Andric SetValue, 4900b57cec5SDimitry Andric LoopBuilder.CreateInBoundsGEP(SetValue->getType(), DstAddr, LoopIndex), 4915ffd83dbSDimitry Andric PartAlign, IsVolatile); 4920b57cec5SDimitry Andric 4930b57cec5SDimitry Andric Value *NewIndex = 4940b57cec5SDimitry Andric LoopBuilder.CreateAdd(LoopIndex, ConstantInt::get(TypeOfCopyLen, 1)); 4950b57cec5SDimitry Andric LoopIndex->addIncoming(NewIndex, LoopBB); 4960b57cec5SDimitry Andric 4970b57cec5SDimitry Andric LoopBuilder.CreateCondBr(LoopBuilder.CreateICmpULT(NewIndex, CopyLen), LoopBB, 4980b57cec5SDimitry Andric NewBB); 4990b57cec5SDimitry Andric } 5000b57cec5SDimitry Andric 50181ad6265SDimitry Andric template <typename T> 50281ad6265SDimitry Andric static bool canOverlap(MemTransferBase<T> *Memcpy, ScalarEvolution *SE) { 50381ad6265SDimitry Andric if (SE) { 50481ad6265SDimitry Andric auto *SrcSCEV = SE->getSCEV(Memcpy->getRawSource()); 50581ad6265SDimitry Andric auto *DestSCEV = SE->getSCEV(Memcpy->getRawDest()); 50681ad6265SDimitry Andric if (SE->isKnownPredicateAt(CmpInst::ICMP_NE, SrcSCEV, DestSCEV, Memcpy)) 50781ad6265SDimitry Andric return false; 50881ad6265SDimitry Andric } 50981ad6265SDimitry Andric return true; 51081ad6265SDimitry Andric } 51181ad6265SDimitry Andric 5120b57cec5SDimitry Andric void llvm::expandMemCpyAsLoop(MemCpyInst *Memcpy, 51381ad6265SDimitry Andric const TargetTransformInfo &TTI, 51481ad6265SDimitry Andric ScalarEvolution *SE) { 51581ad6265SDimitry Andric bool CanOverlap = canOverlap(Memcpy, SE); 5160b57cec5SDimitry Andric if (ConstantInt *CI = dyn_cast<ConstantInt>(Memcpy->getLength())) { 5175ffd83dbSDimitry Andric createMemCpyLoopKnownSize( 5185ffd83dbSDimitry Andric /* InsertBefore */ Memcpy, 5190b57cec5SDimitry Andric /* SrcAddr */ Memcpy->getRawSource(), 5200b57cec5SDimitry Andric /* DstAddr */ Memcpy->getRawDest(), 5210b57cec5SDimitry Andric /* CopyLen */ CI, 5225ffd83dbSDimitry Andric /* SrcAlign */ Memcpy->getSourceAlign().valueOrOne(), 5235ffd83dbSDimitry Andric /* DestAlign */ Memcpy->getDestAlign().valueOrOne(), 5240b57cec5SDimitry Andric /* SrcIsVolatile */ Memcpy->isVolatile(), 5250b57cec5SDimitry Andric /* DstIsVolatile */ Memcpy->isVolatile(), 52681ad6265SDimitry Andric /* CanOverlap */ CanOverlap, 5270b57cec5SDimitry Andric /* TargetTransformInfo */ TTI); 5280b57cec5SDimitry Andric } else { 5295ffd83dbSDimitry Andric createMemCpyLoopUnknownSize( 5305ffd83dbSDimitry Andric /* InsertBefore */ Memcpy, 5310b57cec5SDimitry Andric /* SrcAddr */ Memcpy->getRawSource(), 5320b57cec5SDimitry Andric /* DstAddr */ Memcpy->getRawDest(), 5330b57cec5SDimitry Andric /* CopyLen */ Memcpy->getLength(), 5345ffd83dbSDimitry Andric /* SrcAlign */ Memcpy->getSourceAlign().valueOrOne(), 5355ffd83dbSDimitry Andric /* DestAlign */ Memcpy->getDestAlign().valueOrOne(), 5360b57cec5SDimitry Andric /* SrcIsVolatile */ Memcpy->isVolatile(), 5370b57cec5SDimitry Andric /* DstIsVolatile */ Memcpy->isVolatile(), 53881ad6265SDimitry Andric /* CanOverlap */ CanOverlap, 539349cc55cSDimitry Andric /* TargetTransformInfo */ TTI); 5400b57cec5SDimitry Andric } 5410b57cec5SDimitry Andric } 5420b57cec5SDimitry Andric 54306c3fb27SDimitry Andric bool llvm::expandMemMoveAsLoop(MemMoveInst *Memmove, 54406c3fb27SDimitry Andric const TargetTransformInfo &TTI) { 54506c3fb27SDimitry Andric Value *CopyLen = Memmove->getLength(); 54606c3fb27SDimitry Andric Value *SrcAddr = Memmove->getRawSource(); 54706c3fb27SDimitry Andric Value *DstAddr = Memmove->getRawDest(); 54806c3fb27SDimitry Andric Align SrcAlign = Memmove->getSourceAlign().valueOrOne(); 54906c3fb27SDimitry Andric Align DstAlign = Memmove->getDestAlign().valueOrOne(); 55006c3fb27SDimitry Andric bool SrcIsVolatile = Memmove->isVolatile(); 55106c3fb27SDimitry Andric bool DstIsVolatile = SrcIsVolatile; 55206c3fb27SDimitry Andric IRBuilder<> CastBuilder(Memmove); 55306c3fb27SDimitry Andric 55406c3fb27SDimitry Andric unsigned SrcAS = SrcAddr->getType()->getPointerAddressSpace(); 55506c3fb27SDimitry Andric unsigned DstAS = DstAddr->getType()->getPointerAddressSpace(); 55606c3fb27SDimitry Andric if (SrcAS != DstAS) { 55706c3fb27SDimitry Andric if (!TTI.addrspacesMayAlias(SrcAS, DstAS)) { 55806c3fb27SDimitry Andric // We may not be able to emit a pointer comparison, but we don't have 55906c3fb27SDimitry Andric // to. Expand as memcpy. 56006c3fb27SDimitry Andric if (ConstantInt *CI = dyn_cast<ConstantInt>(CopyLen)) { 56106c3fb27SDimitry Andric createMemCpyLoopKnownSize(/*InsertBefore=*/Memmove, SrcAddr, DstAddr, 56206c3fb27SDimitry Andric CI, SrcAlign, DstAlign, SrcIsVolatile, 56306c3fb27SDimitry Andric DstIsVolatile, 56406c3fb27SDimitry Andric /*CanOverlap=*/false, TTI); 56506c3fb27SDimitry Andric } else { 56606c3fb27SDimitry Andric createMemCpyLoopUnknownSize(/*InsertBefore=*/Memmove, SrcAddr, DstAddr, 56706c3fb27SDimitry Andric CopyLen, SrcAlign, DstAlign, SrcIsVolatile, 56806c3fb27SDimitry Andric DstIsVolatile, 56906c3fb27SDimitry Andric /*CanOverlap=*/false, TTI); 57006c3fb27SDimitry Andric } 57106c3fb27SDimitry Andric 57206c3fb27SDimitry Andric return true; 57306c3fb27SDimitry Andric } 57406c3fb27SDimitry Andric 57506c3fb27SDimitry Andric if (TTI.isValidAddrSpaceCast(DstAS, SrcAS)) 57606c3fb27SDimitry Andric DstAddr = CastBuilder.CreateAddrSpaceCast(DstAddr, SrcAddr->getType()); 57706c3fb27SDimitry Andric else if (TTI.isValidAddrSpaceCast(SrcAS, DstAS)) 57806c3fb27SDimitry Andric SrcAddr = CastBuilder.CreateAddrSpaceCast(SrcAddr, DstAddr->getType()); 57906c3fb27SDimitry Andric else { 58006c3fb27SDimitry Andric // We don't know generically if it's legal to introduce an 58106c3fb27SDimitry Andric // addrspacecast. We need to know either if it's legal to insert an 58206c3fb27SDimitry Andric // addrspacecast, or if the address spaces cannot alias. 58306c3fb27SDimitry Andric LLVM_DEBUG( 58406c3fb27SDimitry Andric dbgs() << "Do not know how to expand memmove between different " 58506c3fb27SDimitry Andric "address spaces\n"); 58606c3fb27SDimitry Andric return false; 58706c3fb27SDimitry Andric } 58806c3fb27SDimitry Andric } 58906c3fb27SDimitry Andric 59006c3fb27SDimitry Andric createMemMoveLoop( 59106c3fb27SDimitry Andric /*InsertBefore=*/Memmove, SrcAddr, DstAddr, CopyLen, SrcAlign, DstAlign, 59206c3fb27SDimitry Andric SrcIsVolatile, DstIsVolatile, TTI); 59306c3fb27SDimitry Andric return true; 5940b57cec5SDimitry Andric } 5950b57cec5SDimitry Andric 5960b57cec5SDimitry Andric void llvm::expandMemSetAsLoop(MemSetInst *Memset) { 5970b57cec5SDimitry Andric createMemSetLoop(/* InsertBefore */ Memset, 5980b57cec5SDimitry Andric /* DstAddr */ Memset->getRawDest(), 5990b57cec5SDimitry Andric /* CopyLen */ Memset->getLength(), 6000b57cec5SDimitry Andric /* SetValue */ Memset->getValue(), 6015ffd83dbSDimitry Andric /* Alignment */ Memset->getDestAlign().valueOrOne(), 6020b57cec5SDimitry Andric Memset->isVolatile()); 6030b57cec5SDimitry Andric } 60481ad6265SDimitry Andric 60581ad6265SDimitry Andric void llvm::expandAtomicMemCpyAsLoop(AtomicMemCpyInst *AtomicMemcpy, 60681ad6265SDimitry Andric const TargetTransformInfo &TTI, 60781ad6265SDimitry Andric ScalarEvolution *SE) { 60881ad6265SDimitry Andric if (ConstantInt *CI = dyn_cast<ConstantInt>(AtomicMemcpy->getLength())) { 60981ad6265SDimitry Andric createMemCpyLoopKnownSize( 61081ad6265SDimitry Andric /* InsertBefore */ AtomicMemcpy, 61181ad6265SDimitry Andric /* SrcAddr */ AtomicMemcpy->getRawSource(), 61281ad6265SDimitry Andric /* DstAddr */ AtomicMemcpy->getRawDest(), 61381ad6265SDimitry Andric /* CopyLen */ CI, 61481ad6265SDimitry Andric /* SrcAlign */ AtomicMemcpy->getSourceAlign().valueOrOne(), 61581ad6265SDimitry Andric /* DestAlign */ AtomicMemcpy->getDestAlign().valueOrOne(), 61681ad6265SDimitry Andric /* SrcIsVolatile */ AtomicMemcpy->isVolatile(), 61781ad6265SDimitry Andric /* DstIsVolatile */ AtomicMemcpy->isVolatile(), 61881ad6265SDimitry Andric /* CanOverlap */ false, // SrcAddr & DstAddr may not overlap by spec. 61981ad6265SDimitry Andric /* TargetTransformInfo */ TTI, 62081ad6265SDimitry Andric /* AtomicCpySize */ AtomicMemcpy->getElementSizeInBytes()); 62181ad6265SDimitry Andric } else { 62281ad6265SDimitry Andric createMemCpyLoopUnknownSize( 62381ad6265SDimitry Andric /* InsertBefore */ AtomicMemcpy, 62481ad6265SDimitry Andric /* SrcAddr */ AtomicMemcpy->getRawSource(), 62581ad6265SDimitry Andric /* DstAddr */ AtomicMemcpy->getRawDest(), 62681ad6265SDimitry Andric /* CopyLen */ AtomicMemcpy->getLength(), 62781ad6265SDimitry Andric /* SrcAlign */ AtomicMemcpy->getSourceAlign().valueOrOne(), 62881ad6265SDimitry Andric /* DestAlign */ AtomicMemcpy->getDestAlign().valueOrOne(), 62981ad6265SDimitry Andric /* SrcIsVolatile */ AtomicMemcpy->isVolatile(), 63081ad6265SDimitry Andric /* DstIsVolatile */ AtomicMemcpy->isVolatile(), 63181ad6265SDimitry Andric /* CanOverlap */ false, // SrcAddr & DstAddr may not overlap by spec. 63281ad6265SDimitry Andric /* TargetTransformInfo */ TTI, 63381ad6265SDimitry Andric /* AtomicCpySize */ AtomicMemcpy->getElementSizeInBytes()); 63481ad6265SDimitry Andric } 63581ad6265SDimitry Andric } 636