aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.zig
diff options
context:
space:
mode:
authorTimon Kruiper <timonkruiper@gmail.com>2020-12-29 20:39:58 +0100
committerTimon Kruiper <timonkruiper@gmail.com>2021-01-03 17:23:30 +0100
commitda545d6a3195c1cafca498d8a695082982f74676 (patch)
treec85dc18ef61eee7982c98ddd80c81223a25f69db /src/llvm_backend.zig
parent47a4d43e41b07b939b840fbf8230b89e27694093 (diff)
downloadzig-da545d6a3195c1cafca498d8a695082982f74676.tar.gz
zig-da545d6a3195c1cafca498d8a695082982f74676.zip
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; } ```
Diffstat (limited to 'src/llvm_backend.zig')
-rw-r--r--src/llvm_backend.zig34
1 files changed, 32 insertions, 2 deletions
diff --git a/src/llvm_backend.zig b/src/llvm_backend.zig
index d56233a503..dbfe182eed 100644
--- a/src/llvm_backend.zig
+++ b/src/llvm_backend.zig
@@ -150,6 +150,10 @@ pub const LLVMIRModule = struct {
/// referred to in other instructions. This table is cleared before every function is generated.
func_inst_table: std.AutoHashMapUnmanaged(*Inst, *const llvm.ValueRef) = .{},
+ /// These fields are used to refer to the LLVM value of the function paramaters in an Arg instruction.
+ args: []*const llvm.ValueRef = &[_]*const llvm.ValueRef{},
+ arg_index: usize = 0,
+
pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*LLVMIRModule {
const self = try allocator.create(LLVMIRModule);
errdefer allocator.destroy(self);
@@ -289,6 +293,17 @@ pub const LLVMIRModule = struct {
const llvm_func = try self.resolveLLVMFunction(func, src);
+ // This gets the LLVM values from the function and stores them in `self.args`.
+ const fn_param_len = func.owner_decl.typed_value.most_recent.typed_value.ty.fnParamLen();
+ var args = try self.gpa.alloc(*const llvm.ValueRef, fn_param_len);
+ defer self.gpa.free(args);
+
+ for (args) |*arg, i| {
+ arg.* = llvm.getParam(llvm_func, @intCast(c_uint, i));
+ }
+ self.args = args;
+ self.arg_index = 0;
+
// Make sure no other LLVM values from other functions can be referenced
self.func_inst_table.clearRetainingCapacity();
@@ -313,6 +328,8 @@ pub const LLVMIRModule = struct {
.alloc => try self.genAlloc(inst.castTag(.alloc).?),
.store => try self.genStore(inst.castTag(.store).?),
.load => try self.genLoad(inst.castTag(.load).?),
+ .ret => try self.genRet(inst.castTag(.ret).?),
+ .not => try self.genNot(inst.castTag(.not).?),
.dbg_stmt => blk: {
// TODO: implement debug info
break :blk null;
@@ -370,14 +387,27 @@ pub const LLVMIRModule = struct {
return null;
}
+ fn genRet(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.ValueRef {
+ _ = self.builder.buildRet(try self.resolveInst(inst.operand));
+ return null;
+ }
+
+ fn genNot(self: *LLVMIRModule, inst: *Inst.UnOp) !?*const llvm.ValueRef {
+ return self.builder.buildNot(try self.resolveInst(inst.operand), "");
+ }
+
fn genUnreach(self: *LLVMIRModule, inst: *Inst.NoOp) ?*const llvm.ValueRef {
_ = self.builder.buildUnreachable();
return null;
}
fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) !?*const llvm.ValueRef {
- // TODO: implement this
- return null;
+ const arg_val = self.args[self.arg_index];
+ self.arg_index += 1;
+
+ const ptr_val = self.builder.buildAlloca(try self.getLLVMType(inst.base.ty, inst.base.src), "");
+ _ = self.builder.buildStore(arg_val, ptr_val);
+ return self.builder.buildLoad(ptr_val, "");
}
fn genAlloc(self: *LLVMIRModule, inst: *Inst.NoOp) !?*const llvm.ValueRef {