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
18using namespace clang;
19using namespace CodeGen;
20
21llvm::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
30void 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
38void 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
51ConstantInitFuture
52ConstantInitBuilderBase::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.
59inline 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
66llvm::GlobalVariable *
67ConstantInitBuilderBase::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
87void ConstantInitBuilderBase::setGlobalInitializer(llvm::GlobalVariable *GV,
88                                                   llvm::Constant *initializer){
89  GV->setInitializer(initializer);
90
91  if (!SelfReferences.empty())
92    resolveSelfReferences(GV);
93}
94
95void 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
107void 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
124void ConstantAggregateBuilderBase::addSize(CharUnits size) {
125  add(Builder.CGM.getSize(size));
126}
127
128llvm::Constant *
129ConstantAggregateBuilderBase::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
147llvm::Constant *
148ConstantAggregateBuilderBase::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
161void 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
181ConstantAggregateBuilderBase::PlaceholderPosition
182ConstantAggregateBuilderBase::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
202CharUnits 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
244llvm::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
259llvm::Constant *
260ConstantAggregateBuilderBase::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