10b57cec5SDimitry Andric //===--- ConstantInitBuilder.cpp - Global initializer builder -------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines out-of-line routines for building initializers for 100b57cec5SDimitry Andric // global variables, in particular the kind of globals that are implicitly 110b57cec5SDimitry Andric // introduced by various language ABIs. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "clang/CodeGen/ConstantInitBuilder.h" 160b57cec5SDimitry Andric #include "CodeGenModule.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric using namespace clang; 190b57cec5SDimitry Andric using namespace CodeGen; 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric llvm::Type *ConstantInitFuture::getType() const { 220b57cec5SDimitry Andric assert(Data && "dereferencing null future"); 230b57cec5SDimitry Andric if (Data.is<llvm::Constant*>()) { 240b57cec5SDimitry Andric return Data.get<llvm::Constant*>()->getType(); 250b57cec5SDimitry Andric } else { 260b57cec5SDimitry Andric return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType(); 270b57cec5SDimitry Andric } 280b57cec5SDimitry Andric } 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric void ConstantInitFuture::abandon() { 310b57cec5SDimitry Andric assert(Data && "abandoning null future"); 320b57cec5SDimitry Andric if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) { 330b57cec5SDimitry Andric builder->abandon(0); 340b57cec5SDimitry Andric } 350b57cec5SDimitry Andric Data = nullptr; 360b57cec5SDimitry Andric } 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) { 390b57cec5SDimitry Andric assert(Data && "installing null future"); 400b57cec5SDimitry Andric if (Data.is<llvm::Constant*>()) { 410b57cec5SDimitry Andric GV->setInitializer(Data.get<llvm::Constant*>()); 420b57cec5SDimitry Andric } else { 430b57cec5SDimitry Andric auto &builder = *Data.get<ConstantInitBuilderBase*>(); 440b57cec5SDimitry Andric assert(builder.Buffer.size() == 1); 450b57cec5SDimitry Andric builder.setGlobalInitializer(GV, builder.Buffer[0]); 460b57cec5SDimitry Andric builder.Buffer.clear(); 470b57cec5SDimitry Andric Data = nullptr; 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric ConstantInitFuture 520b57cec5SDimitry Andric ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) { 530b57cec5SDimitry Andric assert(Buffer.empty() && "buffer not current empty"); 540b57cec5SDimitry Andric Buffer.push_back(initializer); 550b57cec5SDimitry Andric return ConstantInitFuture(this); 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric // Only used in this file. 590b57cec5SDimitry Andric inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder) 600b57cec5SDimitry Andric : Data(builder) { 610b57cec5SDimitry Andric assert(!builder->Frozen); 620b57cec5SDimitry Andric assert(builder->Buffer.size() == 1); 630b57cec5SDimitry Andric assert(builder->Buffer[0] != nullptr); 640b57cec5SDimitry Andric } 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric llvm::GlobalVariable * 670b57cec5SDimitry Andric ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer, 680b57cec5SDimitry Andric const llvm::Twine &name, 690b57cec5SDimitry Andric CharUnits alignment, 700b57cec5SDimitry Andric bool constant, 710b57cec5SDimitry Andric llvm::GlobalValue::LinkageTypes linkage, 720b57cec5SDimitry Andric unsigned addressSpace) { 730b57cec5SDimitry Andric auto GV = new llvm::GlobalVariable(CGM.getModule(), 740b57cec5SDimitry Andric initializer->getType(), 750b57cec5SDimitry Andric constant, 760b57cec5SDimitry Andric linkage, 770b57cec5SDimitry Andric initializer, 780b57cec5SDimitry Andric name, 790b57cec5SDimitry Andric /*insert before*/ nullptr, 800b57cec5SDimitry Andric llvm::GlobalValue::NotThreadLocal, 810b57cec5SDimitry Andric addressSpace); 82a7dea167SDimitry Andric GV->setAlignment(alignment.getAsAlign()); 830b57cec5SDimitry Andric resolveSelfReferences(GV); 840b57cec5SDimitry Andric return GV; 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV, 880b57cec5SDimitry Andric llvm::Constant *initializer){ 890b57cec5SDimitry Andric GV->setInitializer(initializer); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric if (!SelfReferences.empty()) 920b57cec5SDimitry Andric resolveSelfReferences(GV); 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) { 960b57cec5SDimitry Andric for (auto &entry : SelfReferences) { 970b57cec5SDimitry Andric llvm::Constant *resolvedReference = 980b57cec5SDimitry Andric llvm::ConstantExpr::getInBoundsGetElementPtr( 990b57cec5SDimitry Andric GV->getValueType(), GV, entry.Indices); 1000b57cec5SDimitry Andric auto dummy = entry.Dummy; 1010b57cec5SDimitry Andric dummy->replaceAllUsesWith(resolvedReference); 1020b57cec5SDimitry Andric dummy->eraseFromParent(); 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric SelfReferences.clear(); 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric void ConstantInitBuilderBase::abandon(size_t newEnd) { 1080b57cec5SDimitry Andric // Remove all the entries we've added. 1090b57cec5SDimitry Andric Buffer.erase(Buffer.begin() + newEnd, Buffer.end()); 1100b57cec5SDimitry Andric 1110b57cec5SDimitry Andric // If we're abandoning all the way to the beginning, destroy 1120b57cec5SDimitry Andric // all the self-references, because we might not get another 1130b57cec5SDimitry Andric // opportunity. 1140b57cec5SDimitry Andric if (newEnd == 0) { 1150b57cec5SDimitry Andric for (auto &entry : SelfReferences) { 1160b57cec5SDimitry Andric auto dummy = entry.Dummy; 11781ad6265SDimitry Andric dummy->replaceAllUsesWith(llvm::PoisonValue::get(dummy->getType())); 1180b57cec5SDimitry Andric dummy->eraseFromParent(); 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric SelfReferences.clear(); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric void ConstantAggregateBuilderBase::addSize(CharUnits size) { 1250b57cec5SDimitry Andric add(Builder.CGM.getSize(size)); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric llvm::Constant * 1290b57cec5SDimitry Andric ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType, 1300b57cec5SDimitry Andric llvm::Constant *target) { 1315ffd83dbSDimitry Andric return getRelativeOffsetToPosition(offsetType, target, 1325ffd83dbSDimitry Andric Builder.Buffer.size() - Begin); 1335ffd83dbSDimitry Andric } 1345ffd83dbSDimitry Andric 1355ffd83dbSDimitry Andric llvm::Constant *ConstantAggregateBuilderBase::getRelativeOffsetToPosition( 1365ffd83dbSDimitry Andric llvm::IntegerType *offsetType, llvm::Constant *target, size_t position) { 1370b57cec5SDimitry Andric // Compute the address of the relative-address slot. 1385ffd83dbSDimitry Andric auto base = getAddrOfPosition(offsetType, position); 1390b57cec5SDimitry Andric 1400b57cec5SDimitry Andric // Subtract. 1410b57cec5SDimitry Andric base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy); 1420b57cec5SDimitry Andric target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy); 1430b57cec5SDimitry Andric llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base); 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric // Truncate to the relative-address type if necessary. 1460b57cec5SDimitry Andric if (Builder.CGM.IntPtrTy != offsetType) { 1470b57cec5SDimitry Andric offset = llvm::ConstantExpr::getTrunc(offset, offsetType); 1480b57cec5SDimitry Andric } 1490b57cec5SDimitry Andric 1500b57cec5SDimitry Andric return offset; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric llvm::Constant * 1545ffd83dbSDimitry Andric ConstantAggregateBuilderBase::getAddrOfPosition(llvm::Type *type, 1555ffd83dbSDimitry Andric size_t position) { 1565ffd83dbSDimitry Andric // Make a global variable. We will replace this with a GEP to this 1575ffd83dbSDimitry Andric // position after installing the initializer. 1585ffd83dbSDimitry Andric auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true, 1595ffd83dbSDimitry Andric llvm::GlobalVariable::PrivateLinkage, 1605ffd83dbSDimitry Andric nullptr, ""); 1615ffd83dbSDimitry Andric Builder.SelfReferences.emplace_back(dummy); 1625ffd83dbSDimitry Andric auto &entry = Builder.SelfReferences.back(); 1635ffd83dbSDimitry Andric (void)getGEPIndicesTo(entry.Indices, position + Begin); 1645ffd83dbSDimitry Andric return dummy; 1655ffd83dbSDimitry Andric } 1665ffd83dbSDimitry Andric 1675ffd83dbSDimitry Andric llvm::Constant * 1680b57cec5SDimitry Andric ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) { 1690b57cec5SDimitry Andric // Make a global variable. We will replace this with a GEP to this 1700b57cec5SDimitry Andric // position after installing the initializer. 1710b57cec5SDimitry Andric auto dummy = 1720b57cec5SDimitry Andric new llvm::GlobalVariable(Builder.CGM.getModule(), type, true, 1730b57cec5SDimitry Andric llvm::GlobalVariable::PrivateLinkage, 1740b57cec5SDimitry Andric nullptr, ""); 1750b57cec5SDimitry Andric Builder.SelfReferences.emplace_back(dummy); 1760b57cec5SDimitry Andric auto &entry = Builder.SelfReferences.back(); 1770b57cec5SDimitry Andric (void) getGEPIndicesToCurrentPosition(entry.Indices); 1780b57cec5SDimitry Andric return dummy; 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric void ConstantAggregateBuilderBase::getGEPIndicesTo( 1820b57cec5SDimitry Andric llvm::SmallVectorImpl<llvm::Constant*> &indices, 1830b57cec5SDimitry Andric size_t position) const { 1840b57cec5SDimitry Andric // Recurse on the parent builder if present. 1850b57cec5SDimitry Andric if (Parent) { 1860b57cec5SDimitry Andric Parent->getGEPIndicesTo(indices, Begin); 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric // Otherwise, add an index to drill into the first level of pointer. 1890b57cec5SDimitry Andric } else { 1900b57cec5SDimitry Andric assert(indices.empty()); 1910b57cec5SDimitry Andric indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0)); 1920b57cec5SDimitry Andric } 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric assert(position >= Begin); 1950b57cec5SDimitry Andric // We have to use i32 here because struct GEPs demand i32 indices. 1960b57cec5SDimitry Andric // It's rather unlikely to matter in practice. 1970b57cec5SDimitry Andric indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 1980b57cec5SDimitry Andric position - Begin)); 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric ConstantAggregateBuilderBase::PlaceholderPosition 2020b57cec5SDimitry Andric ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) { 2030b57cec5SDimitry Andric // Bring the offset up to the last field. 2040b57cec5SDimitry Andric CharUnits offset = getNextOffsetFromGlobal(); 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric // Create the placeholder. 2070b57cec5SDimitry Andric auto position = addPlaceholder(); 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric // Advance the offset past that field. 2100b57cec5SDimitry Andric auto &layout = Builder.CGM.getDataLayout(); 2110b57cec5SDimitry Andric if (!Packed) 212bdd1243dSDimitry Andric offset = offset.alignTo(CharUnits::fromQuantity(layout.getABITypeAlign(type))); 2130b57cec5SDimitry Andric offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type)); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric CachedOffsetEnd = Builder.Buffer.size(); 2160b57cec5SDimitry Andric CachedOffsetFromGlobal = offset; 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric return position; 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{ 2220b57cec5SDimitry Andric size_t cacheEnd = CachedOffsetEnd; 2230b57cec5SDimitry Andric assert(cacheEnd <= end); 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric // Fast path: if the cache is valid, just use it. 2260b57cec5SDimitry Andric if (cacheEnd == end) { 2270b57cec5SDimitry Andric return CachedOffsetFromGlobal; 2280b57cec5SDimitry Andric } 2290b57cec5SDimitry Andric 2300b57cec5SDimitry Andric // If the cached range ends before the index at which the current 2310b57cec5SDimitry Andric // aggregate starts, recurse for the parent. 2320b57cec5SDimitry Andric CharUnits offset; 2330b57cec5SDimitry Andric if (cacheEnd < Begin) { 2340b57cec5SDimitry Andric assert(cacheEnd == 0); 2350b57cec5SDimitry Andric assert(Parent && "Begin != 0 for root builder"); 2360b57cec5SDimitry Andric cacheEnd = Begin; 2370b57cec5SDimitry Andric offset = Parent->getOffsetFromGlobalTo(Begin); 2380b57cec5SDimitry Andric } else { 2390b57cec5SDimitry Andric offset = CachedOffsetFromGlobal; 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric // Perform simple layout on the elements in cacheEnd..<end. 2430b57cec5SDimitry Andric if (cacheEnd != end) { 2440b57cec5SDimitry Andric auto &layout = Builder.CGM.getDataLayout(); 2450b57cec5SDimitry Andric do { 2460b57cec5SDimitry Andric llvm::Constant *element = Builder.Buffer[cacheEnd]; 2470b57cec5SDimitry Andric assert(element != nullptr && 2480b57cec5SDimitry Andric "cannot compute offset when a placeholder is present"); 2490b57cec5SDimitry Andric llvm::Type *elementType = element->getType(); 2500b57cec5SDimitry Andric if (!Packed) 251bdd1243dSDimitry Andric offset = offset.alignTo( 252bdd1243dSDimitry Andric CharUnits::fromQuantity(layout.getABITypeAlign(elementType))); 2530b57cec5SDimitry Andric offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType)); 2540b57cec5SDimitry Andric } while (++cacheEnd != end); 2550b57cec5SDimitry Andric } 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric // Cache and return. 2580b57cec5SDimitry Andric CachedOffsetEnd = cacheEnd; 2590b57cec5SDimitry Andric CachedOffsetFromGlobal = offset; 2600b57cec5SDimitry Andric return offset; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) { 2640b57cec5SDimitry Andric markFinished(); 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric auto &buffer = getBuffer(); 2670b57cec5SDimitry Andric assert((Begin < buffer.size() || 2680b57cec5SDimitry Andric (Begin == buffer.size() && eltTy)) 2690b57cec5SDimitry Andric && "didn't add any array elements without element type"); 270bdd1243dSDimitry Andric auto elts = llvm::ArrayRef(buffer).slice(Begin); 2710b57cec5SDimitry Andric if (!eltTy) eltTy = elts[0]->getType(); 2720b57cec5SDimitry Andric auto type = llvm::ArrayType::get(eltTy, elts.size()); 2730b57cec5SDimitry Andric auto constant = llvm::ConstantArray::get(type, elts); 2740b57cec5SDimitry Andric buffer.erase(buffer.begin() + Begin, buffer.end()); 2750b57cec5SDimitry Andric return constant; 2760b57cec5SDimitry Andric } 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric llvm::Constant * 2790b57cec5SDimitry Andric ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) { 2800b57cec5SDimitry Andric markFinished(); 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric auto &buffer = getBuffer(); 283bdd1243dSDimitry Andric auto elts = llvm::ArrayRef(buffer).slice(Begin); 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric if (ty == nullptr && elts.empty()) 2860b57cec5SDimitry Andric ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed); 2870b57cec5SDimitry Andric 2880b57cec5SDimitry Andric llvm::Constant *constant; 2890b57cec5SDimitry Andric if (ty) { 2900b57cec5SDimitry Andric assert(ty->isPacked() == Packed); 2910b57cec5SDimitry Andric constant = llvm::ConstantStruct::get(ty, elts); 2920b57cec5SDimitry Andric } else { 2930b57cec5SDimitry Andric constant = llvm::ConstantStruct::getAnon(elts, Packed); 2940b57cec5SDimitry Andric } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric buffer.erase(buffer.begin() + Begin, buffer.end()); 2970b57cec5SDimitry Andric return constant; 2980b57cec5SDimitry Andric } 299*0fca6ea1SDimitry Andric 300*0fca6ea1SDimitry Andric /// Sign the given pointer and add it to the constant initializer 301*0fca6ea1SDimitry Andric /// currently being built. 302*0fca6ea1SDimitry Andric void ConstantAggregateBuilderBase::addSignedPointer( 303*0fca6ea1SDimitry Andric llvm::Constant *Pointer, const PointerAuthSchema &Schema, 304*0fca6ea1SDimitry Andric GlobalDecl CalleeDecl, QualType CalleeType) { 305*0fca6ea1SDimitry Andric if (!Schema || !Builder.CGM.shouldSignPointer(Schema)) 306*0fca6ea1SDimitry Andric return add(Pointer); 307*0fca6ea1SDimitry Andric 308*0fca6ea1SDimitry Andric llvm::Constant *StorageAddress = nullptr; 309*0fca6ea1SDimitry Andric if (Schema.isAddressDiscriminated()) { 310*0fca6ea1SDimitry Andric StorageAddress = getAddrOfCurrentPosition(Pointer->getType()); 311*0fca6ea1SDimitry Andric } 312*0fca6ea1SDimitry Andric 313*0fca6ea1SDimitry Andric llvm::Constant *SignedPointer = Builder.CGM.getConstantSignedPointer( 314*0fca6ea1SDimitry Andric Pointer, Schema, StorageAddress, CalleeDecl, CalleeType); 315*0fca6ea1SDimitry Andric add(SignedPointer); 316*0fca6ea1SDimitry Andric } 317