From 15c0ecff0883ae69a00d301916bb3ce43b3b85fd Mon Sep 17 00:00:00 2001 From: Marc Auberer Date: Thu, 9 May 2024 18:53:13 +0200 Subject: [PATCH] Improve code --- media/test-project/test.spice | 129 +++++++++++++++++++++--- src-bootstrap/bindings/llvm/llvm.spice | 2 +- src/SourceFile.cpp | 6 +- src/global/TypeRegistry.cpp | 42 ++++++++ src/global/TypeRegistry.h | 1 + src/symboltablebuilder/QualType.cpp | 2 +- src/typechecker/OpRuleManager.cpp | 2 +- src/typechecker/TypeChecker.cpp | 4 +- src/typechecker/TypeCheckerImplicit.cpp | 4 +- 9 files changed, 167 insertions(+), 25 deletions(-) diff --git a/media/test-project/test.spice b/media/test-project/test.spice index fa05b2420..ba25fac35 100644 --- a/media/test-project/test.spice +++ b/media/test-project/test.spice @@ -1,26 +1,123 @@ -type T int|long; +import "bootstrap/bindings/llvm/llvm" as llvm; +import "std/data/vector"; -type TestStruct struct { - T _f1 - unsigned long length -} +f main() { + llvm::initializeNativeTarget(); + llvm::initializeNativeAsmPrinter(); -p TestStruct.ctor(const unsigned long initialLength) { - this.length = initialLength; -} + heap string targetTriple = llvm::getDefaultTargetTriple(); + string error; + llvm::Target target = llvm::getTargetFromTriple(targetTriple, &error); + llvm::TargetMachine targetMachine = target.createTargetMachine(targetTriple, "generic", "", llvm::LLVMCodeGenOptLevel::Default, llvm::LLVMRelocMode::Default, llvm::LLVMCodeModel::Default); + + llvm::LLVMContext context; + llvm::Module module = llvm::Module("test", context); + module.setDataLayout(targetMachine.createDataLayout()); + //module.setTargetTriple(targetTriple); // This emits target dependent information in the IR, which is not what we want here. + llvm::Builder builder = llvm::Builder(context); + + llvm::Type returnType = builder.getInt32Ty(); + Vector argTypes; + llvm::Type funcType = llvm::getFunctionType(returnType, argTypes); + llvm::Function func = llvm::Function(module, "main", funcType); + func.setLinkage(llvm::LLVMLinkage::ExternalLinkage); + + llvm::BasicBlock entry = llvm::BasicBlock(context, ""); + func.pushBack(entry); + builder.setInsertPoint(entry); + + llvm::Value calcResult = builder.createAdd(builder.getInt32(1), builder.getInt32(2), "calcResult"); + + llvm::Value helloWorldStr = builder.createGlobalStringPtr("Hello, world!\n", "helloWorldStr"); + Vector printfArgTypes; + printfArgTypes.pushBack(builder.getPtrTy()); + printfArgTypes.pushBack(builder.getInt32Ty()); + llvm::Type printfFuncType = llvm::getFunctionType(builder.getInt32Ty(), printfArgTypes, true); + llvm::Function printfFunc = module.getOrInsertFunction("printf", printfFuncType); + + Vector printfArgs; + printfArgs.pushBack(helloWorldStr); + printfArgs.pushBack(calcResult); + builder.createCall(printfFunc, printfArgs); + + builder.createRet(builder.getInt32(0)); + + assert !llvm::verifyFunction(func); + string output; + assert !llvm::verifyModule(module, &output); -p TestStruct.printLength() { - printf("%d\n", this.length); + printf("Unoptimized IR:\n%s", module.print()); + + llvm::PassBuilderOptions pto; + llvm::PassBuilder passBuilder = llvm::PassBuilder(pto); + passBuilder.buildPerModuleDefaultPipeline(llvm::OptimizationLevel::O2); + passBuilder.addPass(llvm::AlwaysInlinerPass()); + passBuilder.run(module, targetMachine); + + printf("Optimized IR:\n%s", module.print()); + + targetMachine.emitToFile(module, "this-is-a-test.o", llvm::LLVMCodeGenFileType::ObjectFile); } -type Alias alias TestStruct; +/*import "std/iterator/array-iterator"; +import "std/data/pair"; f main() { - Alias a = Alias{12345l, (unsigned long) 54321l}; - a.printLength(); - dyn b = Alias(12l); - b.printLength(); -} + // Create test array to iterate over + int[5] a = [ 123, 4321, 9876, 321, -99 ]; + + // Test base functionality + dyn it = iterate(a, len(a)); + assert it.isValid(); + assert it.get() == 123; + assert it.get() == 123; + it.next(); + assert it.get() == 4321; + assert it.isValid(); + it.next(); + dyn pair = it.getIdx(); + assert pair.getFirst() == 2; + assert pair.getSecond() == 9876; + it.next(); + + // Test overloaded operators + it -= 3; + assert it.get() == 123; + assert it.isValid(); + it++; + assert it.get() == 4321; + it--; + assert it.get() == 123; + it += 4; + assert it.get() == -99; + it.next(); + assert !it.isValid(); + + // Test foreach value + foreach int item : iterate(a, len(a)) { + item++; + } + assert a[0] == 123; + assert a[1] == 4321; + assert a[2] == 9876; + + // Test foreach ref + foreach int& item : iterate(a, len(a)) { + item++; + } + assert a[0] == 124; + assert a[1] == 4322; + assert a[2] == 9877; + + foreach long idx, int& item : iterate(a, len(a)) { + item += idx; + } + assert a[0] == 124; + assert a[1] == 4323; + assert a[2] == 9879; + + printf("All assertions passed!"); +}*/ /*import "bootstrap/util/block-allocator"; import "bootstrap/util/memory"; diff --git a/src-bootstrap/bindings/llvm/llvm.spice b/src-bootstrap/bindings/llvm/llvm.spice index 5c9413491..30476f4fe 100644 --- a/src-bootstrap/bindings/llvm/llvm.spice +++ b/src-bootstrap/bindings/llvm/llvm.spice @@ -780,7 +780,7 @@ public f Builder.getStruct(const Vector& values, bool packed = fal public f Builder.getArray(Type ty, const Vector& values) { unsafe { LLVMValueRef* valuesRef = (LLVMValueRef*) values.getDataPtr(); - LLVMValueRef valueRef = LLVMConstArray2(ty.self, valuesRef, (unsigned long) values.getSize()); + LLVMValueRef valueRef = LLVMConstArray2(ty.self, valuesRef, values.getSize()); return Value{ valueRef }; } } diff --git a/src/SourceFile.cpp b/src/SourceFile.cpp index 279253094..7781633f4 100644 --- a/src/SourceFile.cpp +++ b/src/SourceFile.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -554,6 +555,7 @@ void SourceFile::runBackEnd() { // NOLINT(misc-no-recursion) CHECK_ABORT_FLAG_V() std::cout << "\nSuccessfully compiled " << std::to_string(resourceManager.sourceFiles.size()) << " source file(s)"; std::cout << " or " << std::to_string(resourceManager.getTotalLineCount()) << " lines in total.\n"; + std::cout << "Total number of types: " << std::to_string(TypeRegistry::getTypeCount()) << "\n"; std::cout << "Total compile time: " << std::to_string(resourceManager.totalTimer.getDurationMilliseconds()) << " ms\n"; } } @@ -582,8 +584,8 @@ bool SourceFile::imports(const SourceFile *sourceFile) const { return std::ranges::any_of(dependencies, [=](const auto &dependency) { return dependency.second == sourceFile; }); } -bool SourceFile::isAlreadyImported(const std::string &filePathSearch, - std::vector &circle) const { // NOLINT(misc-no-recursion) +bool SourceFile::isAlreadyImported(const std::string &filePathSearch, // NOLINT(misc-no-recursion) + std::vector &circle) const { circle.push_back(this); // Check if the current source file corresponds to the path to search if (std::filesystem::equivalent(filePath, filePathSearch)) diff --git a/src/global/TypeRegistry.cpp b/src/global/TypeRegistry.cpp index 7163b0997..01b40d990 100644 --- a/src/global/TypeRegistry.cpp +++ b/src/global/TypeRegistry.cpp @@ -9,6 +9,12 @@ namespace spice::compiler { // Static member initialization std::unordered_map> TypeRegistry::types = {}; +/** + * Get or insert a type into the type registry + * + * @param type The type to insert + * @return The inserted type + */ const Type *TypeRegistry::getOrInsert(const Type &&type) { const uint64_t hash = std::hash{}(type); @@ -22,17 +28,53 @@ const Type *TypeRegistry::getOrInsert(const Type &&type) { return insertedElement.first->second.get(); } +/** + * Get or insert a type into the type registry + * + * @param superType The super type of the type + * @return The inserted type + */ const Type *TypeRegistry::getOrInsert(SuperType superType) { return getOrInsert(Type(superType)); } +/** + * Get or insert a type into the type registry + * + * @param superType The super type of the type + * @param subType The sub type of the type + * @return The inserted type + */ const Type *TypeRegistry::getOrInsert(SuperType superType, const std::string &subType) { return getOrInsert(Type(superType, subType)); } +/** + * Get or insert a type into the type registry + * + * @param superType The super type of the type + * @param subType The sub type of the type + * @param typeId The type ID of the type + * @param data The data of the type + * @param templateTypes The template types of the type + * @return The inserted type + */ const Type *TypeRegistry::getOrInsert(SuperType superType, const std::string &subType, uint64_t typeId, const TypeChainElementData &data, const QualTypeList &templateTypes) { return getOrInsert(Type(superType, subType, typeId, data, templateTypes)); } +/** + * Get or insert a type into the type registry + * + * @param typeChain The type chain of the type + * @return The inserted type + */ const Type *TypeRegistry::getOrInsert(const TypeChain &typeChain) { return getOrInsert(Type(typeChain)); } +/** + * Get the number of types in the type registry + * + * @return The number of types in the type registry + */ +const size_t TypeRegistry::getTypeCount() { return types.size(); } + } // namespace spice::compiler diff --git a/src/global/TypeRegistry.h b/src/global/TypeRegistry.h index 5a36a5b23..54e422b1f 100644 --- a/src/global/TypeRegistry.h +++ b/src/global/TypeRegistry.h @@ -23,6 +23,7 @@ class TypeRegistry { static const Type *getOrInsert(SuperType superType, const std::string &subType, uint64_t typeId, const TypeChainElementData &data, const QualTypeList &templateTypes); static const Type *getOrInsert(const TypeChain& typeChain); + static const size_t getTypeCount(); private: // Private members diff --git a/src/symboltablebuilder/QualType.cpp b/src/symboltablebuilder/QualType.cpp index fe3eb5d58..36d5c2e9d 100644 --- a/src/symboltablebuilder/QualType.cpp +++ b/src/symboltablebuilder/QualType.cpp @@ -461,7 +461,7 @@ QualType QualType::toRef(const ASTNode *node) const { */ QualType QualType::toConstRef(const ASTNode *node) const { QualType qualType = toRef(node); - qualType.specifiers.isConst = true; + qualType.makeConst(); return qualType; } diff --git a/src/typechecker/OpRuleManager.cpp b/src/typechecker/OpRuleManager.cpp index 696fc477b..f50329f32 100644 --- a/src/typechecker/OpRuleManager.cpp +++ b/src/typechecker/OpRuleManager.cpp @@ -710,7 +710,7 @@ QualType OpRuleManager::validateBinaryOperation(const ASTNode *node, const Binar for (size_t i = 0; i < opRulesSize; i++) { const BinaryOpRule &rule = opRules[i]; if (std::get<0>(rule) == lhs.getSuperType() && std::get<1>(rule) == rhs.getSuperType()) { - QualType resultType = QualType(SuperType(std::get<2>(rule))); + QualType resultType(SuperType(std::get<2>(rule))); if (preserveSpecifiersFromLhs) resultType.setSpecifiers(lhs.getSpecifiers()); return resultType; diff --git a/src/typechecker/TypeChecker.cpp b/src/typechecker/TypeChecker.cpp index e3a41b54b..1a4f7e2ef 100644 --- a/src/typechecker/TypeChecker.cpp +++ b/src/typechecker/TypeChecker.cpp @@ -169,8 +169,8 @@ std::any TypeChecker::visitForeachLoop(ForeachLoopNode *node) { Scope *matchScope = nameRegistryEntry->targetScope->parent; assert(matchScope->type == ScopeType::GLOBAL); QualType unsignedLongType(TY_LONG); - unsignedLongType.getSpecifiers().isSigned = false; - unsignedLongType.getSpecifiers().isUnsigned = true; + unsignedLongType.makeSigned(false); + unsignedLongType.makeUnsigned(true); const ArgList argTypes = {Arg(iterableType, false), Arg(unsignedLongType, false)}; const QualType thisType(TY_DYN); node->getIteratorFct = FunctionManager::matchFunction(matchScope, "iterate", thisType, argTypes, {}, true, iteratorNode); diff --git a/src/typechecker/TypeCheckerImplicit.cpp b/src/typechecker/TypeCheckerImplicit.cpp index 3549425c4..306cd6fcb 100644 --- a/src/typechecker/TypeCheckerImplicit.cpp +++ b/src/typechecker/TypeCheckerImplicit.cpp @@ -29,7 +29,7 @@ void TypeChecker::createDefaultStructMethod(const Struct &spiceStruct, const std // Procedure type QualType procedureType(TY_PROCEDURE); - procedureType.getSpecifiers().isPublic = true; // Always public + procedureType.makePublic(); // Always public // Insert symbol for function into the symbol table const std::string entryName = Function::getSymbolTableEntryName(methodName, node->codeLoc); @@ -229,7 +229,7 @@ void TypeChecker::createDefaultDtorIfRequired(const Struct &spiceStruct, Scope * // Set dealloc function to used const QualType thisType(TY_DYN); QualType bytePtrRefType = QualType(TY_BYTE).toPtr(node).toRef(node); - bytePtrRefType.getSpecifiers().isHeap = true; + bytePtrRefType.makeHeap(); const ArgList args = {{bytePtrRefType, false /* we always have the field as storage */}}; Function *deallocFct = FunctionManager::matchFunction(matchScope, FCT_NAME_DEALLOC, thisType, args, {}, true, node); assert(deallocFct != nullptr);