clang  19.0.0git
ConstantInitBuilder.h
Go to the documentation of this file.
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"
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);
52  struct SelfReference {
53  llvm::GlobalVariable *Dummy;
55 
56  SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {}
57  };
58  CodeGenModule &CGM;
60  std::vector<SelfReference> SelfReferences;
61  bool Frozen = false;
62 
63  friend class ConstantInitFuture;
65  template <class, class>
67 
68 protected:
69  explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {}
70 
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.
98 protected:
101  size_t Begin;
102  mutable size_t CachedOffsetEnd = 0;
103  bool Finished = false;
104  bool Frozen = false;
105  bool Packed = false;
107 
109  return Builder.Buffer;
110  }
111 
113  return Builder.Buffer;
114  }
115 
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 
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.
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.
156  : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin),
158  Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed),
160  other.Finished = true;
161  }
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.
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.
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.
259  size_t Index;
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.
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.
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 
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>
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:
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.
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.
406  assert(!this->Parent && "finishing non-root builder");
407  return this->Builder.createFuture(asImpl().finishImpl());
408  }
409 };
410 
411 template <class Traits>
413  : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
414  Traits> {
415  using super =
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>
427 
428 protected:
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>
449  : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
450  Traits> {
451  using super =
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>
463 
464 protected:
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>
500 protected:
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 
527 };
528 
529 /// The standard implementation of ConstantInitBuilder used in Clang.
531  : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
532 public:
535 };
536 
537 /// A helper class of ConstantInitBuilder, used for building constant
538 /// array initializers.
540  : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> {
541  template <class Traits>
543 
544  // The use of explicit qualification is a GCC workaround.
545  template <class Impl, class Traits>
547 
550  llvm::Type *eltTy)
551  : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {}
552 };
553 
554 /// A helper class of ConstantInitBuilder, used for building constant
555 /// struct initializers.
557  : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> {
558  template <class Traits>
560 
561  // The use of explicit qualification is a GCC workaround.
562  template <class Impl, class Traits>
564 
567  llvm::StructType *structTy)
568  : ConstantStructBuilderTemplateBase(builder, parent, structTy) {}
569 };
570 
571 } // end namespace CodeGen
572 } // end namespace clang
573 
574 #endif
NodeId Parent
Definition: ASTDiff.cpp:191
target
Definition: SemaSYCL.cpp:45
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
This class organizes the cross-function state that is used while generating LLVM code.
An opaque class to hold the abstract position of a placeholder.
A concrete base class for struct and array aggregate initializer builders.
llvm::SmallVectorImpl< llvm::Constant * > & getBuffer()
bool empty() const
Return true if no elements have yet been added to this struct or array.
void addTaggedRelativeOffset(llvm::IntegerType *type, llvm::Constant *address, unsigned tag)
Add a relative offset to the target address, plus a small constant offset.
void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target)
Add a relative offset to the given target address, i.e.
llvm::Constant * getAddrOfPosition(llvm::Type *type, size_t position)
Produce an address which points to a position in the aggregate being constructed.
PlaceholderPosition addPlaceholder()
Add a placeholder value to the structure.
void addRelativeOffsetToPosition(llvm::IntegerType *type, llvm::Constant *target, size_t position)
Same as addRelativeOffset(), but instead relative to an element in this aggregate,...
void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value)
Fill a previously-added placeholder.
ConstantAggregateBuilderBase & operator=(const ConstantAggregateBuilderBase &)=delete
void abandon()
Abandon this builder completely.
void add(llvm::Constant *value)
Add a new value to this initializer.
llvm::Constant * finishArray(llvm::Type *eltTy)
PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType)
Add a placeholder, giving the expected type that will be filled in.
void addSize(CharUnits size)
Add an integer value of type size_t.
void addInt(llvm::IntegerType *intTy, uint64_t value, bool isSigned=false)
Add an integer value of a specific type.
ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other)
llvm::Constant * finishStruct(llvm::StructType *structTy)
llvm::Constant * getAddrOfCurrentPosition(llvm::Type *type)
Produce an address which will eventually point to the next position to be filled.
ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder, ConstantAggregateBuilderBase *parent)
void addNullPointer(llvm::PointerType *ptrTy)
Add a null pointer of a specific type.
CharUnits getNextOffsetFromGlobal() const
Return the offset from the start of the initializer to the next position, assuming no padding is requ...
llvm::ArrayRef< llvm::Constant * > getGEPIndicesToCurrentPosition(llvm::SmallVectorImpl< llvm::Constant * > &indices)
const llvm::SmallVectorImpl< llvm::Constant * > & getBuffer() const
ConstantAggregateBuilderBase & operator=(ConstantAggregateBuilderBase &&other)=delete
void addAll(llvm::ArrayRef< llvm::Constant * > values)
Add a bunch of new values to this initializer.
size_t size() const
Return the number of elements that have been added to this struct or array.
void fillPlaceholderWithInt(PlaceholderPosition position, llvm::IntegerType *type, uint64_t value, bool isSigned=false)
Fill a previously-added placeholder.
ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &)=delete
llvm::GlobalVariable * finishAndCreateGlobal(As &&...args)
Given that this builder was created by beginning an array or struct directly on a ConstantInitBuilder...
ArrayBuilder beginArray(llvm::Type *eltTy=nullptr)
ConstantInitFuture finishAndCreateFuture()
Given that this builder was created by beginning an array or struct directly on a ConstantInitBuilder...
ConstantAggregateBuilderTemplateBase(InitBuilder &builder, AggregateBuilderBase *parent)
void finishAndSetAsInitializer(llvm::GlobalVariable *global)
Given that this builder was created by beginning an array or struct directly on a ConstantInitBuilder...
StructBuilder beginStruct(llvm::StructType *ty=nullptr)
typename Traits::AggregateBuilderBase AggregateBuilderBase
void finishAndAddTo(AggregateBuilderBase &parent)
Given that this builder was created by beginning an array or struct component on the given parent bui...
ConstantArrayBuilderTemplateBase(InitBuilder &builder, AggregateBuilderBase *parent, llvm::Type *eltTy)
typename Traits::AggregateBuilderBase AggregateBuilderBase
A helper class of ConstantInitBuilder, used for building constant array initializers.
A convenience builder class for complex constant initializers, especially for anonymous global struct...
A template class designed to allow other frontends to easily customize the builder classes used by Co...
StructBuilder beginStruct(llvm::StructType *structTy=nullptr)
ArrayBuilder beginArray(llvm::Type *eltTy=nullptr)
The standard implementation of ConstantInitBuilder used in Clang.
A "future" for a completed constant initializer, which can be passed around independently of any sub-...
A template class designed to allow other frontends to easily customize the builder classes used by Co...
ConstantStructBuilderTemplateBase(InitBuilder &builder, AggregateBuilderBase *parent, llvm::StructType *structTy)
void suggestType(llvm::StructType *structTy)
Use the given type for the struct if its element count is correct.
typename Traits::AggregateBuilderBase AggregateBuilderBase
A helper class of ConstantInitBuilder, used for building constant struct initializers.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
The JSON file list parser is used to communicate input to InstallAPI.
unsigned long uint64_t