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