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 
27 namespace clang {
28 namespace CodeGen {
29 
30 class 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);
51 class 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 
68 protected:
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 
76 private:
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.
97 class ConstantAggregateBuilderBase {
98 protected:
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 
147 public:
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 
321 protected:
322   llvm::Constant *finishArray(llvm::Type *eltTy);
323   llvm::Constant *finishStruct(llvm::StructType *structTy);
324 
325 private:
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 
339 template <class Impl, class Traits>
340 class ConstantAggregateBuilderTemplateBase
341     : public Traits::AggregateBuilderBase {
342   using super = typename Traits::AggregateBuilderBase;
343 public:
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 
349 protected:
350   ConstantAggregateBuilderTemplateBase(InitBuilder &builder,
351                                        AggregateBuilderBase *parent)
352     : super(builder, parent) {}
353 
354   Impl &asImpl() { return *static_cast<Impl*>(this); }
355 
356 public:
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 
411 template <class Traits>
412 class ConstantArrayBuilderTemplateBase
413   : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
414                                                 Traits> {
415   using super =
416     ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>;
417 
418 public:
419   using InitBuilder = typename Traits::InitBuilder;
420   using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
421 
422 private:
423   llvm::Type *EltTy;
424 
425   template <class, class>
426   friend class ConstantAggregateBuilderTemplateBase;
427 
428 protected:
429   ConstantArrayBuilderTemplateBase(InitBuilder &builder,
430                                    AggregateBuilderBase *parent,
431                                    llvm::Type *eltTy)
432     : super(builder, parent), EltTy(eltTy) {}
433 
434 private:
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.
447 template <class Traits>
448 class ConstantStructBuilderTemplateBase
449   : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
450                                                 Traits> {
451   using super =
452     ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>;
453 
454 public:
455   using InitBuilder = typename Traits::InitBuilder;
456   using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
457 
458 private:
459   llvm::StructType *StructTy;
460 
461   template <class, class>
462   friend class ConstantAggregateBuilderTemplateBase;
463 
464 protected:
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 
472 public:
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 
485 private:
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.
498 template <class Traits>
499 class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase {
500 protected:
501   ConstantInitBuilderTemplateBase(CodeGenModule &CGM)
502     : ConstantInitBuilderBase(CGM) {}
503 
504 public:
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 
518 class ConstantInitBuilder;
519 class ConstantStructBuilder;
520 class ConstantArrayBuilder;
521 
522 struct 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.
530 class ConstantInitBuilder
531     : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
532 public:
533   explicit ConstantInitBuilder(CodeGenModule &CGM) :
534     ConstantInitBuilderTemplateBase(CGM) {}
535 };
536 
537 /// A helper class of ConstantInitBuilder, used for building constant
538 /// array initializers.
539 class 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.
556 class 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