diff --git a/oi/CodeGen.cpp b/oi/CodeGen.cpp index d8d9946..6105bd3 100644 --- a/oi/CodeGen.cpp +++ b/oi/CodeGen.cpp @@ -28,6 +28,7 @@ #include "type_graph/DrgnParser.h" #include "type_graph/Flattener.h" #include "type_graph/NameGen.h" +#include "type_graph/RemoveIgnored.h" #include "type_graph/RemoveTopLevelPointer.h" #include "type_graph/TopoSorter.h" #include "type_graph/TypeGraph.h" @@ -420,6 +421,7 @@ bool CodeGen::generate(drgn_type* drgnType, std::string& code) { pm.addPass(type_graph::Flattener::createPass()); pm.addPass(type_graph::TypeIdentifier::createPass()); } + pm.addPass(type_graph::RemoveIgnored::createPass(config_.membersToStub)); pm.addPass(type_graph::AddPadding::createPass()); pm.addPass(type_graph::NameGen::createPass()); pm.addPass(type_graph::AlignmentCalc::createPass()); diff --git a/oi/type_graph/AddPadding.h b/oi/type_graph/AddPadding.h index 72b820c..cd919ea 100644 --- a/oi/type_graph/AddPadding.h +++ b/oi/type_graph/AddPadding.h @@ -19,12 +19,13 @@ #include #include "PassManager.h" -#include "TypeGraph.h" #include "Types.h" #include "Visitor.h" namespace type_graph { +class TypeGraph; + /* * AddPadding * diff --git a/oi/type_graph/CMakeLists.txt b/oi/type_graph/CMakeLists.txt index afae464..e81291f 100644 --- a/oi/type_graph/CMakeLists.txt +++ b/oi/type_graph/CMakeLists.txt @@ -7,6 +7,7 @@ add_library(type_graph NameGen.cpp PassManager.cpp Printer.cpp + RemoveIgnored.cpp RemoveTopLevelPointer.cpp TopoSorter.cpp TypeIdentifier.cpp diff --git a/oi/type_graph/RemoveIgnored.cpp b/oi/type_graph/RemoveIgnored.cpp new file mode 100644 index 0000000..5fdf21b --- /dev/null +++ b/oi/type_graph/RemoveIgnored.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "RemoveIgnored.h" + +#include "TypeGraph.h" + +namespace type_graph { + +Pass RemoveIgnored::createPass( + const std::vector>& membersToIgnore) { + auto fn = [&membersToIgnore](TypeGraph& typeGraph) { + RemoveIgnored removeIgnored{typeGraph, membersToIgnore}; + for (auto& type : typeGraph.rootTypes()) { + removeIgnored.visit(type); + } + }; + + return Pass("RemoveIgnored", fn); +} + +void RemoveIgnored::visit(Type& type) { + if (visited_.count(&type) != 0) + return; + + visited_.insert(&type); + type.accept(*this); +} + +void RemoveIgnored::visit(Class& c) { + for (size_t i = 0; i < c.members.size(); i++) { + if (!ignoreMember(c.name(), c.members[i].name)) { + continue; + } + auto* primitive = typeGraph_.make_type(Primitive::Kind::Int8); + auto* paddingArray = + typeGraph_.make_type(primitive, c.members[i].type->size()); + c.members[i] = Member{paddingArray, c.members[i].name, c.members[i].offset}; + } +} + +bool RemoveIgnored::ignoreMember(const std::string& typeName, + const std::string& memberName) const { + for (const auto& [ignoredType, ignoredMember] : membersToIgnore_) { + if (typeName == ignoredType && memberName == ignoredMember) { + return true; + } + } + return false; +} + +} // namespace type_graph diff --git a/oi/type_graph/RemoveIgnored.h b/oi/type_graph/RemoveIgnored.h new file mode 100644 index 0000000..0af5ca6 --- /dev/null +++ b/oi/type_graph/RemoveIgnored.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include + +#include "PassManager.h" +#include "Types.h" +#include "Visitor.h" + +namespace type_graph { + +class TypeGraph; + +/* + * RemoveIgnored + * + * Remove types and members as requested by the [[codegen.ignore]] section in + * the OI config. + */ +class RemoveIgnored : public RecursiveVisitor { + public: + static Pass createPass( + const std::vector>& membersToIgnore); + + RemoveIgnored( + TypeGraph& typeGraph, + const std::vector>& membersToIgnore) + : typeGraph_(typeGraph), membersToIgnore_(membersToIgnore) { + } + + void visit(Type& type) override; + void visit(Class& c) override; + + private: + bool ignoreMember(const std::string& typeName, + const std::string& memberName) const; + + std::unordered_set visited_; + TypeGraph& typeGraph_; + const std::vector>& membersToIgnore_; +}; + +} // namespace type_graph diff --git a/oi/type_graph/TypeIdentifier.h b/oi/type_graph/TypeIdentifier.h index aff818b..a9287e7 100644 --- a/oi/type_graph/TypeIdentifier.h +++ b/oi/type_graph/TypeIdentifier.h @@ -16,7 +16,6 @@ #pragma once #include -#include #include "PassManager.h" #include "Types.h" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a873778..25dbb79 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -54,6 +54,7 @@ add_executable(test_type_graph test_drgn_parser.cpp test_flattener.cpp test_name_gen.cpp + test_remove_ignored.cpp test_remove_top_level_pointer.cpp test_topo_sorter.cpp test_type_identifier.cpp diff --git a/test/test_add_padding.cpp b/test/test_add_padding.cpp index d02a873..f18a81f 100644 --- a/test/test_add_padding.cpp +++ b/test/test_add_padding.cpp @@ -1,9 +1,7 @@ #include #include "oi/type_graph/AddPadding.h" -#include "oi/type_graph/PassManager.h" #include "oi/type_graph/Printer.h" -#include "oi/type_graph/TypeGraph.h" #include "oi/type_graph/Types.h" #include "test/type_graph_utils.h" diff --git a/test/test_remove_ignored.cpp b/test/test_remove_ignored.cpp new file mode 100644 index 0000000..7ccf5a5 --- /dev/null +++ b/test/test_remove_ignored.cpp @@ -0,0 +1,87 @@ +#include + +#include "oi/type_graph/Printer.h" +#include "oi/type_graph/RemoveIgnored.h" +#include "oi/type_graph/Types.h" +#include "test/type_graph_utils.h" + +using namespace type_graph; + +TEST(RemoveIgnoredTest, Match) { + auto classB = Class{Class::Kind::Class, "ClassB", 4}; + + auto classA = Class{Class::Kind::Class, "ClassA", 12}; + classA.members.push_back(Member(&classB, "a", 0)); + classA.members.push_back(Member(&classB, "b", 4)); + classA.members.push_back(Member(&classB, "c", 8)); + + const std::vector>& membersToIgnore = { + {"ClassA", "b"}, + }; + + test(RemoveIgnored::createPass(membersToIgnore), {classA}, R"( +[0] Class: ClassA (size: 12) + Member: a (offset: 0) +[1] Class: ClassB (size: 4) + Member: b (offset: 4) + [1] + Member: c (offset: 8) + [1] +)", + R"( +[0] Class: ClassA (size: 12) + Member: a (offset: 0) +[1] Class: ClassB (size: 4) + Member: b (offset: 4) +[2] Array: (length: 4) + Primitive: int8_t + Member: c (offset: 8) + [1] +)"); +} + +TEST(RemoveIgnoredTest, TypeMatchMemberMiss) { + auto classB = Class{Class::Kind::Class, "ClassB", 4}; + + auto classA = Class{Class::Kind::Class, "ClassA", 12}; + classA.members.push_back(Member(&classB, "a", 0)); + classA.members.push_back(Member(&classB, "b", 4)); + classA.members.push_back(Member(&classB, "c", 8)); + + const std::vector>& membersToIgnore = { + {"ClassA", "x"}, + }; + + test(RemoveIgnored::createPass(membersToIgnore), {classA}, R"( +[0] Class: ClassA (size: 12) + Member: a (offset: 0) +[1] Class: ClassB (size: 4) + Member: b (offset: 4) + [1] + Member: c (offset: 8) + [1] +)"); +} + +TEST(RemoveIgnoredTest, MemberMatchWrongType) { + auto classB = Class{Class::Kind::Class, "ClassB", 4}; + + auto classA = Class{Class::Kind::Class, "ClassA", 12}; + classA.members.push_back(Member(&classB, "a", 0)); + classA.members.push_back(Member(&classB, "b", 4)); + classA.members.push_back(Member(&classB, "c", 8)); + + const std::vector>& membersToIgnore = { + {"ClassB", "b"}, + }; + + test(RemoveIgnored::createPass(membersToIgnore), {classA}, R"( +[0] Class: ClassA (size: 12) + Member: a (offset: 0) +[1] Class: ClassB (size: 4) + Member: b (offset: 4) + [1] + Member: c (offset: 8) + [1] +)"); +}