authorgravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2020-12-29 20:39:58+01:00
committergravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2021-01-03 17:23:30+01:00
logda545d6a3195c1cafca498d8a695082982f74676
treec85dc18ef61eee7982c98ddd80c81223a25f69db
parent47a4d43e41b07b939b840fbf8230b89e27694093

stage2: implement argument passing and returning in LLVM backend

Furthermore add the Not instruction. The following now works: ``` export fn _start() noreturn { var x: bool = true; var other: bool = foo(x); exit(); } fn foo(cond: bool) bool { return !cond; } fn exit() noreturn { unreachable; } ```

2 files changed, 41 insertions(+), 2 deletions(-)

src/llvm_backend.zig+32-2
...@@ -150,6 +150,10 @@ pub const LLVMIRModule = struct {...@@ -150,6 +150,10 @@ pub const LLVMIRModule = struct {
150 /// referred to in other instructions. This table is cleared before every function is generated.150 /// referred to in other instructions. This table is cleared before every function is generated.
151 func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.ValueRef) = .{},151 func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.ValueRef) = .{},
152152
153 /// These fields are used to refer to the LLVM value of the function paramaters in an Arg instruction.
154 args: []*const llvm.ValueRef = &[_]*const llvm.ValueRef{},
155 arg_index: usize = 0,
156
153 pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule {157 pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule {
154 const self = try allocator.create(LLVMIRModule);158 const self = try allocator.create(LLVMIRModule);
155 errdefer allocator.destroy(self);159 errdefer allocator.destroy(self);
...@@ -289,6 +293,17 @@ pub const LLVMIRModule = struct {...@@ -289,6 +293,17 @@ pub const LLVMIRModule = struct {
289293
290 const llvm_func = try self.resolveLLVMFunction(func, src);294 const llvm_func = try self.resolveLLVMFunction(func, src);
291295
296 // This gets the LLVM values from the function and stores them in `self.args`.
297 const fn_param_len = func.owner_decl.typed_value.most_recent.typed_value.ty.fnParamLen();
298 var args = try self.gpa.alloc(*const llvm.ValueRef, fn_param_len);
299 defer self.gpa.free(args);
300
301 for (args) |*arg, i| {
302 arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i));
303 }
304 self.args = args;
305 self.arg_index = 0;
306
292 // Make sure no other LLVM values from other functions can be referenced307 // Make sure no other LLVM values from other functions can be referenced
293 self.func_inst_table.clearRetainingCapacity();308 self.func_inst_table.clearRetainingCapacity();
294309
...@@ -313,6 +328,8 @@ pub const LLVMIRModule = struct {...@@ -313,6 +328,8 @@ pub const LLVMIRModule = struct {
313 .alloc => try self.genAlloc(inst.castTag(.alloc).?),328 .alloc => try self.genAlloc(inst.castTag(.alloc).?),
314 .store => try self.genStore(inst.castTag(.store).?),329 .store => try self.genStore(inst.castTag(.store).?),
315 .load => try self.genLoad(inst.castTag(.load).?),330 .load => try self.genLoad(inst.castTag(.load).?),
331 .ret => try self.genRet(inst.castTag(.ret).?),
332 .not => try self.genNot(inst.castTag(.not).?),
316 .dbg_stmt => blk: {333 .dbg_stmt => blk: {
317 // TODO: implement debug info334 // TODO: implement debug info
318 break :blk null;335 break :blk null;
...@@ -370,14 +387,27 @@ pub const LLVMIRModule = struct {...@@ -370,14 +387,27 @@ pub const LLVMIRModule = struct {
370 return null;387 return null;
371 }388 }
372389
390 fn genRet(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.ValueRef {
391 _ = self.builder.buildRet(try self.resolveInst(inst.operand));
392 return null;
393 }
394
395 fn genNot(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.ValueRef {
396 return self.builder.buildNot(try self.resolveInst(inst.operand), "");
397 }
398
373 fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.ValueRef {399 fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.ValueRef {
374 _ = self.builder.buildUnreachable();400 _ = self.builder.buildUnreachable();
375 return null;401 return null;
376 }402 }
377403
378 fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) !?*const llvm.ValueRef {404 fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) !?*const llvm.ValueRef {
379 // TODO: implement this405 const arg_val = self.args[self.arg_index];
380 return null;406 self.arg_index += 1;
407
408 const ptr_val = self.builder.buildAlloca(try self.getLLVMType(inst.base.ty, inst.base.src), "");
409 _ = self.builder.buildStore(arg_val, ptr_val);
410 return self.builder.buildLoad(ptr_val, "");
381 }411 }
382412
383 fn genAlloc(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.ValueRef {413 fn genAlloc(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.ValueRef {
src/llvm_bindings.zig+9
...@@ -79,6 +79,9 @@ pub const VerifierFailureAction = extern enum {...@@ -79,6 +79,9 @@ pub const VerifierFailureAction = extern enum {
79pub const voidType = LLVMVoidType;79pub const voidType = LLVMVoidType;
80extern fn LLVMVoidType() *const TypeRef;80extern fn LLVMVoidType() *const TypeRef;
8181
82pub const getParam = LLVMGetParam;
83extern fn LLVMGetParam(Fn: *const ValueRef, Index: c_uint) *const ValueRef;
84
82pub const getEnumAttributeKindForName = LLVMGetEnumAttributeKindForName;85pub const getEnumAttributeKindForName = LLVMGetEnumAttributeKindForName;
83extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint;86extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint;
8487
...@@ -117,6 +120,9 @@ pub const BuilderRef = opaque {...@@ -117,6 +120,9 @@ pub const BuilderRef = opaque {
117 pub const buildRetVoid = LLVMBuildRetVoid;120 pub const buildRetVoid = LLVMBuildRetVoid;
118 extern fn LLVMBuildRetVoid(*const BuilderRef) *const ValueRef;121 extern fn LLVMBuildRetVoid(*const BuilderRef) *const ValueRef;
119122
123 pub const buildRet = LLVMBuildRet;
124 extern fn LLVMBuildRet(*const BuilderRef, V: *const ValueRef) *const ValueRef;
125
120 pub const buildUnreachable = LLVMBuildUnreachable;126 pub const buildUnreachable = LLVMBuildUnreachable;
121 extern fn LLVMBuildUnreachable(*const BuilderRef) *const ValueRef;127 extern fn LLVMBuildUnreachable(*const BuilderRef) *const ValueRef;
122128
...@@ -128,6 +134,9 @@ pub const BuilderRef = opaque {...@@ -128,6 +134,9 @@ pub const BuilderRef = opaque {
128134
129 pub const buildLoad = LLVMBuildLoad;135 pub const buildLoad = LLVMBuildLoad;
130 extern fn LLVMBuildLoad(*const BuilderRef, PointerVal: *const ValueRef, Name: [*:0]const u8) *const ValueRef;136 extern fn LLVMBuildLoad(*const BuilderRef, PointerVal: *const ValueRef, Name: [*:0]const u8) *const ValueRef;
137
138 pub const buildNot = LLVMBuildNot;
139 extern fn LLVMBuildNot(*const BuilderRef, V: *const ValueRef, Name: [*:0]const u8) *const ValueRef;
131};140};
132141
133pub const BasicBlockRef = opaque {142pub const BasicBlockRef = opaque {