From 178acc656f78c219f1b89c47bc412643ebe3a72a Mon Sep 17 00:00:00 2001 From: Luna Date: Fri, 27 Sep 2019 22:49:33 -0300 Subject: [PATCH 1/5] codegen: allow for mutable statements - ast: add llvm_alloca llvmvalueref pointer in VarDeclStmt --- src/ast.zig | 2 ++ src/codegen.zig | 33 ++++++++++++++++++++++----------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index 02093ed..efb0015 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -1,5 +1,6 @@ const std = @import("std"); const tokens = @import("tokens.zig"); +const llvm = @import("llvm.zig"); const Token = tokens.Token; pub const NodeList = std.ArrayList(Node); @@ -184,6 +185,7 @@ pub const ForStmt = struct { pub const VarDeclStmt = struct { name: Token, value: *Expr, + llvm_alloca: ?llvm.LLVMValueRef = null, }; pub const Stmt = union(enum) { diff --git a/src/codegen.zig b/src/codegen.zig index b7212eb..f06ba92 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -238,6 +238,9 @@ pub const Codegen = struct { var param = metadata.from_function.?.parameters.get(vari.lexeme).?.value; var llvm_func = self.llvm_table.get(self.current_function_name.?).?.value; + // TODO we should create stack-stored variables + // instead of the arg registers + // may i thank all the demons in hell for giving me // good energies to make this work break :blk llvm.LLVMGetParam(llvm_func, @intCast(c_uint, param.idx)); @@ -254,7 +257,7 @@ pub const Codegen = struct { }; } - fn emitStmt(self: *Codegen, builder: var, stmt: *const ast.Stmt) anyerror!void { + fn emitStmt(self: *Codegen, builder: var, stmt: *ast.Stmt) anyerror!void { switch (stmt.*) { .Expr => |expr| _ = try self.emitExpr(builder, expr), @@ -286,11 +289,12 @@ pub const Codegen = struct { self.ctx.setScope(self.ctx.current_scope.?.nextChild()); - for (ifstmt.then_branch.toSlice()) |then_stmt| { + var then_branch = ifstmt.then_branch.toSlice(); + for (then_branch) |_, idx| { // keep emitting until branch has ret if (!then_rets) - try self.emitStmt(builder, &then_stmt); + try self.emitStmt(builder, &then_branch[idx]); switch (then_stmt) { .Return => then_rets = true, @@ -314,10 +318,12 @@ pub const Codegen = struct { // 'Else *ElseV = Else->codegen();' if (ifstmt.else_branch) |else_block| { self.ctx.setScope(self.ctx.current_scope.?.nextChild()); - for (else_block.toSlice()) |else_stmt| { + + var else_slice = else_block.toSlice(); + for (else_slice) |_, idx| { // keep emitting until branch has ret if (!else_rets) - try self.emitStmt(builder, &else_stmt); + try self.emitStmt(builder, &else_slice[idx]); switch (else_stmt) { .Return => else_rets = true, @@ -335,11 +341,12 @@ pub const Codegen = struct { llvm.LLVMPositionBuilderAtEnd(builder, merge_bb); + // if both of the branches return, we should put + // the merge branch as unreachable. if (then_rets and else_rets) _ = llvm.LLVMBuildUnreachable(builder); }, - // TODO .VarDecl => |vardecl| { // we alaready inferred the type of the variable in the // analyze pass and the current scope contains the variable's @@ -352,14 +359,17 @@ pub const Codegen = struct { var fn_symbol = self.getFnSymbol(self.current_function_name.?); - _ = llvm.LLVMBuildAlloca( + // TODO add llvm value ref to var metadata as well + var variable = 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); + vardecl.llvm_alloca = variable; + + var llvm_expr = try self.emitExpr(builder, vardecl.value); + _ = llvm.LLVMBuildStore(builder, llvm_expr, variable); }, else => { @@ -423,8 +433,9 @@ pub const Codegen = struct { self.ctx.setScope(fn_sym.scope); defer self.ctx.dumpScope(); - for (decl.body.toSlice()) |stmt| { - try self.emitStmt(builder, &stmt); + var body_slice = decl.body.toSlice(); + for (body_slice) |_, idx| { + try self.emitStmt(builder, &body_slice[idx]); } std.debug.warn("cgen: generated function '{}'\n", name); From 58713b20e3aea976c45da77aa4e083ecc8fda418 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 28 Sep 2019 11:32:36 -0300 Subject: [PATCH 2/5] add llvmvalueref to Parameter --- src/comp_ctx.zig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/comp_ctx.zig b/src/comp_ctx.zig index b22768c..d188645 100644 --- a/src/comp_ctx.zig +++ b/src/comp_ctx.zig @@ -1,5 +1,6 @@ const std = @import("std"); const ast = @import("ast.zig"); +const llvm = @import("llvm.zig"); pub const CompilationError = error{ TypeError, @@ -79,6 +80,7 @@ pub const Scope = struct { pub const Parameter = struct { idx: usize, typ: SymbolUnderlyingType, + alloca: ?llvm.LLVMValueRef = null, }; pub const ParameterMap = std.StringHashMap(Parameter); From 61c84934840052f56b2cb7bb80a6827a459998a2 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 28 Sep 2019 11:40:56 -0300 Subject: [PATCH 3/5] add basics of stack-stored arguments this requires some changes regarding the const-ability of the passed nodes into codegen. --- src/codegen.zig | 22 ++++++++++++++++++---- src/comp_ctx.zig | 2 ++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/codegen.zig b/src/codegen.zig index f06ba92..4d4fefd 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -389,7 +389,7 @@ pub const Codegen = struct { fn genNode( self: *Codegen, mod: llvm.LLVMModuleRef, - node: *const ast.Node, + node: *ast.Node, ) !void { switch (node.*) { .Root => @panic("Should not have gotten Root"), @@ -430,6 +430,20 @@ pub const Codegen = struct { var builder = llvm.LLVMCreateBuilder(); llvm.LLVMPositionBuilderAtEnd(builder, entry); + // to have the ability to mutate parameters, we must allocate them on + // the stack + for (params_slice) |param_node, idx| { + var param = fn_sym.parameters.get(param_node.name.lexeme).?.value; + + const name_cstr = try std.cstr.addNullByte(self.allocator, param_node.name.lexeme); + errdefer self.allocator.free(name_cstr); + + var alloca = llvm.LLVMBuildAlloca(builder, try self.typeToLLVM(param.typ), name_cstr.ptr); + param.llvm_alloca = alloca; + + // TODO store register into stack param + } + self.ctx.setScope(fn_sym.scope); defer self.ctx.dumpScope(); @@ -480,9 +494,9 @@ pub const Codegen = struct { var mod = llvm.LLVMModuleCreateWithName(c"awoo").?; defer llvm.LLVMDisposeModule(mod); - for (root.Root.toSlice()) |child| { - std.debug.warn("cgen: gen {}\n", @tagName(child)); - try self.genNode(mod, &child); + var root_slice = root.Root.toSlice(); + for (root_slice) |_, idx| { + try self.genNode(mod, &root_slice[idx]); } var err: ?[*]u8 = null; diff --git a/src/comp_ctx.zig b/src/comp_ctx.zig index d188645..7f6cb91 100644 --- a/src/comp_ctx.zig +++ b/src/comp_ctx.zig @@ -79,6 +79,7 @@ pub const Scope = struct { pub const Parameter = struct { idx: usize, + name: []const u8, typ: SymbolUnderlyingType, alloca: ?llvm.LLVMValueRef = null, }; @@ -271,6 +272,7 @@ pub const CompilationContext = struct { for (decl.params.toSlice()) |param, idx| { _ = try param_map.put(param.name.lexeme, Parameter{ + .name = param.name.lexeme, .idx = idx, .typ = param_types.at(idx), }); From 93811c986d3a335a76b41f655d6bcf5b7cc3b02b Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 28 Sep 2019 12:46:23 -0300 Subject: [PATCH 4/5] codegen: use Parameter.llvm_alloca --- src/ast.zig | 1 + src/codegen.zig | 12 ++++-------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/ast.zig b/src/ast.zig index efb0015..f23da82 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -24,6 +24,7 @@ pub const NodeType = enum { pub const ParamDecl = struct { name: Token, typ: Token, + }; pub const MethodData = struct { diff --git a/src/codegen.zig b/src/codegen.zig index 4d4fefd..8f24d22 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -236,14 +236,10 @@ pub const Codegen = struct { return switch (metadata.using) { .Function => blk: { var param = metadata.from_function.?.parameters.get(vari.lexeme).?.value; - var llvm_func = self.llvm_table.get(self.current_function_name.?).?.value; + // var llvm_func = self.llvm_table.get(self.current_function_name.?).?.value; + // break :blk llvm.LLVMGetParam(llvm_func, @intCast(c_uint, param.idx)); - // TODO we should create stack-stored variables - // instead of the arg registers - - // may i thank all the demons in hell for giving me - // good energies to make this work - break :blk llvm.LLVMGetParam(llvm_func, @intCast(c_uint, param.idx)); + break :blk param.llvm_alloca; }, .Scope => @panic("TODO local variables"), @@ -359,7 +355,6 @@ pub const Codegen = struct { var fn_symbol = self.getFnSymbol(self.current_function_name.?); - // TODO add llvm value ref to var metadata as well var variable = llvm.LLVMBuildAlloca( builder, try self.typeToLLVM(var_metadata.typ), @@ -442,6 +437,7 @@ pub const Codegen = struct { param.llvm_alloca = alloca; // TODO store register into stack param + // llvm.LLVMBuildStore(builder, null, assign_expr); } self.ctx.setScope(fn_sym.scope); From a136a377ce349b5557b3a5d4b20468ef186e85c9 Mon Sep 17 00:00:00 2001 From: Luna Date: Sat, 28 Sep 2019 13:17:11 -0300 Subject: [PATCH 5/5] change symbol table to use pointers to heap allocated symbols --- examples/hello.ry | 8 ++++---- src/analysis.zig | 4 ++-- src/ast.zig | 1 - src/ast_printer.zig | 2 +- src/codegen.zig | 44 ++++++++++++++++++++++++++------------------ src/comp_ctx.zig | 32 ++++++++++++++++++++------------ 6 files changed, 53 insertions(+), 38 deletions(-) diff --git a/examples/hello.ry b/examples/hello.ry index 0f97d4f..f3909eb 100644 --- a/examples/hello.ry +++ b/examples/hello.ry @@ -31,6 +31,10 @@ fn test_function() B { return B.b; } +fn func_refer_param(b: i32) i32 { + return b * 231 + b; +} + fn multwo(num: i32, double_flag: bool) i32 { if (double_flag) { var truthy = true; @@ -41,10 +45,6 @@ fn multwo(num: i32, double_flag: bool) i32 { } } -fn func_refer_param(b: i32) i32 { - return b * 231 + b; -} - fn add(a: i32, b: i32) i32 { return a + b; } diff --git a/src/analysis.zig b/src/analysis.zig index 4081d43..8a6a90d 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -80,7 +80,7 @@ pub const TypeSolver = struct { return null; } - return switch (sym.?.value) { + return switch (sym.?.value.*) { .Struct => SymbolUnderlyingType{ .Struct = val }, .Enum => SymbolUnderlyingType{ .Enum = val }, @@ -88,7 +88,7 @@ pub const TypeSolver = struct { self.doError( "expected struct or enum for '{}', got {}", val, - @tagName(comp.SymbolType(sym.?.value)), + @tagName(comp.SymbolType(sym.?.value.*)), ); break :blk null; }, diff --git a/src/ast.zig b/src/ast.zig index f23da82..efb0015 100644 --- a/src/ast.zig +++ b/src/ast.zig @@ -24,7 +24,6 @@ pub const NodeType = enum { pub const ParamDecl = struct { name: Token, typ: Token, - }; pub const MethodData = struct { diff --git a/src/ast_printer.zig b/src/ast_printer.zig index 48f9ae2..13b6fe4 100644 --- a/src/ast_printer.zig +++ b/src/ast_printer.zig @@ -388,7 +388,7 @@ pub fn printContext(ctx: CompilationContext) void { var it = ctx.symbol_table.iterator(); while (it.next()) |kv| { - switch (kv.value) { + switch (kv.value.*) { .Function => |fn_sym| { std.debug.warn( "function {} returns {}\n", diff --git a/src/codegen.zig b/src/codegen.zig index 8f24d22..0466d58 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -54,7 +54,7 @@ pub const Codegen = struct { .Struct, .Enum => |lex| blk: { var sym_data = self.ctx.symbol_table.get(lex).?.value; - break :blk switch (sym_data) { + break :blk switch (sym_data.*) { .Struct => unreachable, .Enum => llvm.LLVMInt32Type(), else => { @@ -74,7 +74,7 @@ pub const Codegen = struct { fn emitForVariableType(self: *@This(), vari: var, get: var, kv: var) !llvm.LLVMValueRef { var sym = kv.value; - switch (sym) { + switch (sym.*) { .Enum => |map| { var val = map.get(get.name.lexeme); if (val == null) { @@ -89,7 +89,7 @@ pub const Codegen = struct { .Struct => @panic("TODO handle struct"), else => { - std.debug.warn("Invalid get target: {}\n", comp.SymbolType(sym)); + std.debug.warn("Invalid get target: {}\n", comp.SymbolType(sym.*)); return CompileError.EmitError; }, } @@ -239,7 +239,8 @@ pub const Codegen = struct { // var llvm_func = self.llvm_table.get(self.current_function_name.?).?.value; // break :blk llvm.LLVMGetParam(llvm_func, @intCast(c_uint, param.idx)); - break :blk param.llvm_alloca; + std.debug.warn("fn param alloca {} {}\n", param.name, param.llvm_alloca); + break :blk param.llvm_alloca.?; }, .Scope => @panic("TODO local variables"), @@ -287,12 +288,14 @@ pub const Codegen = struct { var then_branch = ifstmt.then_branch.toSlice(); for (then_branch) |_, idx| { - // keep emitting until branch has ret - if (!then_rets) - try self.emitStmt(builder, &then_branch[idx]); + var then_stmt = &then_branch[idx]; - switch (then_stmt) { + if (!then_rets) + try self.emitStmt(builder, then_stmt); + + // TODO break? lol + switch (then_stmt.*) { .Return => then_rets = true, else => {}, } @@ -318,10 +321,12 @@ pub const Codegen = struct { var else_slice = else_block.toSlice(); for (else_slice) |_, idx| { // keep emitting until branch has ret - if (!else_rets) - try self.emitStmt(builder, &else_slice[idx]); + var else_stmt = &else_slice[idx]; - switch (else_stmt) { + if (!else_rets) + try self.emitStmt(builder, else_stmt); + + switch (else_stmt.*) { .Return => else_rets = true, else => {}, } @@ -361,7 +366,7 @@ pub const Codegen = struct { name_cstr.ptr, ); - vardecl.llvm_alloca = variable; + stmt.*.VarDecl.llvm_alloca = variable; var llvm_expr = try self.emitExpr(builder, vardecl.value); _ = llvm.LLVMBuildStore(builder, llvm_expr, variable); @@ -374,10 +379,10 @@ pub const Codegen = struct { } } - fn getFnSymbol(self: *@This(), name: []const u8) comp.FunctionSymbol { + 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; + std.debug.assert(comp.SymbolType(fn_sym_search.*) == .Function); + return &fn_sym_search.Function; } /// Emit LLVM ir for the given node. @@ -427,13 +432,16 @@ pub const Codegen = struct { // to have the ability to mutate parameters, we must allocate them on // the stack + var params_slice = decl.params.toSlice(); for (params_slice) |param_node, idx| { var param = fn_sym.parameters.get(param_node.name.lexeme).?.value; - const name_cstr = try std.cstr.addNullByte(self.allocator, param_node.name.lexeme); - errdefer self.allocator.free(name_cstr); + const param_name_cstr = try std.cstr.addNullByte(self.allocator, param_node.name.lexeme); + errdefer self.allocator.free(param_name_cstr); - var alloca = llvm.LLVMBuildAlloca(builder, try self.typeToLLVM(param.typ), name_cstr.ptr); + var alloca = llvm.LLVMBuildAlloca(builder, try self.typeToLLVM(param.typ), param_name_cstr.ptr); + + std.debug.warn("SET PARAM LLVM ALLOCA {} to {}\n", param_node.name.lexeme, alloca); param.llvm_alloca = alloca; // TODO store register into stack param diff --git a/src/comp_ctx.zig b/src/comp_ctx.zig index 7f6cb91..a786770 100644 --- a/src/comp_ctx.zig +++ b/src/comp_ctx.zig @@ -7,7 +7,7 @@ pub const CompilationError = error{ UnknownName, }; -pub const SymbolTable = std.hash_map.StringHashMap(SymbolData); +pub const SymbolTable = std.hash_map.StringHashMap(*SymbolData); pub const TypeList = std.ArrayList(SymbolUnderlyingType); pub const SymbolUnderlyingTypeEnum = enum { @@ -81,7 +81,8 @@ pub const Parameter = struct { idx: usize, name: []const u8, typ: SymbolUnderlyingType, - alloca: ?llvm.LLVMValueRef = null, + + llvm_alloca: llvm.LLVMValueRef = null, }; pub const ParameterMap = std.StringHashMap(Parameter); @@ -258,7 +259,9 @@ pub const CompilationContext = struct { _ = try type_map.put(field.name.lexeme, field_types.at(idx)); } - _ = try self.symbol_table.put(struc.name.lexeme, SymbolData{ .Struct = type_map }); + var symbol = try self.allocator.create(SymbolData); + symbol.* = SymbolData{ .Struct = type_map }; + _ = try self.symbol_table.put(struc.name.lexeme, symbol); } pub fn insertFn( @@ -280,7 +283,8 @@ pub const CompilationContext = struct { const lex = decl.func_name.lexeme; - _ = try self.symbol_table.put(lex, SymbolData{ + var symbol = try self.allocator.create(SymbolData); + symbol.* = SymbolData{ .Function = FunctionSymbol{ .decl = decl, .return_type = ret_type, @@ -288,7 +292,9 @@ pub const CompilationContext = struct { .parameter_list = param_types, .scope = scope, }, - }); + }; + + _ = try self.symbol_table.put(lex, symbol); var kv = self.symbol_table.get(lex); self.cur_function = &kv.?.value.Function; @@ -303,20 +309,22 @@ pub const CompilationContext = struct { _ = try ident_map.put(token.lexeme, @intCast(u32, idx)); } - _ = try self.symbol_table.put(enu.name.lexeme, SymbolData{ - .Enum = ident_map, - }); + var symbol = try self.allocator.create(SymbolData); + symbol.* = SymbolData{ .Enum = ident_map }; + _ = try self.symbol_table.put(enu.name.lexeme, symbol); } pub fn insertConst(self: *@This(), constdecl: ast.SingleConst, typ: SymbolUnderlyingType) !void { - _ = try self.symbol_table.put(constdecl.name.lexeme, SymbolData{ .Const = typ }); + var symbol = try self.allocator.create(SymbolData); + symbol.* = SymbolData{ .Const = typ }; + _ = try self.symbol_table.put(constdecl.name.lexeme, symbol); } pub fn fetchGlobalSymbol( self: *@This(), identifier: []const u8, typ: SymbolType, - ) !SymbolData { + ) !*SymbolData { var sym_kv = self.symbol_table.get(identifier); if (sym_kv == null) { std.debug.warn("Unknown {} '{}'\n", typ, identifier); @@ -324,14 +332,14 @@ pub const CompilationContext = struct { } var value = sym_kv.?.value; - var sym_typ = SymbolType(value); + var sym_typ = SymbolType(value.*); if (sym_typ != typ) { std.debug.warn("Expected {}, got {}\n", sym_typ, typ); return CompilationError.TypeError; } - return sym_kv.?.value; + return value; } fn resolveVarTypeInScope(