xref: /freebsd-src/contrib/llvm-project/clang/lib/Frontend/LayoutOverrideSource.cpp (revision 647cbc5de815c5651677bf8582797f716ec7b48d)
10b57cec5SDimitry Andric //===--- LayoutOverrideSource.cpp --Override Record Layouts ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric #include "clang/Frontend/LayoutOverrideSource.h"
90b57cec5SDimitry Andric #include "clang/AST/Decl.h"
1006c3fb27SDimitry Andric #include "clang/AST/DeclCXX.h"
110b57cec5SDimitry Andric #include "clang/Basic/CharInfo.h"
120b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
130b57cec5SDimitry Andric #include <fstream>
140b57cec5SDimitry Andric #include <string>
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric using namespace clang;
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric /// Parse a simple identifier.
parseName(StringRef S)190b57cec5SDimitry Andric static std::string parseName(StringRef S) {
20349cc55cSDimitry Andric   if (S.empty() || !isAsciiIdentifierStart(S[0]))
210b57cec5SDimitry Andric     return "";
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric   unsigned Offset = 1;
24349cc55cSDimitry Andric   while (Offset < S.size() && isAsciiIdentifierContinue(S[Offset]))
250b57cec5SDimitry Andric     ++Offset;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric   return S.substr(0, Offset).str();
280b57cec5SDimitry Andric }
290b57cec5SDimitry Andric 
3006c3fb27SDimitry Andric /// Parse an unsigned integer and move S to the next non-digit character.
parseUnsigned(StringRef & S,unsigned long long & ULL)3106c3fb27SDimitry Andric static bool parseUnsigned(StringRef &S, unsigned long long &ULL) {
3206c3fb27SDimitry Andric   if (S.empty() || !isDigit(S[0]))
3306c3fb27SDimitry Andric     return false;
3406c3fb27SDimitry Andric   unsigned Idx = 1;
3506c3fb27SDimitry Andric   while (Idx < S.size() && isDigit(S[Idx]))
3606c3fb27SDimitry Andric     ++Idx;
3706c3fb27SDimitry Andric   (void)S.substr(0, Idx).getAsInteger(10, ULL);
3806c3fb27SDimitry Andric   S = S.substr(Idx);
3906c3fb27SDimitry Andric   return true;
4006c3fb27SDimitry Andric }
4106c3fb27SDimitry Andric 
LayoutOverrideSource(StringRef Filename)420b57cec5SDimitry Andric LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
430b57cec5SDimitry Andric   std::ifstream Input(Filename.str().c_str());
440b57cec5SDimitry Andric   if (!Input.is_open())
450b57cec5SDimitry Andric     return;
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   // Parse the output of -fdump-record-layouts.
480b57cec5SDimitry Andric   std::string CurrentType;
490b57cec5SDimitry Andric   Layout CurrentLayout;
500b57cec5SDimitry Andric   bool ExpectingType = false;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   while (Input.good()) {
530b57cec5SDimitry Andric     std::string Line;
540b57cec5SDimitry Andric     getline(Input, Line);
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric     StringRef LineStr(Line);
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric     // Determine whether the following line will start a
59349cc55cSDimitry Andric     if (LineStr.contains("*** Dumping AST Record Layout")) {
600b57cec5SDimitry Andric       // Flush the last type/layout, if there is one.
610b57cec5SDimitry Andric       if (!CurrentType.empty())
620b57cec5SDimitry Andric         Layouts[CurrentType] = CurrentLayout;
630b57cec5SDimitry Andric       CurrentLayout = Layout();
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric       ExpectingType = true;
660b57cec5SDimitry Andric       continue;
670b57cec5SDimitry Andric     }
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric     // If we're expecting a type, grab it.
700b57cec5SDimitry Andric     if (ExpectingType) {
710b57cec5SDimitry Andric       ExpectingType = false;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric       StringRef::size_type Pos;
740b57cec5SDimitry Andric       if ((Pos = LineStr.find("struct ")) != StringRef::npos)
750b57cec5SDimitry Andric         LineStr = LineStr.substr(Pos + strlen("struct "));
760b57cec5SDimitry Andric       else if ((Pos = LineStr.find("class ")) != StringRef::npos)
770b57cec5SDimitry Andric         LineStr = LineStr.substr(Pos + strlen("class "));
780b57cec5SDimitry Andric       else if ((Pos = LineStr.find("union ")) != StringRef::npos)
790b57cec5SDimitry Andric         LineStr = LineStr.substr(Pos + strlen("union "));
800b57cec5SDimitry Andric       else
810b57cec5SDimitry Andric         continue;
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric       // Find the name of the type.
840b57cec5SDimitry Andric       CurrentType = parseName(LineStr);
850b57cec5SDimitry Andric       CurrentLayout = Layout();
860b57cec5SDimitry Andric       continue;
870b57cec5SDimitry Andric     }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric     // Check for the size of the type.
900b57cec5SDimitry Andric     StringRef::size_type Pos = LineStr.find(" Size:");
910b57cec5SDimitry Andric     if (Pos != StringRef::npos) {
920b57cec5SDimitry Andric       // Skip past the " Size:" prefix.
930b57cec5SDimitry Andric       LineStr = LineStr.substr(Pos + strlen(" Size:"));
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric       unsigned long long Size = 0;
9606c3fb27SDimitry Andric       if (parseUnsigned(LineStr, Size))
970b57cec5SDimitry Andric         CurrentLayout.Size = Size;
980b57cec5SDimitry Andric       continue;
990b57cec5SDimitry Andric     }
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric     // Check for the alignment of the type.
1020b57cec5SDimitry Andric     Pos = LineStr.find("Alignment:");
1030b57cec5SDimitry Andric     if (Pos != StringRef::npos) {
1040b57cec5SDimitry Andric       // Skip past the "Alignment:" prefix.
1050b57cec5SDimitry Andric       LineStr = LineStr.substr(Pos + strlen("Alignment:"));
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric       unsigned long long Alignment = 0;
10806c3fb27SDimitry Andric       if (parseUnsigned(LineStr, Alignment))
1090b57cec5SDimitry Andric         CurrentLayout.Align = Alignment;
1100b57cec5SDimitry Andric       continue;
1110b57cec5SDimitry Andric     }
1120b57cec5SDimitry Andric 
11306c3fb27SDimitry Andric     // Check for the size/alignment of the type. The number follows "size=" or
11406c3fb27SDimitry Andric     // "align=" indicates number of bytes.
1150b57cec5SDimitry Andric     Pos = LineStr.find("sizeof=");
1160b57cec5SDimitry Andric     if (Pos != StringRef::npos) {
1170b57cec5SDimitry Andric       /* Skip past the sizeof= prefix. */
1180b57cec5SDimitry Andric       LineStr = LineStr.substr(Pos + strlen("sizeof="));
1190b57cec5SDimitry Andric 
1200b57cec5SDimitry Andric       // Parse size.
1210b57cec5SDimitry Andric       unsigned long long Size = 0;
12206c3fb27SDimitry Andric       if (parseUnsigned(LineStr, Size))
12306c3fb27SDimitry Andric         CurrentLayout.Size = Size * 8;
1240b57cec5SDimitry Andric 
1250b57cec5SDimitry Andric       Pos = LineStr.find("align=");
1260b57cec5SDimitry Andric       if (Pos != StringRef::npos) {
1270b57cec5SDimitry Andric         /* Skip past the align= prefix. */
1280b57cec5SDimitry Andric         LineStr = LineStr.substr(Pos + strlen("align="));
1290b57cec5SDimitry Andric 
1300b57cec5SDimitry Andric         // Parse alignment.
1310b57cec5SDimitry Andric         unsigned long long Alignment = 0;
13206c3fb27SDimitry Andric         if (parseUnsigned(LineStr, Alignment))
13306c3fb27SDimitry Andric           CurrentLayout.Align = Alignment * 8;
1340b57cec5SDimitry Andric       }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric       continue;
1370b57cec5SDimitry Andric     }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric     // Check for the field offsets of the type.
1400b57cec5SDimitry Andric     Pos = LineStr.find("FieldOffsets: [");
14106c3fb27SDimitry Andric     if (Pos != StringRef::npos) {
1420b57cec5SDimitry Andric       LineStr = LineStr.substr(Pos + strlen("FieldOffsets: ["));
1430b57cec5SDimitry Andric       while (!LineStr.empty() && isDigit(LineStr[0])) {
1440b57cec5SDimitry Andric         unsigned long long Offset = 0;
14506c3fb27SDimitry Andric         if (parseUnsigned(LineStr, Offset))
1460b57cec5SDimitry Andric           CurrentLayout.FieldOffsets.push_back(Offset);
1470b57cec5SDimitry Andric 
1480b57cec5SDimitry Andric         // Skip over this offset, the following comma, and any spaces.
14906c3fb27SDimitry Andric         LineStr = LineStr.substr(1);
150*647cbc5dSDimitry Andric         LineStr = LineStr.drop_while(isWhitespace);
1510b57cec5SDimitry Andric       }
1520b57cec5SDimitry Andric     }
1530b57cec5SDimitry Andric 
15406c3fb27SDimitry Andric     // Check for the virtual base offsets.
15506c3fb27SDimitry Andric     Pos = LineStr.find("VBaseOffsets: [");
15606c3fb27SDimitry Andric     if (Pos != StringRef::npos) {
15706c3fb27SDimitry Andric       LineStr = LineStr.substr(Pos + strlen("VBaseOffsets: ["));
15806c3fb27SDimitry Andric       while (!LineStr.empty() && isDigit(LineStr[0])) {
15906c3fb27SDimitry Andric         unsigned long long Offset = 0;
16006c3fb27SDimitry Andric         if (parseUnsigned(LineStr, Offset))
16106c3fb27SDimitry Andric           CurrentLayout.VBaseOffsets.push_back(CharUnits::fromQuantity(Offset));
16206c3fb27SDimitry Andric 
16306c3fb27SDimitry Andric         // Skip over this offset, the following comma, and any spaces.
16406c3fb27SDimitry Andric         LineStr = LineStr.substr(1);
165*647cbc5dSDimitry Andric         LineStr = LineStr.drop_while(isWhitespace);
16606c3fb27SDimitry Andric       }
16706c3fb27SDimitry Andric       continue;
16806c3fb27SDimitry Andric     }
16906c3fb27SDimitry Andric 
17006c3fb27SDimitry Andric     // Check for the base offsets.
17106c3fb27SDimitry Andric     Pos = LineStr.find("BaseOffsets: [");
17206c3fb27SDimitry Andric     if (Pos != StringRef::npos) {
17306c3fb27SDimitry Andric       LineStr = LineStr.substr(Pos + strlen("BaseOffsets: ["));
17406c3fb27SDimitry Andric       while (!LineStr.empty() && isDigit(LineStr[0])) {
17506c3fb27SDimitry Andric         unsigned long long Offset = 0;
17606c3fb27SDimitry Andric         if (parseUnsigned(LineStr, Offset))
17706c3fb27SDimitry Andric           CurrentLayout.BaseOffsets.push_back(CharUnits::fromQuantity(Offset));
17806c3fb27SDimitry Andric 
17906c3fb27SDimitry Andric         // Skip over this offset, the following comma, and any spaces.
18006c3fb27SDimitry Andric         LineStr = LineStr.substr(1);
181*647cbc5dSDimitry Andric         LineStr = LineStr.drop_while(isWhitespace);
18206c3fb27SDimitry Andric       }
18306c3fb27SDimitry Andric     }
18406c3fb27SDimitry Andric   }
18506c3fb27SDimitry Andric 
1860b57cec5SDimitry Andric   // Flush the last type/layout, if there is one.
1870b57cec5SDimitry Andric   if (!CurrentType.empty())
1880b57cec5SDimitry Andric     Layouts[CurrentType] = CurrentLayout;
1890b57cec5SDimitry Andric }
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric 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)1920b57cec5SDimitry Andric LayoutOverrideSource::layoutRecordType(const RecordDecl *Record,
1930b57cec5SDimitry Andric   uint64_t &Size, uint64_t &Alignment,
1940b57cec5SDimitry Andric   llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets,
1950b57cec5SDimitry Andric   llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets,
1960b57cec5SDimitry Andric   llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets)
1970b57cec5SDimitry Andric {
1980b57cec5SDimitry Andric   // We can't override unnamed declarations.
1990b57cec5SDimitry Andric   if (!Record->getIdentifier())
2000b57cec5SDimitry Andric     return false;
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric   // Check whether we have a layout for this record.
2030b57cec5SDimitry Andric   llvm::StringMap<Layout>::iterator Known = Layouts.find(Record->getName());
2040b57cec5SDimitry Andric   if (Known == Layouts.end())
2050b57cec5SDimitry Andric     return false;
2060b57cec5SDimitry Andric 
2070b57cec5SDimitry Andric   // Provide field layouts.
2080b57cec5SDimitry Andric   unsigned NumFields = 0;
2090b57cec5SDimitry Andric   for (RecordDecl::field_iterator F = Record->field_begin(),
2100b57cec5SDimitry Andric                                FEnd = Record->field_end();
2110b57cec5SDimitry Andric        F != FEnd; ++F, ++NumFields) {
2120b57cec5SDimitry Andric     if (NumFields >= Known->second.FieldOffsets.size())
2130b57cec5SDimitry Andric       continue;
2140b57cec5SDimitry Andric 
2150b57cec5SDimitry Andric     FieldOffsets[*F] = Known->second.FieldOffsets[NumFields];
2160b57cec5SDimitry Andric   }
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric   // Wrong number of fields.
2190b57cec5SDimitry Andric   if (NumFields != Known->second.FieldOffsets.size())
2200b57cec5SDimitry Andric     return false;
2210b57cec5SDimitry Andric 
22206c3fb27SDimitry Andric   // Provide base offsets.
22306c3fb27SDimitry Andric   if (const auto *RD = dyn_cast<CXXRecordDecl>(Record)) {
22406c3fb27SDimitry Andric     unsigned NumNB = 0;
22506c3fb27SDimitry Andric     unsigned NumVB = 0;
22606c3fb27SDimitry Andric     for (const auto &I : RD->vbases()) {
22706c3fb27SDimitry Andric       if (NumVB >= Known->second.VBaseOffsets.size())
22806c3fb27SDimitry Andric         continue;
22906c3fb27SDimitry Andric       const CXXRecordDecl *VBase = I.getType()->getAsCXXRecordDecl();
23006c3fb27SDimitry Andric       VirtualBaseOffsets[VBase] = Known->second.VBaseOffsets[NumVB++];
23106c3fb27SDimitry Andric     }
23206c3fb27SDimitry Andric     for (const auto &I : RD->bases()) {
23306c3fb27SDimitry Andric       if (I.isVirtual() || NumNB >= Known->second.BaseOffsets.size())
23406c3fb27SDimitry Andric         continue;
23506c3fb27SDimitry Andric       const CXXRecordDecl *Base = I.getType()->getAsCXXRecordDecl();
23606c3fb27SDimitry Andric       BaseOffsets[Base] = Known->second.BaseOffsets[NumNB++];
23706c3fb27SDimitry Andric     }
23806c3fb27SDimitry Andric   }
23906c3fb27SDimitry Andric 
2400b57cec5SDimitry Andric   Size = Known->second.Size;
2410b57cec5SDimitry Andric   Alignment = Known->second.Align;
2420b57cec5SDimitry Andric   return true;
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric 
dump()2450b57cec5SDimitry Andric LLVM_DUMP_METHOD void LayoutOverrideSource::dump() {
2460b57cec5SDimitry Andric   raw_ostream &OS = llvm::errs();
2470b57cec5SDimitry Andric   for (llvm::StringMap<Layout>::iterator L = Layouts.begin(),
2480b57cec5SDimitry Andric                                       LEnd = Layouts.end();
2490b57cec5SDimitry Andric        L != LEnd; ++L) {
2500b57cec5SDimitry Andric     OS << "Type: blah " << L->first() << '\n';
2510b57cec5SDimitry Andric     OS << "  Size:" << L->second.Size << '\n';
2520b57cec5SDimitry Andric     OS << "  Alignment:" << L->second.Align << '\n';
2530b57cec5SDimitry Andric     OS << "  FieldOffsets: [";
2540b57cec5SDimitry Andric     for (unsigned I = 0, N = L->second.FieldOffsets.size(); I != N; ++I) {
2550b57cec5SDimitry Andric       if (I)
2560b57cec5SDimitry Andric         OS << ", ";
2570b57cec5SDimitry Andric       OS << L->second.FieldOffsets[I];
2580b57cec5SDimitry Andric     }
2590b57cec5SDimitry Andric     OS << "]\n";
2600b57cec5SDimitry Andric   }
2610b57cec5SDimitry Andric }
2620b57cec5SDimitry Andric 
263