| ... | ... | @@ -305,11 +305,11 @@ pub const DeclGen = struct { |
| 305 | 305 | |
| 306 | 306 | gpa: *Allocator, |
| 307 | 307 | |
| 308 | | fn fail(self: *DeclGen, src: LazySrcLoc, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 308 | fn todo(self: *DeclGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 309 | 309 | @setCold(true); |
| 310 | 310 | assert(self.err_msg == null); |
| 311 | | const src_loc = src.toSrcLocWithDecl(self.decl); |
| 312 | | self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, format, args); |
| 311 | const src_loc = @as(LazySrcLoc, .{ .node_offset = 0 }).toSrcLocWithDecl(self.decl); |
| 312 | self.err_msg = try Module.ErrorMsg.create(self.gpa, src_loc, "TODO (LLVM): " ++ format, args); |
| 313 | 313 | return error.CodegenFail; |
| 314 | 314 | } |
| 315 | 315 | |
| ... | ... | @@ -325,14 +325,12 @@ pub const DeclGen = struct { |
| 325 | 325 | const decl = self.decl; |
| 326 | 326 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 327 | 327 | |
| 328 | | const src = decl.srcLoc().lazy; |
| 329 | | |
| 330 | 328 | log.debug("gen: {s} type: {}, value: {}", .{ decl.name, typed_value.ty, typed_value.val }); |
| 331 | 329 | |
| 332 | 330 | if (typed_value.val.castTag(.function)) |func_payload| { |
| 333 | 331 | const func = func_payload.data; |
| 334 | 332 | |
| 335 | | const llvm_func = try self.resolveLLVMFunction(func.owner_decl, src); |
| 333 | const llvm_func = try self.resolveLLVMFunction(func.owner_decl); |
| 336 | 334 | |
| 337 | 335 | // This gets the LLVM values from the function and stores them in `self.args`. |
| 338 | 336 | const fn_param_len = func.owner_decl.typed_value.most_recent.typed_value.ty.fnParamLen(); |
| ... | ... | @@ -369,14 +367,14 @@ pub const DeclGen = struct { |
| 369 | 367 | |
| 370 | 368 | try fg.genBody(func.body); |
| 371 | 369 | } else if (typed_value.val.castTag(.extern_fn)) |extern_fn| { |
| 372 | | _ = try self.resolveLLVMFunction(extern_fn.data, src); |
| 370 | _ = try self.resolveLLVMFunction(extern_fn.data); |
| 373 | 371 | } else { |
| 374 | | _ = try self.resolveGlobalDecl(decl, src); |
| 372 | _ = try self.resolveGlobalDecl(decl); |
| 375 | 373 | } |
| 376 | 374 | } |
| 377 | 375 | |
| 378 | 376 | /// If the llvm function does not exist, create it |
| 379 | | fn resolveLLVMFunction(self: *DeclGen, func: *Module.Decl, src: LazySrcLoc) !*const llvm.Value { |
| 377 | fn resolveLLVMFunction(self: *DeclGen, func: *Module.Decl) !*const llvm.Value { |
| 380 | 378 | // TODO: do we want to store this in our own datastructure? |
| 381 | 379 | if (self.llvmModule().getNamedFunction(func.name)) |llvm_fn| return llvm_fn; |
| 382 | 380 | |
| ... | ... | @@ -393,11 +391,11 @@ pub const DeclGen = struct { |
| 393 | 391 | defer self.gpa.free(llvm_param); |
| 394 | 392 | |
| 395 | 393 | for (fn_param_types) |fn_param, i| { |
| 396 | | llvm_param[i] = try self.getLLVMType(fn_param, src); |
| 394 | llvm_param[i] = try self.getLLVMType(fn_param); |
| 397 | 395 | } |
| 398 | 396 | |
| 399 | 397 | const fn_type = llvm.Type.functionType( |
| 400 | | try self.getLLVMType(return_type, src), |
| 398 | try self.getLLVMType(return_type), |
| 401 | 399 | if (fn_param_len == 0) null else llvm_param.ptr, |
| 402 | 400 | @intCast(c_uint, fn_param_len), |
| 403 | 401 | .False, |
| ... | ... | @@ -411,15 +409,15 @@ pub const DeclGen = struct { |
| 411 | 409 | return llvm_fn; |
| 412 | 410 | } |
| 413 | 411 | |
| 414 | | fn resolveGlobalDecl(self: *DeclGen, decl: *Module.Decl, src: LazySrcLoc) error{ OutOfMemory, CodegenFail }!*const llvm.Value { |
| 412 | fn resolveGlobalDecl(self: *DeclGen, decl: *Module.Decl) error{ OutOfMemory, CodegenFail }!*const llvm.Value { |
| 415 | 413 | // TODO: do we want to store this in our own datastructure? |
| 416 | 414 | if (self.llvmModule().getNamedGlobal(decl.name)) |val| return val; |
| 417 | 415 | |
| 418 | 416 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 419 | 417 | |
| 420 | 418 | // TODO: remove this redundant `getLLVMType`, it is also called in `genTypedValue`. |
| 421 | | const llvm_type = try self.getLLVMType(typed_value.ty, src); |
| 422 | | const val = try self.genTypedValue(src, typed_value, null); |
| 419 | const llvm_type = try self.getLLVMType(typed_value.ty); |
| 420 | const val = try self.genTypedValue(typed_value, null); |
| 423 | 421 | const global = self.llvmModule().addGlobal(llvm_type, decl.name); |
| 424 | 422 | llvm.setInitializer(global, val); |
| 425 | 423 | |
| ... | ... | @@ -429,7 +427,7 @@ pub const DeclGen = struct { |
| 429 | 427 | return global; |
| 430 | 428 | } |
| 431 | 429 | |
| 432 | | fn getLLVMType(self: *DeclGen, t: Type, src: LazySrcLoc) error{ OutOfMemory, CodegenFail }!*const llvm.Type { |
| 430 | fn getLLVMType(self: *DeclGen, t: Type) error{ OutOfMemory, CodegenFail }!*const llvm.Type { |
| 433 | 431 | switch (t.zigTypeTag()) { |
| 434 | 432 | .Void => return self.context().voidType(), |
| 435 | 433 | .NoReturn => return self.context().voidType(), |
| ... | ... | @@ -440,14 +438,14 @@ pub const DeclGen = struct { |
| 440 | 438 | .Bool => return self.context().intType(1), |
| 441 | 439 | .Pointer => { |
| 442 | 440 | if (t.isSlice()) { |
| 443 | | return self.fail(src, "TODO: LLVM backend: implement slices", .{}); |
| 441 | return self.todo("implement slices", .{}); |
| 444 | 442 | } else { |
| 445 | | const elem_type = try self.getLLVMType(t.elemType(), src); |
| 443 | const elem_type = try self.getLLVMType(t.elemType()); |
| 446 | 444 | return elem_type.pointerType(0); |
| 447 | 445 | } |
| 448 | 446 | }, |
| 449 | 447 | .Array => { |
| 450 | | const elem_type = try self.getLLVMType(t.elemType(), src); |
| 448 | const elem_type = try self.getLLVMType(t.elemType()); |
| 451 | 449 | return elem_type.arrayType(@intCast(c_uint, t.abiSize(self.module.getTarget()))); |
| 452 | 450 | }, |
| 453 | 451 | .Optional => { |
| ... | ... | @@ -456,21 +454,21 @@ pub const DeclGen = struct { |
| 456 | 454 | const child_type = t.optionalChild(&buf); |
| 457 | 455 | |
| 458 | 456 | var optional_types: [2]*const llvm.Type = .{ |
| 459 | | try self.getLLVMType(child_type, src), |
| 457 | try self.getLLVMType(child_type), |
| 460 | 458 | self.context().intType(1), |
| 461 | 459 | }; |
| 462 | 460 | return self.context().structType(&optional_types, 2, .False); |
| 463 | 461 | } else { |
| 464 | | return self.fail(src, "TODO implement optional pointers as actual pointers", .{}); |
| 462 | return self.todo("implement optional pointers as actual pointers", .{}); |
| 465 | 463 | } |
| 466 | 464 | }, |
| 467 | | else => return self.fail(src, "TODO implement getLLVMType for type '{}'", .{t}), |
| 465 | else => return self.todo("implement getLLVMType for type '{}'", .{t}), |
| 468 | 466 | } |
| 469 | 467 | } |
| 470 | 468 | |
| 471 | 469 | // TODO: figure out a way to remove the FuncGen argument |
| 472 | | fn genTypedValue(self: *DeclGen, src: LazySrcLoc, tv: TypedValue, fg: ?*FuncGen) error{ OutOfMemory, CodegenFail }!*const llvm.Value { |
| 473 | | const llvm_type = try self.getLLVMType(tv.ty, src); |
| 470 | fn genTypedValue(self: *DeclGen, tv: TypedValue, fg: ?*FuncGen) error{ OutOfMemory, CodegenFail }!*const llvm.Value { |
| 471 | const llvm_type = try self.getLLVMType(tv.ty); |
| 474 | 472 | |
| 475 | 473 | if (tv.val.isUndef()) |
| 476 | 474 | return llvm_type.getUndef(); |
| ... | ... | @@ -484,7 +482,7 @@ pub const DeclGen = struct { |
| 484 | 482 | if (bigint.eqZero()) return llvm_type.constNull(); |
| 485 | 483 | |
| 486 | 484 | if (bigint.limbs.len != 1) { |
| 487 | | return self.fail(src, "TODO implement bigger bigint", .{}); |
| 485 | return self.todo("implement bigger bigint", .{}); |
| 488 | 486 | } |
| 489 | 487 | const llvm_int = llvm_type.constInt(bigint.limbs[0], .False); |
| 490 | 488 | if (!bigint.positive) { |
| ... | ... | @@ -495,9 +493,9 @@ pub const DeclGen = struct { |
| 495 | 493 | .Pointer => switch (tv.val.tag()) { |
| 496 | 494 | .decl_ref => { |
| 497 | 495 | const decl = tv.val.castTag(.decl_ref).?.data; |
| 498 | | const val = try self.resolveGlobalDecl(decl, src); |
| 496 | const val = try self.resolveGlobalDecl(decl); |
| 499 | 497 | |
| 500 | | const usize_type = try self.getLLVMType(Type.initTag(.usize), src); |
| 498 | const usize_type = try self.getLLVMType(Type.initTag(.usize)); |
| 501 | 499 | |
| 502 | 500 | // TODO: second index should be the index into the memory! |
| 503 | 501 | var indices: [2]*const llvm.Value = .{ |
| ... | ... | @@ -511,29 +509,29 @@ pub const DeclGen = struct { |
| 511 | 509 | .ref_val => { |
| 512 | 510 | const elem_value = tv.val.castTag(.ref_val).?.data; |
| 513 | 511 | const elem_type = tv.ty.castPointer().?.data; |
| 514 | | const alloca = fg.?.buildAlloca(try self.getLLVMType(elem_type, src)); |
| 515 | | _ = fg.?.builder.buildStore(try self.genTypedValue(src, .{ .ty = elem_type, .val = elem_value }, fg), alloca); |
| 512 | const alloca = fg.?.buildAlloca(try self.getLLVMType(elem_type)); |
| 513 | _ = fg.?.builder.buildStore(try self.genTypedValue(.{ .ty = elem_type, .val = elem_value }, fg), alloca); |
| 516 | 514 | return alloca; |
| 517 | 515 | }, |
| 518 | | else => return self.fail(src, "TODO implement const of pointer type '{}'", .{tv.ty}), |
| 516 | else => return self.todo("implement const of pointer type '{}'", .{tv.ty}), |
| 519 | 517 | }, |
| 520 | 518 | .Array => { |
| 521 | 519 | if (tv.val.castTag(.bytes)) |payload| { |
| 522 | 520 | const zero_sentinel = if (tv.ty.sentinel()) |sentinel| blk: { |
| 523 | 521 | if (sentinel.tag() == .zero) break :blk true; |
| 524 | | return self.fail(src, "TODO handle other sentinel values", .{}); |
| 522 | return self.todo("handle other sentinel values", .{}); |
| 525 | 523 | } else false; |
| 526 | 524 | |
| 527 | 525 | return self.context().constString(payload.data.ptr, @intCast(c_uint, payload.data.len), llvm.Bool.fromBool(!zero_sentinel)); |
| 528 | 526 | } else { |
| 529 | | return self.fail(src, "TODO handle more array values", .{}); |
| 527 | return self.todo("handle more array values", .{}); |
| 530 | 528 | } |
| 531 | 529 | }, |
| 532 | 530 | .Optional => { |
| 533 | 531 | if (!tv.ty.isPtrLikeOptional()) { |
| 534 | 532 | var buf: Type.Payload.ElemType = undefined; |
| 535 | 533 | const child_type = tv.ty.optionalChild(&buf); |
| 536 | | const llvm_child_type = try self.getLLVMType(child_type, src); |
| 534 | const llvm_child_type = try self.getLLVMType(child_type); |
| 537 | 535 | |
| 538 | 536 | if (tv.val.tag() == .null_value) { |
| 539 | 537 | var optional_values: [2]*const llvm.Value = .{ |
| ... | ... | @@ -543,16 +541,16 @@ pub const DeclGen = struct { |
| 543 | 541 | return self.context().constStruct(&optional_values, 2, .False); |
| 544 | 542 | } else { |
| 545 | 543 | var optional_values: [2]*const llvm.Value = .{ |
| 546 | | try self.genTypedValue(src, .{ .ty = child_type, .val = tv.val }, fg), |
| 544 | try self.genTypedValue(.{ .ty = child_type, .val = tv.val }, fg), |
| 547 | 545 | self.context().intType(1).constAllOnes(), |
| 548 | 546 | }; |
| 549 | 547 | return self.context().constStruct(&optional_values, 2, .False); |
| 550 | 548 | } |
| 551 | 549 | } else { |
| 552 | | return self.fail(src, "TODO implement const of optional pointer", .{}); |
| 550 | return self.todo("implement const of optional pointer", .{}); |
| 553 | 551 | } |
| 554 | 552 | }, |
| 555 | | else => return self.fail(src, "TODO implement const of type '{}'", .{tv.ty}), |
| 553 | else => return self.todo("implement const of type '{}'", .{tv.ty}), |
| 556 | 554 | } |
| 557 | 555 | } |
| 558 | 556 | |
| ... | ... | @@ -609,9 +607,9 @@ pub const FuncGen = struct { |
| 609 | 607 | self.blocks.deinit(self.gpa()); |
| 610 | 608 | } |
| 611 | 609 | |
| 612 | | fn fail(self: *FuncGen, src: LazySrcLoc, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 610 | fn todo(self: *FuncGen, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } { |
| 613 | 611 | @setCold(true); |
| 614 | | return self.dg.fail(src, format, args); |
| 612 | return self.dg.todo(format, args); |
| 615 | 613 | } |
| 616 | 614 | |
| 617 | 615 | fn llvmModule(self: *FuncGen) *const llvm.Module { |
| ... | ... | @@ -628,11 +626,11 @@ pub const FuncGen = struct { |
| 628 | 626 | |
| 629 | 627 | fn resolveInst(self: *FuncGen, inst: *ir.Inst) !*const llvm.Value { |
| 630 | 628 | if (inst.value()) |val| { |
| 631 | | return self.dg.genTypedValue(inst.src, .{ .ty = inst.ty, .val = val }, self); |
| 629 | return self.dg.genTypedValue(.{ .ty = inst.ty, .val = val }, self); |
| 632 | 630 | } |
| 633 | 631 | if (self.func_inst_table.get(inst)) |value| return value; |
| 634 | 632 | |
| 635 | | return self.fail(inst.src, "TODO implement global llvm values (or the value is not in the func_inst_table table)", .{}); |
| 633 | return self.todo("implement global llvm values (or the value is not in the func_inst_table table)", .{}); |
| 636 | 634 | } |
| 637 | 635 | |
| 638 | 636 | fn genBody(self: *FuncGen, body: ir.Body) error{ OutOfMemory, CodegenFail }!void { |
| ... | ... | @@ -673,7 +671,7 @@ pub const FuncGen = struct { |
| 673 | 671 | // TODO: implement debug info |
| 674 | 672 | break :blk null; |
| 675 | 673 | }, |
| 676 | | else => |tag| return self.fail(inst.src, "TODO implement LLVM codegen for Zir instruction: {}", .{tag}), |
| 674 | else => |tag| return self.todo("implement TZIR instruction: {}", .{tag}), |
| 677 | 675 | }; |
| 678 | 676 | if (opt_value) |val| try self.func_inst_table.putNoClobber(self.gpa(), inst, val); |
| 679 | 677 | } |
| ... | ... | @@ -689,7 +687,7 @@ pub const FuncGen = struct { |
| 689 | 687 | unreachable; |
| 690 | 688 | |
| 691 | 689 | const zig_fn_type = fn_decl.typed_value.most_recent.typed_value.ty; |
| 692 | | const llvm_fn = try self.dg.resolveLLVMFunction(fn_decl, inst.base.src); |
| 690 | const llvm_fn = try self.dg.resolveLLVMFunction(fn_decl); |
| 693 | 691 | |
| 694 | 692 | const num_args = inst.args.len; |
| 695 | 693 | |
| ... | ... | @@ -719,7 +717,7 @@ pub const FuncGen = struct { |
| 719 | 717 | |
| 720 | 718 | return call; |
| 721 | 719 | } else { |
| 722 | | return self.fail(inst.base.src, "TODO implement calling runtime known function pointer LLVM backend", .{}); |
| 720 | return self.todo("implement calling runtime known function pointer", .{}); |
| 723 | 721 | } |
| 724 | 722 | } |
| 725 | 723 | |
| ... | ... | @@ -739,7 +737,7 @@ pub const FuncGen = struct { |
| 739 | 737 | |
| 740 | 738 | if (!inst.base.ty.isInt()) |
| 741 | 739 | if (inst.base.ty.tag() != .bool) |
| 742 | | return self.fail(inst.base.src, "TODO implement 'genCmp' for type {}", .{inst.base.ty}); |
| 740 | return self.todo("implement 'genCmp' for type {}", .{inst.base.ty}); |
| 743 | 741 | |
| 744 | 742 | const is_signed = inst.base.ty.isSignedInt(); |
| 745 | 743 | const operation = switch (op) { |
| ... | ... | @@ -779,7 +777,7 @@ pub const FuncGen = struct { |
| 779 | 777 | // If the block does not return a value, we dont have to create a phi node. |
| 780 | 778 | if (!inst.base.ty.hasCodeGenBits()) return null; |
| 781 | 779 | |
| 782 | | const phi_node = self.builder.buildPhi(try self.dg.getLLVMType(inst.base.ty, inst.base.src), ""); |
| 780 | const phi_node = self.builder.buildPhi(try self.dg.getLLVMType(inst.base.ty), ""); |
| 783 | 781 | phi_node.addIncoming( |
| 784 | 782 | break_vals.items.ptr, |
| 785 | 783 | break_bbs.items.ptr, |
| ... | ... | @@ -897,7 +895,7 @@ pub const FuncGen = struct { |
| 897 | 895 | const rhs = try self.resolveInst(inst.rhs); |
| 898 | 896 | |
| 899 | 897 | if (!inst.base.ty.isInt()) |
| 900 | | return self.fail(inst.base.src, "TODO implement 'genAdd' for type {}", .{inst.base.ty}); |
| 898 | return self.todo("implement 'genAdd' for type {}", .{inst.base.ty}); |
| 901 | 899 | |
| 902 | 900 | return if (inst.base.ty.isSignedInt()) |
| 903 | 901 | self.builder.buildNSWAdd(lhs, rhs, "") |
| ... | ... | @@ -910,7 +908,7 @@ pub const FuncGen = struct { |
| 910 | 908 | const rhs = try self.resolveInst(inst.rhs); |
| 911 | 909 | |
| 912 | 910 | if (!inst.base.ty.isInt()) |
| 913 | | return self.fail(inst.base.src, "TODO implement 'genSub' for type {}", .{inst.base.ty}); |
| 911 | return self.todo("implement 'genSub' for type {}", .{inst.base.ty}); |
| 914 | 912 | |
| 915 | 913 | return if (inst.base.ty.isSignedInt()) |
| 916 | 914 | self.builder.buildNSWSub(lhs, rhs, "") |
| ... | ... | @@ -924,12 +922,12 @@ pub const FuncGen = struct { |
| 924 | 922 | const signed = inst.base.ty.isSignedInt(); |
| 925 | 923 | // TODO: Should we use intcast here or just a simple bitcast? |
| 926 | 924 | // LLVM does truncation vs bitcast (+signed extension) in the intcast depending on the sizes |
| 927 | | return self.builder.buildIntCast2(val, try self.dg.getLLVMType(inst.base.ty, inst.base.src), llvm.Bool.fromBool(signed), ""); |
| 925 | return self.builder.buildIntCast2(val, try self.dg.getLLVMType(inst.base.ty), llvm.Bool.fromBool(signed), ""); |
| 928 | 926 | } |
| 929 | 927 | |
| 930 | 928 | fn genBitCast(self: *FuncGen, inst: *Inst.UnOp) !?*const llvm.Value { |
| 931 | 929 | const val = try self.resolveInst(inst.operand); |
| 932 | | const dest_type = try self.dg.getLLVMType(inst.base.ty, inst.base.src); |
| 930 | const dest_type = try self.dg.getLLVMType(inst.base.ty); |
| 933 | 931 | |
| 934 | 932 | return self.builder.buildBitCast(val, dest_type, ""); |
| 935 | 933 | } |
| ... | ... | @@ -938,7 +936,7 @@ pub const FuncGen = struct { |
| 938 | 936 | const arg_val = self.args[self.arg_index]; |
| 939 | 937 | self.arg_index += 1; |
| 940 | 938 | |
| 941 | | const ptr_val = self.buildAlloca(try self.dg.getLLVMType(inst.base.ty, inst.base.src)); |
| 939 | const ptr_val = self.buildAlloca(try self.dg.getLLVMType(inst.base.ty)); |
| 942 | 940 | _ = self.builder.buildStore(arg_val, ptr_val); |
| 943 | 941 | return self.builder.buildLoad(ptr_val, ""); |
| 944 | 942 | } |
| ... | ... | @@ -950,7 +948,7 @@ pub const FuncGen = struct { |
| 950 | 948 | |
| 951 | 949 | // TODO: figure out a way to get the name of the var decl. |
| 952 | 950 | // TODO: set alignment and volatile |
| 953 | | return self.buildAlloca(try self.dg.getLLVMType(pointee_type, inst.base.src)); |
| 951 | return self.buildAlloca(try self.dg.getLLVMType(pointee_type)); |
| 954 | 952 | } |
| 955 | 953 | |
| 956 | 954 | /// Use this instead of builder.buildAlloca, because this function makes sure to |