clang  11.0.0git
ConstantInitBuilder.cpp
Go to the documentation of this file.
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 
16 #include "CodeGenModule.h"
17 
18 using namespace clang;
19 using namespace CodeGen;
20 
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 
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 
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.
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 
125  add(Builder.CGM.getSize(size));
126 }
127 
128 llvm::Constant *
129 ConstantAggregateBuilderBase::getRelativeOffset(llvm::IntegerType *offsetType,
130  llvm::Constant *target) {
131  return getRelativeOffsetToPosition(offsetType, target,
132  Builder.Buffer.size() - Begin);
133 }
134 
135 llvm::Constant *ConstantAggregateBuilderBase::getRelativeOffsetToPosition(
136  llvm::IntegerType *offsetType, llvm::Constant *target, size_t position) {
137  // Compute the address of the relative-address slot.
138  auto base = getAddrOfPosition(offsetType, position);
139 
140  // Subtract.
141  base = llvm::ConstantExpr::getPtrToInt(base, Builder.CGM.IntPtrTy);
142  target = llvm::ConstantExpr::getPtrToInt(target, Builder.CGM.IntPtrTy);
143  llvm::Constant *offset = llvm::ConstantExpr::getSub(target, base);
144 
145  // Truncate to the relative-address type if necessary.
146  if (Builder.CGM.IntPtrTy != offsetType) {
147  offset = llvm::ConstantExpr::getTrunc(offset, offsetType);
148  }
149 
150  return offset;
151 }
152 
153 llvm::Constant *
155  size_t position) {
156  // Make a global variable. We will replace this with a GEP to this
157  // position after installing the initializer.
158  auto dummy = new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
159  llvm::GlobalVariable::PrivateLinkage,
160  nullptr, "");
161  Builder.SelfReferences.emplace_back(dummy);
162  auto &entry = Builder.SelfReferences.back();
163  (void)getGEPIndicesTo(entry.Indices, position + Begin);
164  return dummy;
165 }
166 
167 llvm::Constant *
169  // Make a global variable. We will replace this with a GEP to this
170  // position after installing the initializer.
171  auto dummy =
172  new llvm::GlobalVariable(Builder.CGM.getModule(), type, true,
173  llvm::GlobalVariable::PrivateLinkage,
174  nullptr, "");
175  Builder.SelfReferences.emplace_back(dummy);
176  auto &entry = Builder.SelfReferences.back();
177  (void) getGEPIndicesToCurrentPosition(entry.Indices);
178  return dummy;
179 }
180 
181 void ConstantAggregateBuilderBase::getGEPIndicesTo(
183  size_t position) const {
184  // Recurse on the parent builder if present.
185  if (Parent) {
186  Parent->getGEPIndicesTo(indices, Begin);
187 
188  // Otherwise, add an index to drill into the first level of pointer.
189  } else {
190  assert(indices.empty());
191  indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty, 0));
192  }
193 
194  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  indices.push_back(llvm::ConstantInt::get(Builder.CGM.Int32Ty,
198  position - Begin));
199 }
200 
203  // Bring the offset up to the last field.
204  CharUnits offset = getNextOffsetFromGlobal();
205 
206  // Create the placeholder.
207  auto position = addPlaceholder();
208 
209  // Advance the offset past that field.
210  auto &layout = Builder.CGM.getDataLayout();
211  if (!Packed)
212  offset = offset.alignTo(CharUnits::fromQuantity(
213  layout.getABITypeAlignment(type)));
214  offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
215 
216  CachedOffsetEnd = Builder.Buffer.size();
217  CachedOffsetFromGlobal = offset;
218 
219  return position;
220 }
221 
222 CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
223  size_t cacheEnd = CachedOffsetEnd;
224  assert(cacheEnd <= end);
225 
226  // Fast path: if the cache is valid, just use it.
227  if (cacheEnd == end) {
228  return CachedOffsetFromGlobal;
229  }
230 
231  // If the cached range ends before the index at which the current
232  // aggregate starts, recurse for the parent.
233  CharUnits offset;
234  if (cacheEnd < Begin) {
235  assert(cacheEnd == 0);
236  assert(Parent && "Begin != 0 for root builder");
237  cacheEnd = Begin;
238  offset = Parent->getOffsetFromGlobalTo(Begin);
239  } else {
240  offset = CachedOffsetFromGlobal;
241  }
242 
243  // Perform simple layout on the elements in cacheEnd..<end.
244  if (cacheEnd != end) {
245  auto &layout = Builder.CGM.getDataLayout();
246  do {
247  llvm::Constant *element = Builder.Buffer[cacheEnd];
248  assert(element != nullptr &&
249  "cannot compute offset when a placeholder is present");
250  llvm::Type *elementType = element->getType();
251  if (!Packed)
252  offset = offset.alignTo(CharUnits::fromQuantity(
253  layout.getABITypeAlignment(elementType)));
254  offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
255  } while (++cacheEnd != end);
256  }
257 
258  // Cache and return.
259  CachedOffsetEnd = cacheEnd;
260  CachedOffsetFromGlobal = offset;
261  return offset;
262 }
263 
265  markFinished();
266 
267  auto &buffer = getBuffer();
268  assert((Begin < buffer.size() ||
269  (Begin == buffer.size() && eltTy))
270  && "didn't add any array elements without element type");
271  auto elts = llvm::makeArrayRef(buffer).slice(Begin);
272  if (!eltTy) eltTy = elts[0]->getType();
273  auto type = llvm::ArrayType::get(eltTy, elts.size());
274  auto constant = llvm::ConstantArray::get(type, elts);
275  buffer.erase(buffer.begin() + Begin, buffer.end());
276  return constant;
277 }
278 
279 llvm::Constant *
281  markFinished();
282 
283  auto &buffer = getBuffer();
284  auto elts = llvm::makeArrayRef(buffer).slice(Begin);
285 
286  if (ty == nullptr && elts.empty())
287  ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
288 
289  llvm::Constant *constant;
290  if (ty) {
291  assert(ty->isPacked() == Packed);
292  constant = llvm::ConstantStruct::get(ty, elts);
293  } else {
294  constant = llvm::ConstantStruct::getAnon(elts, Packed);
295  }
296 
297  buffer.erase(buffer.begin() + Begin, buffer.end());
298  return constant;
299 }
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
CharUnits alignTo(const CharUnits &Align) const
alignTo - Returns the next integer (mod 2**64) that is greater than or equal to this quantity and is ...
Definition: CharUnits.h:188
void addSize(CharUnits size)
Add an integer value of type size_t.
CharUnits - This is an opaque type for sizes expressed in character units.
Definition: CharUnits.h:38
llvm::Align getAsAlign() const
getAsAlign - Returns Quantity as a valid llvm::Align, Beware llvm::Align assumes power of two 8-bit b...
Definition: CharUnits.h:183
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr or CxxCtorInitializer) selects the name&#39;s to...
llvm::Constant * getAddrOfCurrentPosition(llvm::Type *type)
Produce an address which will eventually point to the next position to be filled. ...
llvm::Constant * finishArray(llvm::Type *eltTy)
NodeId Parent
Definition: ASTDiff.cpp:192
void abandon()
Abandon this initializer.
llvm::Constant * getAddrOfPosition(llvm::Type *type, size_t position)
Produce an address which points to a position in the aggregate being constructed. ...
llvm::Type * getType() const
Return the type of the initializer.
SourceLocation Begin
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition: CharUnits.h:63
The l-value was considered opaque, so the alignment was determined from a type.
A "future" for a completed constant initializer, which can be passed around independently of any sub-...
Dataflow Directional Tag Classes.
llvm::Constant * finishStruct(llvm::StructType *structTy)
PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType)
Add a placeholder, giving the expected type that will be filled in.
An opaque class to hold the abstract position of a placeholder.
void installInGlobal(llvm::GlobalVariable *global)
Install the initializer into a global variable.