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