clang 18.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 bitcast of a value to a specific type.
208 void addBitCast(llvm::Constant *value, llvm::Type *type) {
209 add(llvm::ConstantExpr::getBitCast(value, type));
210 }
211
212 /// Add a bunch of new values to this initializer.
214 assert(!Finished && "cannot add more values after finishing builder");
215 assert(!Frozen && "cannot add values while subbuilder is active");
216 Builder.Buffer.append(values.begin(), values.end());
217 }
218
219 /// Add a relative offset to the given target address, i.e. the
220 /// static difference between the target address and the address
221 /// of the relative offset. The target must be known to be defined
222 /// in the current linkage unit. The offset will have the given
223 /// integer type, which must be no wider than intptr_t. Some
224 /// targets may not fully support this operation.
225 void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) {
226 add(getRelativeOffset(type, target));
227 }
228
229 /// Same as addRelativeOffset(), but instead relative to an element in this
230 /// aggregate, identified by its index.
231 void addRelativeOffsetToPosition(llvm::IntegerType *type,
232 llvm::Constant *target, size_t position) {
233 add(getRelativeOffsetToPosition(type, target, position));
234 }
235
236 /// Add a relative offset to the target address, plus a small
237 /// constant offset. This is primarily useful when the relative
238 /// offset is known to be a multiple of (say) four and therefore
239 /// the tag can be used to express an extra two bits of information.
240 void addTaggedRelativeOffset(llvm::IntegerType *type,
241 llvm::Constant *address,
242 unsigned tag) {
243 llvm::Constant *offset = getRelativeOffset(type, address);
244 if (tag) {
245 offset = llvm::ConstantExpr::getAdd(offset,
246 llvm::ConstantInt::get(type, tag));
247 }
248 add(offset);
249 }
250
251 /// Return the offset from the start of the initializer to the
252 /// next position, assuming no padding is required prior to it.
253 ///
254 /// This operation will not succeed if any unsized placeholders are
255 /// currently in place in the initializer.
257 assert(!Finished && "cannot add more values after finishing builder");
258 assert(!Frozen && "cannot add values while subbuilder is active");
259 return getOffsetFromGlobalTo(Builder.Buffer.size());
260 }
261
262 /// An opaque class to hold the abstract position of a placeholder.
264 size_t Index;
266 PlaceholderPosition(size_t index) : Index(index) {}
267 };
268
269 /// Add a placeholder value to the structure. The returned position
270 /// can be used to set the value later; it will not be invalidated by
271 /// any intermediate operations except (1) filling the same position or
272 /// (2) finishing the entire builder.
273 ///
274 /// This is useful for emitting certain kinds of structure which
275 /// contain some sort of summary field, generally a count, before any
276 /// of the data. By emitting a placeholder first, the structure can
277 /// be emitted eagerly.
279 assert(!Finished && "cannot add more values after finishing builder");
280 assert(!Frozen && "cannot add values while subbuilder is active");
281 Builder.Buffer.push_back(nullptr);
282 return Builder.Buffer.size() - 1;
283 }
284
285 /// Add a placeholder, giving the expected type that will be filled in.
286 PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType);
287
288 /// Fill a previously-added placeholder.
290 llvm::IntegerType *type, uint64_t value,
291 bool isSigned = false) {
292 fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned));
293 }
294
295 /// Fill a previously-added placeholder.
296 void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) {
297 assert(!Finished && "cannot change values after finishing builder");
298 assert(!Frozen && "cannot add values while subbuilder is active");
299 llvm::Constant *&slot = Builder.Buffer[position.Index];
300 assert(slot == nullptr && "placeholder already filled");
301 slot = value;
302 }
303
304 /// Produce an address which will eventually point to the next
305 /// position to be filled. This is computed with an indexed
306 /// getelementptr rather than by computing offsets.
307 ///
308 /// The returned pointer will have type T*, where T is the given type. This
309 /// type can differ from the type of the actual element.
310 llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type);
311
312 /// Produce an address which points to a position in the aggregate being
313 /// constructed. This is computed with an indexed getelementptr rather than by
314 /// computing offsets.
315 ///
316 /// The returned pointer will have type T*, where T is the given type. This
317 /// type can differ from the type of the actual element.
318 llvm::Constant *getAddrOfPosition(llvm::Type *type, size_t position);
319
322 getGEPIndicesTo(indices, Builder.Buffer.size());
323 return indices;
324 }
325
326protected:
327 llvm::Constant *finishArray(llvm::Type *eltTy);
328 llvm::Constant *finishStruct(llvm::StructType *structTy);
329
330private:
331 void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
332 size_t position) const;
333
334 llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType,
335 llvm::Constant *target);
336
337 llvm::Constant *getRelativeOffsetToPosition(llvm::IntegerType *offsetType,
338 llvm::Constant *target,
339 size_t position);
340
341 CharUnits getOffsetFromGlobalTo(size_t index) const;
342};
343
344template <class Impl, class Traits>
346 : public Traits::AggregateBuilderBase {
347 using super = typename Traits::AggregateBuilderBase;
348public:
349 using InitBuilder = typename Traits::InitBuilder;
350 using ArrayBuilder = typename Traits::ArrayBuilder;
351 using StructBuilder = typename Traits::StructBuilder;
352 using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
353
354protected:
356 AggregateBuilderBase *parent)
357 : super(builder, parent) {}
358
359 Impl &asImpl() { return *static_cast<Impl*>(this); }
360
361public:
362 ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
363 return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy);
364 }
365
366 StructBuilder beginStruct(llvm::StructType *ty = nullptr) {
367 return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty);
368 }
369
370 /// Given that this builder was created by beginning an array or struct
371 /// component on the given parent builder, finish the array/struct
372 /// component and add it to the parent.
373 ///
374 /// It is an intentional choice that the parent is passed in explicitly
375 /// despite it being redundant with information already kept in the
376 /// builder. This aids in readability by making it easier to find the
377 /// places that add components to a builder, as well as "bookending"
378 /// the sub-builder more explicitly.
380 assert(this->Parent == &parent && "adding to non-parent builder");
381 parent.add(asImpl().finishImpl());
382 }
383
384 /// Given that this builder was created by beginning an array or struct
385 /// directly on a ConstantInitBuilder, finish the array/struct and
386 /// create a global variable with it as the initializer.
387 template <class... As>
388 llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) {
389 assert(!this->Parent && "finishing non-root builder");
390 return this->Builder.createGlobal(asImpl().finishImpl(),
391 std::forward<As>(args)...);
392 }
393
394 /// Given that this builder was created by beginning an array or struct
395 /// directly on a ConstantInitBuilder, finish the array/struct and
396 /// set it as the initializer of the given global variable.
397 void finishAndSetAsInitializer(llvm::GlobalVariable *global) {
398 assert(!this->Parent && "finishing non-root builder");
399 return this->Builder.setGlobalInitializer(global, asImpl().finishImpl());
400 }
401
402 /// Given that this builder was created by beginning an array or struct
403 /// directly on a ConstantInitBuilder, finish the array/struct and
404 /// return a future which can be used to install the initializer in
405 /// a global later.
406 ///
407 /// This is useful for allowing a finished initializer to passed to
408 /// an API which will build the global. However, the "future" preserves
409 /// a dependency on the original builder; it is an error to pass it aside.
411 assert(!this->Parent && "finishing non-root builder");
412 return this->Builder.createFuture(asImpl().finishImpl());
413 }
414};
415
416template <class Traits>
418 : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
419 Traits> {
420 using super =
422
423public:
424 using InitBuilder = typename Traits::InitBuilder;
425 using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
426
427private:
428 llvm::Type *EltTy;
429
430 template <class, class>
432
433protected:
435 AggregateBuilderBase *parent,
436 llvm::Type *eltTy)
437 : super(builder, parent), EltTy(eltTy) {}
438
439private:
440 /// Form an array constant from the values that have been added to this
441 /// builder.
442 llvm::Constant *finishImpl() {
443 return AggregateBuilderBase::finishArray(EltTy);
444 }
445};
446
447/// A template class designed to allow other frontends to
448/// easily customize the builder classes used by ConstantInitBuilder,
449/// and thus to extend the API to work with the abstractions they
450/// prefer. This would probably not be necessary if C++ just
451/// supported extension methods.
452template <class Traits>
454 : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
455 Traits> {
456 using super =
458
459public:
460 using InitBuilder = typename Traits::InitBuilder;
461 using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
462
463private:
464 llvm::StructType *StructTy;
465
466 template <class, class>
468
469protected:
471 AggregateBuilderBase *parent,
472 llvm::StructType *structTy)
473 : super(builder, parent), StructTy(structTy) {
474 if (structTy) this->Packed = structTy->isPacked();
475 }
476
477public:
478 void setPacked(bool packed) {
479 this->Packed = packed;
480 }
481
482 /// Use the given type for the struct if its element count is correct.
483 /// Don't add more elements after calling this.
484 void suggestType(llvm::StructType *structTy) {
485 if (this->size() == structTy->getNumElements()) {
486 StructTy = structTy;
487 }
488 }
489
490private:
491 /// Form an array constant from the values that have been added to this
492 /// builder.
493 llvm::Constant *finishImpl() {
494 return AggregateBuilderBase::finishStruct(StructTy);
495 }
496};
497
498/// A template class designed to allow other frontends to
499/// easily customize the builder classes used by ConstantInitBuilder,
500/// and thus to extend the API to work with the abstractions they
501/// prefer. This would probably not be necessary if C++ just
502/// supported extension methods.
503template <class Traits>
505protected:
508
509public:
510 using InitBuilder = typename Traits::InitBuilder;
511 using ArrayBuilder = typename Traits::ArrayBuilder;
512 using StructBuilder = typename Traits::StructBuilder;
513
514 ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
515 return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy);
516 }
517
518 StructBuilder beginStruct(llvm::StructType *structTy = nullptr) {
519 return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy);
520 }
521};
522
523class ConstantInitBuilder;
524class ConstantStructBuilder;
525class ConstantArrayBuilder;
526
532};
533
534/// The standard implementation of ConstantInitBuilder used in Clang.
536 : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
537public:
540};
541
542/// A helper class of ConstantInitBuilder, used for building constant
543/// array initializers.
545 : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> {
546 template <class Traits>
548
549 // The use of explicit qualification is a GCC workaround.
550 template <class Impl, class Traits>
552
555 llvm::Type *eltTy)
556 : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {}
557};
558
559/// A helper class of ConstantInitBuilder, used for building constant
560/// struct initializers.
562 : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> {
563 template <class Traits>
565
566 // The use of explicit qualification is a GCC workaround.
567 template <class Impl, class Traits>
569
572 llvm::StructType *structTy)
573 : ConstantStructBuilderTemplateBase(builder, parent, structTy) {}
574};
575
576} // end namespace CodeGen
577} // end namespace clang
578
579#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 addBitCast(llvm::Constant *value, llvm::Type *type)
Add a bitcast of a value to a specific type.
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.