Skip to content

Commit

Permalink
Add tests for LLVM bindings (#472)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer authored Feb 22, 2024
1 parent aaec518 commit edcca00
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 31 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand All @@ -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: |
Expand Down
7 changes: 4 additions & 3 deletions .run/spice.run.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="build -d -O2 -ir ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -d -O2 -ir ../../media/test-project/test.spice" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spice" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spice">
<envs>
<env name="LLVM_LIB_DIR" value="D:/LLVM/build-release/lib" />
<env name="LLVM_INCLUDE_DIR" value="D:/LLVM/llvm/include" />
<env name="LLVM_BUILD_INCLUDE_DIR" value="D:/LLVM/build-release/include" />
<env name="LLVM_INCLUDE_DIR" value="D:/LLVM/llvm/include" />
<env name="LLVM_LIB_DIR" value="D:/LLVM/build-release/lib" />
<env name="LLVM_ADDITIONAL_FLAGS" value="-lole32 -lws2_32" />
<env name="SPICE_STD_DIR" value="$PROJECT_DIR$/std" />
</envs>
<method v="2">
Expand Down
6 changes: 5 additions & 1 deletion .run/spicetest.run.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spicetest" type="CMakeGoogleTestRunConfigurationType" factoryName="Google Test" PROGRAM_PARAMS="--update-refs=false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spicetest" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spicetest" TEST_MODE="SUITE_TEST">
<configuration default="false" name="spicetest" type="CMakeGoogleTestRunConfigurationType" factoryName="Google Test" PROGRAM_PARAMS="--update-refs=false" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="spicetest" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="spicetest" TEST_CLASS="BootstrapCompilerTests" TEST_MODE="SUITE_TEST">
<envs>
<env name="LLVM_BUILD_INCLUDE_DIR" value="D:/LLVM/build-release/include" />
<env name="LLVM_INCLUDE_DIR" value="D:/LLVM/llvm/include" />
<env name="LLVM_LIB_DIR" value="D:/LLVM/build-release/lib" />
<env name="RUN_TESTS" value="ON" />
<env name="LLVM_ADDITIONAL_FLAGS" value="-lole32 -lws2_32" />
<env name="SPICE_STD_DIR" value="$PROJECT_DIR$/std" />
</envs>
<method v="2">
Expand Down
2 changes: 2 additions & 0 deletions docs/docs/language/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
66 changes: 49 additions & 17 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -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<int> 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<llvm::Type> 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<llvm::Type> 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<llvm::Value> 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";
Expand Down
22 changes: 15 additions & 7 deletions src-bootstrap/bindings/llvm/linker-flags.spice
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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
Expand Down
16 changes: 16 additions & 0 deletions src/ast/Attributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -42,6 +44,20 @@ static const std::unordered_map<std::string, AttrConfigValue> 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,
{
Expand Down
18 changes: 15 additions & 3 deletions src/symboltablebuilder/SymbolTableBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -624,11 +624,23 @@ std::any SymbolTableBuilder::visitModAttr(ModAttrNode *node) {
// Retrieve attributes
const AttrLstNode *attrs = node->attrLst();

// Collect linker flags
std::vector<const CompileTimeValue *> 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<const CompileTimeValue *> 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)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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, ...)
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import "bootstrap/bindings/llvm/llvm" as llvm;
import "std/data/vector";

f<int> 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<llvm::Type> 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<llvm::Type> 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<llvm::Value> 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());
}

0 comments on commit edcca00

Please sign in to comment.