1251875Speter//===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
2251875Speter//
3251875Speter// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4251875Speter// See https://llvm.org/LICENSE.txt for license information.
5251875Speter// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6251875Speter//
7251875Speter//===----------------------------------------------------------------------===//
8251875Speter//
9251875Speter//  This files defines TypeLocBuilder, a class for building TypeLocs
10251875Speter//  bottom-up.
11251875Speter//
12251875Speter//===----------------------------------------------------------------------===//
13251875Speter
14251875Speter#include "TypeLocBuilder.h"
15251875Speter
16251875Speterusing namespace clang;
17251875Speter
18251875Spetervoid TypeLocBuilder::pushFullCopy(TypeLoc L) {
19251875Speter  size_t Size = L.getFullDataSize();
20251875Speter  reserve(Size);
21251875Speter
22251875Speter  SmallVector<TypeLoc, 4> TypeLocs;
23251875Speter  TypeLoc CurTL = L;
24251875Speter  while (CurTL) {
25251875Speter    TypeLocs.push_back(CurTL);
26251875Speter    CurTL = CurTL.getNextTypeLoc();
27251875Speter  }
28251875Speter
29251875Speter  for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) {
30251875Speter    TypeLoc CurTL = TypeLocs[e-i-1];
31251875Speter    switch (CurTL.getTypeLocClass()) {
32251875Speter#define ABSTRACT_TYPELOC(CLASS, PARENT)
33251875Speter#define TYPELOC(CLASS, PARENT) \
34251875Speter    case TypeLoc::CLASS: { \
35251875Speter      CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
36251875Speter      memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \
37251875Speter      break; \
38251875Speter    }
39251875Speter#include "clang/AST/TypeLocNodes.def"
40251875Speter    }
41251875Speter  }
42251875Speter}
43251875Speter
44251875Spetervoid TypeLocBuilder::pushTrivial(ASTContext &Context, QualType T,
45251875Speter                                 SourceLocation Loc) {
46251875Speter  auto L = TypeLoc(T, nullptr);
47251875Speter  reserve(L.getFullDataSize());
48251875Speter
49251875Speter  SmallVector<TypeLoc, 4> TypeLocs;
50251875Speter  for (auto CurTL = L; CurTL; CurTL = CurTL.getNextTypeLoc())
51251875Speter    TypeLocs.push_back(CurTL);
52251875Speter
53251875Speter  for (const auto &CurTL : llvm::reverse(TypeLocs)) {
54251875Speter    switch (CurTL.getTypeLocClass()) {
55251875Speter#define ABSTRACT_TYPELOC(CLASS, PARENT)
56251875Speter#define TYPELOC(CLASS, PARENT)                                                 \
57251875Speter  case TypeLoc::CLASS: {                                                       \
58251875Speter    auto NewTL = push<class CLASS##TypeLoc>(CurTL.getType());                  \
59251875Speter    NewTL.initializeLocal(Context, Loc);                                       \
60251875Speter    break;                                                                     \
61251875Speter  }
62251875Speter#include "clang/AST/TypeLocNodes.def"
63251875Speter    }
64251875Speter  }
65251875Speter}
66251875Speter
67251875Spetervoid TypeLocBuilder::grow(size_t NewCapacity) {
68251875Speter  assert(NewCapacity > Capacity);
69251875Speter
70251875Speter  // Allocate the new buffer and copy the old data into it.
71251875Speter  char *NewBuffer = new char[NewCapacity];
72251875Speter  unsigned NewIndex = Index + NewCapacity - Capacity;
73251875Speter  memcpy(&NewBuffer[NewIndex],
74251875Speter         &Buffer[Index],
75251875Speter         Capacity - Index);
76251875Speter
77251875Speter  if (Buffer != InlineBuffer)
78251875Speter    delete[] Buffer;
79251875Speter
80251875Speter  Buffer = NewBuffer;
81251875Speter  Capacity = NewCapacity;
82251875Speter  Index = NewIndex;
83251875Speter}
84251875Speter
85251875SpeterTypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
86251875Speter#ifndef NDEBUG
87251875Speter  QualType TLast = TypeLoc(T, nullptr).getNextTypeLoc().getType();
88251875Speter  assert(TLast == LastTy &&
89251875Speter         "mismatch between last type and new type's inner type");
90251875Speter  LastTy = T;
91251875Speter#endif
92251875Speter
93251875Speter  assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
94251875Speter
95251875Speter  // If we need to grow, grow by a factor of 2.
96251875Speter  if (LocalSize > Index) {
97251875Speter    size_t RequiredCapacity = Capacity + (LocalSize - Index);
98251875Speter    size_t NewCapacity = Capacity * 2;
99251875Speter    while (RequiredCapacity > NewCapacity)
100251875Speter      NewCapacity *= 2;
101251875Speter    grow(NewCapacity);
102251875Speter  }
103251875Speter
104251875Speter  // Because we're adding elements to the TypeLoc backwards, we have to
105251875Speter  // do some extra work to keep everything aligned appropriately.
106251875Speter  // FIXME: This algorithm is a absolute mess because every TypeLoc returned
107251875Speter  // needs to be valid.  Partial TypeLocs are a terrible idea.
108251875Speter  // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
109251875Speter  // hardcode them.
110251875Speter  if (LocalAlignment == 4) {
111251875Speter    if (!AtAlign8) {
112251875Speter      NumBytesAtAlign4 += LocalSize;
113251875Speter    } else {
114251875Speter      unsigned Padding = NumBytesAtAlign4 % 8;
115251875Speter      if (Padding == 0) {
116251875Speter        if (LocalSize % 8 == 0) {
117251875Speter          // Everything is set: there's no padding and we don't need to add
118251875Speter          // any.
119251875Speter        } else {
120251875Speter          assert(LocalSize % 8 == 4);
121251875Speter          // No existing padding; add in 4 bytes padding
122251875Speter          memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
123251875Speter          Index -= 4;
124251875Speter        }
125251875Speter      } else {
126251875Speter        assert(Padding == 4);
127251875Speter        if (LocalSize % 8 == 0) {
128251875Speter          // Everything is set: there's 4 bytes padding and we don't need
129251875Speter          // to add any.
130251875Speter        } else {
131251875Speter          assert(LocalSize % 8 == 4);
132251875Speter          // There are 4 bytes padding, but we don't need any; remove it.
133251875Speter          memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
134251875Speter          Index += 4;
135251875Speter        }
136251875Speter      }
137251875Speter      NumBytesAtAlign4 += LocalSize;
138251875Speter    }
139251875Speter  } else if (LocalAlignment == 8) {
140251875Speter    if (!AtAlign8) {
141251875Speter      // We have not seen any 8-byte aligned element yet. We insert a padding
142251875Speter      // only if the new Index is not 8-byte-aligned.
143251875Speter      if ((Index - LocalSize) % 8 != 0) {
144251875Speter        memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
145251875Speter        Index -= 4;
146251875Speter      }
147251875Speter    } else {
148251875Speter      unsigned Padding = NumBytesAtAlign4 % 8;
149251875Speter      if (Padding == 0) {
150251875Speter        if (LocalSize % 8 == 0) {
151251875Speter          // Everything is set: there's no padding and we don't need to add
152251875Speter          // any.
153251875Speter        } else {
154251875Speter          assert(LocalSize % 8 == 4);
155251875Speter          // No existing padding; add in 4 bytes padding
156251875Speter          memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
157251875Speter          Index -= 4;
158251875Speter        }
159251875Speter      } else {
160251875Speter        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