Skip to content

Commit

Permalink
Introduce lookup caches for struct, function and interface lookups
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed May 11, 2024
1 parent 15c0ecf commit 8dfbf04
Show file tree
Hide file tree
Showing 21 changed files with 256 additions and 199 deletions.
153 changes: 42 additions & 111 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,122 +1,53 @@
import "bootstrap/bindings/llvm/llvm" as llvm;
import "std/data/vector";
import "std/data/doubly-linked-list";

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::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<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("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);
DoublyLinkedList<String> list;
assert list.getSize() == 0;
assert list.isEmpty();
list.pushBack(String("Hello"));
assert list.getSize() == 1;
assert !list.isEmpty();
String var = String("World");
list.pushBack(var);
assert list.getSize() == 2;
list.pushFront(String("Hi"));
assert list.getSize() == 3;
assert list.getFront() == String("Hi");
assert list.getBack() == String("World");
list.removeFront();
assert list.getSize() == 2;
assert list.getFront() == String("Hello");
list.removeBack();
assert list.getSize() == 1;
assert list.getBack() == String("Hello");
list.pushBack(String("World"));
list.pushFront(String("Hi"));
list.pushBack(String("Programmers"));
assert list.getSize() == 4;
list.remove(String("World"));
assert list.getSize() == 3;
assert list.get(0) == String("Hi");
assert list.get(1) == String("Hello");
assert list.get(2) == String("Programmers");
list.removeAt(1);
assert list.getSize() == 2;
assert list.get(0) == String("Hi");
assert list.get(1) == String("Programmers");
printf("All assertions passed!\n");
}

/*import "std/iterator/array-iterator";
import "std/data/pair";
/*import "std/iterator/number-iterator";

f<int> main() {
// 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;
NumberIterator<int> itInt = range(1, 10);
dyn idxAndValueInt = itInt.getIdx();
assert idxAndValueInt.getSecond() == 4;
}*/

foreach long idx, int& item : iterate(a, len(a)) {
item += idx;
}
assert a[0] == 124;
assert a[1] == 4323;
assert a[2] == 9879;
/*import "std/data/hash-table";

printf("All assertions passed!");
f<int> main() {
HashTable<int, string> map = HashTable<int, string>(3l);
}*/

/*import "bootstrap/util/block-allocator";
Expand Down
10 changes: 9 additions & 1 deletion src/global/GlobalResourceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

#include <SourceFile.h>
#include <ast/ASTNodes.h>
#include <global/TypeRegistry.h>
#include <typechecker/FunctionManager.h>
#include <typechecker/StructManager.h>
#include <util/FileUtil.h>

#include <llvm/MC/TargetRegistry.h>
Expand Down Expand Up @@ -61,7 +64,12 @@ GlobalResourceManager::GlobalResourceManager(const CliOptions &cliOptions)
}

GlobalResourceManager::~GlobalResourceManager() {
// Cleanup all global LLVM resources
// Cleanup all statics
TypeRegistry::clear();
FunctionManager::clear();
StructManager::clear();
InterfaceManager::clear();
// Cleanup all LLVM statics
llvm::llvm_shutdown();
}

Expand Down
4 changes: 3 additions & 1 deletion src/global/TypeRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ const Type *TypeRegistry::getOrInsert(const TypeChain &typeChain) { return getOr
*
* @return The number of types in the type registry
*/
const size_t TypeRegistry::getTypeCount() { return types.size(); }
size_t TypeRegistry::getTypeCount() { return types.size(); }

void TypeRegistry::clear() { types.clear();}

} // namespace spice::compiler
3 changes: 2 additions & 1 deletion src/global/TypeRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ 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();
static size_t getTypeCount();
static void clear();

private:
// Private members
Expand Down
4 changes: 2 additions & 2 deletions src/symboltablebuilder/QualType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,7 @@ bool QualType::canBind(const QualType &inputType, bool isTemporary) const {
*/
bool QualType::matches(const QualType &otherType, bool ignoreArraySize, bool ignoreSpecifiers, bool allowConstify) const {
// Compare type
if (!type->matches(*otherType.type, ignoreArraySize))
if (!type->matches(otherType.type, ignoreArraySize))
return false;

// Ignore or compare specifiers
Expand Down Expand Up @@ -734,7 +734,7 @@ void QualType::makeComposition(bool isComposition) { specifiers.isComposition =
* @param rhs Right-hand side type
* @return Equal or not
*/
bool operator==(const QualType &lhs, const QualType &rhs) { return *lhs.type == *rhs.type; }
bool operator==(const QualType &lhs, const QualType &rhs) { return lhs.type == rhs.type; }

/**
* Check if two types are not equal
Expand Down
6 changes: 4 additions & 2 deletions src/symboltablebuilder/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,12 @@ SymbolTableEntry *SymbolTable::insertAnonymous(const QualType &type, ASTNode *de
* @param originalName Original symbol name
* @param newName New symbol name
*/
void SymbolTable::copySymbol(const std::string &originalName, const std::string &newName) {
SymbolTableEntry *SymbolTable::copySymbol(const std::string &originalName, const std::string &newName) {
SymbolTableEntry *entryToCopy = lookupStrict(originalName);
assert(entryToCopy != nullptr);
symbols.insert({newName, *entryToCopy});
auto [it, success] = symbols.insert({newName, *entryToCopy});
assert(success);
return &it->second;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/symboltablebuilder/SymbolTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class SymbolTable {
// Public methods
SymbolTableEntry *insert(const std::string &name, ASTNode *declNode);
SymbolTableEntry *insertAnonymous(const QualType &type, ASTNode *declNode, size_t numericSuffix = 0);
void copySymbol(const std::string &originalName, const std::string &newName);
SymbolTableEntry *copySymbol(const std::string &originalName, const std::string &newName);
SymbolTableEntry *lookup(const std::string &symbolName);
SymbolTableEntry *lookupStrict(const std::string &symbolName);
SymbolTableEntry *lookupInComposedFields(const std::string &name, std::vector<size_t> &indexPath);
Expand Down
10 changes: 3 additions & 7 deletions src/symboltablebuilder/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -628,10 +628,6 @@ const QualTypeList &Type::getFunctionParamAndReturnTypes() const {
return typeChain.front().paramTypes;
}

bool operator==(const Type &lhs, const Type &rhs) { return lhs.typeChain == rhs.typeChain; }

bool operator!=(const Type &lhs, const Type &rhs) { return !(lhs == rhs); }

/**
* Check for the matching compatibility of two types.
* Useful for struct and function matching as well as assignment type validation and function arg matching.
Expand All @@ -640,15 +636,15 @@ bool operator!=(const Type &lhs, const Type &rhs) { return !(lhs == rhs); }
* @param ignoreArraySize Ignore array sizes
* @return Matching or not
*/
bool Type::matches(const Type &otherType, bool ignoreArraySize) const {
bool Type::matches(const Type *otherType, bool ignoreArraySize) const {
// If the size does not match, it is not equal
if (typeChain.size() != otherType.typeChain.size())
if (typeChain.size() != otherType->typeChain.size())
return false;

// Compare the elements
for (size_t i = 0; i < typeChain.size(); i++) {
const TypeChainElement &lhsElement = typeChain.at(i);
const TypeChainElement &rhsElement = otherType.typeChain.at(i);
const TypeChainElement &rhsElement = otherType->typeChain.at(i);

// Ignore differences in array size
if (ignoreArraySize && lhsElement.superType == TY_ARRAY && rhsElement.superType == TY_ARRAY)
Expand Down
6 changes: 1 addition & 5 deletions src/symboltablebuilder/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class Type {

// Complex queries on the type
[[nodiscard]] bool isSameContainerTypeAs(const Type *other) const;
[[nodiscard]] bool matches(const Type &otherType, bool ignoreArraySize) const;
[[nodiscard]] bool matches(const Type *otherType, bool ignoreArraySize) const;

// Serialization
void getName(std::stringstream &name, bool withSize = false) const;
Expand Down Expand Up @@ -82,10 +82,6 @@ class Type {
[[nodiscard]] const Type *getWithBaseTemplateTypes(const QualTypeList &templateTypes) const;
[[nodiscard]] const Type *getWithFunctionParamAndReturnTypes(const QualTypeList &paramAndReturnTypes) const;

// Overloaded operators
friend bool operator==(const Type &lhs, const Type &rhs);
friend bool operator!=(const Type &lhs, const Type &rhs);

// Public static methods
static void unwrapBoth(const Type *&typeA, const Type *&typeB);
static bool hasSameTypeChainDepth(const Type *typeA, const Type *typeB);
Expand Down
21 changes: 8 additions & 13 deletions src/symboltablebuilder/TypeChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,14 @@ bool operator==(const TypeChainElement &lhs, const TypeChainElement &rhs) {
switch (lhs.superType) {
case TY_ARRAY:
return lhs.data.arraySize == rhs.data.arraySize;
case TY_STRUCT: // fall-through
case TY_INTERFACE: // fall-through
case TY_ENUM: {
if (lhs.superType == TY_STRUCT) {
assert(lhs.data.bodyScope != nullptr && rhs.data.bodyScope != nullptr);
return lhs.typeId == rhs.typeId && lhs.templateTypes == rhs.templateTypes;
} else if (lhs.superType == TY_INTERFACE) {
return lhs.typeId == rhs.typeId;
} else {
assert(lhs.data.bodyScope != nullptr && rhs.data.bodyScope != nullptr);
return lhs.typeId == rhs.typeId && lhs.data.bodyScope == rhs.data.bodyScope;
}
}
case TY_STRUCT:
assert(lhs.data.bodyScope != nullptr && rhs.data.bodyScope != nullptr);
return lhs.typeId == rhs.typeId && lhs.templateTypes == rhs.templateTypes;
case TY_INTERFACE:
return lhs.typeId == rhs.typeId;
case TY_ENUM:
assert(lhs.data.bodyScope != nullptr && rhs.data.bodyScope != nullptr);
return lhs.typeId == rhs.typeId && lhs.data.bodyScope == rhs.data.bodyScope;
case TY_FUNCTION: // fall-through
case TY_PROCEDURE:
if (lhs.paramTypes.size() != rhs.paramTypes.size())
Expand Down
Loading

0 comments on commit 8dfbf04

Please sign in to comment.