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