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