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