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   // 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) {
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 
161 void ConstantAggregateBuilderBase::getGEPIndicesTo(
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 
168   // Otherwise, add an index to drill into the first level of pointer.
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 
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 
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();
231       if (!Packed)
232         offset = offset.alignTo(CharUnits::fromQuantity(
233                                   layout.getABITypeAlignment(elementType)));
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) {
245   markFinished();
246 
247   auto &buffer = getBuffer();
248   assert((Begin < buffer.size() ||
249           (Begin == buffer.size() && eltTy))
250          && "didn't add any array elements without element type");
251   auto elts = llvm::makeArrayRef(buffer).slice(Begin);
252   if (!eltTy) eltTy = elts[0]->getType();
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 
259 llvm::Constant *
260 ConstantAggregateBuilderBase::finishStruct(llvm::StructType *ty) {
261   markFinished();
262 
263   auto &buffer = getBuffer();
264   auto elts = llvm::makeArrayRef(buffer).slice(Begin);
265 
266   if (ty == nullptr && elts.empty())
267     ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
268 
269   llvm::Constant *constant;
270   if (ty) {
271     assert(ty->isPacked() == Packed);
272     constant = llvm::ConstantStruct::get(ty, elts);
273   } else {
274     constant = llvm::ConstantStruct::getAnon(elts, Packed);
275   }
276 
277   buffer.erase(buffer.begin() + Begin, buffer.end());
278   return constant;
279 }
280