| ... | ... | @@ -7,6 +7,8 @@ const leb128 = std.leb; |
| 7 | 7 | const link = @import("../../link.zig"); |
| 8 | 8 | const log = std.log.scoped(.codegen); |
| 9 | 9 | const tracking_log = std.log.scoped(.tracking); |
| 10 | const verbose_tracking_log = std.log.scoped(.verbose_tracking); |
| 11 | const wip_mir_log = std.log.scoped(.wip_mir); |
| 10 | 12 | const math = std.math; |
| 11 | 13 | const mem = std.mem; |
| 12 | 14 | const trace = @import("../../tracy.zig").trace; |
| ... | ... | @@ -48,16 +50,13 @@ const sse = abi.RegisterClass.sse; |
| 48 | 50 | |
| 49 | 51 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 50 | 52 | |
| 51 | | const debug_wip_mir = false; |
| 52 | | const debug_tracking = false; |
| 53 | | |
| 54 | 53 | gpa: Allocator, |
| 55 | 54 | air: Air, |
| 56 | 55 | liveness: Liveness, |
| 57 | 56 | bin_file: *link.File, |
| 58 | 57 | debug_output: DebugInfoOutput, |
| 59 | 58 | target: *const std.Target, |
| 60 | | mod_fn: *const Module.Fn, |
| 59 | owner: Owner, |
| 61 | 60 | err_msg: ?*ErrorMsg, |
| 62 | 61 | args: []MCValue, |
| 63 | 62 | ret_mcv: InstTracking, |
| ... | ... | @@ -109,6 +108,44 @@ const mir_to_air_map_init = if (builtin.mode == .Debug) std.AutoHashMapUnmanaged |
| 109 | 108 | const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; |
| 110 | 109 | const RegisterOffset = struct { reg: Register, off: i32 = 0 }; |
| 111 | 110 | |
| 111 | const Owner = union(enum) { |
| 112 | mod_fn: *const Module.Fn, |
| 113 | lazy_sym: link.File.LazySymbol, |
| 114 | |
| 115 | fn getDecl(owner: Owner) Module.Decl.Index { |
| 116 | return switch (owner) { |
| 117 | .mod_fn => |mod_fn| mod_fn.owner_decl, |
| 118 | .lazy_sym => |lazy_sym| lazy_sym.ty.getOwnerDecl(), |
| 119 | }; |
| 120 | } |
| 121 | |
| 122 | fn getSymbolIndex(owner: Owner, ctx: *Self) !u32 { |
| 123 | switch (owner) { |
| 124 | .mod_fn => |mod_fn| { |
| 125 | const decl_index = mod_fn.owner_decl; |
| 126 | if (ctx.bin_file.cast(link.File.MachO)) |macho_file| { |
| 127 | const atom = try macho_file.getOrCreateAtomForDecl(decl_index); |
| 128 | return macho_file.getAtom(atom).getSymbolIndex().?; |
| 129 | } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| { |
| 130 | const atom = try coff_file.getOrCreateAtomForDecl(decl_index); |
| 131 | return coff_file.getAtom(atom).getSymbolIndex().?; |
| 132 | } else unreachable; |
| 133 | }, |
| 134 | .lazy_sym => |lazy_sym| { |
| 135 | if (ctx.bin_file.cast(link.File.MachO)) |macho_file| { |
| 136 | const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| |
| 137 | return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 138 | return macho_file.getAtom(atom).getSymbolIndex().?; |
| 139 | } else if (ctx.bin_file.cast(link.File.Coff)) |coff_file| { |
| 140 | const atom = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| |
| 141 | return ctx.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 142 | return coff_file.getAtom(atom).getSymbolIndex().?; |
| 143 | } else unreachable; |
| 144 | }, |
| 145 | } |
| 146 | } |
| 147 | }; |
| 148 | |
| 112 | 149 | pub const MCValue = union(enum) { |
| 113 | 150 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. |
| 114 | 151 | /// TODO Look into deleting this tag and using `dead` instead, since every use |
| ... | ... | @@ -220,9 +257,9 @@ pub const MCValue = union(enum) { |
| 220 | 257 | .dead, |
| 221 | 258 | .undef, |
| 222 | 259 | .immediate, |
| 260 | .eflags, |
| 223 | 261 | .register, |
| 224 | 262 | .register_offset, |
| 225 | | .eflags, |
| 226 | 263 | .register_overflow, |
| 227 | 264 | .lea_direct, |
| 228 | 265 | .lea_got, |
| ... | ... | @@ -298,6 +335,41 @@ pub const MCValue = union(enum) { |
| 298 | 335 | }; |
| 299 | 336 | } |
| 300 | 337 | |
| 338 | fn mem(mcv: MCValue, ptr_size: Memory.PtrSize) Memory { |
| 339 | return switch (mcv) { |
| 340 | .none, |
| 341 | .unreach, |
| 342 | .dead, |
| 343 | .undef, |
| 344 | .immediate, |
| 345 | .eflags, |
| 346 | .register, |
| 347 | .register_offset, |
| 348 | .register_overflow, |
| 349 | .load_direct, |
| 350 | .lea_direct, |
| 351 | .load_got, |
| 352 | .lea_got, |
| 353 | .load_tlv, |
| 354 | .lea_tlv, |
| 355 | .lea_frame, |
| 356 | .reserved_frame, |
| 357 | => unreachable, |
| 358 | .memory => |addr| if (math.cast(i32, @bitCast(i64, addr))) |small_addr| |
| 359 | Memory.sib(ptr_size, .{ .base = .{ .reg = .ds }, .disp = small_addr }) |
| 360 | else |
| 361 | Memory.moffs(.ds, addr), |
| 362 | .indirect => |reg_off| Memory.sib(ptr_size, .{ |
| 363 | .base = .{ .reg = reg_off.reg }, |
| 364 | .disp = reg_off.off, |
| 365 | }), |
| 366 | .load_frame => |frame_addr| Memory.sib(ptr_size, .{ |
| 367 | .base = .{ .frame = frame_addr.index }, |
| 368 | .disp = frame_addr.off, |
| 369 | }), |
| 370 | }; |
| 371 | } |
| 372 | |
| 301 | 373 | pub fn format( |
| 302 | 374 | mcv: MCValue, |
| 303 | 375 | comptime _: []const u8, |
| ... | ... | @@ -575,12 +647,6 @@ pub fn generate( |
| 575 | 647 | assert(fn_owner_decl.has_tv); |
| 576 | 648 | const fn_type = fn_owner_decl.ty; |
| 577 | 649 | |
| 578 | | if (debug_wip_mir) { |
| 579 | | const stderr = std.io.getStdErr().writer(); |
| 580 | | fn_owner_decl.renderFullyQualifiedName(mod, stderr) catch {}; |
| 581 | | stderr.writeAll(":\n") catch {}; |
| 582 | | } |
| 583 | | |
| 584 | 650 | const gpa = bin_file.allocator; |
| 585 | 651 | var function = Self{ |
| 586 | 652 | .gpa = gpa, |
| ... | ... | @@ -589,7 +655,7 @@ pub fn generate( |
| 589 | 655 | .target = &bin_file.options.target, |
| 590 | 656 | .bin_file = bin_file, |
| 591 | 657 | .debug_output = debug_output, |
| 592 | | .mod_fn = module_fn, |
| 658 | .owner = .{ .mod_fn = module_fn }, |
| 593 | 659 | .err_msg = null, |
| 594 | 660 | .args = undefined, // populated after `resolveCallingConventionValues` |
| 595 | 661 | .ret_mcv = undefined, // populated after `resolveCallingConventionValues` |
| ... | ... | @@ -614,6 +680,8 @@ pub fn generate( |
| 614 | 680 | if (builtin.mode == .Debug) function.mir_to_air_map.deinit(gpa); |
| 615 | 681 | } |
| 616 | 682 | |
| 683 | wip_mir_log.debug("{}:", .{function.fmtDecl(module_fn.owner_decl)}); |
| 684 | |
| 617 | 685 | try function.frame_allocs.resize(gpa, FrameIndex.named_count); |
| 618 | 686 | function.frame_allocs.set( |
| 619 | 687 | @enumToInt(FrameIndex.stack_frame), |
| ... | ... | @@ -715,48 +783,190 @@ pub fn generate( |
| 715 | 783 | } |
| 716 | 784 | } |
| 717 | 785 | |
| 718 | | fn dumpWipMir(self: *Self, inst: Mir.Inst) !void { |
| 719 | | if (!debug_wip_mir) return; |
| 720 | | const stderr = std.io.getStdErr().writer(); |
| 786 | pub fn generateLazy( |
| 787 | bin_file: *link.File, |
| 788 | src_loc: Module.SrcLoc, |
| 789 | lazy_sym: link.File.LazySymbol, |
| 790 | code: *std.ArrayList(u8), |
| 791 | debug_output: DebugInfoOutput, |
| 792 | ) CodeGenError!Result { |
| 793 | const gpa = bin_file.allocator; |
| 794 | var function = Self{ |
| 795 | .gpa = gpa, |
| 796 | .air = undefined, |
| 797 | .liveness = undefined, |
| 798 | .target = &bin_file.options.target, |
| 799 | .bin_file = bin_file, |
| 800 | .debug_output = debug_output, |
| 801 | .owner = .{ .lazy_sym = lazy_sym }, |
| 802 | .err_msg = null, |
| 803 | .args = undefined, |
| 804 | .ret_mcv = undefined, |
| 805 | .fn_type = undefined, |
| 806 | .arg_index = undefined, |
| 807 | .src_loc = src_loc, |
| 808 | .end_di_line = undefined, // no debug info yet |
| 809 | .end_di_column = undefined, // no debug info yet |
| 810 | }; |
| 811 | defer { |
| 812 | function.mir_instructions.deinit(gpa); |
| 813 | function.mir_extra.deinit(gpa); |
| 814 | } |
| 815 | |
| 816 | function.genLazy(lazy_sym) catch |err| switch (err) { |
| 817 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| 818 | error.OutOfRegisters => return Result{ |
| 819 | .fail = try ErrorMsg.create(bin_file.allocator, src_loc, "CodeGen ran out of registers. This is a bug in the Zig compiler.", .{}), |
| 820 | }, |
| 821 | else => |e| return e, |
| 822 | }; |
| 823 | |
| 824 | var mir = Mir{ |
| 825 | .instructions = function.mir_instructions.toOwnedSlice(), |
| 826 | .extra = try function.mir_extra.toOwnedSlice(bin_file.allocator), |
| 827 | .frame_locs = function.frame_locs.toOwnedSlice(), |
| 828 | }; |
| 829 | defer mir.deinit(bin_file.allocator); |
| 830 | |
| 831 | var emit = Emit{ |
| 832 | .lower = .{ |
| 833 | .allocator = bin_file.allocator, |
| 834 | .mir = mir, |
| 835 | .target = &bin_file.options.target, |
| 836 | .src_loc = src_loc, |
| 837 | }, |
| 838 | .bin_file = bin_file, |
| 839 | .debug_output = debug_output, |
| 840 | .code = code, |
| 841 | .prev_di_pc = undefined, // no debug info yet |
| 842 | .prev_di_line = undefined, // no debug info yet |
| 843 | .prev_di_column = undefined, // no debug info yet |
| 844 | }; |
| 845 | defer emit.deinit(); |
| 846 | emit.emitMir() catch |err| switch (err) { |
| 847 | error.LowerFail, error.EmitFail => return Result{ .fail = emit.lower.err_msg.? }, |
| 848 | error.InvalidInstruction, error.CannotEncode => |e| { |
| 849 | const msg = switch (e) { |
| 850 | error.InvalidInstruction => "CodeGen failed to find a viable instruction.", |
| 851 | error.CannotEncode => "CodeGen failed to encode the instruction.", |
| 852 | }; |
| 853 | return Result{ |
| 854 | .fail = try ErrorMsg.create( |
| 855 | bin_file.allocator, |
| 856 | src_loc, |
| 857 | "{s} This is a bug in the Zig compiler.", |
| 858 | .{msg}, |
| 859 | ), |
| 860 | }; |
| 861 | }, |
| 862 | else => |e| return e, |
| 863 | }; |
| 864 | |
| 865 | if (function.err_msg) |em| { |
| 866 | return Result{ .fail = em }; |
| 867 | } else { |
| 868 | return Result.ok; |
| 869 | } |
| 870 | } |
| 871 | |
| 872 | const FormatDeclData = struct { |
| 873 | mod: *Module, |
| 874 | decl_index: Module.Decl.Index, |
| 875 | }; |
| 876 | fn formatDecl( |
| 877 | data: FormatDeclData, |
| 878 | comptime _: []const u8, |
| 879 | _: std.fmt.FormatOptions, |
| 880 | writer: anytype, |
| 881 | ) @TypeOf(writer).Error!void { |
| 882 | try data.mod.declPtr(data.decl_index).renderFullyQualifiedName(data.mod, writer); |
| 883 | } |
| 884 | fn fmtDecl(self: *Self, decl_index: Module.Decl.Index) std.fmt.Formatter(formatDecl) { |
| 885 | return .{ .data = .{ |
| 886 | .mod = self.bin_file.options.module.?, |
| 887 | .decl_index = decl_index, |
| 888 | } }; |
| 889 | } |
| 890 | |
| 891 | const FormatAirData = struct { |
| 892 | self: *Self, |
| 893 | inst: Air.Inst.Index, |
| 894 | }; |
| 895 | fn formatAir( |
| 896 | data: FormatAirData, |
| 897 | comptime _: []const u8, |
| 898 | _: std.fmt.FormatOptions, |
| 899 | writer: anytype, |
| 900 | ) @TypeOf(writer).Error!void { |
| 901 | @import("../../print_air.zig").dumpInst( |
| 902 | data.inst, |
| 903 | data.self.bin_file.options.module.?, |
| 904 | data.self.air, |
| 905 | data.self.liveness, |
| 906 | ); |
| 907 | } |
| 908 | fn fmtAir(self: *Self, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) { |
| 909 | return .{ .data = .{ .self = self, .inst = inst } }; |
| 910 | } |
| 721 | 911 | |
| 912 | const FormatWipMirData = struct { |
| 913 | self: *Self, |
| 914 | inst: Mir.Inst.Index, |
| 915 | }; |
| 916 | fn formatWipMir( |
| 917 | data: FormatWipMirData, |
| 918 | comptime _: []const u8, |
| 919 | _: std.fmt.FormatOptions, |
| 920 | writer: anytype, |
| 921 | ) @TypeOf(writer).Error!void { |
| 722 | 922 | var lower = Lower{ |
| 723 | | .allocator = self.gpa, |
| 923 | .allocator = data.self.gpa, |
| 724 | 924 | .mir = .{ |
| 725 | | .instructions = self.mir_instructions.slice(), |
| 726 | | .extra = self.mir_extra.items, |
| 925 | .instructions = data.self.mir_instructions.slice(), |
| 926 | .extra = data.self.mir_extra.items, |
| 727 | 927 | .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), |
| 728 | 928 | }, |
| 729 | | .target = self.target, |
| 730 | | .src_loc = self.src_loc, |
| 929 | .target = data.self.target, |
| 930 | .src_loc = data.self.src_loc, |
| 731 | 931 | }; |
| 732 | | for (lower.lowerMir(inst) catch |err| switch (err) { |
| 932 | for (lower.lowerMir(data.self.mir_instructions.get(data.inst)) catch |err| switch (err) { |
| 733 | 933 | error.LowerFail => { |
| 734 | 934 | defer { |
| 735 | | lower.err_msg.?.deinit(self.gpa); |
| 935 | lower.err_msg.?.deinit(data.self.gpa); |
| 736 | 936 | lower.err_msg = null; |
| 737 | 937 | } |
| 738 | | try stderr.print("{s}\n", .{lower.err_msg.?.msg}); |
| 938 | try writer.writeAll(lower.err_msg.?.msg); |
| 739 | 939 | return; |
| 740 | 940 | }, |
| 741 | | error.InvalidInstruction, error.CannotEncode => |e| { |
| 742 | | try stderr.writeAll(switch (e) { |
| 743 | | error.InvalidInstruction => "CodeGen failed to find a viable instruction.\n", |
| 744 | | error.CannotEncode => "CodeGen failed to encode the instruction.\n", |
| 941 | error.OutOfMemory, error.InvalidInstruction, error.CannotEncode => |e| { |
| 942 | try writer.writeAll(switch (e) { |
| 943 | error.OutOfMemory => "Out of memory", |
| 944 | error.InvalidInstruction => "CodeGen failed to find a viable instruction.", |
| 945 | error.CannotEncode => "CodeGen failed to encode the instruction.", |
| 745 | 946 | }); |
| 746 | 947 | return; |
| 747 | 948 | }, |
| 748 | 949 | else => |e| return e, |
| 749 | | }) |lower_inst| { |
| 750 | | try stderr.print(" | {}\n", .{lower_inst}); |
| 751 | | } |
| 950 | }) |lower_inst| try writer.print(" | {}", .{lower_inst}); |
| 951 | } |
| 952 | fn fmtWipMir(self: *Self, inst: Mir.Inst.Index) std.fmt.Formatter(formatWipMir) { |
| 953 | return .{ .data = .{ .self = self, .inst = inst } }; |
| 752 | 954 | } |
| 753 | 955 | |
| 754 | | fn dumpTracking(self: *Self) !void { |
| 755 | | if (!debug_tracking) return; |
| 756 | | const stderr = std.io.getStdErr().writer(); |
| 757 | | |
| 758 | | var it = self.inst_tracking.iterator(); |
| 759 | | while (it.next()) |entry| try stderr.print("%{d} = {}\n", .{ entry.key_ptr.*, entry.value_ptr.* }); |
| 956 | const FormatTrackingData = struct { |
| 957 | self: *Self, |
| 958 | }; |
| 959 | fn formatTracking( |
| 960 | data: FormatTrackingData, |
| 961 | comptime _: []const u8, |
| 962 | _: std.fmt.FormatOptions, |
| 963 | writer: anytype, |
| 964 | ) @TypeOf(writer).Error!void { |
| 965 | var it = data.self.inst_tracking.iterator(); |
| 966 | while (it.next()) |entry| try writer.print("\n%{d} = {}", .{ entry.key_ptr.*, entry.value_ptr.* }); |
| 967 | } |
| 968 | fn fmtTracking(self: *Self) std.fmt.Formatter(formatTracking) { |
| 969 | return .{ .data = .{ .self = self } }; |
| 760 | 970 | } |
| 761 | 971 | |
| 762 | 972 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| ... | ... | @@ -764,7 +974,14 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 764 | 974 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); |
| 765 | 975 | const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len); |
| 766 | 976 | self.mir_instructions.appendAssumeCapacity(inst); |
| 767 | | self.dumpWipMir(inst) catch {}; |
| 977 | switch (inst.tag) { |
| 978 | else => wip_mir_log.debug("{}", .{self.fmtWipMir(result_index)}), |
| 979 | .dbg_line, |
| 980 | .dbg_prologue_end, |
| 981 | .dbg_epilogue_begin, |
| 982 | .dead, |
| 983 | => {}, |
| 984 | } |
| 768 | 985 | return result_index; |
| 769 | 986 | } |
| 770 | 987 | |
| ... | ... | @@ -1186,13 +1403,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1186 | 1403 | } |
| 1187 | 1404 | |
| 1188 | 1405 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue; |
| 1189 | | if (debug_wip_mir) @import("../../print_air.zig").dumpInst( |
| 1190 | | inst, |
| 1191 | | self.bin_file.options.module.?, |
| 1192 | | self.air, |
| 1193 | | self.liveness, |
| 1194 | | ); |
| 1195 | | self.dumpTracking() catch {}; |
| 1406 | wip_mir_log.debug("{}", .{self.fmtAir(inst)}); |
| 1407 | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); |
| 1196 | 1408 | |
| 1197 | 1409 | const old_air_bookkeeping = self.air_bookkeeping; |
| 1198 | 1410 | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); |
| ... | ... | @@ -1244,9 +1456,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1244 | 1456 | .ceil, |
| 1245 | 1457 | .round, |
| 1246 | 1458 | .trunc_float, |
| 1247 | | .neg, |
| 1248 | 1459 | => try self.airUnaryMath(inst), |
| 1249 | 1460 | |
| 1461 | .neg => try self.airNeg(inst), |
| 1462 | |
| 1250 | 1463 | .add_with_overflow => try self.airAddSubWithOverflow(inst), |
| 1251 | 1464 | .sub_with_overflow => try self.airAddSubWithOverflow(inst), |
| 1252 | 1465 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| ... | ... | @@ -1453,7 +1666,69 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1453 | 1666 | } |
| 1454 | 1667 | } |
| 1455 | 1668 | } |
| 1456 | | self.dumpTracking() catch {}; |
| 1669 | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); |
| 1670 | } |
| 1671 | |
| 1672 | fn genLazy(self: *Self, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 1673 | switch (lazy_sym.ty.zigTypeTag()) { |
| 1674 | .Enum => { |
| 1675 | const enum_ty = lazy_sym.ty; |
| 1676 | wip_mir_log.debug("{}.@tagName:", .{enum_ty.fmt(self.bin_file.options.module.?)}); |
| 1677 | |
| 1678 | const param_regs = abi.getCAbiIntParamRegs(self.target.*); |
| 1679 | const param_locks = self.register_manager.lockRegsAssumeUnused(2, param_regs[0..2].*); |
| 1680 | defer for (param_locks) |lock| self.register_manager.unlockReg(lock); |
| 1681 | |
| 1682 | const ret_reg = param_regs[0]; |
| 1683 | const enum_mcv = MCValue{ .register = param_regs[1] }; |
| 1684 | |
| 1685 | var exitlude_jump_relocs = try self.gpa.alloc(u32, enum_ty.enumFieldCount()); |
| 1686 | defer self.gpa.free(exitlude_jump_relocs); |
| 1687 | |
| 1688 | const data_reg = try self.register_manager.allocReg(null, gp); |
| 1689 | const data_lock = self.register_manager.lockRegAssumeUnused(data_reg); |
| 1690 | defer self.register_manager.unlockReg(data_lock); |
| 1691 | try self.genLazySymbolRef(.lea, data_reg, .{ .kind = .const_data, .ty = enum_ty }); |
| 1692 | |
| 1693 | var data_off: i32 = 0; |
| 1694 | for ( |
| 1695 | exitlude_jump_relocs, |
| 1696 | enum_ty.enumFields().keys(), |
| 1697 | 0.., |
| 1698 | ) |*exitlude_jump_reloc, tag_name, index| { |
| 1699 | var tag_pl = Value.Payload.U32{ |
| 1700 | .base = .{ .tag = .enum_field_index }, |
| 1701 | .data = @intCast(u32, index), |
| 1702 | }; |
| 1703 | const tag_val = Value.initPayload(&tag_pl.base); |
| 1704 | const tag_mcv = try self.genTypedValue(.{ .ty = enum_ty, .val = tag_val }); |
| 1705 | try self.genBinOpMir(.cmp, enum_ty, enum_mcv, tag_mcv); |
| 1706 | const skip_reloc = try self.asmJccReloc(undefined, .ne); |
| 1707 | |
| 1708 | try self.genSetMem( |
| 1709 | .{ .reg = ret_reg }, |
| 1710 | 0, |
| 1711 | Type.usize, |
| 1712 | .{ .register_offset = .{ .reg = data_reg, .off = data_off } }, |
| 1713 | ); |
| 1714 | try self.genSetMem(.{ .reg = ret_reg }, 8, Type.usize, .{ .immediate = tag_name.len }); |
| 1715 | |
| 1716 | exitlude_jump_reloc.* = try self.asmJmpReloc(undefined); |
| 1717 | try self.performReloc(skip_reloc); |
| 1718 | |
| 1719 | data_off += @intCast(i32, tag_name.len + 1); |
| 1720 | } |
| 1721 | |
| 1722 | try self.airTrap(); |
| 1723 | |
| 1724 | for (exitlude_jump_relocs) |reloc| try self.performReloc(reloc); |
| 1725 | try self.asmOpOnly(.ret); |
| 1726 | }, |
| 1727 | else => return self.fail( |
| 1728 | "TODO implement {s} for {}", |
| 1729 | .{ @tagName(lazy_sym.kind), lazy_sym.ty.fmt(self.bin_file.options.module.?) }, |
| 1730 | ), |
| 1731 | } |
| 1457 | 1732 | } |
| 1458 | 1733 | |
| 1459 | 1734 | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { |
| ... | ... | @@ -1619,15 +1894,16 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 1619 | 1894 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 1620 | 1895 | const frame_size = frame_allocs_slice.items(.abi_size); |
| 1621 | 1896 | const frame_align = frame_allocs_slice.items(.abi_align); |
| 1897 | |
| 1898 | const stack_frame_align = &frame_align[@enumToInt(FrameIndex.stack_frame)]; |
| 1899 | stack_frame_align.* = @max(stack_frame_align.*, alloc.abi_align); |
| 1900 | |
| 1622 | 1901 | for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { |
| 1623 | 1902 | const abi_size = frame_size[@enumToInt(frame_index)]; |
| 1624 | 1903 | if (abi_size != alloc.abi_size) continue; |
| 1625 | 1904 | const abi_align = &frame_align[@enumToInt(frame_index)]; |
| 1626 | 1905 | abi_align.* = @max(abi_align.*, alloc.abi_align); |
| 1627 | 1906 | |
| 1628 | | const stack_frame_align = &frame_align[@enumToInt(FrameIndex.stack_frame)]; |
| 1629 | | stack_frame_align.* = @max(stack_frame_align.*, alloc.abi_align); |
| 1630 | | |
| 1631 | 1907 | _ = self.free_frame_indices.swapRemoveAt(free_i); |
| 1632 | 1908 | return frame_index; |
| 1633 | 1909 | } |
| ... | ... | @@ -1828,7 +2104,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void { |
| 1828 | 2104 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 1829 | 2105 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 1830 | 2106 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { |
| 1831 | | const reg: Register = try self.register_manager.allocReg(null, try self.regClassForType(ty)); |
| 2107 | const reg = try self.register_manager.allocReg(null, try self.regClassForType(ty)); |
| 1832 | 2108 | try self.genSetReg(reg, ty, mcv); |
| 1833 | 2109 | return reg; |
| 1834 | 2110 | } |
| ... | ... | @@ -1871,16 +2147,48 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1871 | 2147 | |
| 1872 | 2148 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1873 | 2149 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1874 | | _ = ty_op; |
| 1875 | | return self.fail("TODO implement airFptrunc for {}", .{self.target.cpu.arch}); |
| 1876 | | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2150 | const dst_ty = self.air.typeOfIndex(inst); |
| 2151 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2152 | if (dst_ty.floatBits(self.target.*) != 32 or src_ty.floatBits(self.target.*) != 64 or |
| 2153 | !Target.x86.featureSetHas(self.target.cpu.features, .sse2)) |
| 2154 | return self.fail("TODO implement airFptrunc from {} to {}", .{ |
| 2155 | src_ty.fmt(self.bin_file.options.module.?), |
| 2156 | dst_ty.fmt(self.bin_file.options.module.?), |
| 2157 | }); |
| 2158 | |
| 2159 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2160 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2161 | src_mcv |
| 2162 | else |
| 2163 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 2164 | const dst_lock = self.register_manager.lockReg(dst_mcv.register); |
| 2165 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2166 | |
| 2167 | try self.genBinOpMir(.cvtsd2ss, src_ty, dst_mcv, src_mcv); |
| 2168 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 1877 | 2169 | } |
| 1878 | 2170 | |
| 1879 | 2171 | fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 1880 | 2172 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1881 | | _ = ty_op; |
| 1882 | | return self.fail("TODO implement airFpext for {}", .{self.target.cpu.arch}); |
| 1883 | | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 2173 | const dst_ty = self.air.typeOfIndex(inst); |
| 2174 | const src_ty = self.air.typeOf(ty_op.operand); |
| 2175 | if (dst_ty.floatBits(self.target.*) != 64 or src_ty.floatBits(self.target.*) != 32 or |
| 2176 | !Target.x86.featureSetHas(self.target.cpu.features, .sse2)) |
| 2177 | return self.fail("TODO implement airFpext from {} to {}", .{ |
| 2178 | src_ty.fmt(self.bin_file.options.module.?), |
| 2179 | dst_ty.fmt(self.bin_file.options.module.?), |
| 2180 | }); |
| 2181 | |
| 2182 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 2183 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) |
| 2184 | src_mcv |
| 2185 | else |
| 2186 | try self.copyToRegisterWithInstTracking(inst, dst_ty, src_mcv); |
| 2187 | const dst_lock = self.register_manager.lockReg(dst_mcv.register); |
| 2188 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 2189 | |
| 2190 | try self.genBinOpMir(.cvtss2sd, src_ty, dst_mcv, src_mcv); |
| 2191 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 1884 | 2192 | } |
| 1885 | 2193 | |
| 1886 | 2194 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -1928,13 +2236,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1928 | 2236 | registerAlias(src_reg, min_abi_size), |
| 1929 | 2237 | ); |
| 1930 | 2238 | }, |
| 1931 | | .load_frame => |frame_addr| try self.asmRegisterMemory( |
| 2239 | .memory, .indirect, .load_frame => try self.asmRegisterMemory( |
| 1932 | 2240 | tag, |
| 1933 | 2241 | dst_alias, |
| 1934 | | Memory.sib(Memory.PtrSize.fromSize(min_abi_size), .{ |
| 1935 | | .base = .{ .frame = frame_addr.index }, |
| 1936 | | .disp = frame_addr.off, |
| 1937 | | }), |
| 2242 | src_mcv.mem(Memory.PtrSize.fromSize(min_abi_size)), |
| 1938 | 2243 | ), |
| 1939 | 2244 | else => return self.fail("TODO airIntCast from {s} to {s}", .{ |
| 1940 | 2245 | @tagName(src_mcv), |
| ... | ... | @@ -2102,6 +2407,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2102 | 2407 | } }; |
| 2103 | 2408 | const src_ty = Type.initPayload(&src_pl.base); |
| 2104 | 2409 | |
| 2410 | try self.spillEflagsIfOccupied(); |
| 2105 | 2411 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 2106 | 2412 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2107 | 2413 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -2315,12 +2621,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2315 | 2621 | |
| 2316 | 2622 | const frame_index = |
| 2317 | 2623 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); |
| 2318 | | try self.genSetFrameTruncatedOverflowCompare( |
| 2319 | | tuple_ty, |
| 2320 | | frame_index, |
| 2321 | | partial_mcv.register, |
| 2322 | | cc, |
| 2323 | | ); |
| 2624 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 2324 | 2625 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 2325 | 2626 | }, |
| 2326 | 2627 | else => unreachable, |
| ... | ... | @@ -2392,12 +2693,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2392 | 2693 | |
| 2393 | 2694 | const frame_index = |
| 2394 | 2695 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); |
| 2395 | | try self.genSetFrameTruncatedOverflowCompare( |
| 2396 | | tuple_ty, |
| 2397 | | frame_index, |
| 2398 | | partial_mcv.register, |
| 2399 | | cc, |
| 2400 | | ); |
| 2696 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 2401 | 2697 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 2402 | 2698 | }, |
| 2403 | 2699 | else => unreachable, |
| ... | ... | @@ -2410,173 +2706,175 @@ fn genSetFrameTruncatedOverflowCompare( |
| 2410 | 2706 | self: *Self, |
| 2411 | 2707 | tuple_ty: Type, |
| 2412 | 2708 | frame_index: FrameIndex, |
| 2413 | | reg: Register, |
| 2414 | | cc: Condition, |
| 2709 | src_mcv: MCValue, |
| 2710 | overflow_cc: ?Condition, |
| 2415 | 2711 | ) !void { |
| 2416 | | const reg_lock = self.register_manager.lockReg(reg); |
| 2417 | | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 2712 | const src_lock = switch (src_mcv) { |
| 2713 | .register => |reg| self.register_manager.lockReg(reg), |
| 2714 | else => null, |
| 2715 | }; |
| 2716 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 2418 | 2717 | |
| 2419 | 2718 | const ty = tuple_ty.structFieldType(0); |
| 2420 | 2719 | const int_info = ty.intInfo(self.target.*); |
| 2421 | | const extended_ty = switch (int_info.signedness) { |
| 2422 | | .signed => Type.isize, |
| 2423 | | .unsigned => ty, |
| 2720 | |
| 2721 | var hi_limb_pl = Type.Payload.Bits{ |
| 2722 | .base = .{ .tag = switch (int_info.signedness) { |
| 2723 | .signed => .int_signed, |
| 2724 | .unsigned => .int_unsigned, |
| 2725 | } }, |
| 2726 | .data = (int_info.bits - 1) % 64 + 1, |
| 2424 | 2727 | }; |
| 2728 | const hi_limb_ty = Type.initPayload(&hi_limb_pl.base); |
| 2425 | 2729 | |
| 2426 | | const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp); |
| 2427 | | const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); |
| 2428 | | defer for (temp_regs_locks) |rreg| { |
| 2429 | | self.register_manager.unlockReg(rreg); |
| 2730 | var rest_pl = Type.Payload.Bits{ |
| 2731 | .base = .{ .tag = .int_unsigned }, |
| 2732 | .data = int_info.bits - hi_limb_pl.data, |
| 2430 | 2733 | }; |
| 2734 | const rest_ty = Type.initPayload(&rest_pl.base); |
| 2735 | |
| 2736 | const temp_regs = try self.register_manager.allocRegs(3, .{ null, null, null }, gp); |
| 2737 | const temp_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); |
| 2738 | defer for (temp_locks) |lock| self.register_manager.unlockReg(lock); |
| 2431 | 2739 | |
| 2432 | 2740 | const overflow_reg = temp_regs[0]; |
| 2433 | | try self.asmSetccRegister(overflow_reg.to8(), cc); |
| 2741 | if (overflow_cc) |cc| try self.asmSetccRegister(overflow_reg.to8(), cc); |
| 2434 | 2742 | |
| 2435 | 2743 | const scratch_reg = temp_regs[1]; |
| 2436 | | try self.genSetReg(scratch_reg, extended_ty, .{ .register = reg }); |
| 2437 | | try self.truncateRegister(ty, scratch_reg); |
| 2438 | | try self.genBinOpMir( |
| 2439 | | .cmp, |
| 2440 | | extended_ty, |
| 2441 | | .{ .register = reg }, |
| 2442 | | .{ .register = scratch_reg }, |
| 2443 | | ); |
| 2744 | const hi_limb_off = if (int_info.bits <= 64) 0 else (int_info.bits - 1) / 64 * 8; |
| 2745 | const hi_limb_mcv = if (hi_limb_off > 0) |
| 2746 | src_mcv.address().offset(int_info.bits / 64 * 8).deref() |
| 2747 | else |
| 2748 | src_mcv; |
| 2749 | try self.genSetReg(scratch_reg, hi_limb_ty, hi_limb_mcv); |
| 2750 | try self.truncateRegister(hi_limb_ty, scratch_reg); |
| 2751 | try self.genBinOpMir(.cmp, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv); |
| 2444 | 2752 | |
| 2445 | 2753 | const eq_reg = temp_regs[2]; |
| 2446 | | try self.asmSetccRegister(eq_reg.to8(), .ne); |
| 2447 | | try self.genBinOpMir( |
| 2448 | | .@"or", |
| 2449 | | Type.u8, |
| 2450 | | .{ .register = overflow_reg }, |
| 2451 | | .{ .register = eq_reg }, |
| 2452 | | ); |
| 2754 | if (overflow_cc) |_| { |
| 2755 | try self.asmSetccRegister(eq_reg.to8(), .ne); |
| 2756 | try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg }); |
| 2757 | } |
| 2453 | 2758 | |
| 2759 | const payload_off = @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)); |
| 2760 | if (hi_limb_off > 0) try self.genSetMem(.{ .frame = frame_index }, payload_off, rest_ty, src_mcv); |
| 2454 | 2761 | try self.genSetMem( |
| 2455 | 2762 | .{ .frame = frame_index }, |
| 2456 | | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), |
| 2457 | | tuple_ty.structFieldType(1), |
| 2458 | | .{ .register = overflow_reg.to8() }, |
| 2763 | payload_off + hi_limb_off, |
| 2764 | hi_limb_ty, |
| 2765 | .{ .register = scratch_reg }, |
| 2459 | 2766 | ); |
| 2460 | 2767 | try self.genSetMem( |
| 2461 | 2768 | .{ .frame = frame_index }, |
| 2462 | | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), |
| 2463 | | ty, |
| 2464 | | .{ .register = scratch_reg }, |
| 2769 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), |
| 2770 | tuple_ty.structFieldType(1), |
| 2771 | if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne }, |
| 2465 | 2772 | ); |
| 2466 | 2773 | } |
| 2467 | 2774 | |
| 2468 | 2775 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2469 | 2776 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2470 | 2777 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2471 | | const result: MCValue = result: { |
| 2472 | | const dst_ty = self.air.typeOf(bin_op.lhs); |
| 2473 | | switch (dst_ty.zigTypeTag()) { |
| 2474 | | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 2475 | | .Int => { |
| 2476 | | try self.spillEflagsIfOccupied(); |
| 2778 | const dst_ty = self.air.typeOf(bin_op.lhs); |
| 2779 | const result: MCValue = switch (dst_ty.zigTypeTag()) { |
| 2780 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 2781 | .Int => result: { |
| 2782 | try self.spillEflagsIfOccupied(); |
| 2783 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 2477 | 2784 | |
| 2478 | | const dst_info = dst_ty.intInfo(self.target.*); |
| 2479 | | const cc: Condition = switch (dst_info.signedness) { |
| 2480 | | .unsigned => .c, |
| 2481 | | .signed => .o, |
| 2785 | const dst_info = dst_ty.intInfo(self.target.*); |
| 2786 | const cc: Condition = switch (dst_info.signedness) { |
| 2787 | .unsigned => .c, |
| 2788 | .signed => .o, |
| 2789 | }; |
| 2790 | |
| 2791 | const lhs_active_bits = self.activeIntBits(bin_op.lhs); |
| 2792 | const rhs_active_bits = self.activeIntBits(bin_op.rhs); |
| 2793 | var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { |
| 2794 | .signed => .int_signed, |
| 2795 | .unsigned => .int_unsigned, |
| 2796 | } }, .data = math.max3(lhs_active_bits, rhs_active_bits, dst_info.bits / 2) }; |
| 2797 | const src_ty = Type.initPayload(&src_pl.base); |
| 2798 | |
| 2799 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2800 | const rhs = try self.resolveInst(bin_op.rhs); |
| 2801 | |
| 2802 | const tuple_ty = self.air.typeOfIndex(inst); |
| 2803 | const extra_bits = if (dst_info.bits <= 64) |
| 2804 | self.regExtraBits(dst_ty) |
| 2805 | else |
| 2806 | dst_info.bits % 64; |
| 2807 | const partial_mcv = if (dst_info.signedness == .signed and extra_bits > 0) dst: { |
| 2808 | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 2809 | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2810 | else => null, |
| 2482 | 2811 | }; |
| 2812 | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2483 | 2813 | |
| 2484 | | const tuple_ty = self.air.typeOfIndex(inst); |
| 2485 | | if (dst_info.bits >= 8 and math.isPowerOfTwo(dst_info.bits)) { |
| 2486 | | var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { |
| 2487 | | .signed => .int_signed, |
| 2488 | | .unsigned => .int_unsigned, |
| 2489 | | } }, .data = math.max3( |
| 2490 | | self.activeIntBits(bin_op.lhs), |
| 2491 | | self.activeIntBits(bin_op.rhs), |
| 2492 | | dst_info.bits / 2, |
| 2493 | | ) }; |
| 2494 | | const src_ty = Type.initPayload(&src_pl.base); |
| 2814 | const dst_reg: Register = blk: { |
| 2815 | if (lhs.isRegister()) break :blk lhs.register; |
| 2816 | break :blk try self.copyToTmpRegister(dst_ty, lhs); |
| 2817 | }; |
| 2818 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 2819 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 2820 | defer self.register_manager.unlockReg(dst_reg_lock); |
| 2495 | 2821 | |
| 2496 | | try self.spillRegisters(&.{ .rax, .rdx }); |
| 2497 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 2498 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 2822 | const rhs_mcv: MCValue = blk: { |
| 2823 | if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; |
| 2824 | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; |
| 2825 | }; |
| 2826 | const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { |
| 2827 | .register => |reg| self.register_manager.lockReg(reg), |
| 2828 | else => null, |
| 2829 | }; |
| 2830 | defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 2499 | 2831 | |
| 2500 | | const partial_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs); |
| 2501 | | switch (partial_mcv) { |
| 2502 | | .register => |reg| { |
| 2503 | | self.eflags_inst = inst; |
| 2504 | | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; |
| 2505 | | }, |
| 2506 | | else => {}, |
| 2507 | | } |
| 2832 | try self.genIntMulComplexOpMir(Type.isize, dst_mcv, rhs_mcv); |
| 2833 | break :dst dst_mcv; |
| 2834 | } else try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs); |
| 2508 | 2835 | |
| 2509 | | // For now, this is the only supported multiply that doesn't fit in a register. |
| 2510 | | assert(dst_info.bits == 128 and src_pl.data == 64); |
| 2836 | switch (partial_mcv) { |
| 2837 | .register => |reg| if (extra_bits == 0) { |
| 2838 | self.eflags_inst = inst; |
| 2839 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; |
| 2840 | } else { |
| 2511 | 2841 | const frame_index = |
| 2512 | 2842 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); |
| 2513 | | try self.genSetMem( |
| 2514 | | .{ .frame = frame_index }, |
| 2515 | | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), |
| 2516 | | tuple_ty.structFieldType(1), |
| 2517 | | .{ .immediate = 0 }, // overflow is impossible for 64-bit*64-bit -> 128-bit |
| 2518 | | ); |
| 2519 | | try self.genSetMem( |
| 2520 | | .{ .frame = frame_index }, |
| 2521 | | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), |
| 2522 | | tuple_ty.structFieldType(0), |
| 2523 | | partial_mcv, |
| 2524 | | ); |
| 2843 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 2525 | 2844 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 2526 | | } |
| 2527 | | |
| 2528 | | const dst_reg: Register = dst_reg: { |
| 2529 | | switch (dst_info.signedness) { |
| 2530 | | .signed => { |
| 2531 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 2532 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 2533 | | |
| 2534 | | const rhs_lock: ?RegisterLock = switch (rhs) { |
| 2535 | | .register => |reg| self.register_manager.lockRegAssumeUnused(reg), |
| 2536 | | else => null, |
| 2537 | | }; |
| 2538 | | defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock); |
| 2539 | | |
| 2540 | | const dst_reg: Register = blk: { |
| 2541 | | if (lhs.isRegister()) break :blk lhs.register; |
| 2542 | | break :blk try self.copyToTmpRegister(dst_ty, lhs); |
| 2543 | | }; |
| 2544 | | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 2545 | | defer self.register_manager.unlockReg(dst_reg_lock); |
| 2546 | | |
| 2547 | | const rhs_mcv: MCValue = blk: { |
| 2548 | | if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; |
| 2549 | | break :blk MCValue{ .register = try self.copyToTmpRegister(dst_ty, rhs) }; |
| 2550 | | }; |
| 2551 | | const rhs_mcv_lock: ?RegisterLock = switch (rhs_mcv) { |
| 2552 | | .register => |reg| self.register_manager.lockReg(reg), |
| 2553 | | else => null, |
| 2554 | | }; |
| 2555 | | defer if (rhs_mcv_lock) |lock| self.register_manager.unlockReg(lock); |
| 2556 | | |
| 2557 | | try self.genIntMulComplexOpMir(Type.isize, .{ .register = dst_reg }, rhs_mcv); |
| 2558 | | |
| 2559 | | break :dst_reg dst_reg; |
| 2560 | | }, |
| 2561 | | .unsigned => { |
| 2562 | | try self.spillRegisters(&.{ .rax, .rdx }); |
| 2563 | | |
| 2564 | | const lhs = try self.resolveInst(bin_op.lhs); |
| 2565 | | const rhs = try self.resolveInst(bin_op.rhs); |
| 2845 | }, |
| 2846 | else => { |
| 2847 | // For now, this is the only supported multiply that doesn't fit in a register, |
| 2848 | // so cc being set is impossible. |
| 2566 | 2849 | |
| 2567 | | const dst_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, dst_ty, lhs, rhs); |
| 2568 | | break :dst_reg dst_mcv.register; |
| 2569 | | }, |
| 2570 | | } |
| 2571 | | }; |
| 2850 | assert(dst_info.bits <= 128 and src_pl.data == 64); |
| 2572 | 2851 | |
| 2573 | | const frame_index = |
| 2574 | | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); |
| 2575 | | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, dst_reg, cc); |
| 2576 | | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 2577 | | }, |
| 2578 | | else => unreachable, |
| 2579 | | } |
| 2852 | const frame_index = |
| 2853 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); |
| 2854 | if (dst_info.bits >= lhs_active_bits + rhs_active_bits) { |
| 2855 | try self.genSetMem( |
| 2856 | .{ .frame = frame_index }, |
| 2857 | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), |
| 2858 | tuple_ty.structFieldType(0), |
| 2859 | partial_mcv, |
| 2860 | ); |
| 2861 | try self.genSetMem( |
| 2862 | .{ .frame = frame_index }, |
| 2863 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), |
| 2864 | tuple_ty.structFieldType(1), |
| 2865 | .{ .immediate = 0 }, |
| 2866 | ); |
| 2867 | } else try self.genSetFrameTruncatedOverflowCompare( |
| 2868 | tuple_ty, |
| 2869 | frame_index, |
| 2870 | partial_mcv, |
| 2871 | null, |
| 2872 | ); |
| 2873 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 2874 | }, |
| 2875 | } |
| 2876 | }, |
| 2877 | else => unreachable, |
| 2580 | 2878 | }; |
| 2581 | 2879 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2582 | 2880 | } |
| ... | ... | @@ -2616,19 +2914,9 @@ fn genIntMulDivOpMir( |
| 2616 | 2914 | }; |
| 2617 | 2915 | switch (mat_rhs) { |
| 2618 | 2916 | .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)), |
| 2619 | | .indirect, .load_frame => try self.asmMemory( |
| 2917 | .memory, .indirect, .load_frame => try self.asmMemory( |
| 2620 | 2918 | tag, |
| 2621 | | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) { |
| 2622 | | .indirect => |reg_off| .{ |
| 2623 | | .base = .{ .reg = reg_off.reg }, |
| 2624 | | .disp = reg_off.off, |
| 2625 | | }, |
| 2626 | | .load_frame => |frame_addr| .{ |
| 2627 | | .base = .{ .frame = frame_addr.index }, |
| 2628 | | .disp = frame_addr.off, |
| 2629 | | }, |
| 2630 | | else => unreachable, |
| 2631 | | }), |
| 2919 | mat_rhs.mem(Memory.PtrSize.fromSize(abi_size)), |
| 2632 | 2920 | ), |
| 2633 | 2921 | else => unreachable, |
| 2634 | 2922 | } |
| ... | ... | @@ -3900,10 +4188,65 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 3900 | 4188 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 3901 | 4189 | } |
| 3902 | 4190 | |
| 4191 | fn airNeg(self: *Self, inst: Air.Inst.Index) !void { |
| 4192 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 4193 | const ty = self.air.typeOf(un_op); |
| 4194 | const ty_bits = ty.floatBits(self.target.*); |
| 4195 | |
| 4196 | var arena = std.heap.ArenaAllocator.init(self.gpa); |
| 4197 | defer arena.deinit(); |
| 4198 | |
| 4199 | const ExpectedContents = union { |
| 4200 | f16: Value.Payload.Float_16, |
| 4201 | f32: Value.Payload.Float_32, |
| 4202 | f64: Value.Payload.Float_64, |
| 4203 | f80: Value.Payload.Float_80, |
| 4204 | f128: Value.Payload.Float_128, |
| 4205 | }; |
| 4206 | var stack align(@alignOf(ExpectedContents)) = |
| 4207 | std.heap.stackFallback(@sizeOf(ExpectedContents), arena.allocator()); |
| 4208 | |
| 4209 | var vec_pl = Type.Payload.Array{ |
| 4210 | .base = .{ .tag = .vector }, |
| 4211 | .data = .{ |
| 4212 | .len = @divExact(128, ty_bits), |
| 4213 | .elem_type = ty, |
| 4214 | }, |
| 4215 | }; |
| 4216 | const vec_ty = Type.initPayload(&vec_pl.base); |
| 4217 | |
| 4218 | var sign_pl = Value.Payload.SubValue{ |
| 4219 | .base = .{ .tag = .repeated }, |
| 4220 | .data = try Value.floatToValue(-0.0, stack.get(), ty, self.target.*), |
| 4221 | }; |
| 4222 | const sign_val = Value.initPayload(&sign_pl.base); |
| 4223 | |
| 4224 | const sign_mcv = try self.genTypedValue(.{ .ty = vec_ty, .val = sign_val }); |
| 4225 | |
| 4226 | const src_mcv = try self.resolveInst(un_op); |
| 4227 | const dst_mcv = if (src_mcv.isRegister() and self.reuseOperand(inst, un_op, 0, src_mcv)) |
| 4228 | src_mcv |
| 4229 | else |
| 4230 | try self.copyToRegisterWithInstTracking(inst, ty, src_mcv); |
| 4231 | const dst_lock = self.register_manager.lockReg(dst_mcv.register); |
| 4232 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 4233 | |
| 4234 | try self.genBinOpMir(switch (ty_bits) { |
| 4235 | 32 => .xorps, |
| 4236 | 64 => .xorpd, |
| 4237 | else => return self.fail("TODO implement airNeg for {}", .{ |
| 4238 | ty.fmt(self.bin_file.options.module.?), |
| 4239 | }), |
| 4240 | }, vec_ty, dst_mcv, sign_mcv); |
| 4241 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 4242 | } |
| 4243 | |
| 3903 | 4244 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { |
| 3904 | 4245 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 3905 | 4246 | _ = un_op; |
| 3906 | | return self.fail("TODO implement airUnaryMath for {}", .{self.target.cpu.arch}); |
| 4247 | return self.fail("TODO implement airUnaryMath for {}", .{ |
| 4248 | self.air.instructions.items(.tag)[inst], |
| 4249 | }); |
| 3907 | 4250 | //return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 3908 | 4251 | } |
| 3909 | 4252 | |
| ... | ... | @@ -4056,7 +4399,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 4056 | 4399 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4057 | 4400 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4058 | 4401 | const elem_ty = self.air.typeOfIndex(inst); |
| 4059 | | const elem_size = elem_ty.abiSize(self.target.*); |
| 4060 | 4402 | const result: MCValue = result: { |
| 4061 | 4403 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; |
| 4062 | 4404 | |
| ... | ... | @@ -4064,14 +4406,20 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4064 | 4406 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx }); |
| 4065 | 4407 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); |
| 4066 | 4408 | |
| 4409 | const ptr_ty = self.air.typeOf(ty_op.operand); |
| 4410 | const elem_size = elem_ty.abiSize(self.target.*); |
| 4411 | |
| 4412 | const elem_rc = try self.regClassForType(elem_ty); |
| 4413 | const ptr_rc = try self.regClassForType(ptr_ty); |
| 4414 | |
| 4067 | 4415 | const ptr_mcv = try self.resolveInst(ty_op.operand); |
| 4068 | | const dst_mcv = if (elem_size <= 8 and self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv)) |
| 4416 | const dst_mcv = if (elem_size <= 8 and elem_rc.supersetOf(ptr_rc) and |
| 4417 | self.reuseOperand(inst, ty_op.operand, 0, ptr_mcv)) |
| 4069 | 4418 | // The MCValue that holds the pointer can be re-used as the value. |
| 4070 | 4419 | ptr_mcv |
| 4071 | 4420 | else |
| 4072 | 4421 | try self.allocRegOrMem(inst, true); |
| 4073 | 4422 | |
| 4074 | | const ptr_ty = self.air.typeOf(ty_op.operand); |
| 4075 | 4423 | if (ptr_ty.ptrInfo().data.host_size > 0) { |
| 4076 | 4424 | try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv); |
| 4077 | 4425 | } else { |
| ... | ... | @@ -4293,17 +4641,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4293 | 4641 | |
| 4294 | 4642 | switch (src_mcv) { |
| 4295 | 4643 | .load_frame => |frame_addr| { |
| 4296 | | const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*)); |
| 4297 | | const limb_abi_size = @min(field_abi_size, 8); |
| 4298 | | const limb_abi_bits = limb_abi_size * 8; |
| 4299 | | const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size); |
| 4300 | | const field_bit_off = field_off % limb_abi_bits; |
| 4301 | | |
| 4302 | | if (field_bit_off == 0) { |
| 4303 | | const off_mcv = MCValue{ .load_frame = .{ |
| 4304 | | .index = frame_addr.index, |
| 4305 | | .off = frame_addr.off + field_byte_off, |
| 4306 | | } }; |
| 4644 | if (field_off % 8 == 0) { |
| 4645 | const off_mcv = |
| 4646 | src_mcv.address().offset(@intCast(i32, @divExact(field_off, 8))).deref(); |
| 4307 | 4647 | if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result off_mcv; |
| 4308 | 4648 | |
| 4309 | 4649 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| ... | ... | @@ -4311,6 +4651,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4311 | 4651 | break :result dst_mcv; |
| 4312 | 4652 | } |
| 4313 | 4653 | |
| 4654 | const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*)); |
| 4655 | const limb_abi_size = @min(field_abi_size, 8); |
| 4656 | const limb_abi_bits = limb_abi_size * 8; |
| 4657 | const field_byte_off = @intCast(i32, field_off / limb_abi_bits * limb_abi_size); |
| 4658 | const field_bit_off = field_off % limb_abi_bits; |
| 4659 | |
| 4314 | 4660 | if (field_abi_size > 8) { |
| 4315 | 4661 | return self.fail("TODO implement struct_field_val with large packed field", .{}); |
| 4316 | 4662 | } |
| ... | ... | @@ -4448,9 +4794,6 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 4448 | 4794 | if (src_ty.zigTypeTag() == .Vector) { |
| 4449 | 4795 | return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); |
| 4450 | 4796 | } |
| 4451 | | if (src_ty.abiSize(self.target.*) > 8) { |
| 4452 | | return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); |
| 4453 | | } |
| 4454 | 4797 | |
| 4455 | 4798 | switch (src_mcv) { |
| 4456 | 4799 | .eflags => |cc| switch (tag) { |
| ... | ... | @@ -4466,13 +4809,13 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 4466 | 4809 | }; |
| 4467 | 4810 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 4468 | 4811 | |
| 4469 | | const dst_mcv: MCValue = if (maybe_inst) |inst| |
| 4470 | | if (self.reuseOperand(inst, src_air, 0, src_mcv)) |
| 4471 | | src_mcv |
| 4472 | | else |
| 4473 | | try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv) |
| 4474 | | else |
| 4475 | | .{ .register = try self.copyToTmpRegister(src_ty, src_mcv) }; |
| 4812 | const dst_mcv: MCValue = dst: { |
| 4813 | if (maybe_inst) |inst| if (self.reuseOperand(inst, src_air, 0, src_mcv)) break :dst src_mcv; |
| 4814 | |
| 4815 | const dst_mcv = try self.allocRegOrMemAdvanced(src_ty, maybe_inst, true); |
| 4816 | try self.genCopy(src_ty, dst_mcv, src_mcv); |
| 4817 | break :dst dst_mcv; |
| 4818 | }; |
| 4476 | 4819 | const dst_lock = switch (dst_mcv) { |
| 4477 | 4820 | .register => |reg| self.register_manager.lockReg(reg), |
| 4478 | 4821 | else => null, |
| ... | ... | @@ -4481,19 +4824,33 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 4481 | 4824 | |
| 4482 | 4825 | switch (tag) { |
| 4483 | 4826 | .not => { |
| 4827 | const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(self.target.*), 8)); |
| 4484 | 4828 | const int_info = if (src_ty.tag() == .bool) |
| 4485 | 4829 | std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 } |
| 4486 | 4830 | else |
| 4487 | 4831 | src_ty.intInfo(self.target.*); |
| 4488 | | const extra_bits = self.regExtraBits(src_ty); |
| 4489 | | if (int_info.signedness == .unsigned and extra_bits > 0) { |
| 4490 | | const mask = (@as(u64, 1) << @intCast(u6, src_ty.bitSize(self.target.*))) - 1; |
| 4491 | | try self.genBinOpMir(.xor, src_ty, dst_mcv, .{ .immediate = mask }); |
| 4492 | | } else try self.genUnOpMir(.not, src_ty, dst_mcv); |
| 4493 | | }, |
| 4832 | var byte_off: i32 = 0; |
| 4833 | while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) { |
| 4834 | var limb_pl = Type.Payload.Bits{ |
| 4835 | .base = .{ .tag = switch (int_info.signedness) { |
| 4836 | .signed => .int_signed, |
| 4837 | .unsigned => .int_unsigned, |
| 4838 | } }, |
| 4839 | .data = @intCast(u16, @min(int_info.bits - byte_off * 8, limb_abi_size * 8)), |
| 4840 | }; |
| 4841 | const limb_ty = Type.initPayload(&limb_pl.base); |
| 4842 | const limb_mcv = switch (byte_off) { |
| 4843 | 0 => dst_mcv, |
| 4844 | else => dst_mcv.address().offset(byte_off).deref(), |
| 4845 | }; |
| 4494 | 4846 | |
| 4847 | if (limb_pl.base.tag == .int_unsigned and self.regExtraBits(limb_ty) > 0) { |
| 4848 | const mask = @as(u64, math.maxInt(u64)) >> @intCast(u6, 64 - limb_pl.data); |
| 4849 | try self.genBinOpMir(.xor, limb_ty, limb_mcv, .{ .immediate = mask }); |
| 4850 | } else try self.genUnOpMir(.not, limb_ty, limb_mcv); |
| 4851 | } |
| 4852 | }, |
| 4495 | 4853 | .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv), |
| 4496 | | |
| 4497 | 4854 | else => unreachable, |
| 4498 | 4855 | } |
| 4499 | 4856 | return dst_mcv; |
| ... | ... | @@ -4534,17 +4891,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue |
| 4534 | 4891 | }, |
| 4535 | 4892 | .indirect, .load_frame => try self.asmMemory( |
| 4536 | 4893 | mir_tag, |
| 4537 | | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (dst_mcv) { |
| 4538 | | .indirect => |reg_off| .{ |
| 4539 | | .base = .{ .reg = reg_off.reg }, |
| 4540 | | .disp = reg_off.off, |
| 4541 | | }, |
| 4542 | | .load_frame => |frame_addr| .{ |
| 4543 | | .base = .{ .frame = frame_addr.index }, |
| 4544 | | .disp = frame_addr.off, |
| 4545 | | }, |
| 4546 | | else => unreachable, |
| 4547 | | }), |
| 4894 | dst_mcv.mem(Memory.PtrSize.fromSize(abi_size)), |
| 4548 | 4895 | ), |
| 4549 | 4896 | } |
| 4550 | 4897 | } |
| ... | ... | @@ -5128,24 +5475,69 @@ fn genBinOp( |
| 5128 | 5475 | switch (tag) { |
| 5129 | 5476 | .add, |
| 5130 | 5477 | .addwrap, |
| 5131 | | => try self.genBinOpMir(switch (lhs_ty.tag()) { |
| 5478 | => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { |
| 5132 | 5479 | else => .add, |
| 5133 | | .f32 => .addss, |
| 5134 | | .f64 => .addsd, |
| 5480 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 5481 | 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) |
| 5482 | .addss |
| 5483 | else |
| 5484 | return self.fail("TODO implement genBinOp for {s} {} without sse", .{ |
| 5485 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5486 | }), |
| 5487 | 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) |
| 5488 | .addsd |
| 5489 | else |
| 5490 | return self.fail("TODO implement genBinOp for {s} {} without sse2", .{ |
| 5491 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5492 | }), |
| 5493 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 5494 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5495 | }), |
| 5496 | }, |
| 5135 | 5497 | }, lhs_ty, dst_mcv, src_mcv), |
| 5136 | 5498 | |
| 5137 | 5499 | .sub, |
| 5138 | 5500 | .subwrap, |
| 5139 | | => try self.genBinOpMir(switch (lhs_ty.tag()) { |
| 5501 | => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { |
| 5140 | 5502 | else => .sub, |
| 5141 | | .f32 => .subss, |
| 5142 | | .f64 => .subsd, |
| 5503 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 5504 | 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) |
| 5505 | .subss |
| 5506 | else |
| 5507 | return self.fail("TODO implement genBinOp for {s} {} without sse", .{ |
| 5508 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5509 | }), |
| 5510 | 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) |
| 5511 | .subsd |
| 5512 | else |
| 5513 | return self.fail("TODO implement genBinOp for {s} {} without sse2", .{ |
| 5514 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5515 | }), |
| 5516 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 5517 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5518 | }), |
| 5519 | }, |
| 5143 | 5520 | }, lhs_ty, dst_mcv, src_mcv), |
| 5144 | 5521 | |
| 5145 | | .mul => try self.genBinOpMir(switch (lhs_ty.tag()) { |
| 5146 | | .f32 => .mulss, |
| 5147 | | .f64 => .mulsd, |
| 5522 | .mul => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { |
| 5148 | 5523 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }), |
| 5524 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 5525 | 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) |
| 5526 | .mulss |
| 5527 | else |
| 5528 | return self.fail("TODO implement genBinOp for {s} {} without sse", .{ |
| 5529 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5530 | }), |
| 5531 | 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) |
| 5532 | .mulsd |
| 5533 | else |
| 5534 | return self.fail("TODO implement genBinOp for {s} {} without sse2", .{ |
| 5535 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5536 | }), |
| 5537 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 5538 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5539 | }), |
| 5540 | }, |
| 5149 | 5541 | }, lhs_ty, dst_mcv, src_mcv), |
| 5150 | 5542 | |
| 5151 | 5543 | .div_float, |
| ... | ... | @@ -5153,12 +5545,27 @@ fn genBinOp( |
| 5153 | 5545 | .div_trunc, |
| 5154 | 5546 | .div_floor, |
| 5155 | 5547 | => { |
| 5156 | | try self.genBinOpMir(switch (lhs_ty.tag()) { |
| 5157 | | .f32 => .divss, |
| 5158 | | .f64 => .divsd, |
| 5548 | try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { |
| 5159 | 5549 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 5160 | 5550 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5161 | 5551 | }), |
| 5552 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 5553 | 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) |
| 5554 | .divss |
| 5555 | else |
| 5556 | return self.fail("TODO implement genBinOp for {s} {} without sse", .{ |
| 5557 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5558 | }), |
| 5559 | 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) |
| 5560 | .divsd |
| 5561 | else |
| 5562 | return self.fail("TODO implement genBinOp for {s} {} without sse2", .{ |
| 5563 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5564 | }), |
| 5565 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 5566 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5567 | }), |
| 5568 | }, |
| 5162 | 5569 | }, lhs_ty, dst_mcv, src_mcv); |
| 5163 | 5570 | switch (tag) { |
| 5164 | 5571 | .div_float, |
| ... | ... | @@ -5169,16 +5576,18 @@ fn genBinOp( |
| 5169 | 5576 | => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) { |
| 5170 | 5577 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); |
| 5171 | 5578 | const dst_alias = registerAlias(dst_mcv.register, abi_size); |
| 5172 | | try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) { |
| 5173 | | .f32 => .roundss, |
| 5174 | | .f64 => .roundsd, |
| 5579 | try self.asmRegisterRegisterImmediate(switch (lhs_ty.floatBits(self.target.*)) { |
| 5580 | 32 => .roundss, |
| 5581 | 64 => .roundsd, |
| 5175 | 5582 | else => unreachable, |
| 5176 | 5583 | }, dst_alias, dst_alias, Immediate.u(switch (tag) { |
| 5177 | 5584 | .div_trunc => 0b1_0_11, |
| 5178 | 5585 | .div_floor => 0b1_0_01, |
| 5179 | 5586 | else => unreachable, |
| 5180 | 5587 | })); |
| 5181 | | } else return self.fail("TODO implement round without sse4_1", .{}), |
| 5588 | } else return self.fail("TODO implement genBinOp for {s} {} without sse4_1", .{ |
| 5589 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), |
| 5590 | }), |
| 5182 | 5591 | else => unreachable, |
| 5183 | 5592 | } |
| 5184 | 5593 | }, |
| ... | ... | @@ -5400,39 +5809,68 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 5400 | 5809 | )), |
| 5401 | 5810 | else => unreachable, |
| 5402 | 5811 | }, |
| 5403 | | .register_offset, |
| 5404 | 5812 | .eflags, |
| 5813 | .register_offset, |
| 5405 | 5814 | .memory, |
| 5815 | .indirect, |
| 5406 | 5816 | .load_direct, |
| 5407 | 5817 | .lea_direct, |
| 5408 | 5818 | .load_got, |
| 5409 | 5819 | .lea_got, |
| 5410 | 5820 | .load_tlv, |
| 5411 | 5821 | .lea_tlv, |
| 5822 | .load_frame, |
| 5412 | 5823 | .lea_frame, |
| 5413 | 5824 | => { |
| 5414 | | assert(abi_size <= 8); |
| 5825 | blk: { |
| 5826 | return self.asmRegisterMemory( |
| 5827 | mir_tag, |
| 5828 | registerAlias(dst_reg, abi_size), |
| 5829 | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) { |
| 5830 | .memory => |addr| .{ |
| 5831 | .base = .{ .reg = .ds }, |
| 5832 | .disp = math.cast(i32, addr) orelse break :blk, |
| 5833 | }, |
| 5834 | .indirect => |reg_off| .{ |
| 5835 | .base = .{ .reg = reg_off.reg }, |
| 5836 | .disp = reg_off.off, |
| 5837 | }, |
| 5838 | .load_frame => |frame_addr| .{ |
| 5839 | .base = .{ .frame = frame_addr.index }, |
| 5840 | .disp = frame_addr.off, |
| 5841 | }, |
| 5842 | else => break :blk, |
| 5843 | }), |
| 5844 | ); |
| 5845 | } |
| 5846 | |
| 5415 | 5847 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 5416 | 5848 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5417 | 5849 | |
| 5418 | | const reg = try self.copyToTmpRegister(ty, src_mcv); |
| 5419 | | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg }); |
| 5420 | | }, |
| 5421 | | .indirect, .load_frame => try self.asmRegisterMemory( |
| 5422 | | mir_tag, |
| 5423 | | registerAlias(dst_reg, abi_size), |
| 5424 | | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) { |
| 5425 | | .indirect => |reg_off| .{ |
| 5426 | | .base = .{ .reg = reg_off.reg }, |
| 5427 | | .disp = reg_off.off, |
| 5850 | switch (src_mcv) { |
| 5851 | .eflags, |
| 5852 | .register_offset, |
| 5853 | .lea_direct, |
| 5854 | .lea_got, |
| 5855 | .lea_tlv, |
| 5856 | .lea_frame, |
| 5857 | => { |
| 5858 | const reg = try self.copyToTmpRegister(ty, src_mcv); |
| 5859 | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg }); |
| 5428 | 5860 | }, |
| 5429 | | .load_frame => |frame_addr| .{ |
| 5430 | | .base = .{ .frame = frame_addr.index }, |
| 5431 | | .disp = frame_addr.off, |
| 5861 | .memory, |
| 5862 | .load_direct, |
| 5863 | .load_got, |
| 5864 | .load_tlv, |
| 5865 | => { |
| 5866 | const addr_reg = try self.copyToTmpRegister(ty, src_mcv.address()); |
| 5867 | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ |
| 5868 | .indirect = .{ .reg = addr_reg }, |
| 5869 | }); |
| 5432 | 5870 | }, |
| 5433 | 5871 | else => unreachable, |
| 5434 | | }), |
| 5435 | | ), |
| 5872 | } |
| 5873 | }, |
| 5436 | 5874 | } |
| 5437 | 5875 | }, |
| 5438 | 5876 | .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => { |
| ... | ... | @@ -5769,7 +6207,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 5769 | 6207 | |
| 5770 | 6208 | const ty = self.air.typeOfIndex(inst); |
| 5771 | 6209 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; |
| 5772 | | const name = self.mod_fn.getParamName(self.bin_file.options.module.?, src_index); |
| 6210 | const name = self.owner.mod_fn.getParamName(self.bin_file.options.module.?, src_index); |
| 5773 | 6211 | try self.genArgDbgInfo(ty, name, dst_mcv); |
| 5774 | 6212 | |
| 5775 | 6213 | break :result dst_mcv; |
| ... | ... | @@ -5793,7 +6231,10 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { |
| 5793 | 6231 | //}, |
| 5794 | 6232 | else => unreachable, // not a valid function parameter |
| 5795 | 6233 | }; |
| 5796 | | try dw.genArgDbgInfo(name, ty, self.mod_fn.owner_decl, loc); |
| 6234 | // TODO: this might need adjusting like the linkers do. |
| 6235 | // Instead of flattening the owner and passing Decl.Index here we may |
| 6236 | // want to special case LazySymbol in DWARF linker too. |
| 6237 | try dw.genArgDbgInfo(name, ty, self.owner.getDecl(), loc); |
| 5797 | 6238 | }, |
| 5798 | 6239 | .plan9 => {}, |
| 5799 | 6240 | .none => {}, |
| ... | ... | @@ -5834,7 +6275,10 @@ fn genVarDbgInfo( |
| 5834 | 6275 | break :blk .nop; |
| 5835 | 6276 | }, |
| 5836 | 6277 | }; |
| 5837 | | try dw.genVarDbgInfo(name, ty, self.mod_fn.owner_decl, is_ptr, loc); |
| 6278 | // TODO: this might need adjusting like the linkers do. |
| 6279 | // Instead of flattening the owner and passing Decl.Index here we may |
| 6280 | // want to special case LazySymbol in DWARF linker too. |
| 6281 | try dw.genVarDbgInfo(name, ty, self.owner.getDecl(), is_ptr, loc); |
| 5838 | 6282 | }, |
| 5839 | 6283 | .plan9 => {}, |
| 5840 | 6284 | .none => {}, |
| ... | ... | @@ -5966,12 +6410,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5966 | 6410 | .base = .{ .reg = .ds }, |
| 5967 | 6411 | .disp = @intCast(i32, got_addr), |
| 5968 | 6412 | })); |
| 5969 | | } else if (self.bin_file.cast(link.File.Coff)) |_| { |
| 5970 | | const sym_index = try self.getSymbolIndexForDecl(func.owner_decl); |
| 6413 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 6414 | const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl); |
| 6415 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; |
| 5971 | 6416 | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); |
| 5972 | 6417 | try self.asmRegister(.call, .rax); |
| 5973 | | } else if (self.bin_file.cast(link.File.MachO)) |_| { |
| 5974 | | const sym_index = try self.getSymbolIndexForDecl(func.owner_decl); |
| 6418 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 6419 | const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl); |
| 6420 | const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; |
| 5975 | 6421 | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); |
| 5976 | 6422 | try self.asmRegister(.call, .rax); |
| 5977 | 6423 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { |
| ... | ... | @@ -5992,7 +6438,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5992 | 6438 | const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); |
| 5993 | 6439 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); |
| 5994 | 6440 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 5995 | | const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); |
| 6441 | const atom_index = try self.owner.getSymbolIndex(self); |
| 5996 | 6442 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); |
| 5997 | 6443 | _ = try self.addInst(.{ |
| 5998 | 6444 | .tag = .mov_linker, |
| ... | ... | @@ -6005,8 +6451,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 6005 | 6451 | }); |
| 6006 | 6452 | try self.asmRegister(.call, .rax); |
| 6007 | 6453 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 6454 | const atom_index = try self.owner.getSymbolIndex(self); |
| 6008 | 6455 | const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); |
| 6009 | | const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); |
| 6010 | 6456 | _ = try self.addInst(.{ |
| 6011 | 6457 | .tag = .call_extern, |
| 6012 | 6458 | .ops = undefined, |
| ... | ... | @@ -6122,10 +6568,25 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 6122 | 6568 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 6123 | 6569 | |
| 6124 | 6570 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; |
| 6125 | | try self.genBinOpMir(switch (ty.tag()) { |
| 6571 | try self.genBinOpMir(switch (ty.zigTypeTag()) { |
| 6126 | 6572 | else => .cmp, |
| 6127 | | .f32 => .ucomiss, |
| 6128 | | .f64 => .ucomisd, |
| 6573 | .Float => switch (ty.floatBits(self.target.*)) { |
| 6574 | 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) |
| 6575 | .ucomiss |
| 6576 | else |
| 6577 | return self.fail("TODO implement airCmp for {} without sse", .{ |
| 6578 | ty.fmt(self.bin_file.options.module.?), |
| 6579 | }), |
| 6580 | 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) |
| 6581 | .ucomisd |
| 6582 | else |
| 6583 | return self.fail("TODO implement airCmp for {} without sse2", .{ |
| 6584 | ty.fmt(self.bin_file.options.module.?), |
| 6585 | }), |
| 6586 | else => return self.fail("TODO implement airCmp for {}", .{ |
| 6587 | ty.fmt(self.bin_file.options.module.?), |
| 6588 | }), |
| 6589 | }, |
| 6129 | 6590 | }, ty, dst_mcv, src_mcv); |
| 6130 | 6591 | |
| 6131 | 6592 | const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; |
| ... | ... | @@ -6141,42 +6602,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { |
| 6141 | 6602 | } |
| 6142 | 6603 | |
| 6143 | 6604 | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 6605 | const mod = self.bin_file.options.module.?; |
| 6144 | 6606 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6145 | 6607 | |
| 6146 | 6608 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 6147 | | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 6148 | | defer self.register_manager.unlockReg(addr_lock); |
| 6149 | | |
| 6150 | | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 6151 | | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( |
| 6152 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 6153 | | 4, // dword alignment |
| 6154 | | ); |
| 6155 | | const atom = elf_file.getAtom(atom_index); |
| 6156 | | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| 6157 | | const got_addr = atom.getOffsetTableAddress(elf_file); |
| 6158 | | try self.asmRegisterMemory( |
| 6159 | | .mov, |
| 6160 | | addr_reg.to64(), |
| 6161 | | Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), |
| 6162 | | ); |
| 6163 | | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 6164 | | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( |
| 6165 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 6166 | | 4, // dword alignment |
| 6167 | | ); |
| 6168 | | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 6169 | | try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); |
| 6170 | | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 6171 | | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( |
| 6172 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 6173 | | 4, // dword alignment |
| 6174 | | ); |
| 6175 | | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 6176 | | try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); |
| 6177 | | } else { |
| 6178 | | return self.fail("TODO implement airCmpLtErrorsLen for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| 6179 | | } |
| 6609 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 6610 | defer self.register_manager.unlockReg(addr_lock); |
| 6611 | try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod)); |
| 6180 | 6612 | |
| 6181 | 6613 | try self.spillEflagsIfOccupied(); |
| 6182 | 6614 | self.eflags_inst = inst; |
| ... | ... | @@ -6345,35 +6777,26 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 6345 | 6777 | if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); |
| 6346 | 6778 | } |
| 6347 | 6779 | |
| 6348 | | const outer_state = try self.saveState(); |
| 6349 | | { |
| 6350 | | self.scope_generation += 1; |
| 6351 | | const inner_state = try self.saveState(); |
| 6780 | self.scope_generation += 1; |
| 6781 | const state = try self.saveState(); |
| 6352 | 6782 | |
| 6353 | | for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand); |
| 6354 | | try self.genBody(then_body); |
| 6355 | | try self.restoreState(inner_state, &.{}, .{ |
| 6356 | | .emit_instructions = false, |
| 6357 | | .update_tracking = true, |
| 6358 | | .resurrect = true, |
| 6359 | | .close_scope = true, |
| 6360 | | }); |
| 6783 | for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand); |
| 6784 | try self.genBody(then_body); |
| 6785 | try self.restoreState(state, &.{}, .{ |
| 6786 | .emit_instructions = false, |
| 6787 | .update_tracking = true, |
| 6788 | .resurrect = true, |
| 6789 | .close_scope = true, |
| 6790 | }); |
| 6361 | 6791 | |
| 6362 | | try self.performReloc(reloc); |
| 6792 | try self.performReloc(reloc); |
| 6363 | 6793 | |
| 6364 | | for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand); |
| 6365 | | try self.genBody(else_body); |
| 6366 | | try self.restoreState(inner_state, &.{}, .{ |
| 6367 | | .emit_instructions = false, |
| 6368 | | .update_tracking = true, |
| 6369 | | .resurrect = true, |
| 6370 | | .close_scope = true, |
| 6371 | | }); |
| 6372 | | } |
| 6373 | | try self.restoreState(outer_state, &.{}, .{ |
| 6794 | for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand); |
| 6795 | try self.genBody(else_body); |
| 6796 | try self.restoreState(state, &.{}, .{ |
| 6374 | 6797 | .emit_instructions = false, |
| 6375 | | .update_tracking = false, |
| 6376 | | .resurrect = false, |
| 6798 | .update_tracking = true, |
| 6799 | .resurrect = true, |
| 6377 | 6800 | .close_scope = true, |
| 6378 | 6801 | }); |
| 6379 | 6802 | |
| ... | ... | @@ -6746,64 +7169,56 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 6746 | 7169 | if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); |
| 6747 | 7170 | } |
| 6748 | 7171 | |
| 6749 | | const outer_state = try self.saveState(); |
| 6750 | | { |
| 6751 | | self.scope_generation += 1; |
| 6752 | | const inner_state = try self.saveState(); |
| 6753 | | |
| 6754 | | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| 6755 | | const case = self.air.extraData(Air.SwitchBr.Case, extra_index); |
| 6756 | | const items = @ptrCast( |
| 6757 | | []const Air.Inst.Ref, |
| 6758 | | self.air.extra[case.end..][0..case.data.items_len], |
| 6759 | | ); |
| 6760 | | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; |
| 6761 | | extra_index = case.end + items.len + case_body.len; |
| 7172 | self.scope_generation += 1; |
| 7173 | const state = try self.saveState(); |
| 6762 | 7174 | |
| 6763 | | var relocs = try self.gpa.alloc(u32, items.len); |
| 6764 | | defer self.gpa.free(relocs); |
| 7175 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| 7176 | const case = self.air.extraData(Air.SwitchBr.Case, extra_index); |
| 7177 | const items = @ptrCast( |
| 7178 | []const Air.Inst.Ref, |
| 7179 | self.air.extra[case.end..][0..case.data.items_len], |
| 7180 | ); |
| 7181 | const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len]; |
| 7182 | extra_index = case.end + items.len + case_body.len; |
| 6765 | 7183 | |
| 6766 | | for (items, relocs) |item, *reloc| { |
| 6767 | | try self.spillEflagsIfOccupied(); |
| 6768 | | const item_mcv = try self.resolveInst(item); |
| 6769 | | try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv); |
| 6770 | | reloc.* = try self.asmJccReloc(undefined, .ne); |
| 6771 | | } |
| 7184 | var relocs = try self.gpa.alloc(u32, items.len); |
| 7185 | defer self.gpa.free(relocs); |
| 6772 | 7186 | |
| 6773 | | for (liveness.deaths[case_i]) |operand| self.processDeath(operand); |
| 7187 | try self.spillEflagsIfOccupied(); |
| 7188 | for (items, relocs, 0..) |item, *reloc, i| { |
| 7189 | const item_mcv = try self.resolveInst(item); |
| 7190 | try self.genBinOpMir(.cmp, condition_ty, condition, item_mcv); |
| 7191 | reloc.* = try self.asmJccReloc(undefined, if (i < relocs.len - 1) .e else .ne); |
| 7192 | } |
| 6774 | 7193 | |
| 6775 | | try self.genBody(case_body); |
| 6776 | | try self.restoreState(inner_state, &.{}, .{ |
| 6777 | | .emit_instructions = false, |
| 6778 | | .update_tracking = true, |
| 6779 | | .resurrect = true, |
| 6780 | | .close_scope = true, |
| 6781 | | }); |
| 7194 | for (liveness.deaths[case_i]) |operand| self.processDeath(operand); |
| 6782 | 7195 | |
| 6783 | | for (relocs) |reloc| try self.performReloc(reloc); |
| 6784 | | } |
| 7196 | for (relocs[0 .. relocs.len - 1]) |reloc| try self.performReloc(reloc); |
| 7197 | try self.genBody(case_body); |
| 7198 | try self.restoreState(state, &.{}, .{ |
| 7199 | .emit_instructions = false, |
| 7200 | .update_tracking = true, |
| 7201 | .resurrect = true, |
| 7202 | .close_scope = true, |
| 7203 | }); |
| 6785 | 7204 | |
| 6786 | | if (switch_br.data.else_body_len > 0) { |
| 6787 | | const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| 7205 | try self.performReloc(relocs[relocs.len - 1]); |
| 7206 | } |
| 6788 | 7207 | |
| 6789 | | const else_deaths = liveness.deaths.len - 1; |
| 6790 | | for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand); |
| 7208 | if (switch_br.data.else_body_len > 0) { |
| 7209 | const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| 6791 | 7210 | |
| 6792 | | try self.genBody(else_body); |
| 6793 | | try self.restoreState(inner_state, &.{}, .{ |
| 6794 | | .emit_instructions = false, |
| 6795 | | .update_tracking = true, |
| 6796 | | .resurrect = true, |
| 6797 | | .close_scope = true, |
| 6798 | | }); |
| 6799 | | } |
| 7211 | const else_deaths = liveness.deaths.len - 1; |
| 7212 | for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand); |
| 7213 | |
| 7214 | try self.genBody(else_body); |
| 7215 | try self.restoreState(state, &.{}, .{ |
| 7216 | .emit_instructions = false, |
| 7217 | .update_tracking = true, |
| 7218 | .resurrect = true, |
| 7219 | .close_scope = true, |
| 7220 | }); |
| 6800 | 7221 | } |
| 6801 | | try self.restoreState(outer_state, &.{}, .{ |
| 6802 | | .emit_instructions = false, |
| 6803 | | .update_tracking = false, |
| 6804 | | .resurrect = false, |
| 6805 | | .close_scope = true, |
| 6806 | | }); |
| 6807 | 7222 | |
| 6808 | 7223 | // We already took care of pl_op.operand earlier, so we're going to pass .none here |
| 6809 | 7224 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); |
| ... | ... | @@ -7289,7 +7704,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 7289 | 7704 | }), |
| 7290 | 7705 | ), |
| 7291 | 7706 | .load_direct => |sym_index| if (try self.movMirTag(ty) == .mov) { |
| 7292 | | const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); |
| 7707 | const atom_index = try self.owner.getSymbolIndex(self); |
| 7293 | 7708 | _ = try self.addInst(.{ |
| 7294 | 7709 | .tag = .mov_linker, |
| 7295 | 7710 | .ops = .direct_reloc, |
| ... | ... | @@ -7316,7 +7731,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 7316 | 7731 | ); |
| 7317 | 7732 | }, |
| 7318 | 7733 | .lea_direct, .lea_got => |sym_index| { |
| 7319 | | const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); |
| 7734 | const atom_index = try self.owner.getSymbolIndex(self); |
| 7320 | 7735 | _ = try self.addInst(.{ |
| 7321 | 7736 | .tag = switch (src_mcv) { |
| 7322 | 7737 | .lea_direct => .lea_linker, |
| ... | ... | @@ -7336,7 +7751,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 7336 | 7751 | }); |
| 7337 | 7752 | }, |
| 7338 | 7753 | .lea_tlv => |sym_index| { |
| 7339 | | const atom_index = try self.getSymbolIndexForDecl(self.mod_fn.owner_decl); |
| 7754 | const atom_index = try self.owner.getSymbolIndex(self); |
| 7340 | 7755 | if (self.bin_file.cast(link.File.MachO)) |_| { |
| 7341 | 7756 | _ = try self.addInst(.{ |
| 7342 | 7757 | .tag = .lea_linker, |
| ... | ... | @@ -7531,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue) |
| 7531 | 7946 | }); |
| 7532 | 7947 | } |
| 7533 | 7948 | |
| 7949 | fn genLazySymbolRef( |
| 7950 | self: *Self, |
| 7951 | comptime tag: Mir.Inst.Tag, |
| 7952 | reg: Register, |
| 7953 | lazy_sym: link.File.LazySymbol, |
| 7954 | ) InnerError!void { |
| 7955 | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 7956 | const atom_index = elf_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| |
| 7957 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 7958 | const atom = elf_file.getAtom(atom_index); |
| 7959 | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| 7960 | const got_addr = atom.getOffsetTableAddress(elf_file); |
| 7961 | const got_mem = |
| 7962 | Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }); |
| 7963 | switch (tag) { |
| 7964 | .lea, .mov => try self.asmRegisterMemory(.mov, reg.to64(), got_mem), |
| 7965 | .call => try self.asmMemory(.call, got_mem), |
| 7966 | else => unreachable, |
| 7967 | } |
| 7968 | switch (tag) { |
| 7969 | .lea, .call => {}, |
| 7970 | .mov => try self.asmRegisterMemory( |
| 7971 | tag, |
| 7972 | reg.to64(), |
| 7973 | Memory.sib(.qword, .{ .base = .{ .reg = reg.to64() } }), |
| 7974 | ), |
| 7975 | else => unreachable, |
| 7976 | } |
| 7977 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 7978 | const atom_index = coff_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| |
| 7979 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 7980 | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 7981 | switch (tag) { |
| 7982 | .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }), |
| 7983 | .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }), |
| 7984 | else => unreachable, |
| 7985 | } |
| 7986 | switch (tag) { |
| 7987 | .lea, .mov => {}, |
| 7988 | .call => try self.asmRegister(.call, reg), |
| 7989 | else => unreachable, |
| 7990 | } |
| 7991 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 7992 | const atom_index = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err| |
| 7993 | return self.fail("{s} creating lazy symbol", .{@errorName(err)}); |
| 7994 | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 7995 | switch (tag) { |
| 7996 | .lea, .call => try self.genSetReg(reg, Type.usize, .{ .lea_got = sym_index }), |
| 7997 | .mov => try self.genSetReg(reg, Type.usize, .{ .load_got = sym_index }), |
| 7998 | else => unreachable, |
| 7999 | } |
| 8000 | switch (tag) { |
| 8001 | .lea, .mov => {}, |
| 8002 | .call => try self.asmRegister(.call, reg), |
| 8003 | else => unreachable, |
| 8004 | } |
| 8005 | } else { |
| 8006 | return self.fail("TODO implement genLazySymbol for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| 8007 | } |
| 8008 | } |
| 8009 | |
| 7534 | 8010 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7535 | 8011 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 7536 | 8012 | const result = result: { |
| ... | ... | @@ -7555,7 +8031,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 7555 | 8031 | const dst_rc = try self.regClassForType(dst_ty); |
| 7556 | 8032 | const src_rc = try self.regClassForType(src_ty); |
| 7557 | 8033 | const operand = try self.resolveInst(ty_op.operand); |
| 7558 | | if (dst_rc.eql(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand)) break :result operand; |
| 8034 | if (dst_rc.supersetOf(src_rc) and self.reuseOperand(inst, ty_op.operand, 0, operand)) |
| 8035 | break :result operand; |
| 7559 | 8036 | |
| 7560 | 8037 | const operand_lock = switch (operand) { |
| 7561 | 8038 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | ... | @@ -7595,9 +8072,59 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 7595 | 8072 | |
| 7596 | 8073 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 7597 | 8074 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7598 | | _ = ty_op; |
| 7599 | | return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch}); |
| 7600 | | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 8075 | |
| 8076 | const src_ty = self.air.typeOf(ty_op.operand); |
| 8077 | const src_bits = @intCast(u32, src_ty.bitSize(self.target.*)); |
| 8078 | const src_signedness = |
| 8079 | if (src_ty.isAbiInt()) src_ty.intInfo(self.target.*).signedness else .unsigned; |
| 8080 | const dst_ty = self.air.typeOfIndex(inst); |
| 8081 | |
| 8082 | const src_size = std.math.divCeil(u32, @max(switch (src_signedness) { |
| 8083 | .signed => src_bits, |
| 8084 | .unsigned => src_bits + 1, |
| 8085 | }, 32), 8) catch unreachable; |
| 8086 | if (src_size > 8) return self.fail("TODO implement airIntToFloat from {} to {}", .{ |
| 8087 | src_ty.fmt(self.bin_file.options.module.?), |
| 8088 | dst_ty.fmt(self.bin_file.options.module.?), |
| 8089 | }); |
| 8090 | |
| 8091 | const src_mcv = try self.resolveInst(ty_op.operand); |
| 8092 | const src_reg = switch (src_mcv) { |
| 8093 | .register => |reg| reg, |
| 8094 | else => try self.copyToTmpRegister(src_ty, src_mcv), |
| 8095 | }; |
| 8096 | const src_lock = self.register_manager.lockRegAssumeUnused(src_reg); |
| 8097 | defer self.register_manager.unlockReg(src_lock); |
| 8098 | |
| 8099 | if (src_bits < src_size * 8) try self.truncateRegister(src_ty, src_reg); |
| 8100 | |
| 8101 | const dst_reg = try self.register_manager.allocReg(inst, try self.regClassForType(dst_ty)); |
| 8102 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 8103 | const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 8104 | defer self.register_manager.unlockReg(dst_lock); |
| 8105 | |
| 8106 | try self.asmRegisterRegister(switch (dst_ty.floatBits(self.target.*)) { |
| 8107 | 32 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse)) |
| 8108 | .cvtsi2ss |
| 8109 | else |
| 8110 | return self.fail("TODO implement airIntToFloat from {} to {} without sse", .{ |
| 8111 | src_ty.fmt(self.bin_file.options.module.?), |
| 8112 | dst_ty.fmt(self.bin_file.options.module.?), |
| 8113 | }), |
| 8114 | 64 => if (Target.x86.featureSetHas(self.target.cpu.features, .sse2)) |
| 8115 | .cvtsi2sd |
| 8116 | else |
| 8117 | return self.fail("TODO implement airIntToFloat from {} to {} without sse2", .{ |
| 8118 | src_ty.fmt(self.bin_file.options.module.?), |
| 8119 | dst_ty.fmt(self.bin_file.options.module.?), |
| 8120 | }), |
| 8121 | else => return self.fail("TODO implement airIntToFloat from {} to {}", .{ |
| 8122 | src_ty.fmt(self.bin_file.options.module.?), |
| 8123 | dst_ty.fmt(self.bin_file.options.module.?), |
| 8124 | }), |
| 8125 | }, dst_reg.to128(), registerAlias(src_reg, src_size)); |
| 8126 | |
| 8127 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); |
| 7601 | 8128 | } |
| 7602 | 8129 | |
| 7603 | 8130 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| ... | ... | @@ -7652,70 +8179,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 7652 | 8179 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 7653 | 8180 | |
| 7654 | 8181 | const ptr_ty = self.air.typeOf(extra.ptr); |
| 7655 | | const ptr_mcv = try self.resolveInst(extra.ptr); |
| 7656 | 8182 | const val_ty = self.air.typeOf(extra.expected_value); |
| 7657 | 8183 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 7658 | 8184 | |
| 7659 | 8185 | try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx }); |
| 7660 | 8186 | const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx }); |
| 7661 | | for (regs_lock) |lock| self.register_manager.unlockReg(lock); |
| 8187 | defer for (regs_lock) |lock| self.register_manager.unlockReg(lock); |
| 7662 | 8188 | |
| 7663 | 8189 | const exp_mcv = try self.resolveInst(extra.expected_value); |
| 7664 | | if (val_abi_size > 8) switch (exp_mcv) { |
| 7665 | | .load_frame => |frame_addr| { |
| 7666 | | try self.genSetReg(.rax, Type.usize, .{ .load_frame = .{ |
| 7667 | | .index = frame_addr.index, |
| 7668 | | .off = frame_addr.off + 0, |
| 7669 | | } }); |
| 7670 | | try self.genSetReg(.rdx, Type.usize, .{ .load_frame = .{ |
| 7671 | | .index = frame_addr.index, |
| 7672 | | .off = frame_addr.off + 8, |
| 7673 | | } }); |
| 7674 | | }, |
| 7675 | | else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}), |
| 8190 | if (val_abi_size > 8) { |
| 8191 | try self.genSetReg(.rax, Type.usize, exp_mcv); |
| 8192 | try self.genSetReg(.rdx, Type.usize, exp_mcv.address().offset(8).deref()); |
| 7676 | 8193 | } else try self.genSetReg(.rax, val_ty, exp_mcv); |
| 7677 | | const rax_lock = self.register_manager.lockRegAssumeUnused(.rax); |
| 7678 | | defer self.register_manager.unlockReg(rax_lock); |
| 7679 | 8194 | |
| 7680 | 8195 | const new_mcv = try self.resolveInst(extra.new_value); |
| 7681 | | const new_reg: Register = if (val_abi_size > 8) switch (new_mcv) { |
| 7682 | | .load_frame => |frame_addr| new: { |
| 7683 | | try self.genSetReg(.rbx, Type.usize, .{ .load_frame = .{ |
| 7684 | | .index = frame_addr.index, |
| 7685 | | .off = frame_addr.off + 0, |
| 7686 | | } }); |
| 7687 | | try self.genSetReg(.rcx, Type.usize, .{ .load_frame = .{ |
| 7688 | | .index = frame_addr.index, |
| 7689 | | .off = frame_addr.off + 8, |
| 7690 | | } }); |
| 7691 | | break :new undefined; |
| 7692 | | }, |
| 7693 | | else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}), |
| 8196 | const new_reg = if (val_abi_size > 8) new: { |
| 8197 | try self.genSetReg(.rbx, Type.usize, new_mcv); |
| 8198 | try self.genSetReg(.rcx, Type.usize, new_mcv.address().offset(8).deref()); |
| 8199 | break :new null; |
| 7694 | 8200 | } else try self.copyToTmpRegister(val_ty, new_mcv); |
| 7695 | | const new_lock = self.register_manager.lockRegAssumeUnused(new_reg); |
| 7696 | | defer self.register_manager.unlockReg(new_lock); |
| 8201 | const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; |
| 8202 | defer if (new_lock) |lock| self.register_manager.unlockReg(lock); |
| 7697 | 8203 | |
| 8204 | const ptr_mcv = try self.resolveInst(extra.ptr); |
| 7698 | 8205 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 7699 | 8206 | const ptr_mem = switch (ptr_mcv) { |
| 7700 | | .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }), |
| 7701 | | .lea_frame => |frame_addr| Memory.sib(ptr_size, .{ |
| 7702 | | .base = .{ .frame = frame_addr.index }, |
| 7703 | | .disp = frame_addr.off, |
| 8207 | .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size), |
| 8208 | else => Memory.sib(ptr_size, .{ |
| 8209 | .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }, |
| 7704 | 8210 | }), |
| 7705 | | else => Memory.sib(ptr_size, .{ .base = .{ |
| 7706 | | .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv), |
| 7707 | | } }), |
| 7708 | 8211 | }; |
| 7709 | | const mem_lock = switch (ptr_mem.base()) { |
| 8212 | switch (ptr_mem) { |
| 8213 | .sib, .rip => {}, |
| 8214 | .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), |
| 8215 | } |
| 8216 | const ptr_lock = switch (ptr_mem.base()) { |
| 7710 | 8217 | .none, .frame => null, |
| 7711 | 8218 | .reg => |reg| self.register_manager.lockReg(reg), |
| 7712 | 8219 | }; |
| 7713 | | defer if (mem_lock) |lock| self.register_manager.unlockReg(lock); |
| 8220 | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 7714 | 8221 | |
| 7715 | 8222 | try self.spillEflagsIfOccupied(); |
| 7716 | 8223 | if (val_abi_size <= 8) { |
| 7717 | 8224 | _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{ |
| 7718 | | .r = registerAlias(new_reg, val_abi_size), |
| 8225 | .r = registerAlias(new_reg.?, val_abi_size), |
| 7719 | 8226 | .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)), |
| 7720 | 8227 | } } }); |
| 7721 | 8228 | } else { |
| ... | ... | @@ -7733,24 +8240,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 7733 | 8240 | } |
| 7734 | 8241 | |
| 7735 | 8242 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 7736 | | try self.genSetMem( |
| 7737 | | .{ .frame = dst_mcv.load_frame.index }, |
| 7738 | | dst_mcv.load_frame.off + 16, |
| 7739 | | Type.bool, |
| 7740 | | .{ .eflags = .ne }, |
| 7741 | | ); |
| 7742 | | try self.genSetMem( |
| 7743 | | .{ .frame = dst_mcv.load_frame.index }, |
| 7744 | | dst_mcv.load_frame.off + 8, |
| 7745 | | Type.usize, |
| 7746 | | .{ .register = .rdx }, |
| 7747 | | ); |
| 7748 | | try self.genSetMem( |
| 7749 | | .{ .frame = dst_mcv.load_frame.index }, |
| 7750 | | dst_mcv.load_frame.off + 0, |
| 7751 | | Type.usize, |
| 7752 | | .{ .register = .rax }, |
| 7753 | | ); |
| 8243 | try self.genCopy(Type.usize, dst_mcv, .{ .register = .rax }); |
| 8244 | try self.genCopy(Type.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx }); |
| 8245 | try self.genCopy(Type.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne }); |
| 7754 | 8246 | break :result dst_mcv; |
| 7755 | 8247 | }; |
| 7756 | 8248 | return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value }); |
| ... | ... | @@ -7781,15 +8273,15 @@ fn atomicOp( |
| 7781 | 8273 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 7782 | 8274 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 7783 | 8275 | const ptr_mem = switch (ptr_mcv) { |
| 7784 | | .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }), |
| 7785 | | .lea_frame => |frame_addr| Memory.sib(ptr_size, .{ |
| 7786 | | .base = .{ .frame = frame_addr.index }, |
| 7787 | | .disp = frame_addr.off, |
| 8276 | .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size), |
| 8277 | else => Memory.sib(ptr_size, .{ |
| 8278 | .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }, |
| 7788 | 8279 | }), |
| 7789 | | else => Memory.sib(ptr_size, .{ .base = .{ |
| 7790 | | .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv), |
| 7791 | | } }), |
| 7792 | 8280 | }; |
| 8281 | switch (ptr_mem) { |
| 8282 | .sib, .rip => {}, |
| 8283 | .moffs => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), |
| 8284 | } |
| 7793 | 8285 | const mem_lock = switch (ptr_mem.base()) { |
| 7794 | 8286 | .none, .frame => null, |
| 7795 | 8287 | .reg => |reg| self.register_manager.lockReg(reg), |
| ... | ... | @@ -7895,12 +8387,9 @@ fn atomicOp( |
| 7895 | 8387 | registerAlias(val_reg, cmov_abi_size), |
| 7896 | 8388 | cc, |
| 7897 | 8389 | ), |
| 7898 | | .load_frame => |frame_addr| try self.asmCmovccRegisterMemory( |
| 8390 | .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory( |
| 7899 | 8391 | registerAlias(tmp_reg, cmov_abi_size), |
| 7900 | | Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), .{ |
| 7901 | | .base = .{ .frame = frame_addr.index }, |
| 7902 | | .disp = frame_addr.off, |
| 7903 | | }), |
| 8392 | val_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)), |
| 7904 | 8393 | cc, |
| 7905 | 8394 | ), |
| 7906 | 8395 | else => { |
| ... | ... | @@ -7923,72 +8412,62 @@ fn atomicOp( |
| 7923 | 8412 | } else { |
| 7924 | 8413 | try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{ |
| 7925 | 8414 | .base = ptr_mem.sib.base, |
| 7926 | | .scale_index = ptr_mem.sib.scale_index, |
| 8415 | .scale_index = ptr_mem.scaleIndex(), |
| 7927 | 8416 | .disp = ptr_mem.sib.disp + 0, |
| 7928 | 8417 | })); |
| 7929 | 8418 | try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{ |
| 7930 | 8419 | .base = ptr_mem.sib.base, |
| 7931 | | .scale_index = ptr_mem.sib.scale_index, |
| 8420 | .scale_index = ptr_mem.scaleIndex(), |
| 7932 | 8421 | .disp = ptr_mem.sib.disp + 8, |
| 7933 | 8422 | })); |
| 7934 | 8423 | const loop = @intCast(u32, self.mir_instructions.len); |
| 7935 | | switch (val_mcv) { |
| 7936 | | .load_frame => |frame_addr| { |
| 7937 | | const val_lo_mem = Memory.sib(.qword, .{ |
| 7938 | | .base = .{ .frame = frame_addr.index }, |
| 7939 | | .disp = frame_addr.off + 0, |
| 7940 | | }); |
| 7941 | | const val_hi_mem = Memory.sib(.qword, .{ |
| 7942 | | .base = .{ .frame = frame_addr.index }, |
| 7943 | | .disp = frame_addr.off + 8, |
| 7944 | | }); |
| 7945 | | |
| 7946 | | if (rmw_op != std.builtin.AtomicRmwOp.Xchg) { |
| 7947 | | try self.asmRegisterRegister(.mov, .rbx, .rax); |
| 7948 | | try self.asmRegisterRegister(.mov, .rcx, .rdx); |
| 7949 | | } |
| 7950 | | if (rmw_op) |op| switch (op) { |
| 7951 | | .Xchg => { |
| 7952 | | try self.asmRegisterMemory(.mov, .rbx, val_lo_mem); |
| 7953 | | try self.asmRegisterMemory(.mov, .rcx, val_hi_mem); |
| 7954 | | }, |
| 7955 | | .Add => { |
| 7956 | | try self.asmRegisterMemory(.add, .rbx, val_lo_mem); |
| 7957 | | try self.asmRegisterMemory(.adc, .rcx, val_hi_mem); |
| 7958 | | }, |
| 7959 | | .Sub => { |
| 7960 | | try self.asmRegisterMemory(.sub, .rbx, val_lo_mem); |
| 7961 | | try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem); |
| 7962 | | }, |
| 7963 | | .And => { |
| 7964 | | try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem); |
| 7965 | | try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem); |
| 7966 | | }, |
| 7967 | | .Nand => { |
| 7968 | | try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem); |
| 7969 | | try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem); |
| 7970 | | try self.asmRegister(.not, .rbx); |
| 7971 | | try self.asmRegister(.not, .rcx); |
| 7972 | | }, |
| 7973 | | .Or => { |
| 7974 | | try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem); |
| 7975 | | try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem); |
| 7976 | | }, |
| 7977 | | .Xor => { |
| 7978 | | try self.asmRegisterMemory(.xor, .rbx, val_lo_mem); |
| 7979 | | try self.asmRegisterMemory(.xor, .rcx, val_hi_mem); |
| 7980 | | }, |
| 7981 | | else => return self.fail( |
| 7982 | | "TODO implement x86 atomic loop for large abi {s}", |
| 7983 | | .{@tagName(op)}, |
| 7984 | | ), |
| 7985 | | }; |
| 7986 | | }, |
| 7987 | | else => return self.fail( |
| 7988 | | "TODO implement x86 atomic loop for large abi {s}", |
| 7989 | | .{@tagName(val_mcv)}, |
| 7990 | | ), |
| 8424 | const val_mem_mcv: MCValue = switch (val_mcv) { |
| 8425 | .memory, .indirect, .load_frame => val_mcv, |
| 8426 | else => .{ .indirect = .{ |
| 8427 | .reg = try self.copyToTmpRegister(Type.usize, val_mcv.address()), |
| 8428 | } }, |
| 8429 | }; |
| 8430 | const val_lo_mem = val_mem_mcv.mem(.qword); |
| 8431 | const val_hi_mem = val_mem_mcv.address().offset(8).deref().mem(.qword); |
| 8432 | if (rmw_op != std.builtin.AtomicRmwOp.Xchg) { |
| 8433 | try self.asmRegisterRegister(.mov, .rbx, .rax); |
| 8434 | try self.asmRegisterRegister(.mov, .rcx, .rdx); |
| 7991 | 8435 | } |
| 8436 | if (rmw_op) |op| switch (op) { |
| 8437 | .Xchg => { |
| 8438 | try self.asmRegisterMemory(.mov, .rbx, val_lo_mem); |
| 8439 | try self.asmRegisterMemory(.mov, .rcx, val_hi_mem); |
| 8440 | }, |
| 8441 | .Add => { |
| 8442 | try self.asmRegisterMemory(.add, .rbx, val_lo_mem); |
| 8443 | try self.asmRegisterMemory(.adc, .rcx, val_hi_mem); |
| 8444 | }, |
| 8445 | .Sub => { |
| 8446 | try self.asmRegisterMemory(.sub, .rbx, val_lo_mem); |
| 8447 | try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem); |
| 8448 | }, |
| 8449 | .And => { |
| 8450 | try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem); |
| 8451 | try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem); |
| 8452 | }, |
| 8453 | .Nand => { |
| 8454 | try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem); |
| 8455 | try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem); |
| 8456 | try self.asmRegister(.not, .rbx); |
| 8457 | try self.asmRegister(.not, .rcx); |
| 8458 | }, |
| 8459 | .Or => { |
| 8460 | try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem); |
| 8461 | try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem); |
| 8462 | }, |
| 8463 | .Xor => { |
| 8464 | try self.asmRegisterMemory(.xor, .rbx, val_lo_mem); |
| 8465 | try self.asmRegisterMemory(.xor, .rcx, val_hi_mem); |
| 8466 | }, |
| 8467 | else => return self.fail("TODO implement x86 atomic loop for {} {s}", .{ |
| 8468 | val_ty.fmt(self.bin_file.options.module.?), @tagName(op), |
| 8469 | }), |
| 8470 | }; |
| 7992 | 8471 | _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{ |
| 7993 | 8472 | .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)), |
| 7994 | 8473 | } }); |
| ... | ... | @@ -8230,14 +8709,48 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 8230 | 8709 | } |
| 8231 | 8710 | |
| 8232 | 8711 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 8712 | const mod = self.bin_file.options.module.?; |
| 8233 | 8713 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8714 | const inst_ty = self.air.typeOfIndex(inst); |
| 8715 | const enum_ty = self.air.typeOf(un_op); |
| 8716 | |
| 8717 | // We need a properly aligned and sized call frame to be able to call this function. |
| 8718 | { |
| 8719 | const needed_call_frame = FrameAlloc.init(.{ |
| 8720 | .size = inst_ty.abiSize(self.target.*), |
| 8721 | .alignment = inst_ty.abiAlignment(self.target.*), |
| 8722 | }); |
| 8723 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 8724 | const stack_frame_size = |
| 8725 | &frame_allocs_slice.items(.abi_size)[@enumToInt(FrameIndex.call_frame)]; |
| 8726 | stack_frame_size.* = @max(stack_frame_size.*, needed_call_frame.abi_size); |
| 8727 | const stack_frame_align = |
| 8728 | &frame_allocs_slice.items(.abi_align)[@enumToInt(FrameIndex.call_frame)]; |
| 8729 | stack_frame_align.* = @max(stack_frame_align.*, needed_call_frame.abi_align); |
| 8730 | } |
| 8731 | |
| 8732 | try self.spillEflagsIfOccupied(); |
| 8733 | try self.spillRegisters(abi.getCallerPreservedRegs(self.target.*)); |
| 8734 | |
| 8735 | const param_regs = abi.getCAbiIntParamRegs(self.target.*); |
| 8736 | |
| 8737 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 8738 | try self.genSetReg(param_regs[0], Type.usize, dst_mcv.address()); |
| 8739 | |
| 8234 | 8740 | const operand = try self.resolveInst(un_op); |
| 8235 | | _ = operand; |
| 8236 | | return self.fail("TODO implement airTagName for x86_64", .{}); |
| 8237 | | //return self.finishAir(inst, result, .{ un_op, .none, .none }); |
| 8741 | try self.genSetReg(param_regs[1], enum_ty, operand); |
| 8742 | |
| 8743 | try self.genLazySymbolRef( |
| 8744 | .call, |
| 8745 | .rax, |
| 8746 | link.File.LazySymbol.initDecl(.code, enum_ty.getOwnerDecl(), mod), |
| 8747 | ); |
| 8748 | |
| 8749 | return self.finishAir(inst, dst_mcv, .{ un_op, .none, .none }); |
| 8238 | 8750 | } |
| 8239 | 8751 | |
| 8240 | 8752 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 8753 | const mod = self.bin_file.options.module.?; |
| 8241 | 8754 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8242 | 8755 | |
| 8243 | 8756 | const err_ty = self.air.typeOf(un_op); |
| ... | ... | @@ -8249,37 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 8249 | 8762 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 8250 | 8763 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 8251 | 8764 | defer self.register_manager.unlockReg(addr_lock); |
| 8252 | | |
| 8253 | | if (self.bin_file.cast(link.File.Elf)) |elf_file| { |
| 8254 | | const atom_index = try elf_file.getOrCreateAtomForLazySymbol( |
| 8255 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8256 | | 4, // dword alignment |
| 8257 | | ); |
| 8258 | | const atom = elf_file.getAtom(atom_index); |
| 8259 | | _ = try atom.getOrCreateOffsetTableEntry(elf_file); |
| 8260 | | const got_addr = atom.getOffsetTableAddress(elf_file); |
| 8261 | | try self.asmRegisterMemory( |
| 8262 | | .mov, |
| 8263 | | addr_reg.to64(), |
| 8264 | | Memory.sib(.qword, .{ .base = .{ .reg = .ds }, .disp = @intCast(i32, got_addr) }), |
| 8265 | | ); |
| 8266 | | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 8267 | | const atom_index = try coff_file.getOrCreateAtomForLazySymbol( |
| 8268 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8269 | | 4, // dword alignment |
| 8270 | | ); |
| 8271 | | const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?; |
| 8272 | | try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); |
| 8273 | | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 8274 | | const atom_index = try macho_file.getOrCreateAtomForLazySymbol( |
| 8275 | | .{ .kind = .const_data, .ty = Type.anyerror }, |
| 8276 | | 4, // dword alignment |
| 8277 | | ); |
| 8278 | | const sym_index = macho_file.getAtom(atom_index).getSymbolIndex().?; |
| 8279 | | try self.genSetReg(addr_reg, Type.usize, .{ .lea_got = sym_index }); |
| 8280 | | } else { |
| 8281 | | return self.fail("TODO implement airErrorName for x86_64 {s}", .{@tagName(self.bin_file.tag)}); |
| 8282 | | } |
| 8765 | try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod)); |
| 8283 | 8766 | |
| 8284 | 8767 | const start_reg = try self.register_manager.allocReg(null, gp); |
| 8285 | 8768 | const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); |
| ... | ... | @@ -8596,12 +9079,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV |
| 8596 | 9079 | } |
| 8597 | 9080 | |
| 8598 | 9081 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 8599 | | const mcv: MCValue = switch (try codegen.genTypedValue( |
| 8600 | | self.bin_file, |
| 8601 | | self.src_loc, |
| 8602 | | arg_tv, |
| 8603 | | self.mod_fn.owner_decl, |
| 8604 | | )) { |
| 9082 | return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl())) { |
| 8605 | 9083 | .mcv => |mcv| switch (mcv) { |
| 8606 | 9084 | .none => .none, |
| 8607 | 9085 | .undef => .undef, |
| ... | ... | @@ -8616,7 +9094,6 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 8616 | 9094 | return error.CodegenFail; |
| 8617 | 9095 | }, |
| 8618 | 9096 | }; |
| 8619 | | return mcv; |
| 8620 | 9097 | } |
| 8621 | 9098 | |
| 8622 | 9099 | const CallMCValues = struct { |
| ... | ... | @@ -8664,6 +9141,7 @@ fn resolveCallingConventionValues( |
| 8664 | 9141 | }, |
| 8665 | 9142 | .C => { |
| 8666 | 9143 | var param_reg_i: usize = 0; |
| 9144 | var param_sse_reg_i: usize = 0; |
| 8667 | 9145 | result.stack_align = 16; |
| 8668 | 9146 | |
| 8669 | 9147 | switch (self.target.os.tag) { |
| ... | ... | @@ -8681,26 +9159,39 @@ fn resolveCallingConventionValues( |
| 8681 | 9159 | // TODO: is this even possible for C calling convention? |
| 8682 | 9160 | result.return_value = InstTracking.init(.none); |
| 8683 | 9161 | } else { |
| 8684 | | const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; |
| 8685 | | const ret_ty_size = @intCast(u31, ret_ty.abiSize(self.target.*)); |
| 8686 | | if (ret_ty_size <= 8) { |
| 8687 | | const aliased_reg = registerAlias(ret_reg, ret_ty_size); |
| 8688 | | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; |
| 8689 | | } else { |
| 8690 | | const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; |
| 8691 | | param_reg_i += 1; |
| 8692 | | result.return_value = .{ |
| 8693 | | .short = .{ .indirect = .{ .reg = ret_reg } }, |
| 8694 | | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 8695 | | }; |
| 9162 | const classes = switch (self.target.os.tag) { |
| 9163 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, self.target.*)}, |
| 9164 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, self.target.*, .ret), .none), |
| 9165 | }; |
| 9166 | if (classes.len > 1) { |
| 9167 | return self.fail("TODO handle multiple classes per type", .{}); |
| 8696 | 9168 | } |
| 9169 | const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; |
| 9170 | result.return_value = switch (classes[0]) { |
| 9171 | .integer => InstTracking.init(.{ .register = registerAlias( |
| 9172 | ret_reg, |
| 9173 | @intCast(u32, ret_ty.abiSize(self.target.*)), |
| 9174 | ) }), |
| 9175 | .float, .sse => InstTracking.init(.{ .register = .xmm0 }), |
| 9176 | .memory => ret: { |
| 9177 | const ret_indirect_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; |
| 9178 | param_reg_i += 1; |
| 9179 | break :ret .{ |
| 9180 | .short = .{ .indirect = .{ .reg = ret_reg } }, |
| 9181 | .long = .{ .indirect = .{ .reg = ret_indirect_reg } }, |
| 9182 | }; |
| 9183 | }, |
| 9184 | else => |class| return self.fail("TODO handle calling convention class {s}", .{ |
| 9185 | @tagName(class), |
| 9186 | }), |
| 9187 | }; |
| 8697 | 9188 | } |
| 8698 | 9189 | |
| 8699 | 9190 | // Input params |
| 8700 | 9191 | for (param_types, result.args) |ty, *arg| { |
| 8701 | 9192 | assert(ty.hasRuntimeBitsIgnoreComptime()); |
| 8702 | 9193 | |
| 8703 | | const classes: []const abi.Class = switch (self.target.os.tag) { |
| 9194 | const classes = switch (self.target.os.tag) { |
| 8704 | 9195 | .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)}, |
| 8705 | 9196 | else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none), |
| 8706 | 9197 | }; |
| ... | ... | @@ -8708,13 +9199,29 @@ fn resolveCallingConventionValues( |
| 8708 | 9199 | return self.fail("TODO handle multiple classes per type", .{}); |
| 8709 | 9200 | } |
| 8710 | 9201 | switch (classes[0]) { |
| 8711 | | .integer => blk: { |
| 8712 | | if (param_reg_i >= abi.getCAbiIntParamRegs(self.target.*).len) break :blk; |
| 8713 | | const param_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; |
| 9202 | .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) { |
| 9203 | arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] }; |
| 8714 | 9204 | param_reg_i += 1; |
| 8715 | | arg.* = .{ .register = param_reg }; |
| 8716 | 9205 | continue; |
| 8717 | 9206 | }, |
| 9207 | .float, .sse => switch (self.target.os.tag) { |
| 9208 | .windows => if (param_reg_i < 4) { |
| 9209 | arg.* = .{ .register = @intToEnum( |
| 9210 | Register, |
| 9211 | @enumToInt(Register.xmm0) + param_reg_i, |
| 9212 | ) }; |
| 9213 | param_reg_i += 1; |
| 9214 | continue; |
| 9215 | }, |
| 9216 | else => if (param_sse_reg_i < 8) { |
| 9217 | arg.* = .{ .register = @intToEnum( |
| 9218 | Register, |
| 9219 | @enumToInt(Register.xmm0) + param_sse_reg_i, |
| 9220 | ) }; |
| 9221 | param_sse_reg_i += 1; |
| 9222 | continue; |
| 9223 | }, |
| 9224 | }, |
| 8718 | 9225 | .memory => {}, // fallthrough |
| 8719 | 9226 | else => |class| return self.fail("TODO handle calling convention class {s}", .{ |
| 8720 | 9227 | @tagName(class), |
| ... | ... | @@ -8863,15 +9370,16 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 8863 | 9370 | } |
| 8864 | 9371 | |
| 8865 | 9372 | fn regBitSize(self: *Self, ty: Type) u64 { |
| 9373 | const abi_size = ty.abiSize(self.target.*); |
| 8866 | 9374 | return switch (ty.zigTypeTag()) { |
| 8867 | | else => switch (ty.abiSize(self.target.*)) { |
| 9375 | else => switch (abi_size) { |
| 8868 | 9376 | 1 => 8, |
| 8869 | 9377 | 2 => 16, |
| 8870 | 9378 | 3...4 => 32, |
| 8871 | 9379 | 5...8 => 64, |
| 8872 | 9380 | else => unreachable, |
| 8873 | 9381 | }, |
| 8874 | | .Float => switch (ty.abiSize(self.target.*)) { |
| 9382 | .Float => switch (abi_size) { |
| 8875 | 9383 | 1...16 => 128, |
| 8876 | 9384 | 17...32 => 256, |
| 8877 | 9385 | else => unreachable, |
| ... | ... | @@ -8882,17 +9390,3 @@ fn regBitSize(self: *Self, ty: Type) u64 { |
| 8882 | 9390 | fn regExtraBits(self: *Self, ty: Type) u64 { |
| 8883 | 9391 | return self.regBitSize(ty) - ty.bitSize(self.target.*); |
| 8884 | 9392 | } |
| 8885 | | |
| 8886 | | fn hasAvxSupport(target: Target) bool { |
| 8887 | | return Target.x86.featureSetHasAny(target.cpu.features, .{ .avx, .avx2 }); |
| 8888 | | } |
| 8889 | | |
| 8890 | | fn getSymbolIndexForDecl(self: *Self, decl_index: Module.Decl.Index) !u32 { |
| 8891 | | if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 8892 | | const atom = try macho_file.getOrCreateAtomForDecl(decl_index); |
| 8893 | | return macho_file.getAtom(atom).getSymbolIndex().?; |
| 8894 | | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 8895 | | const atom = try coff_file.getOrCreateAtomForDecl(decl_index); |
| 8896 | | return coff_file.getAtom(atom).getSymbolIndex().?; |
| 8897 | | } else unreachable; |
| 8898 | | } |