summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h')
-rw-r--r--contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h444
1 files changed, 444 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h b/contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h
new file mode 100644
index 0000000..40b34a9
--- /dev/null
+++ b/contrib/llvm/tools/clang/lib/CodeGen/ConstantBuilder.h
@@ -0,0 +1,444 @@
+//===----- ConstantBuilder.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.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CODEGEN_CONSTANTBUILDER_H
+#define LLVM_CLANG_LIB_CODEGEN_CONSTANTBUILDER_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Constants.h"
+
+#include "CodeGenModule.h"
+
+#include <vector>
+
+namespace clang {
+namespace CodeGen {
+
+class ConstantStructBuilder;
+class ConstantArrayBuilder;
+
+/// 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()));
+/// widgetArray.add(widgetDesc.finish());
+/// }
+/// toplevel.add(widgetArray.finish());
+/// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align,
+/// /*constant*/ true);
+class ConstantInitBuilder {
+ 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;
+
+public:
+ explicit ConstantInitBuilder(CodeGenModule &CGM) : CGM(CGM) {}
+
+ ~ConstantInitBuilder() {
+ assert(Buffer.empty() && "didn't claim all values out of buffer");
+ }
+
+ class AggregateBuilderBase {
+ protected:
+ ConstantInitBuilder &Builder;
+ AggregateBuilderBase *Parent;
+ size_t Begin;
+ bool Finished = false;
+ bool Frozen = false;
+
+ llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() {
+ return Builder.Buffer;
+ }
+
+ const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const {
+ return Builder.Buffer;
+ }
+
+ AggregateBuilderBase(ConstantInitBuilder &builder,
+ AggregateBuilderBase *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;
+ }
+ }
+
+ ~AggregateBuilderBase() {
+ 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.
+ AggregateBuilderBase(const AggregateBuilderBase &) = delete;
+ AggregateBuilderBase &operator=(const AggregateBuilderBase &) = delete;
+
+ // Movable, mostly to allow returning. But we have to write this out
+ // properly to satisfy the assert in the destructor.
+ AggregateBuilderBase(AggregateBuilderBase &&other)
+ : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin),
+ Finished(other.Finished), Frozen(other.Frozen) {
+ other.Finished = false;
+ }
+ AggregateBuilderBase &operator=(AggregateBuilderBase &&other) = delete;
+
+ /// Abandon this builder completely.
+ void abandon() {
+ markFinished();
+ auto &buffer = Builder.Buffer;
+ buffer.erase(buffer.begin() + Begin, buffer.end());
+ }
+
+ /// 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(Builder.CGM.getSize(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(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());
+ }
+
+ /// An opaque class to hold the abstract position of a placeholder.
+ class PlaceholderPosition {
+ size_t Index;
+ friend class AggregateBuilderBase;
+ 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;
+ }
+
+ /// 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) {
+ // Make a global variable. We will replace this with a GEP to this
+ // position after installing the initializer.
+ auto dummy =
+ new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
+ llvm::GlobalVariable::PrivateLinkage,
+ nullptr, "");
+ Builder.SelfReferences.emplace_back(dummy);
+ auto &entry = Builder.SelfReferences.back();
+ (void) getGEPIndicesToCurrentPosition(entry.Indices);
+ return dummy;
+ }
+
+ ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition(
+ llvm::SmallVectorImpl<llvm::Constant*> &indices) {
+ getGEPIndicesTo(indices, Builder.Buffer.size());
+ return indices;
+ }
+
+ ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr);
+ ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr);
+
+ private:
+ void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices,
+ size_t position) const {
+ // Recurse on the parent builder if present.
+ if (Parent) {
+ Parent->getGEPIndicesTo(indices, Begin);
+
+ // Otherwise, add an index to drill into the first level of pointer.
+ } else {
+ assert(indices.empty());
+ indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
+ }
+
+ assert(position >= Begin);
+ // We have to use i32 here because struct GEPs demand i32 indices.
+ // It's rather unlikely to matter in practice.
+ indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
+ position - Begin));
+ }
+ };
+
+ template <class Impl>
+ class AggregateBuilder : public AggregateBuilderBase {
+ protected:
+ AggregateBuilder(ConstantInitBuilder &builder,
+ AggregateBuilderBase *parent)
+ : AggregateBuilderBase(builder, parent) {}
+
+ Impl &asImpl() { return *static_cast<Impl*>(this); }
+
+ public:
+ /// 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(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(!Parent && "finishing non-root builder");
+ return 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(!Parent && "finishing non-root builder");
+ return Builder.setGlobalInitializer(global, asImpl().finishImpl());
+ }
+ };
+
+ ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr);
+
+ ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr);
+
+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) {
+ auto GV = new llvm::GlobalVariable(CGM.getModule(),
+ initializer->getType(),
+ constant,
+ linkage,
+ initializer,
+ name,
+ /*insert before*/ nullptr,
+ llvm::GlobalValue::NotThreadLocal,
+ addressSpace);
+ GV->setAlignment(alignment.getQuantity());
+ resolveSelfReferences(GV);
+ return GV;
+ }
+
+ void setGlobalInitializer(llvm::GlobalVariable *GV,
+ llvm::Constant *initializer) {
+ GV->setInitializer(initializer);
+ resolveSelfReferences(GV);
+ }
+
+ void resolveSelfReferences(llvm::GlobalVariable *GV) {
+ for (auto &entry : SelfReferences) {
+ llvm::Constant *resolvedReference =
+ llvm::ConstantExpr::getInBoundsGetElementPtr(
+ GV->getValueType(), GV, entry.Indices);
+ entry.Dummy->replaceAllUsesWith(resolvedReference);
+ entry.Dummy->eraseFromParent();
+ }
+ }
+};
+
+/// A helper class of ConstantInitBuilder, used for building constant
+/// array initializers.
+class ConstantArrayBuilder
+ : public ConstantInitBuilder::AggregateBuilder<ConstantArrayBuilder> {
+ llvm::Type *EltTy;
+ friend class ConstantInitBuilder;
+ template <class Impl> friend class ConstantInitBuilder::AggregateBuilder;
+ ConstantArrayBuilder(ConstantInitBuilder &builder,
+ AggregateBuilderBase *parent, llvm::Type *eltTy)
+ : AggregateBuilder(builder, parent), EltTy(eltTy) {}
+public:
+ size_t size() const {
+ assert(!Finished);
+ assert(!Frozen);
+ assert(Begin <= getBuffer().size());
+ return getBuffer().size() - Begin;
+ }
+
+ bool empty() const {
+ return size() == 0;
+ }
+
+private:
+ /// Form an array constant from the values that have been added to this
+ /// builder.
+ llvm::Constant *finishImpl() {
+ markFinished();
+
+ auto &buffer = getBuffer();
+ assert((Begin < buffer.size() ||
+ (Begin == buffer.size() && EltTy))
+ && "didn't add any array elements without element type");
+ auto elts = llvm::makeArrayRef(buffer).slice(Begin);
+ auto eltTy = EltTy ? EltTy : elts[0]->getType();
+ auto type = llvm::ArrayType::get(eltTy, elts.size());
+ auto constant = llvm::ConstantArray::get(type, elts);
+ buffer.erase(buffer.begin() + Begin, buffer.end());
+ return constant;
+ }
+};
+
+inline ConstantArrayBuilder
+ConstantInitBuilder::beginArray(llvm::Type *eltTy) {
+ return ConstantArrayBuilder(*this, nullptr, eltTy);
+}
+
+inline ConstantArrayBuilder
+ConstantInitBuilder::AggregateBuilderBase::beginArray(llvm::Type *eltTy) {
+ return ConstantArrayBuilder(Builder, this, eltTy);
+}
+
+/// A helper class of ConstantInitBuilder, used for building constant
+/// struct initializers.
+class ConstantStructBuilder
+ : public ConstantInitBuilder::AggregateBuilder<ConstantStructBuilder> {
+ llvm::StructType *Ty;
+ friend class ConstantInitBuilder;
+ template <class Impl> friend class ConstantInitBuilder::AggregateBuilder;
+ ConstantStructBuilder(ConstantInitBuilder &builder,
+ AggregateBuilderBase *parent, llvm::StructType *ty)
+ : AggregateBuilder(builder, parent), Ty(ty) {}
+
+ /// Finish the struct.
+ llvm::Constant *finishImpl() {
+ markFinished();
+
+ auto &buffer = getBuffer();
+ assert(Begin < buffer.size() && "didn't add any struct elements?");
+ auto elts = llvm::makeArrayRef(buffer).slice(Begin);
+
+ llvm::Constant *constant;
+ if (Ty) {
+ constant = llvm::ConstantStruct::get(Ty, elts);
+ } else {
+ constant = llvm::ConstantStruct::getAnon(elts, /*packed*/ false);
+ }
+
+ buffer.erase(buffer.begin() + Begin, buffer.end());
+ return constant;
+ }
+};
+
+inline ConstantStructBuilder
+ConstantInitBuilder::beginStruct(llvm::StructType *structTy) {
+ return ConstantStructBuilder(*this, nullptr, structTy);
+}
+
+inline ConstantStructBuilder
+ConstantInitBuilder::AggregateBuilderBase::beginStruct(
+ llvm::StructType *structTy) {
+ return ConstantStructBuilder(Builder, this, structTy);
+}
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
OpenPOWER on IntegriCloud