John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 1 | //===--- ConstantInitBuilder.cpp - Global initializer builder -------------===// |
| 2 | // |
Chandler Carruth | 2946cd7 | 2019-01-19 08:50:56 +0000 | [diff] [blame] | 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 |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 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 | |
John McCall | 262f962 | 2017-03-06 19:04:16 +0000 | [diff] [blame] | 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 | |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 66 | llvm::GlobalVariable * |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 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) { |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 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); |
Guillaume Chatelet | c79099e | 2019-10-03 13:00:29 +0000 | [diff] [blame] | 82 | GV->setAlignment(alignment.getAsAlign()); |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 83 | resolveSelfReferences(GV); |
| 84 | return GV; |
| 85 | } |
| 86 | |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 87 | void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV, |
| 88 | llvm::Constant *initializer){ |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 89 | GV->setInitializer(initializer); |
| 90 | |
| 91 | if (!SelfReferences.empty()) |
| 92 | resolveSelfReferences(GV); |
| 93 | } |
| 94 | |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 95 | void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) { |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 96 | for (auto &entry : SelfReferences) { |
| 97 | llvm::Constant *resolvedReference = |
| 98 | llvm::ConstantExpr::getInBoundsGetElementPtr( |
| 99 | GV->getValueType(), GV, entry.Indices); |
John McCall | 262f962 | 2017-03-06 19:04:16 +0000 | [diff] [blame] | 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(); |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 121 | } |
| 122 | } |
| 123 | |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 124 | void ConstantAggregateBuilderBase::addSize(CharUnits size) { |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 125 | add(Builder.CGM.getSize(size)); |
| 126 | } |
| 127 | |
| 128 | llvm::Constant * |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 129 | ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType, |
| 130 | llvm::Constant *target) { |
| 131 | // Compute the address of the relative-address slot. |
| 132 | auto base = getAddrOfCurrentPosition(offsetType); |
| 133 | |
| 134 | // Subtract. |
| 135 | base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy); |
| 136 | target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy); |
| 137 | llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base); |
| 138 | |
| 139 | // Truncate to the relative-address type if necessary. |
| 140 | if (Builder.CGM.IntPtrTy != offsetType) { |
| 141 | offset = llvm::ConstantExpr::getTrunc(offset, offsetType); |
| 142 | } |
| 143 | |
| 144 | return offset; |
| 145 | } |
| 146 | |
| 147 | llvm::Constant * |
| 148 | ConstantAggregateBuilderBase::getAddrOfCurrentPosition(llvm::Type *type) { |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 149 | // Make a global variable. We will replace this with a GEP to this |
| 150 | // position after installing the initializer. |
| 151 | auto dummy = |
| 152 | new llvm::GlobalVariable(Builder.CGM.getModule(), type, true, |
| 153 | llvm::GlobalVariable::PrivateLinkage, |
| 154 | nullptr, ""); |
| 155 | Builder.SelfReferences.emplace_back(dummy); |
| 156 | auto &entry = Builder.SelfReferences.back(); |
| 157 | (void) getGEPIndicesToCurrentPosition(entry.Indices); |
| 158 | return dummy; |
| 159 | } |
| 160 | |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 161 | void ConstantAggregateBuilderBase::getGEPIndicesTo( |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 162 | llvm::SmallVectorImpl<llvm::Constant*> &indices, |
| 163 | size_t position) const { |
| 164 | // Recurse on the parent builder if present. |
| 165 | if (Parent) { |
| 166 | Parent->getGEPIndicesTo(indices, Begin); |
| 167 | |
Fangrui Song | 6907ce2 | 2018-07-30 19:24:48 +0000 | [diff] [blame] | 168 | // Otherwise, add an index to drill into the first level of pointer. |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 169 | } else { |
| 170 | assert(indices.empty()); |
| 171 | indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0)); |
| 172 | } |
| 173 | |
| 174 | assert(position >= Begin); |
| 175 | // We have to use i32 here because struct GEPs demand i32 indices. |
| 176 | // It's rather unlikely to matter in practice. |
| 177 | indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, |
| 178 | position - Begin)); |
| 179 | } |
| 180 | |
John McCall | 262f962 | 2017-03-06 19:04:16 +0000 | [diff] [blame] | 181 | ConstantAggregateBuilderBase::PlaceholderPosition |
| 182 | ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) { |
| 183 | // Bring the offset up to the last field. |
| 184 | CharUnits offset = getNextOffsetFromGlobal(); |
| 185 | |
| 186 | // Create the placeholder. |
| 187 | auto position = addPlaceholder(); |
| 188 | |
| 189 | // Advance the offset past that field. |
| 190 | auto &layout = Builder.CGM.getDataLayout(); |
| 191 | if (!Packed) |
| 192 | offset = offset.alignTo(CharUnits::fromQuantity( |
| 193 | layout.getABITypeAlignment(type))); |
| 194 | offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type)); |
| 195 | |
| 196 | CachedOffsetEnd = Builder.Buffer.size(); |
| 197 | CachedOffsetFromGlobal = offset; |
| 198 | |
| 199 | return position; |
| 200 | } |
| 201 | |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 202 | CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{ |
| 203 | size_t cacheEnd = CachedOffsetEnd; |
| 204 | assert(cacheEnd <= end); |
| 205 | |
| 206 | // Fast path: if the cache is valid, just use it. |
| 207 | if (cacheEnd == end) { |
| 208 | return CachedOffsetFromGlobal; |
| 209 | } |
| 210 | |
| 211 | // If the cached range ends before the index at which the current |
| 212 | // aggregate starts, recurse for the parent. |
| 213 | CharUnits offset; |
| 214 | if (cacheEnd < Begin) { |
| 215 | assert(cacheEnd == 0); |
| 216 | assert(Parent && "Begin != 0 for root builder"); |
| 217 | cacheEnd = Begin; |
| 218 | offset = Parent->getOffsetFromGlobalTo(Begin); |
| 219 | } else { |
| 220 | offset = CachedOffsetFromGlobal; |
| 221 | } |
| 222 | |
| 223 | // Perform simple layout on the elements in cacheEnd..<end. |
| 224 | if (cacheEnd != end) { |
| 225 | auto &layout = Builder.CGM.getDataLayout(); |
| 226 | do { |
| 227 | llvm::Constant *element = Builder.Buffer[cacheEnd]; |
| 228 | assert(element != nullptr && |
| 229 | "cannot compute offset when a placeholder is present"); |
| 230 | llvm::Type *elementType = element->getType(); |
John McCall | 262f962 | 2017-03-06 19:04:16 +0000 | [diff] [blame] | 231 | if (!Packed) |
| 232 | offset = offset.alignTo(CharUnits::fromQuantity( |
| 233 | layout.getABITypeAlignment(elementType))); |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 234 | offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType)); |
| 235 | } while (++cacheEnd != end); |
| 236 | } |
| 237 | |
| 238 | // Cache and return. |
| 239 | CachedOffsetEnd = cacheEnd; |
| 240 | CachedOffsetFromGlobal = offset; |
| 241 | return offset; |
| 242 | } |
| 243 | |
| 244 | llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) { |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 245 | markFinished(); |
| 246 | |
| 247 | auto &buffer = getBuffer(); |
| 248 | assert((Begin < buffer.size() || |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 249 | (Begin == buffer.size() && eltTy)) |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 250 | && "didn't add any array elements without element type"); |
| 251 | auto elts = llvm::makeArrayRef(buffer).slice(Begin); |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 252 | if (!eltTy) eltTy = elts[0]->getType(); |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 253 | auto type = llvm::ArrayType::get(eltTy, elts.size()); |
| 254 | auto constant = llvm::ConstantArray::get(type, elts); |
| 255 | buffer.erase(buffer.begin() + Begin, buffer.end()); |
| 256 | return constant; |
| 257 | } |
| 258 | |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 259 | llvm::Constant * |
| 260 | ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) { |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 261 | markFinished(); |
| 262 | |
| 263 | auto &buffer = getBuffer(); |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 264 | auto elts = llvm::makeArrayRef(buffer).slice(Begin); |
| 265 | |
John McCall | 262f962 | 2017-03-06 19:04:16 +0000 | [diff] [blame] | 266 | if (ty == nullptr && elts.empty()) |
| 267 | ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed); |
| 268 | |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 269 | llvm::Constant *constant; |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 270 | if (ty) { |
John McCall | 262f962 | 2017-03-06 19:04:16 +0000 | [diff] [blame] | 271 | assert(ty->isPacked() == Packed); |
John McCall | 32e0d18 | 2017-03-04 21:26:29 +0000 | [diff] [blame] | 272 | constant = llvm::ConstantStruct::get(ty, elts); |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 273 | } else { |
John McCall | 262f962 | 2017-03-06 19:04:16 +0000 | [diff] [blame] | 274 | constant = llvm::ConstantStruct::getAnon(elts, Packed); |
John McCall | 5ad7407 | 2017-03-02 20:04:19 +0000 | [diff] [blame] | 275 | } |
| 276 | |
| 277 | buffer.erase(buffer.begin() + Begin, buffer.end()); |
| 278 | return constant; |
| 279 | } |