1e5dd7070Spatrick //===- ConstantInitBuilder.h - Builder for LLVM IR constants ----*- C++ -*-===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e5dd7070Spatrick // 7e5dd7070Spatrick //===----------------------------------------------------------------------===// 8e5dd7070Spatrick // 9e5dd7070Spatrick // This class provides a convenient interface for building complex 10e5dd7070Spatrick // global initializers of the sort that are frequently required for 11e5dd7070Spatrick // language ABIs. 12e5dd7070Spatrick // 13e5dd7070Spatrick //===----------------------------------------------------------------------===// 14e5dd7070Spatrick 15e5dd7070Spatrick #ifndef LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H 16e5dd7070Spatrick #define LLVM_CLANG_CODEGEN_CONSTANTINITBUILDER_H 17e5dd7070Spatrick 18e5dd7070Spatrick #include "llvm/ADT/ArrayRef.h" 19e5dd7070Spatrick #include "llvm/ADT/SmallVector.h" 20e5dd7070Spatrick #include "llvm/IR/Constants.h" 21e5dd7070Spatrick #include "llvm/IR/GlobalValue.h" 22e5dd7070Spatrick #include "clang/AST/CharUnits.h" 23e5dd7070Spatrick #include "clang/CodeGen/ConstantInitFuture.h" 24e5dd7070Spatrick 25e5dd7070Spatrick #include <vector> 26e5dd7070Spatrick 27e5dd7070Spatrick namespace clang { 28e5dd7070Spatrick namespace CodeGen { 29e5dd7070Spatrick 30e5dd7070Spatrick class CodeGenModule; 31e5dd7070Spatrick 32e5dd7070Spatrick /// A convenience builder class for complex constant initializers, 33e5dd7070Spatrick /// especially for anonymous global structures used by various language 34e5dd7070Spatrick /// runtimes. 35e5dd7070Spatrick /// 36e5dd7070Spatrick /// The basic usage pattern is expected to be something like: 37e5dd7070Spatrick /// ConstantInitBuilder builder(CGM); 38e5dd7070Spatrick /// auto toplevel = builder.beginStruct(); 39e5dd7070Spatrick /// toplevel.addInt(CGM.SizeTy, widgets.size()); 40e5dd7070Spatrick /// auto widgetArray = builder.beginArray(); 41e5dd7070Spatrick /// for (auto &widget : widgets) { 42e5dd7070Spatrick /// auto widgetDesc = widgetArray.beginStruct(); 43e5dd7070Spatrick /// widgetDesc.addInt(CGM.SizeTy, widget.getPower()); 44e5dd7070Spatrick /// widgetDesc.add(CGM.GetAddrOfConstantString(widget.getName())); 45e5dd7070Spatrick /// widgetDesc.add(CGM.GetAddrOfGlobal(widget.getInitializerDecl())); 46e5dd7070Spatrick /// widgetDesc.finishAndAddTo(widgetArray); 47e5dd7070Spatrick /// } 48e5dd7070Spatrick /// widgetArray.finishAndAddTo(toplevel); 49e5dd7070Spatrick /// auto global = toplevel.finishAndCreateGlobal("WIDGET_LIST", Align, 50e5dd7070Spatrick /// /*constant*/ true); 51e5dd7070Spatrick class ConstantInitBuilderBase { 52e5dd7070Spatrick struct SelfReference { 53e5dd7070Spatrick llvm::GlobalVariable *Dummy; 54e5dd7070Spatrick llvm::SmallVector<llvm::Constant*, 4> Indices; 55e5dd7070Spatrick SelfReferenceSelfReference56e5dd7070Spatrick SelfReference(llvm::GlobalVariable *dummy) : Dummy(dummy) {} 57e5dd7070Spatrick }; 58e5dd7070Spatrick CodeGenModule &CGM; 59e5dd7070Spatrick llvm::SmallVector<llvm::Constant*, 16> Buffer; 60e5dd7070Spatrick std::vector<SelfReference> SelfReferences; 61e5dd7070Spatrick bool Frozen = false; 62e5dd7070Spatrick 63e5dd7070Spatrick friend class ConstantInitFuture; 64e5dd7070Spatrick friend class ConstantAggregateBuilderBase; 65e5dd7070Spatrick template <class, class> 66e5dd7070Spatrick friend class ConstantAggregateBuilderTemplateBase; 67e5dd7070Spatrick 68e5dd7070Spatrick protected: ConstantInitBuilderBase(CodeGenModule & CGM)69e5dd7070Spatrick explicit ConstantInitBuilderBase(CodeGenModule &CGM) : CGM(CGM) {} 70e5dd7070Spatrick ~ConstantInitBuilderBase()71e5dd7070Spatrick ~ConstantInitBuilderBase() { 72e5dd7070Spatrick assert(Buffer.empty() && "didn't claim all values out of buffer"); 73e5dd7070Spatrick assert(SelfReferences.empty() && "didn't apply all self-references"); 74e5dd7070Spatrick } 75e5dd7070Spatrick 76e5dd7070Spatrick private: 77e5dd7070Spatrick llvm::GlobalVariable *createGlobal(llvm::Constant *initializer, 78e5dd7070Spatrick const llvm::Twine &name, 79e5dd7070Spatrick CharUnits alignment, 80e5dd7070Spatrick bool constant = false, 81e5dd7070Spatrick llvm::GlobalValue::LinkageTypes linkage 82e5dd7070Spatrick = llvm::GlobalValue::InternalLinkage, 83e5dd7070Spatrick unsigned addressSpace = 0); 84e5dd7070Spatrick 85e5dd7070Spatrick ConstantInitFuture createFuture(llvm::Constant *initializer); 86e5dd7070Spatrick 87e5dd7070Spatrick void setGlobalInitializer(llvm::GlobalVariable *GV, 88e5dd7070Spatrick llvm::Constant *initializer); 89e5dd7070Spatrick 90e5dd7070Spatrick void resolveSelfReferences(llvm::GlobalVariable *GV); 91e5dd7070Spatrick 92e5dd7070Spatrick void abandon(size_t newEnd); 93e5dd7070Spatrick }; 94e5dd7070Spatrick 95e5dd7070Spatrick /// A concrete base class for struct and array aggregate 96e5dd7070Spatrick /// initializer builders. 97e5dd7070Spatrick class ConstantAggregateBuilderBase { 98e5dd7070Spatrick protected: 99e5dd7070Spatrick ConstantInitBuilderBase &Builder; 100e5dd7070Spatrick ConstantAggregateBuilderBase *Parent; 101e5dd7070Spatrick size_t Begin; 102e5dd7070Spatrick mutable size_t CachedOffsetEnd = 0; 103e5dd7070Spatrick bool Finished = false; 104e5dd7070Spatrick bool Frozen = false; 105e5dd7070Spatrick bool Packed = false; 106e5dd7070Spatrick mutable CharUnits CachedOffsetFromGlobal; 107e5dd7070Spatrick getBuffer()108e5dd7070Spatrick llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() { 109e5dd7070Spatrick return Builder.Buffer; 110e5dd7070Spatrick } 111e5dd7070Spatrick getBuffer()112e5dd7070Spatrick const llvm::SmallVectorImpl<llvm::Constant*> &getBuffer() const { 113e5dd7070Spatrick return Builder.Buffer; 114e5dd7070Spatrick } 115e5dd7070Spatrick ConstantAggregateBuilderBase(ConstantInitBuilderBase & builder,ConstantAggregateBuilderBase * parent)116e5dd7070Spatrick ConstantAggregateBuilderBase(ConstantInitBuilderBase &builder, 117e5dd7070Spatrick ConstantAggregateBuilderBase *parent) 118e5dd7070Spatrick : Builder(builder), Parent(parent), Begin(builder.Buffer.size()) { 119e5dd7070Spatrick if (parent) { 120e5dd7070Spatrick assert(!parent->Frozen && "parent already has child builder active"); 121e5dd7070Spatrick parent->Frozen = true; 122e5dd7070Spatrick } else { 123e5dd7070Spatrick assert(!builder.Frozen && "builder already has child builder active"); 124e5dd7070Spatrick builder.Frozen = true; 125e5dd7070Spatrick } 126e5dd7070Spatrick } 127e5dd7070Spatrick ~ConstantAggregateBuilderBase()128e5dd7070Spatrick ~ConstantAggregateBuilderBase() { 129e5dd7070Spatrick assert(Finished && "didn't finish aggregate builder"); 130e5dd7070Spatrick } 131e5dd7070Spatrick markFinished()132e5dd7070Spatrick void markFinished() { 133e5dd7070Spatrick assert(!Frozen && "child builder still active"); 134e5dd7070Spatrick assert(!Finished && "builder already finished"); 135e5dd7070Spatrick Finished = true; 136e5dd7070Spatrick if (Parent) { 137e5dd7070Spatrick assert(Parent->Frozen && 138e5dd7070Spatrick "parent not frozen while child builder active"); 139e5dd7070Spatrick Parent->Frozen = false; 140e5dd7070Spatrick } else { 141e5dd7070Spatrick assert(Builder.Frozen && 142e5dd7070Spatrick "builder not frozen while child builder active"); 143e5dd7070Spatrick Builder.Frozen = false; 144e5dd7070Spatrick } 145e5dd7070Spatrick } 146e5dd7070Spatrick 147e5dd7070Spatrick public: 148e5dd7070Spatrick // Not copyable. 149e5dd7070Spatrick ConstantAggregateBuilderBase(const ConstantAggregateBuilderBase &) = delete; 150e5dd7070Spatrick ConstantAggregateBuilderBase &operator=(const ConstantAggregateBuilderBase &) 151e5dd7070Spatrick = delete; 152e5dd7070Spatrick 153e5dd7070Spatrick // Movable, mostly to allow returning. But we have to write this out 154e5dd7070Spatrick // properly to satisfy the assert in the destructor. ConstantAggregateBuilderBase(ConstantAggregateBuilderBase && other)155e5dd7070Spatrick ConstantAggregateBuilderBase(ConstantAggregateBuilderBase &&other) 156e5dd7070Spatrick : Builder(other.Builder), Parent(other.Parent), Begin(other.Begin), 157e5dd7070Spatrick CachedOffsetEnd(other.CachedOffsetEnd), 158e5dd7070Spatrick Finished(other.Finished), Frozen(other.Frozen), Packed(other.Packed), 159e5dd7070Spatrick CachedOffsetFromGlobal(other.CachedOffsetFromGlobal) { 160e5dd7070Spatrick other.Finished = true; 161e5dd7070Spatrick } 162e5dd7070Spatrick ConstantAggregateBuilderBase &operator=(ConstantAggregateBuilderBase &&other) 163e5dd7070Spatrick = delete; 164e5dd7070Spatrick 165e5dd7070Spatrick /// Return the number of elements that have been added to 166e5dd7070Spatrick /// this struct or array. size()167e5dd7070Spatrick size_t size() const { 168e5dd7070Spatrick assert(!this->Finished && "cannot query after finishing builder"); 169e5dd7070Spatrick assert(!this->Frozen && "cannot query while sub-builder is active"); 170e5dd7070Spatrick assert(this->Begin <= this->getBuffer().size()); 171e5dd7070Spatrick return this->getBuffer().size() - this->Begin; 172e5dd7070Spatrick } 173e5dd7070Spatrick 174e5dd7070Spatrick /// Return true if no elements have yet been added to this struct or array. empty()175e5dd7070Spatrick bool empty() const { 176e5dd7070Spatrick return size() == 0; 177e5dd7070Spatrick } 178e5dd7070Spatrick 179e5dd7070Spatrick /// Abandon this builder completely. abandon()180e5dd7070Spatrick void abandon() { 181e5dd7070Spatrick markFinished(); 182e5dd7070Spatrick Builder.abandon(Begin); 183e5dd7070Spatrick } 184e5dd7070Spatrick 185e5dd7070Spatrick /// Add a new value to this initializer. add(llvm::Constant * value)186e5dd7070Spatrick void add(llvm::Constant *value) { 187e5dd7070Spatrick assert(value && "adding null value to constant initializer"); 188e5dd7070Spatrick assert(!Finished && "cannot add more values after finishing builder"); 189e5dd7070Spatrick assert(!Frozen && "cannot add values while subbuilder is active"); 190e5dd7070Spatrick Builder.Buffer.push_back(value); 191e5dd7070Spatrick } 192e5dd7070Spatrick 193e5dd7070Spatrick /// Add an integer value of type size_t. 194e5dd7070Spatrick void addSize(CharUnits size); 195e5dd7070Spatrick 196e5dd7070Spatrick /// Add an integer value of a specific type. 197e5dd7070Spatrick void addInt(llvm::IntegerType *intTy, uint64_t value, 198e5dd7070Spatrick bool isSigned = false) { 199e5dd7070Spatrick add(llvm::ConstantInt::get(intTy, value, isSigned)); 200e5dd7070Spatrick } 201e5dd7070Spatrick 202e5dd7070Spatrick /// Add a null pointer of a specific type. addNullPointer(llvm::PointerType * ptrTy)203e5dd7070Spatrick void addNullPointer(llvm::PointerType *ptrTy) { 204e5dd7070Spatrick add(llvm::ConstantPointerNull::get(ptrTy)); 205e5dd7070Spatrick } 206e5dd7070Spatrick 207e5dd7070Spatrick /// Add a bitcast of a value to a specific type. addBitCast(llvm::Constant * value,llvm::Type * type)208e5dd7070Spatrick void addBitCast(llvm::Constant *value, llvm::Type *type) { 209e5dd7070Spatrick add(llvm::ConstantExpr::getBitCast(value, type)); 210e5dd7070Spatrick } 211e5dd7070Spatrick 212e5dd7070Spatrick /// Add a bunch of new values to this initializer. addAll(llvm::ArrayRef<llvm::Constant * > values)213e5dd7070Spatrick void addAll(llvm::ArrayRef<llvm::Constant *> values) { 214e5dd7070Spatrick assert(!Finished && "cannot add more values after finishing builder"); 215e5dd7070Spatrick assert(!Frozen && "cannot add values while subbuilder is active"); 216e5dd7070Spatrick Builder.Buffer.append(values.begin(), values.end()); 217e5dd7070Spatrick } 218e5dd7070Spatrick 219e5dd7070Spatrick /// Add a relative offset to the given target address, i.e. the 220e5dd7070Spatrick /// static difference between the target address and the address 221e5dd7070Spatrick /// of the relative offset. The target must be known to be defined 222e5dd7070Spatrick /// in the current linkage unit. The offset will have the given 223e5dd7070Spatrick /// integer type, which must be no wider than intptr_t. Some 224e5dd7070Spatrick /// targets may not fully support this operation. addRelativeOffset(llvm::IntegerType * type,llvm::Constant * target)225e5dd7070Spatrick void addRelativeOffset(llvm::IntegerType *type, llvm::Constant *target) { 226e5dd7070Spatrick add(getRelativeOffset(type, target)); 227e5dd7070Spatrick } 228e5dd7070Spatrick 229*ec727ea7Spatrick /// Same as addRelativeOffset(), but instead relative to an element in this 230*ec727ea7Spatrick /// aggregate, identified by its index. addRelativeOffsetToPosition(llvm::IntegerType * type,llvm::Constant * target,size_t position)231*ec727ea7Spatrick void addRelativeOffsetToPosition(llvm::IntegerType *type, 232*ec727ea7Spatrick llvm::Constant *target, size_t position) { 233*ec727ea7Spatrick add(getRelativeOffsetToPosition(type, target, position)); 234*ec727ea7Spatrick } 235*ec727ea7Spatrick 236e5dd7070Spatrick /// Add a relative offset to the target address, plus a small 237e5dd7070Spatrick /// constant offset. This is primarily useful when the relative 238e5dd7070Spatrick /// offset is known to be a multiple of (say) four and therefore 239e5dd7070Spatrick /// the tag can be used to express an extra two bits of information. addTaggedRelativeOffset(llvm::IntegerType * type,llvm::Constant * address,unsigned tag)240e5dd7070Spatrick void addTaggedRelativeOffset(llvm::IntegerType *type, 241e5dd7070Spatrick llvm::Constant *address, 242e5dd7070Spatrick unsigned tag) { 243e5dd7070Spatrick llvm::Constant *offset = getRelativeOffset(type, address); 244e5dd7070Spatrick if (tag) { 245e5dd7070Spatrick offset = llvm::ConstantExpr::getAdd(offset, 246e5dd7070Spatrick llvm::ConstantInt::get(type, tag)); 247e5dd7070Spatrick } 248e5dd7070Spatrick add(offset); 249e5dd7070Spatrick } 250e5dd7070Spatrick 251e5dd7070Spatrick /// Return the offset from the start of the initializer to the 252e5dd7070Spatrick /// next position, assuming no padding is required prior to it. 253e5dd7070Spatrick /// 254e5dd7070Spatrick /// This operation will not succeed if any unsized placeholders are 255e5dd7070Spatrick /// currently in place in the initializer. getNextOffsetFromGlobal()256e5dd7070Spatrick CharUnits getNextOffsetFromGlobal() const { 257e5dd7070Spatrick assert(!Finished && "cannot add more values after finishing builder"); 258e5dd7070Spatrick assert(!Frozen && "cannot add values while subbuilder is active"); 259e5dd7070Spatrick return getOffsetFromGlobalTo(Builder.Buffer.size()); 260e5dd7070Spatrick } 261e5dd7070Spatrick 262e5dd7070Spatrick /// An opaque class to hold the abstract position of a placeholder. 263e5dd7070Spatrick class PlaceholderPosition { 264e5dd7070Spatrick size_t Index; 265e5dd7070Spatrick friend class ConstantAggregateBuilderBase; PlaceholderPosition(size_t index)266e5dd7070Spatrick PlaceholderPosition(size_t index) : Index(index) {} 267e5dd7070Spatrick }; 268e5dd7070Spatrick 269e5dd7070Spatrick /// Add a placeholder value to the structure. The returned position 270e5dd7070Spatrick /// can be used to set the value later; it will not be invalidated by 271e5dd7070Spatrick /// any intermediate operations except (1) filling the same position or 272e5dd7070Spatrick /// (2) finishing the entire builder. 273e5dd7070Spatrick /// 274e5dd7070Spatrick /// This is useful for emitting certain kinds of structure which 275e5dd7070Spatrick /// contain some sort of summary field, generally a count, before any 276e5dd7070Spatrick /// of the data. By emitting a placeholder first, the structure can 277e5dd7070Spatrick /// be emitted eagerly. addPlaceholder()278e5dd7070Spatrick PlaceholderPosition addPlaceholder() { 279e5dd7070Spatrick assert(!Finished && "cannot add more values after finishing builder"); 280e5dd7070Spatrick assert(!Frozen && "cannot add values while subbuilder is active"); 281e5dd7070Spatrick Builder.Buffer.push_back(nullptr); 282e5dd7070Spatrick return Builder.Buffer.size() - 1; 283e5dd7070Spatrick } 284e5dd7070Spatrick 285e5dd7070Spatrick /// Add a placeholder, giving the expected type that will be filled in. 286e5dd7070Spatrick PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType); 287e5dd7070Spatrick 288e5dd7070Spatrick /// Fill a previously-added placeholder. 289e5dd7070Spatrick void fillPlaceholderWithInt(PlaceholderPosition position, 290e5dd7070Spatrick llvm::IntegerType *type, uint64_t value, 291e5dd7070Spatrick bool isSigned = false) { 292e5dd7070Spatrick fillPlaceholder(position, llvm::ConstantInt::get(type, value, isSigned)); 293e5dd7070Spatrick } 294e5dd7070Spatrick 295e5dd7070Spatrick /// Fill a previously-added placeholder. fillPlaceholder(PlaceholderPosition position,llvm::Constant * value)296e5dd7070Spatrick void fillPlaceholder(PlaceholderPosition position, llvm::Constant *value) { 297e5dd7070Spatrick assert(!Finished && "cannot change values after finishing builder"); 298e5dd7070Spatrick assert(!Frozen && "cannot add values while subbuilder is active"); 299e5dd7070Spatrick llvm::Constant *&slot = Builder.Buffer[position.Index]; 300e5dd7070Spatrick assert(slot == nullptr && "placeholder already filled"); 301e5dd7070Spatrick slot = value; 302e5dd7070Spatrick } 303e5dd7070Spatrick 304e5dd7070Spatrick /// Produce an address which will eventually point to the next 305e5dd7070Spatrick /// position to be filled. This is computed with an indexed 306e5dd7070Spatrick /// getelementptr rather than by computing offsets. 307e5dd7070Spatrick /// 308*ec727ea7Spatrick /// The returned pointer will have type T*, where T is the given type. This 309*ec727ea7Spatrick /// type can differ from the type of the actual element. 310e5dd7070Spatrick llvm::Constant *getAddrOfCurrentPosition(llvm::Type *type); 311e5dd7070Spatrick 312*ec727ea7Spatrick /// Produce an address which points to a position in the aggregate being 313*ec727ea7Spatrick /// constructed. This is computed with an indexed getelementptr rather than by 314*ec727ea7Spatrick /// computing offsets. 315*ec727ea7Spatrick /// 316*ec727ea7Spatrick /// The returned pointer will have type T*, where T is the given type. This 317*ec727ea7Spatrick /// type can differ from the type of the actual element. 318*ec727ea7Spatrick llvm::Constant *getAddrOfPosition(llvm::Type *type, size_t position); 319*ec727ea7Spatrick getGEPIndicesToCurrentPosition(llvm::SmallVectorImpl<llvm::Constant * > & indices)320e5dd7070Spatrick llvm::ArrayRef<llvm::Constant*> getGEPIndicesToCurrentPosition( 321e5dd7070Spatrick llvm::SmallVectorImpl<llvm::Constant*> &indices) { 322e5dd7070Spatrick getGEPIndicesTo(indices, Builder.Buffer.size()); 323e5dd7070Spatrick return indices; 324e5dd7070Spatrick } 325e5dd7070Spatrick 326e5dd7070Spatrick protected: 327e5dd7070Spatrick llvm::Constant *finishArray(llvm::Type *eltTy); 328e5dd7070Spatrick llvm::Constant *finishStruct(llvm::StructType *structTy); 329e5dd7070Spatrick 330e5dd7070Spatrick private: 331e5dd7070Spatrick void getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant*> &indices, 332e5dd7070Spatrick size_t position) const; 333e5dd7070Spatrick 334e5dd7070Spatrick llvm::Constant *getRelativeOffset(llvm::IntegerType *offsetType, 335e5dd7070Spatrick llvm::Constant *target); 336e5dd7070Spatrick 337*ec727ea7Spatrick llvm::Constant *getRelativeOffsetToPosition(llvm::IntegerType *offsetType, 338*ec727ea7Spatrick llvm::Constant *target, 339*ec727ea7Spatrick size_t position); 340*ec727ea7Spatrick 341e5dd7070Spatrick CharUnits getOffsetFromGlobalTo(size_t index) const; 342e5dd7070Spatrick }; 343e5dd7070Spatrick 344e5dd7070Spatrick template <class Impl, class Traits> 345e5dd7070Spatrick class ConstantAggregateBuilderTemplateBase 346e5dd7070Spatrick : public Traits::AggregateBuilderBase { 347e5dd7070Spatrick using super = typename Traits::AggregateBuilderBase; 348e5dd7070Spatrick public: 349e5dd7070Spatrick using InitBuilder = typename Traits::InitBuilder; 350e5dd7070Spatrick using ArrayBuilder = typename Traits::ArrayBuilder; 351e5dd7070Spatrick using StructBuilder = typename Traits::StructBuilder; 352e5dd7070Spatrick using AggregateBuilderBase = typename Traits::AggregateBuilderBase; 353e5dd7070Spatrick 354e5dd7070Spatrick protected: ConstantAggregateBuilderTemplateBase(InitBuilder & builder,AggregateBuilderBase * parent)355e5dd7070Spatrick ConstantAggregateBuilderTemplateBase(InitBuilder &builder, 356e5dd7070Spatrick AggregateBuilderBase *parent) 357e5dd7070Spatrick : super(builder, parent) {} 358e5dd7070Spatrick asImpl()359e5dd7070Spatrick Impl &asImpl() { return *static_cast<Impl*>(this); } 360e5dd7070Spatrick 361e5dd7070Spatrick public: 362e5dd7070Spatrick ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { 363e5dd7070Spatrick return ArrayBuilder(static_cast<InitBuilder&>(this->Builder), this, eltTy); 364e5dd7070Spatrick } 365e5dd7070Spatrick 366e5dd7070Spatrick StructBuilder beginStruct(llvm::StructType *ty = nullptr) { 367e5dd7070Spatrick return StructBuilder(static_cast<InitBuilder&>(this->Builder), this, ty); 368e5dd7070Spatrick } 369e5dd7070Spatrick 370e5dd7070Spatrick /// Given that this builder was created by beginning an array or struct 371e5dd7070Spatrick /// component on the given parent builder, finish the array/struct 372e5dd7070Spatrick /// component and add it to the parent. 373e5dd7070Spatrick /// 374e5dd7070Spatrick /// It is an intentional choice that the parent is passed in explicitly 375e5dd7070Spatrick /// despite it being redundant with information already kept in the 376e5dd7070Spatrick /// builder. This aids in readability by making it easier to find the 377e5dd7070Spatrick /// places that add components to a builder, as well as "bookending" 378e5dd7070Spatrick /// the sub-builder more explicitly. finishAndAddTo(AggregateBuilderBase & parent)379e5dd7070Spatrick void finishAndAddTo(AggregateBuilderBase &parent) { 380e5dd7070Spatrick assert(this->Parent == &parent && "adding to non-parent builder"); 381e5dd7070Spatrick parent.add(asImpl().finishImpl()); 382e5dd7070Spatrick } 383e5dd7070Spatrick 384e5dd7070Spatrick /// Given that this builder was created by beginning an array or struct 385e5dd7070Spatrick /// directly on a ConstantInitBuilder, finish the array/struct and 386e5dd7070Spatrick /// create a global variable with it as the initializer. 387e5dd7070Spatrick template <class... As> finishAndCreateGlobal(As &&...args)388e5dd7070Spatrick llvm::GlobalVariable *finishAndCreateGlobal(As &&...args) { 389e5dd7070Spatrick assert(!this->Parent && "finishing non-root builder"); 390e5dd7070Spatrick return this->Builder.createGlobal(asImpl().finishImpl(), 391e5dd7070Spatrick std::forward<As>(args)...); 392e5dd7070Spatrick } 393e5dd7070Spatrick 394e5dd7070Spatrick /// Given that this builder was created by beginning an array or struct 395e5dd7070Spatrick /// directly on a ConstantInitBuilder, finish the array/struct and 396e5dd7070Spatrick /// set it as the initializer of the given global variable. finishAndSetAsInitializer(llvm::GlobalVariable * global)397e5dd7070Spatrick void finishAndSetAsInitializer(llvm::GlobalVariable *global) { 398e5dd7070Spatrick assert(!this->Parent && "finishing non-root builder"); 399e5dd7070Spatrick return this->Builder.setGlobalInitializer(global, asImpl().finishImpl()); 400e5dd7070Spatrick } 401e5dd7070Spatrick 402e5dd7070Spatrick /// Given that this builder was created by beginning an array or struct 403e5dd7070Spatrick /// directly on a ConstantInitBuilder, finish the array/struct and 404e5dd7070Spatrick /// return a future which can be used to install the initializer in 405e5dd7070Spatrick /// a global later. 406e5dd7070Spatrick /// 407e5dd7070Spatrick /// This is useful for allowing a finished initializer to passed to 408e5dd7070Spatrick /// an API which will build the global. However, the "future" preserves 409e5dd7070Spatrick /// a dependency on the original builder; it is an error to pass it aside. finishAndCreateFuture()410e5dd7070Spatrick ConstantInitFuture finishAndCreateFuture() { 411e5dd7070Spatrick assert(!this->Parent && "finishing non-root builder"); 412e5dd7070Spatrick return this->Builder.createFuture(asImpl().finishImpl()); 413e5dd7070Spatrick } 414e5dd7070Spatrick }; 415e5dd7070Spatrick 416e5dd7070Spatrick template <class Traits> 417e5dd7070Spatrick class ConstantArrayBuilderTemplateBase 418e5dd7070Spatrick : public ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, 419e5dd7070Spatrick Traits> { 420e5dd7070Spatrick using super = 421e5dd7070Spatrick ConstantAggregateBuilderTemplateBase<typename Traits::ArrayBuilder, Traits>; 422e5dd7070Spatrick 423e5dd7070Spatrick public: 424e5dd7070Spatrick using InitBuilder = typename Traits::InitBuilder; 425e5dd7070Spatrick using AggregateBuilderBase = typename Traits::AggregateBuilderBase; 426e5dd7070Spatrick 427e5dd7070Spatrick private: 428e5dd7070Spatrick llvm::Type *EltTy; 429e5dd7070Spatrick 430e5dd7070Spatrick template <class, class> 431e5dd7070Spatrick friend class ConstantAggregateBuilderTemplateBase; 432e5dd7070Spatrick 433e5dd7070Spatrick protected: ConstantArrayBuilderTemplateBase(InitBuilder & builder,AggregateBuilderBase * parent,llvm::Type * eltTy)434e5dd7070Spatrick ConstantArrayBuilderTemplateBase(InitBuilder &builder, 435e5dd7070Spatrick AggregateBuilderBase *parent, 436e5dd7070Spatrick llvm::Type *eltTy) 437e5dd7070Spatrick : super(builder, parent), EltTy(eltTy) {} 438e5dd7070Spatrick 439e5dd7070Spatrick private: 440e5dd7070Spatrick /// Form an array constant from the values that have been added to this 441e5dd7070Spatrick /// builder. finishImpl()442e5dd7070Spatrick llvm::Constant *finishImpl() { 443e5dd7070Spatrick return AggregateBuilderBase::finishArray(EltTy); 444e5dd7070Spatrick } 445e5dd7070Spatrick }; 446e5dd7070Spatrick 447e5dd7070Spatrick /// A template class designed to allow other frontends to 448e5dd7070Spatrick /// easily customize the builder classes used by ConstantInitBuilder, 449e5dd7070Spatrick /// and thus to extend the API to work with the abstractions they 450e5dd7070Spatrick /// prefer. This would probably not be necessary if C++ just 451e5dd7070Spatrick /// supported extension methods. 452e5dd7070Spatrick template <class Traits> 453e5dd7070Spatrick class ConstantStructBuilderTemplateBase 454e5dd7070Spatrick : public ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder, 455e5dd7070Spatrick Traits> { 456e5dd7070Spatrick using super = 457e5dd7070Spatrick ConstantAggregateBuilderTemplateBase<typename Traits::StructBuilder,Traits>; 458e5dd7070Spatrick 459e5dd7070Spatrick public: 460e5dd7070Spatrick using InitBuilder = typename Traits::InitBuilder; 461e5dd7070Spatrick using AggregateBuilderBase = typename Traits::AggregateBuilderBase; 462e5dd7070Spatrick 463e5dd7070Spatrick private: 464e5dd7070Spatrick llvm::StructType *StructTy; 465e5dd7070Spatrick 466e5dd7070Spatrick template <class, class> 467e5dd7070Spatrick friend class ConstantAggregateBuilderTemplateBase; 468e5dd7070Spatrick 469e5dd7070Spatrick protected: ConstantStructBuilderTemplateBase(InitBuilder & builder,AggregateBuilderBase * parent,llvm::StructType * structTy)470e5dd7070Spatrick ConstantStructBuilderTemplateBase(InitBuilder &builder, 471e5dd7070Spatrick AggregateBuilderBase *parent, 472e5dd7070Spatrick llvm::StructType *structTy) 473e5dd7070Spatrick : super(builder, parent), StructTy(structTy) { 474e5dd7070Spatrick if (structTy) this->Packed = structTy->isPacked(); 475e5dd7070Spatrick } 476e5dd7070Spatrick 477e5dd7070Spatrick public: setPacked(bool packed)478e5dd7070Spatrick void setPacked(bool packed) { 479e5dd7070Spatrick this->Packed = packed; 480e5dd7070Spatrick } 481e5dd7070Spatrick 482e5dd7070Spatrick /// Use the given type for the struct if its element count is correct. 483e5dd7070Spatrick /// Don't add more elements after calling this. suggestType(llvm::StructType * structTy)484e5dd7070Spatrick void suggestType(llvm::StructType *structTy) { 485e5dd7070Spatrick if (this->size() == structTy->getNumElements()) { 486e5dd7070Spatrick StructTy = structTy; 487e5dd7070Spatrick } 488e5dd7070Spatrick } 489e5dd7070Spatrick 490e5dd7070Spatrick private: 491e5dd7070Spatrick /// Form an array constant from the values that have been added to this 492e5dd7070Spatrick /// builder. finishImpl()493e5dd7070Spatrick llvm::Constant *finishImpl() { 494e5dd7070Spatrick return AggregateBuilderBase::finishStruct(StructTy); 495e5dd7070Spatrick } 496e5dd7070Spatrick }; 497e5dd7070Spatrick 498e5dd7070Spatrick /// A template class designed to allow other frontends to 499e5dd7070Spatrick /// easily customize the builder classes used by ConstantInitBuilder, 500e5dd7070Spatrick /// and thus to extend the API to work with the abstractions they 501e5dd7070Spatrick /// prefer. This would probably not be necessary if C++ just 502e5dd7070Spatrick /// supported extension methods. 503e5dd7070Spatrick template <class Traits> 504e5dd7070Spatrick class ConstantInitBuilderTemplateBase : public ConstantInitBuilderBase { 505e5dd7070Spatrick protected: ConstantInitBuilderTemplateBase(CodeGenModule & CGM)506e5dd7070Spatrick ConstantInitBuilderTemplateBase(CodeGenModule &CGM) 507e5dd7070Spatrick : ConstantInitBuilderBase(CGM) {} 508e5dd7070Spatrick 509e5dd7070Spatrick public: 510e5dd7070Spatrick using InitBuilder = typename Traits::InitBuilder; 511e5dd7070Spatrick using ArrayBuilder = typename Traits::ArrayBuilder; 512e5dd7070Spatrick using StructBuilder = typename Traits::StructBuilder; 513e5dd7070Spatrick 514e5dd7070Spatrick ArrayBuilder beginArray(llvm::Type *eltTy = nullptr) { 515e5dd7070Spatrick return ArrayBuilder(static_cast<InitBuilder&>(*this), nullptr, eltTy); 516e5dd7070Spatrick } 517e5dd7070Spatrick 518e5dd7070Spatrick StructBuilder beginStruct(llvm::StructType *structTy = nullptr) { 519e5dd7070Spatrick return StructBuilder(static_cast<InitBuilder&>(*this), nullptr, structTy); 520e5dd7070Spatrick } 521e5dd7070Spatrick }; 522e5dd7070Spatrick 523e5dd7070Spatrick class ConstantInitBuilder; 524e5dd7070Spatrick class ConstantStructBuilder; 525e5dd7070Spatrick class ConstantArrayBuilder; 526e5dd7070Spatrick 527e5dd7070Spatrick struct ConstantInitBuilderTraits { 528e5dd7070Spatrick using InitBuilder = ConstantInitBuilder; 529e5dd7070Spatrick using AggregateBuilderBase = ConstantAggregateBuilderBase; 530e5dd7070Spatrick using ArrayBuilder = ConstantArrayBuilder; 531e5dd7070Spatrick using StructBuilder = ConstantStructBuilder; 532e5dd7070Spatrick }; 533e5dd7070Spatrick 534e5dd7070Spatrick /// The standard implementation of ConstantInitBuilder used in Clang. 535e5dd7070Spatrick class ConstantInitBuilder 536e5dd7070Spatrick : public ConstantInitBuilderTemplateBase<ConstantInitBuilderTraits> { 537e5dd7070Spatrick public: ConstantInitBuilder(CodeGenModule & CGM)538e5dd7070Spatrick explicit ConstantInitBuilder(CodeGenModule &CGM) : 539e5dd7070Spatrick ConstantInitBuilderTemplateBase(CGM) {} 540e5dd7070Spatrick }; 541e5dd7070Spatrick 542e5dd7070Spatrick /// A helper class of ConstantInitBuilder, used for building constant 543e5dd7070Spatrick /// array initializers. 544e5dd7070Spatrick class ConstantArrayBuilder 545e5dd7070Spatrick : public ConstantArrayBuilderTemplateBase<ConstantInitBuilderTraits> { 546e5dd7070Spatrick template <class Traits> 547e5dd7070Spatrick friend class ConstantInitBuilderTemplateBase; 548e5dd7070Spatrick 549e5dd7070Spatrick // The use of explicit qualification is a GCC workaround. 550e5dd7070Spatrick template <class Impl, class Traits> 551e5dd7070Spatrick friend class CodeGen::ConstantAggregateBuilderTemplateBase; 552e5dd7070Spatrick ConstantArrayBuilder(ConstantInitBuilder & builder,ConstantAggregateBuilderBase * parent,llvm::Type * eltTy)553e5dd7070Spatrick ConstantArrayBuilder(ConstantInitBuilder &builder, 554e5dd7070Spatrick ConstantAggregateBuilderBase *parent, 555e5dd7070Spatrick llvm::Type *eltTy) 556e5dd7070Spatrick : ConstantArrayBuilderTemplateBase(builder, parent, eltTy) {} 557e5dd7070Spatrick }; 558e5dd7070Spatrick 559e5dd7070Spatrick /// A helper class of ConstantInitBuilder, used for building constant 560e5dd7070Spatrick /// struct initializers. 561e5dd7070Spatrick class ConstantStructBuilder 562e5dd7070Spatrick : public ConstantStructBuilderTemplateBase<ConstantInitBuilderTraits> { 563e5dd7070Spatrick template <class Traits> 564e5dd7070Spatrick friend class ConstantInitBuilderTemplateBase; 565e5dd7070Spatrick 566e5dd7070Spatrick // The use of explicit qualification is a GCC workaround. 567e5dd7070Spatrick template <class Impl, class Traits> 568e5dd7070Spatrick friend class CodeGen::ConstantAggregateBuilderTemplateBase; 569e5dd7070Spatrick ConstantStructBuilder(ConstantInitBuilder & builder,ConstantAggregateBuilderBase * parent,llvm::StructType * structTy)570e5dd7070Spatrick ConstantStructBuilder(ConstantInitBuilder &builder, 571e5dd7070Spatrick ConstantAggregateBuilderBase *parent, 572e5dd7070Spatrick llvm::StructType *structTy) 573e5dd7070Spatrick : ConstantStructBuilderTemplateBase(builder, parent, structTy) {} 574e5dd7070Spatrick }; 575e5dd7070Spatrick 576e5dd7070Spatrick } // end namespace CodeGen 577e5dd7070Spatrick } // end namespace clang 578e5dd7070Spatrick 579e5dd7070Spatrick #endif 580