1//===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
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 files defines TypeLocBuilder, a class for building TypeLocs
10//  bottom-up.
11//
12//===----------------------------------------------------------------------===//
13
14#include "TypeLocBuilder.h"
15
16using namespace clang;
17
18void TypeLocBuilder::pushFullCopy(TypeLoc L) {
19  size_t Size = L.getFullDataSize();
20  reserve(Size);
21
22  SmallVector<TypeLoc, 4> TypeLocs;
23  TypeLoc CurTL = L;
24  while (CurTL) {
25    TypeLocs.push_back(CurTL);
26    CurTL = CurTL.getNextTypeLoc();
27  }
28
29  for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) {
30    TypeLoc CurTL = TypeLocs[e-i-1];
31    switch (CurTL.getTypeLocClass()) {
32#define ABSTRACT_TYPELOC(CLASS, PARENT)
33#define TYPELOC(CLASS, PARENT) \
34    case TypeLoc::CLASS: { \
35      CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
36      memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \
37      break; \
38    }
39#include "clang/AST/TypeLocNodes.def"
40    }
41  }
42}
43
44void TypeLocBuilder::pushTrivial(ASTContext &Context, QualType T,
45                                 SourceLocation Loc) {
46  auto L = TypeLoc(T, nullptr);
47  reserve(L.getFullDataSize());
48
49  SmallVector<TypeLoc, 4> TypeLocs;
50  for (auto CurTL = L; CurTL; CurTL = CurTL.getNextTypeLoc())
51    TypeLocs.push_back(CurTL);
52
53  for (const auto &CurTL : llvm::reverse(TypeLocs)) {
54    switch (CurTL.getTypeLocClass()) {
55#define ABSTRACT_TYPELOC(CLASS, PARENT)
56#define TYPELOC(CLASS, PARENT)                                                 \
57  case TypeLoc::CLASS: {                                                       \
58    auto NewTL = push<class CLASS##TypeLoc>(CurTL.getType());                  \
59    NewTL.initializeLocal(Context, Loc);                                       \
60    break;                                                                     \
61  }
62#include "clang/AST/TypeLocNodes.def"
63    }
64  }
65}
66
67void TypeLocBuilder::grow(size_t NewCapacity) {
68  assert(NewCapacity > Capacity);
69
70  // Allocate the new buffer and copy the old data into it.
71  char *NewBuffer = new char[NewCapacity];
72  unsigned NewIndex = Index + NewCapacity - Capacity;
73  memcpy(&NewBuffer[NewIndex],
74         &Buffer[Index],
75         Capacity - Index);
76
77  if (Buffer != InlineBuffer)
78    delete[] Buffer;
79
80  Buffer = NewBuffer;
81  Capacity = NewCapacity;
82  Index = NewIndex;
83}
84
85TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
86#ifndef NDEBUG
87  QualType TLast = TypeLoc(T, nullptr).getNextTypeLoc().getType();
88  assert(TLast == LastTy &&
89         "mismatch between last type and new type's inner type");
90  LastTy = T;
91#endif
92
93  assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
94
95  // If we need to grow, grow by a factor of 2.
96  if (LocalSize > Index) {
97    size_t RequiredCapacity = Capacity + (LocalSize - Index);
98    size_t NewCapacity = Capacity * 2;
99    while (RequiredCapacity > NewCapacity)
100      NewCapacity *= 2;
101    grow(NewCapacity);
102  }
103
104  // Because we're adding elements to the TypeLoc backwards, we have to
105  // do some extra work to keep everything aligned appropriately.
106  // FIXME: This algorithm is a absolute mess because every TypeLoc returned
107  // needs to be valid.  Partial TypeLocs are a terrible idea.
108  // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
109  // hardcode them.
110  if (LocalAlignment == 4) {
111    if (!AtAlign8) {
112      NumBytesAtAlign4 += LocalSize;
113    } else {
114      unsigned Padding = NumBytesAtAlign4 % 8;
115      if (Padding == 0) {
116        if (LocalSize % 8 == 0) {
117          // Everything is set: there's no padding and we don't need to add
118          // any.
119        } else {
120          assert(LocalSize % 8 == 4);
121          // No existing padding; add in 4 bytes padding
122          memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
123          Index -= 4;
124        }
125      } else {
126        assert(Padding == 4);
127        if (LocalSize % 8 == 0) {
128          // Everything is set: there's 4 bytes padding and we don't need
129          // to add any.
130        } else {
131          assert(LocalSize % 8 == 4);
132          // There are 4 bytes padding, but we don't need any; remove it.
133          memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
134          Index += 4;
135        }
136      }
137      NumBytesAtAlign4 += LocalSize;
138    }
139  } else if (LocalAlignment == 8) {
140    if (!AtAlign8) {
141      // We have not seen any 8-byte aligned element yet. We insert a padding
142      // only if the new Index is not 8-byte-aligned.
143      if ((Index - LocalSize) % 8 != 0) {
144        memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
145        Index -= 4;
146      }
147    } else {
148      unsigned Padding = NumBytesAtAlign4 % 8;
149      if (Padding == 0) {
150        if (LocalSize % 8 == 0) {
151          // Everything is set: there's no padding and we don't need to add
152          // any.
153        } else {
154          assert(LocalSize % 8 == 4);
155          // No existing padding; add in 4 bytes padding
156          memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
157          Index -= 4;
158        }
159      } else {
160        assert(Padding == 4);
161        if (LocalSize % 8 == 0) {
162          // Everything is set: there's 4 bytes padding and we don't need
163          // to add any.
164        } else {
165          assert(LocalSize % 8 == 4);
166          // There are 4 bytes padding, but we don't need any; remove it.
167          memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
168          Index += 4;
169        }
170      }
171    }
172
173    // Forget about any padding.
174    NumBytesAtAlign4 = 0;
175    AtAlign8 = true;
176  } else {
177    assert(LocalSize == 0);
178  }
179
180  Index -= LocalSize;
181
182  assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) &&
183         "incorrect data size provided to CreateTypeSourceInfo!");
184
185  return getTemporaryTypeLoc(T);
186}
187