/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/CodeGen/ConstantInitBuilder.cpp
Line | Count | Source (jump to first uncovered line) |
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 | 0 | llvm::Type *ConstantInitFuture::getType() const { |
22 | 0 | assert(Data && "dereferencing null future"); |
23 | 0 | if (Data.is<llvm::Constant*>()) { |
24 | 0 | return Data.get<llvm::Constant*>()->getType(); |
25 | 0 | } else { |
26 | 0 | return Data.get<ConstantInitBuilderBase*>()->Buffer[0]->getType(); |
27 | 0 | } |
28 | 0 | } |
29 | | |
30 | 0 | void ConstantInitFuture::abandon() { |
31 | 0 | assert(Data && "abandoning null future"); |
32 | 0 | if (auto builder = Data.dyn_cast<ConstantInitBuilderBase*>()) { |
33 | 0 | builder->abandon(0); |
34 | 0 | } |
35 | 0 | Data = nullptr; |
36 | 0 | } |
37 | | |
38 | 0 | void ConstantInitFuture::installInGlobal(llvm::GlobalVariable *GV) { |
39 | 0 | assert(Data && "installing null future"); |
40 | 0 | if (Data.is<llvm::Constant*>()) { |
41 | 0 | GV->setInitializer(Data.get<llvm::Constant*>()); |
42 | 0 | } else { |
43 | 0 | auto &builder = *Data.get<ConstantInitBuilderBase*>(); |
44 | 0 | assert(builder.Buffer.size() == 1); |
45 | 0 | builder.setGlobalInitializer(GV, builder.Buffer[0]); |
46 | 0 | builder.Buffer.clear(); |
47 | 0 | Data = nullptr; |
48 | 0 | } |
49 | 0 | } |
50 | | |
51 | | ConstantInitFuture |
52 | 0 | ConstantInitBuilderBase::createFuture(llvm::Constant *initializer) { |
53 | 0 | assert(Buffer.empty() && "buffer not current empty"); |
54 | 0 | Buffer.push_back(initializer); |
55 | 0 | return ConstantInitFuture(this); |
56 | 0 | } |
57 | | |
58 | | // Only used in this file. |
59 | | inline ConstantInitFuture::ConstantInitFuture(ConstantInitBuilderBase *builder) |
60 | 0 | : Data(builder) { |
61 | 0 | assert(!builder->Frozen); |
62 | 0 | assert(builder->Buffer.size() == 1); |
63 | 0 | assert(builder->Buffer[0] != nullptr); |
64 | 0 | } |
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 | 13.7k | unsigned addressSpace) { |
73 | 13.7k | auto GV = new llvm::GlobalVariable(CGM.getModule(), |
74 | 13.7k | initializer->getType(), |
75 | 13.7k | constant, |
76 | 13.7k | linkage, |
77 | 13.7k | initializer, |
78 | 13.7k | name, |
79 | 13.7k | /*insert before*/ nullptr, |
80 | 13.7k | llvm::GlobalValue::NotThreadLocal, |
81 | 13.7k | addressSpace); |
82 | 13.7k | GV->setAlignment(alignment.getAsAlign()); |
83 | 13.7k | resolveSelfReferences(GV); |
84 | 13.7k | return GV; |
85 | 13.7k | } |
86 | | |
87 | | void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV, |
88 | 4.71k | llvm::Constant *initializer){ |
89 | 4.71k | GV->setInitializer(initializer); |
90 | | |
91 | 4.71k | if (!SelfReferences.empty()) |
92 | 54 | resolveSelfReferences(GV); |
93 | 4.71k | } |
94 | | |
95 | 13.8k | void ConstantInitBuilderBase::resolveSelfReferences(llvm::GlobalVariable *GV) { |
96 | 13.8k | for (auto &entry : SelfReferences) { |
97 | 166 | llvm::Constant *resolvedReference = |
98 | 166 | llvm::ConstantExpr::getInBoundsGetElementPtr( |
99 | 166 | GV->getValueType(), GV, entry.Indices); |
100 | 166 | auto dummy = entry.Dummy; |
101 | 166 | dummy->replaceAllUsesWith(resolvedReference); |
102 | 166 | dummy->eraseFromParent(); |
103 | 166 | } |
104 | 13.8k | SelfReferences.clear(); |
105 | 13.8k | } |
106 | | |
107 | 862 | void ConstantInitBuilderBase::abandon(size_t newEnd) { |
108 | | // Remove all the entries we've added. |
109 | 862 | 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 | 862 | if (newEnd == 0) { |
115 | 445 | for (auto &entry : SelfReferences) { |
116 | 0 | auto dummy = entry.Dummy; |
117 | 0 | dummy->replaceAllUsesWith(llvm::PoisonValue::get(dummy->getType())); |
118 | 0 | dummy->eraseFromParent(); |
119 | 0 | } |
120 | 445 | SelfReferences.clear(); |
121 | 445 | } |
122 | 862 | } |
123 | | |
124 | 0 | void ConstantAggregateBuilderBase::addSize(CharUnits size) { |
125 | 0 | add(Builder.CGM.getSize(size)); |
126 | 0 | } |
127 | | |
128 | | llvm::Constant * |
129 | | ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType, |
130 | 0 | llvm::Constant *target) { |
131 | 0 | return getRelativeOffsetToPosition(offsetType, target, |
132 | 0 | Builder.Buffer.size() - Begin); |
133 | 0 | } |
134 | | |
135 | | llvm::Constant *ConstantAggregateBuilderBase::getRelativeOffsetToPosition( |
136 | 166 | llvm::IntegerType *offsetType, llvm::Constant *target, size_t position) { |
137 | | // Compute the address of the relative-address slot. |
138 | 166 | auto base = getAddrOfPosition(offsetType, position); |
139 | | |
140 | | // Subtract. |
141 | 166 | base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy); |
142 | 166 | target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy); |
143 | 166 | llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base); |
144 | | |
145 | | // Truncate to the relative-address type if necessary. |
146 | 166 | if (Builder.CGM.IntPtrTy != offsetType) { |
147 | 166 | offset = llvm::ConstantExpr::getTrunc(offset, offsetType); |
148 | 166 | } |
149 | | |
150 | 166 | return offset; |
151 | 166 | } |
152 | | |
153 | | llvm::Constant * |
154 | | ConstantAggregateBuilderBase::getAddrOfPosition(llvm::Type *type, |
155 | 166 | size_t position) { |
156 | | // Make a global variable. We will replace this with a GEP to this |
157 | | // position after installing the initializer. |
158 | 166 | auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true, |
159 | 166 | llvm::GlobalVariable::PrivateLinkage, |
160 | 166 | nullptr, ""); |
161 | 166 | Builder.SelfReferences.emplace_back(dummy); |
162 | 166 | auto &entry = Builder.SelfReferences.back(); |
163 | 166 | (void)getGEPIndicesTo(entry.Indices, position + Begin); |
164 | 166 | return dummy; |
165 | 166 | } |
166 | | |
167 | | llvm::Constant * |
168 | 0 | 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 | 0 | auto dummy = |
172 | 0 | new llvm::GlobalVariable(Builder.CGM.getModule(), type, true, |
173 | 0 | llvm::GlobalVariable::PrivateLinkage, |
174 | 0 | nullptr, ""); |
175 | 0 | Builder.SelfReferences.emplace_back(dummy); |
176 | 0 | auto &entry = Builder.SelfReferences.back(); |
177 | 0 | (void) getGEPIndicesToCurrentPosition(entry.Indices); |
178 | 0 | return dummy; |
179 | 0 | } |
180 | | |
181 | | void ConstantAggregateBuilderBase::getGEPIndicesTo( |
182 | | llvm::SmallVectorImpl<llvm::Constant*> &indices, |
183 | 332 | size_t position) const { |
184 | | // Recurse on the parent builder if present. |
185 | 332 | if (Parent) { |
186 | 166 | Parent->getGEPIndicesTo(indices, Begin); |
187 | | |
188 | | // Otherwise, add an index to drill into the first level of pointer. |
189 | 166 | } else { |
190 | 166 | assert(indices.empty()); |
191 | 0 | indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0)); |
192 | 166 | } |
193 | | |
194 | 0 | 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 | 0 | indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, |
198 | 332 | position - Begin)); |
199 | 332 | } |
200 | | |
201 | | ConstantAggregateBuilderBase::PlaceholderPosition |
202 | 0 | ConstantAggregateBuilderBase::addPlaceholderWithSize(llvm::Type *type) { |
203 | | // Bring the offset up to the last field. |
204 | 0 | CharUnits offset = getNextOffsetFromGlobal(); |
205 | | |
206 | | // Create the placeholder. |
207 | 0 | auto position = addPlaceholder(); |
208 | | |
209 | | // Advance the offset past that field. |
210 | 0 | auto &layout = Builder.CGM.getDataLayout(); |
211 | 0 | if (!Packed) |
212 | 0 | offset = offset.alignTo(CharUnits::fromQuantity( |
213 | 0 | layout.getABITypeAlignment(type))); |
214 | 0 | offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type)); |
215 | |
|
216 | 0 | CachedOffsetEnd = Builder.Buffer.size(); |
217 | 0 | CachedOffsetFromGlobal = offset; |
218 | |
|
219 | 0 | return position; |
220 | 0 | } |
221 | | |
222 | 0 | CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{ |
223 | 0 | size_t cacheEnd = CachedOffsetEnd; |
224 | 0 | assert(cacheEnd <= end); |
225 | | |
226 | | // Fast path: if the cache is valid, just use it. |
227 | 0 | if (cacheEnd == end) { |
228 | 0 | return CachedOffsetFromGlobal; |
229 | 0 | } |
230 | | |
231 | | // If the cached range ends before the index at which the current |
232 | | // aggregate starts, recurse for the parent. |
233 | 0 | CharUnits offset; |
234 | 0 | if (cacheEnd < Begin) { |
235 | 0 | assert(cacheEnd == 0); |
236 | 0 | assert(Parent && "Begin != 0 for root builder"); |
237 | 0 | cacheEnd = Begin; |
238 | 0 | offset = Parent->getOffsetFromGlobalTo(Begin); |
239 | 0 | } else { |
240 | 0 | offset = CachedOffsetFromGlobal; |
241 | 0 | } |
242 | | |
243 | | // Perform simple layout on the elements in cacheEnd..<end. |
244 | 0 | if (cacheEnd != end) { |
245 | 0 | auto &layout = Builder.CGM.getDataLayout(); |
246 | 0 | do { |
247 | 0 | llvm::Constant *element = Builder.Buffer[cacheEnd]; |
248 | 0 | assert(element != nullptr && |
249 | 0 | "cannot compute offset when a placeholder is present"); |
250 | 0 | llvm::Type *elementType = element->getType(); |
251 | 0 | if (!Packed) |
252 | 0 | offset = offset.alignTo(CharUnits::fromQuantity( |
253 | 0 | layout.getABITypeAlignment(elementType))); |
254 | 0 | offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType)); |
255 | 0 | } while (++cacheEnd != end); |
256 | 0 | } |
257 | | |
258 | | // Cache and return. |
259 | 0 | CachedOffsetEnd = cacheEnd; |
260 | 0 | CachedOffsetFromGlobal = offset; |
261 | 0 | return offset; |
262 | 0 | } |
263 | | |
264 | 9.19k | llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) { |
265 | 9.19k | markFinished(); |
266 | | |
267 | 9.19k | auto &buffer = getBuffer(); |
268 | 9.19k | assert((Begin < buffer.size() || |
269 | 9.19k | (Begin == buffer.size() && eltTy)) |
270 | 9.19k | && "didn't add any array elements without element type"); |
271 | 0 | auto elts = llvm::makeArrayRef(buffer).slice(Begin); |
272 | 9.19k | if (!eltTy) eltTy = elts[0]->getType()25 ; |
273 | 9.19k | auto type = llvm::ArrayType::get(eltTy, elts.size()); |
274 | 9.19k | auto constant = llvm::ConstantArray::get(type, elts); |
275 | 9.19k | buffer.erase(buffer.begin() + Begin, buffer.end()); |
276 | 9.19k | return constant; |
277 | 9.19k | } |
278 | | |
279 | | llvm::Constant * |
280 | 24.0k | ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) { |
281 | 24.0k | markFinished(); |
282 | | |
283 | 24.0k | auto &buffer = getBuffer(); |
284 | 24.0k | auto elts = llvm::makeArrayRef(buffer).slice(Begin); |
285 | | |
286 | 24.0k | if (ty == nullptr && elts.empty()6.86k ) |
287 | 0 | ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed); |
288 | | |
289 | 24.0k | llvm::Constant *constant; |
290 | 24.0k | if (ty) { |
291 | 17.2k | assert(ty->isPacked() == Packed); |
292 | 0 | constant = llvm::ConstantStruct::get(ty, elts); |
293 | 17.2k | } else { |
294 | 6.86k | constant = llvm::ConstantStruct::getAnon(elts, Packed); |
295 | 6.86k | } |
296 | | |
297 | 0 | buffer.erase(buffer.begin() + Begin, buffer.end()); |
298 | 24.0k | return constant; |
299 | 24.0k | } |