1e9fc377aSDouglas Gregor //===--- LayoutOverrideSource.cpp --Override Record Layouts ---------------===//
2e9fc377aSDouglas Gregor //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e9fc377aSDouglas Gregor //
7e9fc377aSDouglas Gregor //===----------------------------------------------------------------------===//
8e9fc377aSDouglas Gregor #include "clang/Frontend/LayoutOverrideSource.h"
9e9fc377aSDouglas Gregor #include "clang/AST/Decl.h"
10a7d03840SJordan Rose #include "clang/Basic/CharInfo.h"
11e9fc377aSDouglas Gregor #include "llvm/Support/raw_ostream.h"
12e9fc377aSDouglas Gregor #include <fstream>
13e9fc377aSDouglas Gregor #include <string>
14e9fc377aSDouglas Gregor
15e9fc377aSDouglas Gregor using namespace clang;
16e9fc377aSDouglas Gregor
179fc8faf9SAdrian Prantl /// Parse a simple identifier.
parseName(StringRef S)18bf8da9d7SBenjamin Kramer static std::string parseName(StringRef S) {
19601102d2SCorentin Jabot if (S.empty() || !isAsciiIdentifierStart(S[0]))
20a7d03840SJordan Rose return "";
21a7d03840SJordan Rose
22a7d03840SJordan Rose unsigned Offset = 1;
23601102d2SCorentin Jabot while (Offset < S.size() && isAsciiIdentifierContinue(S[Offset]))
24e9fc377aSDouglas Gregor ++Offset;
25e9fc377aSDouglas Gregor
26e9fc377aSDouglas Gregor return S.substr(0, Offset).str();
27e9fc377aSDouglas Gregor }
28e9fc377aSDouglas Gregor
LayoutOverrideSource(StringRef Filename)29f857950dSDmitri Gribenko LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
30e9fc377aSDouglas Gregor std::ifstream Input(Filename.str().c_str());
31e9fc377aSDouglas Gregor if (!Input.is_open())
32e9fc377aSDouglas Gregor return;
33e9fc377aSDouglas Gregor
34e9fc377aSDouglas Gregor // Parse the output of -fdump-record-layouts.
35e9fc377aSDouglas Gregor std::string CurrentType;
36e9fc377aSDouglas Gregor Layout CurrentLayout;
37e9fc377aSDouglas Gregor bool ExpectingType = false;
38e9fc377aSDouglas Gregor
39e9fc377aSDouglas Gregor while (Input.good()) {
40e9fc377aSDouglas Gregor std::string Line;
41e9fc377aSDouglas Gregor getline(Input, Line);
42e9fc377aSDouglas Gregor
43e9fc377aSDouglas Gregor StringRef LineStr(Line);
44e9fc377aSDouglas Gregor
45e9fc377aSDouglas Gregor // Determine whether the following line will start a
46*cf68e1b2SKazu Hirata if (LineStr.contains("*** Dumping AST Record Layout")) {
47e9fc377aSDouglas Gregor // Flush the last type/layout, if there is one.
48e9fc377aSDouglas Gregor if (!CurrentType.empty())
49e9fc377aSDouglas Gregor Layouts[CurrentType] = CurrentLayout;
50e9fc377aSDouglas Gregor CurrentLayout = Layout();
51e9fc377aSDouglas Gregor
52e9fc377aSDouglas Gregor ExpectingType = true;
53e9fc377aSDouglas Gregor continue;
54e9fc377aSDouglas Gregor }
55e9fc377aSDouglas Gregor
56e9fc377aSDouglas Gregor // If we're expecting a type, grab it.
57e9fc377aSDouglas Gregor if (ExpectingType) {
58e9fc377aSDouglas Gregor ExpectingType = false;
59e9fc377aSDouglas Gregor
60e9fc377aSDouglas Gregor StringRef::size_type Pos;
61e9fc377aSDouglas Gregor if ((Pos = LineStr.find("struct ")) != StringRef::npos)
62e9fc377aSDouglas Gregor LineStr = LineStr.substr(Pos + strlen("struct "));
63e9fc377aSDouglas Gregor else if ((Pos = LineStr.find("class ")) != StringRef::npos)
64e9fc377aSDouglas Gregor LineStr = LineStr.substr(Pos + strlen("class "));
65e9fc377aSDouglas Gregor else if ((Pos = LineStr.find("union ")) != StringRef::npos)
66e9fc377aSDouglas Gregor LineStr = LineStr.substr(Pos + strlen("union "));
67e9fc377aSDouglas Gregor else
68e9fc377aSDouglas Gregor continue;
69e9fc377aSDouglas Gregor
70e9fc377aSDouglas Gregor // Find the name of the type.
71e9fc377aSDouglas Gregor CurrentType = parseName(LineStr);
72e9fc377aSDouglas Gregor CurrentLayout = Layout();
73e9fc377aSDouglas Gregor continue;
74e9fc377aSDouglas Gregor }
75e9fc377aSDouglas Gregor
76e9fc377aSDouglas Gregor // Check for the size of the type.
77e9fc377aSDouglas Gregor StringRef::size_type Pos = LineStr.find(" Size:");
78e9fc377aSDouglas Gregor if (Pos != StringRef::npos) {
79e9fc377aSDouglas Gregor // Skip past the " Size:" prefix.
80e9fc377aSDouglas Gregor LineStr = LineStr.substr(Pos + strlen(" Size:"));
81e9fc377aSDouglas Gregor
82e9fc377aSDouglas Gregor unsigned long long Size = 0;
83e9fc377aSDouglas Gregor (void)LineStr.getAsInteger(10, Size);
84e9fc377aSDouglas Gregor CurrentLayout.Size = Size;
85e9fc377aSDouglas Gregor continue;
86e9fc377aSDouglas Gregor }
87e9fc377aSDouglas Gregor
88e9fc377aSDouglas Gregor // Check for the alignment of the type.
89e9fc377aSDouglas Gregor Pos = LineStr.find("Alignment:");
90e9fc377aSDouglas Gregor if (Pos != StringRef::npos) {
91e9fc377aSDouglas Gregor // Skip past the "Alignment:" prefix.
92e9fc377aSDouglas Gregor LineStr = LineStr.substr(Pos + strlen("Alignment:"));
93e9fc377aSDouglas Gregor
94e9fc377aSDouglas Gregor unsigned long long Alignment = 0;
95e9fc377aSDouglas Gregor (void)LineStr.getAsInteger(10, Alignment);
96e9fc377aSDouglas Gregor CurrentLayout.Align = Alignment;
97e9fc377aSDouglas Gregor continue;
98e9fc377aSDouglas Gregor }
99e9fc377aSDouglas Gregor
100e9fc377aSDouglas Gregor // Check for the size/alignment of the type.
101e9fc377aSDouglas Gregor Pos = LineStr.find("sizeof=");
102e9fc377aSDouglas Gregor if (Pos != StringRef::npos) {
103e9fc377aSDouglas Gregor /* Skip past the sizeof= prefix. */
104e9fc377aSDouglas Gregor LineStr = LineStr.substr(Pos + strlen("sizeof="));
105e9fc377aSDouglas Gregor
106e9fc377aSDouglas Gregor // Parse size.
107e9fc377aSDouglas Gregor unsigned long long Size = 0;
108e9fc377aSDouglas Gregor (void)LineStr.getAsInteger(10, Size);
109e9fc377aSDouglas Gregor CurrentLayout.Size = Size;
110e9fc377aSDouglas Gregor
111e9fc377aSDouglas Gregor Pos = LineStr.find("align=");
112e9fc377aSDouglas Gregor if (Pos != StringRef::npos) {
113e9fc377aSDouglas Gregor /* Skip past the align= prefix. */
114e9fc377aSDouglas Gregor LineStr = LineStr.substr(Pos + strlen("align="));
115e9fc377aSDouglas Gregor
116e9fc377aSDouglas Gregor // Parse alignment.
117e9fc377aSDouglas Gregor unsigned long long Alignment = 0;
118e9fc377aSDouglas Gregor (void)LineStr.getAsInteger(10, Alignment);
119e9fc377aSDouglas Gregor CurrentLayout.Align = Alignment;
120e9fc377aSDouglas Gregor }
121e9fc377aSDouglas Gregor
122e9fc377aSDouglas Gregor continue;
123e9fc377aSDouglas Gregor }
124e9fc377aSDouglas Gregor
125e9fc377aSDouglas Gregor // Check for the field offsets of the type.
126e9fc377aSDouglas Gregor Pos = LineStr.find("FieldOffsets: [");
127e9fc377aSDouglas Gregor if (Pos == StringRef::npos)
128e9fc377aSDouglas Gregor continue;
129e9fc377aSDouglas Gregor
130e9fc377aSDouglas Gregor LineStr = LineStr.substr(Pos + strlen("FieldOffsets: ["));
131a7d03840SJordan Rose while (!LineStr.empty() && isDigit(LineStr[0])) {
132e9fc377aSDouglas Gregor // Parse this offset.
133e9fc377aSDouglas Gregor unsigned Idx = 1;
134a7d03840SJordan Rose while (Idx < LineStr.size() && isDigit(LineStr[Idx]))
135e9fc377aSDouglas Gregor ++Idx;
136e9fc377aSDouglas Gregor
137e9fc377aSDouglas Gregor unsigned long long Offset = 0;
138e9fc377aSDouglas Gregor (void)LineStr.substr(0, Idx).getAsInteger(10, Offset);
139e9fc377aSDouglas Gregor
140e9fc377aSDouglas Gregor CurrentLayout.FieldOffsets.push_back(Offset);
141e9fc377aSDouglas Gregor
142e9fc377aSDouglas Gregor // Skip over this offset, the following comma, and any spaces.
143e9fc377aSDouglas Gregor LineStr = LineStr.substr(Idx + 1);
144a7d03840SJordan Rose while (!LineStr.empty() && isWhitespace(LineStr[0]))
145e9fc377aSDouglas Gregor LineStr = LineStr.substr(1);
146e9fc377aSDouglas Gregor }
147e9fc377aSDouglas Gregor }
148e9fc377aSDouglas Gregor
149e9fc377aSDouglas Gregor // Flush the last type/layout, if there is one.
150e9fc377aSDouglas Gregor if (!CurrentType.empty())
151e9fc377aSDouglas Gregor Layouts[CurrentType] = CurrentLayout;
152e9fc377aSDouglas Gregor }
153e9fc377aSDouglas Gregor
154e9fc377aSDouglas Gregor bool
layoutRecordType(const RecordDecl * Record,uint64_t & Size,uint64_t & Alignment,llvm::DenseMap<const FieldDecl *,uint64_t> & FieldOffsets,llvm::DenseMap<const CXXRecordDecl *,CharUnits> & BaseOffsets,llvm::DenseMap<const CXXRecordDecl *,CharUnits> & VirtualBaseOffsets)155e9fc377aSDouglas Gregor LayoutOverrideSource::layoutRecordType(const RecordDecl *Record,
156e9fc377aSDouglas Gregor uint64_t &Size, uint64_t &Alignment,
157e9fc377aSDouglas Gregor llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
158e9fc377aSDouglas Gregor llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
159e9fc377aSDouglas Gregor llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
160e9fc377aSDouglas Gregor {
161e9fc377aSDouglas Gregor // We can't override unnamed declarations.
162e9fc377aSDouglas Gregor if (!Record->getIdentifier())
163e9fc377aSDouglas Gregor return false;
164e9fc377aSDouglas Gregor
165e9fc377aSDouglas Gregor // Check whether we have a layout for this record.
166e9fc377aSDouglas Gregor llvm::StringMap<Layout>::iterator Known = Layouts.find(Record->getName());
167e9fc377aSDouglas Gregor if (Known == Layouts.end())
168e9fc377aSDouglas Gregor return false;
169e9fc377aSDouglas Gregor
170e9fc377aSDouglas Gregor // Provide field layouts.
171e9fc377aSDouglas Gregor unsigned NumFields = 0;
172e9fc377aSDouglas Gregor for (RecordDecl::field_iterator F = Record->field_begin(),
173e9fc377aSDouglas Gregor FEnd = Record->field_end();
174e9fc377aSDouglas Gregor F != FEnd; ++F, ++NumFields) {
175e9fc377aSDouglas Gregor if (NumFields >= Known->second.FieldOffsets.size())
176e9fc377aSDouglas Gregor continue;
177e9fc377aSDouglas Gregor
17840ed2973SDavid Blaikie FieldOffsets[*F] = Known->second.FieldOffsets[NumFields];
179e9fc377aSDouglas Gregor }
180e9fc377aSDouglas Gregor
181e9fc377aSDouglas Gregor // Wrong number of fields.
182e9fc377aSDouglas Gregor if (NumFields != Known->second.FieldOffsets.size())
183e9fc377aSDouglas Gregor return false;
184e9fc377aSDouglas Gregor
185e9fc377aSDouglas Gregor Size = Known->second.Size;
186e9fc377aSDouglas Gregor Alignment = Known->second.Align;
187e9fc377aSDouglas Gregor return true;
188e9fc377aSDouglas Gregor }
189e9fc377aSDouglas Gregor
dump()190cdae941eSYaron Keren LLVM_DUMP_METHOD void LayoutOverrideSource::dump() {
191f857950dSDmitri Gribenko raw_ostream &OS = llvm::errs();
192e9fc377aSDouglas Gregor for (llvm::StringMap<Layout>::iterator L = Layouts.begin(),
193e9fc377aSDouglas Gregor LEnd = Layouts.end();
194e9fc377aSDouglas Gregor L != LEnd; ++L) {
195e9fc377aSDouglas Gregor OS << "Type: blah " << L->first() << '\n';
196e9fc377aSDouglas Gregor OS << " Size:" << L->second.Size << '\n';
197e9fc377aSDouglas Gregor OS << " Alignment:" << L->second.Align << '\n';
198e9fc377aSDouglas Gregor OS << " FieldOffsets: [";
199e9fc377aSDouglas Gregor for (unsigned I = 0, N = L->second.FieldOffsets.size(); I != N; ++I) {
200e9fc377aSDouglas Gregor if (I)
201e9fc377aSDouglas Gregor OS << ", ";
202e9fc377aSDouglas Gregor OS << L->second.FieldOffsets[I];
203e9fc377aSDouglas Gregor }
204e9fc377aSDouglas Gregor OS << "]\n";
205e9fc377aSDouglas Gregor }
206e9fc377aSDouglas Gregor }
207e9fc377aSDouglas Gregor
208