authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-03 18:06:25+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-03 18:06:25+01:00
logc746cbc686c46904a5d381725079a69e38b201cd
tree46dbe180dd40e9cf8dfea6fae933e6f011b4b3ee
parent6be5946ed8026f2a7ae990aced9572f229acecf4

codegen: move gen logic for typed values, consts and decl ref to common codegen


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,11 +41,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs;
41const c_abi_int_return_regs = abi.c_abi_int_return_regs;41const c_abi_int_return_regs = abi.c_abi_int_return_regs;
42const gp = abi.RegisterClass.gp;42const gp = abi.RegisterClass.gp;
4343
44const InnerError = error{44const InnerError = codegen.CodeGenError || error{OutOfRegisters};
45 OutOfMemory,
46 CodegenFail,
47 OutOfRegisters,
48};
4945
50gpa: Allocator,46gpa: Allocator,
51air: Air,47air: 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,11 +42,7 @@ const c_abi_int_param_regs = abi.c_abi_int_param_regs;
42const c_abi_int_return_regs = abi.c_abi_int_return_regs;42const c_abi_int_return_regs = abi.c_abi_int_return_regs;
43const gp = abi.RegisterClass.gp;43const gp = abi.RegisterClass.gp;
4444
45const InnerError = error{45const InnerError = codegen.CodeGenError || error{OutOfRegisters};
46 OutOfMemory,
47 CodegenFail,
48 OutOfRegisters,
49};
5046
51gpa: Allocator,47gpa: Allocator,
52air: Air,48air: Air,
src/arch/riscv64/CodeGen.zig+5-9
...@@ -21,10 +21,10 @@ const DW = std.dwarf;...@@ -21,10 +21,10 @@ const DW = std.dwarf;
21const leb128 = std.leb;21const leb128 = std.leb;
22const log = std.log.scoped(.codegen);22const log = std.log.scoped(.codegen);
23const build_options = @import("build_options");23const build_options = @import("build_options");
24const codegen = @import("../../codegen.zig");
2425
25const Result = @import("../../codegen.zig").Result;26const Result = codegen.Result;
26const GenerateSymbolError = @import("../../codegen.zig").GenerateSymbolError;27const DebugInfoOutput = codegen.DebugInfoOutput;
27const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
2828
29const bits = @import("bits.zig");29const bits = @import("bits.zig");
30const abi = @import("abi.zig");30const abi = @import("abi.zig");
...@@ -35,11 +35,7 @@ const Instruction = abi.Instruction;...@@ -35,11 +35,7 @@ const Instruction = abi.Instruction;
35const callee_preserved_regs = abi.callee_preserved_regs;35const callee_preserved_regs = abi.callee_preserved_regs;
36const gp = abi.RegisterClass.gp;36const gp = abi.RegisterClass.gp;
3737
38const InnerError = error{38const InnerError = codegen.CodeGenError || error{OutOfRegisters};
39 OutOfMemory,
40 CodegenFail,
41 OutOfRegisters,
42};
4339
44gpa: Allocator,40gpa: Allocator,
45air: Air,41air: Air,
...@@ -225,7 +221,7 @@ pub fn generate(...@@ -225,7 +221,7 @@ pub fn generate(
225 liveness: Liveness,221 liveness: Liveness,
226 code: *std.ArrayList(u8),222 code: *std.ArrayList(u8),
227 debug_output: DebugInfoOutput,223 debug_output: DebugInfoOutput,
228) GenerateSymbolError!Result {224) codegen.CodeGenError!Result {
229 if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) {225 if (build_options.skip_non_native and builtin.cpu.arch != bin_file.options.target.cpu.arch) {
230 @panic("Attempted to compile for architecture that was disabled by build configuration");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,11 +38,7 @@ const gp = abi.RegisterClass.gp;
3838
39const Self = @This();39const Self = @This();
4040
41const InnerError = error{41const InnerError = codegen.CodeGenError || error{OutOfRegisters};
42 OutOfMemory,
43 CodegenFail,
44 OutOfRegisters,
45};
4642
47const RegisterView = enum(u1) {43const RegisterView = enum(u1) {
48 caller,44 caller,
src/arch/wasm/CodeGen.zig-2
...@@ -733,8 +733,6 @@ const InnerError = error{...@@ -733,8 +733,6 @@ const InnerError = error{
733 OutOfMemory,733 OutOfMemory,
734 /// An error occurred when trying to lower AIR to MIR.734 /// An error occurred when trying to lower AIR to MIR.
735 CodegenFail,735 CodegenFail,
736 /// Can occur when dereferencing a pointer that points to a `Decl` of which the analysis has failed
737 AnalysisFail,
738 /// Compiler implementation could not handle a large integer.736 /// Compiler implementation could not handle a large integer.
739 Overflow,737 Overflow,
740};738};
src/arch/x86_64/CodeGen.zig+19-197
...@@ -40,11 +40,7 @@ const Register = bits.Register;...@@ -40,11 +40,7 @@ const Register = bits.Register;
40const gp = abi.RegisterClass.gp;40const gp = abi.RegisterClass.gp;
41const sse = abi.RegisterClass.sse;41const sse = abi.RegisterClass.sse;
4242
43const InnerError = error{43const InnerError = codegen.CodeGenError || error{OutOfRegisters};
44 OutOfMemory,
45 CodegenFail,
46 OutOfRegisters,
47};
4844
49gpa: Allocator,45gpa: Allocator,
50air: Air,46air: Air,
...@@ -6683,7 +6679,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {...@@ -6683,7 +6679,7 @@ fn airMulAdd(self: *Self, inst: Air.Inst.Index) !void {
6683 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });6679 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, pl_op.operand });
6684}6680}
66856681
6686pub fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {6682fn resolveInst(self: *Self, inst: Air.Inst.Ref) InnerError!MCValue {
6687 // First section of indexes correspond to a set number of constant values.6683 // First section of indexes correspond to a set number of constant values.
6688 const ref_int = @enumToInt(inst);6684 const ref_int = @enumToInt(inst);
6689 if (ref_int < Air.Inst.Ref.typed_value_map.len) {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,200 +6748,26 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
6752 return mcv;6748 return mcv;
6753}6749}
67546750
6755fn 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
6800fn 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
6828fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {6751fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue {
6829 var typed_value = arg_tv;6752 const mcv: MCValue = switch (try codegen.genTypedValue(
6830 if (typed_value.val.castTag(.runtime_value)) |rt| {6753 self.bin_file,
6831 typed_value.val = rt.data;6754 self.src_loc,
6832 }6755 arg_tv,
6833 log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });6756 self.mod_fn.owner_decl,
6834 if (typed_value.val.isUndef())6757 )) {
6835 return MCValue{ .undef = {} };6758 .mcv => |mcv| switch (mcv) {
6836 const ptr_bits = self.target.cpu.arch.ptrBitWidth();6759 .none => .none,
68376760 .undef => .undef,
6838 if (typed_value.val.castTag(.decl_ref)) |payload| {6761 .linker_load => |ll| .{ .linker_load = ll },
6839 return self.lowerDeclRef(typed_value, payload.data);6762 .immediate => |imm| .{ .immediate = imm },
6840 }6763 .memory => |addr| .{ .memory = addr },
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 },
6859 },6764 },
6860 .Int => {6765 .fail => |msg| {
6861 const info = typed_value.ty.intInfo(self.target.*);6766 self.err_msg = msg;
6862 if (info.bits <= ptr_bits and info.signedness == .signed) {6767 return error.CodegenFail;
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 }
6908 },6768 },
6909 .ErrorSet => {6769 };
6910 switch (typed_value.val.tag()) {6770 return mcv;
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);
6949}6771}
69506772
6951const CallMCValues = struct {6773const CallMCValues = struct {
src/codegen.zig+288-19
...@@ -29,13 +29,14 @@ pub const Result = union(enum) {...@@ -29,13 +29,14 @@ pub const Result = union(enum) {
29 fail: *ErrorMsg,29 fail: *ErrorMsg,
30};30};
3131
32pub const GenerateSymbolError = error{32pub const CodeGenError = error{
33 OutOfMemory,33 OutOfMemory,
34 Overflow,34 Overflow,
35 /// A Decl that this symbol depends on had a semantic analysis failure.35 CodegenFail,
36 AnalysisFail,
37};36};
3837
38pub const GenerateSymbolError = CodeGenError;
39
39pub const DebugInfoOutput = union(enum) {40pub const DebugInfoOutput = union(enum) {
40 dwarf: *link.File.Dwarf.DeclState,41 dwarf: *link.File.Dwarf.DeclState,
41 /// the plan9 debuginfo output is a bytecode with 4 opcodes42 /// the plan9 debuginfo output is a bytecode with 4 opcodes
...@@ -63,19 +64,6 @@ pub const DebugInfoOutput = union(enum) {...@@ -63,19 +64,6 @@ pub const DebugInfoOutput = union(enum) {
63 none,64 none,
64};65};
6566
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)
70pub const LinkerLoad = struct {
71 type: enum {
72 got,
73 direct,
74 import,
75 },
76 sym_index: u32,
77};
78
79pub fn generateFunction(67pub fn generateFunction(
80 bin_file: *link.File,68 bin_file: *link.File,
81 src_loc: Module.SrcLoc,69 src_loc: Module.SrcLoc,
...@@ -84,7 +72,7 @@ pub fn generateFunction(...@@ -84,7 +72,7 @@ pub fn generateFunction(
84 liveness: Liveness,72 liveness: Liveness,
85 code: *std.ArrayList(u8),73 code: *std.ArrayList(u8),
86 debug_output: DebugInfoOutput,74 debug_output: DebugInfoOutput,
87) GenerateSymbolError!Result {75) CodeGenError!Result {
88 switch (bin_file.options.target.cpu.arch) {76 switch (bin_file.options.target.cpu.arch) {
89 .arm,77 .arm,
90 .armeb,78 .armeb,
...@@ -120,7 +108,7 @@ pub fn generateSymbol(...@@ -120,7 +108,7 @@ pub fn generateSymbol(
120 code: *std.ArrayList(u8),108 code: *std.ArrayList(u8),
121 debug_output: DebugInfoOutput,109 debug_output: DebugInfoOutput,
122 reloc_info: RelocInfo,110 reloc_info: RelocInfo,
123) GenerateSymbolError!Result {111) CodeGenError!Result {
124 const tracy = trace(@src());112 const tracy = trace(@src());
125 defer tracy.end();113 defer tracy.end();
126114
...@@ -823,7 +811,7 @@ fn lowerDeclRef(...@@ -823,7 +811,7 @@ fn lowerDeclRef(
823 code: *std.ArrayList(u8),811 code: *std.ArrayList(u8),
824 debug_output: DebugInfoOutput,812 debug_output: DebugInfoOutput,
825 reloc_info: RelocInfo,813 reloc_info: RelocInfo,
826) GenerateSymbolError!Result {814) CodeGenError!Result {
827 const target = bin_file.options.target;815 const target = bin_file.options.target;
828 const module = bin_file.options.module.?;816 const module = bin_file.options.module.?;
829 if (typed_value.ty.isSlice()) {817 if (typed_value.ty.isSlice()) {
...@@ -880,6 +868,287 @@ fn lowerDeclRef(...@@ -880,6 +868,287 @@ fn lowerDeclRef(
880 return Result.ok;868 return Result.ok;
881}869}
882870
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)
875pub const LinkerLoad = struct {
876 type: enum {
877 got,
878 direct,
879 import,
880 },
881 sym_index: u32,
882};
883
884pub 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
914fn 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
978fn 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
1013pub 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
883pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 {1152pub fn errUnionPayloadOffset(payload_ty: Type, target: std.Target) u64 {
884 const payload_align = payload_ty.abiAlignment(target);1153 const payload_align = payload_ty.abiAlignment(target);
885 const error_align = Type.anyerror.abiAlignment(target);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,7 +1060,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
1060 decl.analysis = .codegen_failure;1060 decl.analysis = .codegen_failure;
1061 try mod.failed_decls.put(mod.gpa, decl_index, em);1061 try mod.failed_decls.put(mod.gpa, decl_index, em);
1062 log.err("{s}", .{em.msg});1062 log.err("{s}", .{em.msg});
1063 return error.AnalysisFail;1063 return error.CodegenFail;
1064 },1064 },
1065 };1065 };
10661066
src/link/Elf.zig+1-1
...@@ -2618,7 +2618,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -2618,7 +2618,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
2618 decl.analysis = .codegen_failure;2618 decl.analysis = .codegen_failure;
2619 try mod.failed_decls.put(mod.gpa, decl_index, em);2619 try mod.failed_decls.put(mod.gpa, decl_index, em);
2620 log.err("{s}", .{em.msg});2620 log.err("{s}", .{em.msg});
2621 return error.AnalysisFail;2621 return error.CodegenFail;
2622 },2622 },
2623 };2623 };
26242624
src/link/MachO.zig+1-1
...@@ -2089,7 +2089,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu...@@ -2089,7 +2089,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
2089 decl.analysis = .codegen_failure;2089 decl.analysis = .codegen_failure;
2090 try module.failed_decls.put(module.gpa, decl_index, em);2090 try module.failed_decls.put(module.gpa, decl_index, em);
2091 log.err("{s}", .{em.msg});2091 log.err("{s}", .{em.msg});
2092 return error.AnalysisFail;2092 return error.CodegenFail;
2093 },2093 },
2094 };2094 };
20952095
src/link/Plan9.zig+1-1
...@@ -377,7 +377,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I...@@ -377,7 +377,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I
377 decl.analysis = .codegen_failure;377 decl.analysis = .codegen_failure;
378 try mod.failed_decls.put(mod.gpa, decl_index, em);378 try mod.failed_decls.put(mod.gpa, decl_index, em);
379 log.err("{s}", .{em.msg});379 log.err("{s}", .{em.msg});
380 return error.AnalysisFail;380 return error.CodegenFail;
381 },381 },
382 };382 };
383 // duped_code is freed when the unnamed const is freed383 // 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,7 +1255,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1255 .fail => |em| {1255 .fail => |em| {
1256 decl.analysis = .codegen_failure;1256 decl.analysis = .codegen_failure;
1257 try mod.failed_decls.put(mod.gpa, decl_index, em);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,6 +19,9 @@ pub const AllocateRegistersError = error{
19 /// Can happen when spilling an instruction in codegen runs out of19 /// Can happen when spilling an instruction in codegen runs out of
20 /// memory, so we propagate that error20 /// memory, so we propagate that error
21 OutOfMemory,21 OutOfMemory,
22 /// Can happen when spilling an instruction in codegen triggers integer
23 /// overflow, so we propagate that error
24 Overflow,
22 /// Can happen when spilling an instruction triggers a codegen25 /// Can happen when spilling an instruction triggers a codegen
23 /// error, so we propagate that error26 /// error, so we propagate that error
24 CodegenFail,27 CodegenFail,