summaryrefslogtreecommitdiffstats
path: root/lib/CodeGen/CGBuilder.h
blob: 50ef853b8300a7f0dd97bda2eeda24f0dd8c7353 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
//===-- CGBuilder.h - Choose IRBuilder implementation  ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
#define LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H

#include "llvm/IR/DataLayout.h"
#include "llvm/IR/IRBuilder.h"
#include "Address.h"
#include "CodeGenTypeCache.h"

namespace clang {
namespace CodeGen {

class CodeGenFunction;

/// This is an IRBuilder insertion helper that forwards to
/// CodeGenFunction::InsertHelper, which adds necessary metadata to
/// instructions.
class CGBuilderInserter : protected llvm::IRBuilderDefaultInserter {
public:
  CGBuilderInserter() = default;
  explicit CGBuilderInserter(CodeGenFunction *CGF) : CGF(CGF) {}

protected:
  /// This forwards to CodeGenFunction::InsertHelper.
  void InsertHelper(llvm::Instruction *I, const llvm::Twine &Name,
                    llvm::BasicBlock *BB,
                    llvm::BasicBlock::iterator InsertPt) const;
private:
  CodeGenFunction *CGF = nullptr;
};

typedef CGBuilderInserter CGBuilderInserterTy;

typedef llvm::IRBuilder<llvm::ConstantFolder, CGBuilderInserterTy>
    CGBuilderBaseTy;

class CGBuilderTy : public CGBuilderBaseTy {
  /// Storing a reference to the type cache here makes it a lot easier
  /// to build natural-feeling, target-specific IR.
  const CodeGenTypeCache &TypeCache;
public:
  CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::LLVMContext &C)
    : CGBuilderBaseTy(C), TypeCache(TypeCache) {}
  CGBuilderTy(const CodeGenTypeCache &TypeCache,
              llvm::LLVMContext &C, const llvm::ConstantFolder &F,
              const CGBuilderInserterTy &Inserter)
    : CGBuilderBaseTy(C, F, Inserter), TypeCache(TypeCache) {}
  CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::Instruction *I)
    : CGBuilderBaseTy(I), TypeCache(TypeCache) {}
  CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::BasicBlock *BB)
    : CGBuilderBaseTy(BB), TypeCache(TypeCache) {}

  llvm::ConstantInt *getSize(CharUnits N) {
    return llvm::ConstantInt::get(TypeCache.SizeTy, N.getQuantity());
  }
  llvm::ConstantInt *getSize(uint64_t N) {
    return llvm::ConstantInt::get(TypeCache.SizeTy, N);
  }

  // Note that we intentionally hide the CreateLoad APIs that don't
  // take an alignment.
  llvm::LoadInst *CreateLoad(Address Addr, const llvm::Twine &Name = "") {
    return CreateAlignedLoad(Addr.getPointer(),
                             Addr.getAlignment().getQuantity(),
                             Name);
  }
  llvm::LoadInst *CreateLoad(Address Addr, const char *Name) {
    // This overload is required to prevent string literals from
    // ending up in the IsVolatile overload.
    return CreateAlignedLoad(Addr.getPointer(),
                             Addr.getAlignment().getQuantity(),
                             Name);
  }
  llvm::LoadInst *CreateLoad(Address Addr, bool IsVolatile,
                             const llvm::Twine &Name = "") {
    return CreateAlignedLoad(Addr.getPointer(),
                             Addr.getAlignment().getQuantity(),
                             IsVolatile,
                             Name);
  }

  using CGBuilderBaseTy::CreateAlignedLoad;
  llvm::LoadInst *CreateAlignedLoad(llvm::Value *Addr, CharUnits Align,
                                    const llvm::Twine &Name = "") {
    return CreateAlignedLoad(Addr, Align.getQuantity(), Name);
  }
  llvm::LoadInst *CreateAlignedLoad(llvm::Value *Addr, CharUnits Align,
                                    const char *Name) {
    return CreateAlignedLoad(Addr, Align.getQuantity(), Name);
  }
  llvm::LoadInst *CreateAlignedLoad(llvm::Type *Ty, llvm::Value *Addr,
                                    CharUnits Align,
                                    const llvm::Twine &Name = "") {
    assert(Addr->getType()->getPointerElementType() == Ty);
    return CreateAlignedLoad(Addr, Align.getQuantity(), Name);
  }

  // Note that we intentionally hide the CreateStore APIs that don't
  // take an alignment.
  llvm::StoreInst *CreateStore(llvm::Value *Val, Address Addr,
                               bool IsVolatile = false) {
    return CreateAlignedStore(Val, Addr.getPointer(),
                              Addr.getAlignment().getQuantity(), IsVolatile);
  }

  using CGBuilderBaseTy::CreateAlignedStore;
  llvm::StoreInst *CreateAlignedStore(llvm::Value *Val, llvm::Value *Addr,
                                      CharUnits Align, bool IsVolatile = false) {
    return CreateAlignedStore(Val, Addr, Align.getQuantity(), IsVolatile);
  }

  // FIXME: these "default-aligned" APIs should be removed,
  // but I don't feel like fixing all the builtin code right now.
  llvm::StoreInst *CreateDefaultAlignedStore(llvm::Value *Val,
                                             llvm::Value *Addr,
                                             bool IsVolatile = false) {
    return CGBuilderBaseTy::CreateStore(Val, Addr, IsVolatile);
  }

  /// Emit a load from an i1 flag variable.
  llvm::LoadInst *CreateFlagLoad(llvm::Value *Addr,
                                 const llvm::Twine &Name = "") {
    assert(Addr->getType()->getPointerElementType() == getInt1Ty());
    return CreateAlignedLoad(getInt1Ty(), Addr, CharUnits::One(), Name);
  }

  /// Emit a store to an i1 flag variable.
  llvm::StoreInst *CreateFlagStore(bool Value, llvm::Value *Addr) {
    assert(Addr->getType()->getPointerElementType() == getInt1Ty());
    return CreateAlignedStore(getInt1(Value), Addr, CharUnits::One());
  }

  using CGBuilderBaseTy::CreateBitCast;
  Address CreateBitCast(Address Addr, llvm::Type *Ty,
                        const llvm::Twine &Name = "") {
    return Address(CreateBitCast(Addr.getPointer(), Ty, Name),
                   Addr.getAlignment());
  }

  using CGBuilderBaseTy::CreateAddrSpaceCast;
  Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty,
                              const llvm::Twine &Name = "") {
    return Address(CreateAddrSpaceCast(Addr.getPointer(), Ty, Name),
                   Addr.getAlignment());
  }

  /// Cast the element type of the given address to a different type,
  /// preserving information like the alignment and address space.
  Address CreateElementBitCast(Address Addr, llvm::Type *Ty,
                               const llvm::Twine &Name = "") {
    auto PtrTy = Ty->getPointerTo(Addr.getAddressSpace());
    return CreateBitCast(Addr, PtrTy, Name);
  }

  using CGBuilderBaseTy::CreatePointerBitCastOrAddrSpaceCast;
  Address CreatePointerBitCastOrAddrSpaceCast(Address Addr, llvm::Type *Ty,
                                              const llvm::Twine &Name = "") {
    llvm::Value *Ptr =
      CreatePointerBitCastOrAddrSpaceCast(Addr.getPointer(), Ty, Name);
    return Address(Ptr, Addr.getAlignment());
  }

  /// Given
  ///   %addr = {T1, T2...}* ...
  /// produce
  ///   %name = getelementptr inbounds %addr, i32 0, i32 index
  ///
  /// This API assumes that drilling into a struct like this is always an
  /// inbounds operation.
  using CGBuilderBaseTy::CreateStructGEP;
  Address CreateStructGEP(Address Addr, unsigned Index,
                          const llvm::Twine &Name = "") {
    llvm::StructType *ElTy = cast<llvm::StructType>(Addr.getElementType());
    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
    const llvm::StructLayout *Layout = DL.getStructLayout(ElTy);
    auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index));

    return Address(CreateStructGEP(Addr.getElementType(),
                                   Addr.getPointer(), Index, Name),
                   Addr.getAlignment().alignmentAtOffset(Offset));
  }

  /// Given
  ///   %addr = [n x T]* ...
  /// produce
  ///   %name = getelementptr inbounds %addr, i64 0, i64 index
  /// where i64 is actually the target word size.
  ///
  /// This API assumes that drilling into an array like this is always
  /// an inbounds operation.
  Address CreateConstArrayGEP(Address Addr, uint64_t Index,
                              const llvm::Twine &Name = "") {
    llvm::ArrayType *ElTy = cast<llvm::ArrayType>(Addr.getElementType());
    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
    CharUnits EltSize =
        CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy->getElementType()));

    return Address(
        CreateInBoundsGEP(Addr.getPointer(),
                          {getSize(CharUnits::Zero()), getSize(Index)}, Name),
        Addr.getAlignment().alignmentAtOffset(Index * EltSize));
  }

  /// Given
  ///   %addr = T* ...
  /// produce
  ///   %name = getelementptr inbounds %addr, i64 index
  /// where i64 is actually the target word size.
  Address CreateConstInBoundsGEP(Address Addr, uint64_t Index,
                                 const llvm::Twine &Name = "") {
    llvm::Type *ElTy = Addr.getElementType();
    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
    CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy));

    return Address(CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(),
                                     getSize(Index), Name),
                   Addr.getAlignment().alignmentAtOffset(Index * EltSize));
  }

  /// Given
  ///   %addr = T* ...
  /// produce
  ///   %name = getelementptr inbounds %addr, i64 index
  /// where i64 is actually the target word size.
  Address CreateConstGEP(Address Addr, uint64_t Index,
                         const llvm::Twine &Name = "") {
    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();
    CharUnits EltSize =
        CharUnits::fromQuantity(DL.getTypeAllocSize(Addr.getElementType()));

    return Address(CreateGEP(Addr.getElementType(), Addr.getPointer(),
                             getSize(Index), Name),
                   Addr.getAlignment().alignmentAtOffset(Index * EltSize));
  }

  /// Given a pointer to i8, adjust it by a given constant offset.
  Address CreateConstInBoundsByteGEP(Address Addr, CharUnits Offset,
                                     const llvm::Twine &Name = "") {
    assert(Addr.getElementType() == TypeCache.Int8Ty);
    return Address(CreateInBoundsGEP(Addr.getPointer(), getSize(Offset), Name),
                   Addr.getAlignment().alignmentAtOffset(Offset));
  }
  Address CreateConstByteGEP(Address Addr, CharUnits Offset,
                             const llvm::Twine &Name = "") {
    assert(Addr.getElementType() == TypeCache.Int8Ty);
    return Address(CreateGEP(Addr.getPointer(), getSize(Offset), Name),
                   Addr.getAlignment().alignmentAtOffset(Offset));
  }

  using CGBuilderBaseTy::CreateConstInBoundsGEP2_32;
  Address CreateConstInBoundsGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1,
                                     const llvm::Twine &Name = "") {
    const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout();

    auto *GEP = cast<llvm::GetElementPtrInst>(CreateConstInBoundsGEP2_32(
        Addr.getElementType(), Addr.getPointer(), Idx0, Idx1, Name));
    llvm::APInt Offset(
        DL.getIndexSizeInBits(Addr.getType()->getPointerAddressSpace()), 0,
        /*IsSigned=*/true);
    if (!GEP->accumulateConstantOffset(DL, Offset))
      llvm_unreachable("offset of GEP with constants is always computable");
    return Address(GEP, Addr.getAlignment().alignmentAtOffset(
                            CharUnits::fromQuantity(Offset.getSExtValue())));
  }

  using CGBuilderBaseTy::CreateMemCpy;
  llvm::CallInst *CreateMemCpy(Address Dest, Address Src, llvm::Value *Size,
                               bool IsVolatile = false) {
    return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getQuantity(),
                        Src.getPointer(), Src.getAlignment().getQuantity(),
                        Size,IsVolatile);
  }
  llvm::CallInst *CreateMemCpy(Address Dest, Address Src, uint64_t Size,
                               bool IsVolatile = false) {
    return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getQuantity(),
                        Src.getPointer(), Src.getAlignment().getQuantity(),
                        Size, IsVolatile);
  }

  using CGBuilderBaseTy::CreateMemMove;
  llvm::CallInst *CreateMemMove(Address Dest, Address Src, llvm::Value *Size,
                                bool IsVolatile = false) {
    return CreateMemMove(Dest.getPointer(), Dest.getAlignment().getQuantity(),
                         Src.getPointer(), Src.getAlignment().getQuantity(),
                         Size, IsVolatile);
  }

  using CGBuilderBaseTy::CreateMemSet;
  llvm::CallInst *CreateMemSet(Address Dest, llvm::Value *Value,
                               llvm::Value *Size, bool IsVolatile = false) {
    return CreateMemSet(Dest.getPointer(), Value, Size,
                        Dest.getAlignment().getQuantity(), IsVolatile);
  }
};

}  // end namespace CodeGen
}  // end namespace clang

#endif