Skip to content

Commit

Permalink
Extend
Browse files Browse the repository at this point in the history
  • Loading branch information
marcauberer committed Nov 21, 2023
1 parent a5b956b commit 7286c08
Show file tree
Hide file tree
Showing 15 changed files with 103 additions and 72 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 --disable-verifier ../../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 --disable-verifier ../../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
38 changes: 36 additions & 2 deletions media/test-project/test.spice
Original file line number Diff line number Diff line change
@@ -1,5 +1,39 @@
import "../../src-bootstrap/reader/reader";
import "std/iterator/iterable";
import "std/data/pair";

type T short|int|long;

type MockIterator<T> struct : Iterable<T> {
T item
unsigned long cursor
}

p MockIterator.ctor() {
this.cursor = 0l;
}

f<T&> MockIterator.get() {
return this.item;
}

f<Pair<unsigned long, T&>> MockIterator.getIdx() {
return Pair<unsigned long, T&>(0l, this.item);
}

f<bool> MockIterator.isValid() {
return true;
}

p MockIterator.next() {}

f<int> main() {
foreach dyn item : MockIterator<short>() {
printf("Demo item: %d\n", item);
}
}

/*import "../../src-bootstrap/reader/reader";

f<int> main() {
Reader reader = Reader("./test.spice");
}
}*/
2 changes: 2 additions & 0 deletions src/ast/ASTNodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class ASTNode {
[[nodiscard]] virtual bool isFctOrProcDef() const { return false; }
[[nodiscard]] virtual bool isStructDef() const { return false; }
[[nodiscard]] virtual bool isStmtNode() const { return false; }
[[nodiscard]] virtual bool isParamNode() const { return false; }
[[nodiscard]] virtual bool isAssignExpr() const { return false; }

// Public members
Expand Down Expand Up @@ -918,6 +919,7 @@ class DeclStmtNode : public ASTNode {

// Util methods
void customItemsInitialization(size_t manifestationCount) override { entries.resize(manifestationCount, nullptr); }
[[nodiscard]] bool isParamNode() const override { return isParam; }

// Public members
std::string varName;
Expand Down
11 changes: 8 additions & 3 deletions src/irgenerator/GenImplicit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,14 @@ void IRGenerator::generateCtorOrDtorCall(SymbolTableEntry *entry, const Function
}

void IRGenerator::generateDeallocCall(llvm::Value *variableAddress) const {
// Issue call
llvm::Function *deallocFct = stdFunctionManager.getDeallocBytePtrRefFct();
builder.CreateCall(deallocFct, variableAddress);
// In case of string runtime, call free manually. Otherwise, use the memory_rt implementation of sDealloc()
if (sourceFile->isStringRT()) {
llvm::Function *freeFct = stdFunctionManager.getFreeFctPtr();
builder.CreateCall(freeFct, variableAddress);
} else {
llvm::Function *deallocFct = stdFunctionManager.getDeallocBytePtrRefFct();
builder.CreateCall(deallocFct, variableAddress);
}
}

llvm::Function *IRGenerator::generateImplicitFunction(const std::function<void(void)> &generateBody, const Function *spiceFunc) {
Expand Down
45 changes: 0 additions & 45 deletions src/irgenerator/GenTopLevelDefinitions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -479,45 +479,9 @@ std::any IRGenerator::visitStructDef(const StructDefNode *node) {
currentScope = spiceStruct->scope;
assert(currentScope);

// Create struct definition
const std::string mangledName = NameMangling::mangleStruct(*spiceStruct);
llvm::StructType *structType = llvm::StructType::create(context, mangledName);

// Set LLVM type to the struct entry
SymbolTableEntry *structEntry = spiceStruct->entry;
assert(structEntry != nullptr);
structEntry->setStructLLVMType(structType);
std::vector<llvm::Type *> fieldTypes;
fieldTypes.reserve(node->fields().size());

// Collect interface types
if (const TypeLstNode *typeLst = node->interfaceTypeLst()) {
for (const DataTypeNode *interfaceTypeNode : typeLst->dataTypes()) {
const SymbolType symbolType = interfaceTypeNode->getEvaluatedSymbolType(manIdx);
assert(symbolType.is(TY_INTERFACE));
const Interface *interface = symbolType.getInterface(interfaceTypeNode);
assert(interface != nullptr);
llvm::StructType *interfaceType = interface->entry->getStructLLVMType();
assert(interfaceType != nullptr);
fieldTypes.push_back(interfaceType);
}
} else if (node->emitVTable) {
// If no interface was specified, we still need to add a pointer to the VTable
fieldTypes.push_back(builder.getPtrTy());
}

// Collect concrete field types
for (const FieldNode *field : node->fields()) {
SymbolTableEntry *fieldEntry = currentScope->lookupStrict(field->fieldName);
assert(fieldEntry && !fieldEntry->getType().hasAnyGenericParts());
fieldTypes.push_back(fieldEntry->getType().toLLVMType(context, currentScope));
}

// Set field types to struct type
bool isPacked = false;
if (node->attrs() && node->attrs()->attrLst()->hasAttr(ATTR_CORE_COMPILER_PACKED))
isPacked = node->attrs()->attrLst()->getAttrValueByName(ATTR_CORE_COMPILER_PACKED)->boolValue;
structType->setBody(fieldTypes, isPacked);

// Generate VTable if required
if (node->emitVTable) {
Expand Down Expand Up @@ -567,15 +531,6 @@ std::any IRGenerator::visitInterfaceDef(const InterfaceDefNode *node) {
if (!spiceInterface->used && !spiceInterface->entry->getType().isPublic())
continue;

// Generate empty struct
const std::string mangledName = NameMangling::mangleInterface(*spiceInterface);
llvm::StructType *structType = llvm::StructType::create(context, mangledName);
structType->setBody(builder.getPtrTy());

// Set LLVM type to the interface entry
node->entry->setStructLLVMType(structType);
spiceInterface->entry->setStructLLVMType(structType);

// Generate VTable information
generateVTable(spiceInterface);
deferredVTableInitializations.emplace_back([=, this]() { generateVTableInitializer(spiceInterface); }, false);
Expand Down
6 changes: 3 additions & 3 deletions src/irgenerator/GenValues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ std::any IRGenerator::visitLambdaFunc(const LambdaFuncNode *node) {
captureType = capture.second.capturedEntry->getType().toLLVMType(context, currentScope);
captureTypes.push_back(captureType);
}
capturesStructType = llvm::StructType::create(context, captureTypes, getUnusedGlobalName(ANON_GLOBAL_CAPTURES_ARRAY_NAME));
capturesStructType = llvm::StructType::get(context, captureTypes);
// Add the captures struct as first parameter
paramInfoList.emplace_back(CAPTURES_PARAM_NAME, nullptr);
paramTypes.push_back(builder.getPtrTy()); // The capture struct is always passed as pointer
Expand Down Expand Up @@ -602,7 +602,7 @@ std::any IRGenerator::visitLambdaProc(const LambdaProcNode *node) {
captureType = capture.second.capturedEntry->getType().toLLVMType(context, currentScope);
captureTypes.push_back(captureType);
}
capturesStructType = llvm::StructType::create(context, captureTypes, getUnusedGlobalName(ANON_GLOBAL_CAPTURES_ARRAY_NAME));
capturesStructType = llvm::StructType::get(context, captureTypes);
// Add the captures struct as first parameter
paramInfoList.emplace_back(CAPTURES_PARAM_NAME, nullptr);
paramTypes.push_back(builder.getPtrTy()); // The captures struct is always passed as pointer
Expand Down Expand Up @@ -760,7 +760,7 @@ std::any IRGenerator::visitLambdaExpr(const LambdaExprNode *node) {
captureType = capture.second.capturedEntry->getType().toLLVMType(context, currentScope);
captureTypes.push_back(captureType);
}
capturesStructType = llvm::StructType::create(context, captureTypes, getUnusedGlobalName(ANON_GLOBAL_CAPTURES_ARRAY_NAME));
capturesStructType = llvm::StructType::get(context, captureTypes);
// Add the captures struct as first parameter
paramInfoList.emplace_back(CAPTURES_PARAM_NAME, nullptr);
paramTypes.push_back(builder.getPtrTy()); // The capture struct is always passed as pointer
Expand Down
2 changes: 0 additions & 2 deletions src/irgenerator/IRGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ namespace spice::compiler {

const char *const ANON_GLOBAL_STRING_NAME = "anon.string.";
const char *const ANON_GLOBAL_ARRAY_NAME = "anon.array.";
const char *const ANON_GLOBAL_STRUCT_NAME = "anon.struct.";
const char *const ANON_GLOBAL_CAPTURES_ARRAY_NAME = "anon.captures.";
const char *const CAPTURES_PARAM_NAME = "captures";

enum Likeliness { UNSPECIFIED, LIKELY, UNLIKELY };
Expand Down
10 changes: 10 additions & 0 deletions src/irgenerator/StdFunctionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,16 @@ llvm::Function *StdFunctionManager::getPrintfFct() const {
return printfFct;
}

llvm::Function *StdFunctionManager::getFreeFctPtr() const {
llvm::Function *freeFct = getProcedure("free", builder.getPtrTy());
// Set attributes
freeFct->addFnAttr(llvm::Attribute::NoUnwind);
freeFct->addParamAttr(0, llvm::Attribute::NoCapture);
freeFct->addParamAttr(0, llvm::Attribute::NoUndef);
freeFct->addParamAttr(0, llvm::Attribute::ReadOnly);
return freeFct;
}

llvm::Function *StdFunctionManager::getExitFct() const {
llvm::Function *exitFct = getProcedure("exit", builder.getInt32Ty());
// Set attributes
Expand Down
1 change: 1 addition & 0 deletions src/irgenerator/StdFunctionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class StdFunctionManager {

// Public methods for function retrieval
[[nodiscard]] llvm::Function *getPrintfFct() const;
[[nodiscard]] llvm::Function *getFreeFctPtr() const;
[[nodiscard]] llvm::Function *getExitFct() const;
[[nodiscard]] llvm::Function *getMemcpyIntrinsic() const;
[[nodiscard]] llvm::Function *getMemcmpIntrinsic() const;
Expand Down
4 changes: 2 additions & 2 deletions src/model/StructBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ std::string StructBase::getSignature(const std::string &name, const std::vector<
for (size_t i = 0; i < concreteTemplateTypes.size(); i++) {
if (i > 0)
templateTyStr << ",";
templateTyStr << concreteTemplateTypes.at(i).getName();
templateTyStr << concreteTemplateTypes.at(i).getName(false, true);
}
templateTyStr << ">";
}
Expand Down Expand Up @@ -81,4 +81,4 @@ std::vector<SymbolType> StructBase::getTemplateTypes() const {
*/
const CodeLoc &StructBase::getDeclCodeLoc() const { return declNode->codeLoc; }

} // namespace spice::compiler
} // namespace spice::compiler
2 changes: 1 addition & 1 deletion src/symboltablebuilder/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ SymbolTableEntry *SymbolTable::insert(const std::string &name, ASTNode *declNode
entry->updateState(DECLARED, declNode);

// Check if shadowed
if (parent != nullptr && parent->lookup(name) != nullptr) {
if (parent != nullptr && parent->lookup(name) != nullptr && !declNode->isParamNode()) {
CompilerWarning warning(declNode->codeLoc, SHADOWED_VARIABLE, "Variable '" + name + "' shadows a variable in a parent scope");
scope->sourceFile->compilerOutput.warnings.push_back(warning);
}
Expand Down
21 changes: 18 additions & 3 deletions src/symboltablebuilder/SymbolType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "SymbolType.h"

#include <SourceFile.h>
#include <ast/Attributes.h>
#include <exception/CompilerError.h>
#include <exception/SemanticError.h>
#include <irgenerator/NameMangling.h>
Expand Down Expand Up @@ -181,20 +182,33 @@ llvm::Type *SymbolType::toLLVMType(llvm::LLVMContext &context, Scope *accessScop

// Collect concrete field types
std::vector<llvm::Type *> fieldTypes;
bool isPacked = false;
if (is(TY_STRUCT)) { // Struct
const size_t totalFieldCount = spiceStruct->scope->getFieldCount();
fieldTypes.reserve(totalFieldCount);

// If the struct has no interface types, but a vtable was requested, add another ptr field type
assert(structSymbol->declNode->isStructDef());
auto structDeclNode = spice_pointer_cast<StructDefNode *>(structSymbol->declNode);
if (!structDeclNode->hasInterfaces && structDeclNode->emitVTable)
fieldTypes.push_back(llvm::PointerType::get(context, 0));

// Collect all field types
for (size_t i = 0; i < totalFieldCount; i++) {
const SymbolTableEntry *fieldSymbol = spiceStruct->scope->symbolTable.lookupStrictByIndex(i);
assert(fieldSymbol != nullptr);
fieldTypes.push_back(fieldSymbol->getType().toLLVMType(context, accessScope));
}

// Check if the struct is declared as packed
if (structDeclNode->attrs() && structDeclNode->attrs()->attrLst()->hasAttr(ATTR_CORE_COMPILER_PACKED))
isPacked = structDeclNode->attrs()->attrLst()->getAttrValueByName(ATTR_CORE_COMPILER_PACKED)->boolValue;
} else { // Interface
fieldTypes.push_back(llvm::PointerType::get(context, 0));
}

// Set field types to struct type
structType->setBody(fieldTypes);
structType->setBody(fieldTypes, isPacked);
}

return structType;
Expand Down Expand Up @@ -381,14 +395,15 @@ bool SymbolType::isCoveredByGenericTypeList(std::vector<GenericType> &genericTyp
* Get the name of the symbol type as a string
*
* @param withSize Include the array size for sized types
* @param ignorePublic Ignore any potential public specifier
* @return Symbol type name
*/
std::string SymbolType::getName(bool withSize) const { // NOLINT(misc-no-recursion)
std::string SymbolType::getName(bool withSize, bool ignorePublic) const { // NOLINT(misc-no-recursion)
std::stringstream name;

// Append the specifiers
const TypeSpecifiers defaultForSuperType = TypeSpecifiers::of(getBaseType().getSuperType());
if (specifiers.isPublic && !defaultForSuperType.isPublic)
if (!ignorePublic && specifiers.isPublic && !defaultForSuperType.isPublic)
name << "public ";
if (specifiers.isInline && !defaultForSuperType.isInline)
name << "inline ";
Expand Down
5 changes: 3 additions & 2 deletions src/symboltablebuilder/SymbolType.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class SymbolType {
friend bool operator==(const TypeChainElement &lhs, const TypeChainElement &rhs);
friend bool operator!=(const TypeChainElement &lhs, const TypeChainElement &rhs);
[[nodiscard]] std::string getName(bool withSize) const;
[[nodiscard]] std::string getOriginalSubType() const;

// Public members
SymbolSuperType superType = TY_DYN;
Expand Down Expand Up @@ -158,7 +159,7 @@ class SymbolType {
}
[[nodiscard]] ALWAYS_INLINE std::string getOriginalSubType() const {
assert(isOneOf({TY_STRUCT, TY_INTERFACE, TY_ENUM, TY_GENERIC}));
return CommonUtil::getLastFragment(typeChain.back().subType, SCOPE_ACCESS_TOKEN);
return typeChain.back().getOriginalSubType();
}
[[nodiscard]] ALWAYS_INLINE SymbolType removeReferenceWrapper() const { return isRef() ? getContainedTy() : *this; }
[[nodiscard]] SymbolType getBaseType() const {
Expand All @@ -170,7 +171,7 @@ class SymbolType {
void setBaseTemplateTypes(const std::vector<SymbolType> &templateTypes);
[[nodiscard]] const std::vector<SymbolType> &getTemplateTypes() const;
[[nodiscard]] bool isCoveredByGenericTypeList(std::vector<GenericType> &genericTypeList) const;
[[nodiscard]] std::string getName(bool withSize = false) const;
[[nodiscard]] std::string getName(bool withSize = false, bool ignorePublic = false) const;
[[nodiscard]] ALWAYS_INLINE size_t getArraySize() const {
assert(getSuperType() == TY_ARRAY);
return typeChain.back().data.arraySize;
Expand Down
25 changes: 18 additions & 7 deletions src/symboltablebuilder/TypeChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,18 @@ std::string SymbolType::TypeChainElement::getName(bool withSize) const {
return "bool";
case TY_STRUCT: // fall-through
case TY_INTERFACE: {
std::string templateStr;
std::stringstream name;
name << subType;
if (!templateTypes.empty()) {
for (const auto &templateType : templateTypes) {
if (!templateStr.empty())
templateStr += ",";
templateStr += templateType.getName();
name << "<";
for (size_t i = 0; i < templateTypes.size(); i++) {
if (i > 0)
name << ",";
name << templateTypes.at(i).getName();
}
templateStr = "<" + templateStr + ">";
name << ">";
}
return subType + templateStr;
return name.str();
}
case TY_ENUM:
return "enum";
Expand Down Expand Up @@ -133,4 +135,13 @@ std::string SymbolType::TypeChainElement::getName(bool withSize) const {
}
}

/**
* Get the original sub type, without any namespace information
*
* @return last fragment of sub type
*/
std::string SymbolType::TypeChainElement::getOriginalSubType() const {
return CommonUtil::getLastFragment(subType, SCOPE_ACCESS_TOKEN);
}

} // namespace spice::compiler
1 change: 0 additions & 1 deletion std/runtime/string_rt.spice
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import "std/type/error";
// We intentionally do not use the memory_rt here to avoid dependency circles
ext f<heap char*> malloc(unsigned long);
ext f<heap char*> realloc(heap char*, unsigned long);
ext p free(heap char*);
ext p memcpy(heap char*, heap char*, unsigned long);

// Constants
Expand Down

0 comments on commit 7286c08

Please sign in to comment.