ConstantInitBuilder.cpp revision 317030
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