1 //===- LowerMemIntrinsics.cpp ----------------------------------*- C++ -*--===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
10 #include "llvm/Analysis/TargetTransformInfo.h"
11 #include "llvm/IR/IRBuilder.h"
12 #include "llvm/IR/IntrinsicInst.h"
13 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
17 void llvm::createMemCpyLoopKnownSize(Instruction
*InsertBefore
, Value
*SrcAddr
,
18 Value
*DstAddr
, ConstantInt
*CopyLen
,
19 Align SrcAlign
, Align DstAlign
,
20 bool SrcIsVolatile
, bool DstIsVolatile
,
21 const TargetTransformInfo
&TTI
) {
22 // No need to expand zero length copies.
23 if (CopyLen
->isZero())
26 BasicBlock
*PreLoopBB
= InsertBefore
->getParent();
27 BasicBlock
*PostLoopBB
= nullptr;
28 Function
*ParentFunc
= PreLoopBB
->getParent();
29 LLVMContext
&Ctx
= PreLoopBB
->getContext();
30 const DataLayout
&DL
= ParentFunc
->getParent()->getDataLayout();
32 unsigned SrcAS
= cast
<PointerType
>(SrcAddr
->getType())->getAddressSpace();
33 unsigned DstAS
= cast
<PointerType
>(DstAddr
->getType())->getAddressSpace();
35 Type
*TypeOfCopyLen
= CopyLen
->getType();
36 Type
*LoopOpType
= TTI
.getMemcpyLoopLoweringType(
37 Ctx
, CopyLen
, SrcAS
, DstAS
, SrcAlign
.value(), DstAlign
.value());
39 unsigned LoopOpSize
= DL
.getTypeStoreSize(LoopOpType
);
40 uint64_t LoopEndCount
= CopyLen
->getZExtValue() / LoopOpSize
;
42 if (LoopEndCount
!= 0) {
44 PostLoopBB
= PreLoopBB
->splitBasicBlock(InsertBefore
, "memcpy-split");
46 BasicBlock::Create(Ctx
, "load-store-loop", ParentFunc
, PostLoopBB
);
47 PreLoopBB
->getTerminator()->setSuccessor(0, LoopBB
);
49 IRBuilder
<> PLBuilder(PreLoopBB
->getTerminator());
51 // Cast the Src and Dst pointers to pointers to the loop operand type (if
53 PointerType
*SrcOpType
= PointerType::get(LoopOpType
, SrcAS
);
54 PointerType
*DstOpType
= PointerType::get(LoopOpType
, DstAS
);
55 if (SrcAddr
->getType() != SrcOpType
) {
56 SrcAddr
= PLBuilder
.CreateBitCast(SrcAddr
, SrcOpType
);
58 if (DstAddr
->getType() != DstOpType
) {
59 DstAddr
= PLBuilder
.CreateBitCast(DstAddr
, DstOpType
);
62 Align
PartDstAlign(commonAlignment(DstAlign
, LoopOpSize
));
63 Align
PartSrcAlign(commonAlignment(SrcAlign
, LoopOpSize
));
65 IRBuilder
<> LoopBuilder(LoopBB
);
66 PHINode
*LoopIndex
= LoopBuilder
.CreatePHI(TypeOfCopyLen
, 2, "loop-index");
67 LoopIndex
->addIncoming(ConstantInt::get(TypeOfCopyLen
, 0U), PreLoopBB
);
70 LoopBuilder
.CreateInBoundsGEP(LoopOpType
, SrcAddr
, LoopIndex
);
71 Value
*Load
= LoopBuilder
.CreateAlignedLoad(LoopOpType
, SrcGEP
,
72 PartSrcAlign
, SrcIsVolatile
);
74 LoopBuilder
.CreateInBoundsGEP(LoopOpType
, DstAddr
, LoopIndex
);
75 LoopBuilder
.CreateAlignedStore(Load
, DstGEP
, PartDstAlign
, DstIsVolatile
);
78 LoopBuilder
.CreateAdd(LoopIndex
, ConstantInt::get(TypeOfCopyLen
, 1U));
79 LoopIndex
->addIncoming(NewIndex
, LoopBB
);
81 // Create the loop branch condition.
82 Constant
*LoopEndCI
= ConstantInt::get(TypeOfCopyLen
, LoopEndCount
);
83 LoopBuilder
.CreateCondBr(LoopBuilder
.CreateICmpULT(NewIndex
, LoopEndCI
),
87 uint64_t BytesCopied
= LoopEndCount
* LoopOpSize
;
88 uint64_t RemainingBytes
= CopyLen
->getZExtValue() - BytesCopied
;
90 IRBuilder
<> RBuilder(PostLoopBB
? PostLoopBB
->getFirstNonPHI()
93 SmallVector
<Type
*, 5> RemainingOps
;
94 TTI
.getMemcpyLoopResidualLoweringType(RemainingOps
, Ctx
, RemainingBytes
,
95 SrcAS
, DstAS
, SrcAlign
.value(),
98 for (auto OpTy
: RemainingOps
) {
99 Align
PartSrcAlign(commonAlignment(SrcAlign
, BytesCopied
));
100 Align
PartDstAlign(commonAlignment(DstAlign
, BytesCopied
));
102 // Calaculate the new index
103 unsigned OperandSize
= DL
.getTypeStoreSize(OpTy
);
104 uint64_t GepIndex
= BytesCopied
/ OperandSize
;
105 assert(GepIndex
* OperandSize
== BytesCopied
&&
106 "Division should have no Remainder!");
107 // Cast source to operand type and load
108 PointerType
*SrcPtrType
= PointerType::get(OpTy
, SrcAS
);
109 Value
*CastedSrc
= SrcAddr
->getType() == SrcPtrType
111 : RBuilder
.CreateBitCast(SrcAddr
, SrcPtrType
);
112 Value
*SrcGEP
= RBuilder
.CreateInBoundsGEP(
113 OpTy
, CastedSrc
, ConstantInt::get(TypeOfCopyLen
, GepIndex
));
115 RBuilder
.CreateAlignedLoad(OpTy
, SrcGEP
, PartSrcAlign
, SrcIsVolatile
);
117 // Cast destination to operand type and store.
118 PointerType
*DstPtrType
= PointerType::get(OpTy
, DstAS
);
119 Value
*CastedDst
= DstAddr
->getType() == DstPtrType
121 : RBuilder
.CreateBitCast(DstAddr
, DstPtrType
);
122 Value
*DstGEP
= RBuilder
.CreateInBoundsGEP(
123 OpTy
, CastedDst
, ConstantInt::get(TypeOfCopyLen
, GepIndex
));
124 RBuilder
.CreateAlignedStore(Load
, DstGEP
, PartDstAlign
, DstIsVolatile
);
126 BytesCopied
+= OperandSize
;
129 assert(BytesCopied
== CopyLen
->getZExtValue() &&
130 "Bytes copied should match size in the call!");
133 void llvm::createMemCpyLoopUnknownSize(Instruction
*InsertBefore
,
134 Value
*SrcAddr
, Value
*DstAddr
,
135 Value
*CopyLen
, Align SrcAlign
,
136 Align DstAlign
, bool SrcIsVolatile
,
138 const TargetTransformInfo
&TTI
) {
139 BasicBlock
*PreLoopBB
= InsertBefore
->getParent();
140 BasicBlock
*PostLoopBB
=
141 PreLoopBB
->splitBasicBlock(InsertBefore
, "post-loop-memcpy-expansion");
143 Function
*ParentFunc
= PreLoopBB
->getParent();
144 const DataLayout
&DL
= ParentFunc
->getParent()->getDataLayout();
145 LLVMContext
&Ctx
= PreLoopBB
->getContext();
146 unsigned SrcAS
= cast
<PointerType
>(SrcAddr
->getType())->getAddressSpace();
147 unsigned DstAS
= cast
<PointerType
>(DstAddr
->getType())->getAddressSpace();
149 Type
*LoopOpType
= TTI
.getMemcpyLoopLoweringType(
150 Ctx
, CopyLen
, SrcAS
, DstAS
, SrcAlign
.value(), DstAlign
.value());
151 unsigned LoopOpSize
= DL
.getTypeStoreSize(LoopOpType
);
153 IRBuilder
<> PLBuilder(PreLoopBB
->getTerminator());
155 PointerType
*SrcOpType
= PointerType::get(LoopOpType
, SrcAS
);
156 PointerType
*DstOpType
= PointerType::get(LoopOpType
, DstAS
);
157 if (SrcAddr
->getType() != SrcOpType
) {
158 SrcAddr
= PLBuilder
.CreateBitCast(SrcAddr
, SrcOpType
);
160 if (DstAddr
->getType() != DstOpType
) {
161 DstAddr
= PLBuilder
.CreateBitCast(DstAddr
, DstOpType
);
164 // Calculate the loop trip count, and remaining bytes to copy after the loop.
165 Type
*CopyLenType
= CopyLen
->getType();
166 IntegerType
*ILengthType
= dyn_cast
<IntegerType
>(CopyLenType
);
167 assert(ILengthType
&&
168 "expected size argument to memcpy to be an integer type!");
169 Type
*Int8Type
= Type::getInt8Ty(Ctx
);
170 bool LoopOpIsInt8
= LoopOpType
== Int8Type
;
171 ConstantInt
*CILoopOpSize
= ConstantInt::get(ILengthType
, LoopOpSize
);
172 Value
*RuntimeLoopCount
= LoopOpIsInt8
?
174 PLBuilder
.CreateUDiv(CopyLen
, CILoopOpSize
);
176 BasicBlock::Create(Ctx
, "loop-memcpy-expansion", ParentFunc
, PostLoopBB
);
177 IRBuilder
<> LoopBuilder(LoopBB
);
179 Align
PartSrcAlign(commonAlignment(SrcAlign
, LoopOpSize
));
180 Align
PartDstAlign(commonAlignment(DstAlign
, LoopOpSize
));
182 PHINode
*LoopIndex
= LoopBuilder
.CreatePHI(CopyLenType
, 2, "loop-index");
183 LoopIndex
->addIncoming(ConstantInt::get(CopyLenType
, 0U), PreLoopBB
);
185 Value
*SrcGEP
= LoopBuilder
.CreateInBoundsGEP(LoopOpType
, SrcAddr
, LoopIndex
);
186 Value
*Load
= LoopBuilder
.CreateAlignedLoad(LoopOpType
, SrcGEP
, PartSrcAlign
,
188 Value
*DstGEP
= LoopBuilder
.CreateInBoundsGEP(LoopOpType
, DstAddr
, LoopIndex
);
189 LoopBuilder
.CreateAlignedStore(Load
, DstGEP
, PartDstAlign
, DstIsVolatile
);
192 LoopBuilder
.CreateAdd(LoopIndex
, ConstantInt::get(CopyLenType
, 1U));
193 LoopIndex
->addIncoming(NewIndex
, LoopBB
);
197 Value
*RuntimeResidual
= PLBuilder
.CreateURem(CopyLen
, CILoopOpSize
);
198 Value
*RuntimeBytesCopied
= PLBuilder
.CreateSub(CopyLen
, RuntimeResidual
);
200 // Loop body for the residual copy.
201 BasicBlock
*ResLoopBB
= BasicBlock::Create(Ctx
, "loop-memcpy-residual",
202 PreLoopBB
->getParent(),
204 // Residual loop header.
205 BasicBlock
*ResHeaderBB
= BasicBlock::Create(
206 Ctx
, "loop-memcpy-residual-header", PreLoopBB
->getParent(), nullptr);
208 // Need to update the pre-loop basic block to branch to the correct place.
209 // branch to the main loop if the count is non-zero, branch to the residual
210 // loop if the copy size is smaller then 1 iteration of the main loop but
211 // non-zero and finally branch to after the residual loop if the memcpy
213 ConstantInt
*Zero
= ConstantInt::get(ILengthType
, 0U);
214 PLBuilder
.CreateCondBr(PLBuilder
.CreateICmpNE(RuntimeLoopCount
, Zero
),
215 LoopBB
, ResHeaderBB
);
216 PreLoopBB
->getTerminator()->eraseFromParent();
218 LoopBuilder
.CreateCondBr(
219 LoopBuilder
.CreateICmpULT(NewIndex
, RuntimeLoopCount
), LoopBB
,
222 // Determine if we need to branch to the residual loop or bypass it.
223 IRBuilder
<> RHBuilder(ResHeaderBB
);
224 RHBuilder
.CreateCondBr(RHBuilder
.CreateICmpNE(RuntimeResidual
, Zero
),
225 ResLoopBB
, PostLoopBB
);
227 // Copy the residual with single byte load/store loop.
228 IRBuilder
<> ResBuilder(ResLoopBB
);
229 PHINode
*ResidualIndex
=
230 ResBuilder
.CreatePHI(CopyLenType
, 2, "residual-loop-index");
231 ResidualIndex
->addIncoming(Zero
, ResHeaderBB
);
234 ResBuilder
.CreateBitCast(SrcAddr
, PointerType::get(Int8Type
, SrcAS
));
236 ResBuilder
.CreateBitCast(DstAddr
, PointerType::get(Int8Type
, DstAS
));
237 Value
*FullOffset
= ResBuilder
.CreateAdd(RuntimeBytesCopied
, ResidualIndex
);
239 ResBuilder
.CreateInBoundsGEP(Int8Type
, SrcAsInt8
, FullOffset
);
240 Value
*Load
= ResBuilder
.CreateAlignedLoad(Int8Type
, SrcGEP
, PartSrcAlign
,
243 ResBuilder
.CreateInBoundsGEP(Int8Type
, DstAsInt8
, FullOffset
);
244 ResBuilder
.CreateAlignedStore(Load
, DstGEP
, PartDstAlign
, DstIsVolatile
);
247 ResBuilder
.CreateAdd(ResidualIndex
, ConstantInt::get(CopyLenType
, 1U));
248 ResidualIndex
->addIncoming(ResNewIndex
, ResLoopBB
);
250 // Create the loop branch condition.
251 ResBuilder
.CreateCondBr(
252 ResBuilder
.CreateICmpULT(ResNewIndex
, RuntimeResidual
), ResLoopBB
,
255 // In this case the loop operand type was a byte, and there is no need for a
256 // residual loop to copy the remaining memory after the main loop.
257 // We do however need to patch up the control flow by creating the
258 // terminators for the preloop block and the memcpy loop.
259 ConstantInt
*Zero
= ConstantInt::get(ILengthType
, 0U);
260 PLBuilder
.CreateCondBr(PLBuilder
.CreateICmpNE(RuntimeLoopCount
, Zero
),
262 PreLoopBB
->getTerminator()->eraseFromParent();
263 LoopBuilder
.CreateCondBr(
264 LoopBuilder
.CreateICmpULT(NewIndex
, RuntimeLoopCount
), LoopBB
,
269 // Lower memmove to IR. memmove is required to correctly copy overlapping memory
270 // regions; therefore, it has to check the relative positions of the source and
271 // destination pointers and choose the copy direction accordingly.
273 // The code below is an IR rendition of this C function:
275 // void* memmove(void* dst, const void* src, size_t n) {
276 // unsigned char* d = dst;
277 // const unsigned char* s = src;
285 // for (size_t i = 0; i < n; ++i) {
291 static void createMemMoveLoop(Instruction
*InsertBefore
, Value
*SrcAddr
,
292 Value
*DstAddr
, Value
*CopyLen
, Align SrcAlign
,
293 Align DstAlign
, bool SrcIsVolatile
,
294 bool DstIsVolatile
) {
295 Type
*TypeOfCopyLen
= CopyLen
->getType();
296 BasicBlock
*OrigBB
= InsertBefore
->getParent();
297 Function
*F
= OrigBB
->getParent();
298 const DataLayout
&DL
= F
->getParent()->getDataLayout();
300 Type
*EltTy
= cast
<PointerType
>(SrcAddr
->getType())->getElementType();
302 // Create the a comparison of src and dst, based on which we jump to either
303 // the forward-copy part of the function (if src >= dst) or the backwards-copy
304 // part (if src < dst).
305 // SplitBlockAndInsertIfThenElse conveniently creates the basic if-then-else
306 // structure. Its block terminators (unconditional branches) are replaced by
307 // the appropriate conditional branches when the loop is built.
308 ICmpInst
*PtrCompare
= new ICmpInst(InsertBefore
, ICmpInst::ICMP_ULT
,
309 SrcAddr
, DstAddr
, "compare_src_dst");
310 Instruction
*ThenTerm
, *ElseTerm
;
311 SplitBlockAndInsertIfThenElse(PtrCompare
, InsertBefore
, &ThenTerm
,
314 // Each part of the function consists of two blocks:
315 // copy_backwards: used to skip the loop when n == 0
316 // copy_backwards_loop: the actual backwards loop BB
317 // copy_forward: used to skip the loop when n == 0
318 // copy_forward_loop: the actual forward loop BB
319 BasicBlock
*CopyBackwardsBB
= ThenTerm
->getParent();
320 CopyBackwardsBB
->setName("copy_backwards");
321 BasicBlock
*CopyForwardBB
= ElseTerm
->getParent();
322 CopyForwardBB
->setName("copy_forward");
323 BasicBlock
*ExitBB
= InsertBefore
->getParent();
324 ExitBB
->setName("memmove_done");
326 unsigned PartSize
= DL
.getTypeStoreSize(EltTy
);
327 Align
PartSrcAlign(commonAlignment(SrcAlign
, PartSize
));
328 Align
PartDstAlign(commonAlignment(DstAlign
, PartSize
));
330 // Initial comparison of n == 0 that lets us skip the loops altogether. Shared
331 // between both backwards and forward copy clauses.
333 new ICmpInst(OrigBB
->getTerminator(), ICmpInst::ICMP_EQ
, CopyLen
,
334 ConstantInt::get(TypeOfCopyLen
, 0), "compare_n_to_0");
336 // Copying backwards.
338 BasicBlock::Create(F
->getContext(), "copy_backwards_loop", F
, CopyForwardBB
);
339 IRBuilder
<> LoopBuilder(LoopBB
);
340 PHINode
*LoopPhi
= LoopBuilder
.CreatePHI(TypeOfCopyLen
, 0);
341 Value
*IndexPtr
= LoopBuilder
.CreateSub(
342 LoopPhi
, ConstantInt::get(TypeOfCopyLen
, 1), "index_ptr");
343 Value
*Element
= LoopBuilder
.CreateAlignedLoad(
344 EltTy
, LoopBuilder
.CreateInBoundsGEP(EltTy
, SrcAddr
, IndexPtr
),
345 PartSrcAlign
, "element");
346 LoopBuilder
.CreateAlignedStore(
347 Element
, LoopBuilder
.CreateInBoundsGEP(EltTy
, DstAddr
, IndexPtr
),
349 LoopBuilder
.CreateCondBr(
350 LoopBuilder
.CreateICmpEQ(IndexPtr
, ConstantInt::get(TypeOfCopyLen
, 0)),
352 LoopPhi
->addIncoming(IndexPtr
, LoopBB
);
353 LoopPhi
->addIncoming(CopyLen
, CopyBackwardsBB
);
354 BranchInst::Create(ExitBB
, LoopBB
, CompareN
, ThenTerm
);
355 ThenTerm
->eraseFromParent();
358 BasicBlock
*FwdLoopBB
=
359 BasicBlock::Create(F
->getContext(), "copy_forward_loop", F
, ExitBB
);
360 IRBuilder
<> FwdLoopBuilder(FwdLoopBB
);
361 PHINode
*FwdCopyPhi
= FwdLoopBuilder
.CreatePHI(TypeOfCopyLen
, 0, "index_ptr");
362 Value
*SrcGEP
= FwdLoopBuilder
.CreateInBoundsGEP(EltTy
, SrcAddr
, FwdCopyPhi
);
364 FwdLoopBuilder
.CreateAlignedLoad(EltTy
, SrcGEP
, PartSrcAlign
, "element");
365 Value
*DstGEP
= FwdLoopBuilder
.CreateInBoundsGEP(EltTy
, DstAddr
, FwdCopyPhi
);
366 FwdLoopBuilder
.CreateAlignedStore(FwdElement
, DstGEP
, PartDstAlign
);
367 Value
*FwdIndexPtr
= FwdLoopBuilder
.CreateAdd(
368 FwdCopyPhi
, ConstantInt::get(TypeOfCopyLen
, 1), "index_increment");
369 FwdLoopBuilder
.CreateCondBr(FwdLoopBuilder
.CreateICmpEQ(FwdIndexPtr
, CopyLen
),
371 FwdCopyPhi
->addIncoming(FwdIndexPtr
, FwdLoopBB
);
372 FwdCopyPhi
->addIncoming(ConstantInt::get(TypeOfCopyLen
, 0), CopyForwardBB
);
374 BranchInst::Create(ExitBB
, FwdLoopBB
, CompareN
, ElseTerm
);
375 ElseTerm
->eraseFromParent();
378 static void createMemSetLoop(Instruction
*InsertBefore
, Value
*DstAddr
,
379 Value
*CopyLen
, Value
*SetValue
, Align DstAlign
,
381 Type
*TypeOfCopyLen
= CopyLen
->getType();
382 BasicBlock
*OrigBB
= InsertBefore
->getParent();
383 Function
*F
= OrigBB
->getParent();
384 const DataLayout
&DL
= F
->getParent()->getDataLayout();
386 OrigBB
->splitBasicBlock(InsertBefore
, "split");
388 = BasicBlock::Create(F
->getContext(), "loadstoreloop", F
, NewBB
);
390 IRBuilder
<> Builder(OrigBB
->getTerminator());
392 // Cast pointer to the type of value getting stored
393 unsigned dstAS
= cast
<PointerType
>(DstAddr
->getType())->getAddressSpace();
394 DstAddr
= Builder
.CreateBitCast(DstAddr
,
395 PointerType::get(SetValue
->getType(), dstAS
));
397 Builder
.CreateCondBr(
398 Builder
.CreateICmpEQ(ConstantInt::get(TypeOfCopyLen
, 0), CopyLen
), NewBB
,
400 OrigBB
->getTerminator()->eraseFromParent();
402 unsigned PartSize
= DL
.getTypeStoreSize(SetValue
->getType());
403 Align
PartAlign(commonAlignment(DstAlign
, PartSize
));
405 IRBuilder
<> LoopBuilder(LoopBB
);
406 PHINode
*LoopIndex
= LoopBuilder
.CreatePHI(TypeOfCopyLen
, 0);
407 LoopIndex
->addIncoming(ConstantInt::get(TypeOfCopyLen
, 0), OrigBB
);
409 LoopBuilder
.CreateAlignedStore(
411 LoopBuilder
.CreateInBoundsGEP(SetValue
->getType(), DstAddr
, LoopIndex
),
412 PartAlign
, IsVolatile
);
415 LoopBuilder
.CreateAdd(LoopIndex
, ConstantInt::get(TypeOfCopyLen
, 1));
416 LoopIndex
->addIncoming(NewIndex
, LoopBB
);
418 LoopBuilder
.CreateCondBr(LoopBuilder
.CreateICmpULT(NewIndex
, CopyLen
), LoopBB
,
422 void llvm::expandMemCpyAsLoop(MemCpyInst
*Memcpy
,
423 const TargetTransformInfo
&TTI
) {
424 if (ConstantInt
*CI
= dyn_cast
<ConstantInt
>(Memcpy
->getLength())) {
425 createMemCpyLoopKnownSize(
426 /* InsertBefore */ Memcpy
,
427 /* SrcAddr */ Memcpy
->getRawSource(),
428 /* DstAddr */ Memcpy
->getRawDest(),
430 /* SrcAlign */ Memcpy
->getSourceAlign().valueOrOne(),
431 /* DestAlign */ Memcpy
->getDestAlign().valueOrOne(),
432 /* SrcIsVolatile */ Memcpy
->isVolatile(),
433 /* DstIsVolatile */ Memcpy
->isVolatile(),
434 /* TargetTransformInfo */ TTI
);
436 createMemCpyLoopUnknownSize(
437 /* InsertBefore */ Memcpy
,
438 /* SrcAddr */ Memcpy
->getRawSource(),
439 /* DstAddr */ Memcpy
->getRawDest(),
440 /* CopyLen */ Memcpy
->getLength(),
441 /* SrcAlign */ Memcpy
->getSourceAlign().valueOrOne(),
442 /* DestAlign */ Memcpy
->getDestAlign().valueOrOne(),
443 /* SrcIsVolatile */ Memcpy
->isVolatile(),
444 /* DstIsVolatile */ Memcpy
->isVolatile(),
445 /* TargetTransformInfo */ TTI
);
449 void llvm::expandMemMoveAsLoop(MemMoveInst
*Memmove
) {
450 createMemMoveLoop(/* InsertBefore */ Memmove
,
451 /* SrcAddr */ Memmove
->getRawSource(),
452 /* DstAddr */ Memmove
->getRawDest(),
453 /* CopyLen */ Memmove
->getLength(),
454 /* SrcAlign */ Memmove
->getSourceAlign().valueOrOne(),
455 /* DestAlign */ Memmove
->getDestAlign().valueOrOne(),
456 /* SrcIsVolatile */ Memmove
->isVolatile(),
457 /* DstIsVolatile */ Memmove
->isVolatile());
460 void llvm::expandMemSetAsLoop(MemSetInst
*Memset
) {
461 createMemSetLoop(/* InsertBefore */ Memset
,
462 /* DstAddr */ Memset
->getRawDest(),
463 /* CopyLen */ Memset
->getLength(),
464 /* SetValue */ Memset
->getValue(),
465 /* Alignment */ Memset
->getDestAlign().valueOrOne(),
466 Memset
->isVolatile());