TypeLocBuilder.cpp revision 360784
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::grow(size_t NewCapacity) {
45  assert(NewCapacity > Capacity);
46
47  // Allocate the new buffer and copy the old data into it.
48  char *NewBuffer = new char[NewCapacity];
49  unsigned NewIndex = Index + NewCapacity - Capacity;
50  memcpy(&NewBuffer[NewIndex],
51         &Buffer[Index],
52         Capacity - Index);
53
54  if (Buffer != InlineBuffer)
55    delete[] Buffer;
56
57  Buffer = NewBuffer;
58  Capacity = NewCapacity;
59  Index = NewIndex;
60}
61
62TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
63#ifndef NDEBUG
64  QualType TLast = TypeLoc(T, nullptr).getNextTypeLoc().getType();
65  assert(TLast == LastTy &&
66         "mismatch between last type and new type's inner type");
67  LastTy = T;
68#endif
69
70  assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
71
72  // If we need to grow, grow by a factor of 2.
73  if (LocalSize > Index) {
74    size_t RequiredCapacity = Capacity + (LocalSize - Index);
75    size_t NewCapacity = Capacity * 2;
76    while (RequiredCapacity > NewCapacity)
77      NewCapacity *= 2;
78    grow(NewCapacity);
79  }
80
81  // Because we're adding elements to the TypeLoc backwards, we have to
82  // do some extra work to keep everything aligned appropriately.
83  // FIXME: This algorithm is a absolute mess because every TypeLoc returned
84  // needs to be valid.  Partial TypeLocs are a terrible idea.
85  // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
86  // hardcode them.
87  if (LocalAlignment == 4) {
88    if (NumBytesAtAlign8 == 0) {
89      NumBytesAtAlign4 += LocalSize;
90    } else {
91      unsigned Padding = NumBytesAtAlign4 % 8;
92      if (Padding == 0) {
93        if (LocalSize % 8 == 0) {
94          // Everything is set: there's no padding and we don't need to add
95          // any.
96        } else {
97          assert(LocalSize % 8 == 4);
98          // No existing padding; add in 4 bytes padding
99          memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
100          Index -= 4;
101        }
102      } else {
103        assert(Padding == 4);
104        if (LocalSize % 8 == 0) {
105          // Everything is set: there's 4 bytes padding and we don't need
106          // to add any.
107        } else {
108          assert(LocalSize % 8 == 4);
109          // There are 4 bytes padding, but we don't need any; remove it.
110          memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
111          Index += 4;
112        }
113      }
114      NumBytesAtAlign4 += LocalSize;
115    }
116  } else if (LocalAlignment == 8) {
117    if (NumBytesAtAlign8 == 0) {
118      // We have not seen any 8-byte aligned element yet. We insert a padding
119      // only if the new Index is not 8-byte-aligned.
120      if ((Index - LocalSize) % 8 != 0) {
121        memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
122        Index -= 4;
123      }
124    } else {
125      unsigned Padding = NumBytesAtAlign4 % 8;
126      if (Padding == 0) {
127        if (LocalSize % 8 == 0) {
128          // Everything is set: there's no padding and we don't need to add
129          // any.
130        } else {
131          assert(LocalSize % 8 == 4);
132          // No existing padding; add in 4 bytes padding
133          memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
134          Index -= 4;
135        }
136      } else {
137        assert(Padding == 4);
138        if (LocalSize % 8 == 0) {
139          // Everything is set: there's 4 bytes padding and we don't need
140          // to add any.
141        } else {
142          assert(LocalSize % 8 == 4);
143          // There are 4 bytes padding, but we don't need any; remove it.
144          memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
145          Index += 4;
146        }
147      }
148    }
149
150    // Forget about any padding.
151    NumBytesAtAlign4 = 0;
152    NumBytesAtAlign8 += LocalSize;
153  } else {
154    assert(LocalSize == 0);
155  }
156
157  Index -= LocalSize;
158
159  assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) &&
160         "incorrect data size provided to CreateTypeSourceInfo!");
161
162  return getTemporaryTypeLoc(T);
163}
164