Skip to content

Commit

Permalink
Improve debug info generator (#404)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer authored Dec 31, 2023
1 parent 74b4b0a commit aae057e
Show file tree
Hide file tree
Showing 17 changed files with 124 additions and 62 deletions.
2 changes: 1 addition & 1 deletion .run/spice.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="spice" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="run -O0 -d ../../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 -O0 -d -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" />
Expand Down
15 changes: 11 additions & 4 deletions build.bat
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
@echo off

REM - Check for LLVM_DIR env var
:: Check for LLVM_DIR env var
set LLVM_DIR=".\llvm\build-release\lib\cmake\llvm"

REM - Build
mkdir bin 2> NUL
:: Prepare
if not exist bin (
mkdir bin
)
pushd bin

:: Build
cmake -DCMAKE_BUILD_TYPE=Release -GNinja -DCMAKE_CXX_FLAGS_RELEASE="-O2" ..
cmake --build . --target spice
cmake --build . --target spice spicetest

:: Cleanup
move src\spice.exe spice.exe
move test\spicetest.exe spicetest.exe
popd
11 changes: 6 additions & 5 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
#!/bin/sh
set -eu

# Create bin dir
mkdir bin

# Check for LLVM_DIR env var
# Prepare
if [ ! -d bin ]; then
mkdir -p bin
fi
export LLVM_DIR=./llvm/build-release/lib/cmake/llvm

# Build
(
cd ./bin || exit
cmake -DCMAKE_BUILD_TYPE=Release -GNinja -DCMAKE_CXX_FLAGS_RELEASE="-O2" ..
cmake --build . --target spice
cmake --build . --target spice spicetest
mv ./src/spice spice
mv ./test/spicetest spicetest
)
18 changes: 9 additions & 9 deletions dev-setup.bat
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@

echo [Step 1] Checking installations ...

REM - Check if MinGW is installed
:: Check if MinGW is installed
where g++ > nul 2>&1
if errorlevel 1 (
echo MinGW-w64 was not found. Please install the latest version from https://winlibs.com
goto end
)

REM - Check if lld is installed
:: Check if lld is installed
where lld > nul 2>&1
if errorlevel 1 (
echo LLD linker was not found. Please install the latest version from https://winlibs.com
goto end
)

REM - Check if Ninja is installed
:: Check if Ninja is installed
where ninja > nul 2>&1
if errorlevel 1 (
echo Ninja was not found. Please install the latest version from https://github.com/ninja-build/ninja/releases
goto end
)

REM - Check if CMake is installed
:: Check if CMake is installed
where cmake > nul 2>&1
if errorlevel 1 (
echo CMake was not found. Please install the latest version from https://cmake.org/download
Expand All @@ -32,12 +32,12 @@ if errorlevel 1 (

echo done.

REM - Clone LLVM
:: Clone LLVM
echo [Step 2] Cloning LLVM (Could take a while) ...
git clone --depth 1 --branch llvmorg-17.0.6 https://github.com/llvm/llvm-project llvm
echo done.

REM - Build LLVM
:: Build LLVM
echo [Step 3] Building LLVM (Could take a whole while, please be patient) ...
mkdir .\llvm\build-release
pushd .\llvm\build-release
Expand All @@ -46,17 +46,17 @@ cmake --build .
popd
echo done.

REM - Download third-party libs
:: Download third-party libs
echo [Step 4] Downloading third-party libraries ...
cmd /c .\setup-libs.bat > nul 2>&1
echo done.

REM - Build in dev context
:: Build in dev context
echo [Step 5] Building Spice ...
cmd /c .\build.bat
echo done.

REM - End message
:: End message
echo The setup is done. Have fun coding!
echo Whenever you need to build Spice again, use the ./build.sh script.

Expand Down
22 changes: 20 additions & 2 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,11 +1,29 @@
import "../../src-bootstrap/lexer/lexer";
type Visitable interface {
p print();
}

type Test1 struct : Visitable {
int f1
}

p Test1.print() {
printf("Foo: %d", this.f1);
}

f<int> main() {
Test1 t1 = Test1{123};
Visitable* v = &t1;
v.print();
}

/*import "../../src-bootstrap/lexer/lexer";
import "../../src-bootstrap/parser/parser";

f<int> main() {
Lexer lexer = Lexer("./file.spice");
Parser parser = Parser(lexer);
parser.parse();
}
}*/

/*import "../../src-bootstrap/lexer/lexer";
import "std/time/timer";
Expand Down
12 changes: 10 additions & 2 deletions setup-libs.bat
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
@echo off

mkdir lib
:: Check if the backup directory exists, if not create it
if not exist lib (
mkdir lib
)
pushd lib

:: Download ANTLR4
git clone --quiet --depth 1 --branch 4.13.1 https://github.com/antlr/antlr4.git

:: Download Google Test
git clone --quiet --depth 1 --branch v1.14.0 https://github.com/google/googletest.git

:: Download JSON for Modern C++
mkdir json
curl -SsL "https://github.com/nlohmann/json/releases/download/v3.11.2/json.hpp" --output json/json.hpp

:: Download Thread Pool
mkdir thread-pool
curl -SsL "https://raw.githubusercontent.com/bshoshany/thread-pool/master/include/BS_thread_pool.hpp" --output thread-pool/thread-pool.hpp
curl -SsL "https://raw.githubusercontent.com/bshoshany/thread-pool/v3.5.0/include/BS_thread_pool.hpp" --output thread-pool/thread-pool.hpp

:: Download CLI11
mkdir cli11
curl -SsL "https://github.com/spicelang/CLI11/releases/download/v2.3.2-spice/CLI11.hpp" --output cli11/CLI11.hpp

Expand Down
11 changes: 9 additions & 2 deletions setup-libs.sh
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
#!/bin/sh

mkdir lib
if [ ! -d lib ]; then
mkdir -p lib
fi
cd lib || exit

# Download ANTLR4
git clone --quiet --depth 1 --branch 4.13.1 https://github.com/antlr/antlr4.git

# Download Google Test
git clone --quiet --depth 1 --branch v1.14.0 https://github.com/google/googletest.git

# Download JSON for Modern C++
mkdir json
curl -SsL "https://github.com/nlohmann/json/releases/download/v3.11.2/json.hpp" --output json/json.hpp

# Download Thread Pool
mkdir thread-pool
curl -SsL "https://raw.githubusercontent.com/bshoshany/thread-pool/master/include/BS_thread_pool.hpp" --output thread-pool/thread-pool.hpp
curl -SsL "https://raw.githubusercontent.com/bshoshany/thread-pool/v3.5.0/include/BS_thread_pool.hpp" --output thread-pool/thread-pool.hpp

# Download CLI11
mkdir cli11
curl -SsL "https://github.com/spicelang/CLI11/releases/download/v2.3.2-spice/CLI11.hpp" --output cli11/CLI11.hpp

Expand Down
6 changes: 3 additions & 3 deletions src-bootstrap/parser/parser.spice
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ public f<ASTFctDefNode*> Parser.parseFctDef() {
return this.concludeNode(fctDefNode);
}

public f<ASTFctDefNode*> Parser.parseProcDef() {
public f<ASTProcDefNode*> Parser.parseProcDef() {
dyn procDefNode = this.createNode<ASTProcDefNode>();

// Parse topLevelDefAttr
Expand Down Expand Up @@ -484,7 +484,7 @@ f<ASTDoWhileLoopNode*> Parser.parseDoWhileLoop() {
return this.concludeNode(doWhileLoopNode);
}

f<ASTIfStmtNode> Parser.parseIfStmt() {
f<ASTIfStmtNode*> Parser.parseIfStmt() {
dyn ifStmtNode = this.createNode<ASTIfStmtNode>();

this.lexer.expect(TokenType::IF);
Expand All @@ -503,7 +503,7 @@ f<ASTIfStmtNode> Parser.parseIfStmt() {
return this.concludeNode(ifStmtNode);
}

f<ASTElseStmtNode> Parser.parseElseStmt() {
f<ASTElseStmtNode*> Parser.parseElseStmt() {
dyn elseStmtNode = this.createNode<ASTElseStmtNode>();

this.lexer.expect(TokenType::ELSE);
Expand Down
32 changes: 23 additions & 9 deletions src/irgenerator/DebugInfoGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,22 @@ void DebugInfoGenerator::generateFunctionDebugInfo(llvm::Function *llvmFunction,
const ASTNode *node = spiceFunc->declNode;
const size_t lineNo = spiceFunc->getDeclCodeLoc().line;

// Prepare information
// Prepare flags
llvm::DIScope *scope = diFile;
llvm::DINode::DIFlags flags = llvm::DINode::FlagPrototyped;
if (spiceFunc->entry && spiceFunc->entry->getType().specifiers.isPublic)
flags |= llvm::DINode::FlagPublic;

// Prepare spFlags
llvm::DISubprogram::DISPFlags spFlags = llvm::DISubprogram::SPFlagDefinition;
if (isLambda)
spFlags |= llvm::DISubprogram::SPFlagLocalToUnit;
if (spiceFunc->isVirtual) {
if (spiceFunc->thisType.is(TY_INTERFACE))
spFlags |= llvm::DISubprogram::SPFlagPureVirtual;
else
spFlags |= llvm::DISubprogram::SPFlagVirtual;
}

// Collect arguments
std::vector<llvm::Metadata *> argTypes;
Expand Down Expand Up @@ -324,15 +334,15 @@ llvm::DIType *DebugInfoGenerator::getDITypeForSymbolType(const ASTNode *node, co
const size_t lineNo = spiceStruct->getDeclCodeLoc().line;
llvm::Type *structType = spiceStruct->entry->getType().toLLVMType(irGenerator->context, irGenerator->currentScope);
assert(structType != nullptr);
const llvm::StructLayout *structLayout =
irGenerator->module->getDataLayout().getStructLayout(reinterpret_cast<llvm::StructType *>(structType));
const uint32_t alignInBits = irGenerator->module->getDataLayout().getABITypeAlign(structType).value();
llvm::DataLayout dataLayout = irGenerator->module->getDataLayout();
const llvm::StructLayout *structLayout = dataLayout.getStructLayout(reinterpret_cast<llvm::StructType *>(structType));
const uint32_t alignInBits = dataLayout.getABITypeAlign(structType).value();

// Create struct type
const std::string mangledName = NameMangling::mangleStruct(*spiceStruct);
llvm::DICompositeType *structDiType = diBuilder->createStructType(
diFile, spiceStruct->name, diFile, lineNo, structLayout->getSizeInBits(), alignInBits,
llvm::DINode::FlagTypePassByValue | llvm::DINode::FlagNonTrivial, nullptr, {}, 0, nullptr, mangledName);
llvm::DINode::FlagTypePassByReference | llvm::DINode::FlagNonTrivial, nullptr, {}, 0, nullptr, mangledName);
baseDiType = spiceStruct->diType = structDiType;

// Collect DI types for fields
Expand Down Expand Up @@ -373,15 +383,19 @@ llvm::DIType *DebugInfoGenerator::getDITypeForSymbolType(const ASTNode *node, co
const size_t lineNo = spiceInterface->getDeclCodeLoc().line;
llvm::Type *interfaceType = spiceInterface->entry->getType().toLLVMType(irGenerator->context, irGenerator->currentScope);
assert(interfaceType != nullptr);
const llvm::StructLayout *structLayout =
irGenerator->module->getDataLayout().getStructLayout(static_cast<llvm::StructType *>(interfaceType));
const uint32_t alignInBits = irGenerator->module->getDataLayout().getABITypeAlign(interfaceType).value();
llvm::DataLayout dataLayout = irGenerator->module->getDataLayout();
const llvm::StructLayout *structLayout = dataLayout.getStructLayout(reinterpret_cast<llvm::StructType *>(interfaceType));
const uint32_t alignInBits = dataLayout.getABITypeAlign(interfaceType).value();

// Create interface type
const std::string mangledName = NameMangling::mangleInterface(*spiceInterface);
llvm::DICompositeType *interfaceDiType = diBuilder->createStructType(
diFile, spiceInterface->name, diFile, lineNo, structLayout->getSizeInBits(), alignInBits,
llvm::DINode::FlagTypePassByValue | llvm::DINode::FlagNonTrivial, nullptr, {}, 0, nullptr, mangledName);
llvm::DINode::FlagTypePassByReference | llvm::DINode::FlagNonTrivial, nullptr, {}, 0, nullptr, mangledName);

// Set vtable holder to itself for interfaces
interfaceDiType->replaceVTableHolder(interfaceDiType);

baseDiType = spiceInterface->diType = interfaceDiType;
break;
}
Expand Down
8 changes: 4 additions & 4 deletions src/irgenerator/GenVTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ llvm::Constant *IRGenerator::generateTypeInfo(StructBase *spiceStruct) {
if (!sourceFile->isRttiRT()) {
// Add external global pointer for TypeInfo vtable
assert(sourceFile->isRuntimeModuleAvailable(RuntimeModule::RTTI_RT));
const std::string mangledName = NameMangling::mangleVTable("TypeInfo");
llvm::Constant *typeInfoExtPtr = module->getOrInsertGlobal(mangledName, builder.getPtrTy());
const std::string typeInfoMangledName = NameMangling::mangleVTable("TypeInfo");
llvm::Constant *typeInfoExtPtr = module->getOrInsertGlobal(typeInfoMangledName, builder.getPtrTy());
typeInfoVTable = llvm::ConstantExpr::getInBoundsGetElementPtr(ptrTy, typeInfoExtPtr, builder.getInt64(2));
}
std::vector<llvm::Constant *> fieldValues;
Expand All @@ -60,8 +60,8 @@ llvm::Constant *IRGenerator::generateTypeInfo(StructBase *spiceStruct) {
for (const SymbolType &interfaceType : interfaceTypes) {
Interface *interface = interfaceType.getInterface(nullptr);
assert(interface != nullptr && interface->typeInfo != nullptr);
const std::string mangledName = NameMangling::mangleTypeInfo(interface);
llvm::Constant *global = module->getOrInsertGlobal(mangledName, builder.getPtrTy());
const std::string interfaceMangledName = NameMangling::mangleTypeInfo(interface);
llvm::Constant *global = module->getOrInsertGlobal(interfaceMangledName, builder.getPtrTy());
fieldValues.push_back(global);
}
llvm::Constant *typeInfo = llvm::ConstantStruct::get(spiceStruct->typeInfoType, fieldValues);
Expand Down
13 changes: 11 additions & 2 deletions src/symboltablebuilder/Scope.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,17 @@ void Scope::collectWarnings(std::vector<CompilerWarning> &warnings) const { // N
break;
}
case TY_INTERFACE: {
warningType = UNUSED_INTERFACE;
warningMessage = "The interface '" + entry.name + "' is unused";
if (entry.scope->type == ScopeType::GLOBAL) {
// Skip generic struct entries
if (!entry.getType().getTemplateTypes().empty())
continue;

warningType = UNUSED_INTERFACE;
warningMessage = "The interface '" + entry.name + "' is unused";
} else {
warningType = UNUSED_VARIABLE;
warningMessage = "The variable '" + entry.name + "' is unused";
}
break;
}
case TY_IMPORT: {
Expand Down
5 changes: 3 additions & 2 deletions src/typechecker/OpRuleManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ SymbolType OpRuleManager::getAssignResultType(const ASTNode *node, SymbolType lh
// Allow char* = string
if (lhs.isPtrOf(TY_CHAR) && rhs.is(TY_STRING) && lhs.specifiers == rhs.specifiers)
return lhs;
// Allow interface = struct that implements this interface
if (lhs.isBaseType(TY_INTERFACE) && rhs.isBaseType(TY_STRUCT) && lhs.typeChain.size() == rhs.typeChain.size()) {
// Allow interface* = struct* that implements this interface
const bool sameChainDepth = lhs.typeChain.size() == rhs.typeChain.size();
if (lhs.isPtr() && rhs.isPtr() && sameChainDepth && lhs.isBaseType(TY_INTERFACE) && rhs.isBaseType(TY_STRUCT)) {
SymbolType lhsCopy = lhs;
SymbolType rhsCopy = rhs;
SymbolType::unwrapBoth(lhsCopy, rhsCopy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -523,8 +523,8 @@ attributes #3 = { cold noreturn nounwind }
!25 = !DILocalVariable(name: "_argc", arg: 1, scope: !15, file: !5, line: 6, type: !18)
!26 = !DILocalVariable(name: "_argv", arg: 2, scope: !15, file: !5, line: 6, type: !19)
!27 = !DILocalVariable(name: "vi", scope: !15, file: !5, line: 8, type: !28)
!28 = !DICompositeType(tag: DW_TAG_structure_type, name: "Vector", scope: !29, file: !29, line: 22, size: 192, align: 8, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !30, identifier: "struct.Vector")
!29 = !DIFile(filename: "vector.spice", directory: "C:\\Users\\Marc\\Documents\\JustForFunGitHubClonesFast\\spice\\std\\data")
!28 = !DICompositeType(tag: DW_TAG_structure_type, name: "Vector", scope: !29, file: !29, line: 22, size: 192, align: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !30, identifier: "struct.Vector")
!29 = !DIFile(filename: "vector.spice", directory: "C:\\Users\\I516467\\Documents\\JustForFunGitHubClones\\spice\\std\\data")
!30 = !{!31, !33, !35}
!31 = !DIDerivedType(tag: DW_TAG_member, name: "contents", scope: !28, file: !29, line: 23, baseType: !32, size: 64)
!32 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !18, size: 64)
Expand All @@ -541,8 +541,8 @@ attributes #3 = { cold noreturn nounwind }
!43 = !{!"branch_weights", i32 2000, i32 1}
!44 = !DILocation(line: 15, column: 22, scope: !15)
!45 = !DILocalVariable(name: "it", scope: !15, file: !5, line: 15, type: !46)
!46 = !DICompositeType(tag: DW_TAG_structure_type, name: "VectorIterator", scope: !47, file: !47, line: 13, size: 192, align: 8, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !48, identifier: "struct.VectorIterator")
!47 = !DIFile(filename: "vector-iterator.spice", directory: "C:\\Users\\Marc\\Documents\\JustForFunGitHubClonesFast\\spice\\std\\iterator")
!46 = !DICompositeType(tag: DW_TAG_structure_type, name: "VectorIterator", scope: !47, file: !47, line: 13, size: 192, align: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !48, identifier: "struct.VectorIterator")
!47 = !DIFile(filename: "vector-iterator.spice", directory: "C:\\Users\\I516467\\Documents\\JustForFunGitHubClones\\spice\\std\\iterator")
!48 = !{!49, !51}
!49 = !DIDerivedType(tag: DW_TAG_member, name: "vector", scope: !46, file: !47, line: 14, baseType: !50, size: 64, offset: 64)
!50 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !28, size: 64)
Expand All @@ -560,8 +560,8 @@ attributes #3 = { cold noreturn nounwind }
!62 = !DILocation(line: 22, column: 5, scope: !15)
!63 = !DILocation(line: 23, column: 16, scope: !15)
!64 = !DILocalVariable(name: "pair", scope: !15, file: !5, line: 23, type: !65)
!65 = !DICompositeType(tag: DW_TAG_structure_type, name: "Pair", scope: !66, file: !66, line: 8, size: 128, align: 8, flags: DIFlagTypePassByValue | DIFlagNonTrivial, elements: !67, identifier: "struct.Pair")
!66 = !DIFile(filename: "pair.spice", directory: "C:\\Users\\Marc\\Documents\\JustForFunGitHubClonesFast\\spice\\std\\data")
!65 = !DICompositeType(tag: DW_TAG_structure_type, name: "Pair", scope: !66, file: !66, line: 8, size: 128, align: 8, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !67, identifier: "struct.Pair")
!66 = !DIFile(filename: "pair.spice", directory: "C:\\Users\\I516467\\Documents\\JustForFunGitHubClones\\spice\\std\\data")
!67 = !{!68, !69}
!68 = !DIDerivedType(tag: DW_TAG_member, name: "first", scope: !65, file: !66, line: 9, baseType: !34, size: 64)
!69 = !DIDerivedType(tag: DW_TAG_member, name: "second", scope: !65, file: !66, line: 10, baseType: !32, size: 64, offset: 64)
Expand Down
Loading

0 comments on commit aae057e

Please sign in to comment.