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 
16 using namespace clang;
17 
18 void 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 
44 void 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 
62 TypeLoc 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