AlignmentCalc: Tests for bitfields

Extend TypeGraphParser to understand bitfields
This commit is contained in:
Alastair Robertson 2023-07-19 07:49:27 -07:00 committed by Alastair Robertson
parent 14d193df64
commit dfc0c62749
2 changed files with 41 additions and 21 deletions

View File

@ -102,28 +102,28 @@ void removePrefix(std::string_view& line, std::string_view prefix) {
std::string{line} + "'."};
}
std::optional<uint64_t> tryParseIntAttribute(std::string_view line,
std::optional<double> tryParseNumericAttribute(std::string_view line,
std::string_view marker) {
auto attrStartPos = line.find(marker);
if (attrStartPos == line.npos)
return {};
auto valStartPos = attrStartPos + marker.size();
auto valEndPos = line.find_first_not_of("0123456789", valStartPos);
auto valEndPos = line.find_first_not_of("0123456789.", valStartPos);
auto valStr = line.substr(valStartPos, valEndPos);
uint64_t val = std::stoi(std::string{valStr}); // Makes a string copy :'(
double val = std::stod(std::string{valStr}); // Makes a string copy :'(
return val;
}
uint64_t parseIntAttribute(std::string_view line,
double parseNumericAttribute(std::string_view line,
std::string_view type,
std::string_view marker) {
auto val = tryParseIntAttribute(line, marker);
auto val = tryParseNumericAttribute(line, marker);
if (!val)
throw TypeGraphParserError{
std::string{type} + " must have an attribute: '" + std::string{marker} +
"'. Got: '" + std::string{line} + "'"};
std::string{type} + " must have a numeric attribute: '" +
std::string{marker} + "'. Got: '" + std::string{line} + "'"};
return *val;
}
@ -219,12 +219,12 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) {
auto nameEndPos = line.find('(', nameStartPos + 1);
auto name = line.substr(nameStartPos, nameEndPos - nameStartPos - 1);
auto size = parseIntAttribute(line, nodeTypeName, "size: ");
auto align = tryParseIntAttribute(line, "align: ");
auto size = parseNumericAttribute(line, nodeTypeName, "size: ");
auto align = tryParseNumericAttribute(line, "align: ");
Class& c = typeGraph_.makeType<Class>(id, kind, std::string{name}, size);
if (align)
c.setAlign(*align);
c.setAlign(static_cast<uint64_t>(*align));
nodesById_.insert({id, c});
parseParams(c, input, indent + 2);
@ -244,7 +244,7 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) {
auto& info = getContainerInfo(name);
auto size = parseIntAttribute(line, nodeTypeName, "size: ");
auto size = parseNumericAttribute(line, nodeTypeName, "size: ");
Container& c = typeGraph_.makeType<Container>(id, info, size);
nodesById_.insert({id, c});
@ -262,11 +262,11 @@ Type& TypeGraphParser::parseType(std::string_view& input, size_t rootIndent) {
removePrefix(line, "Enum: ");
auto nameEndPos = line.find(' ');
auto name = line.substr(0, nameEndPos);
auto size = parseIntAttribute(line, nodeTypeName, "size: ");
auto size = parseNumericAttribute(line, nodeTypeName, "size: ");
type = &typeGraph_.makeType<Enum>(std::string{name}, size);
} else if (nodeTypeName == "Array") {
// Format: "Array: (length: 5)
auto len = parseIntAttribute(line, nodeTypeName, "length: ");
auto len = parseNumericAttribute(line, nodeTypeName, "length: ");
auto& elementType = parseType(input, indent + 2);
type = &typeGraph_.makeType<Array>(id, elementType, len);
} else if (nodeTypeName == "Typedef") {
@ -337,7 +337,7 @@ void TypeGraphParser::parseParents(Class& c,
if (!tryRemovePrefix(line, "Parent "))
break;
auto offset = parseIntAttribute(line, "Parent", "offset: ");
auto offset = parseNumericAttribute(line, "Parent", "offset: ");
Type& type = parseType(input, rootIndent + 2);
c.parents.emplace_back(type, offset * 8);
@ -361,13 +361,16 @@ void TypeGraphParser::parseMembers(Class& c,
auto nameEndPos = line.find(' ');
auto name = line.substr(0, nameEndPos);
auto offset = parseIntAttribute(line, "Member", "offset: ");
auto align = tryParseIntAttribute(line, "align: ");
auto offset = parseNumericAttribute(line, "Member", "offset: ");
auto align = tryParseNumericAttribute(line, "align: ");
auto bitsize = tryParseNumericAttribute(line, "bitsize: ");
Type& type = parseType(input, rootIndent + 2);
Member member{type, std::string{name}, offset * 8};
Member member{type, std::string{name}, static_cast<uint64_t>(offset * 8)};
if (align)
member.align = *align;
member.align = static_cast<uint64_t>(*align);
if (bitsize)
member.bitsize = static_cast<uint64_t>(*bitsize);
c.members.push_back(member);
}

View File

@ -165,3 +165,20 @@ TEST(AlignmentCalcTest, RecurseClassChild) {
Primitive: int64_t
)");
}
TEST(AlignmentCalcTest, Bitfields) {
test(AlignmentCalc::createPass(), R"(
[0] Class: MyClass (size: 8)
Member: a (offset: 0, bitsize: 2)
Primitive: int8_t
Member: b (offset: 0.25, bitsize: 30)
Primitive: int64_t
)",
R"(
[0] Class: MyClass (size: 8, align: 8)
Member: a (offset: 0, align: 1, bitsize: 2)
Primitive: int8_t
Member: b (offset: 0.25, align: 8, bitsize: 30)
Primitive: int64_t
)");
}