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.buffer)
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