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 { fn multwo(num: i32, double_flag: bool) i32 {
// TODO resolve expr variables if (double_flag) {
if (true) {
var truthy = true; var truthy = true;
return 1 * 2; return num * 2;
} else { } else {
var falsey = false; 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 // for a function, we always create a new root scope for it
// and force-set it into the current context // 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(); errdefer scope.deinit();
// we intentionally insert the function so that: // we intentionally insert the function so that:

View File

@ -284,6 +284,8 @@ pub const Codegen = struct {
var then_rets = false; var then_rets = false;
var else_rets = false; var else_rets = false;
self.ctx.setScope(self.ctx.current_scope.?.nextChild());
for (ifstmt.then_branch.toSlice()) |then_stmt| { for (ifstmt.then_branch.toSlice()) |then_stmt| {
// keep emitting until branch has ret // 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 // only build the br instruction if we didn't ret, because
// there can't be any instruction after a terminator // there can't be any instruction after a terminator
// same applies for the else branch // same applies for the else branch
@ -309,6 +313,7 @@ pub const Codegen = struct {
// roughly translating to kaleidoscope's // roughly translating to kaleidoscope's
// 'Else *ElseV = Else->codegen();' // 'Else *ElseV = Else->codegen();'
if (ifstmt.else_branch) |else_block| { if (ifstmt.else_branch) |else_block| {
self.ctx.setScope(self.ctx.current_scope.?.nextChild());
for (else_block.toSlice()) |else_stmt| { for (else_block.toSlice()) |else_stmt| {
// keep emitting until branch has ret // keep emitting until branch has ret
if (!else_rets) if (!else_rets)
@ -319,6 +324,8 @@ pub const Codegen = struct {
else => {}, else => {},
} }
} }
self.ctx.dumpScope();
} }
if (!else_rets) if (!else_rets)
@ -330,18 +337,30 @@ pub const Codegen = struct {
if (then_rets and else_rets) if (then_rets and else_rets)
_ = llvm.LLVMBuildUnreachable(builder); _ = 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 // 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 => { else => {
std.debug.warn("Got unexpected stmt {}\n", stmt.*); 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. /// Emit LLVM ir for the given node.
fn genNode( fn genNode(
self: *Codegen, self: *Codegen,
@ -361,10 +386,9 @@ pub const Codegen = struct {
.FnDecl => |decl| { .FnDecl => |decl| {
const name = decl.func_name.lexeme; const name = decl.func_name.lexeme;
self.current_function_name = name; self.current_function_name = name;
std.debug.warn("cgen: genning function '{}'\n", name);
var fn_sym_search = self.ctx.symbol_table.get(name).?.value; var fn_sym = self.getFnSymbol(name);
std.debug.assert(comp.SymbolType(fn_sym_search) == .Function);
var fn_sym = fn_sym_search.Function;
const name_cstr = try std.cstr.addNullByte(self.allocator, name); const name_cstr = try std.cstr.addNullByte(self.allocator, name);
errdefer self.allocator.free(name_cstr); errdefer self.allocator.free(name_cstr);
@ -396,6 +420,9 @@ pub const Codegen = struct {
var builder = llvm.LLVMCreateBuilder(); var builder = llvm.LLVMCreateBuilder();
llvm.LLVMPositionBuilderAtEnd(builder, entry); llvm.LLVMPositionBuilderAtEnd(builder, entry);
self.ctx.setScope(fn_sym.scope);
defer self.ctx.dumpScope();
for (decl.body.toSlice()) |stmt| { for (decl.body.toSlice()) |stmt| {
try self.emitStmt(builder, &stmt); try self.emitStmt(builder, &stmt);
} }

View File

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