1259701Sdim//===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
2259701Sdim//
3259701Sdim//                     The LLVM Compiler Infrastructure
4259701Sdim//
5259701Sdim// This file is distributed under the University of Illinois Open Source
6259701Sdim// License. See LICENSE.TXT for details.
7259701Sdim//
8259701Sdim//===----------------------------------------------------------------------===//
9259701Sdim//
10259701Sdim//  This files defines TypeLocBuilder, a class for building TypeLocs
11259701Sdim//  bottom-up.
12259701Sdim//
13259701Sdim//===----------------------------------------------------------------------===//
14259701Sdim
15259701Sdim#include "TypeLocBuilder.h"
16259701Sdim
17259701Sdimusing namespace clang;
18259701Sdim
19259701Sdimvoid TypeLocBuilder::pushFullCopy(TypeLoc L) {
20259701Sdim  size_t Size = L.getFullDataSize();
21259701Sdim  reserve(Size);
22259701Sdim
23259701Sdim  SmallVector<TypeLoc, 4> TypeLocs;
24259701Sdim  TypeLoc CurTL = L;
25259701Sdim  while (CurTL) {
26259701Sdim    TypeLocs.push_back(CurTL);
27259701Sdim    CurTL = CurTL.getNextTypeLoc();
28259701Sdim  }
29259701Sdim
30259701Sdim  for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) {
31259701Sdim    TypeLoc CurTL = TypeLocs[e-i-1];
32259701Sdim    switch (CurTL.getTypeLocClass()) {
33259701Sdim#define ABSTRACT_TYPELOC(CLASS, PARENT)
34259701Sdim#define TYPELOC(CLASS, PARENT) \
35259701Sdim    case TypeLoc::CLASS: { \
36259701Sdim      CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
37259701Sdim      memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \
38259701Sdim      break; \
39259701Sdim    }
40259701Sdim#include "clang/AST/TypeLocNodes.def"
41259701Sdim    }
42259701Sdim  }
43259701Sdim}
44259701Sdim
45259701Sdimvoid TypeLocBuilder::grow(size_t NewCapacity) {
46259701Sdim  assert(NewCapacity > Capacity);
47259701Sdim
48259701Sdim  // Allocate the new buffer and copy the old data into it.
49259701Sdim  char *NewBuffer = new char[NewCapacity];
50259701Sdim  unsigned NewIndex = Index + NewCapacity - Capacity;
51259701Sdim  memcpy(&NewBuffer[NewIndex],
52259701Sdim         &Buffer[Index],
53259701Sdim         Capacity - Index);
54259701Sdim
55259701Sdim  if (Buffer != InlineBuffer.buffer)
56259701Sdim    delete[] Buffer;
57259701Sdim
58259701Sdim  Buffer = NewBuffer;
59259701Sdim  Capacity = NewCapacity;
60259701Sdim  Index = NewIndex;
61259701Sdim}
62259701Sdim
63259701SdimTypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
64259701Sdim#ifndef NDEBUG
65259701Sdim  QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
66259701Sdim  assert(TLast == LastTy &&
67259701Sdim         "mismatch between last type and new type's inner type");
68259701Sdim  LastTy = T;
69259701Sdim#endif
70259701Sdim
71259701Sdim  assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
72259701Sdim
73259701Sdim  // If we need to grow, grow by a factor of 2.
74259701Sdim  if (LocalSize > Index) {
75259701Sdim    size_t RequiredCapacity = Capacity + (LocalSize - Index);
76259701Sdim    size_t NewCapacity = Capacity * 2;
77259701Sdim    while (RequiredCapacity > NewCapacity)
78259701Sdim      NewCapacity *= 2;
79259701Sdim    grow(NewCapacity);
80259701Sdim  }
81259701Sdim
82259701Sdim  // Because we're adding elements to the TypeLoc backwards, we have to
83259701Sdim  // do some extra work to keep everything aligned appropriately.
84259701Sdim  // FIXME: This algorithm is a absolute mess because every TypeLoc returned
85259701Sdim  // needs to be valid.  Partial TypeLocs are a terrible idea.
86259701Sdim  // FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
87259701Sdim  // hardcode them.
88259701Sdim  if (LocalAlignment == 4) {
89259701Sdim    if (NumBytesAtAlign8 == 0) {
90259701Sdim      NumBytesAtAlign4 += LocalSize;
91259701Sdim    } else {
92259701Sdim      unsigned Padding = NumBytesAtAlign4 % 8;
93259701Sdim      if (Padding == 0) {
94259701Sdim        if (LocalSize % 8 == 0) {
95259701Sdim          // Everything is set: there's no padding and we don't need to add
96259701Sdim          // any.
97259701Sdim        } else {
98259701Sdim          assert(LocalSize % 8 == 4);
99259701Sdim          // No existing padding; add in 4 bytes padding
100259701Sdim          memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
101259701Sdim          Index -= 4;
102259701Sdim        }
103259701Sdim      } else {
104259701Sdim        assert(Padding == 4);
105259701Sdim        if (LocalSize % 8 == 0) {
106259701Sdim          // Everything is set: there's 4 bytes padding and we don't need
107259701Sdim          // to add any.
108259701Sdim        } else {
109259701Sdim          assert(LocalSize % 8 == 4);
110259701Sdim          // There are 4 bytes padding, but we don't need any; remove it.
111259701Sdim          memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
112259701Sdim          Index += 4;
113259701Sdim        }
114259701Sdim      }
115259701Sdim      NumBytesAtAlign4 += LocalSize;
116259701Sdim    }
117259701Sdim  } else if (LocalAlignment == 8) {
118259701Sdim    if (!NumBytesAtAlign8 && NumBytesAtAlign4 % 8 != 0) {
119259701Sdim      // No existing padding and misaligned members; add in 4 bytes padding
120259701Sdim      memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
121259701Sdim      Index -= 4;
122259701Sdim    }
123259701Sdim    // Forget about any padding.
124259701Sdim    NumBytesAtAlign4 = 0;
125259701Sdim    NumBytesAtAlign8 += LocalSize;
126259701Sdim  } else {
127259701Sdim    assert(LocalSize == 0);
128259701Sdim  }
129259701Sdim
130259701Sdim  Index -= LocalSize;
131259701Sdim
132259701Sdim  assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) &&
133259701Sdim         "incorrect data size provided to CreateTypeSourceInfo!");
134259701Sdim
135259701Sdim  return getTemporaryTypeLoc(T);
136259701Sdim}
137