//===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This files defines TypeLocBuilder, a class for building TypeLocs
// bottom-up.
//
//===----------------------------------------------------------------------===//
#include "TypeLocBuilder.h"
using namespace clang;
void TypeLocBuilder::pushFullCopy(TypeLoc L) {
size_t Size = L.getFullDataSize();
reserve(Size);
SmallVector<TypeLoc, 4> TypeLocs;
TypeLoc CurTL = L;
while (CurTL) {
TypeLocs.push_back(CurTL);
CurTL = CurTL.getNextTypeLoc();
}
for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) {
TypeLoc CurTL = TypeLocs[e-i-1];
switch (CurTL.getTypeLocClass()) {
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
case TypeLoc::CLASS: { \
CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \
break; \
}
#include "clang/AST/TypeLocNodes.def"
}
}
}
void TypeLocBuilder::grow(size_t NewCapacity) {
assert(NewCapacity > Capacity);
// Allocate the new buffer and copy the old data into it.
char *NewBuffer = new char[NewCapacity];
unsigned NewIndex = Index + NewCapacity - Capacity;
memcpy(&NewBuffer[NewIndex],
&Buffer[Index],
Capacity - Index);
if (Buffer != InlineBuffer)
delete[] Buffer;
Buffer = NewBuffer;
Capacity = NewCapacity;
Index = NewIndex;
}
TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
#ifndef NDEBUG
QualType TLast = TypeLoc(T, nullptr).getNextTypeLoc().getType();
assert(TLast == LastTy &&
"mismatch between last type and new type's inner type");
LastTy = T;
#endif
assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
// If we need to grow, grow by a factor of 2.
if (LocalSize > Index) {
size_t RequiredCapacity = Capacity + (LocalSize - Index);
size_t NewCapacity = Capacity * 2;
while (RequiredCapacity > NewCapacity)
NewCapacity *= 2;
grow(NewCapacity);
}
// Because we're adding elements to the TypeLoc backwards, we have to
// do some extra work to keep everything aligned appropriately.
// FIXME: This algorithm is a absolute mess because every TypeLoc returned
// needs to be valid. Partial TypeLocs are a terrible idea.
// FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
// hardcode them.
if (LocalAlignment == 4) {
if (NumBytesAtAlign8 == 0) {
NumBytesAtAlign4 += LocalSize;
} else {
unsigned Padding = NumBytesAtAlign4 % 8;
if (Padding == 0) {
if (LocalSize % 8 == 0) {
// Everything is set: there's no padding and we don't need to add
// any.
} else {
assert(LocalSize % 8 == 4);
// No existing padding; add in 4 bytes padding
memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
Index -= 4;
}
} else {
assert(Padding == 4);
if (LocalSize % 8 == 0) {
// Everything is set: there's 4 bytes padding and we don't need
// to add any.
} else {
assert(LocalSize % 8 == 4);
// There are 4 bytes padding, but we don't need any; remove it.
memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
Index += 4;
}
}
NumBytesAtAlign4 += LocalSize;
}
} else if (LocalAlignment == 8) {
if (NumBytesAtAlign8 == 0) {
// We have not seen any 8-byte aligned element yet. We insert a padding
// only if the new Index is not 8-byte-aligned.
if ((Index - LocalSize) % 8 != 0) {
memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
Index -= 4;
}
} else {
unsigned Padding = NumBytesAtAlign4 % 8;
if (Padding == 0) {
if (LocalSize % 8 == 0) {
// Everything is set: there's no padding and we don't need to add
// any.
} else {
assert(LocalSize % 8 == 4);
// No existing padding; add in 4 bytes padding
memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
Index -= 4;
}
} else {
assert(Padding == 4);
if (LocalSize % 8 == 0) {
// Everything is set: there's 4 bytes padding and we don't need
// to add any.
} else {
assert(LocalSize % 8 == 4);
// There are 4 bytes padding, but we don't need any; remove it.
memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
Index += 4;
}
}
}
// Forget about any padding.
NumBytesAtAlign4 = 0;
NumBytesAtAlign8 += LocalSize;
} else {
assert(LocalSize == 0);
}
Index -= LocalSize;
assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) &&
"incorrect data size provided to CreateTypeSourceInfo!");
return getTemporaryTypeLoc(T);
}