Skip to content

Commit

Permalink
Cache LLVM types (#558)
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer authored May 22, 2024
1 parent e51f8e2 commit 797d153
Show file tree
Hide file tree
Showing 50 changed files with 854 additions and 817 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_ADDITIONAL_FLAGS" value="-lole32 -lws2_32" />
<env name="LLVM_BUILD_INCLUDE_DIR" value="$PROJECT_DIR$/../llvm-project-latest/build/include" />
Expand Down
21 changes: 11 additions & 10 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import "std/os/env";
import "bootstrap/ast/ast-nodes";
import "bootstrap/lexer/lexer";
import "bootstrap/parser/parser";
import "std/io/file";

f<int> main() {
String filePath = getEnv("SPICE_STD_DIR") + "/../test/test-files/bootstrap-compiler/standalone-parser-test/test-file.spice";
Lexer lexer = Lexer(filePath.getRaw());
Parser parser = Parser(lexer);
ASTEntryNode* ast = parser.parse();
assert ast != nil<ASTEntryNode*>;
printf("All assertions passed!\n");
string filename = "./test-file.txt";
deleteFile(filename); // Ensure that the file is not present in the beginning

assert !fileExists(filename);
assert createFile(filename);
assert fileExists(filename);
assert deleteFile(filename);
assert !fileExists(filename);

printf("All assertions passed!");
}
11 changes: 2 additions & 9 deletions media/test-project/test2.spice
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
type A dyn;

public p printFormat<A>(A element) {
printf("Sizeof output: %d\n", sizeof(element));
}

public f<A*> getAInc<A>(A* number) {
(*number)++;
return number;
public f<int> functionInModuleB(int x, int y) {
return x + y;
}
2 changes: 1 addition & 1 deletion src-bootstrap/global/runtime-module-manager.spice
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public f<SourceFile *> RuntimeModuleManager.loadModule(SourceFile* parentSourceF

// Instruct the global resource manager to create a new source file
SourceFile* moduleSourceFile = resourceManager.createSourceFile(parentSourceFile, importName, filrPath, true);
moduleSourceFile.mainFile = false;
moduleSourceFile.isMainFile = false;

// Run frontend and first type checker run for the loaded source file
moduleSourceFile.runFrontEnd();
Expand Down
2 changes: 1 addition & 1 deletion src-bootstrap/main.spice
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ f<bool> compileProject(const CliOptions& cliOptions) {
dyn resourceManager = GlobalResourceManager(options);

// Create source file instance for main source file
SourceFile* mainSourceFile = resourceManager.createSourceFile(nullptr, MAIN_FILE_NAME, cliOptions.mainFile, false);
SourceFile* mainSourceFile = resourceManager.createSourceFile(nullptr, MAIN_FILE_NAME, cliOptions.mainSourceFile, false);

// Run compile pipeline for main source file. All dependent source files are triggered by their parents
mainSourceFile.runFrontEnd();
Expand Down
8 changes: 4 additions & 4 deletions src-bootstrap/source-file.spice
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ public type SourceFile struct {
public String fileName
public FilePath filePath
public String fileDir
public bool stdFile = false
public bool mainFile = true
public bool isStdFile = false
public bool isMainFile = true
public bool alwaysKeepSymbolsOnNameCollision = false
public bool ignoreWarnings = false
public CompileStageType previousStage = CompileStageType::NONE
Expand All @@ -100,13 +100,13 @@ public type SourceFile struct {
unsigned short totalTypeCheckerRuns = 0s
}

public p SourceFile.ctor(GlobalResourceManager &resourceManager, SourceFile* parent, const String& name, const String& filePath, bool stdFile) {
public p SourceFile.ctor(GlobalResourceManager &resourceManager, SourceFile* parent, const String& name, const String& filePath, bool isStdFile) {
// Copy data
this.resourceManager = resourceManager;
this.parent = parent;
this.name = name;
this.filePath = filePath;
this.stdFile = stdFile;
this.isStdFile = isStdFile;

// Deduce fileName and fileDir
/*this.fileName = ;
Expand Down
54 changes: 43 additions & 11 deletions src/SourceFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,38 @@
#include <visualizer/ASTVisualizer.h>
#include <visualizer/CSTVisualizer.h>

#include <llvm/MC/TargetRegistry.h>

namespace spice::compiler {

SourceFile::SourceFile(GlobalResourceManager &resourceManager, SourceFile *parent, std::string name,
const std::filesystem::path &filePath, bool stdFile)
: name(std::move(name)), filePath(filePath), stdFile(stdFile), parent(parent), resourceManager(resourceManager),
: name(std::move(name)), filePath(filePath), isStdFile(stdFile), parent(parent),
builder(resourceManager.cliOptions.useLTO ? resourceManager.ltoContext : context), resourceManager(resourceManager),
cliOptions(resourceManager.cliOptions), tout(resourceManager.tout) {
// Deduce fileName and fileDir
fileName = std::filesystem::path(filePath).filename().string();
fileDir = std::filesystem::path(filePath).parent_path().string();

// Search after selected target
std::string error;
const llvm::Target *target = llvm::TargetRegistry::lookupTarget(cliOptions.targetTriple, error);
if (!target)
throw CompilerError(TARGET_NOT_AVAILABLE, "Selected target was not found: " + error); // GCOV_EXCL_LINE

// Create target machine
llvm::TargetOptions opt;
opt.MCOptions.AsmVerbose = true;
opt.MCOptions.PreserveAsmComments = true;
const std::string &cpuName = resourceManager.cpuName;
const std::string &features = resourceManager.cpuFeatures;
const std::string &targetTriple = cliOptions.targetTriple;
llvm::TargetMachine *targetMachineRaw = target->createTargetMachine(targetTriple, cpuName, features, opt, llvm::Reloc::PIC_);
targetMachine = std::unique_ptr<llvm::TargetMachine>(targetMachineRaw);
}

void SourceFile::runLexer() {
if (mainFile)
if (isMainFile)
resourceManager.totalTimer.start();

// Check if this stage has already been done
Expand Down Expand Up @@ -297,7 +316,8 @@ void SourceFile::runIRGenerator() {
timer.start();

// Create LLVM module for this source file
llvmModule = std::make_unique<llvm::Module>(filePath.filename().string(), resourceManager.context);
llvm::LLVMContext &llvmContext = cliOptions.useLTO ? resourceManager.ltoContext : context;
llvmModule = std::make_unique<llvm::Module>(filePath.filename().string(), llvmContext);

// Generate this source file
IRGenerator irGenerator(resourceManager, this);
Expand Down Expand Up @@ -383,7 +403,7 @@ void SourceFile::runBitcodeLinker() {
assert(cliOptions.useLTO);

// Skip if this is not the main source file
if (!mainFile)
if (!isMainFile)
return;

// Skip if restored from cache or this stage has already been done
Expand All @@ -404,7 +424,7 @@ void SourceFile::runPostLinkIROptimizer() {
assert(cliOptions.useLTO);

// Skip if this is not the main source file
if (!mainFile)
if (!isMainFile)
return;

// Skip if restored from cache or this stage has already been done
Expand Down Expand Up @@ -444,7 +464,7 @@ void SourceFile::runObjectEmitter() {
return;

// Skip if LTO is enabled and this is not the main source file
if (cliOptions.useLTO && !mainFile)
if (cliOptions.useLTO && !isMainFile)
return;

Timer timer(&compilerOutput.times.objectEmitter);
Expand Down Expand Up @@ -484,11 +504,11 @@ void SourceFile::concludeCompilation() {
resourceManager.cacheManager.cacheSourceFile(this);

// Save type registry as string in the compiler output
if (mainFile && (cliOptions.dumpSettings.dumpTypes || cliOptions.testMode))
if (isMainFile && (cliOptions.dumpSettings.dumpTypes || cliOptions.testMode))
compilerOutput.typesString = TypeRegistry::dump();

// Dump type registry
if (mainFile && cliOptions.dumpSettings.dumpTypes)
if (isMainFile && cliOptions.dumpSettings.dumpTypes)
dumpOutput(compilerOutput.typesString, "Type Registry", "type-registry.out");

// Print warning if verifier is disabled
Expand Down Expand Up @@ -557,7 +577,7 @@ void SourceFile::runBackEnd() { // NOLINT(misc-no-recursion)
// Wait until all compile tasks for all depending source files are done
resourceManager.threadPool.wait();

if (mainFile) {
if (isMainFile) {
resourceManager.totalTimer.stop();
if (cliOptions.printDebugOutput) {
CHECK_ABORT_FLAG_V()
Expand All @@ -581,7 +601,7 @@ void SourceFile::addDependency(SourceFile *sourceFile, const ASTNode *declNode,
}

// Add the dependency
sourceFile->mainFile = false;
sourceFile->isMainFile = false;
dependencies.insert({dependencyName, sourceFile});

// Add the dependant
Expand Down Expand Up @@ -634,6 +654,18 @@ const NameRegistryEntry *SourceFile::getNameRegistryEntry(const std::string &sym
return entry;
}

llvm::Type *SourceFile::getLLVMType(const Type *type) {
// Check if the type is already in the mapping
const auto it = typeToLLVMTypeMapping.find(type);
if (it != typeToLLVMTypeMapping.end())
return it->second;

// If not, generate the LLVM type
llvm::Type *llvmType = type->toLLVMType(this);
typeToLLVMTypeMapping[type] = llvmType;
return llvmType;
}

void SourceFile::checkForSoftErrors() {
// Check if there are any soft errors and if so, print them
if (!resourceManager.errorManager.softErrors.empty()) {
Expand All @@ -648,7 +680,7 @@ void SourceFile::checkForSoftErrors() {
void SourceFile::collectAndPrintWarnings() { // NOLINT(misc-no-recursion)
// Print warnings for all dependencies
for (const auto &dependency : dependencies) {
if (!dependency.second->stdFile)
if (!dependency.second->isStdFile)
dependency.second->collectAndPrintWarnings();
}
// Collect warnings for this file
Expand Down
10 changes: 8 additions & 2 deletions src/SourceFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <util/CompilerWarning.h>

#include <llvm/IR/IRBuilder.h>
#include <llvm/Target/TargetMachine.h>

#include "../lib/thread-pool/thread-pool-utils.hpp"
#include "../lib/thread-pool/thread-pool.hpp"
Expand Down Expand Up @@ -152,6 +153,7 @@ class SourceFile {
void addNameRegistryEntry(const std::string &symbolName, uint64_t typeId, SymbolTableEntry *entry, Scope *scope,
bool keepNewOnCollision = true, SymbolTableEntry *importEntry = nullptr);
[[nodiscard]] const NameRegistryEntry *getNameRegistryEntry(const std::string &symbolName) const;
[[nodiscard]] llvm::Type *getLLVMType(const Type *type);
void checkForSoftErrors();
void collectAndPrintWarnings();
const SourceFile *getRootSourceFile() const;
Expand All @@ -164,8 +166,8 @@ class SourceFile {
std::string fileName;
std::filesystem::path filePath;
std::string fileDir;
bool stdFile = false;
bool mainFile = true;
bool isStdFile = false;
bool isMainFile = true;
bool alwaysKeepSymbolsOnNameCollision = false;
bool ignoreWarnings = false;
CompileStageType previousStage = NONE;
Expand All @@ -176,6 +178,9 @@ class SourceFile {
bool restoredFromCache = false;
EntryNode *ast = nullptr;
std::unique_ptr<Scope> globalScope;
llvm::LLVMContext context;
llvm::IRBuilder<> builder;
std::unique_ptr<llvm::TargetMachine> targetMachine;
std::unique_ptr<llvm::Module> llvmModule;
std::unordered_map<std::string, SourceFile *> dependencies;
std::vector<const SourceFile *> dependants;
Expand All @@ -187,6 +192,7 @@ class SourceFile {
GlobalResourceManager &resourceManager;
const CliOptions &cliOptions;
BS::synced_stream &tout;
std::unordered_map<const Type *, llvm::Type *> typeToLLVMTypeMapping;
uint8_t importedRuntimeModules = 0;
uint8_t totalTypeCheckerRuns = 0;

Expand Down
3 changes: 2 additions & 1 deletion src/ast/ASTBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <ast/ASTNodes.h>
#include <ast/Attributes.h>
#include <exception/ParserError.h>
#include <global/GlobalResourceManager.h>
#include <typechecker/OpRuleManager.h>
#include <util/CommonUtil.h>
#include <util/GlobalDefinitions.h>
Expand Down Expand Up @@ -1502,7 +1503,7 @@ std::string ASTBuilder::getIdentifier(TerminalNode *terminal) {
std::string identifier = terminal->getText();

// Check if the identifier is 'String' and this is no std source file
bool isReserved = !sourceFile->stdFile && (identifier == STROBJ_NAME || identifier == RESULTOBJ_NAME);
bool isReserved = !sourceFile->isStdFile && (identifier == STROBJ_NAME || identifier == RESULTOBJ_NAME);
// Check if the list of reserved keywords contains the given identifier
isReserved |= std::find(std::begin(RESERVED_KEYWORDS), std::end(RESERVED_KEYWORDS), identifier) != std::end(RESERVED_KEYWORDS);
// Print error message
Expand Down
28 changes: 6 additions & 22 deletions src/global/GlobalResourceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
#include <typechecker/StructManager.h>
#include <util/FileUtil.h>

#include <llvm/MC/TargetRegistry.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/TargetParser/Host.h>

namespace spice::compiler {
Expand All @@ -28,17 +26,8 @@ GlobalResourceManager::GlobalResourceManager(const CliOptions &cliOptions)
llvm::InitializeAllAsmPrinters();
} // GCOV_EXCL_STOP

// Search after selected target
std::string error;
const llvm::Target *target = llvm::TargetRegistry::lookupTarget(cliOptions.targetTriple, error);
if (!target)
throw CompilerError(TARGET_NOT_AVAILABLE, "Selected target was not found: " + error); // GCOV_EXCL_LINE

// Create target machine for LLVM
llvm::TargetOptions opt;
opt.MCOptions.AsmVerbose = true;
opt.MCOptions.PreserveAsmComments = true;
std::string cpuName = "generic";
// Create cpu name and features strings
cpuName = "generic";
std::stringstream featureString;
if (cliOptions.isNativeTarget && cliOptions.useCPUFeatures) {
// Retrieve native CPU name and the supported CPU features
Expand All @@ -47,20 +36,15 @@ GlobalResourceManager::GlobalResourceManager(const CliOptions &cliOptions)
llvm::sys::getHostCPUFeatures(hostFeatures);
for (const llvm::StringMapEntry<bool> &feature : hostFeatures) {
if (featureString.rdbuf()->in_avail() > 0)
featureString << ",";
featureString << (feature.second ? "+" : "-") << feature.first().str();
featureString << ',';
featureString << (feature.second ? '+' : '-') << feature.first().str();
}
}

// Create target machine
const std::string features = featureString.str();
const std::string &targetTriple = cliOptions.targetTriple;
llvm::TargetMachine *targetMachineRaw = target->createTargetMachine(targetTriple, cpuName, features, opt, llvm::Reloc::PIC_);
targetMachine = std::unique_ptr<llvm::TargetMachine>(targetMachineRaw);
cpuFeatures = featureString.str();

// Create lto module
if (cliOptions.useLTO)
ltoModule = std::make_unique<llvm::Module>(LTO_FILE_NAME, context);
ltoModule = std::make_unique<llvm::Module>(LTO_FILE_NAME, ltoContext);
}

GlobalResourceManager::~GlobalResourceManager() {
Expand Down
9 changes: 3 additions & 6 deletions src/global/GlobalResourceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
#include <util/CodeLoc.h>
#include <util/Timer.h>

#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Target/TargetMachine.h>

#include "../../lib/thread-pool/thread-pool-utils.hpp"
#include "../../lib/thread-pool/thread-pool.hpp"
Expand Down Expand Up @@ -46,10 +43,10 @@ class GlobalResourceManager {
size_t getTotalLineCount() const;

// Public members
llvm::LLVMContext context;
llvm::IRBuilder<> builder = llvm::IRBuilder<>(context);
std::string cpuName;
std::string cpuFeatures;
llvm::LLVMContext ltoContext;
std::unique_ptr<llvm::Module> ltoModule;
std::unique_ptr<llvm::TargetMachine> targetMachine;
DefaultMemoryManager memoryManager;
std::vector<std::string> compileTimeStringValues;
BlockAllocator<ASTNode> astNodeAlloc = BlockAllocator<ASTNode>(memoryManager); // Used to allocate all AST nodes
Expand Down
2 changes: 1 addition & 1 deletion src/global/RuntimeModuleManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ SourceFile *RuntimeModuleManager::loadModule(SourceFile *parentSourceFile, Runti

// Instruct the global resource manager to create a new source file
SourceFile *moduleSourceFile = resourceManager.createSourceFile(parentSourceFile, importName, filePath, true);
moduleSourceFile->mainFile = false;
moduleSourceFile->isMainFile = false;

// Run frontend and first type checker run for the loaded source file
moduleSourceFile->runFrontEnd();
Expand Down
2 changes: 1 addition & 1 deletion src/global/TypeRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class TypeRegistry {
static const Type *getOrInsert(SuperType superType, const std::string &subType);
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 Type *getOrInsert(const TypeChain &typeChain);
static size_t getTypeCount();
static std::string dump();
static void clear();
Expand Down
Loading

0 comments on commit 797d153

Please sign in to comment.