Skip to content

Commit

Permalink
globals
Browse files Browse the repository at this point in the history
  • Loading branch information
vajexal committed May 6, 2024
1 parent 90fab2e commit c7bd036
Show file tree
Hide file tree
Showing 17 changed files with 176 additions and 55 deletions.
1 change: 1 addition & 0 deletions parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ top_statement:
class_decl { $$ = $1; }
| interface_decl { $$ = $1; }
| fn_def { $$ = $1; }
| var_decl { $$ = $1; }
| COMMENT { $$ = new CommentNode(std::move($1)); }
;

Expand Down
2 changes: 2 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ fn types() void {
[]Foo arr = []Foo{new Foo(), new Foo()}
}
auto PI = 3.14 // globals
fn flow() void {
// will print "then"
if true {
Expand Down
19 changes: 19 additions & 0 deletions src/ast.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,25 @@ namespace X {
return false;
}

void TopStatementListNode::add(Node *node) {
switch (node->getKind()) {
case NodeKind::Class:
classes.push_back(llvm::cast<ClassNode>(node));
break;
case NodeKind::Interface:
interfaces.push_back(llvm::cast<InterfaceNode>(node));
break;
case NodeKind::FnDef:
funcs.push_back(llvm::cast<FnDefNode>(node));
break;
case NodeKind::Decl:
globals.push_back(llvm::cast<DeclNode>(node));
break;
}

StatementListNode::add(node);
}

ClassNode::ClassNode(std::string name, StatementListNode *body, std::string parent, std::vector<std::string> interfaces, bool abstract) :
Node(NodeKind::Class), name(std::move(name)), body(body), parent(std::move(parent)), interfaces(std::move(interfaces)), abstract(abstract) {
for (auto child: body->getChildren()) {
Expand Down
16 changes: 4 additions & 12 deletions src/ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,28 +176,20 @@ namespace X {
class FnDefNode;
class ClassNode;
class InterfaceNode;
class DeclNode;

class TopStatementListNode : public StatementListNode {
std::vector<ClassNode *> classes;
std::vector<InterfaceNode *> interfaces;
std::vector<FnDefNode *> funcs;
std::vector<DeclNode *> globals;

public:
void add(Node *node) {
if (auto classNode = llvm::dyn_cast<ClassNode>(node)) {
classes.push_back(classNode);
} else if (auto interfaceNode = llvm::dyn_cast<InterfaceNode>(node)) {
interfaces.push_back(interfaceNode);
} else if (auto fnDefNode = llvm::dyn_cast<FnDefNode>(node)) {
funcs.push_back(fnDefNode);
}

StatementListNode::add(node);
}

void add(Node *node);
const std::vector<ClassNode *> &getClasses() const { return classes; }
const std::vector<InterfaceNode *> &getInterfaces() const { return interfaces; }
const std::vector<FnDefNode *> &getFuncs() const { return funcs; }
const std::vector<DeclNode *> &getGlobals() const { return globals; }
};

class UnaryNode : public ExprNode {
Expand Down
8 changes: 7 additions & 1 deletion src/codegen/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace X::Codegen {
// declare props here, so we can calc class size (for allocating objects)
declProps(node);
declFuncs(node);
declGlobals(node);

gen(node);
}
Expand All @@ -34,6 +35,10 @@ namespace X::Codegen {

llvm::Value *Codegen::gen(TopStatementListNode *node) {
for (auto child: node->getChildren()) {
if (llvm::isa<DeclNode>(child)) {
continue; // we already declared globals
}

child->gen(*this);
}

Expand Down Expand Up @@ -74,6 +79,7 @@ namespace X::Codegen {
return builder.getFalse();
case Type::TypeID::STRING:
case Type::TypeID::ARRAY:
case Type::TypeID::CLASS:
return llvm::ConstantPointerNull::get(builder.getPtrTy());
default:
throw InvalidTypeException();
Expand All @@ -92,7 +98,7 @@ namespace X::Codegen {
return builder.CreateCall(module.getFunction(Mangler::mangleInternalFunction("createEmptyString")));
case Type::TypeID::ARRAY: {
auto arrType = getArrayForType(type);
auto arr = createAlloca(arrType);
auto arr = newObj(arrType);
auto len = builder.getInt64(0);
builder.CreateCall(getInternalConstructor(arrType->getName().str()), {arr, len});
return arr;
Expand Down
5 changes: 4 additions & 1 deletion src/codegen/codegen.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace X::Codegen {

public:
static inline const std::string MAIN_FN_NAME = "main";
static inline const std::string INIT_FN_NAME = "init";

Codegen(llvm::LLVMContext &context, llvm::IRBuilder<> &builder, llvm::Module &module, CompilerRuntime &compilerRuntime, GC::GC &gc) :
context(context), builder(builder), module(module), compilerRuntime(compilerRuntime), arrayRuntime(Runtime::ArrayRuntime(context, module)),
Expand Down Expand Up @@ -149,6 +150,7 @@ namespace X::Codegen {
void declMethods(TopStatementListNode *node);
void declProps(TopStatementListNode *node);
void declFuncs(TopStatementListNode *node);
void declGlobals(TopStatementListNode *node);

llvm::Type *mapType(const Type &type);
llvm::Constant *getDefaultValue(const Type &type);
Expand Down Expand Up @@ -206,7 +208,8 @@ namespace X::Codegen {

// gc helpers
llvm::Value *gcAlloc(llvm::Value *size);
void gcAddRoot(llvm::Value *root, const Type &type);
void gcAddRoot(llvm::AllocaInst *root, const Type &type);
void gcAddGlobalRoot(llvm::Value *root, const Type &type);
};

class CodegenException : public std::exception {
Expand Down
48 changes: 48 additions & 0 deletions src/codegen/decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,54 @@ namespace X::Codegen {
}
}

void Codegen::declGlobals(TopStatementListNode *node) {
auto &globals = node->getGlobals();

if (globals.empty()) {
return;
}

// create init function
auto initFn = llvm::Function::Create(
llvm::FunctionType::get(builder.getVoidTy(), {}, false),
llvm::Function::ExternalLinkage,
Mangler::mangleInternalFunction(INIT_FN_NAME),
module
);
builder.SetInsertPoint(llvm::BasicBlock::Create(context, "entry", initFn));

varScopes.emplace_back();
auto &vars = varScopes.back();

for (auto decl: globals) {
auto &name = decl->getName();
if (vars.contains(name)) {
throw VarAlreadyExistsException(name);
}

auto &type = decl->getType();
auto llvmType = mapType(type);
auto global = llvm::cast<llvm::GlobalVariable>(module.getOrInsertGlobal(name, llvmType));

auto value = decl->getExpr() ?
decl->getExpr()->gen(*this) :
createDefaultValue(type);

if (auto constValue = llvm::dyn_cast<llvm::Constant>(value)) {
global->setInitializer(constValue);
} else {
global->setInitializer(getDefaultValue(type));
builder.CreateStore(value, global);
}

vars[name] = {global, type};

gcAddGlobalRoot(global, type);
}

builder.CreateRetVoid();
}

void Codegen::checkConstructor(MethodDefNode *node, const std::string &className) const {
if (node->getIsStatic()) {
throw CodegenException(fmt::format("{}::{} cannot be static", className, CONSTRUCTOR_FN_NAME));
Expand Down
2 changes: 1 addition & 1 deletion src/codegen/function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ namespace X::Codegen {
builder.CreateRetVoid();
}

varScopes.clear();
varScopes.pop_back();

that = std::nullopt;
}
Expand Down
12 changes: 11 additions & 1 deletion src/codegen/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,22 @@ namespace X::Codegen {
return builder.CreateCall(allocFn, {gcVar, size});
}

void Codegen::gcAddRoot(llvm::Value *root, const Type &type) {
void Codegen::gcAddRoot(llvm::AllocaInst *root, const Type &type) {
auto meta = getGCMetaValue(type);
if (!meta) {
return;
}

builder.CreateIntrinsic(llvm::Intrinsic::gcroot, {}, {root, meta});
}

void Codegen::gcAddGlobalRoot(llvm::Value *root, const Type &type) {
auto meta = getGCMetaValue(type);
if (!meta) {
return;
}

auto gcVar = module.getGlobalVariable(Mangler::mangleInternalSymbol("gc"));
builder.CreateCall(module.getFunction(Mangler::mangleInternalFunction("gcAddGlobalRoot")), {gcVar, root, meta});
}
}
11 changes: 11 additions & 0 deletions src/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ namespace X::GC {
stackFrames.back().push_back({root, meta});
}

void GC::addGlobalRoot(void **root, Metadata *meta) {
globalRoots.push_back({root, meta});
}

void GC::run() {
mark();
sweep();
Expand All @@ -60,6 +64,13 @@ namespace X::GC {
}

std::deque<std::pair<void *, Metadata *>> objects;

for (auto &root: globalRoots) {
if (*root.ptr) {
objects.emplace_back(*root.ptr, root.meta);
}
}

for (auto &roots: stackFrames) {
for (auto &root: roots) {
if (*root.ptr) {
Expand Down
2 changes: 2 additions & 0 deletions src/gc/gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ namespace X::GC {

// {ptr -> is alive}
std::unordered_map<void *, bool> allocs;
std::vector<Root> globalRoots;
std::deque<std::vector<Root>> stackFrames;

public:
Expand All @@ -49,6 +50,7 @@ namespace X::GC {
void pushStackFrame();
void popStackFrame();
void addRoot(void **root, Metadata *meta);
void addGlobalRoot(void **root, Metadata *meta);

private:
void mark();
Expand Down
9 changes: 8 additions & 1 deletion src/pipes/code_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,16 @@ namespace X::Pipes {
auto runtimeGCPtr = runtimeGCSymbol.toPtr<GC::GC **>();
*runtimeGCPtr = &gc; // nolint

// run init
auto maybeInitFn = jitter->lookup(Mangler::mangleInternalFunction(Codegen::Codegen::INIT_FN_NAME));
if (maybeInitFn) {
auto *fn = (*maybeInitFn).toPtr<void()>();
fn();
}

// run main
auto mainFn = throwOnError(jitter->lookup(Codegen::Codegen::MAIN_FN_NAME));
auto *fn = mainFn.toPtr<void()>();

fn();

// we can't run gc in alloc for now because we don't have intermediate roots ("h(f(), g())"),
Expand Down
17 changes: 15 additions & 2 deletions src/pipes/type_inferrer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace X::Pipes {
declClasses(node);
declMethods(node);
declFuncs(node);
declGlobals(node);

infer(node);

Expand Down Expand Up @@ -126,6 +127,18 @@ namespace X::Pipes {
}
}

void TypeInferrer::declGlobals(TopStatementListNode *node) {
auto &globals = node->getGlobals();

if (!globals.empty()) {
varScopes.emplace_back();
}

for (auto decl: globals) {
decl->infer(*this);
}
}

Type TypeInferrer::infer(Node *node) {
throw TypeInferrerException("can't infer node");
}
Expand Down Expand Up @@ -411,7 +424,7 @@ namespace X::Pipes {

node->getBody()->infer(*this);

varScopes.clear();
varScopes.pop_back();

return Type::voidTy();
}
Expand Down Expand Up @@ -485,7 +498,7 @@ namespace X::Pipes {

node->getFnDef()->getBody()->infer(*this);

varScopes.clear();
varScopes.pop_back();

that.reset();

Expand Down
1 change: 1 addition & 0 deletions src/pipes/type_inferrer.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ namespace X::Pipes {
void declClasses(TopStatementListNode *node);
void declMethods(TopStatementListNode *node);
void declFuncs(TopStatementListNode *node);
void declGlobals(TopStatementListNode *node);

void checkTypeIsValid(const Type &type) const;
void checkLvalueTypeIsValid(const Type &type) const;
Expand Down
Loading

0 comments on commit c7bd036

Please sign in to comment.