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 
19 using namespace clang;
20 using namespace CodeGen;
21 
getType() const22 llvm::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 
abandon()31 void 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 
installInGlobal(llvm::GlobalVariable * GV)39 void 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 
52 ConstantInitFuture
createFuture(llvm::Constant * initializer)53 ConstantInitBuilderBase::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.
ConstantInitFuture(ConstantInitBuilderBase * builder)60 inline 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 
67 llvm::GlobalVariable *
createGlobal(llvm::Constant * initializer,const llvm::Twine & name,CharUnits alignment,bool constant,llvm::GlobalValue::LinkageTypes linkage,unsigned addressSpace)68 ConstantInitBuilderBase::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 
setGlobalInitializer(llvm::GlobalVariable * GV,llvm::Constant * initializer)88 void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
89                                                    llvm::Constant *initializer){
90   GV->setInitializer(initializer);
91 
92   if (!SelfReferences.empty())
93     resolveSelfReferences(GV);
94 }
95 
resolveSelfReferences(llvm::GlobalVariable * GV)96 void 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 
abandon(size_t newEnd)108 void 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 
addSize(CharUnits size)125 void ConstantAggregateBuilderBase::addSize(CharUnits size) {
126   add(Builder.CGM.getSize(size));
127 }
128 
129 llvm::Constant *
getRelativeOffset(llvm::IntegerType * offsetType,llvm::Constant * target)130 ConstantAggregateBuilderBase::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 
148 llvm::Constant *
getAddrOfCurrentPosition(llvm::Type * type)149 ConstantAggregateBuilderBase::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 
getGEPIndicesTo(llvm::SmallVectorImpl<llvm::Constant * > & indices,size_t position) const162 void 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 
182 ConstantAggregateBuilderBase::PlaceholderPosition
addPlaceholderWithSize(llvm::Type * type)183 ConstantAggregateBuilderBase::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 
getOffsetFromGlobalTo(size_t end) const203 CharUnits 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 
finishArray(llvm::Type * eltTy)245 llvm::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 
260 llvm::Constant *
finishStruct(llvm::StructType * ty)261 ConstantAggregateBuilderBase::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