From: John McCall Date: Sat, 4 Mar 2017 21:26:29 +0000 (+0000) Subject: Refactor ConstantInitBuilder to allow other frontends to more X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=03662f351adb31104fca74d0aea51c48108299b8;p=clang Refactor ConstantInitBuilder to allow other frontends to more easily extend the aggregate-builder API. Stupid missing language features. Also add APIs for constructing a relative reference and computing the offset of a position from the start of the initializer. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@296979 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/CodeGen/ConstantInitBuilder.h b/include/clang/CodeGen/ConstantInitBuilder.h index 5c1a8d3ca4..3e183e6f85 100644 --- a/include/clang/CodeGen/ConstantInitBuilder.h +++ b/include/clang/CodeGen/ConstantInitBuilder.h @@ -28,8 +28,6 @@ namespace clang { namespace CodeGen { class CodeGenModule; -class ConstantStructBuilder; -class ConstantArrayBuilder; /// A convenience builder class for complex constant initializers, /// especially for anonymous global structures used by various language @@ -45,12 +43,12 @@ class ConstantArrayBuilder; /// widgetDesc.addInt(CGM.SizeTy, widget.getPower()); /// widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName())); /// widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl())); -/// widgetArray.add(widgetDesc.finish()); +/// widgetDesc.finishAndAddTo(widgetArray); /// } -/// toplevel.add(widgetArray.finish()); +/// widgetArray.finishAndAddTo(toplevel); /// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align, /// /*constant*/ true); -class ConstantInitBuilder { +class ConstantInitBuilderBase { struct SelfReference { llvm::GlobalVariable *Dummy; llvm::SmallVector Indices; @@ -62,254 +60,331 @@ class ConstantInitBuilder { std::vector SelfReferences; bool Frozen = false; -public: - explicit ConstantInitBuilder(CodeGenModule &CGM) : CGM(CGM) {} + friend class ConstantAggregateBuilderBase; + template + friend class ConstantAggregateBuilderTemplateBase; + + // The rule for CachedOffset is that anything which removes elements + // from the Buffer + +protected: + explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {} - ~ConstantInitBuilder() { + ~ConstantInitBuilderBase() { 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; +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); - llvm::SmallVectorImpl &getBuffer() { - return Builder.Buffer; - } + void setGlobalInitializer(llvm::GlobalVariable *GV, + llvm::Constant *initializer); - const llvm::SmallVectorImpl &getBuffer() const { - return Builder.Buffer; - } + void resolveSelfReferences(llvm::GlobalVariable *GV); +}; - 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; - } - } +/// 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; + mutable CharUnits CachedOffsetFromGlobal; - ~AggregateBuilderBase() { - assert(Finished && "didn't finish aggregate builder"); - } + llvm::SmallVectorImpl &getBuffer() { + return Builder.Buffer; + } - 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; - } - } + const llvm::SmallVectorImpl &getBuffer() const { + return Builder.Buffer; + } - 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; + 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; } - AggregateBuilderBase &operator=(AggregateBuilderBase &&other) = delete; + } - /// Abandon this builder completely. - void abandon() { - markFinished(); - auto &buffer = Builder.Buffer; - buffer.erase(buffer.begin() + Begin, buffer.end()); - } + ~ConstantAggregateBuilderBase() { + assert(Finished && "didn't finish aggregate builder"); + } - /// 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); + 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; } + } - /// Add an integer value of type size_t. - void addSize(CharUnits size); +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), + Finished(other.Finished), Frozen(other.Frozen) { + other.Finished = true; + } + ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other) + = delete; + + /// Abandon this builder completely. + void abandon() { + markFinished(); + auto &buffer = Builder.Buffer; + buffer.erase(buffer.begin() + Begin, buffer.end()); + } - /// 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 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 a null pointer of a specific type. - void addNullPointer(llvm::PointerType *ptrTy) { - add(llvm::ConstantPointerNull::get(ptrTy)); - } + /// Add an integer value of type size_t. + void addSize(CharUnits size); - /// 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 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 bunch of new values to this initializer. - void addAll(llvm::ArrayRef 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 null pointer of a specific type. + void addNullPointer(llvm::PointerType *ptrTy) { + add(llvm::ConstantPointerNull::get(ptrTy)); + } - /// 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; - } + /// Add a bitcast of a value to a specific type. + void addBitCast(llvm::Constant *value, llvm::Type *type) { + add(llvm::ConstantExpr::getBitCast(value, type)); + } - /// 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)); - } + /// Add a bunch of new values to this initializer. + void addAll(llvm::ArrayRef 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()); + } - /// 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; - } + /// 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)); + } - /// 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 getGEPIndicesToCurrentPosition( - llvm::SmallVectorImpl &indices) { - getGEPIndicesTo(indices, Builder.Buffer.size()); - return indices; + /// 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); + } - ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr); - ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr); + /// Return the offset from the start of the initializer to the + /// next position, assuming no padding is required prior to it. + 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()); + } - private: - void getGEPIndicesTo(llvm::SmallVectorImpl &indices, - size_t position) const; + /// 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) {} }; - template - class AggregateBuilder : public AggregateBuilderBase { - protected: - AggregateBuilder(ConstantInitBuilder &builder, - AggregateBuilderBase *parent) - : AggregateBuilderBase(builder, parent) {} - - Impl &asImpl() { return *static_cast(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()); - } + /// 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; + } - /// 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 - llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) { - assert(!Parent && "finishing non-root builder"); - return Builder.createGlobal(asImpl().finishImpl(), - std::forward(args)...); - } + /// 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)); + } - /// 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()); - } - }; + /// 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; + } - ConstantArrayBuilder beginArray(llvm::Type *eltTy = nullptr); + /// 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 getGEPIndicesToCurrentPosition( + llvm::SmallVectorImpl &indices) { + getGEPIndicesTo(indices, Builder.Buffer.size()); + return indices; + } - ConstantStructBuilder beginStruct(llvm::StructType *structTy = nullptr); +protected: + llvm::Constant *finishArray(llvm::Type *eltTy); + llvm::Constant *finishStruct(llvm::StructType *structTy); 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); + void getGEPIndicesTo(llvm::SmallVectorImpl &indices, + size_t position) const; - void setGlobalInitializer(llvm::GlobalVariable *GV, - llvm::Constant *initializer); + llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType, + llvm::Constant *target); - void resolveSelfReferences(llvm::GlobalVariable *GV); + CharUnits getOffsetFromGlobalTo(size_t index) const; }; -/// A helper class of ConstantInitBuilder, used for building constant -/// array initializers. -class ConstantArrayBuilder - : public ConstantInitBuilder::AggregateBuilder { +template +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(this); } + +public: + ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { + return ArrayBuilder(static_cast(this->Builder), this, eltTy); + } + + StructBuilder beginStruct(llvm::StructType *ty = nullptr) { + return StructBuilder(static_cast(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 + llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) { + assert(!this->Parent && "finishing non-root builder"); + return this->Builder.createGlobal(asImpl().finishImpl(), + std::forward(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()); + } +}; + +template +class ConstantArrayBuilderTemplateBase + : public ConstantAggregateBuilderTemplateBase { + using super = + ConstantAggregateBuilderTemplateBase; + +public: + using InitBuilder = typename Traits::InitBuilder; + using AggregateBuilderBase = typename Traits::AggregateBuilderBase; + +private: llvm::Type *EltTy; - friend class ConstantInitBuilder; - template friend class ConstantInitBuilder::AggregateBuilder; - ConstantArrayBuilder(ConstantInitBuilder &builder, - AggregateBuilderBase *parent, llvm::Type *eltTy) - : AggregateBuilder(builder, parent), EltTy(eltTy) {} + + template + friend class ConstantAggregateBuilderTemplateBase; + +protected: + ConstantArrayBuilderTemplateBase(InitBuilder &builder, + AggregateBuilderBase *parent, + llvm::Type *eltTy) + : super(builder, parent), EltTy(eltTy) {} + public: size_t size() const { - assert(!Finished); - assert(!Frozen); - assert(Begin <= getBuffer().size()); - return getBuffer().size() - Begin; + 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; } bool empty() const { @@ -319,44 +394,120 @@ public: private: /// Form an array constant from the values that have been added to this /// builder. - llvm::Constant *finishImpl(); + llvm::Constant *finishImpl() { + return AggregateBuilderBase::finishArray(EltTy); + } }; -inline ConstantArrayBuilder -ConstantInitBuilder::beginArray(llvm::Type *eltTy) { - return ConstantArrayBuilder(*this, nullptr, 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 ConstantStructBuilderTemplateBase + : public ConstantAggregateBuilderTemplateBase { + using super = + ConstantAggregateBuilderTemplateBase; + +public: + using InitBuilder = typename Traits::InitBuilder; + using AggregateBuilderBase = typename Traits::AggregateBuilderBase; + +private: + llvm::StructType *StructTy; + + template + friend class ConstantAggregateBuilderTemplateBase; -inline ConstantArrayBuilder -ConstantInitBuilder::AggregateBuilderBase::beginArray(llvm::Type *eltTy) { - return ConstantArrayBuilder(Builder, this, eltTy); -} +protected: + ConstantStructBuilderTemplateBase(InitBuilder &builder, + AggregateBuilderBase *parent, + llvm::StructType *structTy) + : super(builder, parent), 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 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(*this), nullptr, eltTy); + } + + StructBuilder beginStruct(llvm::StructType *structTy = nullptr) { + return StructBuilder(static_cast(*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 { +public: + explicit ConstantInitBuilder(CodeGenModule &CGM) : + ConstantInitBuilderTemplateBase(CGM) {} +}; /// A helper class of ConstantInitBuilder, used for building constant -/// struct initializers. -class ConstantStructBuilder - : public ConstantInitBuilder::AggregateBuilder { - llvm::StructType *Ty; - friend class ConstantInitBuilder; - template friend class ConstantInitBuilder::AggregateBuilder; - ConstantStructBuilder(ConstantInitBuilder &builder, - AggregateBuilderBase *parent, llvm::StructType *ty) - : AggregateBuilder(builder, parent), Ty(ty) {} +/// array initializers. +class ConstantArrayBuilder + : public ConstantArrayBuilderTemplateBase { + template + friend class ConstantInitBuilderTemplateBase; + template + friend class ConstantAggregateBuilderTemplateBase; - /// Finish the struct. - llvm::Constant *finishImpl(); + ConstantArrayBuilder(ConstantInitBuilder &builder, + ConstantAggregateBuilderBase *parent, + llvm::Type *eltTy) + : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {} }; -inline ConstantStructBuilder -ConstantInitBuilder::beginStruct(llvm::StructType *structTy) { - return ConstantStructBuilder(*this, nullptr, structTy); -} +/// A helper class of ConstantInitBuilder, used for building constant +/// struct initializers. +class ConstantStructBuilder + : public ConstantStructBuilderTemplateBase { + template + friend class ConstantInitBuilderTemplateBase; + template + friend class ConstantAggregateBuilderTemplateBase; -inline ConstantStructBuilder -ConstantInitBuilder::AggregateBuilderBase::beginStruct( - llvm::StructType *structTy) { - return ConstantStructBuilder(Builder, this, structTy); -} + ConstantStructBuilder(ConstantInitBuilder &builder, + ConstantAggregateBuilderBase *parent, + llvm::StructType *structTy) + : ConstantStructBuilderTemplateBase(builder, parent, structTy) {} +}; } // end namespace CodeGen } // end namespace clang diff --git a/lib/CodeGen/ConstantInitBuilder.cpp b/lib/CodeGen/ConstantInitBuilder.cpp index 772391e77d..d1a707b323 100644 --- a/lib/CodeGen/ConstantInitBuilder.cpp +++ b/lib/CodeGen/ConstantInitBuilder.cpp @@ -20,12 +20,12 @@ using namespace clang; using namespace CodeGen; llvm::GlobalVariable * -ConstantInitBuilder::createGlobal(llvm::Constant *initializer, - const llvm::Twine &name, - CharUnits alignment, - bool constant, - llvm::GlobalValue::LinkageTypes linkage, - unsigned addressSpace) { +ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer, + const llvm::Twine &name, + CharUnits alignment, + bool constant, + llvm::GlobalValue::LinkageTypes linkage, + unsigned addressSpace) { auto GV = new llvm::GlobalVariable(CGM.getModule(), initializer->getType(), constant, @@ -40,15 +40,15 @@ ConstantInitBuilder::createGlobal(llvm::Constant *initializer, return GV; } -void ConstantInitBuilder::setGlobalInitializer(llvm::GlobalVariable *GV, - llvm::Constant *initializer) { +void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV, + llvm::Constant *initializer){ GV->setInitializer(initializer); if (!SelfReferences.empty()) resolveSelfReferences(GV); } -void ConstantInitBuilder::resolveSelfReferences(llvm::GlobalVariable *GV) { +void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) { for (auto &entry : SelfReferences) { llvm::Constant *resolvedReference = llvm::ConstantExpr::getInBoundsGetElementPtr( @@ -58,13 +58,31 @@ void ConstantInitBuilder::resolveSelfReferences(llvm::GlobalVariable *GV) { } } -void ConstantInitBuilder::AggregateBuilderBase::addSize(CharUnits size) { +void ConstantAggregateBuilderBase::addSize(CharUnits size) { add(Builder.CGM.getSize(size)); } llvm::Constant * -ConstantInitBuilder::AggregateBuilderBase::getAddrOfCurrentPosition( - llvm::Type *type) { +ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType, + llvm::Constant *target) { + // Compute the address of the relative-address slot. + auto base = getAddrOfCurrentPosition(offsetType); + + // Subtract. + base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy); + target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy); + llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base); + + // Truncate to the relative-address type if necessary. + if (Builder.CGM.IntPtrTy != offsetType) { + offset = llvm::ConstantExpr::getTrunc(offset, offsetType); + } + + return offset; +} + +llvm::Constant * +ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) { // Make a global variable. We will replace this with a GEP to this // position after installing the initializer. auto dummy = @@ -77,7 +95,7 @@ ConstantInitBuilder::AggregateBuilderBase::getAddrOfCurrentPosition( return dummy; } -void ConstantInitBuilder::AggregateBuilderBase::getGEPIndicesTo( +void ConstantAggregateBuilderBase::getGEPIndicesTo( llvm::SmallVectorImpl &indices, size_t position) const { // Recurse on the parent builder if present. @@ -97,22 +115,64 @@ void ConstantInitBuilder::AggregateBuilderBase::getGEPIndicesTo( position - Begin)); } -llvm::Constant *ConstantArrayBuilder::finishImpl() { +CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{ + size_t cacheEnd = CachedOffsetEnd; + assert(cacheEnd <= end); + + // Fast path: if the cache is valid, just use it. + if (cacheEnd == end) { + return CachedOffsetFromGlobal; + } + + // If the cached range ends before the index at which the current + // aggregate starts, recurse for the parent. + CharUnits offset; + if (cacheEnd < Begin) { + assert(cacheEnd == 0); + assert(Parent && "Begin != 0 for root builder"); + cacheEnd = Begin; + offset = Parent->getOffsetFromGlobalTo(Begin); + } else { + offset = CachedOffsetFromGlobal; + } + + // Perform simple layout on the elements in cacheEnd..getType(); + offset = offset.alignTo(CharUnits::fromQuantity( + layout.getABITypeAlignment(elementType))); + offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType)); + } while (++cacheEnd != end); + } + + // Cache and return. + CachedOffsetEnd = cacheEnd; + CachedOffsetFromGlobal = offset; + return offset; +} + +llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) { markFinished(); auto &buffer = getBuffer(); assert((Begin < buffer.size() || - (Begin == buffer.size() && EltTy)) + (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(); + if (!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; } -llvm::Constant *ConstantStructBuilder::finishImpl() { +llvm::Constant * +ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) { markFinished(); auto &buffer = getBuffer(); @@ -120,8 +180,8 @@ llvm::Constant *ConstantStructBuilder::finishImpl() { auto elts = llvm::makeArrayRef(buffer).slice(Begin); llvm::Constant *constant; - if (Ty) { - constant = llvm::ConstantStruct::get(Ty, elts); + if (ty) { + constant = llvm::ConstantStruct::get(ty, elts); } else { constant = llvm::ConstantStruct::getAnon(elts, /*packed*/ false); }