From c2db112b28932b72a6b661987730b4199366c370 Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Sun, 12 May 2024 14:12:36 +0200 Subject: [PATCH] Add type registry dumper (#549) --- .run/spice.run.xml | 2 +- docs/docs/cli/build.md | 1 + docs/docs/cli/install.md | 1 + docs/docs/cli/run.md | 1 + docs/docs/cli/test.md | 1 + media/test-project/test.spice | 46 +++++++++---------- src/SourceFile.cpp | 8 ++++ src/SourceFile.h | 1 + src/driver/Driver.cpp | 2 + src/driver/Driver.h | 1 + src/global/TypeRegistry.cpp | 24 +++++++++- src/global/TypeRegistry.h | 1 + src/symboltablebuilder/TypeChain.cpp | 4 +- src/util/CustomHashFunctions.cpp | 2 +- test/TestRunner.cpp | 6 +++ .../success-ackermann/type-registry.out | 7 +++ .../success-faculty/type-registry.out | 7 +++ .../type-registry.out | 37 +++++++++++++++ .../success-fibonacci/type-registry.out | 7 +++ .../success-hello-world/type-registry.out | 5 ++ .../success-hello-world2/type-registry.out | 7 +++ .../success-pidigits/type-registry.out | 6 +++ test/util/TestUtil.h | 1 + 23 files changed, 149 insertions(+), 29 deletions(-) create mode 100644 test/test-files/benchmark/success-ackermann/type-registry.out create mode 100644 test/test-files/benchmark/success-faculty/type-registry.out create mode 100644 test/test-files/benchmark/success-fibonacci-threaded/type-registry.out create mode 100644 test/test-files/benchmark/success-fibonacci/type-registry.out create mode 100644 test/test-files/benchmark/success-hello-world/type-registry.out create mode 100644 test/test-files/benchmark/success-hello-world2/type-registry.out create mode 100644 test/test-files/benchmark/success-pidigits/type-registry.out diff --git a/.run/spice.run.xml b/.run/spice.run.xml index b74e2481f..efc46a910 100644 --- a/.run/spice.run.xml +++ b/.run/spice.run.xml @@ -1,5 +1,5 @@ - + diff --git a/docs/docs/cli/build.md b/docs/docs/cli/build.md index 00c6b7db5..f7433ffb9 100644 --- a/docs/docs/cli/build.md +++ b/docs/docs/cli/build.md @@ -25,6 +25,7 @@ You can apply following options to the `build` subcommand: | `-cst` | `--dump-cst` | Dump CST as serialized string and SVG image | | `-ast` | `--dump-ast` | Dump AST as serialized string and SVG image | | `-symtab` | `--dump-symtab` | Dump serialized symbol tables | +| `-types` | `--dump-types` | Dump all used types | | `-ir` | `--dump-ir` | Dump LLVM-IR | | `-s`, `-asm` | `--dump-assembly` | Dump Assembly code | | `-b`, `-obj` | `--dump-object-file` | Dump object files | diff --git a/docs/docs/cli/install.md b/docs/docs/cli/install.md index 1fd833892..b1785d033 100644 --- a/docs/docs/cli/install.md +++ b/docs/docs/cli/install.md @@ -25,6 +25,7 @@ You can apply following options to the `install` subcommand: | `-cst` | `--dump-cst` | Dump CST as serialized string and SVG image | | `-ast` | `--dump-ast` | Dump AST as serialized string and SVG image | | `-symtab` | `--dump-symtab` | Dump serialized symbol tables | +| `-types` | `--dump-types` | Dump all used types | | `-ir` | `--dump-ir` | Dump LLVM-IR | | `-s`, `-asm` | `--dump-assembly` | Dump Assembly code | | `-b`, `-obj` | `--dump-object-file` | Dump object files | diff --git a/docs/docs/cli/run.md b/docs/docs/cli/run.md index d9898c29a..2b2939988 100644 --- a/docs/docs/cli/run.md +++ b/docs/docs/cli/run.md @@ -25,6 +25,7 @@ You can apply following options to the `run` subcommand: | `-cst` | `--dump-cst` | Dump CST as serialized string and SVG image | | `-ast` | `--dump-ast` | Dump AST as serialized string and SVG image | | `-symtab` | `--dump-symtab` | Dump serialized symbol tables | +| `-types` | `--dump-types` | Dump all used types | | `-ir` | `--dump-ir` | Dump LLVM-IR | | `-s`, `-asm` | `--dump-assembly` | Dump Assembly code | | `-b`, `-obj` | `--dump-object-file` | Dump object files | diff --git a/docs/docs/cli/test.md b/docs/docs/cli/test.md index eff8ddad9..a12b852cd 100644 --- a/docs/docs/cli/test.md +++ b/docs/docs/cli/test.md @@ -27,6 +27,7 @@ You can apply following options to the `test` subcommand: | `-cst` | `--dump-cst` | Dump CST as serialized string and SVG image | | `-ast` | `--dump-ast` | Dump AST as serialized string and SVG image | | `-symtab` | `--dump-symtab` | Dump serialized symbol tables | +| `-types` | `--dump-types` | Dump all used types | | `-ir` | `--dump-ir` | Dump LLVM-IR | | `-s`, `-asm` | `--dump-assembly` | Dump Assembly code | | `-j ` | `--jobs ` | Set number of jobs to parallelize compilation (default is auto) | diff --git a/media/test-project/test.spice b/media/test-project/test.spice index 76959fdec..f919a118c 100644 --- a/media/test-project/test.spice +++ b/media/test-project/test.spice @@ -1,32 +1,28 @@ -import "std/os/env"; -import "bootstrap/lexer/lexer"; +import "std/os/thread"; -f main() { - String filePath = getEnv("SPICE_STD_DIR") + "/../test/test-files/bootstrap-compiler/standalone-lexer-test/test-file.spice"; - Lexer lexer = Lexer(filePath.getRaw()); - unsigned long tokenCount = 0l; - while (!lexer.isEOF()) { - Token token = lexer.getToken(); - token.print(); - lexer.advance(); - tokenCount++; - } - printf("\nLexed tokens: %d\n", tokenCount); +f fib(int n) { + if n <= 2 { return 1; } + return fib(n - 1) + fib(n - 2); } -/*import "std/iterator/number-iterator"; - f main() { - NumberIterator itInt = range(1, 10); - dyn idxAndValueInt = itInt.getIdx(); - assert idxAndValueInt.getSecond() == 4; -}*/ - -/*import "std/data/hash-table"; - -f main() { - HashTable map = HashTable(3l); -}*/ + int threadCount = 8; + Thread[8] threads = []; + for unsigned int i = 0; i < threadCount; i++ { + threads[i] = Thread(p() { + int res = fib(30); + printf("Thread returned with result: %d\n", res); + }); + Thread& thread = threads[i]; + thread.run(); + } + printf("Started all threads. Waiting for results ...\n"); + for unsigned int i = 0; i < threadCount; i++ { + Thread& thread = threads[i]; + thread.join(); + } + printf("Program finished"); +} /*import "bootstrap/util/block-allocator"; import "bootstrap/util/memory"; diff --git a/src/SourceFile.cpp b/src/SourceFile.cpp index 7781633f4..66f9c09af 100644 --- a/src/SourceFile.cpp +++ b/src/SourceFile.cpp @@ -483,6 +483,14 @@ void SourceFile::concludeCompilation() { if (!cliOptions.ignoreCache) resourceManager.cacheManager.cacheSourceFile(this); + // Save type registry as string in the compiler output + if (mainFile && (cliOptions.dumpSettings.dumpTypes || cliOptions.testMode)) + compilerOutput.typesString = TypeRegistry::dump(); + + // Dump type registry + if (mainFile && cliOptions.dumpSettings.dumpTypes) + dumpOutput(compilerOutput.typesString, "Type Registry", "type-registry.out"); + // Print warning if verifier is disabled if (parent == nullptr && cliOptions.disableVerifier) { const std::string warningMessage = diff --git a/src/SourceFile.h b/src/SourceFile.h index 5947dad3a..d30eb9575 100644 --- a/src/SourceFile.h +++ b/src/SourceFile.h @@ -92,6 +92,7 @@ struct CompilerOutput { std::string irString; std::string irOptString; std::string asmString; + std::string typesString; std::vector warnings; TimerOutput times; }; diff --git a/src/driver/Driver.cpp b/src/driver/Driver.cpp index 10cb0264b..14ee63de5 100644 --- a/src/driver/Driver.cpp +++ b/src/driver/Driver.cpp @@ -337,6 +337,8 @@ void Driver::addCompileSubcommandOptions(CLI::App *subCmd) { subCmd->add_flag("--dump-ast,-ast", cliOptions.dumpSettings.dumpAST, "Dump AST as serialized string and SVG image"); // --dump-symtab subCmd->add_flag("--dump-symtab,-symtab", cliOptions.dumpSettings.dumpSymbolTable, "Dump serialized symbol tables"); + // --dump-types + subCmd->add_flag("--dump-types,-types", cliOptions.dumpSettings.dumpTypes, "Dump all used types"); // --dump-ir subCmd->add_flag("--dump-ir,-ir", cliOptions.dumpSettings.dumpIR, "Dump LLVM-IR"); // --dump-assembly diff --git a/src/driver/Driver.h b/src/driver/Driver.h index 5ed36ac20..1154d0bcb 100644 --- a/src/driver/Driver.h +++ b/src/driver/Driver.h @@ -55,6 +55,7 @@ struct CliOptions { bool dumpCST = false; bool dumpAST = false; bool dumpSymbolTable = false; + bool dumpTypes = false; bool dumpIR = false; bool dumpAssembly = false; bool dumpObjectFile = false; diff --git a/src/global/TypeRegistry.cpp b/src/global/TypeRegistry.cpp index 323e7170b..699f4961f 100644 --- a/src/global/TypeRegistry.cpp +++ b/src/global/TypeRegistry.cpp @@ -2,6 +2,8 @@ #include "TypeRegistry.h" +#include + #include namespace spice::compiler { @@ -77,6 +79,26 @@ const Type *TypeRegistry::getOrInsert(const TypeChain &typeChain) { return getOr */ size_t TypeRegistry::getTypeCount() { return types.size(); } -void TypeRegistry::clear() { types.clear();} +/** + * Dump all types in the type registry + */ +std::string TypeRegistry::dump() { + std::vector typeStrings; + typeStrings.reserve(types.size()); + for (const auto &type : types) + typeStrings.push_back(type.second->getName()); + // Sort to ensure deterministic output + std::sort(typeStrings.begin(), typeStrings.end()); + // Serialize type registry + std::stringstream typeRegistryString; + for (const std::string &typeString : typeStrings) + typeRegistryString << typeString << "\n"; + return typeRegistryString.str(); +} + +/** + * Clear the type registry + */ +void TypeRegistry::clear() { types.clear(); } } // namespace spice::compiler diff --git a/src/global/TypeRegistry.h b/src/global/TypeRegistry.h index c1998d7a9..322abfd2c 100644 --- a/src/global/TypeRegistry.h +++ b/src/global/TypeRegistry.h @@ -24,6 +24,7 @@ class TypeRegistry { const TypeChainElementData &data, const QualTypeList &templateTypes); static const Type *getOrInsert(const TypeChain& typeChain); static size_t getTypeCount(); + static std::string dump(); static void clear(); private: diff --git a/src/symboltablebuilder/TypeChain.cpp b/src/symboltablebuilder/TypeChain.cpp index 7a5308626..e75293f1d 100644 --- a/src/symboltablebuilder/TypeChain.cpp +++ b/src/symboltablebuilder/TypeChain.cpp @@ -102,7 +102,9 @@ void TypeChainElement::getName(std::stringstream &name, bool withSize) const { name << "f"; if (data.hasCaptures) name << "[]"; - name << "<" << paramTypes.front().getName(true) << ">("; + if (!paramTypes.empty()) + name << "<" << paramTypes.front().getName(true) << ">"; + name << "("; for (size_t i = 1; i < paramTypes.size(); i++) { if (i > 1) name << ","; diff --git a/src/util/CustomHashFunctions.cpp b/src/util/CustomHashFunctions.cpp index cd23cb174..f22b0eb42 100644 --- a/src/util/CustomHashFunctions.cpp +++ b/src/util/CustomHashFunctions.cpp @@ -6,7 +6,7 @@ namespace std { size_t hash::operator()(const spice::compiler::TypeChainElement &tce) const { // Hasher for QualTypeList - const auto pred = [](size_t acc, const spice::compiler::QualType &val) { + constexpr auto pred = [](size_t acc, const spice::compiler::QualType &val) { // Combine the previous hash value with the current element's hash, adjusted by a prime number to reduce collisions return acc * 31 + std::hash{}(val); }; diff --git a/test/TestRunner.cpp b/test/TestRunner.cpp index 0ee60f107..8064787bc 100644 --- a/test/TestRunner.cpp +++ b/test/TestRunner.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,7 @@ void execTestCase(const TestCase &testCase) { /* dumpCST= */ false, /* dumpAST= */ false, /* dumpSymbolTables= */ false, + /* dumpTypes= */ false, /* dumpIR= */ false, /* dumpAssembly= */ false, /* dumpObjectFile= */ false, @@ -71,6 +73,7 @@ void execTestCase(const TestCase &testCase) { /* disableVerifier= */ false, /* testMode= */ true, }; + static_assert(sizeof(CliOptions::DumpSettings) == 9, "CliOptions::DumpSettings struct size changed"); static_assert(sizeof(CliOptions) == 360, "CliOptions struct size changed"); // Instantiate GlobalResourceManager @@ -196,6 +199,9 @@ void execTestCase(const TestCase &testCase) { resourceManager.linker.link(); } + // Check type registry output + TestUtil::checkRefMatch(testCase.testPath / REF_NAME_TYPE_REGISTRY, [&]() { return TypeRegistry::dump(); }); + // Check if the execution output matches the expected output TestUtil::checkRefMatch(testCase.testPath / REF_NAME_EXECUTION_OUTPUT, [&]() { const std::filesystem::path cliFlagsFile = testCase.testPath / INPUT_NAME_CLI_FLAGS; diff --git a/test/test-files/benchmark/success-ackermann/type-registry.out b/test/test-files/benchmark/success-ackermann/type-registry.out new file mode 100644 index 000000000..b715b3f2e --- /dev/null +++ b/test/test-files/benchmark/success-ackermann/type-registry.out @@ -0,0 +1,7 @@ +bool +dyn +f() +f() +f(int,int) +int +invalid diff --git a/test/test-files/benchmark/success-faculty/type-registry.out b/test/test-files/benchmark/success-faculty/type-registry.out new file mode 100644 index 000000000..01d3c8322 --- /dev/null +++ b/test/test-files/benchmark/success-faculty/type-registry.out @@ -0,0 +1,7 @@ +bool +dyn +f() +f() +f(int) +int +invalid diff --git a/test/test-files/benchmark/success-fibonacci-threaded/type-registry.out b/test/test-files/benchmark/success-fibonacci-threaded/type-registry.out new file mode 100644 index 000000000..c7df3a982 --- /dev/null +++ b/test/test-files/benchmark/success-fibonacci-threaded/type-registry.out @@ -0,0 +1,37 @@ +* +Error +Error& +Error* +Pthread_attr_t +Pthread_attr_t& +Pthread_attr_t* +Thread +Thread +Thread& +Thread* +bool +byte +byte* +byte** +char +char* +dyn +dyn +f() +f() +f(int) +f(long*,Pthread_attr_t*,p()) +f(long,byte**) +f() +import +int +invalid +long +long +long* +p() +p() +p(int,string) +p(p()) +p(string) +string diff --git a/test/test-files/benchmark/success-fibonacci/type-registry.out b/test/test-files/benchmark/success-fibonacci/type-registry.out new file mode 100644 index 000000000..01d3c8322 --- /dev/null +++ b/test/test-files/benchmark/success-fibonacci/type-registry.out @@ -0,0 +1,7 @@ +bool +dyn +f() +f() +f(int) +int +invalid diff --git a/test/test-files/benchmark/success-hello-world/type-registry.out b/test/test-files/benchmark/success-hello-world/type-registry.out new file mode 100644 index 000000000..88cb97e41 --- /dev/null +++ b/test/test-files/benchmark/success-hello-world/type-registry.out @@ -0,0 +1,5 @@ +bool +f() +f() +int +invalid diff --git a/test/test-files/benchmark/success-hello-world2/type-registry.out b/test/test-files/benchmark/success-hello-world2/type-registry.out new file mode 100644 index 000000000..6b80f408a --- /dev/null +++ b/test/test-files/benchmark/success-hello-world2/type-registry.out @@ -0,0 +1,7 @@ +bool +char +f() +f() +int +invalid +long diff --git a/test/test-files/benchmark/success-pidigits/type-registry.out b/test/test-files/benchmark/success-pidigits/type-registry.out new file mode 100644 index 000000000..f18c0d9a7 --- /dev/null +++ b/test/test-files/benchmark/success-pidigits/type-registry.out @@ -0,0 +1,6 @@ +bool +f() +f() +int +invalid +long diff --git a/test/util/TestUtil.h b/test/util/TestUtil.h index b111223fa..4b2897c29 100644 --- a/test/util/TestUtil.h +++ b/test/util/TestUtil.h @@ -30,6 +30,7 @@ const char *const REF_NAME_SOURCE = "source.spice"; const char *const REF_NAME_PARSE_TREE = "parse-tree.dot"; const char *const REF_NAME_SYNTAX_TREE = "syntax-tree.dot"; const char *const REF_NAME_SYMBOL_TABLE = "symbol-table.json"; +const char *const REF_NAME_TYPE_REGISTRY = "type-registry.out"; const char *const REF_NAME_IR = "ir-code.ll"; const char *const REF_NAME_ASM = "assembly.asm"; const char *const REF_NAME_OPT_IR[5] = {"ir-code-O1.ll", "ir-code-O2.ll", "ir-code-O3.ll", "ir-code-Os.ll", "ir-code-Oz.ll"};