From 0792de3bed8f346bac906f7885867678852f5d06 Mon Sep 17 00:00:00 2001 From: Alastair Robertson Date: Mon, 26 Jun 2023 08:07:12 -0700 Subject: [PATCH] Flattener: Attempt to take params from parent allocator in case of bad DWARF --- oi/EnumBitset.h | 10 +++++ oi/type_graph/Flattener.cpp | 42 +++++++++++++++++++ oi/type_graph/Printer.cpp | 15 +++++++ oi/type_graph/Printer.h | 1 + oi/type_graph/TypeIdentifier.cpp | 30 +++++++------ oi/type_graph/TypeIdentifier.h | 1 + test/test_codegen.cpp | 67 +++++++++++++++++++++++++++++ test/test_flattener.cpp | 72 ++++++++++++++++++++++++++++++++ test/test_type_identifier.cpp | 38 +++++++++++++++++ 9 files changed, 260 insertions(+), 16 deletions(-) diff --git a/oi/EnumBitset.h b/oi/EnumBitset.h index b001318d0..1370a18b8 100644 --- a/oi/EnumBitset.h +++ b/oi/EnumBitset.h @@ -37,6 +37,16 @@ class EnumBitset { return bitset[static_cast(v)]; } + bool all() const noexcept { + return bitset.all(); + } + bool any() const noexcept { + return bitset.any(); + } + bool none() const noexcept { + return bitset.none(); + } + private: BitsetType bitset; }; diff --git a/oi/type_graph/Flattener.cpp b/oi/type_graph/Flattener.cpp index bc0f9d94a..f3276c909 100644 --- a/oi/type_graph/Flattener.cpp +++ b/oi/type_graph/Flattener.cpp @@ -16,6 +16,7 @@ #include "Flattener.h" #include "TypeGraph.h" +#include "TypeIdentifier.h" namespace type_graph { @@ -75,6 +76,44 @@ void flattenParent(const Parent& parent, throw std::runtime_error("Invalid type for parent"); } } + +/* + * Some compilers generate bad DWARF for allocators, such that they are missing + * their template parameter (which represents the type to be allocated). + * + * Try to add this missing parameter back in by pulling it from the allocator's + * parent class. + */ +void fixAllocatorParams(Class& alloc) { + if (!TypeIdentifier::isAllocator(alloc)) { + return; + } + + if (!alloc.templateParams.empty()) { + // The DWARF looks ok + return; + } + + if (alloc.parents.empty()) { + // Nothing we can do + return; + } + + Type& parent = stripTypedefs(*alloc.parents[0].type); + Class* parentClass = dynamic_cast(&parent); + if (!parentClass) { + // Not handled + return; + } + + if (parentClass->templateParams.empty()) { + // Nothing we can do + return; + } + + Type& typeToAllocate = stripTypedefs(*parentClass->templateParams[0].type); + alloc.templateParams.push_back(TemplateParam{&typeToAllocate}); +} } // namespace void Flattener::visit(Class& c) { @@ -152,6 +191,9 @@ void Flattener::visit(Class& c) { flattenParent(parent, flattenedMembers); } + // Perform fixups for bad DWARF + fixAllocatorParams(c); + c.parents.clear(); c.members = std::move(flattenedMembers); diff --git a/oi/type_graph/Printer.cpp b/oi/type_graph/Printer.cpp index 8e33a97f9..6784b4c75 100644 --- a/oi/type_graph/Printer.cpp +++ b/oi/type_graph/Printer.cpp @@ -159,6 +159,7 @@ void Printer::print_param(const TemplateParam& param) { } else { print(*param.type); } + print_qualifiers(param.qualifiers); depth_--; } @@ -204,6 +205,20 @@ void Printer::print_value(const std::string& value) { depth_--; } +void Printer::print_qualifiers(const QualifierSet& qualifiers) { + if (qualifiers.none()) { + return; + } + depth_++; + prefix(); + out_ << "Qualifiers:"; + if (qualifiers[Qualifier::Const]) { + out_ << " const"; + } + out_ << std::endl; + depth_--; +} + std::string Printer::align_str(uint64_t align) { if (align == 0) return ""; diff --git a/oi/type_graph/Printer.h b/oi/type_graph/Printer.h index 1b0f64219..36723f5ec 100644 --- a/oi/type_graph/Printer.h +++ b/oi/type_graph/Printer.h @@ -50,6 +50,7 @@ class Printer : public ConstVisitor { void print_function(const Function& function); void print_child(const Type& child); void print_value(const std::string& value); + void print_qualifiers(const QualifierSet& qualifiers); static std::string align_str(uint64_t align); std::ostream& out_; diff --git a/oi/type_graph/TypeIdentifier.cpp b/oi/type_graph/TypeIdentifier.cpp index b1a351b31..843b59878 100644 --- a/oi/type_graph/TypeIdentifier.cpp +++ b/oi/type_graph/TypeIdentifier.cpp @@ -31,17 +31,8 @@ Pass TypeIdentifier::createPass() { return Pass("TypeIdentifier", fn); } -void TypeIdentifier::visit(Type& type) { - if (visited_.count(&type) != 0) - return; - - visited_.insert(&type); - type.accept(*this); -} - -namespace { -bool isAllocator(Type* t) { - auto* c = dynamic_cast(t); +bool TypeIdentifier::isAllocator(Type& t) { + auto* c = dynamic_cast(&t); if (!c) return false; @@ -54,7 +45,14 @@ bool isAllocator(Type* t) { } return false; } -} // namespace + +void TypeIdentifier::visit(Type& type) { + if (visited_.count(&type) != 0) + return; + + visited_.insert(&type); + type.accept(*this); +} void TypeIdentifier::visit(Container& c) { const auto& stubParams = c.containerInfo_.stubTemplateParams; @@ -78,15 +76,15 @@ void TypeIdentifier::visit(Container& c) { size = 0; } - if (isAllocator(param.type)) { + if (isAllocator(*param.type)) { auto* allocator = dynamic_cast(param.type); // TODO please don't do this... Type* typeToAllocate; if (!allocator->templateParams.empty()) { - typeToAllocate = allocator->templateParams.at(0).type; + typeToAllocate = allocator->templateParams[0].type; } else { - // We've encountered some bad DWARF. Let's guess that the type to - // allocate is the first parameter of the container. + // Otherwise, let's guess that the type to allocate is the first + // parameter of the container. typeToAllocate = c.templateParams[0].type; } auto* dummy = typeGraph_.make_type( diff --git a/oi/type_graph/TypeIdentifier.h b/oi/type_graph/TypeIdentifier.h index 93779943d..46d2ec05b 100644 --- a/oi/type_graph/TypeIdentifier.h +++ b/oi/type_graph/TypeIdentifier.h @@ -33,6 +33,7 @@ class TypeGraph; class TypeIdentifier : public RecursiveVisitor { public: static Pass createPass(); + static bool isAllocator(Type& t); TypeIdentifier(TypeGraph& typeGraph) : typeGraph_(typeGraph) { } diff --git a/test/test_codegen.cpp b/test/test_codegen.cpp index 69a2feb8f..cfa7c10f5 100644 --- a/test/test_codegen.cpp +++ b/test/test_codegen.cpp @@ -64,3 +64,70 @@ TEST(CodeGenTest, TransformContainerAllocator) { Primitive: int32_t )"); } + +TEST(CodeGenTest, TransformContainerAllocatorParamInParent) { + ContainerInfo pairInfo{"std::pair", SEQ_TYPE, "utility"}; + + ContainerInfo mapInfo{"std::map", STD_MAP_TYPE, "utility"}; + mapInfo.stubTemplateParams = {2, 3}; + + Primitive myint{Primitive::Kind::Int32}; + + Container pair{pairInfo, 8}; + pair.templateParams.push_back(TemplateParam{&myint, {Qualifier::Const}}); + pair.templateParams.push_back(TemplateParam{&myint}); + + Class myallocBase{Class::Kind::Struct, + "MyAllocBase>", 1}; + myallocBase.templateParams.push_back(TemplateParam{&pair}); + myallocBase.functions.push_back(Function{"allocate"}); + myallocBase.functions.push_back(Function{"deallocate"}); + + Class myalloc{Class::Kind::Struct, "MyAlloc>", 1}; + myalloc.parents.push_back(Parent{&myallocBase, 0}); + myalloc.functions.push_back(Function{"allocate"}); + myalloc.functions.push_back(Function{"deallocate"}); + + Container map{mapInfo, 24}; + map.templateParams.push_back(TemplateParam{&myint}); + map.templateParams.push_back(TemplateParam{&myint}); + map.templateParams.push_back(TemplateParam{&myalloc}); + + testTransform(map, R"( +[0] Container: std::map (size: 24) + Param + Primitive: int32_t + Param + Primitive: int32_t + Param +[1] Struct: MyAlloc> (size: 1) + Parent (offset: 0) +[2] Struct: MyAllocBase> (size: 1) + Param +[3] Container: std::pair (size: 8) + Param + Primitive: int32_t + Qualifiers: const + Param + Primitive: int32_t + Function: allocate + Function: deallocate + Function: allocate + Function: deallocate +)", + R"( +[0] Container: std::map, 0, 0>> (size: 24) + Param + Primitive: int32_t + Param + Primitive: int32_t + Param + DummyAllocator (size: 0) +[1] Container: std::pair (size: 8) + Param + Primitive: int32_t + Qualifiers: const + Param + Primitive: int32_t +)"); +} diff --git a/test/test_flattener.cpp b/test/test_flattener.cpp index 12867420d..62ea2338f 100644 --- a/test/test_flattener.cpp +++ b/test/test_flattener.cpp @@ -762,3 +762,75 @@ TEST(FlattenerTest, ParentClassAndContainer) { Primitive: int32_t )"); } + +TEST(FlattenerTest, AllocatorParamInParent) { + ContainerInfo pairInfo{"std::pair", SEQ_TYPE, "utility"}; + + ContainerInfo mapInfo{"std::map", STD_MAP_TYPE, "utility"}; + mapInfo.stubTemplateParams = {2, 3}; + + Primitive myint{Primitive::Kind::Int32}; + + Container pair{pairInfo, 8}; + pair.templateParams.push_back(TemplateParam{&myint, {Qualifier::Const}}); + pair.templateParams.push_back(TemplateParam{&myint}); + + Class myallocBase{Class::Kind::Struct, + "MyAllocBase>", 1}; + myallocBase.templateParams.push_back(TemplateParam{&pair}); + myallocBase.functions.push_back(Function{"allocate"}); + myallocBase.functions.push_back(Function{"deallocate"}); + + Class myalloc{Class::Kind::Struct, "MyAlloc>", 1}; + myalloc.parents.push_back(Parent{&myallocBase, 0}); + myalloc.functions.push_back(Function{"allocate"}); + myalloc.functions.push_back(Function{"deallocate"}); + + Container map{mapInfo, 24}; + map.templateParams.push_back(TemplateParam{&myint}); + map.templateParams.push_back(TemplateParam{&myint}); + map.templateParams.push_back(TemplateParam{&myalloc}); + + test(Flattener::createPass(), {map}, R"( +[0] Container: std::map (size: 24) + Param + Primitive: int32_t + Param + Primitive: int32_t + Param +[1] Struct: MyAlloc> (size: 1) + Parent (offset: 0) +[2] Struct: MyAllocBase> (size: 1) + Param +[3] Container: std::pair (size: 8) + Param + Primitive: int32_t + Qualifiers: const + Param + Primitive: int32_t + Function: allocate + Function: deallocate + Function: allocate + Function: deallocate +)", + R"( +[0] Container: std::map (size: 24) + Param + Primitive: int32_t + Param + Primitive: int32_t + Param +[1] Struct: MyAlloc> (size: 1) + Param +[2] Container: std::pair (size: 8) + Param + Primitive: int32_t + Qualifiers: const + Param + Primitive: int32_t + Function: allocate + Function: deallocate + Function: allocate + Function: deallocate +)"); +} diff --git a/test/test_type_identifier.cpp b/test/test_type_identifier.cpp index 172b85b80..ffa5e7d4d 100644 --- a/test/test_type_identifier.cpp +++ b/test/test_type_identifier.cpp @@ -77,6 +77,44 @@ TEST(TypeIdentifierTest, Allocator) { )"); } +TEST(TypeIdentifierTest, AllocatorSize1) { + auto myint = Primitive{Primitive::Kind::Int32}; + + auto myalloc = Class{Class::Kind::Struct, "MyAlloc", 1}; + myalloc.templateParams.push_back(TemplateParam{&myint}); + myalloc.functions.push_back(Function{"allocate"}); + myalloc.functions.push_back(Function{"deallocate"}); + + auto container = getVector(); + container.templateParams.push_back(TemplateParam{&myint}); + container.templateParams.push_back(TemplateParam{&myalloc}); + container.templateParams.push_back(TemplateParam{&myint}); + + test(TypeIdentifier::createPass(), {container}, R"( +[0] Container: std::vector (size: 24) + Param + Primitive: int32_t + Param +[1] Struct: MyAlloc (size: 1) + Param + Primitive: int32_t + Function: allocate + Function: deallocate + Param + Primitive: int32_t +)", + R"( +[0] Container: std::vector (size: 24) + Param + Primitive: int32_t + Param + DummyAllocator (size: 0) + Primitive: int32_t + Param + Primitive: int32_t +)"); +} + TEST(TypeIdentifierTest, AllocatorNoParam) { auto myint = Primitive{Primitive::Kind::Int32};