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