authorgravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2020-12-24 16:52:14+01:00
committergravatar for timonkruiper@gmail.comTimon Kruiper <timonkruiper@gmail.com> 2020-12-28 21:20:49+01:00
logec3aedffb173845b3fe6f7559e06e1bc3cfde6f7
tree8826f40cd08a1cbe945e82bc3f2495a0ed42ad7d
parent4a32d4f288737a0d67484c1f05817ec468ec41f1

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; } ```

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

src/llvm_backend.zig+38-2
...@@ -301,6 +301,7 @@ pub const LLVMIRModule = struct {...@@ -301,6 +301,7 @@ pub const LLVMIRModule = struct {
301 .call => try self.genCall(inst.castTag(.call).?),301 .call => try self.genCall(inst.castTag(.call).?),
302 .unreach => self.genUnreach(inst.castTag(.unreach).?),302 .unreach => self.genUnreach(inst.castTag(.unreach).?),
303 .retvoid => self.genRetVoid(inst.castTag(.retvoid).?),303 .retvoid => self.genRetVoid(inst.castTag(.retvoid).?),
304 .arg => self.genArg(inst.castTag(.arg).?),
304 .dbg_stmt => {305 .dbg_stmt => {
305 // TODO: implement debug info306 // TODO: implement debug info
306 },307 },
...@@ -319,11 +320,23 @@ pub const LLVMIRModule = struct {...@@ -319,11 +320,23 @@ pub const LLVMIRModule = struct {
319 const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;320 const zig_fn_type = func.owner_decl.typed_value.most_recent.typed_value.ty;
320 const llvm_fn = try self.resolveLLVMFunction(func);321 const llvm_fn = try self.resolveLLVMFunction(func);
321322
322 // TODO: handle more arguments, inst.args323 const num_args = inst.args.len;
324
325 const llvm_param_vals = try self.gpa.alloc(*const llvm.ValueRef, num_args);
326 defer self.gpa.free(llvm_param_vals);
327
328 for (inst.args) |arg, i| {
329 llvm_param_vals[i] = try self.resolveInst(arg);
330 }
323331
324 // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs332 // TODO: LLVMBuildCall2 handles opaque function pointers, according to llvm docs
325 // Do we need that?333 // Do we need that?
326 const call = self.builder.buildCall(llvm_fn, null, 0, "");334 const call = self.builder.buildCall(
335 llvm_fn,
336 if (num_args == 0) null else llvm_param_vals.ptr,
337 @intCast(c_uint, num_args),
338 "",
339 );
327340
328 if (zig_fn_type.fnReturnType().zigTypeTag() == .NoReturn) {341 if (zig_fn_type.fnReturnType().zigTypeTag() == .NoReturn) {
329 _ = self.builder.buildUnreachable();342 _ = self.builder.buildUnreachable();
...@@ -340,6 +353,10 @@ pub const LLVMIRModule = struct {...@@ -340,6 +353,10 @@ pub const LLVMIRModule = struct {
340 _ = self.builder.buildUnreachable();353 _ = self.builder.buildUnreachable();
341 }354 }
342355
356 fn genArg(self: *LLVMIRModule, inst: *Inst.Arg) void {
357 // TODO: implement this
358 }
359
343 fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !void {360 fn genBreakpoint(self: *LLVMIRModule, inst: *Inst.NoOp) !void {
344 // TODO: Store this function somewhere such that we dont have to add it again361 // TODO: Store this function somewhere such that we dont have to add it again
345 const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false);362 const fn_type = llvm.TypeRef.functionType(llvm.voidType(), null, 0, false);
...@@ -348,6 +365,25 @@ pub const LLVMIRModule = struct {...@@ -348,6 +365,25 @@ pub const LLVMIRModule = struct {
348 _ = self.builder.buildCall(func, null, 0, "");365 _ = self.builder.buildCall(func, null, 0, "");
349 }366 }
350367
368 fn resolveInst(self: *LLVMIRModule, inst: *ir.Inst) !*const llvm.ValueRef {
369 if (inst.castTag(.constant)) |const_inst| {
370 return self.genTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val });
371 }
372 return self.fail(inst.src, "TODO implement resolveInst", .{});
373 }
374
375 fn genTypedValue(self: *LLVMIRModule, src: usize, typed_value: TypedValue) !*const llvm.ValueRef {
376 const llvm_type = self.getLLVMType(typed_value.ty);
377
378 if (typed_value.val.isUndef())
379 return llvm_type.getUndef();
380
381 switch (typed_value.ty.zigTypeTag()) {
382 .Bool => return if (typed_value.val.toBool()) llvm_type.constAllOnes() else llvm_type.constNull(),
383 else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),
384 }
385 }
386
351 /// If the llvm function does not exist, create it387 /// If the llvm function does not exist, create it
352 fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Fn) !*const llvm.ValueRef {388 fn resolveLLVMFunction(self: *LLVMIRModule, func: *Module.Fn) !*const llvm.ValueRef {
353 // TODO: do we want to store this in our own datastructure?389 // TODO: do we want to store this in our own datastructure?
src/llvm_bindings.zig+9
...@@ -36,6 +36,15 @@ pub const ValueRef = opaque {...@@ -36,6 +36,15 @@ pub const ValueRef = opaque {
36pub const TypeRef = opaque {36pub const TypeRef = opaque {
37 pub const functionType = LLVMFunctionType;37 pub const functionType = LLVMFunctionType;
38 extern fn LLVMFunctionType(ReturnType: *const TypeRef, ParamTypes: ?[*]*const TypeRef, ParamCount: c_uint, IsVarArg: LLVMBool) *const TypeRef;38 extern fn LLVMFunctionType(ReturnType: *const TypeRef, ParamTypes: ?[*]*const TypeRef, ParamCount: c_uint, IsVarArg: LLVMBool) *const TypeRef;
39
40 pub const constNull = LLVMConstNull;
41 extern fn LLVMConstNull(Ty: *const TypeRef) *const ValueRef;
42
43 pub const constAllOnes = LLVMConstAllOnes;
44 extern fn LLVMConstAllOnes(Ty: *const TypeRef) *const ValueRef;
45
46 pub const getUndef = LLVMGetUndef;
47 extern fn LLVMGetUndef(Ty: *const TypeRef) *const ValueRef;
39};48};
4049
41pub const ModuleRef = opaque {50pub const ModuleRef = opaque {