diff --git a/.github/workflows/ci-cpp.yml b/.github/workflows/ci-cpp.yml index 4802c567b..8f616c891 100644 --- a/.github/workflows/ci-cpp.yml +++ b/.github/workflows/ci-cpp.yml @@ -103,6 +103,9 @@ jobs: - name: Run Test target # if: github.event_name != 'pull_request' env: + LLVM_LIB_DIR: /home/runner/work/spice/llvm/build/lib + LLVM_INCLUDE_DIR: /home/runner/work/spice/llvm/llvm/include + LLVM_BUILD_INCLUDE_DIR: /home/runner/work/spice/llvm/build/include SPICE_STD_DIR: /home/runner/work/spice/spice/std SPICE_BOOTSTRAP_DIR: /home/runner/work/spice/spice/src-bootstrap run: | @@ -112,6 +115,9 @@ jobs: # - name: Run Test target with Valgrind # if: github.event_name == 'pull_request' # env: +# LLVM_LIB_DIR: /home/runner/work/spice/llvm/build/lib +# LLVM_INCLUDE_DIR: /home/runner/work/spice/llvm/llvm/include +# LLVM_BUILD_INCLUDE_DIR: /home/runner/work/spice/llvm/build/include # SPICE_STD_DIR: /home/runner/work/spice/spice/std # SPICE_BOOTSTRAP_DIR: /home/runner/work/spice/spice/src-bootstrap # run: | diff --git a/.run/spice.run.xml b/.run/spice.run.xml index ab577d7da..3b09fbe29 100644 --- a/.run/spice.run.xml +++ b/.run/spice.run.xml @@ -1,9 +1,10 @@ - + - - + + + diff --git a/.run/spicetest.run.xml b/.run/spicetest.run.xml index 2b9329852..4e6a6a964 100644 --- a/.run/spicetest.run.xml +++ b/.run/spicetest.run.xml @@ -1,7 +1,11 @@ - + + + + + diff --git a/docs/docs/language/attributes.md b/docs/docs/language/attributes.md index 806738767..4df1736bd 100644 --- a/docs/docs/language/attributes.md +++ b/docs/docs/language/attributes.md @@ -17,6 +17,8 @@ For attributes of type bool, the value `true` can be omitted. ### Available attributes - `core.linker.flag: string (default: "")`: Append linker flag +- `core.linux.linker.flag: string (default: "")`: Append linker flag for Linux +- `core.windows.linker.flag: string (default: "")`: Append linker flag for Windows - `core.compiler.alwaysKeepOnNameCollision: bool (default: false)`: Always keep the symbols of this source files when merging the name registries of multiple source files diff --git a/media/test-project/test.spice b/media/test-project/test.spice index 23b63a27d..e5df07450 100644 --- a/media/test-project/test.spice +++ b/media/test-project/test.spice @@ -1,22 +1,54 @@ -type Struct struct { - int _fieldA - bool _fieldB - string _fieldC -} +import "bootstrap/bindings/llvm/llvm" as llvm; +import "std/data/vector"; f main() { - printf("Alignment of double: %d\n", alignof(-19.34989)); - printf("Alignment of int: %d\n", alignof(353)); - printf("Alignment of short: %d\n", alignof(35s)); - printf("Alignment of long: %d\n", alignof(9223372036854775807l)); - printf("Alignment of byte: %d\n", alignof((byte) 13)); - printf("Alignment of char: %d\n", alignof((char) 65)); - printf("Alignment of string: %d\n", alignof("Hello Spice!")); - printf("Alignment of bool: %d\n", alignof(false)); - printf("Alignment of int[]: %d\n", alignof([1, 2, 3, 4, 5, 6, 7])); - int intVariable = 123; - printf("Alignment of int*: %d\n", alignof(&intVariable)); - printf("Alignment of struct instance: %d\n", alignof(type Struct)); + llvm::initializeNativeTarget(); + llvm::initializeNativeAsmPrinter(); + + heap string targetTriple = llvm::getDefaultTargetTriple(); + string error; + llvm::Target target = llvm::getTargetFromTriple(targetTriple, &error); + llvm::TargetMachine targetMachine = target.createTargetMachine(targetTriple, "generic", "", llvm::LLVMCodeGenOptLevel::CodeGenLevelDefault, llvm::LLVMRelocMode::RelocDefault, llvm::LLVMCodeModel::CodeModelDefault); + + llvm::LLVMContext context; + llvm::Module module = llvm::Module("test", context); + module.setDataLayout(targetMachine.createDataLayout()); + module.setTargetTriple(targetTriple); + 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); + + printf("%s", module.print()); + + //llvm::PassBuilderOptions passBuilderOptions; } /*import "bootstrap/util/block-allocator"; diff --git a/src-bootstrap/bindings/llvm/linker-flags.spice b/src-bootstrap/bindings/llvm/linker-flags.spice index 59afd47dc..878a0cbd5 100644 --- a/src-bootstrap/bindings/llvm/linker-flags.spice +++ b/src-bootstrap/bindings/llvm/linker-flags.spice @@ -1,12 +1,18 @@ #![ // Paths - Linux - core.linker.flag = "-L$LLVM_LIB_DIR", - core.linker.flag = "-I$LLVM_INCLUDE_DIR", - core.linker.flag = "-I$LLVM_BUILD_INCLUDE_DIR", + core.linux.linker.flag = "-L$LLVM_LIB_DIR", + core.linux.linker.flag = "-I$LLVM_INCLUDE_DIR", + core.linux.linker.flag = "-I$LLVM_BUILD_INCLUDE_DIR", + core.linux.linker.flag = "-lm", // math + core.linux.linker.flag = "-lz", // zlib + core.linux.linker.flag = "-ltinfo", // ncurses + core.linux.linker.flag = "-lzstd", // zstd // Paths - Windows - core.linker.flag = "-L%LLVM_LIB_DIR%", // e.g.: D:/LLVM/build-release/lib - core.linker.flag = "-I%LLVM_INCLUDE_DIR%", // e.g.: D:/LLVM/llvm/include - core.linker.flag = "-I%LLVM_BUILD_INCLUDE_DIR%", // e.g.: D:/LLVM/build-release/include + core.windows.linker.flag = "-L%LLVM_LIB_DIR%", // e.g.: D:/LLVM/build-release/lib + core.windows.linker.flag = "-I%LLVM_INCLUDE_DIR%", // e.g.: D:/LLVM/llvm/include + core.windows.linker.flag = "-I%LLVM_BUILD_INCLUDE_DIR%", // e.g.: D:/LLVM/build-release/include + core.windows.linker.flag = "-lole32", // COM + core.windows.linker.flag = "-lws2_32", // WinSock // LLVM libs core.linker.flag = "-lLLVMAArch64AsmParser", core.linker.flag = "-lLLVMAArch64CodeGen", @@ -83,7 +89,9 @@ core.linker.flag = "-lLLVMExegesisX86", core.linker.flag = "-lLLVMExtensions", core.linker.flag = "-lLLVMFileCheck", + core.linker.flag = "-lLLVMFrontendDriver", core.linker.flag = "-lLLVMFrontendHLSL", + core.linker.flag = "-lLLVMFrontendOffloading", core.linker.flag = "-lLLVMFrontendOpenACC", core.linker.flag = "-lLLVMFrontendOpenMP", core.linker.flag = "-lLLVMFuzzerCLI", @@ -94,6 +102,7 @@ core.linker.flag = "-lLLVMHexagonDesc", core.linker.flag = "-lLLVMHexagonDisassembler", core.linker.flag = "-lLLVMHexagonInfo", + core.linker.flag = "-lLLVMHipStdPar", core.linker.flag = "-lLLVMInstCombine", core.linker.flag = "-lLLVMInstrumentation", core.linker.flag = "-lLLVMInterfaceStub", @@ -205,7 +214,6 @@ core.linker.flag = "-lLLVMXCoreInfo", core.linker.flag = "-lLLVMXRay", core.linker.flag = "-lstdc++", - core.linker.flag = "-lole32", core.linker.flag = "-luuid", core.linker.flag = "-pthread", // Wrapper around target macro definitions diff --git a/src/ast/Attributes.h b/src/ast/Attributes.h index 14bea0bf1..e77e0dca0 100644 --- a/src/ast/Attributes.h +++ b/src/ast/Attributes.h @@ -11,6 +11,8 @@ namespace spice::compiler { // Constants static constexpr const char *const ATTR_CORE_LINKER_FLAG = "core.linker.flag"; +static constexpr const char *const ATTR_CORE_LINUX_LINKER_FLAG = "core.linux.linker.flag"; +static constexpr const char *const ATTR_CORE_WINDOWS_LINKER_FLAG = "core.windows.linker.flag"; static constexpr const char *const ATTR_CORE_LINKER_ADDITIONAL_SOURCE = "core.linker.additional_source"; static constexpr const char *const ATTR_CORE_LINKER_DLL = "core.linker.dll"; static constexpr const char *const ATTR_CORE_COMPILER_MANGLE = "core.compiler.mangle"; @@ -42,6 +44,20 @@ static const std::unordered_map ATTR_CONFIGS = { .type = AttrNode::TYPE_STRING, }, }, + { + ATTR_CORE_LINUX_LINKER_FLAG, + { + .target = AttrNode::TARGET_MODULE, + .type = AttrNode::TYPE_STRING, + }, + }, + { + ATTR_CORE_WINDOWS_LINKER_FLAG, + { + .target = AttrNode::TARGET_MODULE, + .type = AttrNode::TYPE_STRING, + }, + }, { ATTR_CORE_LINKER_ADDITIONAL_SOURCE, { diff --git a/src/symboltablebuilder/SymbolTableBuilder.cpp b/src/symboltablebuilder/SymbolTableBuilder.cpp index eb85e9b8c..4fd9520ba 100644 --- a/src/symboltablebuilder/SymbolTableBuilder.cpp +++ b/src/symboltablebuilder/SymbolTableBuilder.cpp @@ -624,11 +624,23 @@ std::any SymbolTableBuilder::visitModAttr(ModAttrNode *node) { // Retrieve attributes const AttrLstNode *attrs = node->attrLst(); + // Collect linker flags + std::vector linkerFlagValues; // core.linker.flag - for (const CompileTimeValue *value : attrs->getAttrValuesByName(ATTR_CORE_LINKER_FLAG)) { - const std::string &stringValue = resourceManager.compileTimeStringValues.at(value->stringValueOffset); - resourceManager.linker.addLinkerFlag(stringValue); + std::vector values = attrs->getAttrValuesByName(ATTR_CORE_LINKER_FLAG); + linkerFlagValues.insert(linkerFlagValues.end(), values.begin(), values.end()); + // core.linux.linker.flag + if (resourceManager.targetMachine->getTargetTriple().isOSLinux()) { + values = attrs->getAttrValuesByName(ATTR_CORE_LINUX_LINKER_FLAG); + linkerFlagValues.insert(linkerFlagValues.end(), values.begin(), values.end()); + } + // core.windows.linker.flag + if (resourceManager.targetMachine->getTargetTriple().isOSWindows()) { + values = attrs->getAttrValuesByName(ATTR_CORE_WINDOWS_LINKER_FLAG); + linkerFlagValues.insert(linkerFlagValues.end(), values.begin(), values.end()); } + for (const CompileTimeValue *value : linkerFlagValues) + resourceManager.linker.addLinkerFlag(resourceManager.compileTimeStringValues.at(value->stringValueOffset)); // core.linker.additional_source for (const CompileTimeValue *value : attrs->getAttrValuesByName(ATTR_CORE_LINKER_ADDITIONAL_SOURCE)) { diff --git a/test/test-files/bootstrap-compiler/standalone-llvm-bindings/cout.out b/test/test-files/bootstrap-compiler/standalone-llvm-bindings/cout.out new file mode 100644 index 000000000..81df84f23 --- /dev/null +++ b/test/test-files/bootstrap-compiler/standalone-llvm-bindings/cout.out @@ -0,0 +1,11 @@ +; ModuleID = 'test' +source_filename = "test" + +@helloWorldStr = private unnamed_addr constant [15 x i8] c"Hello, world!\0A\00", align 1 + +define i32 @main() { + %1 = call i32 (ptr, i32, ...) @printf(ptr @helloWorldStr, i32 3) + ret i32 0 +} + +declare i32 @printf(ptr, i32, ...) diff --git a/test/test-files/bootstrap-compiler/standalone-llvm-bindings/source.spice b/test/test-files/bootstrap-compiler/standalone-llvm-bindings/source.spice new file mode 100644 index 000000000..d20e0f230 --- /dev/null +++ b/test/test-files/bootstrap-compiler/standalone-llvm-bindings/source.spice @@ -0,0 +1,50 @@ +import "bootstrap/bindings/llvm/llvm" as llvm; +import "std/data/vector"; + +f main() { + llvm::initializeNativeTarget(); + llvm::initializeNativeAsmPrinter(); + + heap string targetTriple = llvm::getDefaultTargetTriple(); + string error; + llvm::Target target = llvm::getTargetFromTriple(targetTriple, &error); + llvm::TargetMachine targetMachine = target.createTargetMachine(targetTriple, "generic", "", llvm::LLVMCodeGenOptLevel::CodeGenLevelDefault, llvm::LLVMRelocMode::RelocDefault, llvm::LLVMCodeModel::CodeModelDefault); + + 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); + + printf("%s", module.print()); +} \ No newline at end of file