1//===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- 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// This class provides a convenient interface for building complex
10// global initializers of the sort that are frequently required for
11// language ABIs.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
16#define LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
17
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/IR/Constants.h"
21#include "llvm/IR/GlobalValue.h"
22#include "clang/AST/CharUnits.h"
23#include "clang/CodeGen/ConstantInitFuture.h"
24
25#include <vector>
26
27namespace clang {
28namespace CodeGen {
29
30class CodeGenModule;
31
32/// A convenience builder class for complex constant initializers,
33/// especially for anonymous global structures used by various language
34/// runtimes.
35///
36/// The basic usage pattern is expected to be something like:
37///    ConstantInitBuilder builder(CGM);
38///    auto toplevel = builder.beginStruct();
39///    toplevel.addInt(CGM.SizeTy, widgets.size());
40///    auto widgetArray = builder.beginArray();
41///    for (auto &widget : widgets) {
42///      auto widgetDesc = widgetArray.beginStruct();
43///      widgetDesc.addInt(CGM.SizeTy, widget.getPower());
44///      widgetDesc.add(CGM.GetAddrOfConstantStringFromLiteral(widget.getName()));
45///      widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl()));
46///      widgetDesc.finishAndAddTo(widgetArray);
47///    }
48///    widgetArray.finishAndAddTo(toplevel);
49///    auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align,
50///                                                 /*constant*/ true);
51class ConstantInitBuilderBase {
52  struct SelfReference {
53    llvm::GlobalVariable *Dummy;
54    llvm::SmallVector<llvm::Constant*, 4> Indices;
55
56    SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {}
57  };
58  CodeGenModule &CGM;
59  llvm::SmallVector<llvm::Constant*, 16> Buffer;
60  std::vector<SelfReference> SelfReferences;
61  bool Frozen = false;
62
63  friend class ConstantInitFuture;
64  friend class ConstantAggregateBuilderBase;
65  template <class, class>
66  friend class ConstantAggregateBuilderTemplateBase;
67
68protected:
69  explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {}
70
71  ~ConstantInitBuilderBase() {
72    assert(Buffer.empty() && "didn't claim all values out of buffer");
73    assert(SelfReferences.empty() && "didn't apply all self-references");
74  }
75
76private:
77  llvm::GlobalVariable *createGlobal(llvm::Constant *initializer,
78                                     const llvm::Twine &name,
79                                     CharUnits alignment,
80                                     bool constant = false,
81                                     llvm::GlobalValue::LinkageTypes linkage
82                                       = llvm::GlobalValue::InternalLinkage,
83                                     unsigned addressSpace = 0);
84
85  ConstantInitFuture createFuture(llvm::Constant *initializer);
86
87  void setGlobalInitializer(llvm::GlobalVariable *GV,
88                            llvm::Constant *initializer);
89
90  void resolveSelfReferences(llvm::GlobalVariable *GV);
91
92  void abandon(size_t newEnd);
93};
94
95/// A concrete base class for struct and array aggregate
96/// initializer builders.
97class ConstantAggregateBuilderBase {
98protected:
99  ConstantInitBuilderBase &Builder;
100  ConstantAggregateBuilderBase *Parent;
101  size_t Begin;
102  mutable size_t CachedOffsetEnd = 0;
103  bool Finished = false;
104  bool Frozen = false;
105  bool Packed = false;
106  mutable CharUnits CachedOffsetFromGlobal;
107
108  llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
109    return Builder.Buffer;
110  }
111
112  const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
113    return Builder.Buffer;
114  }
115
116  ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder,
117                               ConstantAggregateBuilderBase *parent)
118      : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) {
119    if (parent) {
120      assert(!parent->Frozen && "parent already has child builder active");
121      parent->Frozen = true;
122    } else {
123      assert(!builder.Frozen && "builder already has child builder active");
124      builder.Frozen = true;
125    }
126  }
127
128  ~ConstantAggregateBuilderBase() {
129    assert(Finished && "didn't finish aggregate builder");
130  }
131
132  void markFinished() {
133    assert(!Frozen && "child builder still active");
134    assert(!Finished && "builder already finished");
135    Finished = true;
136    if (Parent) {
137      assert(Parent->Frozen &&
138             "parent not frozen while child builder active");
139      Parent->Frozen = false;
140    } else {
141      assert(Builder.Frozen &&
142             "builder not frozen while child builder active");
143      Builder.Frozen = false;
144    }
145  }
146
147public:
148  // Not copyable.
149  ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &) = delete;
150  ConstantAggregateBuilderBase &operator=(const ConstantAggregateBuilderBase &)
151    = delete;
152
153  // Movable, mostly to allow returning.  But we have to write this out
154  // properly to satisfy the assert in the destructor.
155  ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other)
156    : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin),
157      CachedOffsetEnd(other.CachedOffsetEnd),
158      Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed),
159      CachedOffsetFromGlobal(other.CachedOffsetFromGlobal) {
160    other.Finished = true;
161  }
162  ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other)
163    = delete;
164
165  /// Return the number of elements that have been added to
166  /// this struct or array.
167  size_t size() const {
168    assert(!this->Finished && "cannot query after finishing builder");
169    assert(!this->Frozen && "cannot query while sub-builder is active");
170    assert(this->Begin <= this->getBuffer().size());
171    return this->getBuffer().size() - this->Begin;
172  }
173
174  /// Return true if no elements have yet been added to this struct or array.
175  bool empty() const {
176    return size() == 0;
177  }
178
179  /// Abandon this builder completely.
180  void abandon() {
181    markFinished();
182    Builder.abandon(Begin);
183  }
184
185  /// Add a new value to this initializer.
186  void add(llvm::Constant *value) {
187    assert(value && "adding null value to constant initializer");
188    assert(!Finished && "cannot add more values after finishing builder");
189    assert(!Frozen && "cannot add values while subbuilder is active");
190    Builder.Buffer.push_back(value);
191  }
192
193  /// Add an integer value of type size_t.
194  void addSize(CharUnits size);
195
196  /// Add an integer value of a specific type.
197  void addInt(llvm::IntegerType *intTy, uint64_t value,
198              bool isSigned = false) {
199    add(llvm::ConstantInt::get(intTy, value, isSigned));
200  }
201
202  /// Add a null pointer of a specific type.
203  void addNullPointer(llvm::PointerType *ptrTy) {
204    add(llvm::ConstantPointerNull::get(ptrTy));
205  }
206
207  /// Add a bunch of new values to this initializer.
208  void addAll(llvm::ArrayRef<llvm::Constant *> values) {
209    assert(!Finished && "cannot add more values after finishing builder");
210    assert(!Frozen && "cannot add values while subbuilder is active");
211    Builder.Buffer.append(values.begin(), values.end());
212  }
213
214  /// Add a relative offset to the given target address, i.e. the
215  /// static difference between the target address and the address
216  /// of the relative offset.  The target must be known to be defined
217  /// in the current linkage unit.  The offset will have the given
218  /// integer type, which must be no wider than intptr_t.  Some
219  /// targets may not fully support this operation.
220  void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) {
221    add(getRelativeOffset(type, target));
222  }
223
224  /// Same as addRelativeOffset(), but instead relative to an element in this
225  /// aggregate, identified by its index.
226  void addRelativeOffsetToPosition(llvm::IntegerType *type,
227                                   llvm::Constant *target, size_t position) {
228    add(getRelativeOffsetToPosition(type, target, position));
229  }
230
231  /// Add a relative offset to the target address, plus a small
232  /// constant offset.  This is primarily useful when the relative
233  /// offset is known to be a multiple of (say) four and therefore
234  /// the tag can be used to express an extra two bits of information.
235  void addTaggedRelativeOffset(llvm::IntegerType *type,
236                               llvm::Constant *address,
237                               unsigned tag) {
238    llvm::Constant *offset = getRelativeOffset(type, address);
239    if (tag) {
240      offset = llvm::ConstantExpr::getAdd(offset,
241                                          llvm::ConstantInt::get(type, tag));
242    }
243    add(offset);
244  }
245
246  /// Return the offset from the start of the initializer to the
247  /// next position, assuming no padding is required prior to it.
248  ///
249  /// This operation will not succeed if any unsized placeholders are
250  /// currently in place in the initializer.
251  CharUnits getNextOffsetFromGlobal() const {
252    assert(!Finished && "cannot add more values after finishing builder");
253    assert(!Frozen && "cannot add values while subbuilder is active");
254    return getOffsetFromGlobalTo(Builder.Buffer.size());
255  }
256
257  /// An opaque class to hold the abstract position of a placeholder.
258  class PlaceholderPosition {
259    size_t Index;
260    friend class ConstantAggregateBuilderBase;
261    PlaceholderPosition(size_t index) : Index(index) {}
262  };
263
264  /// Add a placeholder value to the structure.  The returned position
265  /// can be used to set the value later; it will not be invalidated by
266  /// any intermediate operations except (1) filling the same position or
267  /// (2) finishing the entire builder.
268  ///
269  /// This is useful for emitting certain kinds of structure which
270  /// contain some sort of summary field, generally a count, before any
271  /// of the data.  By emitting a placeholder first, the structure can
272  /// be emitted eagerly.
273  PlaceholderPosition addPlaceholder() {
274    assert(!Finished && "cannot add more values after finishing builder");
275    assert(!Frozen && "cannot add values while subbuilder is active");
276    Builder.Buffer.push_back(nullptr);
277    return Builder.Buffer.size() - 1;
278  }
279
280  /// Add a placeholder, giving the expected type that will be filled in.
281  PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType);
282
283  /// Fill a previously-added placeholder.
284  void fillPlaceholderWithInt(PlaceholderPosition position,
285                              llvm::IntegerType *type, uint64_t value,
286                              bool isSigned = false) {
287    fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned));
288  }
289
290  /// Fill a previously-added placeholder.
291  void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) {
292    assert(!Finished && "cannot change values after finishing builder");
293    assert(!Frozen && "cannot add values while subbuilder is active");
294    llvm::Constant *&slot = Builder.Buffer[position.Index];
295    assert(slot == nullptr && "placeholder already filled");
296    slot = value;
297  }
298
299  /// Produce an address which will eventually point to the next
300  /// position to be filled.  This is computed with an indexed
301  /// getelementptr rather than by computing offsets.
302  ///
303  /// The returned pointer will have type T*, where T is the given type. This
304  /// type can differ from the type of the actual element.
305  llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type);
306
307  /// Produce an address which points to a position in the aggregate being
308  /// constructed. This is computed with an indexed getelementptr rather than by
309  /// computing offsets.
310  ///
311  /// The returned pointer will have type T*, where T is the given type. This
312  /// type can differ from the type of the actual element.
313  llvm::Constant *getAddrOfPosition(llvm::Type *type, size_t position);
314
315  llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition(
316                           llvm::SmallVectorImpl<llvm::Constant*> &indices) {
317    getGEPIndicesTo(indices, Builder.Buffer.size());
318    return indices;
319  }
320
321protected:
322  llvm::Constant *finishArray(llvm::Type *eltTy);
323  llvm::Constant *finishStruct(llvm::StructType *structTy);
324
325private:
326  void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
327                       size_t position) const;
328
329  llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType,
330                                    llvm::Constant *target);
331
332  llvm::Constant *getRelativeOffsetToPosition(llvm::IntegerType *offsetType,
333                                              llvm::Constant *target,
334                                              size_t position);
335
336  CharUnits getOffsetFromGlobalTo(size_t index) const;
337};
338
339template <class Impl, class Traits>
340class ConstantAggregateBuilderTemplateBase
341    : public Traits::AggregateBuilderBase {
342  using super = typename Traits::AggregateBuilderBase;
343public:
344  using InitBuilder = typename Traits::InitBuilder;
345  using ArrayBuilder = typename Traits::ArrayBuilder;
346  using StructBuilder = typename Traits::StructBuilder;
347  using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
348
349protected:
350  ConstantAggregateBuilderTemplateBase(InitBuilder &builder,
351                                       AggregateBuilderBase *parent)
352    : super(builder, parent) {}
353
354  Impl &asImpl() { return *static_cast<Impl*>(this); }
355
356public:
357  ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
358    return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy);
359  }
360
361  StructBuilder beginStruct(llvm::StructType *ty = nullptr) {
362    return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty);
363  }
364
365  /// Given that this builder was created by beginning an array or struct
366  /// component on the given parent builder, finish the array/struct
367  /// component and add it to the parent.
368  ///
369  /// It is an intentional choice that the parent is passed in explicitly
370  /// despite it being redundant with information already kept in the
371  /// builder.  This aids in readability by making it easier to find the
372  /// places that add components to a builder, as well as "bookending"
373  /// the sub-builder more explicitly.
374  void finishAndAddTo(AggregateBuilderBase &parent) {
375    assert(this->Parent == &parent && "adding to non-parent builder");
376    parent.add(asImpl().finishImpl());
377  }
378
379  /// Given that this builder was created by beginning an array or struct
380  /// directly on a ConstantInitBuilder, finish the array/struct and
381  /// create a global variable with it as the initializer.
382  template <class... As>
383  llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) {
384    assert(!this->Parent && "finishing non-root builder");
385    return this->Builder.createGlobal(asImpl().finishImpl(),
386                                      std::forward<As>(args)...);
387  }
388
389  /// Given that this builder was created by beginning an array or struct
390  /// directly on a ConstantInitBuilder, finish the array/struct and
391  /// set it as the initializer of the given global variable.
392  void finishAndSetAsInitializer(llvm::GlobalVariable *global) {
393    assert(!this->Parent && "finishing non-root builder");
394    return this->Builder.setGlobalInitializer(global, asImpl().finishImpl());
395  }
396
397  /// Given that this builder was created by beginning an array or struct
398  /// directly on a ConstantInitBuilder, finish the array/struct and
399  /// return a future which can be used to install the initializer in
400  /// a global later.
401  ///
402  /// This is useful for allowing a finished initializer to passed to
403  /// an API which will build the global.  However, the "future" preserves
404  /// a dependency on the original builder; it is an error to pass it aside.
405  ConstantInitFuture finishAndCreateFuture() {
406    assert(!this->Parent && "finishing non-root builder");
407    return this->Builder.createFuture(asImpl().finishImpl());
408  }
409};
410
411template <class Traits>
412class ConstantArrayBuilderTemplateBase
413  : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
414                                                Traits> {
415  using super =
416    ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>;
417
418public:
419  using InitBuilder = typename Traits::InitBuilder;
420  using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
421
422private:
423  llvm::Type *EltTy;
424
425  template <class, class>
426  friend class ConstantAggregateBuilderTemplateBase;
427
428protected:
429  ConstantArrayBuilderTemplateBase(InitBuilder &builder,
430                                   AggregateBuilderBase *parent,
431                                   llvm::Type *eltTy)
432    : super(builder, parent), EltTy(eltTy) {}
433
434private:
435  /// Form an array constant from the values that have been added to this
436  /// builder.
437  llvm::Constant *finishImpl() {
438    return AggregateBuilderBase::finishArray(EltTy);
439  }
440};
441
442/// A template class designed to allow other frontends to
443/// easily customize the builder classes used by ConstantInitBuilder,
444/// and thus to extend the API to work with the abstractions they
445/// prefer.  This would probably not be necessary if C++ just
446/// supported extension methods.
447template <class Traits>
448class ConstantStructBuilderTemplateBase
449  : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
450                                                Traits> {
451  using super =
452    ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>;
453
454public:
455  using InitBuilder = typename Traits::InitBuilder;
456  using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
457
458private:
459  llvm::StructType *StructTy;
460
461  template <class, class>
462  friend class ConstantAggregateBuilderTemplateBase;
463
464protected:
465  ConstantStructBuilderTemplateBase(InitBuilder &builder,
466                                    AggregateBuilderBase *parent,
467                                    llvm::StructType *structTy)
468    : super(builder, parent), StructTy(structTy) {
469    if (structTy) this->Packed = structTy->isPacked();
470  }
471
472public:
473  void setPacked(bool packed) {
474    this->Packed = packed;
475  }
476
477  /// Use the given type for the struct if its element count is correct.
478  /// Don't add more elements after calling this.
479  void suggestType(llvm::StructType *structTy) {
480    if (this->size() == structTy->getNumElements()) {
481      StructTy = structTy;
482    }
483  }
484
485private:
486  /// Form an array constant from the values that have been added to this
487  /// builder.
488  llvm::Constant *finishImpl() {
489    return AggregateBuilderBase::finishStruct(StructTy);
490  }
491};
492
493/// A template class designed to allow other frontends to
494/// easily customize the builder classes used by ConstantInitBuilder,
495/// and thus to extend the API to work with the abstractions they
496/// prefer.  This would probably not be necessary if C++ just
497/// supported extension methods.
498template <class Traits>
499class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase {
500protected:
501  ConstantInitBuilderTemplateBase(CodeGenModule &CGM)
502    : ConstantInitBuilderBase(CGM) {}
503
504public:
505  using InitBuilder = typename Traits::InitBuilder;
506  using ArrayBuilder = typename Traits::ArrayBuilder;
507  using StructBuilder = typename Traits::StructBuilder;
508
509  ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
510    return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy);
511  }
512
513  StructBuilder beginStruct(llvm::StructType *structTy = nullptr) {
514    return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy);
515  }
516};
517
518class ConstantInitBuilder;
519class ConstantStructBuilder;
520class ConstantArrayBuilder;
521
522struct ConstantInitBuilderTraits {
523  using InitBuilder = ConstantInitBuilder;
524  using AggregateBuilderBase = ConstantAggregateBuilderBase;
525  using ArrayBuilder = ConstantArrayBuilder;
526  using StructBuilder = ConstantStructBuilder;
527};
528
529/// The standard implementation of ConstantInitBuilder used in Clang.
530class ConstantInitBuilder
531    : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
532public:
533  explicit ConstantInitBuilder(CodeGenModule &CGM) :
534    ConstantInitBuilderTemplateBase(CGM) {}
535};
536
537/// A helper class of ConstantInitBuilder, used for building constant
538/// array initializers.
539class ConstantArrayBuilder
540    : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> {
541  template <class Traits>
542  friend class ConstantInitBuilderTemplateBase;
543
544  // The use of explicit qualification is a GCC workaround.
545  template <class Impl, class Traits>
546  friend class CodeGen::ConstantAggregateBuilderTemplateBase;
547
548  ConstantArrayBuilder(ConstantInitBuilder &builder,
549                       ConstantAggregateBuilderBase *parent,
550                       llvm::Type *eltTy)
551    : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {}
552};
553
554/// A helper class of ConstantInitBuilder, used for building constant
555/// struct initializers.
556class ConstantStructBuilder
557    : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> {
558  template <class Traits>
559  friend class ConstantInitBuilderTemplateBase;
560
561  // The use of explicit qualification is a GCC workaround.
562  template <class Impl, class Traits>
563  friend class CodeGen::ConstantAggregateBuilderTemplateBase;
564
565  ConstantStructBuilder(ConstantInitBuilder &builder,
566                        ConstantAggregateBuilderBase *parent,
567                        llvm::StructType *structTy)
568    : ConstantStructBuilderTemplateBase(builder, parent, structTy) {}
569};
570
571}  // end namespace CodeGen
572}  // end namespace clang
573
574#endif
575