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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines out-of-line routines for building initializers for 10 // global variables, in particular the kind of globals that are implicitly 11 // introduced by various language ABIs. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/CodeGen/ConstantInitBuilder.h" 16 #include "CodeGenModule.h" 17 18 using namespace clang; 19 using namespace CodeGen; 20 21 llvm::Type *ConstantInitFuture::getType() const { 22 assert(Data && "dereferencing null future"); 23 if (Data.is<llvm::Constant*>()) { 24 return Data.get<llvm::Constant*>()->getType(); 25 } else { 26 return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType(); 27 } 28 } 29 30 void ConstantInitFuture::abandon() { 31 assert(Data && "abandoning null future"); 32 if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) { 33 builder->abandon(0); 34 } 35 Data = nullptr; 36 } 37 38 void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) { 39 assert(Data && "installing null future"); 40 if (Data.is<llvm::Constant*>()) { 41 GV->setInitializer(Data.get<llvm::Constant*>()); 42 } else { 43 auto &builder = *Data.get<ConstantInitBuilderBase*>(); 44 assert(builder.Buffer.size() == 1); 45 builder.setGlobalInitializer(GV, builder.Buffer[0]); 46 builder.Buffer.clear(); 47 Data = nullptr; 48 } 49 } 50 51 ConstantInitFuture 52 ConstantInitBuilderBase::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. 59 inline 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 66 llvm::GlobalVariable * 67 ConstantInitBuilderBase::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 87 void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV, 88 llvm::Constant *initializer){ 89 GV->setInitializer(initializer); 90 91 if (!SelfReferences.empty()) 92 resolveSelfReferences(GV); 93 } 94 95 void 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 107 void 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, destroy 112 // all the self-references, because we might not get another 113 // opportunity. 114 if (newEnd == 0) { 115 for (auto &entry : SelfReferences) { 116 auto dummy = entry.Dummy; 117 dummy->replaceAllUsesWith(llvm::UndefValue::get(dummy->getType())); 118 dummy->eraseFromParent(); 119 } 120 SelfReferences.clear(); 121 } 122 } 123 124 void ConstantAggregateBuilderBase::addSize(CharUnits size) { 125 add(Builder.CGM.getSize(size)); 126 } 127 128 llvm::Constant * 129 ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType, 130 llvm::Constant *target) { 131 return getRelativeOffsetToPosition(offsetType, target, 132 Builder.Buffer.size() - Begin); 133 } 134 135 llvm::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 153 llvm::Constant * 154 ConstantAggregateBuilderBase::getAddrOfPosition(llvm::Type *type, 155 size_t position) { 156 // Make a global variable. We will replace this with a GEP to this 157 // 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 (void)getGEPIndicesTo(entry.Indices, position + Begin); 164 return dummy; 165 } 166 167 llvm::Constant * 168 ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) { 169 // Make a global variable. We will replace this with a GEP to this 170 // 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 181 void 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 201 ConstantAggregateBuilderBase::PlaceholderPosition 202 ConstantAggregateBuilderBase::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( 213 layout.getABITypeAlignment(type))); 214 offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type)); 215 216 CachedOffsetEnd = Builder.Buffer.size(); 217 CachedOffsetFromGlobal = offset; 218 219 return position; 220 } 221 222 CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{ 223 size_t cacheEnd = CachedOffsetEnd; 224 assert(cacheEnd <= end); 225 226 // Fast path: if the cache is valid, just use it. 227 if (cacheEnd == end) { 228 return CachedOffsetFromGlobal; 229 } 230 231 // If the cached range ends before the index at which the current 232 // aggregate starts, recurse for the parent. 233 CharUnits offset; 234 if (cacheEnd < Begin) { 235 assert(cacheEnd == 0); 236 assert(Parent && "Begin != 0 for root builder"); 237 cacheEnd = Begin; 238 offset = Parent->getOffsetFromGlobalTo(Begin); 239 } else { 240 offset = CachedOffsetFromGlobal; 241 } 242 243 // Perform simple layout on the elements in cacheEnd..<end. 244 if (cacheEnd != end) { 245 auto &layout = Builder.CGM.getDataLayout(); 246 do { 247 llvm::Constant *element = Builder.Buffer[cacheEnd]; 248 assert(element != nullptr && 249 "cannot compute offset when a placeholder is present"); 250 llvm::Type *elementType = element->getType(); 251 if (!Packed) 252 offset = offset.alignTo(CharUnits::fromQuantity( 253 layout.getABITypeAlignment(elementType))); 254 offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType)); 255 } while (++cacheEnd != end); 256 } 257 258 // Cache and return. 259 CachedOffsetEnd = cacheEnd; 260 CachedOffsetFromGlobal = offset; 261 return offset; 262 } 263 264 llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) { 265 markFinished(); 266 267 auto &buffer = getBuffer(); 268 assert((Begin < buffer.size() || 269 (Begin == buffer.size() && eltTy)) 270 && "didn't add any array elements without element type"); 271 auto elts = llvm::makeArrayRef(buffer).slice(Begin); 272 if (!eltTy) eltTy = elts[0]->getType(); 273 auto type = llvm::ArrayType::get(eltTy, elts.size()); 274 auto constant = llvm::ConstantArray::get(type, elts); 275 buffer.erase(buffer.begin() + Begin, buffer.end()); 276 return constant; 277 } 278 279 llvm::Constant * 280 ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) { 281 markFinished(); 282 283 auto &buffer = getBuffer(); 284 auto elts = llvm::makeArrayRef(buffer).slice(Begin); 285 286 if (ty == nullptr && elts.empty()) 287 ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed); 288 289 llvm::Constant *constant; 290 if (ty) { 291 assert(ty->isPacked() == Packed); 292 constant = llvm::ConstantStruct::get(ty, elts); 293 } else { 294 constant = llvm::ConstantStruct::getAnon(elts, Packed); 295 } 296 297 buffer.erase(buffer.begin() + Begin, buffer.end()); 298 return constant; 299 } 300