clang  19.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 
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 
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::PoisonValue::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.
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(layout.getABITypeAlign(type)));
213  offset += CharUnits::fromQuantity(layout.getTypeStoreSize(type));
214 
215  CachedOffsetEnd = Builder.Buffer.size();
216  CachedOffsetFromGlobal = offset;
217 
218  return position;
219 }
220 
221 CharUnits ConstantAggregateBuilderBase::getOffsetFromGlobalTo(size_t end) const{
222  size_t cacheEnd = CachedOffsetEnd;
223  assert(cacheEnd <= end);
224 
225  // Fast path: if the cache is valid, just use it.
226  if (cacheEnd == end) {
227  return CachedOffsetFromGlobal;
228  }
229 
230  // If the cached range ends before the index at which the current
231  // aggregate starts, recurse for the parent.
232  CharUnits offset;
233  if (cacheEnd < Begin) {
234  assert(cacheEnd == 0);
235  assert(Parent && "Begin != 0 for root builder");
236  cacheEnd = Begin;
237  offset = Parent->getOffsetFromGlobalTo(Begin);
238  } else {
239  offset = CachedOffsetFromGlobal;
240  }
241 
242  // Perform simple layout on the elements in cacheEnd..<end.
243  if (cacheEnd != end) {
244  auto &layout = Builder.CGM.getDataLayout();
245  do {
246  llvm::Constant *element = Builder.Buffer[cacheEnd];
247  assert(element != nullptr &&
248  "cannot compute offset when a placeholder is present");
249  llvm::Type *elementType = element->getType();
250  if (!Packed)
251  offset = offset.alignTo(
252  CharUnits::fromQuantity(layout.getABITypeAlign(elementType)));
253  offset += CharUnits::fromQuantity(layout.getTypeStoreSize(elementType));
254  } while (++cacheEnd != end);
255  }
256 
257  // Cache and return.
258  CachedOffsetEnd = cacheEnd;
259  CachedOffsetFromGlobal = offset;
260  return offset;
261 }
262 
263 llvm::Constant *ConstantAggregateBuilderBase::finishArray(llvm::Type *eltTy) {
264  markFinished();
265 
266  auto &buffer = getBuffer();
267  assert((Begin < buffer.size() ||
268  (Begin == buffer.size() && eltTy))
269  && "didn't add any array elements without element type");
270  auto elts = llvm::ArrayRef(buffer).slice(Begin);
271  if (!eltTy) eltTy = elts[0]->getType();
272  auto type = llvm::ArrayType::get(eltTy, elts.size());
273  auto constant = llvm::ConstantArray::get(type, elts);
274  buffer.erase(buffer.begin() + Begin, buffer.end());
275  return constant;
276 }
277 
278 llvm::Constant *
280  markFinished();
281 
282  auto &buffer = getBuffer();
283  auto elts = llvm::ArrayRef(buffer).slice(Begin);
284 
285  if (ty == nullptr && elts.empty())
286  ty = llvm::StructType::get(Builder.CGM.getLLVMContext(), {}, Packed);
287 
288  llvm::Constant *constant;
289  if (ty) {
290  assert(ty->isPacked() == Packed);
291  constant = llvm::ConstantStruct::get(ty, elts);
292  } else {
293  constant = llvm::ConstantStruct::getAnon(elts, Packed);
294  }
295 
296  buffer.erase(buffer.begin() + Begin, buffer.end());
297  return constant;
298 }
target
Definition: SemaSYCL.cpp:45
const char * Data
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:189
static CharUnits fromQuantity(QuantityType Quantity)
fromQuantity - Construct a CharUnits quantity from a raw integer type.
Definition: CharUnits.h:63
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:201
const llvm::DataLayout & getDataLayout() const
llvm::Module & getModule() const
llvm::LLVMContext & getLLVMContext()
llvm::ConstantInt * getSize(CharUnits numChars)
Emit the given number of characters as a value of type size_t.
An opaque class to hold the abstract position of a placeholder.
llvm::SmallVectorImpl< llvm::Constant * > & getBuffer()
llvm::Constant * getAddrOfPosition(llvm::Type *type, size_t position)
Produce an address which points to a position in the aggregate being constructed.
PlaceholderPosition addPlaceholder()
Add a placeholder value to the structure.
void add(llvm::Constant *value)
Add a new value to this initializer.
llvm::Constant * finishArray(llvm::Type *eltTy)
PlaceholderPosition addPlaceholderWithSize(llvm::Type *expectedType)
Add a placeholder, giving the expected type that will be filled in.
void addSize(CharUnits size)
Add an integer value of type size_t.
llvm::Constant * finishStruct(llvm::StructType *structTy)
llvm::Constant * getAddrOfCurrentPosition(llvm::Type *type)
Produce an address which will eventually point to the next position to be filled.
CharUnits getNextOffsetFromGlobal() const
Return the offset from the start of the initializer to the next position, assuming no padding is requ...
llvm::ArrayRef< llvm::Constant * > getGEPIndicesToCurrentPosition(llvm::SmallVectorImpl< llvm::Constant * > &indices)
size_t size() const
Return the number of elements that have been added to this struct or array.
A convenience builder class for complex constant initializers, especially for anonymous global struct...
A "future" for a completed constant initializer, which can be passed around independently of any sub-...
llvm::Type * getType() const
Return the type of the initializer.
void abandon()
Abandon this initializer.
void installInGlobal(llvm::GlobalVariable *global)
Install the initializer into a global variable.
const internal::VariadicAllOfMatcher< Type > type
Matches Types in the clang AST.
RangeSelector name(std::string ID)
Given a node with a "name", (like NamedDecl, DeclRefExpr, CxxCtorInitializer, and TypeLoc) selects th...
The JSON file list parser is used to communicate input to InstallAPI.