Commit ec3aedffb1

Timon Kruiper <timonkruiper@gmail.com>
2020-12-24 16:52:14
stage2: add initial implementation of func arguments in LLVM backend
The following works: ``` export fn _start() noreturn { assert(true); exit(); } fn assert(cond: bool) void {} fn exit() noreturn { unreachable; } ```
1 parent 4a32d4f
src/llvm_backend.zig
@@ -301,6 +301,7 @@ pub const LLVMIRModule = struct {
                         .call => try self.genCall(inst.castTag(.call).?),
                         .unreach => self.genUnreach(inst.castTag(.unreach).?),
                         .retvoid => self.genRetVoid(inst.castTag(.retvoid).?),
+                        .arg => self.genArg(inst.castTag(.arg).?),
                         .dbg_stmt => {
                             // TODO: implement debug info
                         },
@@ -319,11 +320,23 @@ pub const LLVMIRModule = struct {
                 const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;
                 const llvm_fn = try self.resolveLLVMFunction(func);
 
-                // TODO: handle more arguments, inst.args
+                const num_args = inst.args.len;
+
+                const llvm_param_vals = try self.gpa.alloc(*const llvm.ValueRef, num_args);
+                defer self.gpa.free(llvm_param_vals);
+
+                for (inst.args) |arg, i| {
+                    llvm_param_vals[i] = try self.resolveInst(arg);
+                }
 
                 // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs
                 //       Do we need that?
-                const call = self.builder.buildCall(llvm_fn, null, 0, "");
+                const call = self.builder.buildCall(
+                    llvm_fn,
+                    if (num_args == 0) null else llvm_param_vals.ptr,
+                    @intCast(c_uint, num_args),
+                    "",
+                );
 
                 if (zig_fn_type.fnReturnType().zigTypeTag() == .NoReturn) {
                     _ = self.builder.buildUnreachable();
@@ -340,6 +353,10 @@ pub const LLVMIRModule = struct {
         _ = self.builder.buildUnreachable();
     }
 
+    fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) void {
+        // TODO: implement this
+    }
+
     fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !void {
         // TODO: Store this function somewhere such that we dont have to add it again
         const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false);
@@ -348,6 +365,25 @@ pub const LLVMIRModule = struct {
         _ = self.builder.buildCall(func, null, 0, "");
     }
 
+    fn resolveInst(self: *LLVMIRModule, inst: *ir.Inst) !*const llvm.ValueRef {
+        if (inst.castTag(.constant)) |const_inst| {
+            return self.genTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val });
+        }
+        return self.fail(inst.src, "TODO implement resolveInst", .{});
+    }
+
+    fn genTypedValue(self: *LLVMIRModule, src: usize, typed_value: TypedValue) !*const llvm.ValueRef {
+        const llvm_type = self.getLLVMType(typed_value.ty);
+
+        if (typed_value.val.isUndef())
+            return llvm_type.getUndef();
+
+        switch (typed_value.ty.zigTypeTag()) {
+            .Bool => return if (typed_value.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(),
+            else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),
+        }
+    }
+
     /// If the llvm function does not exist, create it
     fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Fn) !*const llvm.ValueRef {
         // TODO: do we want to store this in our own datastructure?
src/llvm_bindings.zig
@@ -36,6 +36,15 @@ pub const ValueRef = opaque {
 pub const TypeRef = opaque {
     pub const functionType = LLVMFunctionType;
     extern fn LLVMFunctionType(ReturnType: *const TypeRef, ParamTypes: ?[*]*const TypeRef, ParamCount: c_uint, IsVarArg: LLVMBool) *const TypeRef;
+
+    pub const constNull = LLVMConstNull;
+    extern fn LLVMConstNull(Ty: *const TypeRef) *const ValueRef;
+
+    pub const constAllOnes = LLVMConstAllOnes;
+    extern fn LLVMConstAllOnes(Ty: *const TypeRef) *const ValueRef;
+
+    pub const getUndef = LLVMGetUndef;
+    extern fn LLVMGetUndef(Ty: *const TypeRef) *const ValueRef;
 };
 
 pub const ModuleRef = opaque {