| author | |
| committer | |
| log | c746cbc686c46904a5d381725079a69e38b201cd |
| tree | 46dbe180dd40e9cf8dfea6fae933e6f011b4b3ee |
| parent | 6be5946ed8026f2a7ae990aced9572f229acecf4 |
13 files changed, 323 insertions(+), 247 deletions(-)
src/arch/aarch64/CodeGen.zig+1-5| ... | ... | @@ -41,11 +41,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 41 | 41 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 42 | 42 | const gp = abi.RegisterClass.gp; |
| 43 | 43 | |
| 44 | const InnerError = error{ | |
| 45 | OutOfMemory, | |
| 46 | CodegenFail, | |
| 47 | OutOfRegisters, | |
| 48 | }; | |
| 44 | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; | |
| 49 | 45 | |
| 50 | 46 | gpa: Allocator, |
| 51 | 47 | air: Air, |
src/arch/arm/CodeGen.zig+1-5| ... | ... | @@ -42,11 +42,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs; |
| 42 | 42 | const c_abi_int_return_regs = abi.c_abi_int_return_regs; |
| 43 | 43 | const gp = abi.RegisterClass.gp; |
| 44 | 44 | |
| 45 | const InnerError = error{ | |
| 46 | OutOfMemory, | |
| 47 | CodegenFail, | |
| 48 | OutOfRegisters, | |
| 49 | }; | |
| 45 | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; | |
| 50 | 46 | |
| 51 | 47 | gpa: Allocator, |
| 52 | 48 | air: Air, |
src/arch/riscv64/CodeGen.zig+5-9| ... | ... | @@ -21,10 +21,10 @@ const DW = std.dwarf; |
| 21 | 21 | const leb128 = std.leb; |
| 22 | 22 | const log = std.log.scoped(.codegen); |
| 23 | 23 | const build_options = @import("build_options"); |
| 24 | const codegen = @import("../../codegen.zig"); | |
| 24 | 25 | |
| 25 | const Result = @import("../../codegen.zig").Result; | |
| 26 | const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError; | |
| 27 | const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput; | |
| 26 | const Result = codegen.Result; | |
| 27 | const DebugInfoOutput = codegen.DebugInfoOutput; | |
| 28 | 28 | |
| 29 | 29 | const bits = @import("bits.zig"); |
| 30 | 30 | const abi = @import("abi.zig"); |
| ... | ... | @@ -35,11 +35,7 @@ const Instruction = abi.Instruction; |
| 35 | 35 | const callee_preserved_regs = abi.callee_preserved_regs; |
| 36 | 36 | const gp = abi.RegisterClass.gp; |
| 37 | 37 | |
| 38 | const InnerError = error{ | |
| 39 | OutOfMemory, | |
| 40 | CodegenFail, | |
| 41 | OutOfRegisters, | |
| 42 | }; | |
| 38 | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; | |
| 43 | 39 | |
| 44 | 40 | gpa: Allocator, |
| 45 | 41 | air: Air, |
| ... | ... | @@ -225,7 +221,7 @@ pub fn generate( |
| 225 | 221 | liveness: Liveness, |
| 226 | 222 | code: *std.ArrayList(u8), |
| 227 | 223 | debug_output: DebugInfoOutput, |
| 228 | ) GenerateSymbolError!Result { | |
| 224 | ) codegen.CodeGenError!Result { | |
| 229 | 225 | if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) { |
| 230 | 226 | @panic("Attempted to compile for architecture that was disabled by build configuration"); |
| 231 | 227 | } |
src/arch/sparc64/CodeGen.zig+1-5| ... | ... | @@ -38,11 +38,7 @@ const gp = abi.RegisterClass.gp; |
| 38 | 38 | |
| 39 | 39 | const Self = @This(); |
| 40 | 40 | |
| 41 | const InnerError = error{ | |
| 42 | OutOfMemory, | |
| 43 | CodegenFail, | |
| 44 | OutOfRegisters, | |
| 45 | }; | |
| 41 | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; | |
| 46 | 42 | |
| 47 | 43 | const RegisterView = enum(u1) { |
| 48 | 44 | caller, |
src/arch/wasm/CodeGen.zig-2| ... | ... | @@ -733,8 +733,6 @@ const InnerError = error{ |
| 733 | 733 | OutOfMemory, |
| 734 | 734 | /// An error occurred when trying to lower AIR to MIR. |
| 735 | 735 | CodegenFail, |
| 736 | /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed | |
| 737 | AnalysisFail, | |
| 738 | 736 | /// Compiler implementation could not handle a large integer. |
| 739 | 737 | Overflow, |
| 740 | 738 | }; |
src/arch/x86_64/CodeGen.zig+19-197| ... | ... | @@ -40,11 +40,7 @@ const Register = bits.Register; |
| 40 | 40 | const gp = abi.RegisterClass.gp; |
| 41 | 41 | const sse = abi.RegisterClass.sse; |
| 42 | 42 | |
| 43 | const InnerError = error{ | |
| 44 | OutOfMemory, | |
| 45 | CodegenFail, | |
| 46 | OutOfRegisters, | |
| 47 | }; | |
| 43 | const InnerError = codegen.CodeGenError || error{OutOfRegisters}; | |
| 48 | 44 | |
| 49 | 45 | gpa: Allocator, |
| 50 | 46 | air: Air, |
| ... | ... | @@ -6683,7 +6679,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void { |
| 6683 | 6679 | return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand }); |
| 6684 | 6680 | } |
| 6685 | 6681 | |
| 6686 | pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | |
| 6682 | fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue { | |
| 6687 | 6683 | // First section of indexes correspond to a set number of constant values. |
| 6688 | 6684 | const ref_int = @enumToInt(inst); |
| 6689 | 6685 | if (ref_int < Air.Inst.Ref.typed_value_map.len) { |
| ... | ... | @@ -6752,200 +6748,26 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV |
| 6752 | 6748 | return mcv; |
| 6753 | 6749 | } |
| 6754 | 6750 | |
| 6755 | fn lowerDeclRef(self: *Self, tv: TypedValue, decl_index: Module.Decl.Index) InnerError!MCValue { | |
| 6756 | log.debug("lowerDeclRef: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | |
| 6757 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | |
| 6758 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | |
| 6759 | ||
| 6760 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? | |
| 6761 | if (tv.ty.zigTypeTag() == .Pointer) blk: { | |
| 6762 | if (tv.ty.castPtrToFn()) |_| break :blk; | |
| 6763 | if (!tv.ty.elemType2().hasRuntimeBits()) { | |
| 6764 | return MCValue.none; | |
| 6765 | } | |
| 6766 | } | |
| 6767 | ||
| 6768 | const module = self.bin_file.options.module.?; | |
| 6769 | const decl = module.declPtr(decl_index); | |
| 6770 | module.markDeclAlive(decl); | |
| 6771 | ||
| 6772 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | |
| 6773 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | |
| 6774 | const atom = elf_file.getAtom(atom_index); | |
| 6775 | return MCValue{ .memory = atom.getOffsetTableAddress(elf_file) }; | |
| 6776 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | |
| 6777 | const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); | |
| 6778 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | |
| 6779 | return MCValue{ .linker_load = .{ | |
| 6780 | .type = .got, | |
| 6781 | .sym_index = sym_index, | |
| 6782 | } }; | |
| 6783 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { | |
| 6784 | const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); | |
| 6785 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | |
| 6786 | return MCValue{ .linker_load = .{ | |
| 6787 | .type = .got, | |
| 6788 | .sym_index = sym_index, | |
| 6789 | } }; | |
| 6790 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | |
| 6791 | const decl_block_index = try p9.seeDecl(decl_index); | |
| 6792 | const decl_block = p9.getDeclBlock(decl_block_index); | |
| 6793 | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; | |
| 6794 | return MCValue{ .memory = got_addr }; | |
| 6795 | } else { | |
| 6796 | return self.fail("TODO codegen non-ELF const Decl pointer", .{}); | |
| 6797 | } | |
| 6798 | } | |
| 6799 | ||
| 6800 | fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue { | |
| 6801 | log.debug("lowerUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | |
| 6802 | const local_sym_index = self.bin_file.lowerUnnamedConst(tv, self.mod_fn.owner_decl) catch |err| { | |
| 6803 | return self.fail("lowering unnamed constant failed: {s}", .{@errorName(err)}); | |
| 6804 | }; | |
| 6805 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { | |
| 6806 | return MCValue{ .memory = elf_file.getSymbol(local_sym_index).st_value }; | |
| 6807 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | |
| 6808 | return MCValue{ .linker_load = .{ | |
| 6809 | .type = .direct, | |
| 6810 | .sym_index = local_sym_index, | |
| 6811 | } }; | |
| 6812 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | |
| 6813 | return MCValue{ .linker_load = .{ | |
| 6814 | .type = .direct, | |
| 6815 | .sym_index = local_sym_index, | |
| 6816 | } }; | |
| 6817 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | |
| 6818 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | |
| 6819 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | |
| 6820 | const got_index = local_sym_index; // the plan9 backend returns the got_index | |
| 6821 | const got_addr = p9.bases.data + got_index * ptr_bytes; | |
| 6822 | return MCValue{ .memory = got_addr }; | |
| 6823 | } else { | |
| 6824 | return self.fail("TODO lower unnamed const", .{}); | |
| 6825 | } | |
| 6826 | } | |
| 6827 | ||
| 6828 | 6751 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 6829 | var typed_value = arg_tv; | |
| 6830 | if (typed_value.val.castTag(.runtime_value)) |rt| { | |
| 6831 | typed_value.val = rt.data; | |
| 6832 | } | |
| 6833 | log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); | |
| 6834 | if (typed_value.val.isUndef()) | |
| 6835 | return MCValue{ .undef = {} }; | |
| 6836 | const ptr_bits = self.target.cpu.arch.ptrBitWidth(); | |
| 6837 | ||
| 6838 | if (typed_value.val.castTag(.decl_ref)) |payload| { | |
| 6839 | return self.lowerDeclRef(typed_value, payload.data); | |
| 6840 | } | |
| 6841 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | |
| 6842 | return self.lowerDeclRef(typed_value, payload.data.decl_index); | |
| 6843 | } | |
| 6844 | ||
| 6845 | const target = self.target.*; | |
| 6846 | ||
| 6847 | switch (typed_value.ty.zigTypeTag()) { | |
| 6848 | .Void => return MCValue{ .none = {} }, | |
| 6849 | .Pointer => switch (typed_value.ty.ptrSize()) { | |
| 6850 | .Slice => {}, | |
| 6851 | else => { | |
| 6852 | switch (typed_value.val.tag()) { | |
| 6853 | .int_u64 => { | |
| 6854 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | |
| 6855 | }, | |
| 6856 | else => {}, | |
| 6857 | } | |
| 6858 | }, | |
| 6752 | const mcv: MCValue = switch (try codegen.genTypedValue( | |
| 6753 | self.bin_file, | |
| 6754 | self.src_loc, | |
| 6755 | arg_tv, | |
| 6756 | self.mod_fn.owner_decl, | |
| 6757 | )) { | |
| 6758 | .mcv => |mcv| switch (mcv) { | |
| 6759 | .none => .none, | |
| 6760 | .undef => .undef, | |
| 6761 | .linker_load => |ll| .{ .linker_load = ll }, | |
| 6762 | .immediate => |imm| .{ .immediate = imm }, | |
| 6763 | .memory => |addr| .{ .memory = addr }, | |
| 6859 | 6764 | }, |
| 6860 | .Int => { | |
| 6861 | const info = typed_value.ty.intInfo(self.target.*); | |
| 6862 | if (info.bits <= ptr_bits and info.signedness == .signed) { | |
| 6863 | return MCValue{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) }; | |
| 6864 | } | |
| 6865 | if (!(info.bits > ptr_bits or info.signedness == .signed)) { | |
| 6866 | return MCValue{ .immediate = typed_value.val.toUnsignedInt(target) }; | |
| 6867 | } | |
| 6868 | }, | |
| 6869 | .Bool => { | |
| 6870 | return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) }; | |
| 6871 | }, | |
| 6872 | .Optional => { | |
| 6873 | if (typed_value.ty.isPtrLikeOptional()) { | |
| 6874 | if (typed_value.val.isNull()) | |
| 6875 | return MCValue{ .immediate = 0 }; | |
| 6876 | ||
| 6877 | var buf: Type.Payload.ElemType = undefined; | |
| 6878 | return self.genTypedValue(.{ | |
| 6879 | .ty = typed_value.ty.optionalChild(&buf), | |
| 6880 | .val = typed_value.val, | |
| 6881 | }); | |
| 6882 | } else if (typed_value.ty.abiSize(self.target.*) == 1) { | |
| 6883 | return MCValue{ .immediate = @boolToInt(!typed_value.val.isNull()) }; | |
| 6884 | } | |
| 6885 | }, | |
| 6886 | .Enum => { | |
| 6887 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | |
| 6888 | switch (typed_value.ty.tag()) { | |
| 6889 | .enum_simple => { | |
| 6890 | return MCValue{ .immediate = field_index.data }; | |
| 6891 | }, | |
| 6892 | .enum_full, .enum_nonexhaustive => { | |
| 6893 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | |
| 6894 | if (enum_full.values.count() != 0) { | |
| 6895 | const tag_val = enum_full.values.keys()[field_index.data]; | |
| 6896 | return self.genTypedValue(.{ .ty = enum_full.tag_ty, .val = tag_val }); | |
| 6897 | } else { | |
| 6898 | return MCValue{ .immediate = field_index.data }; | |
| 6899 | } | |
| 6900 | }, | |
| 6901 | else => unreachable, | |
| 6902 | } | |
| 6903 | } else { | |
| 6904 | var int_tag_buffer: Type.Payload.Bits = undefined; | |
| 6905 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | |
| 6906 | return self.genTypedValue(.{ .ty = int_tag_ty, .val = typed_value.val }); | |
| 6907 | } | |
| 6765 | .fail => |msg| { | |
| 6766 | self.err_msg = msg; | |
| 6767 | return error.CodegenFail; | |
| 6908 | 6768 | }, |
| 6909 | .ErrorSet => { | |
| 6910 | switch (typed_value.val.tag()) { | |
| 6911 | .@"error" => { | |
| 6912 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | |
| 6913 | const module = self.bin_file.options.module.?; | |
| 6914 | const global_error_set = module.global_error_set; | |
| 6915 | const error_index = global_error_set.get(err_name).?; | |
| 6916 | return MCValue{ .immediate = error_index }; | |
| 6917 | }, | |
| 6918 | else => { | |
| 6919 | // In this case we are rendering an error union which has a 0 bits payload. | |
| 6920 | return MCValue{ .immediate = 0 }; | |
| 6921 | }, | |
| 6922 | } | |
| 6923 | }, | |
| 6924 | .ErrorUnion => { | |
| 6925 | const error_type = typed_value.ty.errorUnionSet(); | |
| 6926 | const payload_type = typed_value.ty.errorUnionPayload(); | |
| 6927 | const is_pl = typed_value.val.errorUnionIsPayload(); | |
| 6928 | ||
| 6929 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | |
| 6930 | // We use the error type directly as the type. | |
| 6931 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); | |
| 6932 | return self.genTypedValue(.{ .ty = error_type, .val = err_val }); | |
| 6933 | } | |
| 6934 | }, | |
| 6935 | ||
| 6936 | .ComptimeInt => unreachable, | |
| 6937 | .ComptimeFloat => unreachable, | |
| 6938 | .Type => unreachable, | |
| 6939 | .EnumLiteral => unreachable, | |
| 6940 | .NoReturn => unreachable, | |
| 6941 | .Undefined => unreachable, | |
| 6942 | .Null => unreachable, | |
| 6943 | .Opaque => unreachable, | |
| 6944 | ||
| 6945 | else => {}, | |
| 6946 | } | |
| 6947 | ||
| 6948 | return self.lowerUnnamedConst(typed_value); | |
| 6769 | }; | |
| 6770 | return mcv; | |
| 6949 | 6771 | } |
| 6950 | 6772 | |
| 6951 | 6773 | const CallMCValues = struct { |
src/codegen.zig+288-19| ... | ... | @@ -29,13 +29,14 @@ pub const Result = union(enum) { |
| 29 | 29 | fail: *ErrorMsg, |
| 30 | 30 | }; |
| 31 | 31 | |
| 32 | pub const GenerateSymbolError = error{ | |
| 32 | pub const CodeGenError = error{ | |
| 33 | 33 | OutOfMemory, |
| 34 | 34 | Overflow, |
| 35 | /// A Decl that this symbol depends on had a semantic analysis failure. | |
| 36 | AnalysisFail, | |
| 35 | CodegenFail, | |
| 37 | 36 | }; |
| 38 | 37 | |
| 38 | pub const GenerateSymbolError = CodeGenError; | |
| 39 | ||
| 39 | 40 | pub const DebugInfoOutput = union(enum) { |
| 40 | 41 | dwarf: *link.File.Dwarf.DeclState, |
| 41 | 42 | /// the plan9 debuginfo output is a bytecode with 4 opcodes |
| ... | ... | @@ -63,19 +64,6 @@ pub const DebugInfoOutput = union(enum) { |
| 63 | 64 | none, |
| 64 | 65 | }; |
| 65 | 66 | |
| 66 | /// Helper struct to denote that the value is in memory but requires a linker relocation fixup: | |
| 67 | /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) | |
| 68 | /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) | |
| 69 | /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) | |
| 70 | pub const LinkerLoad = struct { | |
| 71 | type: enum { | |
| 72 | got, | |
| 73 | direct, | |
| 74 | import, | |
| 75 | }, | |
| 76 | sym_index: u32, | |
| 77 | }; | |
| 78 | ||
| 79 | 67 | pub fn generateFunction( |
| 80 | 68 | bin_file: *link.File, |
| 81 | 69 | src_loc: Module.SrcLoc, |
| ... | ... | @@ -84,7 +72,7 @@ pub fn generateFunction( |
| 84 | 72 | liveness: Liveness, |
| 85 | 73 | code: *std.ArrayList(u8), |
| 86 | 74 | debug_output: DebugInfoOutput, |
| 87 | ) GenerateSymbolError!Result { | |
| 75 | ) CodeGenError!Result { | |
| 88 | 76 | switch (bin_file.options.target.cpu.arch) { |
| 89 | 77 | .arm, |
| 90 | 78 | .armeb, |
| ... | ... | @@ -120,7 +108,7 @@ pub fn generateSymbol( |
| 120 | 108 | code: *std.ArrayList(u8), |
| 121 | 109 | debug_output: DebugInfoOutput, |
| 122 | 110 | reloc_info: RelocInfo, |
| 123 | ) GenerateSymbolError!Result { | |
| 111 | ) CodeGenError!Result { | |
| 124 | 112 | const tracy = trace(@src()); |
| 125 | 113 | defer tracy.end(); |
| 126 | 114 | |
| ... | ... | @@ -823,7 +811,7 @@ fn lowerDeclRef( |
| 823 | 811 | code: *std.ArrayList(u8), |
| 824 | 812 | debug_output: DebugInfoOutput, |
| 825 | 813 | reloc_info: RelocInfo, |
| 826 | ) GenerateSymbolError!Result { | |
| 814 | ) CodeGenError!Result { | |
| 827 | 815 | const target = bin_file.options.target; |
| 828 | 816 | const module = bin_file.options.module.?; |
| 829 | 817 | if (typed_value.ty.isSlice()) { |
| ... | ... | @@ -880,6 +868,287 @@ fn lowerDeclRef( |
| 880 | 868 | return Result.ok; |
| 881 | 869 | } |
| 882 | 870 | |
| 871 | /// Helper struct to denote that the value is in memory but requires a linker relocation fixup: | |
| 872 | /// * got - the value is referenced indirectly via GOT entry index (the linker emits a got-type reloc) | |
| 873 | /// * direct - the value is referenced directly via symbol index index (the linker emits a displacement reloc) | |
| 874 | /// * import - the value is referenced indirectly via import entry index (the linker emits an import-type reloc) | |
| 875 | pub const LinkerLoad = struct { | |
| 876 | type: enum { | |
| 877 | got, | |
| 878 | direct, | |
| 879 | import, | |
| 880 | }, | |
| 881 | sym_index: u32, | |
| 882 | }; | |
| 883 | ||
| 884 | pub const GenResult = union(enum) { | |
| 885 | mcv: MCValue, | |
| 886 | fail: *ErrorMsg, | |
| 887 | ||
| 888 | const MCValue = union(enum) { | |
| 889 | none, | |
| 890 | undef, | |
| 891 | /// The bit-width of the immediate may be smaller than `u64`. For example, on 32-bit targets | |
| 892 | /// such as ARM, the immediate will never exceed 32-bits. | |
| 893 | immediate: u64, | |
| 894 | linker_load: LinkerLoad, | |
| 895 | /// Direct by-address reference to memory location. | |
| 896 | memory: u64, | |
| 897 | }; | |
| 898 | ||
| 899 | fn mcv(val: MCValue) GenResult { | |
| 900 | return .{ .mcv = val }; | |
| 901 | } | |
| 902 | ||
| 903 | fn fail( | |
| 904 | gpa: Allocator, | |
| 905 | src_loc: Module.SrcLoc, | |
| 906 | comptime format: []const u8, | |
| 907 | args: anytype, | |
| 908 | ) Allocator.Error!GenResult { | |
| 909 | const msg = try ErrorMsg.create(gpa, src_loc, format, args); | |
| 910 | return .{ .fail = msg }; | |
| 911 | } | |
| 912 | }; | |
| 913 | ||
| 914 | fn genDeclRef( | |
| 915 | bin_file: *link.File, | |
| 916 | src_loc: Module.SrcLoc, | |
| 917 | tv: TypedValue, | |
| 918 | decl_index: Module.Decl.Index, | |
| 919 | ) CodeGenError!GenResult { | |
| 920 | log.debug("genDeclRef: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | |
| 921 | ||
| 922 | const target = bin_file.options.target; | |
| 923 | const ptr_bits = target.cpu.arch.ptrBitWidth(); | |
| 924 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | |
| 925 | ||
| 926 | const module = bin_file.options.module.?; | |
| 927 | const decl = module.declPtr(decl_index); | |
| 928 | ||
| 929 | if (decl.ty.zigTypeTag() != .Fn and !decl.ty.hasRuntimeBitsIgnoreComptime()) { | |
| 930 | const imm: u64 = switch (ptr_bytes) { | |
| 931 | 1 => 0xaa, | |
| 932 | 2 => 0xaaaa, | |
| 933 | 4 => 0xaaaaaaaa, | |
| 934 | 8 => 0xaaaaaaaaaaaaaaaa, | |
| 935 | else => unreachable, | |
| 936 | }; | |
| 937 | return GenResult.mcv(.{ .immediate = imm }); | |
| 938 | } | |
| 939 | ||
| 940 | // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`? | |
| 941 | if (tv.ty.zigTypeTag() == .Pointer) blk: { | |
| 942 | if (tv.ty.castPtrToFn()) |_| break :blk; | |
| 943 | if (!tv.ty.elemType2().hasRuntimeBits()) { | |
| 944 | return GenResult.mcv(.none); | |
| 945 | } | |
| 946 | } | |
| 947 | ||
| 948 | module.markDeclAlive(decl); | |
| 949 | ||
| 950 | if (bin_file.cast(link.File.Elf)) |elf_file| { | |
| 951 | const atom_index = try elf_file.getOrCreateAtomForDecl(decl_index); | |
| 952 | const atom = elf_file.getAtom(atom_index); | |
| 953 | return GenResult.mcv(.{ .memory = atom.getOffsetTableAddress(elf_file) }); | |
| 954 | } else if (bin_file.cast(link.File.MachO)) |macho_file| { | |
| 955 | const atom_index = try macho_file.getOrCreateAtomForDecl(decl_index); | |
| 956 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; | |
| 957 | return GenResult.mcv(.{ .linker_load = .{ | |
| 958 | .type = .got, | |
| 959 | .sym_index = sym_index, | |
| 960 | } }); | |
| 961 | } else if (bin_file.cast(link.File.Coff)) |coff_file| { | |
| 962 | const atom_index = try coff_file.getOrCreateAtomForDecl(decl_index); | |
| 963 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; | |
| 964 | return GenResult.mcv(.{ .linker_load = .{ | |
| 965 | .type = .got, | |
| 966 | .sym_index = sym_index, | |
| 967 | } }); | |
| 968 | } else if (bin_file.cast(link.File.Plan9)) |p9| { | |
| 969 | const decl_block_index = try p9.seeDecl(decl_index); | |
| 970 | const decl_block = p9.getDeclBlock(decl_block_index); | |
| 971 | const got_addr = p9.bases.data + decl_block.got_index.? * ptr_bytes; | |
| 972 | return GenResult.mcv(.{ .memory = got_addr }); | |
| 973 | } else { | |
| 974 | return GenResult.fail(bin_file.allocator, src_loc, "TODO genDeclRef for target {}", .{target}); | |
| 975 | } | |
| 976 | } | |
| 977 | ||
| 978 | fn genUnnamedConst( | |
| 979 | bin_file: *link.File, | |
| 980 | src_loc: Module.SrcLoc, | |
| 981 | tv: TypedValue, | |
| 982 | owner_decl_index: Module.Decl.Index, | |
| 983 | ) CodeGenError!GenResult { | |
| 984 | log.debug("genUnnamedConst: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() }); | |
| 985 | ||
| 986 | const target = bin_file.options.target; | |
| 987 | const local_sym_index = bin_file.lowerUnnamedConst(tv, owner_decl_index) catch |err| { | |
| 988 | return GenResult.fail(bin_file.allocator, src_loc, "lowering unnamed constant failed: {s}", .{@errorName(err)}); | |
| 989 | }; | |
| 990 | if (bin_file.cast(link.File.Elf)) |elf_file| { | |
| 991 | return GenResult.mcv(.{ .memory = elf_file.getSymbol(local_sym_index).st_value }); | |
| 992 | } else if (bin_file.cast(link.File.MachO)) |_| { | |
| 993 | return GenResult.mcv(.{ .linker_load = .{ | |
| 994 | .type = .direct, | |
| 995 | .sym_index = local_sym_index, | |
| 996 | } }); | |
| 997 | } else if (bin_file.cast(link.File.Coff)) |_| { | |
| 998 | return GenResult.mcv(.{ .linker_load = .{ | |
| 999 | .type = .direct, | |
| 1000 | .sym_index = local_sym_index, | |
| 1001 | } }); | |
| 1002 | } else if (bin_file.cast(link.File.Plan9)) |p9| { | |
| 1003 | const ptr_bits = target.cpu.arch.ptrBitWidth(); | |
| 1004 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | |
| 1005 | const got_index = local_sym_index; // the plan9 backend returns the got_index | |
| 1006 | const got_addr = p9.bases.data + got_index * ptr_bytes; | |
| 1007 | return GenResult.mcv(.{ .memory = got_addr }); | |
| 1008 | } else { | |
| 1009 | return GenResult.fail(bin_file.allocator, src_loc, "TODO genUnnamedConst for target {}", .{target}); | |
| 1010 | } | |
| 1011 | } | |
| 1012 | ||
| 1013 | pub fn genTypedValue( | |
| 1014 | bin_file: *link.File, | |
| 1015 | src_loc: Module.SrcLoc, | |
| 1016 | arg_tv: TypedValue, | |
| 1017 | owner_decl_index: Module.Decl.Index, | |
| 1018 | ) CodeGenError!GenResult { | |
| 1019 | var typed_value = arg_tv; | |
| 1020 | if (typed_value.val.castTag(.runtime_value)) |rt| { | |
| 1021 | typed_value.val = rt.data; | |
| 1022 | } | |
| 1023 | ||
| 1024 | log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() }); | |
| 1025 | ||
| 1026 | if (typed_value.val.isUndef()) | |
| 1027 | return GenResult.mcv(.undef); | |
| 1028 | ||
| 1029 | const target = bin_file.options.target; | |
| 1030 | const ptr_bits = target.cpu.arch.ptrBitWidth(); | |
| 1031 | ||
| 1032 | if (typed_value.val.castTag(.decl_ref)) |payload| { | |
| 1033 | return genDeclRef(bin_file, src_loc, typed_value, payload.data); | |
| 1034 | } | |
| 1035 | if (typed_value.val.castTag(.decl_ref_mut)) |payload| { | |
| 1036 | return genDeclRef(bin_file, src_loc, typed_value, payload.data.decl_index); | |
| 1037 | } | |
| 1038 | ||
| 1039 | switch (typed_value.ty.zigTypeTag()) { | |
| 1040 | .Void => return GenResult.mcv(.none), | |
| 1041 | .Pointer => switch (typed_value.ty.ptrSize()) { | |
| 1042 | .Slice => {}, | |
| 1043 | else => { | |
| 1044 | switch (typed_value.val.tag()) { | |
| 1045 | .int_u64 => { | |
| 1046 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); | |
| 1047 | }, | |
| 1048 | else => {}, | |
| 1049 | } | |
| 1050 | }, | |
| 1051 | }, | |
| 1052 | .Int => { | |
| 1053 | const info = typed_value.ty.intInfo(target); | |
| 1054 | if (info.bits <= ptr_bits and info.signedness == .signed) { | |
| 1055 | return GenResult.mcv(.{ .immediate = @bitCast(u64, typed_value.val.toSignedInt(target)) }); | |
| 1056 | } | |
| 1057 | if (!(info.bits > ptr_bits or info.signedness == .signed)) { | |
| 1058 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); | |
| 1059 | } | |
| 1060 | }, | |
| 1061 | .Bool => { | |
| 1062 | return GenResult.mcv(.{ .immediate = @boolToInt(typed_value.val.toBool()) }); | |
| 1063 | }, | |
| 1064 | .Optional => { | |
| 1065 | if (typed_value.ty.isPtrLikeOptional()) { | |
| 1066 | if (typed_value.val.isNull()) | |
| 1067 | return GenResult.mcv(.{ .immediate = 0 }); | |
| 1068 | ||
| 1069 | var buf: Type.Payload.ElemType = undefined; | |
| 1070 | return genTypedValue(bin_file, src_loc, .{ | |
| 1071 | .ty = typed_value.ty.optionalChild(&buf), | |
| 1072 | .val = typed_value.val, | |
| 1073 | }, owner_decl_index); | |
| 1074 | } else if (typed_value.ty.abiSize(target) == 1) { | |
| 1075 | return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull()) }); | |
| 1076 | } | |
| 1077 | }, | |
| 1078 | .Enum => { | |
| 1079 | if (typed_value.val.castTag(.enum_field_index)) |field_index| { | |
| 1080 | switch (typed_value.ty.tag()) { | |
| 1081 | .enum_simple => { | |
| 1082 | return GenResult.mcv(.{ .immediate = field_index.data }); | |
| 1083 | }, | |
| 1084 | .enum_full, .enum_nonexhaustive => { | |
| 1085 | const enum_full = typed_value.ty.cast(Type.Payload.EnumFull).?.data; | |
| 1086 | if (enum_full.values.count() != 0) { | |
| 1087 | const tag_val = enum_full.values.keys()[field_index.data]; | |
| 1088 | return genTypedValue(bin_file, src_loc, .{ | |
| 1089 | .ty = enum_full.tag_ty, | |
| 1090 | .val = tag_val, | |
| 1091 | }, owner_decl_index); | |
| 1092 | } else { | |
| 1093 | return GenResult.mcv(.{ .immediate = field_index.data }); | |
| 1094 | } | |
| 1095 | }, | |
| 1096 | else => unreachable, | |
| 1097 | } | |
| 1098 | } else { | |
| 1099 | var int_tag_buffer: Type.Payload.Bits = undefined; | |
| 1100 | const int_tag_ty = typed_value.ty.intTagType(&int_tag_buffer); | |
| 1101 | return genTypedValue(bin_file, src_loc, .{ | |
| 1102 | .ty = int_tag_ty, | |
| 1103 | .val = typed_value.val, | |
| 1104 | }, owner_decl_index); | |
| 1105 | } | |
| 1106 | }, | |
| 1107 | .ErrorSet => { | |
| 1108 | switch (typed_value.val.tag()) { | |
| 1109 | .@"error" => { | |
| 1110 | const err_name = typed_value.val.castTag(.@"error").?.data.name; | |
| 1111 | const module = bin_file.options.module.?; | |
| 1112 | const global_error_set = module.global_error_set; | |
| 1113 | const error_index = global_error_set.get(err_name).?; | |
| 1114 | return GenResult.mcv(.{ .immediate = error_index }); | |
| 1115 | }, | |
| 1116 | else => { | |
| 1117 | // In this case we are rendering an error union which has a 0 bits payload. | |
| 1118 | return GenResult.mcv(.{ .immediate = 0 }); | |
| 1119 | }, | |
| 1120 | } | |
| 1121 | }, | |
| 1122 | .ErrorUnion => { | |
| 1123 | const error_type = typed_value.ty.errorUnionSet(); | |
| 1124 | const payload_type = typed_value.ty.errorUnionPayload(); | |
| 1125 | const is_pl = typed_value.val.errorUnionIsPayload(); | |
| 1126 | ||
| 1127 | if (!payload_type.hasRuntimeBitsIgnoreComptime()) { | |
| 1128 | // We use the error type directly as the type. | |
| 1129 | const err_val = if (!is_pl) typed_value.val else Value.initTag(.zero); | |
| 1130 | return genTypedValue(bin_file, src_loc, .{ | |
| 1131 | .ty = error_type, | |
| 1132 | .val = err_val, | |
| 1133 | }, owner_decl_index); | |
| 1134 | } | |
| 1135 | }, | |
| 1136 | ||
| 1137 | .ComptimeInt => unreachable, | |
| 1138 | .ComptimeFloat => unreachable, | |
| 1139 | .Type => unreachable, | |
| 1140 | .EnumLiteral => unreachable, | |
| 1141 | .NoReturn => unreachable, | |
| 1142 | .Undefined => unreachable, | |
| 1143 | .Null => unreachable, | |
| 1144 | .Opaque => unreachable, | |
| 1145 | ||
| 1146 | else => {}, | |
| 1147 | } | |
| 1148 | ||
| 1149 | return genUnnamedConst(bin_file, src_loc, typed_value, owner_decl_index); | |
| 1150 | } | |
| 1151 | ||
| 883 | 1152 | pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 { |
| 884 | 1153 | const payload_align = payload_ty.abiAlignment(target); |
| 885 | 1154 | const error_align = Type.anyerror.abiAlignment(target); |
src/link/Coff.zig+1-1| ... | ... | @@ -1060,7 +1060,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 1060 | 1060 | decl.analysis = .codegen_failure; |
| 1061 | 1061 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1062 | 1062 | log.err("{s}", .{em.msg}); |
| 1063 | return error.AnalysisFail; | |
| 1063 | return error.CodegenFail; | |
| 1064 | 1064 | }, |
| 1065 | 1065 | }; |
| 1066 | 1066 |
src/link/Elf.zig+1-1| ... | ... | @@ -2618,7 +2618,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 2618 | 2618 | decl.analysis = .codegen_failure; |
| 2619 | 2619 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 2620 | 2620 | log.err("{s}", .{em.msg}); |
| 2621 | return error.AnalysisFail; | |
| 2621 | return error.CodegenFail; | |
| 2622 | 2622 | }, |
| 2623 | 2623 | }; |
| 2624 | 2624 |
src/link/MachO.zig+1-1| ... | ... | @@ -2089,7 +2089,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 2089 | 2089 | decl.analysis = .codegen_failure; |
| 2090 | 2090 | try module.failed_decls.put(module.gpa, decl_index, em); |
| 2091 | 2091 | log.err("{s}", .{em.msg}); |
| 2092 | return error.AnalysisFail; | |
| 2092 | return error.CodegenFail; | |
| 2093 | 2093 | }, |
| 2094 | 2094 | }; |
| 2095 | 2095 |
src/link/Plan9.zig+1-1| ... | ... | @@ -377,7 +377,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I |
| 377 | 377 | decl.analysis = .codegen_failure; |
| 378 | 378 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 379 | 379 | log.err("{s}", .{em.msg}); |
| 380 | return error.AnalysisFail; | |
| 380 | return error.CodegenFail; | |
| 381 | 381 | }, |
| 382 | 382 | }; |
| 383 | 383 | // duped_code is freed when the unnamed const is freed |
src/link/Wasm.zig+1-1| ... | ... | @@ -1255,7 +1255,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1255 | 1255 | .fail => |em| { |
| 1256 | 1256 | decl.analysis = .codegen_failure; |
| 1257 | 1257 | try mod.failed_decls.put(mod.gpa, decl_index, em); |
| 1258 | return error.AnalysisFail; | |
| 1258 | return error.CodegenFail; | |
| 1259 | 1259 | }, |
| 1260 | 1260 | }; |
| 1261 | 1261 | }; |
src/register_manager.zig+3| ... | ... | @@ -19,6 +19,9 @@ pub const AllocateRegistersError = error{ |
| 19 | 19 | /// Can happen when spilling an instruction in codegen runs out of |
| 20 | 20 | /// memory, so we propagate that error |
| 21 | 21 | OutOfMemory, |
| 22 | /// Can happen when spilling an instruction in codegen triggers integer | |
| 23 | /// overflow, so we propagate that error | |
| 24 | Overflow, | |
| 22 | 25 | /// Can happen when spilling an instruction triggers a codegen |
| 23 | 26 | /// error, so we propagate that error |
| 24 | 27 | CodegenFail, |