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
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);
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
68protected:
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
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.
98protected:
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
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.
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
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>
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:
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.
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
411template <class Traits>
413 : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
414 Traits> {
415 using super =
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>
427
428protected:
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>
449 : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
450 Traits> {
451 using super =
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>
463
464protected:
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>
500protected:
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
527};
528
529/// The standard implementation of ConstantInitBuilder used in Clang.
531 : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
532public:
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
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.
ConstantAggregateBuilderBase & operator=(ConstantAggregateBuilderBase &&other)=delete
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.
ConstantAggregateBuilderBase & operator=(const ConstantAggregateBuilderBase &)=delete
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.
llvm::SmallVectorImpl< llvm::Constant * > & getBuffer()
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)
void addAll(llvm::ArrayRef< llvm::Constant * > values)
Add a bunch of new values to this initializer.
const llvm::SmallVectorImpl< llvm::Constant * > & getBuffer() const
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
ArrayBuilder beginArray(llvm::Type *eltTy=nullptr)
llvm::GlobalVariable * finishAndCreateGlobal(As &&...args)
Given that this builder was created by beginning an array or struct directly on a ConstantInitBuilder...
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.
The JSON file list parser is used to communicate input to InstallAPI.