317 lines · cpp
1//===--- ConstantInitBuilder.cpp - Global initializer builder -------------===//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines out-of-line routines for building initializers for10// global variables, in particular the kind of globals that are implicitly11// introduced by various language ABIs.12//13//===----------------------------------------------------------------------===//14 15#include "clang/CodeGen/ConstantInitBuilder.h"16#include "CodeGenModule.h"17 18using namespace clang;19using namespace CodeGen;20 21llvm::Type *ConstantInitFuture::getType() const {22 assert(Data && "dereferencing null future");23 if (const auto *C = dyn_cast<llvm::Constant *>(Data)) {24 return C->getType();25 } else {26 return cast<ConstantInitBuilderBase *>(Data)->Buffer[0]->getType();27 }28}29 30void ConstantInitFuture::abandon() {31 assert(Data && "abandoning null future");32 if (auto *builder = dyn_cast<ConstantInitBuilderBase *>(Data)) {33 builder->abandon(0);34 }35 Data = nullptr;36}37 38void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) {39 assert(Data && "installing null future");40 if (auto *C = dyn_cast<llvm::Constant *>(Data)) {41 GV->setInitializer(C);42 } else {43 auto &builder = *cast<ConstantInitBuilderBase *>(Data);44 assert(builder.Buffer.size() == 1);45 builder.setGlobalInitializer(GV, builder.Buffer[0]);46 builder.Buffer.clear();47 Data = nullptr;48 }49}50 51ConstantInitFuture52ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) {53 assert(Buffer.empty() && "buffer not current empty");54 Buffer.push_back(initializer);55 return ConstantInitFuture(this);56}57 58// Only used in this file.59inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder)60 : Data(builder) {61 assert(!builder->Frozen);62 assert(builder->Buffer.size() == 1);63 assert(builder->Buffer[0] != nullptr);64}65 66llvm::GlobalVariable *67ConstantInitBuilderBase::createGlobal(llvm::Constant *initializer,68 const llvm::Twine &name,69 CharUnits alignment,70 bool constant,71 llvm::GlobalValue::LinkageTypes linkage,72 unsigned addressSpace) {73 auto GV = new llvm::GlobalVariable(CGM.getModule(),74 initializer->getType(),75 constant,76 linkage,77 initializer,78 name,79 /*insert before*/ nullptr,80 llvm::GlobalValue::NotThreadLocal,81 addressSpace);82 GV->setAlignment(alignment.getAsAlign());83 resolveSelfReferences(GV);84 return GV;85}86 87void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,88 llvm::Constant *initializer){89 GV->setInitializer(initializer);90 91 if (!SelfReferences.empty())92 resolveSelfReferences(GV);93}94 95void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) {96 for (auto &entry : SelfReferences) {97 llvm::Constant *resolvedReference =98 llvm::ConstantExpr::getInBoundsGetElementPtr(99 GV->getValueType(), GV, entry.Indices);100 auto dummy = entry.Dummy;101 dummy->replaceAllUsesWith(resolvedReference);102 dummy->eraseFromParent();103 }104 SelfReferences.clear();105}106 107void ConstantInitBuilderBase::abandon(size_t newEnd) {108 // Remove all the entries we've added.109 Buffer.erase(Buffer.begin() + newEnd, Buffer.end());110 111 // If we're abandoning all the way to the beginning, destroy112 // all the self-references, because we might not get another113 // opportunity.114 if (newEnd == 0) {115 for (auto &entry : SelfReferences) {116 auto dummy = entry.Dummy;117 dummy->replaceAllUsesWith(llvm::PoisonValue::get(dummy->getType()));118 dummy->eraseFromParent();119 }120 SelfReferences.clear();121 }122}123 124void ConstantAggregateBuilderBase::addSize(CharUnits size) {125 add(Builder.CGM.getSize(size));126}127 128llvm::Constant *129ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,130 llvm::Constant *target) {131 return getRelativeOffsetToPosition(offsetType, target,132 Builder.Buffer.size() - Begin);133}134 135llvm::Constant *ConstantAggregateBuilderBase::getRelativeOffsetToPosition(136 llvm::IntegerType *offsetType, llvm::Constant *target, size_t position) {137 // Compute the address of the relative-address slot.138 auto base = getAddrOfPosition(offsetType, position);139 140 // Subtract.141 base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);142 target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);143 llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);144 145 // Truncate to the relative-address type if necessary.146 if (Builder.CGM.IntPtrTy != offsetType) {147 offset = llvm::ConstantExpr::getTrunc(offset, offsetType);148 }149 150 return offset;151}152 153llvm::Constant *154ConstantAggregateBuilderBase::getAddrOfPosition(llvm::Type *type,155 size_t position) {156 // Make a global variable. We will replace this with a GEP to this157 // position after installing the initializer.158 auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,159 llvm::GlobalVariable::PrivateLinkage,160 nullptr, "");161 Builder.SelfReferences.emplace_back(dummy);162 auto &entry = Builder.SelfReferences.back();163 getGEPIndicesTo(entry.Indices, position + Begin);164 return dummy;165}166 167llvm::Constant *168ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) {169 // Make a global variable. We will replace this with a GEP to this170 // position after installing the initializer.171 auto dummy =172 new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,173 llvm::GlobalVariable::PrivateLinkage,174 nullptr, "");175 Builder.SelfReferences.emplace_back(dummy);176 auto &entry = Builder.SelfReferences.back();177 (void) getGEPIndicesToCurrentPosition(entry.Indices);178 return dummy;179}180 181void ConstantAggregateBuilderBase::getGEPIndicesTo(182 llvm::SmallVectorImpl<llvm::Constant*> &indices,183 size_t position) const {184 // Recurse on the parent builder if present.185 if (Parent) {186 Parent->getGEPIndicesTo(indices, Begin);187 188 // Otherwise, add an index to drill into the first level of pointer.189 } else {190 assert(indices.empty());191 indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));192 }193 194 assert(position >= Begin);195 // We have to use i32 here because struct GEPs demand i32 indices.196 // It's rather unlikely to matter in practice.197 indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,198 position - Begin));199}200 201ConstantAggregateBuilderBase::PlaceholderPosition202ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) {203 // Bring the offset up to the last field.204 CharUnits offset = getNextOffsetFromGlobal();205 206 // Create the placeholder.207 auto position = addPlaceholder();208 209 // Advance the offset past that field.210 auto &layout = Builder.CGM.getDataLayout();211 if (!Packed)212 offset = offset.alignTo(CharUnits::fromQuantity(layout.getABITypeAlign(type)));213 offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));214 215 CachedOffsetEnd = Builder.Buffer.size();216 CachedOffsetFromGlobal = offset;217 218 return position;219}220 221CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{222 size_t cacheEnd = CachedOffsetEnd;223 assert(cacheEnd <= end);224 225 // Fast path: if the cache is valid, just use it.226 if (cacheEnd == end) {227 return CachedOffsetFromGlobal;228 }229 230 // If the cached range ends before the index at which the current231 // aggregate starts, recurse for the parent.232 CharUnits offset;233 if (cacheEnd < Begin) {234 assert(cacheEnd == 0);235 assert(Parent && "Begin != 0 for root builder");236 cacheEnd = Begin;237 offset = Parent->getOffsetFromGlobalTo(Begin);238 } else {239 offset = CachedOffsetFromGlobal;240 }241 242 // Perform simple layout on the elements in cacheEnd..<end.243 if (cacheEnd != end) {244 auto &layout = Builder.CGM.getDataLayout();245 do {246 llvm::Constant *element = Builder.Buffer[cacheEnd];247 assert(element != nullptr &&248 "cannot compute offset when a placeholder is present");249 llvm::Type *elementType = element->getType();250 if (!Packed)251 offset = offset.alignTo(252 CharUnits::fromQuantity(layout.getABITypeAlign(elementType)));253 offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));254 } while (++cacheEnd != end);255 }256 257 // Cache and return.258 CachedOffsetEnd = cacheEnd;259 CachedOffsetFromGlobal = offset;260 return offset;261}262 263llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {264 markFinished();265 266 auto &buffer = getBuffer();267 assert((Begin < buffer.size() ||268 (Begin == buffer.size() && eltTy))269 && "didn't add any array elements without element type");270 auto elts = llvm::ArrayRef(buffer).slice(Begin);271 if (!eltTy) eltTy = elts[0]->getType();272 auto type = llvm::ArrayType::get(eltTy, elts.size());273 auto constant = llvm::ConstantArray::get(type, elts);274 buffer.erase(buffer.begin() + Begin, buffer.end());275 return constant;276}277 278llvm::Constant *279ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {280 markFinished();281 282 auto &buffer = getBuffer();283 auto elts = llvm::ArrayRef(buffer).slice(Begin);284 285 if (ty == nullptr && elts.empty())286 ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);287 288 llvm::Constant *constant;289 if (ty) {290 assert(ty->isPacked() == Packed);291 constant = llvm::ConstantStruct::get(ty, elts);292 } else {293 constant = llvm::ConstantStruct::getAnon(elts, Packed);294 }295 296 buffer.erase(buffer.begin() + Begin, buffer.end());297 return constant;298}299 300/// Sign the given pointer and add it to the constant initializer301/// currently being built.302void ConstantAggregateBuilderBase::addSignedPointer(303 llvm::Constant *Pointer, const PointerAuthSchema &Schema,304 GlobalDecl CalleeDecl, QualType CalleeType) {305 if (!Schema || !Builder.CGM.shouldSignPointer(Schema))306 return add(Pointer);307 308 llvm::Constant *StorageAddress = nullptr;309 if (Schema.isAddressDiscriminated()) {310 StorageAddress = getAddrOfCurrentPosition(Pointer->getType());311 }312 313 llvm::Constant *SignedPointer = Builder.CGM.getConstantSignedPointer(314 Pointer, Schema, StorageAddress, CalleeDecl, CalleeType);315 add(SignedPointer);316}317