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 "llvm/IR/DataLayout.h"
13#include "llvm/IR/IRBuilder.h"
14#include "Address.h"
15#include "CodeGenTypeCache.h"
16
17namespace clang {
18namespace CodeGen {
19
20class CodeGenFunction;
21
22/// This is an IRBuilder insertion helper that forwards to
23/// CodeGenFunction::InsertHelper, which adds necessary metadata to
24/// instructions.
25class CGBuilderInserter final : public llvm::IRBuilderDefaultInserter {
26public:
27  CGBuilderInserter() = default;
28  explicit CGBuilderInserter(CodeGenFunction *CGF) : CGF(CGF) {}
29
30  /// This forwards to CodeGenFunction::InsertHelper.
31  void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
32                    llvm::BasicBlock *BB,
33                    llvm::BasicBlock::iterator InsertPt) const override;
34private:
35  CodeGenFunction *CGF = nullptr;
36};
37
38typedef CGBuilderInserter CGBuilderInserterTy;
39
40typedef llvm::IRBuilder<llvm::ConstantFolder, CGBuilderInserterTy>
41    CGBuilderBaseTy;
42
43class CGBuilderTy : public CGBuilderBaseTy {
44  /// Storing a reference to the type cache here makes it a lot easier
45  /// to build natural-feeling, target-specific IR.
46  const CodeGenTypeCache &TypeCache;
47public:
48  CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::LLVMContext &C)
49    : CGBuilderBaseTy(C), TypeCache(TypeCache) {}
50  CGBuilderTy(const CodeGenTypeCache &TypeCache,
51              llvm::LLVMContext &C, const llvm::ConstantFolder &F,
52              const CGBuilderInserterTy &Inserter)
53    : CGBuilderBaseTy(C, F, Inserter), TypeCache(TypeCache) {}
54  CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::Instruction *I)
55    : CGBuilderBaseTy(I), TypeCache(TypeCache) {}
56  CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::BasicBlock *BB)
57    : CGBuilderBaseTy(BB), TypeCache(TypeCache) {}
58
59  llvm::ConstantInt *getSize(CharUnits N) {
60    return llvm::ConstantInt::get(TypeCache.SizeTy, N.getQuantity());
61  }
62  llvm::ConstantInt *getSize(uint64_t N) {
63    return llvm::ConstantInt::get(TypeCache.SizeTy, N);
64  }
65
66  // Note that we intentionally hide the CreateLoad APIs that don't
67  // take an alignment.
68  llvm::LoadInst *CreateLoad(Address Addr, const llvm::Twine &Name = "") {
69    return CreateAlignedLoad(Addr.getElementType(), Addr.getPointer(),
70                             Addr.getAlignment().getAsAlign(), Name);
71  }
72  llvm::LoadInst *CreateLoad(Address Addr, const char *Name) {
73    // This overload is required to prevent string literals from
74    // ending up in the IsVolatile overload.
75    return CreateAlignedLoad(Addr.getElementType(), Addr.getPointer(),
76                             Addr.getAlignment().getAsAlign(), Name);
77  }
78  llvm::LoadInst *CreateLoad(Address Addr, bool IsVolatile,
79                             const llvm::Twine &Name = "") {
80    return CreateAlignedLoad(Addr.getElementType(), Addr.getPointer(),
81                             Addr.getAlignment().getAsAlign(), IsVolatile,
82                             Name);
83  }
84
85  using CGBuilderBaseTy::CreateAlignedLoad;
86  llvm::LoadInst *CreateAlignedLoad(llvm::Type *Ty, llvm::Value *Addr,
87                                    CharUnits Align,
88                                    const llvm::Twine &Name = "") {
89    assert(Addr->getType()->getPointerElementType() == Ty);
90    return CreateAlignedLoad(Ty, Addr, Align.getAsAlign(), Name);
91  }
92
93  // Note that we intentionally hide the CreateStore APIs that don't
94  // take an alignment.
95  llvm::StoreInst *CreateStore(llvm::Value *Val, Address Addr,
96                               bool IsVolatile = false) {
97    return CreateAlignedStore(Val, Addr.getPointer(),
98                              Addr.getAlignment().getAsAlign(), IsVolatile);
99  }
100
101  using CGBuilderBaseTy::CreateAlignedStore;
102  llvm::StoreInst *CreateAlignedStore(llvm::Value *Val, llvm::Value *Addr,
103                                      CharUnits Align, bool IsVolatile = false) {
104    return CreateAlignedStore(Val, Addr, Align.getAsAlign(), IsVolatile);
105  }
106
107  // FIXME: these "default-aligned" APIs should be removed,
108  // but I don't feel like fixing all the builtin code right now.
109  llvm::StoreInst *CreateDefaultAlignedStore(llvm::Value *Val,
110                                             llvm::Value *Addr,
111                                             bool IsVolatile = false) {
112    return CGBuilderBaseTy::CreateStore(Val, Addr, IsVolatile);
113  }
114
115  /// Emit a load from an i1 flag variable.
116  llvm::LoadInst *CreateFlagLoad(llvm::Value *Addr,
117                                 const llvm::Twine &Name = "") {
118    assert(Addr->getType()->getPointerElementType() == getInt1Ty());
119    return CreateAlignedLoad(getInt1Ty(), Addr, CharUnits::One(), Name);
120  }
121
122  /// Emit a store to an i1 flag variable.
123  llvm::StoreInst *CreateFlagStore(bool Value, llvm::Value *Addr) {
124    assert(Addr->getType()->getPointerElementType() == getInt1Ty());
125    return CreateAlignedStore(getInt1(Value), Addr, CharUnits::One());
126  }
127
128  // Temporarily use old signature; clang will be updated to an Address overload
129  // in a subsequent patch.
130  llvm::AtomicCmpXchgInst *
131  CreateAtomicCmpXchg(llvm::Value *Ptr, llvm::Value *Cmp, llvm::Value *New,
132                      llvm::AtomicOrdering SuccessOrdering,
133                      llvm::AtomicOrdering FailureOrdering,
134                      llvm::SyncScope::ID SSID = llvm::SyncScope::System) {
135    return CGBuilderBaseTy::CreateAtomicCmpXchg(
136        Ptr, Cmp, New, llvm::MaybeAlign(), SuccessOrdering, FailureOrdering,
137        SSID);
138  }
139
140  // Temporarily use old signature; clang will be updated to an Address overload
141  // in a subsequent patch.
142  llvm::AtomicRMWInst *
143  CreateAtomicRMW(llvm::AtomicRMWInst::BinOp Op, llvm::Value *Ptr,
144                  llvm::Value *Val, llvm::AtomicOrdering Ordering,
145                  llvm::SyncScope::ID SSID = llvm::SyncScope::System) {
146    return CGBuilderBaseTy::CreateAtomicRMW(Op, Ptr, Val, llvm::MaybeAlign(),
147                                            Ordering, SSID);
148  }
149
150  using CGBuilderBaseTy::CreateBitCast;
151  Address CreateBitCast(Address Addr, llvm::Type *Ty,
152                        const llvm::Twine &Name = "") {
153    return Address(CreateBitCast(Addr.getPointer(), Ty, Name),
154                   Addr.getAlignment());
155  }
156
157  using CGBuilderBaseTy::CreateAddrSpaceCast;
158  Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty,
159                              const llvm::Twine &Name = "") {
160    return Address(CreateAddrSpaceCast(Addr.getPointer(), Ty, Name),
161                   Addr.getAlignment());
162  }
163
164  /// Cast the element type of the given address to a different type,
165  /// preserving information like the alignment and address space.
166  Address CreateElementBitCast(Address Addr, llvm::Type *Ty,
167                               const llvm::Twine &Name = "") {
168    auto PtrTy = Ty->getPointerTo(Addr.getAddressSpace());
169    return CreateBitCast(Addr, PtrTy, Name);
170  }
171
172  using CGBuilderBaseTy::CreatePointerBitCastOrAddrSpaceCast;
173  Address CreatePointerBitCastOrAddrSpaceCast(Address Addr, llvm::Type *Ty,
174                                              const llvm::Twine &Name = "") {
175    llvm::Value *Ptr =
176      CreatePointerBitCastOrAddrSpaceCast(Addr.getPointer(), Ty, Name);
177    return Address(Ptr, Addr.getAlignment());
178  }
179
180  /// Given
181  ///   %addr = {T1, T2...}* ...
182  /// produce
183  ///   %name = getelementptr inbounds %addr, i32 0, i32 index
184  ///
185  /// This API assumes that drilling into a struct like this is always an
186  /// inbounds operation.
187  using CGBuilderBaseTy::CreateStructGEP;
188  Address CreateStructGEP(Address Addr, unsigned Index,
189                          const llvm::Twine &Name = "") {
190    llvm::StructType *ElTy = cast<llvm::StructType>(Addr.getElementType());
191    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
192    const llvm::StructLayout *Layout = DL.getStructLayout(ElTy);
193    auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index));
194
195    return Address(CreateStructGEP(Addr.getElementType(),
196                                   Addr.getPointer(), Index, Name),
197                   Addr.getAlignment().alignmentAtOffset(Offset));
198  }
199
200  /// Given
201  ///   %addr = [n x T]* ...
202  /// produce
203  ///   %name = getelementptr inbounds %addr, i64 0, i64 index
204  /// where i64 is actually the target word size.
205  ///
206  /// This API assumes that drilling into an array like this is always
207  /// an inbounds operation.
208  Address CreateConstArrayGEP(Address Addr, uint64_t Index,
209                              const llvm::Twine &Name = "") {
210    llvm::ArrayType *ElTy = cast<llvm::ArrayType>(Addr.getElementType());
211    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
212    CharUnits EltSize =
213        CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy->getElementType()));
214
215    return Address(
216        CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(),
217                          {getSize(CharUnits::Zero()), getSize(Index)}, Name),
218        Addr.getAlignment().alignmentAtOffset(Index * EltSize));
219  }
220
221  /// Given
222  ///   %addr = T* ...
223  /// produce
224  ///   %name = getelementptr inbounds %addr, i64 index
225  /// where i64 is actually the target word size.
226  Address CreateConstInBoundsGEP(Address Addr, uint64_t Index,
227                                 const llvm::Twine &Name = "") {
228    llvm::Type *ElTy = Addr.getElementType();
229    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
230    CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy));
231
232    return Address(CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(),
233                                     getSize(Index), Name),
234                   Addr.getAlignment().alignmentAtOffset(Index * EltSize));
235  }
236
237  /// Given
238  ///   %addr = T* ...
239  /// produce
240  ///   %name = getelementptr inbounds %addr, i64 index
241  /// where i64 is actually the target word size.
242  Address CreateConstGEP(Address Addr, uint64_t Index,
243                         const llvm::Twine &Name = "") {
244    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
245    CharUnits EltSize =
246        CharUnits::fromQuantity(DL.getTypeAllocSize(Addr.getElementType()));
247
248    return Address(CreateGEP(Addr.getElementType(), Addr.getPointer(),
249                             getSize(Index), Name),
250                   Addr.getAlignment().alignmentAtOffset(Index * EltSize));
251  }
252
253  /// Given a pointer to i8, adjust it by a given constant offset.
254  Address CreateConstInBoundsByteGEP(Address Addr, CharUnits Offset,
255                                     const llvm::Twine &Name = "") {
256    assert(Addr.getElementType() == TypeCache.Int8Ty);
257    return Address(CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(),
258                                     getSize(Offset), Name),
259                   Addr.getAlignment().alignmentAtOffset(Offset));
260  }
261  Address CreateConstByteGEP(Address Addr, CharUnits Offset,
262                             const llvm::Twine &Name = "") {
263    assert(Addr.getElementType() == TypeCache.Int8Ty);
264    return Address(CreateGEP(Addr.getPointer(), getSize(Offset), Name),
265                   Addr.getAlignment().alignmentAtOffset(Offset));
266  }
267
268  using CGBuilderBaseTy::CreateConstInBoundsGEP2_32;
269  Address CreateConstInBoundsGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1,
270                                     const llvm::Twine &Name = "") {
271    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
272
273    auto *GEP = cast<llvm::GetElementPtrInst>(CreateConstInBoundsGEP2_32(
274        Addr.getElementType(), Addr.getPointer(), Idx0, Idx1, Name));
275    llvm::APInt Offset(
276        DL.getIndexSizeInBits(Addr.getType()->getPointerAddressSpace()), 0,
277        /*isSigned=*/true);
278    if (!GEP->accumulateConstantOffset(DL, Offset))
279      llvm_unreachable("offset of GEP with constants is always computable");
280    return Address(GEP, Addr.getAlignment().alignmentAtOffset(
281                            CharUnits::fromQuantity(Offset.getSExtValue())));
282  }
283
284  using CGBuilderBaseTy::CreateMemCpy;
285  llvm::CallInst *CreateMemCpy(Address Dest, Address Src, llvm::Value *Size,
286                               bool IsVolatile = false) {
287    return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(),
288                        Src.getPointer(), Src.getAlignment().getAsAlign(), Size,
289                        IsVolatile);
290  }
291  llvm::CallInst *CreateMemCpy(Address Dest, Address Src, uint64_t Size,
292                               bool IsVolatile = false) {
293    return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(),
294                        Src.getPointer(), Src.getAlignment().getAsAlign(), Size,
295                        IsVolatile);
296  }
297
298  using CGBuilderBaseTy::CreateMemCpyInline;
299  llvm::CallInst *CreateMemCpyInline(Address Dest, Address Src, uint64_t Size) {
300    return CreateMemCpyInline(
301        Dest.getPointer(), Dest.getAlignment().getAsAlign(), Src.getPointer(),
302        Src.getAlignment().getAsAlign(), getInt64(Size));
303  }
304
305  using CGBuilderBaseTy::CreateMemMove;
306  llvm::CallInst *CreateMemMove(Address Dest, Address Src, llvm::Value *Size,
307                                bool IsVolatile = false) {
308    return CreateMemMove(Dest.getPointer(), Dest.getAlignment().getAsAlign(),
309                         Src.getPointer(), Src.getAlignment().getAsAlign(),
310                         Size, IsVolatile);
311  }
312
313  using CGBuilderBaseTy::CreateMemSet;
314  llvm::CallInst *CreateMemSet(Address Dest, llvm::Value *Value,
315                               llvm::Value *Size, bool IsVolatile = false) {
316    return CreateMemSet(Dest.getPointer(), Value, Size,
317                        Dest.getAlignment().getAsAlign(), IsVolatile);
318  }
319
320  using CGBuilderBaseTy::CreatePreserveStructAccessIndex;
321  Address CreatePreserveStructAccessIndex(Address Addr,
322                                          unsigned Index,
323                                          unsigned FieldIndex,
324                                          llvm::MDNode *DbgInfo) {
325    llvm::StructType *ElTy = cast<llvm::StructType>(Addr.getElementType());
326    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
327    const llvm::StructLayout *Layout = DL.getStructLayout(ElTy);
328    auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index));
329
330    return Address(CreatePreserveStructAccessIndex(ElTy, Addr.getPointer(),
331                                                   Index, FieldIndex, DbgInfo),
332                   Addr.getAlignment().alignmentAtOffset(Offset));
333  }
334};
335
336}  // end namespace CodeGen
337}  // end namespace clang
338
339#endif
340