From d7d18541d32e571fde67379c2b2c97bbe8a4d4cd Mon Sep 17 00:00:00 2001 From: Anthony Cui Date: Wed, 7 Aug 2024 10:51:20 -0700 Subject: [PATCH] Have driver_ast_parser report the size of structs and types. PiperOrigin-RevId: 660453033 --- .../nvidia_driver_differ/driver_ast_parser.cc | 38 ++++++++++++------- .../driver_ast_parser_test.go | 19 ++++++++-- .../parser/json_definitions.go | 31 +++++++++------ tools/nvidia_driver_differ/run_differ.go | 4 +- tools/nvidia_driver_differ/test_struct.cc | 2 + 5 files changed, 65 insertions(+), 29 deletions(-) diff --git a/tools/nvidia_driver_differ/driver_ast_parser.cc b/tools/nvidia_driver_differ/driver_ast_parser.cc index 9f5196a7c..b89202ca5 100644 --- a/tools/nvidia_driver_differ/driver_ast_parser.cc +++ b/tools/nvidia_driver_differ/driver_ast_parser.cc @@ -24,6 +24,7 @@ #include "absl/container/flat_hash_set.h" #include "absl/strings/str_cat.h" #include "nlohmann/json.hpp" +#include "clang/include/clang/AST/ASTContext.h" #include "clang/include/clang/AST/Decl.h" #include "clang/include/clang/AST/Type.h" #include "clang/include/clang/ASTMatchers/ASTMatchFinder.h" @@ -89,7 +90,7 @@ struct DriverStructReporter : public MatchFinder::MatchCallback { } void run(const MatchFinder::MatchResult &result) override { - const auto &sm = result.Context->getSourceManager(); + const auto *ctx = result.Context; const auto *typedef_decl = result.Nodes.getNodeAs("typedef_decl"); @@ -104,22 +105,28 @@ struct DriverStructReporter : public MatchFinder::MatchCallback { const auto *struct_decl = result.Nodes.getNodeAs("struct_decl"); if (struct_decl == nullptr) { - // Add the typedef to TypeAliases, and recurse on the underlying type. + // Generate the definition for the underlying type, then copy it for + // this struct. const auto type = typedef_decl->getUnderlyingType(); const auto type_name = type.getAsString(); - TypeAliases[name] = type_name; - add_type_definition(type, type_name, sm); + add_type_definition(type, type_name, ctx); + + if (type->isRecordType()) { + RecordDefinitions[name] = RecordDefinitions[type_name]; + } else { + TypeAliases[name] = TypeAliases[type_name]; + } return; } - add_type_definition(result.Context->getTypeDeclType(struct_decl), name, sm); + add_type_definition(ctx->getTypeDeclType(struct_decl), name, ctx); } // Adds the type definition of `type` to either `RecordDefinitions` or // `TypeAliases`, mapped to `name`. Recursively adds the type definitions // of any nested types. void add_type_definition(const clang::QualType &type, const std::string &name, - const clang::SourceManager &sm) { + const clang::ASTContext *ctx) { // We've already handled this type. if (ParsedTypes.contains(name)) { return; @@ -132,9 +139,12 @@ struct DriverStructReporter : public MatchFinder::MatchCallback { if (canonical_type->isRecordType()) { const auto record_decl = canonical_type->getAsRecordDecl(); - add_record_definition(record_decl, name, sm); + add_record_definition(record_decl, name, ctx); } else { - TypeAliases[name] = canonical_type.getAsString(); + // getTypeSize returns the size in bits, so we divide by 8 to get bytes. + uint64_t size = ctx->getTypeSize(canonical_type) / 8; + TypeAliases[name] = json::object( + {{"size", size}, {"type", canonical_type.getAsString()}}); } } @@ -142,7 +152,7 @@ struct DriverStructReporter : public MatchFinder::MatchCallback { // to `name`. Recursively adds the type definitions of any nested types. void add_record_definition(const clang::RecordDecl *record_decl, const std::string &name, - const clang::SourceManager &sm) { + const clang::ASTContext *ctx) { json fields; for (const auto *field : record_decl->fields()) { auto field_type = field->getType(); @@ -182,13 +192,15 @@ struct DriverStructReporter : public MatchFinder::MatchCallback { {{"name", field->getNameAsString()}, {"type", field_type_name}})); // Recurse on the field type. - add_type_definition(field_type, base_type_name, sm); + add_type_definition(field_type, base_type_name, ctx); } - std::string source = record_decl->getLocation().printToString(sm); - + std::string source = + record_decl->getLocation().printToString(ctx->getSourceManager()); + // getTypeSize returns the size in bits, so we divide by 8 to get bytes. + uint64_t size = ctx->getTypeSize(record_decl->getTypeForDecl()) / 8; RecordDefinitions[name] = - json::object({{"source", source}, {"fields", fields}}); + json::object({{"source", source}, {"fields", fields}, {"size", size}}); } }; diff --git a/tools/nvidia_driver_differ/driver_ast_parser_test.go b/tools/nvidia_driver_differ/driver_ast_parser_test.go index e61f43816..225a53258 100644 --- a/tools/nvidia_driver_differ/driver_ast_parser_test.go +++ b/tools/nvidia_driver_differ/driver_ast_parser_test.go @@ -56,7 +56,7 @@ func TestParser(t *testing.T) { }() input := parser.InputJSON{ - Structs: []string{"TestStruct"}, + Structs: []string{"TestStruct", "TestStruct2"}, } if err := json.NewEncoder(structsFile).Encode(&input); err != nil { t.Fatalf("failed to write input structs file: %v", err) @@ -84,6 +84,17 @@ func TestParser(t *testing.T) { parser.RecordField{Name: "e", Type: "TestStruct::e_t[4]"}, parser.RecordField{Name: "f", Type: "TestUnion"}, }, + Size: 44, + Source: "test_struct.cc:25:16", + }, + "TestStruct2": parser.RecordDef{ + Fields: []parser.RecordField{ + parser.RecordField{Name: "a", Type: "int"}, + parser.RecordField{Name: "b", Type: "int"}, + parser.RecordField{Name: "e", Type: "TestStruct::e_t[4]"}, + parser.RecordField{Name: "f", Type: "TestUnion"}, + }, + Size: 44, Source: "test_struct.cc:25:16", }, "TestStruct::e_t": parser.RecordDef{ @@ -91,6 +102,7 @@ func TestParser(t *testing.T) { parser.RecordField{Name: "c", Type: "OtherInt"}, parser.RecordField{Name: "d", Type: "OtherInt"}, }, + Size: 8, Source: "test_struct.cc:28:3", }, "TestUnion": parser.RecordDef{ @@ -98,12 +110,13 @@ func TestParser(t *testing.T) { parser.RecordField{Name: "u_a", Type: "int"}, parser.RecordField{Name: "u_b", Type: "int"}, }, + Size: 4, Source: "test_struct.cc:20:9", }, }, Aliases: parser.TypeAliases{ - "OtherInt": "int", - "int": "int", + "OtherInt": parser.TypeDef{Type: "int", Size: 4}, + "int": parser.TypeDef{Type: "int", Size: 4}, }, } diff --git a/tools/nvidia_driver_differ/parser/json_definitions.go b/tools/nvidia_driver_differ/parser/json_definitions.go index 82d4bfee3..7686ba7c1 100644 --- a/tools/nvidia_driver_differ/parser/json_definitions.go +++ b/tools/nvidia_driver_differ/parser/json_definitions.go @@ -61,29 +61,38 @@ func (s RecordField) String() string { // RecordDef represents the definition of a record (struct or union). type RecordDef struct { Fields []RecordField + Size uint64 Source string } -// Equals returns true if the two record definitions are equal. We only -// compare the fields, not the source. +// Equals returns true if the two record definitions are equal. We ignore the source of the records. func (s RecordDef) Equals(other RecordDef) bool { - return slices.Equal(s.Fields, other.Fields) + return s.Size == other.Size && slices.Equal(s.Fields, other.Fields) +} + +// TypeDef represents the definition of a type. +type TypeDef struct { + Type string + Size uint64 } // RecordDefs is a map of type names to definitions. type RecordDefs map[string]RecordDef // TypeAliases is a map of type aliases to their underlying type. -type TypeAliases map[string]string +type TypeAliases map[string]TypeDef // GetRecordDiff prints a diff between two records. -func GetRecordDiff(name nvproxy.DriverStructName, s1, s2 RecordDef) string { - var b strings.Builder - fmt.Fprintf(&b, "--- A: %s\n", s1.Source) - fmt.Fprintf(&b, "+++ B: %s\n", s2.Source) +func GetRecordDiff(name nvproxy.DriverStructName, a, b RecordDef) string { + var sb strings.Builder + fmt.Fprintf(&sb, "--- A: %s\n", a.Source) + fmt.Fprintf(&sb, "+++ B: %s\n", b.Source) - fmt.Fprintf(&b, "struct %s\n", name) - fmt.Fprint(&b, cmp.Diff(s1.Fields, s2.Fields)) + fmt.Fprintf(&sb, "struct %s\n", name) + if a.Size != b.Size { + fmt.Fprintf(&sb, " size: %d -> %d (bytes)\n", a.Size, b.Size) + } + fmt.Fprint(&sb, cmp.Diff(a.Fields, b.Fields)) - return b.String() + return sb.String() } diff --git a/tools/nvidia_driver_differ/run_differ.go b/tools/nvidia_driver_differ/run_differ.go index 171a1dd2f..f28dcf92a 100644 --- a/tools/nvidia_driver_differ/run_differ.go +++ b/tools/nvidia_driver_differ/run_differ.go @@ -170,8 +170,8 @@ func Main() error { continue } - if baseAlias != nextAlias { - log.Infof("alias %s changed from %s to %s", name, baseAlias, nextAlias) + if baseAlias.Type != nextAlias.Type { + log.Infof("alias %s changed from %s to %s", name, baseAlias.Type, nextAlias.Type) } } diff --git a/tools/nvidia_driver_differ/test_struct.cc b/tools/nvidia_driver_differ/test_struct.cc index 347a51376..bd055ebe5 100644 --- a/tools/nvidia_driver_differ/test_struct.cc +++ b/tools/nvidia_driver_differ/test_struct.cc @@ -31,3 +31,5 @@ typedef struct TestStruct { } e[4]; TestUnion f; } TestStruct; + +typedef TestStruct TestStruct2;