blob: 1c2a60a6b8b247eac7bf5fdd4957c666e6b416eb [file] [log] [blame]
Matt Arsenault56066522017-02-08 17:49:52 +00001//===- LowerMemIntrinsics.cpp ----------------------------------*- C++ -*--===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/Transforms/Utils/LowerMemIntrinsics.h"
Matt Arsenault56066522017-02-08 17:49:52 +000011#include "llvm/IR/IRBuilder.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000012#include "llvm/IR/IntrinsicInst.h"
13#include "llvm/Transforms/Utils/BasicBlockUtils.h"
Matt Arsenault56066522017-02-08 17:49:52 +000014
15using namespace llvm;
16
17void llvm::createMemCpyLoop(Instruction *InsertBefore,
18 Value *SrcAddr, Value *DstAddr, Value *CopyLen,
19 unsigned SrcAlign, unsigned DestAlign,
20 bool SrcIsVolatile, bool DstIsVolatile) {
21 Type *TypeOfCopyLen = CopyLen->getType();
22
23 BasicBlock *OrigBB = InsertBefore->getParent();
24 Function *F = OrigBB->getParent();
25 BasicBlock *NewBB =
26 InsertBefore->getParent()->splitBasicBlock(InsertBefore, "split");
27 BasicBlock *LoopBB = BasicBlock::Create(F->getContext(), "loadstoreloop",
28 F, NewBB);
29
Matt Arsenault56066522017-02-08 17:49:52 +000030 IRBuilder<> Builder(OrigBB->getTerminator());
31
32 // SrcAddr and DstAddr are expected to be pointer types,
33 // so no check is made here.
34 unsigned SrcAS = cast<PointerType>(SrcAddr->getType())->getAddressSpace();
35 unsigned DstAS = cast<PointerType>(DstAddr->getType())->getAddressSpace();
36
37 // Cast pointers to (char *)
38 SrcAddr = Builder.CreateBitCast(SrcAddr, Builder.getInt8PtrTy(SrcAS));
39 DstAddr = Builder.CreateBitCast(DstAddr, Builder.getInt8PtrTy(DstAS));
40
Teresa Johnson32d95742017-07-01 03:24:10 +000041 Builder.CreateCondBr(
42 Builder.CreateICmpEQ(ConstantInt::get(TypeOfCopyLen, 0), CopyLen), NewBB,
43 LoopBB);
44 OrigBB->getTerminator()->eraseFromParent();
45
Matt Arsenault56066522017-02-08 17:49:52 +000046 IRBuilder<> LoopBuilder(LoopBB);
47 PHINode *LoopIndex = LoopBuilder.CreatePHI(TypeOfCopyLen, 0);
48 LoopIndex->addIncoming(ConstantInt::get(TypeOfCopyLen, 0), OrigBB);
49
50 // load from SrcAddr+LoopIndex
51 // TODO: we can leverage the align parameter of llvm.memcpy for more efficient
52 // word-sized loads and stores.
53 Value *Element =
54 LoopBuilder.CreateLoad(LoopBuilder.CreateInBoundsGEP(
55 LoopBuilder.getInt8Ty(), SrcAddr, LoopIndex),
56 SrcIsVolatile);
57 // store at DstAddr+LoopIndex
58 LoopBuilder.CreateStore(Element,
59 LoopBuilder.CreateInBoundsGEP(LoopBuilder.getInt8Ty(),
60 DstAddr, LoopIndex),
61 DstIsVolatile);
62
63 // The value for LoopIndex coming from backedge is (LoopIndex + 1)
64 Value *NewIndex =
65 LoopBuilder.CreateAdd(LoopIndex, ConstantInt::get(TypeOfCopyLen, 1));
66 LoopIndex->addIncoming(NewIndex, LoopBB);
67
68 LoopBuilder.CreateCondBr(LoopBuilder.CreateICmpULT(NewIndex, CopyLen), LoopBB,
69 NewBB);
70}
71
72// Lower memmove to IR. memmove is required to correctly copy overlapping memory
73// regions; therefore, it has to check the relative positions of the source and
74// destination pointers and choose the copy direction accordingly.
75//
76// The code below is an IR rendition of this C function:
77//
78// void* memmove(void* dst, const void* src, size_t n) {
79// unsigned char* d = dst;
80// const unsigned char* s = src;
81// if (s < d) {
82// // copy backwards
83// while (n--) {
84// d[n] = s[n];
85// }
86// } else {
87// // copy forward
88// for (size_t i = 0; i < n; ++i) {
89// d[i] = s[i];
90// }
91// }
92// return dst;
93// }
94static void createMemMoveLoop(Instruction *InsertBefore,
95 Value *SrcAddr, Value *DstAddr, Value *CopyLen,
96 unsigned SrcAlign, unsigned DestAlign,
97 bool SrcIsVolatile, bool DstIsVolatile) {
98 Type *TypeOfCopyLen = CopyLen->getType();
99 BasicBlock *OrigBB = InsertBefore->getParent();
100 Function *F = OrigBB->getParent();
101
102 // Create the a comparison of src and dst, based on which we jump to either
103 // the forward-copy part of the function (if src >= dst) or the backwards-copy
104 // part (if src < dst).
105 // SplitBlockAndInsertIfThenElse conveniently creates the basic if-then-else
106 // structure. Its block terminators (unconditional branches) are replaced by
107 // the appropriate conditional branches when the loop is built.
108 ICmpInst *PtrCompare = new ICmpInst(InsertBefore, ICmpInst::ICMP_ULT,
109 SrcAddr, DstAddr, "compare_src_dst");
110 TerminatorInst *ThenTerm, *ElseTerm;
111 SplitBlockAndInsertIfThenElse(PtrCompare, InsertBefore, &ThenTerm,
112 &ElseTerm);
113
114 // Each part of the function consists of two blocks:
115 // copy_backwards: used to skip the loop when n == 0
116 // copy_backwards_loop: the actual backwards loop BB
117 // copy_forward: used to skip the loop when n == 0
118 // copy_forward_loop: the actual forward loop BB
119 BasicBlock *CopyBackwardsBB = ThenTerm->getParent();
120 CopyBackwardsBB->setName("copy_backwards");
121 BasicBlock *CopyForwardBB = ElseTerm->getParent();
122 CopyForwardBB->setName("copy_forward");
123 BasicBlock *ExitBB = InsertBefore->getParent();
124 ExitBB->setName("memmove_done");
125
126 // Initial comparison of n == 0 that lets us skip the loops altogether. Shared
127 // between both backwards and forward copy clauses.
128 ICmpInst *CompareN =
129 new ICmpInst(OrigBB->getTerminator(), ICmpInst::ICMP_EQ, CopyLen,
130 ConstantInt::get(TypeOfCopyLen, 0), "compare_n_to_0");
131
132 // Copying backwards.
133 BasicBlock *LoopBB =
134 BasicBlock::Create(F->getContext(), "copy_backwards_loop", F, CopyForwardBB);
135 IRBuilder<> LoopBuilder(LoopBB);
136 PHINode *LoopPhi = LoopBuilder.CreatePHI(TypeOfCopyLen, 0);
137 Value *IndexPtr = LoopBuilder.CreateSub(
138 LoopPhi, ConstantInt::get(TypeOfCopyLen, 1), "index_ptr");
139 Value *Element = LoopBuilder.CreateLoad(
140 LoopBuilder.CreateInBoundsGEP(SrcAddr, IndexPtr), "element");
141 LoopBuilder.CreateStore(Element,
142 LoopBuilder.CreateInBoundsGEP(DstAddr, IndexPtr));
143 LoopBuilder.CreateCondBr(
144 LoopBuilder.CreateICmpEQ(IndexPtr, ConstantInt::get(TypeOfCopyLen, 0)),
145 ExitBB, LoopBB);
146 LoopPhi->addIncoming(IndexPtr, LoopBB);
147 LoopPhi->addIncoming(CopyLen, CopyBackwardsBB);
148 BranchInst::Create(ExitBB, LoopBB, CompareN, ThenTerm);
149 ThenTerm->eraseFromParent();
150
151 // Copying forward.
152 BasicBlock *FwdLoopBB =
153 BasicBlock::Create(F->getContext(), "copy_forward_loop", F, ExitBB);
154 IRBuilder<> FwdLoopBuilder(FwdLoopBB);
155 PHINode *FwdCopyPhi = FwdLoopBuilder.CreatePHI(TypeOfCopyLen, 0, "index_ptr");
156 Value *FwdElement = FwdLoopBuilder.CreateLoad(
157 FwdLoopBuilder.CreateInBoundsGEP(SrcAddr, FwdCopyPhi), "element");
158 FwdLoopBuilder.CreateStore(
159 FwdElement, FwdLoopBuilder.CreateInBoundsGEP(DstAddr, FwdCopyPhi));
160 Value *FwdIndexPtr = FwdLoopBuilder.CreateAdd(
161 FwdCopyPhi, ConstantInt::get(TypeOfCopyLen, 1), "index_increment");
162 FwdLoopBuilder.CreateCondBr(FwdLoopBuilder.CreateICmpEQ(FwdIndexPtr, CopyLen),
163 ExitBB, FwdLoopBB);
164 FwdCopyPhi->addIncoming(FwdIndexPtr, FwdLoopBB);
165 FwdCopyPhi->addIncoming(ConstantInt::get(TypeOfCopyLen, 0), CopyForwardBB);
166
167 BranchInst::Create(ExitBB, FwdLoopBB, CompareN, ElseTerm);
168 ElseTerm->eraseFromParent();
169}
170
171static void createMemSetLoop(Instruction *InsertBefore,
172 Value *DstAddr, Value *CopyLen, Value *SetValue,
173 unsigned Align, bool IsVolatile) {
Teresa Johnson32d95742017-07-01 03:24:10 +0000174 Type *TypeOfCopyLen = CopyLen->getType();
Matt Arsenault56066522017-02-08 17:49:52 +0000175 BasicBlock *OrigBB = InsertBefore->getParent();
176 Function *F = OrigBB->getParent();
177 BasicBlock *NewBB =
178 OrigBB->splitBasicBlock(InsertBefore, "split");
179 BasicBlock *LoopBB
180 = BasicBlock::Create(F->getContext(), "loadstoreloop", F, NewBB);
181
Matt Arsenault56066522017-02-08 17:49:52 +0000182 IRBuilder<> Builder(OrigBB->getTerminator());
183
184 // Cast pointer to the type of value getting stored
185 unsigned dstAS = cast<PointerType>(DstAddr->getType())->getAddressSpace();
186 DstAddr = Builder.CreateBitCast(DstAddr,
187 PointerType::get(SetValue->getType(), dstAS));
188
Teresa Johnson32d95742017-07-01 03:24:10 +0000189 Builder.CreateCondBr(
190 Builder.CreateICmpEQ(ConstantInt::get(TypeOfCopyLen, 0), CopyLen), NewBB,
191 LoopBB);
192 OrigBB->getTerminator()->eraseFromParent();
193
Matt Arsenault56066522017-02-08 17:49:52 +0000194 IRBuilder<> LoopBuilder(LoopBB);
Teresa Johnson32d95742017-07-01 03:24:10 +0000195 PHINode *LoopIndex = LoopBuilder.CreatePHI(TypeOfCopyLen, 0);
196 LoopIndex->addIncoming(ConstantInt::get(TypeOfCopyLen, 0), OrigBB);
Matt Arsenault56066522017-02-08 17:49:52 +0000197
198 LoopBuilder.CreateStore(
199 SetValue,
200 LoopBuilder.CreateInBoundsGEP(SetValue->getType(), DstAddr, LoopIndex),
201 IsVolatile);
202
203 Value *NewIndex =
Teresa Johnson32d95742017-07-01 03:24:10 +0000204 LoopBuilder.CreateAdd(LoopIndex, ConstantInt::get(TypeOfCopyLen, 1));
Matt Arsenault56066522017-02-08 17:49:52 +0000205 LoopIndex->addIncoming(NewIndex, LoopBB);
206
207 LoopBuilder.CreateCondBr(LoopBuilder.CreateICmpULT(NewIndex, CopyLen), LoopBB,
208 NewBB);
209}
210
211void llvm::expandMemCpyAsLoop(MemCpyInst *Memcpy) {
212 createMemCpyLoop(/* InsertBefore */ Memcpy,
213 /* SrcAddr */ Memcpy->getRawSource(),
214 /* DstAddr */ Memcpy->getRawDest(),
215 /* CopyLen */ Memcpy->getLength(),
216 /* SrcAlign */ Memcpy->getAlignment(),
217 /* DestAlign */ Memcpy->getAlignment(),
218 /* SrcIsVolatile */ Memcpy->isVolatile(),
219 /* DstIsVolatile */ Memcpy->isVolatile());
220}
221
222void llvm::expandMemMoveAsLoop(MemMoveInst *Memmove) {
223 createMemMoveLoop(/* InsertBefore */ Memmove,
224 /* SrcAddr */ Memmove->getRawSource(),
225 /* DstAddr */ Memmove->getRawDest(),
226 /* CopyLen */ Memmove->getLength(),
227 /* SrcAlign */ Memmove->getAlignment(),
228 /* DestAlign */ Memmove->getAlignment(),
229 /* SrcIsVolatile */ Memmove->isVolatile(),
230 /* DstIsVolatile */ Memmove->isVolatile());
231}
232
233void llvm::expandMemSetAsLoop(MemSetInst *Memset) {
234 createMemSetLoop(/* InsertBefore */ Memset,
235 /* DstAddr */ Memset->getRawDest(),
236 /* CopyLen */ Memset->getLength(),
237 /* SetValue */ Memset->getValue(),
238 /* Alignment */ Memset->getAlignment(),
239 Memset->isVolatile());
240}