Rename RemoveIgnored -> RemoveMembers

Also reshuffle CodeGen's passes to fix an alignment bug with removed
members.

Change RemoveMembers to actually remove members instead of replacing
them with padding. AddPadding must be run afterwards to fill in the
gaps.
This commit is contained in:
Alastair Robertson 2023-07-25 05:45:22 -07:00 committed by Alastair Robertson
parent 99462b2132
commit 2d1cc92bb4
7 changed files with 119 additions and 67 deletions

View File

@ -31,7 +31,7 @@
#include "type_graph/DrgnParser.h"
#include "type_graph/Flattener.h"
#include "type_graph/NameGen.h"
#include "type_graph/RemoveIgnored.h"
#include "type_graph/RemoveMembers.h"
#include "type_graph/RemoveTopLevelPointer.h"
#include "type_graph/TopoSorter.h"
#include "type_graph/TypeGraph.h"
@ -783,28 +783,34 @@ void CodeGen::addDrgnRoot(struct drgn_type* drgnType,
void CodeGen::transform(type_graph::TypeGraph& typeGraph) {
type_graph::PassManager pm;
// 1. Transformation passes
// Simplify the type graph first so there is less work for later passes
pm.addPass(type_graph::RemoveTopLevelPointer::createPass());
pm.addPass(type_graph::Flattener::createPass());
pm.addPass(type_graph::TypeIdentifier::createPass(config_.passThroughTypes));
if (config_.features[Feature::PolymorphicInheritance]) {
// Parse new children nodes
type_graph::DrgnParser drgnParser{
typeGraph, containerInfos_,
config_.features[Feature::ChaseRawPointers]};
pm.addPass(type_graph::AddChildren::createPass(drgnParser, symbols_));
// Re-run passes over newly added children
pm.addPass(type_graph::Flattener::createPass());
pm.addPass(
type_graph::TypeIdentifier::createPass(config_.passThroughTypes));
}
pm.addPass(type_graph::RemoveIgnored::createPass(config_.membersToStub));
pm.addPass(type_graph::RemoveTopLevelPointer::createPass());
// 2. Fixup passes to repair type graph after partial transformations
// Calculate alignment before removing members, as those members may have an
// influence on the class' overall alignment.
pm.addPass(type_graph::AlignmentCalc::createPass());
pm.addPass(type_graph::RemoveMembers::createPass(config_.membersToStub));
// Add padding to fill in the gaps of removed members and ensure their
// alignments
pm.addPass(type_graph::AddPadding::createPass(config_.features));
// 3. Annotation passes
pm.addPass(type_graph::NameGen::createPass());
pm.addPass(type_graph::AlignmentCalc::createPass());
pm.addPass(type_graph::TopoSorter::createPass());
pm.run(typeGraph);

View File

@ -7,7 +7,7 @@ add_library(type_graph
NameGen.cpp
PassManager.cpp
Printer.cpp
RemoveIgnored.cpp
RemoveMembers.cpp
RemoveTopLevelPointer.cpp
TopoSorter.cpp
TypeGraph.cpp

View File

@ -13,26 +13,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "RemoveIgnored.h"
#include "RemoveMembers.h"
#include "AddPadding.h"
#include "TypeGraph.h"
namespace type_graph {
Pass RemoveIgnored::createPass(
Pass RemoveMembers::createPass(
const std::vector<std::pair<std::string, std::string>>& membersToIgnore) {
auto fn = [&membersToIgnore](TypeGraph& typeGraph) {
RemoveIgnored removeIgnored{typeGraph, membersToIgnore};
RemoveMembers removeMembers{membersToIgnore};
for (auto& type : typeGraph.rootTypes()) {
removeIgnored.accept(type);
removeMembers.accept(type);
}
};
return Pass("RemoveIgnored", fn);
return Pass("RemoveMembers", fn);
}
void RemoveIgnored::accept(Type& type) {
void RemoveMembers::accept(Type& type) {
if (visited_.count(&type) != 0)
return;
@ -40,7 +40,7 @@ void RemoveIgnored::accept(Type& type) {
type.accept(*this);
}
void RemoveIgnored::visit(Class& c) {
void RemoveMembers::visit(Class& c) {
for (const auto& param : c.templateParams) {
accept(param.type());
}
@ -54,19 +54,12 @@ void RemoveIgnored::visit(Class& c) {
accept(child);
}
for (size_t i = 0; i < c.members.size(); i++) {
if (!ignoreMember(c.name(), c.members[i].name)) {
continue;
}
auto& primitive = typeGraph_.makeType<Primitive>(Primitive::Kind::Int8);
auto& paddingArray =
typeGraph_.makeType<Array>(primitive, c.members[i].type().size());
c.members[i] =
Member{paddingArray, AddPadding::MemberPrefix, c.members[i].bitOffset};
}
std::erase_if(c.members, [this, &c](Member member) {
return ignoreMember(c.name(), member.name);
});
}
bool RemoveIgnored::ignoreMember(const std::string& typeName,
bool RemoveMembers::ignoreMember(const std::string& typeName,
const std::string& memberName) const {
for (const auto& [ignoredType, ignoredMember] : membersToIgnore_) {
if (typeName == ignoredType && memberName == ignoredMember) {

View File

@ -23,23 +23,20 @@
namespace type_graph {
class TypeGraph;
/*
* RemoveIgnored
* RemoveMembers
*
* Remove types and members as requested by the [[codegen.ignore]] section in
* the OI config.
* Removes members as requested by the [[codegen.ignore]] section in the OI
* config.
*/
class RemoveIgnored : public RecursiveVisitor {
class RemoveMembers : public RecursiveVisitor {
public:
static Pass createPass(
const std::vector<std::pair<std::string, std::string>>& membersToIgnore);
RemoveIgnored(
TypeGraph& typeGraph,
RemoveMembers(
const std::vector<std::pair<std::string, std::string>>& membersToIgnore)
: typeGraph_(typeGraph), membersToIgnore_(membersToIgnore) {
: membersToIgnore_(membersToIgnore) {
}
using RecursiveVisitor::accept;
@ -52,7 +49,6 @@ class RemoveIgnored : public RecursiveVisitor {
const std::string& memberName) const;
std::unordered_set<Type*> visited_;
TypeGraph& typeGraph_;
const std::vector<std::pair<std::string, std::string>>& membersToIgnore_;
};

View File

@ -44,7 +44,7 @@ add_executable(test_type_graph
test_flattener.cpp
test_name_gen.cpp
test_node_tracker.cpp
test_remove_ignored.cpp
test_remove_members.cpp
test_remove_top_level_pointer.cpp
test_topo_sorter.cpp
test_type_identifier.cpp

View File

@ -5,6 +5,7 @@
#include <string_view>
#include <vector>
#include "TypeGraphParser.h"
#include "mocks.h"
#include "oi/CodeGen.h"
#include "oi/type_graph/Printer.h"
@ -33,6 +34,33 @@ void testTransform(Type& type,
check({type}, expectedAfter, "after transform");
}
void testTransform(OICodeGen::Config& config,
std::string_view input,
std::string_view expectedAfter) {
input.remove_prefix(1); // Remove initial '\n'
TypeGraph typeGraph;
TypeGraphParser parser{typeGraph};
try {
parser.parse(input);
} catch (const TypeGraphParserError& err) {
FAIL() << "Error parsing input graph: " << err.what();
}
// Validate input formatting
check(typeGraph.rootTypes(), input, "parsing input graph");
MockSymbolService symbols;
CodeGen codegen{config, symbols};
codegen.transform(typeGraph);
check(typeGraph.rootTypes(), expectedAfter, "after transform");
}
void testTransform(std::string_view input, std::string_view expectedAfter) {
OICodeGen::Config config;
testTransform(config, input, expectedAfter);
}
} // namespace
TEST(CodeGenTest, TransformContainerAllocator) {
@ -135,3 +163,47 @@ TEST(CodeGenTest, TransformContainerAllocatorParamInParent) {
Primitive: int32_t
)");
}
TEST(CodeGenTest, RemovedMemberAlignment) {
OICodeGen::Config config;
config.membersToStub = {{"MyClass", "b"}};
testTransform(config, R"(
[0] Class: MyClass (size: 24)
Member: a (offset: 0)
Primitive: int8_t
Member: b (offset: 8)
Primitive: int64_t
Member: c (offset: 16)
Primitive: int8_t
)",
R"(
[0] Class: MyClass_0 (size: 24, align: 8)
Member: a_0 (offset: 0, align: 1)
Primitive: int8_t
Member: __oi_padding_1 (offset: 1)
[1] Array: (length: 15)
Primitive: int8_t
Member: c_2 (offset: 16, align: 1)
Primitive: int8_t
Member: __oi_padding_3 (offset: 17)
[2] Array: (length: 7)
Primitive: int8_t
)");
}
TEST(CodeGenTest, UnionMembersAlignment) {
testTransform(R"(
[0] Union: MyUnion (size: 8)
Member: a (offset: 0)
Primitive: int8_t
Member: b (offset: 8)
Primitive: int64_t
)",
R"(
[0] Union: MyUnion_0 (size: 8, align: 8)
Member: a_0 (offset: 0, align: 1)
Primitive: int8_t
Member: b_1 (offset: 8, align: 8)
Primitive: int64_t
)");
}

View File

@ -1,12 +1,12 @@
#include <gtest/gtest.h>
#include "oi/type_graph/RemoveIgnored.h"
#include "oi/type_graph/RemoveMembers.h"
#include "oi/type_graph/Types.h"
#include "test/type_graph_utils.h"
using namespace type_graph;
TEST(RemoveIgnoredTest, Match) {
TEST(RemoveMembersTest, Match) {
auto classB = Class{1, Class::Kind::Class, "ClassB", 4};
auto classA = Class{0, Class::Kind::Class, "ClassA", 12};
@ -18,7 +18,7 @@ TEST(RemoveIgnoredTest, Match) {
{"ClassA", "b"},
};
test(RemoveIgnored::createPass(membersToIgnore), {classA}, R"(
test(RemoveMembers::createPass(membersToIgnore), {classA}, R"(
[0] Class: ClassA (size: 12)
Member: a (offset: 0)
[1] Class: ClassB (size: 4)
@ -31,15 +31,12 @@ TEST(RemoveIgnoredTest, Match) {
[0] Class: ClassA (size: 12)
Member: a (offset: 0)
[1] Class: ClassB (size: 4)
Member: __oi_padding (offset: 4)
[2] Array: (length: 4)
Primitive: int8_t
Member: c (offset: 8)
[1]
)");
}
TEST(RemoveIgnoredTest, TypeMatchMemberMiss) {
TEST(RemoveMembersTest, TypeMatchMemberMiss) {
auto classB = Class{1, Class::Kind::Class, "ClassB", 4};
auto classA = Class{0, Class::Kind::Class, "ClassA", 12};
@ -51,7 +48,7 @@ TEST(RemoveIgnoredTest, TypeMatchMemberMiss) {
{"ClassA", "x"},
};
test(RemoveIgnored::createPass(membersToIgnore), {classA}, R"(
test(RemoveMembers::createPass(membersToIgnore), {classA}, R"(
[0] Class: ClassA (size: 12)
Member: a (offset: 0)
[1] Class: ClassB (size: 4)
@ -62,7 +59,7 @@ TEST(RemoveIgnoredTest, TypeMatchMemberMiss) {
)");
}
TEST(RemoveIgnoredTest, MemberMatchWrongType) {
TEST(RemoveMembersTest, MemberMatchWrongType) {
auto classB = Class{1, Class::Kind::Class, "ClassB", 4};
auto classA = Class{0, Class::Kind::Class, "ClassA", 12};
@ -74,7 +71,7 @@ TEST(RemoveIgnoredTest, MemberMatchWrongType) {
{"ClassB", "b"},
};
test(RemoveIgnored::createPass(membersToIgnore), {classA}, R"(
test(RemoveMembers::createPass(membersToIgnore), {classA}, R"(
[0] Class: ClassA (size: 12)
Member: a (offset: 0)
[1] Class: ClassB (size: 4)
@ -85,11 +82,11 @@ TEST(RemoveIgnoredTest, MemberMatchWrongType) {
)");
}
TEST(RemoveIgnoredTest, RecurseClassParam) {
TEST(RemoveMembersTest, RecurseClassParam) {
const std::vector<std::pair<std::string, std::string>>& membersToIgnore = {
{"ClassA", "b"},
};
test(RemoveIgnored::createPass(membersToIgnore), R"(
test(RemoveMembers::createPass(membersToIgnore), R"(
[0] Class: MyClass (size: 0)
Param
[1] Class: ClassA (size: 12)
@ -106,19 +103,16 @@ TEST(RemoveIgnoredTest, RecurseClassParam) {
[1] Class: ClassA (size: 12)
Member: a (offset: 0)
Primitive: int32_t
Member: __oi_padding (offset: 4)
[2] Array: (length: 4)
Primitive: int8_t
Member: c (offset: 8)
Primitive: int32_t
)");
}
TEST(RemoveIgnoredTest, RecurseClassParent) {
TEST(RemoveMembersTest, RecurseClassParent) {
const std::vector<std::pair<std::string, std::string>>& membersToIgnore = {
{"ClassA", "b"},
};
test(RemoveIgnored::createPass(membersToIgnore), R"(
test(RemoveMembers::createPass(membersToIgnore), R"(
[0] Class: MyClass (size: 0)
Parent (offset: 0)
[1] Class: ClassA (size: 12)
@ -135,19 +129,16 @@ TEST(RemoveIgnoredTest, RecurseClassParent) {
[1] Class: ClassA (size: 12)
Member: a (offset: 0)
Primitive: int32_t
Member: __oi_padding (offset: 4)
[2] Array: (length: 4)
Primitive: int8_t
Member: c (offset: 8)
Primitive: int32_t
)");
}
TEST(RemoveIgnoredTest, RecurseClassMember) {
TEST(RemoveMembersTest, RecurseClassMember) {
const std::vector<std::pair<std::string, std::string>>& membersToIgnore = {
{"ClassA", "b"},
};
test(RemoveIgnored::createPass(membersToIgnore), R"(
test(RemoveMembers::createPass(membersToIgnore), R"(
[0] Class: MyClass (size: 0)
Member: xxx (offset: 0)
[1] Class: ClassA (size: 12)
@ -164,19 +155,16 @@ TEST(RemoveIgnoredTest, RecurseClassMember) {
[1] Class: ClassA (size: 12)
Member: a (offset: 0)
Primitive: int32_t
Member: __oi_padding (offset: 4)
[2] Array: (length: 4)
Primitive: int8_t
Member: c (offset: 8)
Primitive: int32_t
)");
}
TEST(RemoveIgnoredTest, RecurseClassChild) {
TEST(RemoveMembersTest, RecurseClassChild) {
const std::vector<std::pair<std::string, std::string>>& membersToIgnore = {
{"ClassA", "b"},
};
test(RemoveIgnored::createPass(membersToIgnore), R"(
test(RemoveMembers::createPass(membersToIgnore), R"(
[0] Class: MyClass (size: 0)
Child
[1] Class: ClassA (size: 12)
@ -193,9 +181,6 @@ TEST(RemoveIgnoredTest, RecurseClassChild) {
[1] Class: ClassA (size: 12)
Member: a (offset: 0)
Primitive: int32_t
Member: __oi_padding (offset: 4)
[2] Array: (length: 4)
Primitive: int8_t
Member: c (offset: 8)
Primitive: int32_t
)");