| 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(Requested: Size); |
| 21 | |
| 22 | SmallVector<TypeLoc, 4> TypeLocs; |
| 23 | TypeLoc CurTL = L; |
| 24 | while (CurTL) { |
| 25 | TypeLocs.push_back(Elt: 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::pushTrivial(ASTContext &Context, QualType T, |
| 45 | SourceLocation Loc) { |
| 46 | auto L = TypeLoc(T, nullptr); |
| 47 | reserve(Requested: L.getFullDataSize()); |
| 48 | |
| 49 | SmallVector<TypeLoc, 4> TypeLocs; |
| 50 | for (auto CurTL = L; CurTL; CurTL = CurTL.getNextTypeLoc()) |
| 51 | TypeLocs.push_back(Elt: CurTL); |
| 52 | |
| 53 | for (const auto &CurTL : llvm::reverse(C&: 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 | |
| 67 | void 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(dest: &NewBuffer[NewIndex], |
| 74 | src: &Buffer[Index], |
| 75 | n: Capacity - Index); |
| 76 | |
| 77 | if (Buffer != InlineBuffer) |
| 78 | delete[] Buffer; |
| 79 | |
| 80 | Buffer = NewBuffer; |
| 81 | Capacity = NewCapacity; |
| 82 | Index = NewIndex; |
| 83 | } |
| 84 | |
| 85 | TypeLoc 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(dest: &Buffer[Index - 4], src: &Buffer[Index], n: 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(dest: &Buffer[Index + 4], src: &Buffer[Index], n: 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(dest: &Buffer[Index - 4], src: &Buffer[Index], n: 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(dest: &Buffer[Index - 4], src: &Buffer[Index], n: 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(dest: &Buffer[Index + 4], src: &Buffer[Index], n: 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 | |