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