1//===-- CGBuilder.h - Choose IRBuilder implementation ----------*- C++ -*-===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
10#define LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
11
12#include "Address.h"
13#include "CGValue.h"
14#include "CodeGenModule.h"
15#include "CodeGenTypeCache.h"
16#include "llvm/Analysis/TargetFolder.h"
17#include "llvm/Analysis/Utils/Local.h"
18#include "llvm/IR/DataLayout.h"
19#include "llvm/IR/GEPNoWrapFlags.h"
20#include "llvm/IR/IRBuilder.h"
21#include "llvm/IR/Type.h"
22
23namespace clang {
24namespace CodeGen {
25
26class CGBuilderTy;
27class CodeGenFunction;
28
29/// This is an IRBuilder insertion helper that forwards to
30/// CodeGenFunction::InsertHelper, which adds necessary metadata to
31/// instructions.
32class CGBuilderInserter final : public llvm::IRBuilderDefaultInserter {
33 friend CGBuilderTy;
34
35public:
36 CGBuilderInserter() = default;
37 explicit CGBuilderInserter(CodeGenFunction *CGF) : CGF(CGF) {}
38
39 /// This forwards to CodeGenFunction::InsertHelper.
40 void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
41 llvm::BasicBlock::iterator InsertPt) const;
42
43private:
44 CodeGenFunction *CGF = nullptr;
45};
46
47typedef CGBuilderInserter CGBuilderInserterTy;
48
49typedef llvm::IRBuilder<llvm::TargetFolder, CGBuilderInserterTy>
50 CGBuilderBaseTy;
51
52class CGBuilderTy : public CGBuilderBaseTy {
53 friend class Address;
54
55 /// Storing a reference to the type cache here makes it a lot easier
56 /// to build natural-feeling, target-specific IR.
57 const CodeGenTypeCache &TypeCache;
58
59 CodeGenFunction *getCGF() const { return getInserter().CGF; }
60
61 llvm::Value *emitRawPointerFromAddress(Address Addr) const {
62 return Addr.getBasePointer();
63 }
64
65 template <bool IsInBounds>
66 Address createConstGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1,
67 const llvm::Twine &Name) {
68 const llvm::DataLayout &DL = getDataLayout();
69 llvm::Value *V;
70 if (IsInBounds)
71 V = CreateConstInBoundsGEP2_32(Ty: Addr.getElementType(),
72 Ptr: emitRawPointerFromAddress(Addr), Idx0,
73 Idx1, Name);
74 else
75 V = CreateConstGEP2_32(Ty: Addr.getElementType(),
76 Ptr: emitRawPointerFromAddress(Addr), Idx0, Idx1, Name);
77 llvm::APInt Offset(
78 DL.getIndexSizeInBits(AS: Addr.getType()->getPointerAddressSpace()), 0,
79 /*isSigned=*/true);
80 if (!llvm::GEPOperator::accumulateConstantOffset(
81 SourceType: Addr.getElementType(), Index: {getInt32(C: Idx0), getInt32(C: Idx1)}, DL,
82 Offset))
83 llvm_unreachable(
84 "accumulateConstantOffset with constant indices should not fail.");
85 llvm::Type *ElementTy = llvm::GetElementPtrInst::getIndexedType(
86 Ty: Addr.getElementType(), IdxList: {Idx0, Idx1});
87 return Address(V, ElementTy,
88 Addr.getAlignment().alignmentAtOffset(
89 offset: CharUnits::fromQuantity(Quantity: Offset.getSExtValue())),
90 IsInBounds ? Addr.isKnownNonNull() : NotKnownNonNull);
91 }
92
93public:
94 CGBuilderTy(const CodeGenModule &CGM, llvm::LLVMContext &C)
95 : CGBuilderBaseTy(CGM.getModule(),
96 llvm::TargetFolder(CGM.getDataLayout())),
97 TypeCache(CGM) {}
98 CGBuilderTy(const CodeGenModule &CGM, llvm::LLVMContext &C,
99 const CGBuilderInserterTy &Inserter)
100 : CGBuilderBaseTy(CGM.getModule(),
101 llvm::TargetFolder(CGM.getDataLayout()), Inserter),
102 TypeCache(CGM) {}
103 CGBuilderTy(const CodeGenModule &CGM, llvm::Instruction *I)
104 : CGBuilderBaseTy(I->getIterator(),
105 llvm::TargetFolder(CGM.getDataLayout())),
106 TypeCache(CGM) {}
107 CGBuilderTy(const CodeGenModule &CGM, llvm::BasicBlock *BB)
108 : CGBuilderBaseTy(BB, llvm::TargetFolder(CGM.getDataLayout())),
109 TypeCache(CGM) {}
110
111 llvm::ConstantInt *getSize(CharUnits N) {
112 return llvm::ConstantInt::getSigned(Ty: TypeCache.SizeTy, V: N.getQuantity());
113 }
114 llvm::ConstantInt *getSize(uint64_t N) {
115 return llvm::ConstantInt::get(Ty: TypeCache.SizeTy, V: N);
116 }
117
118 // Note that we intentionally hide the CreateLoad APIs that don't
119 // take an alignment.
120 llvm::LoadInst *CreateLoad(Address Addr, const llvm::Twine &Name = "") {
121 return CreateAlignedLoad(Ty: Addr.getElementType(),
122 Ptr: emitRawPointerFromAddress(Addr),
123 Align: Addr.getAlignment().getAsAlign(), Name);
124 }
125 llvm::LoadInst *CreateLoad(Address Addr, const char *Name) {
126 // This overload is required to prevent string literals from
127 // ending up in the IsVolatile overload.
128 return CreateAlignedLoad(Ty: Addr.getElementType(),
129 Ptr: emitRawPointerFromAddress(Addr),
130 Align: Addr.getAlignment().getAsAlign(), Name);
131 }
132 llvm::LoadInst *CreateLoad(Address Addr, bool IsVolatile,
133 const llvm::Twine &Name = "") {
134 return CreateAlignedLoad(
135 Ty: Addr.getElementType(), Ptr: emitRawPointerFromAddress(Addr),
136 Align: Addr.getAlignment().getAsAlign(), isVolatile: IsVolatile, Name);
137 }
138
139 using CGBuilderBaseTy::CreateAlignedLoad;
140 llvm::LoadInst *CreateAlignedLoad(llvm::Type *Ty, llvm::Value *Addr,
141 CharUnits Align,
142 const llvm::Twine &Name = "") {
143 return CreateAlignedLoad(Ty, Ptr: Addr, Align: Align.getAsAlign(), Name);
144 }
145
146 // Note that we intentionally hide the CreateStore APIs that don't
147 // take an alignment.
148 llvm::StoreInst *CreateStore(llvm::Value *Val, Address Addr,
149 bool IsVolatile = false) {
150 return CreateAlignedStore(Val, Ptr: emitRawPointerFromAddress(Addr),
151 Align: Addr.getAlignment().getAsAlign(), isVolatile: IsVolatile);
152 }
153
154 using CGBuilderBaseTy::CreateAlignedStore;
155 llvm::StoreInst *CreateAlignedStore(llvm::Value *Val, llvm::Value *Addr,
156 CharUnits Align,
157 bool IsVolatile = false) {
158 return CreateAlignedStore(Val, Ptr: Addr, Align: Align.getAsAlign(), isVolatile: IsVolatile);
159 }
160
161 // FIXME: these "default-aligned" APIs should be removed,
162 // but I don't feel like fixing all the builtin code right now.
163 llvm::StoreInst *CreateDefaultAlignedStore(llvm::Value *Val,
164 llvm::Value *Addr,
165 bool IsVolatile = false) {
166 return CGBuilderBaseTy::CreateStore(Val, Ptr: Addr, isVolatile: IsVolatile);
167 }
168
169 /// Emit a load from an i1 flag variable.
170 llvm::LoadInst *CreateFlagLoad(llvm::Value *Addr,
171 const llvm::Twine &Name = "") {
172 return CreateAlignedLoad(Ty: getInt1Ty(), Addr, Align: CharUnits::One(), Name);
173 }
174
175 /// Emit a store to an i1 flag variable.
176 llvm::StoreInst *CreateFlagStore(bool Value, llvm::Value *Addr) {
177 return CreateAlignedStore(Val: getInt1(V: Value), Addr, Align: CharUnits::One());
178 }
179
180 llvm::AtomicCmpXchgInst *
181 CreateAtomicCmpXchg(Address Addr, llvm::Value *Cmp, llvm::Value *New,
182 llvm::AtomicOrdering SuccessOrdering,
183 llvm::AtomicOrdering FailureOrdering,
184 llvm::SyncScope::ID SSID = llvm::SyncScope::System) {
185 return CGBuilderBaseTy::CreateAtomicCmpXchg(
186 Ptr: Addr.emitRawPointer(CGF&: *getCGF()), Cmp, New,
187 Align: Addr.getAlignment().getAsAlign(), SuccessOrdering, FailureOrdering,
188 SSID);
189 }
190
191 llvm::AtomicRMWInst *
192 CreateAtomicRMW(llvm::AtomicRMWInst::BinOp Op, Address Addr, llvm::Value *Val,
193 llvm::AtomicOrdering Ordering,
194 llvm::SyncScope::ID SSID = llvm::SyncScope::System) {
195 return CGBuilderBaseTy::CreateAtomicRMW(
196 Op, Ptr: Addr.emitRawPointer(CGF&: *getCGF()), Val,
197 Align: Addr.getAlignment().getAsAlign(), Ordering, SSID);
198 }
199
200 using CGBuilderBaseTy::CreateAddrSpaceCast;
201 Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty,
202 llvm::Type *ElementTy,
203 const llvm::Twine &Name = "") {
204 if (!Addr.hasOffset())
205 return Address(CreateAddrSpaceCast(V: Addr.getBasePointer(), DestTy: Ty, Name),
206 ElementTy, Addr.getAlignment(), Addr.getPointerAuthInfo(),
207 /*Offset=*/nullptr, Addr.isKnownNonNull());
208 // Eagerly force a raw address if these is an offset.
209 return RawAddress(
210 CreateAddrSpaceCast(V: Addr.emitRawPointer(CGF&: *getCGF()), DestTy: Ty, Name),
211 ElementTy, Addr.getAlignment(), Addr.isKnownNonNull());
212 }
213
214 using CGBuilderBaseTy::CreatePointerBitCastOrAddrSpaceCast;
215 Address CreatePointerBitCastOrAddrSpaceCast(Address Addr, llvm::Type *Ty,
216 llvm::Type *ElementTy,
217 const llvm::Twine &Name = "") {
218 if (Addr.getType()->getAddressSpace() == Ty->getPointerAddressSpace())
219 return Addr.withElementType(ElemTy: ElementTy);
220 return CreateAddrSpaceCast(Addr, Ty, ElementTy, Name);
221 }
222
223 /// Given
224 /// %addr = {T1, T2...}* ...
225 /// produce
226 /// %name = getelementptr inbounds nuw %addr, i32 0, i32 index
227 ///
228 /// This API assumes that drilling into a struct like this is always an
229 /// inbounds and nuw operation.
230 using CGBuilderBaseTy::CreateStructGEP;
231 Address CreateStructGEP(Address Addr, unsigned Index,
232 const llvm::Twine &Name = "") {
233 llvm::StructType *ElTy = cast<llvm::StructType>(Val: Addr.getElementType());
234 const llvm::DataLayout &DL = getDataLayout();
235 const llvm::StructLayout *Layout = DL.getStructLayout(Ty: ElTy);
236 auto Offset = CharUnits::fromQuantity(Quantity: Layout->getElementOffset(Idx: Index));
237
238 return Address(CreateStructGEP(Ty: Addr.getElementType(), Ptr: Addr.getBasePointer(),
239 Idx: Index, Name),
240 ElTy->getElementType(N: Index),
241 Addr.getAlignment().alignmentAtOffset(offset: Offset),
242 Addr.isKnownNonNull());
243 }
244
245 /// Given
246 /// %addr = [n x T]* ...
247 /// produce
248 /// %name = getelementptr inbounds %addr, i64 0, i64 index
249 /// where i64 is actually the target word size.
250 ///
251 /// This API assumes that drilling into an array like this is always
252 /// an inbounds operation.
253 Address CreateConstArrayGEP(Address Addr, uint64_t Index,
254 const llvm::Twine &Name = "") {
255 llvm::ArrayType *ElTy = cast<llvm::ArrayType>(Val: Addr.getElementType());
256 const llvm::DataLayout &DL = getDataLayout();
257 CharUnits EltSize =
258 CharUnits::fromQuantity(Quantity: DL.getTypeAllocSize(Ty: ElTy->getElementType()));
259
260 return Address(
261 CreateInBoundsGEP(Ty: Addr.getElementType(), Ptr: Addr.getBasePointer(),
262 IdxList: {getSize(N: CharUnits::Zero()), getSize(N: Index)}, Name),
263 ElTy->getElementType(),
264 Addr.getAlignment().alignmentAtOffset(offset: Index * EltSize),
265 Addr.isKnownNonNull());
266 }
267
268 /// Given
269 /// %addr = T* ...
270 /// produce
271 /// %name = getelementptr inbounds %addr, i64 index
272 /// where i64 is actually the target word size.
273 Address CreateConstInBoundsGEP(Address Addr, uint64_t Index,
274 const llvm::Twine &Name = "") {
275 llvm::Type *ElTy = Addr.getElementType();
276 const llvm::DataLayout &DL = getDataLayout();
277 CharUnits EltSize = CharUnits::fromQuantity(Quantity: DL.getTypeAllocSize(Ty: ElTy));
278
279 return Address(
280 CreateInBoundsGEP(Ty: ElTy, Ptr: Addr.getBasePointer(), IdxList: getSize(N: Index), Name),
281 ElTy, Addr.getAlignment().alignmentAtOffset(offset: Index * EltSize),
282 Addr.isKnownNonNull());
283 }
284
285 /// Given
286 /// %addr = T* ...
287 /// produce
288 /// %name = getelementptr inbounds %addr, i64 index
289 /// where i64 is actually the target word size.
290 Address CreateConstGEP(Address Addr, uint64_t Index,
291 const llvm::Twine &Name = "") {
292 llvm::Type *ElTy = Addr.getElementType();
293 const llvm::DataLayout &DL = getDataLayout();
294 CharUnits EltSize = CharUnits::fromQuantity(Quantity: DL.getTypeAllocSize(Ty: ElTy));
295
296 return Address(CreateGEP(Ty: ElTy, Ptr: Addr.getBasePointer(), IdxList: getSize(N: Index), Name),
297 Addr.getElementType(),
298 Addr.getAlignment().alignmentAtOffset(offset: Index * EltSize));
299 }
300
301 /// Create GEP with single dynamic index. The address alignment is reduced
302 /// according to the element size.
303 using CGBuilderBaseTy::CreateGEP;
304 Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index,
305 const llvm::Twine &Name = "") {
306 const llvm::DataLayout &DL = getDataLayout();
307 CharUnits EltSize =
308 CharUnits::fromQuantity(Quantity: DL.getTypeAllocSize(Ty: Addr.getElementType()));
309
310 return Address(
311 CreateGEP(Ty: Addr.getElementType(), Ptr: Addr.emitRawPointer(CGF), IdxList: Index, Name),
312 Addr.getElementType(),
313 Addr.getAlignment().alignmentOfArrayElement(elementSize: EltSize));
314 }
315
316 /// Given a pointer to i8, adjust it by a given constant offset.
317 Address CreateConstInBoundsByteGEP(Address Addr, CharUnits Offset,
318 const llvm::Twine &Name = "") {
319 assert(Addr.getElementType() == TypeCache.Int8Ty);
320 return Address(
321 CreateInBoundsGEP(Ty: Addr.getElementType(), Ptr: Addr.getBasePointer(),
322 IdxList: getSize(N: Offset), Name),
323 Addr.getElementType(), Addr.getAlignment().alignmentAtOffset(offset: Offset),
324 Addr.isKnownNonNull());
325 }
326
327 Address CreateConstByteGEP(Address Addr, CharUnits Offset,
328 const llvm::Twine &Name = "") {
329 assert(Addr.getElementType() == TypeCache.Int8Ty);
330 return Address(CreateGEP(Ty: Addr.getElementType(), Ptr: Addr.getBasePointer(),
331 IdxList: getSize(N: Offset), Name),
332 Addr.getElementType(),
333 Addr.getAlignment().alignmentAtOffset(offset: Offset));
334 }
335
336 using CGBuilderBaseTy::CreateConstInBoundsGEP2_32;
337 Address CreateConstInBoundsGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1,
338 const llvm::Twine &Name = "") {
339 return createConstGEP2_32<true>(Addr, Idx0, Idx1, Name);
340 }
341
342 using CGBuilderBaseTy::CreateConstGEP2_32;
343 Address CreateConstGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1,
344 const llvm::Twine &Name = "") {
345 return createConstGEP2_32<false>(Addr, Idx0, Idx1, Name);
346 }
347
348 Address CreateGEP(Address Addr, ArrayRef<llvm::Value *> IdxList,
349 llvm::Type *ElementType, CharUnits Align,
350 const Twine &Name = "",
351 llvm::GEPNoWrapFlags NW = llvm::GEPNoWrapFlags::none()) {
352 llvm::Value *Ptr = emitRawPointerFromAddress(Addr);
353 return RawAddress(CreateGEP(Ty: Addr.getElementType(), Ptr, IdxList, Name, NW),
354 ElementType, Align);
355 }
356
357 using CGBuilderBaseTy::CreateInBoundsGEP;
358 Address CreateInBoundsGEP(Address Addr, ArrayRef<llvm::Value *> IdxList,
359 llvm::Type *ElementType, CharUnits Align,
360 const Twine &Name = "") {
361 return RawAddress(CreateInBoundsGEP(Ty: Addr.getElementType(),
362 Ptr: emitRawPointerFromAddress(Addr),
363 IdxList, Name),
364 ElementType, Align, Addr.isKnownNonNull());
365 }
366
367 using CGBuilderBaseTy::CreateStructuredGEP;
368 llvm::Value *CreateAccessChain(bool Logical, llvm::Type *BaseType,
369 llvm::Value *PtrBase,
370 ArrayRef<llvm::Value *> IdxList,
371 const Twine &Name = "") {
372
373 if (Logical)
374 return CreateStructuredGEP(BaseType, PtrBase, Indices: IdxList, Name);
375 return CreateInBoundsGEP(Ty: BaseType, Ptr: PtrBase, IdxList, Name);
376 }
377
378 Address CreateAccessChain(bool Logical, Address Addr,
379 ArrayRef<llvm::Value *> IdxList,
380 llvm::Type *ElementType, CharUnits Align,
381 const Twine &Name = "") {
382
383 return RawAddress(CreateAccessChain(Logical, BaseType: Addr.getElementType(),
384 PtrBase: emitRawPointerFromAddress(Addr),
385 IdxList, Name),
386 ElementType, Align, Addr.isKnownNonNull());
387 }
388
389 using CGBuilderBaseTy::CreateIsNull;
390 llvm::Value *CreateIsNull(Address Addr, const Twine &Name = "") {
391 if (!Addr.hasOffset())
392 return CreateIsNull(Arg: Addr.getBasePointer(), Name);
393 // The pointer isn't null if Addr has an offset since offsets can always
394 // be applied inbound.
395 return llvm::ConstantInt::getFalse(Context);
396 }
397
398 using CGBuilderBaseTy::CreateMemCpy;
399 llvm::CallInst *CreateMemCpy(Address Dest, Address Src, llvm::Value *Size,
400 bool IsVolatile = false) {
401 llvm::Value *DestPtr = emitRawPointerFromAddress(Addr: Dest);
402 llvm::Value *SrcPtr = emitRawPointerFromAddress(Addr: Src);
403 return CreateMemCpy(Dst: DestPtr, DstAlign: Dest.getAlignment().getAsAlign(), Src: SrcPtr,
404 SrcAlign: Src.getAlignment().getAsAlign(), Size, isVolatile: IsVolatile);
405 }
406 llvm::CallInst *CreateMemCpy(Address Dest, Address Src, uint64_t Size,
407 bool IsVolatile = false) {
408 llvm::Value *DestPtr = emitRawPointerFromAddress(Addr: Dest);
409 llvm::Value *SrcPtr = emitRawPointerFromAddress(Addr: Src);
410 return CreateMemCpy(Dst: DestPtr, DstAlign: Dest.getAlignment().getAsAlign(), Src: SrcPtr,
411 SrcAlign: Src.getAlignment().getAsAlign(), Size, isVolatile: IsVolatile);
412 }
413
414 using CGBuilderBaseTy::CreateMemCpyInline;
415 llvm::CallInst *CreateMemCpyInline(Address Dest, Address Src, uint64_t Size) {
416 llvm::Value *DestPtr = emitRawPointerFromAddress(Addr: Dest);
417 llvm::Value *SrcPtr = emitRawPointerFromAddress(Addr: Src);
418 return CreateMemCpyInline(Dst: DestPtr, DstAlign: Dest.getAlignment().getAsAlign(), Src: SrcPtr,
419 SrcAlign: Src.getAlignment().getAsAlign(), Size: getInt64(C: Size));
420 }
421
422 using CGBuilderBaseTy::CreateMemMove;
423 llvm::CallInst *CreateMemMove(Address Dest, Address Src, llvm::Value *Size,
424 bool IsVolatile = false) {
425 llvm::Value *DestPtr = emitRawPointerFromAddress(Addr: Dest);
426 llvm::Value *SrcPtr = emitRawPointerFromAddress(Addr: Src);
427 return CreateMemMove(Dst: DestPtr, DstAlign: Dest.getAlignment().getAsAlign(), Src: SrcPtr,
428 SrcAlign: Src.getAlignment().getAsAlign(), Size, isVolatile: IsVolatile);
429 }
430
431 using CGBuilderBaseTy::CreateMemSet;
432 llvm::CallInst *CreateMemSet(Address Dest, llvm::Value *Value,
433 llvm::Value *Size, bool IsVolatile = false) {
434 return CreateMemSet(Ptr: emitRawPointerFromAddress(Addr: Dest), Val: Value, Size,
435 Align: Dest.getAlignment().getAsAlign(), isVolatile: IsVolatile);
436 }
437
438 using CGBuilderBaseTy::CreateMemSetInline;
439 llvm::CallInst *CreateMemSetInline(Address Dest, llvm::Value *Value,
440 uint64_t Size) {
441 return CreateMemSetInline(Dst: emitRawPointerFromAddress(Addr: Dest),
442 DstAlign: Dest.getAlignment().getAsAlign(), Val: Value,
443 Size: getInt64(C: Size));
444 }
445
446 using CGBuilderBaseTy::CreatePreserveStructAccessIndex;
447 Address CreatePreserveStructAccessIndex(Address Addr, unsigned Index,
448 unsigned FieldIndex,
449 llvm::MDNode *DbgInfo) {
450 llvm::StructType *ElTy = cast<llvm::StructType>(Val: Addr.getElementType());
451 const llvm::DataLayout &DL = getDataLayout();
452 const llvm::StructLayout *Layout = DL.getStructLayout(Ty: ElTy);
453 auto Offset = CharUnits::fromQuantity(Quantity: Layout->getElementOffset(Idx: Index));
454
455 return Address(
456 CreatePreserveStructAccessIndex(ElTy, Base: emitRawPointerFromAddress(Addr),
457 Index, FieldIndex, DbgInfo),
458 ElTy->getElementType(N: Index),
459 Addr.getAlignment().alignmentAtOffset(offset: Offset));
460 }
461
462 using CGBuilderBaseTy::CreatePreserveUnionAccessIndex;
463 Address CreatePreserveUnionAccessIndex(Address Addr, unsigned FieldIndex,
464 llvm::MDNode *DbgInfo) {
465 Addr.replaceBasePointer(P: CreatePreserveUnionAccessIndex(
466 Base: Addr.getBasePointer(), FieldIndex, DbgInfo));
467 return Addr;
468 }
469
470 using CGBuilderBaseTy::CreateLaunderInvariantGroup;
471 Address CreateLaunderInvariantGroup(Address Addr) {
472 Addr.replaceBasePointer(P: CreateLaunderInvariantGroup(Ptr: Addr.getBasePointer()));
473 return Addr;
474 }
475};
476
477} // end namespace CodeGen
478} // end namespace clang
479
480#endif
481