123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This class provides a convenient interface for building complex
- // global initializers of the sort that are frequently required for
- // language ABIs.
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
- #define LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/IR/Constants.h"
- #include "llvm/IR/GlobalValue.h"
- #include "clang/AST/CharUnits.h"
- #include "clang/CodeGen/ConstantInitFuture.h"
- #include <vector>
- namespace clang {
- namespace CodeGen {
- class CodeGenModule;
- /// A convenience builder class for complex constant initializers,
- /// especially for anonymous global structures used by various language
- /// runtimes.
- ///
- /// The basic usage pattern is expected to be something like:
- /// ConstantInitBuilder builder(CGM);
- /// auto toplevel = builder.beginStruct();
- /// toplevel.addInt(CGM.SizeTy, widgets.size());
- /// auto widgetArray = builder.beginArray();
- /// for (auto &widget : widgets) {
- /// auto widgetDesc = widgetArray.beginStruct();
- /// widgetDesc.addInt(CGM.SizeTy, widget.getPower());
- /// widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName()));
- /// widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl()));
- /// widgetDesc.finishAndAddTo(widgetArray);
- /// }
- /// widgetArray.finishAndAddTo(toplevel);
- /// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align,
- /// /*constant*/ true);
- class ConstantInitBuilderBase {
- struct SelfReference {
- llvm::GlobalVariable *Dummy;
- llvm::SmallVector<llvm::Constant*, 4> Indices;
- SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {}
- };
- CodeGenModule &CGM;
- llvm::SmallVector<llvm::Constant*, 16> Buffer;
- std::vector<SelfReference> SelfReferences;
- bool Frozen = false;
- friend class ConstantInitFuture;
- friend class ConstantAggregateBuilderBase;
- template <class, class>
- friend class ConstantAggregateBuilderTemplateBase;
- protected:
- explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {}
- ~ConstantInitBuilderBase() {
- assert(Buffer.empty() && "didn't claim all values out of buffer");
- assert(SelfReferences.empty() && "didn't apply all self-references");
- }
- private:
- llvm::GlobalVariable *createGlobal(llvm::Constant *initializer,
- const llvm::Twine &name,
- CharUnits alignment,
- bool constant = false,
- llvm::GlobalValue::LinkageTypes linkage
- = llvm::GlobalValue::InternalLinkage,
- unsigned addressSpace = 0);
- ConstantInitFuture createFuture(llvm::Constant *initializer);
- void setGlobalInitializer(llvm::GlobalVariable *GV,
- llvm::Constant *initializer);
- void resolveSelfReferences(llvm::GlobalVariable *GV);
- void abandon(size_t newEnd);
- };
- /// A concrete base class for struct and array aggregate
- /// initializer builders.
- class ConstantAggregateBuilderBase {
- protected:
- ConstantInitBuilderBase &Builder;
- ConstantAggregateBuilderBase *Parent;
- size_t Begin;
- mutable size_t CachedOffsetEnd = 0;
- bool Finished = false;
- bool Frozen = false;
- bool Packed = false;
- mutable CharUnits CachedOffsetFromGlobal;
- llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
- return Builder.Buffer;
- }
- const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
- return Builder.Buffer;
- }
- ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder,
- ConstantAggregateBuilderBase *parent)
- : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) {
- if (parent) {
- assert(!parent->Frozen && "parent already has child builder active");
- parent->Frozen = true;
- } else {
- assert(!builder.Frozen && "builder already has child builder active");
- builder.Frozen = true;
- }
- }
- ~ConstantAggregateBuilderBase() {
- assert(Finished && "didn't finish aggregate builder");
- }
- void markFinished() {
- assert(!Frozen && "child builder still active");
- assert(!Finished && "builder already finished");
- Finished = true;
- if (Parent) {
- assert(Parent->Frozen &&
- "parent not frozen while child builder active");
- Parent->Frozen = false;
- } else {
- assert(Builder.Frozen &&
- "builder not frozen while child builder active");
- Builder.Frozen = false;
- }
- }
- public:
- // Not copyable.
- ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &) = delete;
- ConstantAggregateBuilderBase &operator=(const ConstantAggregateBuilderBase &)
- = delete;
- // Movable, mostly to allow returning. But we have to write this out
- // properly to satisfy the assert in the destructor.
- ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other)
- : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin),
- CachedOffsetEnd(other.CachedOffsetEnd),
- Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed),
- CachedOffsetFromGlobal(other.CachedOffsetFromGlobal) {
- other.Finished = true;
- }
- ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other)
- = delete;
- /// Return the number of elements that have been added to
- /// this struct or array.
- size_t size() const {
- assert(!this->Finished && "cannot query after finishing builder");
- assert(!this->Frozen && "cannot query while sub-builder is active");
- assert(this->Begin <= this->getBuffer().size());
- return this->getBuffer().size() - this->Begin;
- }
- /// Return true if no elements have yet been added to this struct or array.
- bool empty() const {
- return size() == 0;
- }
- /// Abandon this builder completely.
- void abandon() {
- markFinished();
- Builder.abandon(Begin);
- }
- /// Add a new value to this initializer.
- void add(llvm::Constant *value) {
- assert(value && "adding null value to constant initializer");
- assert(!Finished && "cannot add more values after finishing builder");
- assert(!Frozen && "cannot add values while subbuilder is active");
- Builder.Buffer.push_back(value);
- }
- /// Add an integer value of type size_t.
- void addSize(CharUnits size);
- /// Add an integer value of a specific type.
- void addInt(llvm::IntegerType *intTy, uint64_t value,
- bool isSigned = false) {
- add(llvm::ConstantInt::get(intTy, value, isSigned));
- }
- /// Add a null pointer of a specific type.
- void addNullPointer(llvm::PointerType *ptrTy) {
- add(llvm::ConstantPointerNull::get(ptrTy));
- }
- /// Add a bitcast of a value to a specific type.
- void addBitCast(llvm::Constant *value, llvm::Type *type) {
- add(llvm::ConstantExpr::getBitCast(value, type));
- }
- /// Add a bunch of new values to this initializer.
- void addAll(llvm::ArrayRef<llvm::Constant *> values) {
- assert(!Finished && "cannot add more values after finishing builder");
- assert(!Frozen && "cannot add values while subbuilder is active");
- Builder.Buffer.append(values.begin(), values.end());
- }
- /// Add a relative offset to the given target address, i.e. the
- /// static difference between the target address and the address
- /// of the relative offset. The target must be known to be defined
- /// in the current linkage unit. The offset will have the given
- /// integer type, which must be no wider than intptr_t. Some
- /// targets may not fully support this operation.
- void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) {
- add(getRelativeOffset(type, target));
- }
- /// Same as addRelativeOffset(), but instead relative to an element in this
- /// aggregate, identified by its index.
- void addRelativeOffsetToPosition(llvm::IntegerType *type,
- llvm::Constant *target, size_t position) {
- add(getRelativeOffsetToPosition(type, target, position));
- }
- /// Add a relative offset to the target address, plus a small
- /// constant offset. This is primarily useful when the relative
- /// offset is known to be a multiple of (say) four and therefore
- /// the tag can be used to express an extra two bits of information.
- void addTaggedRelativeOffset(llvm::IntegerType *type,
- llvm::Constant *address,
- unsigned tag) {
- llvm::Constant *offset = getRelativeOffset(type, address);
- if (tag) {
- offset = llvm::ConstantExpr::getAdd(offset,
- llvm::ConstantInt::get(type, tag));
- }
- add(offset);
- }
- /// Return the offset from the start of the initializer to the
- /// next position, assuming no padding is required prior to it.
- ///
- /// This operation will not succeed if any unsized placeholders are
- /// currently in place in the initializer.
- CharUnits getNextOffsetFromGlobal() const {
- assert(!Finished && "cannot add more values after finishing builder");
- assert(!Frozen && "cannot add values while subbuilder is active");
- return getOffsetFromGlobalTo(Builder.Buffer.size());
- }
- /// An opaque class to hold the abstract position of a placeholder.
- class PlaceholderPosition {
- size_t Index;
- friend class ConstantAggregateBuilderBase;
- PlaceholderPosition(size_t index) : Index(index) {}
- };
- /// Add a placeholder value to the structure. The returned position
- /// can be used to set the value later; it will not be invalidated by
- /// any intermediate operations except (1) filling the same position or
- /// (2) finishing the entire builder.
- ///
- /// This is useful for emitting certain kinds of structure which
- /// contain some sort of summary field, generally a count, before any
- /// of the data. By emitting a placeholder first, the structure can
- /// be emitted eagerly.
- PlaceholderPosition addPlaceholder() {
- assert(!Finished && "cannot add more values after finishing builder");
- assert(!Frozen && "cannot add values while subbuilder is active");
- Builder.Buffer.push_back(nullptr);
- return Builder.Buffer.size() - 1;
- }
- /// Add a placeholder, giving the expected type that will be filled in.
- PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType);
- /// Fill a previously-added placeholder.
- void fillPlaceholderWithInt(PlaceholderPosition position,
- llvm::IntegerType *type, uint64_t value,
- bool isSigned = false) {
- fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned));
- }
- /// Fill a previously-added placeholder.
- void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) {
- assert(!Finished && "cannot change values after finishing builder");
- assert(!Frozen && "cannot add values while subbuilder is active");
- llvm::Constant *&slot = Builder.Buffer[position.Index];
- assert(slot == nullptr && "placeholder already filled");
- slot = value;
- }
- /// Produce an address which will eventually point to the next
- /// position to be filled. This is computed with an indexed
- /// getelementptr rather than by computing offsets.
- ///
- /// The returned pointer will have type T*, where T is the given type. This
- /// type can differ from the type of the actual element.
- llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type);
- /// Produce an address which points to a position in the aggregate being
- /// constructed. This is computed with an indexed getelementptr rather than by
- /// computing offsets.
- ///
- /// The returned pointer will have type T*, where T is the given type. This
- /// type can differ from the type of the actual element.
- llvm::Constant *getAddrOfPosition(llvm::Type *type, size_t position);
- llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition(
- llvm::SmallVectorImpl<llvm::Constant*> &indices) {
- getGEPIndicesTo(indices, Builder.Buffer.size());
- return indices;
- }
- protected:
- llvm::Constant *finishArray(llvm::Type *eltTy);
- llvm::Constant *finishStruct(llvm::StructType *structTy);
- private:
- void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
- size_t position) const;
- llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType,
- llvm::Constant *target);
- llvm::Constant *getRelativeOffsetToPosition(llvm::IntegerType *offsetType,
- llvm::Constant *target,
- size_t position);
- CharUnits getOffsetFromGlobalTo(size_t index) const;
- };
- template <class Impl, class Traits>
- class ConstantAggregateBuilderTemplateBase
- : public Traits::AggregateBuilderBase {
- using super = typename Traits::AggregateBuilderBase;
- public:
- using InitBuilder = typename Traits::InitBuilder;
- using ArrayBuilder = typename Traits::ArrayBuilder;
- using StructBuilder = typename Traits::StructBuilder;
- using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
- protected:
- ConstantAggregateBuilderTemplateBase(InitBuilder &builder,
- AggregateBuilderBase *parent)
- : super(builder, parent) {}
- Impl &asImpl() { return *static_cast<Impl*>(this); }
- public:
- ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
- return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy);
- }
- StructBuilder beginStruct(llvm::StructType *ty = nullptr) {
- return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty);
- }
- /// Given that this builder was created by beginning an array or struct
- /// component on the given parent builder, finish the array/struct
- /// component and add it to the parent.
- ///
- /// It is an intentional choice that the parent is passed in explicitly
- /// despite it being redundant with information already kept in the
- /// builder. This aids in readability by making it easier to find the
- /// places that add components to a builder, as well as "bookending"
- /// the sub-builder more explicitly.
- void finishAndAddTo(AggregateBuilderBase &parent) {
- assert(this->Parent == &parent && "adding to non-parent builder");
- parent.add(asImpl().finishImpl());
- }
- /// Given that this builder was created by beginning an array or struct
- /// directly on a ConstantInitBuilder, finish the array/struct and
- /// create a global variable with it as the initializer.
- template <class... As>
- llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) {
- assert(!this->Parent && "finishing non-root builder");
- return this->Builder.createGlobal(asImpl().finishImpl(),
- std::forward<As>(args)...);
- }
- /// Given that this builder was created by beginning an array or struct
- /// directly on a ConstantInitBuilder, finish the array/struct and
- /// set it as the initializer of the given global variable.
- void finishAndSetAsInitializer(llvm::GlobalVariable *global) {
- assert(!this->Parent && "finishing non-root builder");
- return this->Builder.setGlobalInitializer(global, asImpl().finishImpl());
- }
- /// Given that this builder was created by beginning an array or struct
- /// directly on a ConstantInitBuilder, finish the array/struct and
- /// return a future which can be used to install the initializer in
- /// a global later.
- ///
- /// This is useful for allowing a finished initializer to passed to
- /// an API which will build the global. However, the "future" preserves
- /// a dependency on the original builder; it is an error to pass it aside.
- ConstantInitFuture finishAndCreateFuture() {
- assert(!this->Parent && "finishing non-root builder");
- return this->Builder.createFuture(asImpl().finishImpl());
- }
- };
- template <class Traits>
- class ConstantArrayBuilderTemplateBase
- : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder,
- Traits> {
- using super =
- ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>;
- public:
- using InitBuilder = typename Traits::InitBuilder;
- using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
- private:
- llvm::Type *EltTy;
- template <class, class>
- friend class ConstantAggregateBuilderTemplateBase;
- protected:
- ConstantArrayBuilderTemplateBase(InitBuilder &builder,
- AggregateBuilderBase *parent,
- llvm::Type *eltTy)
- : super(builder, parent), EltTy(eltTy) {}
- private:
- /// Form an array constant from the values that have been added to this
- /// builder.
- llvm::Constant *finishImpl() {
- return AggregateBuilderBase::finishArray(EltTy);
- }
- };
- /// A template class designed to allow other frontends to
- /// easily customize the builder classes used by ConstantInitBuilder,
- /// and thus to extend the API to work with the abstractions they
- /// prefer. This would probably not be necessary if C++ just
- /// supported extension methods.
- template <class Traits>
- class ConstantStructBuilderTemplateBase
- : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,
- Traits> {
- using super =
- ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>;
- public:
- using InitBuilder = typename Traits::InitBuilder;
- using AggregateBuilderBase = typename Traits::AggregateBuilderBase;
- private:
- llvm::StructType *StructTy;
- template <class, class>
- friend class ConstantAggregateBuilderTemplateBase;
- protected:
- ConstantStructBuilderTemplateBase(InitBuilder &builder,
- AggregateBuilderBase *parent,
- llvm::StructType *structTy)
- : super(builder, parent), StructTy(structTy) {
- if (structTy) this->Packed = structTy->isPacked();
- }
- public:
- void setPacked(bool packed) {
- this->Packed = packed;
- }
- /// Use the given type for the struct if its element count is correct.
- /// Don't add more elements after calling this.
- void suggestType(llvm::StructType *structTy) {
- if (this->size() == structTy->getNumElements()) {
- StructTy = structTy;
- }
- }
- private:
- /// Form an array constant from the values that have been added to this
- /// builder.
- llvm::Constant *finishImpl() {
- return AggregateBuilderBase::finishStruct(StructTy);
- }
- };
- /// A template class designed to allow other frontends to
- /// easily customize the builder classes used by ConstantInitBuilder,
- /// and thus to extend the API to work with the abstractions they
- /// prefer. This would probably not be necessary if C++ just
- /// supported extension methods.
- template <class Traits>
- class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase {
- protected:
- ConstantInitBuilderTemplateBase(CodeGenModule &CGM)
- : ConstantInitBuilderBase(CGM) {}
- public:
- using InitBuilder = typename Traits::InitBuilder;
- using ArrayBuilder = typename Traits::ArrayBuilder;
- using StructBuilder = typename Traits::StructBuilder;
- ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) {
- return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy);
- }
- StructBuilder beginStruct(llvm::StructType *structTy = nullptr) {
- return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy);
- }
- };
- class ConstantInitBuilder;
- class ConstantStructBuilder;
- class ConstantArrayBuilder;
- struct ConstantInitBuilderTraits {
- using InitBuilder = ConstantInitBuilder;
- using AggregateBuilderBase = ConstantAggregateBuilderBase;
- using ArrayBuilder = ConstantArrayBuilder;
- using StructBuilder = ConstantStructBuilder;
- };
- /// The standard implementation of ConstantInitBuilder used in Clang.
- class ConstantInitBuilder
- : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> {
- public:
- explicit ConstantInitBuilder(CodeGenModule &CGM) :
- ConstantInitBuilderTemplateBase(CGM) {}
- };
- /// A helper class of ConstantInitBuilder, used for building constant
- /// array initializers.
- class ConstantArrayBuilder
- : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> {
- template <class Traits>
- friend class ConstantInitBuilderTemplateBase;
- // The use of explicit qualification is a GCC workaround.
- template <class Impl, class Traits>
- friend class CodeGen::ConstantAggregateBuilderTemplateBase;
- ConstantArrayBuilder(ConstantInitBuilder &builder,
- ConstantAggregateBuilderBase *parent,
- llvm::Type *eltTy)
- : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {}
- };
- /// A helper class of ConstantInitBuilder, used for building constant
- /// struct initializers.
- class ConstantStructBuilder
- : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> {
- template <class Traits>
- friend class ConstantInitBuilderTemplateBase;
- // The use of explicit qualification is a GCC workaround.
- template <class Impl, class Traits>
- friend class CodeGen::ConstantAggregateBuilderTemplateBase;
- ConstantStructBuilder(ConstantInitBuilder &builder,
- ConstantAggregateBuilderBase *parent,
- llvm::StructType *structTy)
- : ConstantStructBuilderTemplateBase(builder, parent, structTy) {}
- };
- } // end namespace CodeGen
- } // end namespace clang
- #endif
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|