From d235ce0d139b73b8d371dc9bc56ec6338563b4ff Mon Sep 17 00:00:00 2001 From: Luna Date: Fri, 27 Sep 2019 22:36:35 -0300 Subject: [PATCH] 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 --- examples/hello.ry | 7 +++---- src/analysis.zig | 2 +- src/codegen.zig | 51 ++++++++++++++++++++++++++++++++++++----------- src/comp_ctx.zig | 10 +++++++++- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/examples/hello.ry b/examples/hello.ry index d3a4e54..0f97d4f 100644 --- a/examples/hello.ry +++ b/examples/hello.ry @@ -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; } } diff --git a/src/analysis.zig b/src/analysis.zig index f5c4897..4081d43 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -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: diff --git a/src/codegen.zig b/src/codegen.zig index 0e1f0be..b7212eb 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -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); } diff --git a/src/comp_ctx.zig b/src/comp_ctx.zig index c6d7a37..b22768c 100644 --- a/src/comp_ctx.zig +++ b/src/comp_ctx.zig @@ -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; }