aboutsummaryrefslogtreecommitdiff
path: root/include/clang/CodeGen/ConstantInitBuilder.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/CodeGen/ConstantInitBuilder.h')
-rw-r--r--include/clang/CodeGen/ConstantInitBuilder.h561
1 files changed, 561 insertions, 0 deletions
diff --git a/include/clang/CodeGen/ConstantInitBuilder.h b/include/clang/CodeGen/ConstantInitBuilder.h
new file mode 100644
index 000000000000..113d86d82c10
--- /dev/null
+++ b/include/clang/CodeGen/ConstantInitBuilder.h
@@ -0,0 +1,561 @@
+//===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// 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));
+ }
+
+ /// 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, generaly 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 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
+ /// position.
+ llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type);
+
+ 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);
+
+ 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