add codegen for allocating vardecls onto stack (not init yet)

codegen pass needs type information about the variable. thankfully,
analyze pass already did the hard work for it, and scope info has types
of all its declared names. we use that info to generate the alloca

to have information about which current scope we are, we add a "child
index" to scopes so we can repoint current context at them instead of
bumpScope(), which always creates new, empty ones.

initializer exprs are next
This commit is contained in:
Luna 2019-09-27 22:36:35 -03:00
parent 77c88fad34
commit d235ce0d13
4 changed files with 52 additions and 18 deletions

View file

@ -32,13 +32,12 @@ fn test_function() B {
}
fn multwo(num: i32, double_flag: bool) i32 {
// TODO resolve expr variables
if (true) {
if (double_flag) {
var truthy = true;
return 1 * 2;
return num * 2;
} else {
var falsey = false;
return 1;
return num;
}
}

View file

@ -458,7 +458,7 @@ pub const TypeSolver = struct {
// for a function, we always create a new root scope for it
// and force-set it into the current context
var scope = try comp.Scope.create(self.allocator, null, "function");
var scope = try comp.Scope.create(self.allocator, null, name);
errdefer scope.deinit();
// we intentionally insert the function so that:

View file

@ -284,6 +284,8 @@ pub const Codegen = struct {
var then_rets = false;
var else_rets = false;
self.ctx.setScope(self.ctx.current_scope.?.nextChild());
for (ifstmt.then_branch.toSlice()) |then_stmt| {
// keep emitting until branch has ret
@ -296,6 +298,8 @@ pub const Codegen = struct {
}
}
self.ctx.dumpScope();
// only build the br instruction if we didn't ret, because
// there can't be any instruction after a terminator
// same applies for the else branch
@ -309,6 +313,7 @@ pub const Codegen = struct {
// roughly translating to kaleidoscope's
// 'Else *ElseV = Else->codegen();'
if (ifstmt.else_branch) |else_block| {
self.ctx.setScope(self.ctx.current_scope.?.nextChild());
for (else_block.toSlice()) |else_stmt| {
// keep emitting until branch has ret
if (!else_rets)
@ -319,6 +324,8 @@ pub const Codegen = struct {
else => {},
}
}
self.ctx.dumpScope();
}
if (!else_rets)
@ -330,18 +337,30 @@ pub const Codegen = struct {
if (then_rets and else_rets)
_ = llvm.LLVMBuildUnreachable(builder);
// phis aren't needed since our ifs arent expressions
//var phi = llvm.LLVMBuildPhi(builder, llvm.LLVMVoidType(), c"iftmp");
//var then_bb_val = llvm.LLVMBasicBlockAsValue(then_bb);
//var else_bb_val = llvm.LLVMBasicBlockAsValue(else_bb);
//llvm.LLVMAddIncoming(phi, &then_bb_val, &then_bb, 1);
//llvm.LLVMAddIncoming(phi, &else_bb_val, &else_bb, 1);
},
// TODO
.VarDecl => {},
.VarDecl => |vardecl| {
// we alaready inferred the type of the variable in the
// analyze pass and the current scope contains the variable's
// type(hopefully), so we resolve it
const name = vardecl.name.lexeme;
var var_metadata = try self.ctx.resolveVarType(name);
var name_cstr = try std.cstr.addNullByte(self.allocator, name);
errdefer self.allocator.free(name_cstr);
var fn_symbol = self.getFnSymbol(self.current_function_name.?);
_ = llvm.LLVMBuildAlloca(
builder,
try self.typeToLLVM(var_metadata.typ),
name_cstr.ptr,
);
// TODO generate the store for the initializer
//var llvm_expr = try self.emitExpr(vardecl.value);
},
else => {
std.debug.warn("Got unexpected stmt {}\n", stmt.*);
@ -350,6 +369,12 @@ pub const Codegen = struct {
}
}
fn getFnSymbol(self: *@This(), name: []const u8) comp.FunctionSymbol {
var fn_sym_search = self.ctx.symbol_table.get(name).?.value;
std.debug.assert(comp.SymbolType(fn_sym_search) == .Function);
return fn_sym_search.Function;
}
/// Emit LLVM ir for the given node.
fn genNode(
self: *Codegen,
@ -361,10 +386,9 @@ pub const Codegen = struct {
.FnDecl => |decl| {
const name = decl.func_name.lexeme;
self.current_function_name = name;
std.debug.warn("cgen: genning function '{}'\n", name);
var fn_sym_search = self.ctx.symbol_table.get(name).?.value;
std.debug.assert(comp.SymbolType(fn_sym_search) == .Function);
var fn_sym = fn_sym_search.Function;
var fn_sym = self.getFnSymbol(name);
const name_cstr = try std.cstr.addNullByte(self.allocator, name);
errdefer self.allocator.free(name_cstr);
@ -396,6 +420,9 @@ pub const Codegen = struct {
var builder = llvm.LLVMCreateBuilder();
llvm.LLVMPositionBuilderAtEnd(builder, entry);
self.ctx.setScope(fn_sym.scope);
defer self.ctx.dumpScope();
for (decl.body.toSlice()) |stmt| {
try self.emitStmt(builder, &stmt);
}

View file

@ -39,8 +39,9 @@ pub const Scope = struct {
parent: ?*Scope,
env: UnderlyingTypeMap,
/// Used for debug information.
/// List of children in the scope.
children: ScopeList,
cur_child_idx: usize = 0,
allocator: *std.mem.Allocator,
id: ?[]const u8 = null,
@ -64,6 +65,12 @@ pub const Scope = struct {
return child;
}
pub fn nextChild(self: *@This()) *Scope {
var child = self.children.at(self.cur_child_idx);
self.cur_child_idx += 1;
return child;
}
pub fn deinit(self: *const @This()) void {
self.env.deinit();
}
@ -184,6 +191,7 @@ pub const CompilationContext = struct {
/// Set a given scope as the current scope.
pub fn setScope(self: *@This(), scope: *Scope) void {
std.debug.warn("==set== set scope to {}\n", scope.id);
self.current_scope = scope;
}