| author | |
| committer | |
| log | a2e2e25165b51ef92dbfbd9c46b6a01c90b250b3 |
| tree | 7a3889971c17987ed1644945f1399e3c4309ed92 |
| parent | 28923474401051a9aa0bddd60904b9be64943dba |
| parent | 3b1ea390a301dbdc992043d97cf618a94e8801de |
| signature |
x86_64: fixes for behavior tests36 files changed, 1578 insertions(+), 859 deletions(-)
lib/std/start.zig+1-1| ... | @@ -18,7 +18,7 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start"; | ... | @@ -18,7 +18,7 @@ const start_sym_name = if (native_arch.isMIPS()) "__start" else "_start"; |
| 18 | // Until then, we have simplified logic here for self-hosted. TODO remove this once | 18 | // Until then, we have simplified logic here for self-hosted. TODO remove this once |
| 19 | // self-hosted is capable enough to handle all of the real start.zig logic. | 19 | // self-hosted is capable enough to handle all of the real start.zig logic. |
| 20 | pub const simplified_logic = | 20 | pub const simplified_logic = |
| 21 | (builtin.zig_backend == .stage2_x86_64 and (builtin.link_libc or builtin.os.tag == .plan9)) or | 21 | (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .plan9) or |
| 22 | builtin.zig_backend == .stage2_x86 or | 22 | builtin.zig_backend == .stage2_x86 or |
| 23 | builtin.zig_backend == .stage2_aarch64 or | 23 | builtin.zig_backend == .stage2_aarch64 or |
| 24 | builtin.zig_backend == .stage2_arm or | 24 | builtin.zig_backend == .stage2_arm or |
lib/test_runner.zig+12-5| ... | @@ -13,7 +13,6 @@ var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer); | ... | @@ -13,7 +13,6 @@ var fba = std.heap.FixedBufferAllocator.init(&cmdline_buffer); |
| 13 | 13 | ||
| 14 | pub fn main() void { | 14 | pub fn main() void { |
| 15 | if (builtin.zig_backend == .stage2_wasm or | 15 | if (builtin.zig_backend == .stage2_wasm or |
| 16 | (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag != .linux) or | ||
| 17 | builtin.zig_backend == .stage2_aarch64) | 16 | builtin.zig_backend == .stage2_aarch64) |
| 18 | { | 17 | { |
| 19 | return mainSimple() catch @panic("test failure"); | 18 | return mainSimple() catch @panic("test failure"); |
| ... | @@ -234,25 +233,33 @@ pub fn log( | ... | @@ -234,25 +233,33 @@ pub fn log( |
| 234 | /// work-in-progress backends can handle it. | 233 | /// work-in-progress backends can handle it. |
| 235 | pub fn mainSimple() anyerror!void { | 234 | pub fn mainSimple() anyerror!void { |
| 236 | const enable_print = false; | 235 | const enable_print = false; |
| 236 | const print_all = false; | ||
| 237 | 237 | ||
| 238 | var passed: u64 = 0; | 238 | var passed: u64 = 0; |
| 239 | var skipped: u64 = 0; | 239 | var skipped: u64 = 0; |
| 240 | var failed: u64 = 0; | 240 | var failed: u64 = 0; |
| 241 | const stderr = if (enable_print) std.io.getStdErr() else {}; | 241 | const stderr = if (enable_print) std.io.getStdErr() else {}; |
| 242 | for (builtin.test_functions) |test_fn| { | 242 | for (builtin.test_functions) |test_fn| { |
| 243 | if (enable_print and print_all) { | ||
| 244 | stderr.writeAll(test_fn.name) catch {}; | ||
| 245 | stderr.writeAll("... ") catch {}; | ||
| 246 | } | ||
| 243 | test_fn.func() catch |err| { | 247 | test_fn.func() catch |err| { |
| 244 | if (enable_print) stderr.writeAll(test_fn.name) catch {}; | 248 | if (enable_print and !print_all) { |
| 249 | stderr.writeAll(test_fn.name) catch {}; | ||
| 250 | stderr.writeAll("... ") catch {}; | ||
| 251 | } | ||
| 245 | if (err != error.SkipZigTest) { | 252 | if (err != error.SkipZigTest) { |
| 246 | if (enable_print) stderr.writeAll("... FAIL\n") catch {}; | 253 | if (enable_print) stderr.writeAll("FAIL\n") catch {}; |
| 247 | failed += 1; | 254 | failed += 1; |
| 248 | if (!enable_print) return err; | 255 | if (!enable_print) return err; |
| 249 | continue; | 256 | continue; |
| 250 | } | 257 | } |
| 251 | if (enable_print) stderr.writeAll("... SKIP\n") catch {}; | 258 | if (enable_print) stderr.writeAll("SKIP\n") catch {}; |
| 252 | skipped += 1; | 259 | skipped += 1; |
| 253 | continue; | 260 | continue; |
| 254 | }; | 261 | }; |
| 255 | //if (enable_print) stderr.writeAll("... PASS\n") catch {}; | 262 | if (enable_print and print_all) stderr.writeAll("PASS\n") catch {}; |
| 256 | passed += 1; | 263 | passed += 1; |
| 257 | } | 264 | } |
| 258 | if (enable_print) { | 265 | if (enable_print) { |
src/Sema.zig+3-6| ... | @@ -23287,8 +23287,7 @@ fn panicWithMsg( | ... | @@ -23287,8 +23287,7 @@ fn panicWithMsg( |
| 23287 | const arena = sema.arena; | 23287 | const arena = sema.arena; |
| 23288 | 23288 | ||
| 23289 | if (!mod.backendSupportsFeature(.panic_fn)) { | 23289 | if (!mod.backendSupportsFeature(.panic_fn)) { |
| 23290 | _ = try block.addNoOp(.breakpoint); | 23290 | _ = try block.addNoOp(.trap); |
| 23291 | _ = try block.addNoOp(.unreach); | ||
| 23292 | return; | 23291 | return; |
| 23293 | } | 23292 | } |
| 23294 | const panic_fn = try sema.getBuiltin("panic"); | 23293 | const panic_fn = try sema.getBuiltin("panic"); |
| ... | @@ -23336,8 +23335,7 @@ fn panicUnwrapError( | ... | @@ -23336,8 +23335,7 @@ fn panicUnwrapError( |
| 23336 | 23335 | ||
| 23337 | { | 23336 | { |
| 23338 | if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) { | 23337 | if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) { |
| 23339 | _ = try fail_block.addNoOp(.breakpoint); | 23338 | _ = try fail_block.addNoOp(.trap); |
| 23340 | _ = try fail_block.addNoOp(.unreach); | ||
| 23341 | } else { | 23339 | } else { |
| 23342 | const panic_fn = try sema.getBuiltin("panicUnwrapError"); | 23340 | const panic_fn = try sema.getBuiltin("panicUnwrapError"); |
| 23343 | const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand); | 23341 | const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand); |
| ... | @@ -23462,8 +23460,7 @@ fn safetyCheckFormatted( | ... | @@ -23462,8 +23460,7 @@ fn safetyCheckFormatted( |
| 23462 | defer fail_block.instructions.deinit(gpa); | 23460 | defer fail_block.instructions.deinit(gpa); |
| 23463 | 23461 | ||
| 23464 | if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) { | 23462 | if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) { |
| 23465 | _ = try fail_block.addNoOp(.breakpoint); | 23463 | _ = try fail_block.addNoOp(.trap); |
| 23466 | _ = try fail_block.addNoOp(.unreach); | ||
| 23467 | } else { | 23464 | } else { |
| 23468 | const panic_fn = try sema.getBuiltin(func); | 23465 | const panic_fn = try sema.getBuiltin(func); |
| 23469 | _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null); | 23466 | _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null); |
src/arch/x86_64/CodeGen.zig+1115-621| ... | @@ -7,6 +7,8 @@ const leb128 = std.leb; | ... | @@ -7,6 +7,8 @@ const leb128 = std.leb; |
| 7 | const link = @import("../../link.zig"); | 7 | const link = @import("../../link.zig"); |
| 8 | const log = std.log.scoped(.codegen); | 8 | const log = std.log.scoped(.codegen); |
| 9 | const tracking_log = std.log.scoped(.tracking); | 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 | const math = std.math; | 12 | const math = std.math; |
| 11 | const mem = std.mem; | 13 | const mem = std.mem; |
| 12 | const trace = @import("../../tracy.zig").trace; | 14 | const trace = @import("../../tracy.zig").trace; |
| ... | @@ -48,16 +50,13 @@ const sse = abi.RegisterClass.sse; | ... | @@ -48,16 +50,13 @@ const sse = abi.RegisterClass.sse; |
| 48 | 50 | ||
| 49 | const InnerError = CodeGenError || error{OutOfRegisters}; | 51 | const InnerError = CodeGenError || error{OutOfRegisters}; |
| 50 | 52 | ||
| 51 | const debug_wip_mir = false; | ||
| 52 | const debug_tracking = false; | ||
| 53 | |||
| 54 | gpa: Allocator, | 53 | gpa: Allocator, |
| 55 | air: Air, | 54 | air: Air, |
| 56 | liveness: Liveness, | 55 | liveness: Liveness, |
| 57 | bin_file: *link.File, | 56 | bin_file: *link.File, |
| 58 | debug_output: DebugInfoOutput, | 57 | debug_output: DebugInfoOutput, |
| 59 | target: *const std.Target, | 58 | target: *const std.Target, |
| 60 | mod_fn: *const Module.Fn, | 59 | owner: Owner, |
| 61 | err_msg: ?*ErrorMsg, | 60 | err_msg: ?*ErrorMsg, |
| 62 | args: []MCValue, | 61 | args: []MCValue, |
| 63 | ret_mcv: InstTracking, | 62 | ret_mcv: InstTracking, |
| ... | @@ -109,6 +108,44 @@ const mir_to_air_map_init = if (builtin.mode == .Debug) std.AutoHashMapUnmanaged | ... | @@ -109,6 +108,44 @@ const mir_to_air_map_init = if (builtin.mode == .Debug) std.AutoHashMapUnmanaged |
| 109 | const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; | 108 | const FrameAddr = struct { index: FrameIndex, off: i32 = 0 }; |
| 110 | const RegisterOffset = struct { reg: Register, off: i32 = 0 }; | 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 | pub const MCValue = union(enum) { | 149 | pub const MCValue = union(enum) { |
| 113 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. | 150 | /// No runtime bits. `void` types, empty structs, u0, enums with 1 tag, etc. |
| 114 | /// TODO Look into deleting this tag and using `dead` instead, since every use | 151 | /// TODO Look into deleting this tag and using `dead` instead, since every use |
| ... | @@ -220,9 +257,9 @@ pub const MCValue = union(enum) { | ... | @@ -220,9 +257,9 @@ pub const MCValue = union(enum) { |
| 220 | .dead, | 257 | .dead, |
| 221 | .undef, | 258 | .undef, |
| 222 | .immediate, | 259 | .immediate, |
| 260 | .eflags, | ||
| 223 | .register, | 261 | .register, |
| 224 | .register_offset, | 262 | .register_offset, |
| 225 | .eflags, | ||
| 226 | .register_overflow, | 263 | .register_overflow, |
| 227 | .lea_direct, | 264 | .lea_direct, |
| 228 | .lea_got, | 265 | .lea_got, |
| ... | @@ -298,6 +335,41 @@ pub const MCValue = union(enum) { | ... | @@ -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 | pub fn format( | 373 | pub fn format( |
| 302 | mcv: MCValue, | 374 | mcv: MCValue, |
| 303 | comptime _: []const u8, | 375 | comptime _: []const u8, |
| ... | @@ -575,12 +647,6 @@ pub fn generate( | ... | @@ -575,12 +647,6 @@ pub fn generate( |
| 575 | assert(fn_owner_decl.has_tv); | 647 | assert(fn_owner_decl.has_tv); |
| 576 | const fn_type = fn_owner_decl.ty; | 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 | const gpa = bin_file.allocator; | 650 | const gpa = bin_file.allocator; |
| 585 | var function = Self{ | 651 | var function = Self{ |
| 586 | .gpa = gpa, | 652 | .gpa = gpa, |
| ... | @@ -589,7 +655,7 @@ pub fn generate( | ... | @@ -589,7 +655,7 @@ pub fn generate( |
| 589 | .target = &bin_file.options.target, | 655 | .target = &bin_file.options.target, |
| 590 | .bin_file = bin_file, | 656 | .bin_file = bin_file, |
| 591 | .debug_output = debug_output, | 657 | .debug_output = debug_output, |
| 592 | .mod_fn = module_fn, | 658 | .owner = .{ .mod_fn = module_fn }, |
| 593 | .err_msg = null, | 659 | .err_msg = null, |
| 594 | .args = undefined, // populated after `resolveCallingConventionValues` | 660 | .args = undefined, // populated after `resolveCallingConventionValues` |
| 595 | .ret_mcv = undefined, // populated after `resolveCallingConventionValues` | 661 | .ret_mcv = undefined, // populated after `resolveCallingConventionValues` |
| ... | @@ -614,6 +680,8 @@ pub fn generate( | ... | @@ -614,6 +680,8 @@ pub fn generate( |
| 614 | if (builtin.mode == .Debug) function.mir_to_air_map.deinit(gpa); | 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 | try function.frame_allocs.resize(gpa, FrameIndex.named_count); | 685 | try function.frame_allocs.resize(gpa, FrameIndex.named_count); |
| 618 | function.frame_allocs.set( | 686 | function.frame_allocs.set( |
| 619 | @enumToInt(FrameIndex.stack_frame), | 687 | @enumToInt(FrameIndex.stack_frame), |
| ... | @@ -715,48 +783,190 @@ pub fn generate( | ... | @@ -715,48 +783,190 @@ pub fn generate( |
| 715 | } | 783 | } |
| 716 | } | 784 | } |
| 717 | 785 | ||
| 718 | fn dumpWipMir(self: *Self, inst: Mir.Inst) !void { | 786 | pub fn generateLazy( |
| 719 | if (!debug_wip_mir) return; | 787 | bin_file: *link.File, |
| 720 | const stderr = std.io.getStdErr().writer(); | 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 | var lower = Lower{ | 922 | var lower = Lower{ |
| 723 | .allocator = self.gpa, | 923 | .allocator = data.self.gpa, |
| 724 | .mir = .{ | 924 | .mir = .{ |
| 725 | .instructions = self.mir_instructions.slice(), | 925 | .instructions = data.self.mir_instructions.slice(), |
| 726 | .extra = self.mir_extra.items, | 926 | .extra = data.self.mir_extra.items, |
| 727 | .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), | 927 | .frame_locs = (std.MultiArrayList(Mir.FrameLoc){}).slice(), |
| 728 | }, | 928 | }, |
| 729 | .target = self.target, | 929 | .target = data.self.target, |
| 730 | .src_loc = self.src_loc, | 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 | error.LowerFail => { | 933 | error.LowerFail => { |
| 734 | defer { | 934 | defer { |
| 735 | lower.err_msg.?.deinit(self.gpa); | 935 | lower.err_msg.?.deinit(data.self.gpa); |
| 736 | lower.err_msg = null; | 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 | return; | 939 | return; |
| 740 | }, | 940 | }, |
| 741 | error.InvalidInstruction, error.CannotEncode => |e| { | 941 | error.OutOfMemory, error.InvalidInstruction, error.CannotEncode => |e| { |
| 742 | try stderr.writeAll(switch (e) { | 942 | try writer.writeAll(switch (e) { |
| 743 | error.InvalidInstruction => "CodeGen failed to find a viable instruction.\n", | 943 | error.OutOfMemory => "Out of memory", |
| 744 | error.CannotEncode => "CodeGen failed to encode the instruction.\n", | 944 | error.InvalidInstruction => "CodeGen failed to find a viable instruction.", |
| 945 | error.CannotEncode => "CodeGen failed to encode the instruction.", | ||
| 745 | }); | 946 | }); |
| 746 | return; | 947 | return; |
| 747 | }, | 948 | }, |
| 748 | else => |e| return e, | 949 | else => |e| return e, |
| 749 | }) |lower_inst| { | 950 | }) |lower_inst| try writer.print(" | {}", .{lower_inst}); |
| 750 | try stderr.print(" | {}\n", .{lower_inst}); | 951 | } |
| 751 | } | 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 { | 956 | const FormatTrackingData = struct { |
| 755 | if (!debug_tracking) return; | 957 | self: *Self, |
| 756 | const stderr = std.io.getStdErr().writer(); | 958 | }; |
| 757 | 959 | fn formatTracking( | |
| 758 | var it = self.inst_tracking.iterator(); | 960 | data: FormatTrackingData, |
| 759 | while (it.next()) |entry| try stderr.print("%{d} = {}\n", .{ entry.key_ptr.*, entry.value_ptr.* }); | 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 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { | 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,7 +974,14 @@ fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 764 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); | 974 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); |
| 765 | const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len); | 975 | const result_index = @intCast(Mir.Inst.Index, self.mir_instructions.len); |
| 766 | self.mir_instructions.appendAssumeCapacity(inst); | 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 | return result_index; | 985 | return result_index; |
| 769 | } | 986 | } |
| 770 | 987 | ||
| ... | @@ -1186,13 +1403,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -1186,13 +1403,8 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1186 | } | 1403 | } |
| 1187 | 1404 | ||
| 1188 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue; | 1405 | if (self.liveness.isUnused(inst) and !self.air.mustLower(inst)) continue; |
| 1189 | if (debug_wip_mir) @import("../../print_air.zig").dumpInst( | 1406 | wip_mir_log.debug("{}", .{self.fmtAir(inst)}); |
| 1190 | inst, | 1407 | verbose_tracking_log.debug("{}", .{self.fmtTracking()}); |
| 1191 | self.bin_file.options.module.?, | ||
| 1192 | self.air, | ||
| 1193 | self.liveness, | ||
| 1194 | ); | ||
| 1195 | self.dumpTracking() catch {}; | ||
| 1196 | 1408 | ||
| 1197 | const old_air_bookkeeping = self.air_bookkeeping; | 1409 | const old_air_bookkeeping = self.air_bookkeeping; |
| 1198 | try self.inst_tracking.ensureUnusedCapacity(self.gpa, 1); | 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,9 +1456,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { |
| 1244 | .ceil, | 1456 | .ceil, |
| 1245 | .round, | 1457 | .round, |
| 1246 | .trunc_float, | 1458 | .trunc_float, |
| 1247 | .neg, | ||
| 1248 | => try self.airUnaryMath(inst), | 1459 | => try self.airUnaryMath(inst), |
| 1249 | 1460 | ||
| 1461 | .neg => try self.airNeg(inst), | ||
| 1462 | |||
| 1250 | .add_with_overflow => try self.airAddSubWithOverflow(inst), | 1463 | .add_with_overflow => try self.airAddSubWithOverflow(inst), |
| 1251 | .sub_with_overflow => try self.airAddSubWithOverflow(inst), | 1464 | .sub_with_overflow => try self.airAddSubWithOverflow(inst), |
| 1252 | .mul_with_overflow => try self.airMulWithOverflow(inst), | 1465 | .mul_with_overflow => try self.airMulWithOverflow(inst), |
| ... | @@ -1453,7 +1666,69 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void { | ... | @@ -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 | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { | 1734 | fn getValue(self: *Self, value: MCValue, inst: ?Air.Inst.Index) void { |
| ... | @@ -1619,15 +1894,16 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { | ... | @@ -1619,15 +1894,16 @@ fn allocFrameIndex(self: *Self, alloc: FrameAlloc) !FrameIndex { |
| 1619 | const frame_allocs_slice = self.frame_allocs.slice(); | 1894 | const frame_allocs_slice = self.frame_allocs.slice(); |
| 1620 | const frame_size = frame_allocs_slice.items(.abi_size); | 1895 | const frame_size = frame_allocs_slice.items(.abi_size); |
| 1621 | const frame_align = frame_allocs_slice.items(.abi_align); | 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 | for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { | 1901 | for (self.free_frame_indices.keys(), 0..) |frame_index, free_i| { |
| 1623 | const abi_size = frame_size[@enumToInt(frame_index)]; | 1902 | const abi_size = frame_size[@enumToInt(frame_index)]; |
| 1624 | if (abi_size != alloc.abi_size) continue; | 1903 | if (abi_size != alloc.abi_size) continue; |
| 1625 | const abi_align = &frame_align[@enumToInt(frame_index)]; | 1904 | const abi_align = &frame_align[@enumToInt(frame_index)]; |
| 1626 | abi_align.* = @max(abi_align.*, alloc.abi_align); | 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 | _ = self.free_frame_indices.swapRemoveAt(free_i); | 1907 | _ = self.free_frame_indices.swapRemoveAt(free_i); |
| 1632 | return frame_index; | 1908 | return frame_index; |
| 1633 | } | 1909 | } |
| ... | @@ -1828,7 +2104,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void { | ... | @@ -1828,7 +2104,7 @@ pub fn spillRegisters(self: *Self, registers: []const Register) !void { |
| 1828 | /// allocated. A second call to `copyToTmpRegister` may return the same register. | 2104 | /// allocated. A second call to `copyToTmpRegister` may return the same register. |
| 1829 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 2105 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 1830 | fn copyToTmpRegister(self: *Self, ty: Type, mcv: MCValue) !Register { | 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 | try self.genSetReg(reg, ty, mcv); | 2108 | try self.genSetReg(reg, ty, mcv); |
| 1833 | return reg; | 2109 | return reg; |
| 1834 | } | 2110 | } |
| ... | @@ -1871,16 +2147,48 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1871,16 +2147,48 @@ fn airRetPtr(self: *Self, inst: Air.Inst.Index) !void { |
| 1871 | 2147 | ||
| 1872 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { | 2148 | fn airFptrunc(self: *Self, inst: Air.Inst.Index) !void { |
| 1873 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2149 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1874 | _ = ty_op; | 2150 | const dst_ty = self.air.typeOfIndex(inst); |
| 1875 | return self.fail("TODO implement airFptrunc for {}", .{self.target.cpu.arch}); | 2151 | const src_ty = self.air.typeOf(ty_op.operand); |
| 1876 | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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 | fn airFpext(self: *Self, inst: Air.Inst.Index) !void { | 2171 | fn airFpext(self: *Self, inst: Air.Inst.Index) !void { |
| 1880 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 2172 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 1881 | _ = ty_op; | 2173 | const dst_ty = self.air.typeOfIndex(inst); |
| 1882 | return self.fail("TODO implement airFpext for {}", .{self.target.cpu.arch}); | 2174 | const src_ty = self.air.typeOf(ty_op.operand); |
| 1883 | // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | 2194 | fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -1928,13 +2236,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -1928,13 +2236,10 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { |
| 1928 | registerAlias(src_reg, min_abi_size), | 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 | tag, | 2240 | tag, |
| 1933 | dst_alias, | 2241 | dst_alias, |
| 1934 | Memory.sib(Memory.PtrSize.fromSize(min_abi_size), .{ | 2242 | src_mcv.mem(Memory.PtrSize.fromSize(min_abi_size)), |
| 1935 | .base = .{ .frame = frame_addr.index }, | ||
| 1936 | .disp = frame_addr.off, | ||
| 1937 | }), | ||
| 1938 | ), | 2243 | ), |
| 1939 | else => return self.fail("TODO airIntCast from {s} to {s}", .{ | 2244 | else => return self.fail("TODO airIntCast from {s} to {s}", .{ |
| 1940 | @tagName(src_mcv), | 2245 | @tagName(src_mcv), |
| ... | @@ -2102,6 +2407,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2102,6 +2407,7 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void { |
| 2102 | } }; | 2407 | } }; |
| 2103 | const src_ty = Type.initPayload(&src_pl.base); | 2408 | const src_ty = Type.initPayload(&src_pl.base); |
| 2104 | 2409 | ||
| 2410 | try self.spillEflagsIfOccupied(); | ||
| 2105 | try self.spillRegisters(&.{ .rax, .rdx }); | 2411 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 2106 | const lhs = try self.resolveInst(bin_op.lhs); | 2412 | const lhs = try self.resolveInst(bin_op.lhs); |
| 2107 | const rhs = try self.resolveInst(bin_op.rhs); | 2413 | const rhs = try self.resolveInst(bin_op.rhs); |
| ... | @@ -2315,12 +2621,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2315,12 +2621,7 @@ fn airAddSubWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2315 | 2621 | ||
| 2316 | const frame_index = | 2622 | const frame_index = |
| 2317 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 2623 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); |
| 2318 | try self.genSetFrameTruncatedOverflowCompare( | 2624 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 2319 | tuple_ty, | ||
| 2320 | frame_index, | ||
| 2321 | partial_mcv.register, | ||
| 2322 | cc, | ||
| 2323 | ); | ||
| 2324 | break :result .{ .load_frame = .{ .index = frame_index } }; | 2625 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 2325 | }, | 2626 | }, |
| 2326 | else => unreachable, | 2627 | else => unreachable, |
| ... | @@ -2392,12 +2693,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -2392,12 +2693,7 @@ fn airShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2392 | 2693 | ||
| 2393 | const frame_index = | 2694 | const frame_index = |
| 2394 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 2695 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); |
| 2395 | try self.genSetFrameTruncatedOverflowCompare( | 2696 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 2396 | tuple_ty, | ||
| 2397 | frame_index, | ||
| 2398 | partial_mcv.register, | ||
| 2399 | cc, | ||
| 2400 | ); | ||
| 2401 | break :result .{ .load_frame = .{ .index = frame_index } }; | 2697 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 2402 | }, | 2698 | }, |
| 2403 | else => unreachable, | 2699 | else => unreachable, |
| ... | @@ -2410,173 +2706,175 @@ fn genSetFrameTruncatedOverflowCompare( | ... | @@ -2410,173 +2706,175 @@ fn genSetFrameTruncatedOverflowCompare( |
| 2410 | self: *Self, | 2706 | self: *Self, |
| 2411 | tuple_ty: Type, | 2707 | tuple_ty: Type, |
| 2412 | frame_index: FrameIndex, | 2708 | frame_index: FrameIndex, |
| 2413 | reg: Register, | 2709 | src_mcv: MCValue, |
| 2414 | cc: Condition, | 2710 | overflow_cc: ?Condition, |
| 2415 | ) !void { | 2711 | ) !void { |
| 2416 | const reg_lock = self.register_manager.lockReg(reg); | 2712 | const src_lock = switch (src_mcv) { |
| 2417 | defer if (reg_lock) |lock| self.register_manager.unlockReg(lock); | 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 | const ty = tuple_ty.structFieldType(0); | 2718 | const ty = tuple_ty.structFieldType(0); |
| 2420 | const int_info = ty.intInfo(self.target.*); | 2719 | const int_info = ty.intInfo(self.target.*); |
| 2421 | const extended_ty = switch (int_info.signedness) { | 2720 | |
| 2422 | .signed => Type.isize, | 2721 | var hi_limb_pl = Type.Payload.Bits{ |
| 2423 | .unsigned => ty, | 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); | 2730 | var rest_pl = Type.Payload.Bits{ |
| 2427 | const temp_regs_locks = self.register_manager.lockRegsAssumeUnused(3, temp_regs); | 2731 | .base = .{ .tag = .int_unsigned }, |
| 2428 | defer for (temp_regs_locks) |rreg| { | 2732 | .data = int_info.bits - hi_limb_pl.data, |
| 2429 | self.register_manager.unlockReg(rreg); | ||
| 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 | const overflow_reg = temp_regs[0]; | 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 | const scratch_reg = temp_regs[1]; | 2743 | const scratch_reg = temp_regs[1]; |
| 2436 | try self.genSetReg(scratch_reg, extended_ty, .{ .register = reg }); | 2744 | const hi_limb_off = if (int_info.bits <= 64) 0 else (int_info.bits - 1) / 64 * 8; |
| 2437 | try self.truncateRegister(ty, scratch_reg); | 2745 | const hi_limb_mcv = if (hi_limb_off > 0) |
| 2438 | try self.genBinOpMir( | 2746 | src_mcv.address().offset(int_info.bits / 64 * 8).deref() |
| 2439 | .cmp, | 2747 | else |
| 2440 | extended_ty, | 2748 | src_mcv; |
| 2441 | .{ .register = reg }, | 2749 | try self.genSetReg(scratch_reg, hi_limb_ty, hi_limb_mcv); |
| 2442 | .{ .register = scratch_reg }, | 2750 | try self.truncateRegister(hi_limb_ty, scratch_reg); |
| 2443 | ); | 2751 | try self.genBinOpMir(.cmp, hi_limb_ty, .{ .register = scratch_reg }, hi_limb_mcv); |
| 2444 | 2752 | ||
| 2445 | const eq_reg = temp_regs[2]; | 2753 | const eq_reg = temp_regs[2]; |
| 2446 | try self.asmSetccRegister(eq_reg.to8(), .ne); | 2754 | if (overflow_cc) |_| { |
| 2447 | try self.genBinOpMir( | 2755 | try self.asmSetccRegister(eq_reg.to8(), .ne); |
| 2448 | .@"or", | 2756 | try self.genBinOpMir(.@"or", Type.u8, .{ .register = overflow_reg }, .{ .register = eq_reg }); |
| 2449 | Type.u8, | 2757 | } |
| 2450 | .{ .register = overflow_reg }, | ||
| 2451 | .{ .register = eq_reg }, | ||
| 2452 | ); | ||
| 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 | try self.genSetMem( | 2761 | try self.genSetMem( |
| 2455 | .{ .frame = frame_index }, | 2762 | .{ .frame = frame_index }, |
| 2456 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), | 2763 | payload_off + hi_limb_off, |
| 2457 | tuple_ty.structFieldType(1), | 2764 | hi_limb_ty, |
| 2458 | .{ .register = overflow_reg.to8() }, | 2765 | .{ .register = scratch_reg }, |
| 2459 | ); | 2766 | ); |
| 2460 | try self.genSetMem( | 2767 | try self.genSetMem( |
| 2461 | .{ .frame = frame_index }, | 2768 | .{ .frame = frame_index }, |
| 2462 | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), | 2769 | @intCast(i32, tuple_ty.structFieldOffset(1, self.target.*)), |
| 2463 | ty, | 2770 | tuple_ty.structFieldType(1), |
| 2464 | .{ .register = scratch_reg }, | 2771 | if (overflow_cc) |_| .{ .register = overflow_reg.to8() } else .{ .eflags = .ne }, |
| 2465 | ); | 2772 | ); |
| 2466 | } | 2773 | } |
| 2467 | 2774 | ||
| 2468 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { | 2775 | fn airMulWithOverflow(self: *Self, inst: Air.Inst.Index) !void { |
| 2469 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 2776 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 2470 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 2777 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 2471 | const result: MCValue = result: { | 2778 | const dst_ty = self.air.typeOf(bin_op.lhs); |
| 2472 | const dst_ty = self.air.typeOf(bin_op.lhs); | 2779 | const result: MCValue = switch (dst_ty.zigTypeTag()) { |
| 2473 | switch (dst_ty.zigTypeTag()) { | 2780 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), |
| 2474 | .Vector => return self.fail("TODO implement mul_with_overflow for Vector type", .{}), | 2781 | .Int => result: { |
| 2475 | .Int => { | 2782 | try self.spillEflagsIfOccupied(); |
| 2476 | try self.spillEflagsIfOccupied(); | 2783 | try self.spillRegisters(&.{ .rax, .rdx }); |
| 2477 | 2784 | ||
| 2478 | const dst_info = dst_ty.intInfo(self.target.*); | 2785 | const dst_info = dst_ty.intInfo(self.target.*); |
| 2479 | const cc: Condition = switch (dst_info.signedness) { | 2786 | const cc: Condition = switch (dst_info.signedness) { |
| 2480 | .unsigned => .c, | 2787 | .unsigned => .c, |
| 2481 | .signed => .o, | 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); | 2814 | const dst_reg: Register = blk: { |
| 2485 | if (dst_info.bits >= 8 and math.isPowerOfTwo(dst_info.bits)) { | 2815 | if (lhs.isRegister()) break :blk lhs.register; |
| 2486 | var src_pl = Type.Payload.Bits{ .base = .{ .tag = switch (dst_info.signedness) { | 2816 | break :blk try self.copyToTmpRegister(dst_ty, lhs); |
| 2487 | .signed => .int_signed, | 2817 | }; |
| 2488 | .unsigned => .int_unsigned, | 2818 | const dst_mcv = MCValue{ .register = dst_reg }; |
| 2489 | } }, .data = math.max3( | 2819 | const dst_reg_lock = self.register_manager.lockRegAssumeUnused(dst_reg); |
| 2490 | self.activeIntBits(bin_op.lhs), | 2820 | defer self.register_manager.unlockReg(dst_reg_lock); |
| 2491 | self.activeIntBits(bin_op.rhs), | ||
| 2492 | dst_info.bits / 2, | ||
| 2493 | ) }; | ||
| 2494 | const src_ty = Type.initPayload(&src_pl.base); | ||
| 2495 | 2821 | ||
| 2496 | try self.spillRegisters(&.{ .rax, .rdx }); | 2822 | const rhs_mcv: MCValue = blk: { |
| 2497 | const lhs = try self.resolveInst(bin_op.lhs); | 2823 | if (rhs.isRegister() or rhs.isMemory()) break :blk rhs; |
| 2498 | const rhs = try self.resolveInst(bin_op.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); | 2832 | try self.genIntMulComplexOpMir(Type.isize, dst_mcv, rhs_mcv); |
| 2501 | switch (partial_mcv) { | 2833 | break :dst dst_mcv; |
| 2502 | .register => |reg| { | 2834 | } else try self.genMulDivBinOp(.mul, null, dst_ty, src_ty, lhs, rhs); |
| 2503 | self.eflags_inst = inst; | ||
| 2504 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; | ||
| 2505 | }, | ||
| 2506 | else => {}, | ||
| 2507 | } | ||
| 2508 | 2835 | ||
| 2509 | // For now, this is the only supported multiply that doesn't fit in a register. | 2836 | switch (partial_mcv) { |
| 2510 | assert(dst_info.bits == 128 and src_pl.data == 64); | 2837 | .register => |reg| if (extra_bits == 0) { |
| 2838 | self.eflags_inst = inst; | ||
| 2839 | break :result .{ .register_overflow = .{ .reg = reg, .eflags = cc } }; | ||
| 2840 | } else { | ||
| 2511 | const frame_index = | 2841 | const frame_index = |
| 2512 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 2842 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); |
| 2513 | try self.genSetMem( | 2843 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, partial_mcv, cc); |
| 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 | ); | ||
| 2525 | break :result .{ .load_frame = .{ .index = frame_index } }; | 2844 | break :result .{ .load_frame = .{ .index = frame_index } }; |
| 2526 | } | 2845 | }, |
| 2527 | 2846 | else => { | |
| 2528 | const dst_reg: Register = dst_reg: { | 2847 | // For now, this is the only supported multiply that doesn't fit in a register, |
| 2529 | switch (dst_info.signedness) { | 2848 | // so cc being set is impossible. |
| 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); | ||
| 2566 | 2849 | ||
| 2567 | const dst_mcv = try self.genMulDivBinOp(.mul, null, dst_ty, dst_ty, lhs, rhs); | 2850 | assert(dst_info.bits <= 128 and src_pl.data == 64); |
| 2568 | break :dst_reg dst_mcv.register; | ||
| 2569 | }, | ||
| 2570 | } | ||
| 2571 | }; | ||
| 2572 | 2851 | ||
| 2573 | const frame_index = | 2852 | const frame_index = |
| 2574 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); | 2853 | try self.allocFrameIndex(FrameAlloc.initType(tuple_ty, self.target.*)); |
| 2575 | try self.genSetFrameTruncatedOverflowCompare(tuple_ty, frame_index, dst_reg, cc); | 2854 | if (dst_info.bits >= lhs_active_bits + rhs_active_bits) { |
| 2576 | break :result .{ .load_frame = .{ .index = frame_index } }; | 2855 | try self.genSetMem( |
| 2577 | }, | 2856 | .{ .frame = frame_index }, |
| 2578 | else => unreachable, | 2857 | @intCast(i32, tuple_ty.structFieldOffset(0, self.target.*)), |
| 2579 | } | 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 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); | 2879 | return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none }); |
| 2582 | } | 2880 | } |
| ... | @@ -2616,19 +2914,9 @@ fn genIntMulDivOpMir( | ... | @@ -2616,19 +2914,9 @@ fn genIntMulDivOpMir( |
| 2616 | }; | 2914 | }; |
| 2617 | switch (mat_rhs) { | 2915 | switch (mat_rhs) { |
| 2618 | .register => |reg| try self.asmRegister(tag, registerAlias(reg, abi_size)), | 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 | tag, | 2918 | tag, |
| 2621 | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (mat_rhs) { | 2919 | mat_rhs.mem(Memory.PtrSize.fromSize(abi_size)), |
| 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 | }), | ||
| 2632 | ), | 2920 | ), |
| 2633 | else => unreachable, | 2921 | else => unreachable, |
| 2634 | } | 2922 | } |
| ... | @@ -3900,10 +4188,65 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -3900,10 +4188,65 @@ fn airBitReverse(self: *Self, inst: Air.Inst.Index) !void { |
| 3900 | return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none }); | 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 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { | 4244 | fn airUnaryMath(self: *Self, inst: Air.Inst.Index) !void { |
| 3904 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 4245 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 3905 | _ = un_op; | 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 | //return self.finishAir(inst, result, .{ un_op, .none, .none }); | 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,7 +4399,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerErro |
| 4056 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | 4399 | fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4057 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 4400 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 4058 | const elem_ty = self.air.typeOfIndex(inst); | 4401 | const elem_ty = self.air.typeOfIndex(inst); |
| 4059 | const elem_size = elem_ty.abiSize(self.target.*); | ||
| 4060 | const result: MCValue = result: { | 4402 | const result: MCValue = result: { |
| 4061 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; | 4403 | if (!elem_ty.hasRuntimeBitsIgnoreComptime()) break :result .none; |
| 4062 | 4404 | ||
| ... | @@ -4064,14 +4406,20 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4064,14 +4406,20 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void { |
| 4064 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx }); | 4406 | const reg_locks = self.register_manager.lockRegsAssumeUnused(3, .{ .rdi, .rsi, .rcx }); |
| 4065 | defer for (reg_locks) |lock| self.register_manager.unlockReg(lock); | 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 | const ptr_mcv = try self.resolveInst(ty_op.operand); | 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 | // The MCValue that holds the pointer can be re-used as the value. | 4418 | // The MCValue that holds the pointer can be re-used as the value. |
| 4070 | ptr_mcv | 4419 | ptr_mcv |
| 4071 | else | 4420 | else |
| 4072 | try self.allocRegOrMem(inst, true); | 4421 | try self.allocRegOrMem(inst, true); |
| 4073 | 4422 | ||
| 4074 | const ptr_ty = self.air.typeOf(ty_op.operand); | ||
| 4075 | if (ptr_ty.ptrInfo().data.host_size > 0) { | 4423 | if (ptr_ty.ptrInfo().data.host_size > 0) { |
| 4076 | try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv); | 4424 | try self.packedLoad(dst_mcv, ptr_ty, ptr_mcv); |
| 4077 | } else { | 4425 | } else { |
| ... | @@ -4293,17 +4641,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4293,17 +4641,9 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4293 | 4641 | ||
| 4294 | switch (src_mcv) { | 4642 | switch (src_mcv) { |
| 4295 | .load_frame => |frame_addr| { | 4643 | .load_frame => |frame_addr| { |
| 4296 | const field_abi_size = @intCast(u32, field_ty.abiSize(self.target.*)); | 4644 | if (field_off % 8 == 0) { |
| 4297 | const limb_abi_size = @min(field_abi_size, 8); | 4645 | const off_mcv = |
| 4298 | const limb_abi_bits = limb_abi_size * 8; | 4646 | src_mcv.address().offset(@intCast(i32, @divExact(field_off, 8))).deref(); |
| 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 | } }; | ||
| 4307 | if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result off_mcv; | 4647 | if (self.reuseOperand(inst, operand, 0, src_mcv)) break :result off_mcv; |
| 4308 | 4648 | ||
| 4309 | const dst_mcv = try self.allocRegOrMem(inst, true); | 4649 | const dst_mcv = try self.allocRegOrMem(inst, true); |
| ... | @@ -4311,6 +4651,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -4311,6 +4651,12 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void { |
| 4311 | break :result dst_mcv; | 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 | if (field_abi_size > 8) { | 4660 | if (field_abi_size > 8) { |
| 4315 | return self.fail("TODO implement struct_field_val with large packed field", .{}); | 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,9 +4794,6 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 4448 | if (src_ty.zigTypeTag() == .Vector) { | 4794 | if (src_ty.zigTypeTag() == .Vector) { |
| 4449 | return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)}); | 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 | switch (src_mcv) { | 4798 | switch (src_mcv) { |
| 4456 | .eflags => |cc| switch (tag) { | 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,13 +4809,13 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 4466 | }; | 4809 | }; |
| 4467 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); | 4810 | defer if (src_lock) |lock| self.register_manager.unlockReg(lock); |
| 4468 | 4811 | ||
| 4469 | const dst_mcv: MCValue = if (maybe_inst) |inst| | 4812 | const dst_mcv: MCValue = dst: { |
| 4470 | if (self.reuseOperand(inst, src_air, 0, src_mcv)) | 4813 | if (maybe_inst) |inst| if (self.reuseOperand(inst, src_air, 0, src_mcv)) break :dst src_mcv; |
| 4471 | src_mcv | 4814 | |
| 4472 | else | 4815 | const dst_mcv = try self.allocRegOrMemAdvanced(src_ty, maybe_inst, true); |
| 4473 | try self.copyToRegisterWithInstTracking(inst, src_ty, src_mcv) | 4816 | try self.genCopy(src_ty, dst_mcv, src_mcv); |
| 4474 | else | 4817 | break :dst dst_mcv; |
| 4475 | .{ .register = try self.copyToTmpRegister(src_ty, src_mcv) }; | 4818 | }; |
| 4476 | const dst_lock = switch (dst_mcv) { | 4819 | const dst_lock = switch (dst_mcv) { |
| 4477 | .register => |reg| self.register_manager.lockReg(reg), | 4820 | .register => |reg| self.register_manager.lockReg(reg), |
| 4478 | else => null, | 4821 | else => null, |
| ... | @@ -4481,19 +4824,33 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: | ... | @@ -4481,19 +4824,33 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air: |
| 4481 | 4824 | ||
| 4482 | switch (tag) { | 4825 | switch (tag) { |
| 4483 | .not => { | 4826 | .not => { |
| 4827 | const limb_abi_size = @intCast(u16, @min(src_ty.abiSize(self.target.*), 8)); | ||
| 4484 | const int_info = if (src_ty.tag() == .bool) | 4828 | const int_info = if (src_ty.tag() == .bool) |
| 4485 | std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 } | 4829 | std.builtin.Type.Int{ .signedness = .unsigned, .bits = 1 } |
| 4486 | else | 4830 | else |
| 4487 | src_ty.intInfo(self.target.*); | 4831 | src_ty.intInfo(self.target.*); |
| 4488 | const extra_bits = self.regExtraBits(src_ty); | 4832 | var byte_off: i32 = 0; |
| 4489 | if (int_info.signedness == .unsigned and extra_bits > 0) { | 4833 | while (byte_off * 8 < int_info.bits) : (byte_off += limb_abi_size) { |
| 4490 | const mask = (@as(u64, 1) << @intCast(u6, src_ty.bitSize(self.target.*))) - 1; | 4834 | var limb_pl = Type.Payload.Bits{ |
| 4491 | try self.genBinOpMir(.xor, src_ty, dst_mcv, .{ .immediate = mask }); | 4835 | .base = .{ .tag = switch (int_info.signedness) { |
| 4492 | } else try self.genUnOpMir(.not, src_ty, dst_mcv); | 4836 | .signed => .int_signed, |
| 4493 | }, | 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 | .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv), | 4853 | .neg => try self.genUnOpMir(.neg, src_ty, dst_mcv), |
| 4496 | |||
| 4497 | else => unreachable, | 4854 | else => unreachable, |
| 4498 | } | 4855 | } |
| 4499 | return dst_mcv; | 4856 | return dst_mcv; |
| ... | @@ -4534,17 +4891,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue | ... | @@ -4534,17 +4891,7 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue |
| 4534 | }, | 4891 | }, |
| 4535 | .indirect, .load_frame => try self.asmMemory( | 4892 | .indirect, .load_frame => try self.asmMemory( |
| 4536 | mir_tag, | 4893 | mir_tag, |
| 4537 | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (dst_mcv) { | 4894 | dst_mcv.mem(Memory.PtrSize.fromSize(abi_size)), |
| 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 | }), | ||
| 4548 | ), | 4895 | ), |
| 4549 | } | 4896 | } |
| 4550 | } | 4897 | } |
| ... | @@ -5128,24 +5475,69 @@ fn genBinOp( | ... | @@ -5128,24 +5475,69 @@ fn genBinOp( |
| 5128 | switch (tag) { | 5475 | switch (tag) { |
| 5129 | .add, | 5476 | .add, |
| 5130 | .addwrap, | 5477 | .addwrap, |
| 5131 | => try self.genBinOpMir(switch (lhs_ty.tag()) { | 5478 | => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { |
| 5132 | else => .add, | 5479 | else => .add, |
| 5133 | .f32 => .addss, | 5480 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 5134 | .f64 => .addsd, | 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 | }, lhs_ty, dst_mcv, src_mcv), | 5497 | }, lhs_ty, dst_mcv, src_mcv), |
| 5136 | 5498 | ||
| 5137 | .sub, | 5499 | .sub, |
| 5138 | .subwrap, | 5500 | .subwrap, |
| 5139 | => try self.genBinOpMir(switch (lhs_ty.tag()) { | 5501 | => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { |
| 5140 | else => .sub, | 5502 | else => .sub, |
| 5141 | .f32 => .subss, | 5503 | .Float => switch (lhs_ty.floatBits(self.target.*)) { |
| 5142 | .f64 => .subsd, | 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 | }, lhs_ty, dst_mcv, src_mcv), | 5520 | }, lhs_ty, dst_mcv, src_mcv), |
| 5144 | 5521 | ||
| 5145 | .mul => try self.genBinOpMir(switch (lhs_ty.tag()) { | 5522 | .mul => try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { |
| 5146 | .f32 => .mulss, | ||
| 5147 | .f64 => .mulsd, | ||
| 5148 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?) }), | 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 | }, lhs_ty, dst_mcv, src_mcv), | 5541 | }, lhs_ty, dst_mcv, src_mcv), |
| 5150 | 5542 | ||
| 5151 | .div_float, | 5543 | .div_float, |
| ... | @@ -5153,12 +5545,27 @@ fn genBinOp( | ... | @@ -5153,12 +5545,27 @@ fn genBinOp( |
| 5153 | .div_trunc, | 5545 | .div_trunc, |
| 5154 | .div_floor, | 5546 | .div_floor, |
| 5155 | => { | 5547 | => { |
| 5156 | try self.genBinOpMir(switch (lhs_ty.tag()) { | 5548 | try self.genBinOpMir(switch (lhs_ty.zigTypeTag()) { |
| 5157 | .f32 => .divss, | ||
| 5158 | .f64 => .divsd, | ||
| 5159 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ | 5549 | else => return self.fail("TODO implement genBinOp for {s} {}", .{ |
| 5160 | @tagName(tag), lhs_ty.fmt(self.bin_file.options.module.?), | 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 | }, lhs_ty, dst_mcv, src_mcv); | 5569 | }, lhs_ty, dst_mcv, src_mcv); |
| 5163 | switch (tag) { | 5570 | switch (tag) { |
| 5164 | .div_float, | 5571 | .div_float, |
| ... | @@ -5169,16 +5576,18 @@ fn genBinOp( | ... | @@ -5169,16 +5576,18 @@ fn genBinOp( |
| 5169 | => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) { | 5576 | => if (Target.x86.featureSetHas(self.target.cpu.features, .sse4_1)) { |
| 5170 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); | 5577 | const abi_size = @intCast(u32, lhs_ty.abiSize(self.target.*)); |
| 5171 | const dst_alias = registerAlias(dst_mcv.register, abi_size); | 5578 | const dst_alias = registerAlias(dst_mcv.register, abi_size); |
| 5172 | try self.asmRegisterRegisterImmediate(switch (lhs_ty.tag()) { | 5579 | try self.asmRegisterRegisterImmediate(switch (lhs_ty.floatBits(self.target.*)) { |
| 5173 | .f32 => .roundss, | 5580 | 32 => .roundss, |
| 5174 | .f64 => .roundsd, | 5581 | 64 => .roundsd, |
| 5175 | else => unreachable, | 5582 | else => unreachable, |
| 5176 | }, dst_alias, dst_alias, Immediate.u(switch (tag) { | 5583 | }, dst_alias, dst_alias, Immediate.u(switch (tag) { |
| 5177 | .div_trunc => 0b1_0_11, | 5584 | .div_trunc => 0b1_0_11, |
| 5178 | .div_floor => 0b1_0_01, | 5585 | .div_floor => 0b1_0_01, |
| 5179 | else => unreachable, | 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 | else => unreachable, | 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,39 +5809,68 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, ty: Type, dst_mcv: MCValue, s |
| 5400 | )), | 5809 | )), |
| 5401 | else => unreachable, | 5810 | else => unreachable, |
| 5402 | }, | 5811 | }, |
| 5403 | .register_offset, | ||
| 5404 | .eflags, | 5812 | .eflags, |
| 5813 | .register_offset, | ||
| 5405 | .memory, | 5814 | .memory, |
| 5815 | .indirect, | ||
| 5406 | .load_direct, | 5816 | .load_direct, |
| 5407 | .lea_direct, | 5817 | .lea_direct, |
| 5408 | .load_got, | 5818 | .load_got, |
| 5409 | .lea_got, | 5819 | .lea_got, |
| 5410 | .load_tlv, | 5820 | .load_tlv, |
| 5411 | .lea_tlv, | 5821 | .lea_tlv, |
| 5822 | .load_frame, | ||
| 5412 | .lea_frame, | 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 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); | 5847 | const dst_reg_lock = self.register_manager.lockReg(dst_reg); |
| 5416 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); | 5848 | defer if (dst_reg_lock) |lock| self.register_manager.unlockReg(lock); |
| 5417 | 5849 | ||
| 5418 | const reg = try self.copyToTmpRegister(ty, src_mcv); | 5850 | switch (src_mcv) { |
| 5419 | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg }); | 5851 | .eflags, |
| 5420 | }, | 5852 | .register_offset, |
| 5421 | .indirect, .load_frame => try self.asmRegisterMemory( | 5853 | .lea_direct, |
| 5422 | mir_tag, | 5854 | .lea_got, |
| 5423 | registerAlias(dst_reg, abi_size), | 5855 | .lea_tlv, |
| 5424 | Memory.sib(Memory.PtrSize.fromSize(abi_size), switch (src_mcv) { | 5856 | .lea_frame, |
| 5425 | .indirect => |reg_off| .{ | 5857 | => { |
| 5426 | .base = .{ .reg = reg_off.reg }, | 5858 | const reg = try self.copyToTmpRegister(ty, src_mcv); |
| 5427 | .disp = reg_off.off, | 5859 | return self.genBinOpMir(mir_tag, ty, dst_mcv, .{ .register = reg }); |
| 5428 | }, | 5860 | }, |
| 5429 | .load_frame => |frame_addr| .{ | 5861 | .memory, |
| 5430 | .base = .{ .frame = frame_addr.index }, | 5862 | .load_direct, |
| 5431 | .disp = frame_addr.off, | 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 | else => unreachable, | 5871 | else => unreachable, |
| 5434 | }), | 5872 | } |
| 5435 | ), | 5873 | }, |
| 5436 | } | 5874 | } |
| 5437 | }, | 5875 | }, |
| 5438 | .memory, .indirect, .load_got, .load_direct, .load_tlv, .load_frame => { | 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,7 +6207,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 5769 | 6207 | ||
| 5770 | const ty = self.air.typeOfIndex(inst); | 6208 | const ty = self.air.typeOfIndex(inst); |
| 5771 | const src_index = self.air.instructions.items(.data)[inst].arg.src_index; | 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 | try self.genArgDbgInfo(ty, name, dst_mcv); | 6211 | try self.genArgDbgInfo(ty, name, dst_mcv); |
| 5774 | 6212 | ||
| 5775 | break :result dst_mcv; | 6213 | break :result dst_mcv; |
| ... | @@ -5793,7 +6231,10 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { | ... | @@ -5793,7 +6231,10 @@ fn genArgDbgInfo(self: Self, ty: Type, name: [:0]const u8, mcv: MCValue) !void { |
| 5793 | //}, | 6231 | //}, |
| 5794 | else => unreachable, // not a valid function parameter | 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 | .plan9 => {}, | 6239 | .plan9 => {}, |
| 5799 | .none => {}, | 6240 | .none => {}, |
| ... | @@ -5834,7 +6275,10 @@ fn genVarDbgInfo( | ... | @@ -5834,7 +6275,10 @@ fn genVarDbgInfo( |
| 5834 | break :blk .nop; | 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 | .plan9 => {}, | 6283 | .plan9 => {}, |
| 5840 | .none => {}, | 6284 | .none => {}, |
| ... | @@ -5966,12 +6410,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -5966,12 +6410,14 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5966 | .base = .{ .reg = .ds }, | 6410 | .base = .{ .reg = .ds }, |
| 5967 | .disp = @intCast(i32, got_addr), | 6411 | .disp = @intCast(i32, got_addr), |
| 5968 | })); | 6412 | })); |
| 5969 | } else if (self.bin_file.cast(link.File.Coff)) |_| { | 6413 | } else if (self.bin_file.cast(link.File.Coff)) |coff_file| { |
| 5970 | const sym_index = try self.getSymbolIndexForDecl(func.owner_decl); | 6414 | const atom = try coff_file.getOrCreateAtomForDecl(func.owner_decl); |
| 6415 | const sym_index = coff_file.getAtom(atom).getSymbolIndex().?; | ||
| 5971 | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); | 6416 | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); |
| 5972 | try self.asmRegister(.call, .rax); | 6417 | try self.asmRegister(.call, .rax); |
| 5973 | } else if (self.bin_file.cast(link.File.MachO)) |_| { | 6418 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 5974 | const sym_index = try self.getSymbolIndexForDecl(func.owner_decl); | 6419 | const atom = try macho_file.getOrCreateAtomForDecl(func.owner_decl); |
| 6420 | const sym_index = macho_file.getAtom(atom).getSymbolIndex().?; | ||
| 5975 | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); | 6421 | try self.genSetReg(.rax, Type.usize, .{ .lea_got = sym_index }); |
| 5976 | try self.asmRegister(.call, .rax); | 6422 | try self.asmRegister(.call, .rax); |
| 5977 | } else if (self.bin_file.cast(link.File.Plan9)) |p9| { | 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,7 +6438,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 5992 | const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); | 6438 | const decl_name = mem.sliceTo(mod.declPtr(extern_fn.owner_decl).name, 0); |
| 5993 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); | 6439 | const lib_name = mem.sliceTo(extern_fn.lib_name, 0); |
| 5994 | if (self.bin_file.cast(link.File.Coff)) |coff_file| { | 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 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); | 6442 | const sym_index = try coff_file.getGlobalSymbol(decl_name, lib_name); |
| 5997 | _ = try self.addInst(.{ | 6443 | _ = try self.addInst(.{ |
| 5998 | .tag = .mov_linker, | 6444 | .tag = .mov_linker, |
| ... | @@ -6005,8 +6451,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier | ... | @@ -6005,8 +6451,8 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier |
| 6005 | }); | 6451 | }); |
| 6006 | try self.asmRegister(.call, .rax); | 6452 | try self.asmRegister(.call, .rax); |
| 6007 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { | 6453 | } else if (self.bin_file.cast(link.File.MachO)) |macho_file| { |
| 6454 | const atom_index = try self.owner.getSymbolIndex(self); | ||
| 6008 | const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); | 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 | _ = try self.addInst(.{ | 6456 | _ = try self.addInst(.{ |
| 6011 | .tag = .call_extern, | 6457 | .tag = .call_extern, |
| 6012 | .ops = undefined, | 6458 | .ops = undefined, |
| ... | @@ -6122,10 +6568,25 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { | ... | @@ -6122,10 +6568,25 @@ fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void { |
| 6122 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); | 6568 | defer if (dst_lock) |lock| self.register_manager.unlockReg(lock); |
| 6123 | 6569 | ||
| 6124 | const src_mcv = if (flipped) lhs_mcv else rhs_mcv; | 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 | else => .cmp, | 6572 | else => .cmp, |
| 6127 | .f32 => .ucomiss, | 6573 | .Float => switch (ty.floatBits(self.target.*)) { |
| 6128 | .f64 => .ucomisd, | 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 | }, ty, dst_mcv, src_mcv); | 6590 | }, ty, dst_mcv, src_mcv); |
| 6130 | 6591 | ||
| 6131 | const signedness = if (ty.isAbiInt()) ty.intInfo(self.target.*).signedness else .unsigned; | 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,42 +6602,13 @@ fn airCmpVector(self: *Self, inst: Air.Inst.Index) !void { |
| 6141 | } | 6602 | } |
| 6142 | 6603 | ||
| 6143 | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { | 6604 | fn airCmpLtErrorsLen(self: *Self, inst: Air.Inst.Index) !void { |
| 6605 | const mod = self.bin_file.options.module.?; | ||
| 6144 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 6606 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 6145 | 6607 | ||
| 6146 | const addr_reg = try self.register_manager.allocReg(null, gp); | 6608 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 6147 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | 6609 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 6148 | defer self.register_manager.unlockReg(addr_lock); | 6610 | defer self.register_manager.unlockReg(addr_lock); |
| 6149 | 6611 | try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod)); | |
| 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 | } | ||
| 6180 | 6612 | ||
| 6181 | try self.spillEflagsIfOccupied(); | 6613 | try self.spillEflagsIfOccupied(); |
| 6182 | self.eflags_inst = inst; | 6614 | self.eflags_inst = inst; |
| ... | @@ -6345,35 +6777,26 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6345,35 +6777,26 @@ fn airCondBr(self: *Self, inst: Air.Inst.Index) !void { |
| 6345 | if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); | 6777 | if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); |
| 6346 | } | 6778 | } |
| 6347 | 6779 | ||
| 6348 | const outer_state = try self.saveState(); | 6780 | self.scope_generation += 1; |
| 6349 | { | 6781 | const state = try self.saveState(); |
| 6350 | self.scope_generation += 1; | ||
| 6351 | const inner_state = try self.saveState(); | ||
| 6352 | 6782 | ||
| 6353 | for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand); | 6783 | for (liveness_cond_br.then_deaths) |operand| self.processDeath(operand); |
| 6354 | try self.genBody(then_body); | 6784 | try self.genBody(then_body); |
| 6355 | try self.restoreState(inner_state, &.{}, .{ | 6785 | try self.restoreState(state, &.{}, .{ |
| 6356 | .emit_instructions = false, | 6786 | .emit_instructions = false, |
| 6357 | .update_tracking = true, | 6787 | .update_tracking = true, |
| 6358 | .resurrect = true, | 6788 | .resurrect = true, |
| 6359 | .close_scope = true, | 6789 | .close_scope = true, |
| 6360 | }); | 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); | 6794 | for (liveness_cond_br.else_deaths) |operand| self.processDeath(operand); |
| 6365 | try self.genBody(else_body); | 6795 | try self.genBody(else_body); |
| 6366 | try self.restoreState(inner_state, &.{}, .{ | 6796 | try self.restoreState(state, &.{}, .{ |
| 6367 | .emit_instructions = false, | ||
| 6368 | .update_tracking = true, | ||
| 6369 | .resurrect = true, | ||
| 6370 | .close_scope = true, | ||
| 6371 | }); | ||
| 6372 | } | ||
| 6373 | try self.restoreState(outer_state, &.{}, .{ | ||
| 6374 | .emit_instructions = false, | 6797 | .emit_instructions = false, |
| 6375 | .update_tracking = false, | 6798 | .update_tracking = true, |
| 6376 | .resurrect = false, | 6799 | .resurrect = true, |
| 6377 | .close_scope = true, | 6800 | .close_scope = true, |
| 6378 | }); | 6801 | }); |
| 6379 | 6802 | ||
| ... | @@ -6746,64 +7169,56 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -6746,64 +7169,56 @@ fn airSwitchBr(self: *Self, inst: Air.Inst.Index) !void { |
| 6746 | if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); | 7169 | if (Air.refToIndex(pl_op.operand)) |op_inst| self.processDeath(op_inst); |
| 6747 | } | 7170 | } |
| 6748 | 7171 | ||
| 6749 | const outer_state = try self.saveState(); | 7172 | self.scope_generation += 1; |
| 6750 | { | 7173 | const state = try self.saveState(); |
| 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; | ||
| 6762 | 7174 | ||
| 6763 | var relocs = try self.gpa.alloc(u32, items.len); | 7175 | while (case_i < switch_br.data.cases_len) : (case_i += 1) { |
| 6764 | defer self.gpa.free(relocs); | 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| { | 7184 | var relocs = try self.gpa.alloc(u32, items.len); |
| 6767 | try self.spillEflagsIfOccupied(); | 7185 | defer self.gpa.free(relocs); |
| 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 | } | ||
| 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); | 7194 | for (liveness.deaths[case_i]) |operand| self.processDeath(operand); |
| 6776 | try self.restoreState(inner_state, &.{}, .{ | ||
| 6777 | .emit_instructions = false, | ||
| 6778 | .update_tracking = true, | ||
| 6779 | .resurrect = true, | ||
| 6780 | .close_scope = true, | ||
| 6781 | }); | ||
| 6782 | 7195 | ||
| 6783 | for (relocs) |reloc| try self.performReloc(reloc); | 7196 | for (relocs[0 .. relocs.len - 1]) |reloc| try self.performReloc(reloc); |
| 6784 | } | 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) { | 7205 | try self.performReloc(relocs[relocs.len - 1]); |
| 6787 | const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; | 7206 | } |
| 6788 | 7207 | ||
| 6789 | const else_deaths = liveness.deaths.len - 1; | 7208 | if (switch_br.data.else_body_len > 0) { |
| 6790 | for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand); | 7209 | const else_body = self.air.extra[extra_index..][0..switch_br.data.else_body_len]; |
| 6791 | 7210 | ||
| 6792 | try self.genBody(else_body); | 7211 | const else_deaths = liveness.deaths.len - 1; |
| 6793 | try self.restoreState(inner_state, &.{}, .{ | 7212 | for (liveness.deaths[else_deaths]) |operand| self.processDeath(operand); |
| 6794 | .emit_instructions = false, | 7213 | |
| 6795 | .update_tracking = true, | 7214 | try self.genBody(else_body); |
| 6796 | .resurrect = true, | 7215 | try self.restoreState(state, &.{}, .{ |
| 6797 | .close_scope = true, | 7216 | .emit_instructions = false, |
| 6798 | }); | 7217 | .update_tracking = true, |
| 6799 | } | 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 | // We already took care of pl_op.operand earlier, so we're going to pass .none here | 7223 | // We already took care of pl_op.operand earlier, so we're going to pass .none here |
| 6809 | return self.finishAir(inst, .unreach, .{ .none, .none, .none }); | 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,7 +7704,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 7289 | }), | 7704 | }), |
| 7290 | ), | 7705 | ), |
| 7291 | .load_direct => |sym_index| if (try self.movMirTag(ty) == .mov) { | 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 | _ = try self.addInst(.{ | 7708 | _ = try self.addInst(.{ |
| 7294 | .tag = .mov_linker, | 7709 | .tag = .mov_linker, |
| 7295 | .ops = .direct_reloc, | 7710 | .ops = .direct_reloc, |
| ... | @@ -7316,7 +7731,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -7316,7 +7731,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 7316 | ); | 7731 | ); |
| 7317 | }, | 7732 | }, |
| 7318 | .lea_direct, .lea_got => |sym_index| { | 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 | _ = try self.addInst(.{ | 7735 | _ = try self.addInst(.{ |
| 7321 | .tag = switch (src_mcv) { | 7736 | .tag = switch (src_mcv) { |
| 7322 | .lea_direct => .lea_linker, | 7737 | .lea_direct => .lea_linker, |
| ... | @@ -7336,7 +7751,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr | ... | @@ -7336,7 +7751,7 @@ fn genSetReg(self: *Self, dst_reg: Register, ty: Type, src_mcv: MCValue) InnerEr |
| 7336 | }); | 7751 | }); |
| 7337 | }, | 7752 | }, |
| 7338 | .lea_tlv => |sym_index| { | 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 | if (self.bin_file.cast(link.File.MachO)) |_| { | 7755 | if (self.bin_file.cast(link.File.MachO)) |_| { |
| 7341 | _ = try self.addInst(.{ | 7756 | _ = try self.addInst(.{ |
| 7342 | .tag = .lea_linker, | 7757 | .tag = .lea_linker, |
| ... | @@ -7531,6 +7946,67 @@ fn genInlineMemset(self: *Self, dst_ptr: MCValue, value: MCValue, len: MCValue) | ... | @@ -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 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { | 8010 | fn airPtrToInt(self: *Self, inst: Air.Inst.Index) !void { |
| 7535 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8011 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 7536 | const result = result: { | 8012 | const result = result: { |
| ... | @@ -7555,7 +8031,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7555,7 +8031,8 @@ fn airBitCast(self: *Self, inst: Air.Inst.Index) !void { |
| 7555 | const dst_rc = try self.regClassForType(dst_ty); | 8031 | const dst_rc = try self.regClassForType(dst_ty); |
| 7556 | const src_rc = try self.regClassForType(src_ty); | 8032 | const src_rc = try self.regClassForType(src_ty); |
| 7557 | const operand = try self.resolveInst(ty_op.operand); | 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 | const operand_lock = switch (operand) { | 8037 | const operand_lock = switch (operand) { |
| 7561 | .register => |reg| self.register_manager.lockReg(reg), | 8038 | .register => |reg| self.register_manager.lockReg(reg), |
| ... | @@ -7595,9 +8072,59 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7595,9 +8072,59 @@ fn airArrayToSlice(self: *Self, inst: Air.Inst.Index) !void { |
| 7595 | 8072 | ||
| 7596 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { | 8073 | fn airIntToFloat(self: *Self, inst: Air.Inst.Index) !void { |
| 7597 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; | 8074 | const ty_op = self.air.instructions.items(.data)[inst].ty_op; |
| 7598 | _ = ty_op; | 8075 | |
| 7599 | return self.fail("TODO implement airIntToFloat for {}", .{self.target.cpu.arch}); | 8076 | const src_ty = self.air.typeOf(ty_op.operand); |
| 7600 | //return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); | 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 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { | 8130 | fn airFloatToInt(self: *Self, inst: Air.Inst.Index) !void { |
| ... | @@ -7652,70 +8179,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7652,70 +8179,50 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 7652 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; | 8179 | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 7653 | 8180 | ||
| 7654 | const ptr_ty = self.air.typeOf(extra.ptr); | 8181 | const ptr_ty = self.air.typeOf(extra.ptr); |
| 7655 | const ptr_mcv = try self.resolveInst(extra.ptr); | ||
| 7656 | const val_ty = self.air.typeOf(extra.expected_value); | 8182 | const val_ty = self.air.typeOf(extra.expected_value); |
| 7657 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); | 8183 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 7658 | 8184 | ||
| 7659 | try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx }); | 8185 | try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx }); |
| 7660 | const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx }); | 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 | const exp_mcv = try self.resolveInst(extra.expected_value); | 8189 | const exp_mcv = try self.resolveInst(extra.expected_value); |
| 7664 | if (val_abi_size > 8) switch (exp_mcv) { | 8190 | if (val_abi_size > 8) { |
| 7665 | .load_frame => |frame_addr| { | 8191 | try self.genSetReg(.rax, Type.usize, exp_mcv); |
| 7666 | try self.genSetReg(.rax, Type.usize, .{ .load_frame = .{ | 8192 | try self.genSetReg(.rdx, Type.usize, exp_mcv.address().offset(8).deref()); |
| 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)}), | ||
| 7676 | } else try self.genSetReg(.rax, val_ty, exp_mcv); | 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 | const new_mcv = try self.resolveInst(extra.new_value); | 8195 | const new_mcv = try self.resolveInst(extra.new_value); |
| 7681 | const new_reg: Register = if (val_abi_size > 8) switch (new_mcv) { | 8196 | const new_reg = if (val_abi_size > 8) new: { |
| 7682 | .load_frame => |frame_addr| new: { | 8197 | try self.genSetReg(.rbx, Type.usize, new_mcv); |
| 7683 | try self.genSetReg(.rbx, Type.usize, .{ .load_frame = .{ | 8198 | try self.genSetReg(.rcx, Type.usize, new_mcv.address().offset(8).deref()); |
| 7684 | .index = frame_addr.index, | 8199 | break :new null; |
| 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)}), | ||
| 7694 | } else try self.copyToTmpRegister(val_ty, new_mcv); | 8200 | } else try self.copyToTmpRegister(val_ty, new_mcv); |
| 7695 | const new_lock = self.register_manager.lockRegAssumeUnused(new_reg); | 8201 | const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; |
| 7696 | defer self.register_manager.unlockReg(new_lock); | 8202 | defer if (new_lock) |lock| self.register_manager.unlockReg(lock); |
| 7697 | 8203 | ||
| 8204 | const ptr_mcv = try self.resolveInst(extra.ptr); | ||
| 7698 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); | 8205 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 7699 | const ptr_mem = switch (ptr_mcv) { | 8206 | const ptr_mem = switch (ptr_mcv) { |
| 7700 | .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }), | 8207 | .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size), |
| 7701 | .lea_frame => |frame_addr| Memory.sib(ptr_size, .{ | 8208 | else => Memory.sib(ptr_size, .{ |
| 7702 | .base = .{ .frame = frame_addr.index }, | 8209 | .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }, |
| 7703 | .disp = frame_addr.off, | ||
| 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 | .none, .frame => null, | 8217 | .none, .frame => null, |
| 7711 | .reg => |reg| self.register_manager.lockReg(reg), | 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 | try self.spillEflagsIfOccupied(); | 8222 | try self.spillEflagsIfOccupied(); |
| 7716 | if (val_abi_size <= 8) { | 8223 | if (val_abi_size <= 8) { |
| 7717 | _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{ | 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 | .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)), | 8226 | .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)), |
| 7720 | } } }); | 8227 | } } }); |
| 7721 | } else { | 8228 | } else { |
| ... | @@ -7733,24 +8240,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -7733,24 +8240,9 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void { |
| 7733 | } | 8240 | } |
| 7734 | 8241 | ||
| 7735 | const dst_mcv = try self.allocRegOrMem(inst, false); | 8242 | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 7736 | try self.genSetMem( | 8243 | try self.genCopy(Type.usize, dst_mcv, .{ .register = .rax }); |
| 7737 | .{ .frame = dst_mcv.load_frame.index }, | 8244 | try self.genCopy(Type.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx }); |
| 7738 | dst_mcv.load_frame.off + 16, | 8245 | try self.genCopy(Type.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne }); |
| 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 | ); | ||
| 7754 | break :result dst_mcv; | 8246 | break :result dst_mcv; |
| 7755 | }; | 8247 | }; |
| 7756 | return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value }); | 8248 | return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value }); |
| ... | @@ -7781,15 +8273,15 @@ fn atomicOp( | ... | @@ -7781,15 +8273,15 @@ fn atomicOp( |
| 7781 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); | 8273 | const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*)); |
| 7782 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); | 8274 | const ptr_size = Memory.PtrSize.fromSize(val_abi_size); |
| 7783 | const ptr_mem = switch (ptr_mcv) { | 8275 | const ptr_mem = switch (ptr_mcv) { |
| 7784 | .register => |reg| Memory.sib(ptr_size, .{ .base = .{ .reg = reg } }), | 8276 | .immediate, .register, .register_offset, .lea_frame => ptr_mcv.deref().mem(ptr_size), |
| 7785 | .lea_frame => |frame_addr| Memory.sib(ptr_size, .{ | 8277 | else => Memory.sib(ptr_size, .{ |
| 7786 | .base = .{ .frame = frame_addr.index }, | 8278 | .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }, |
| 7787 | .disp = frame_addr.off, | ||
| 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 | const mem_lock = switch (ptr_mem.base()) { | 8285 | const mem_lock = switch (ptr_mem.base()) { |
| 7794 | .none, .frame => null, | 8286 | .none, .frame => null, |
| 7795 | .reg => |reg| self.register_manager.lockReg(reg), | 8287 | .reg => |reg| self.register_manager.lockReg(reg), |
| ... | @@ -7895,12 +8387,9 @@ fn atomicOp( | ... | @@ -7895,12 +8387,9 @@ fn atomicOp( |
| 7895 | registerAlias(val_reg, cmov_abi_size), | 8387 | registerAlias(val_reg, cmov_abi_size), |
| 7896 | cc, | 8388 | cc, |
| 7897 | ), | 8389 | ), |
| 7898 | .load_frame => |frame_addr| try self.asmCmovccRegisterMemory( | 8390 | .memory, .indirect, .load_frame => try self.asmCmovccRegisterMemory( |
| 7899 | registerAlias(tmp_reg, cmov_abi_size), | 8391 | registerAlias(tmp_reg, cmov_abi_size), |
| 7900 | Memory.sib(Memory.PtrSize.fromSize(cmov_abi_size), .{ | 8392 | val_mcv.mem(Memory.PtrSize.fromSize(cmov_abi_size)), |
| 7901 | .base = .{ .frame = frame_addr.index }, | ||
| 7902 | .disp = frame_addr.off, | ||
| 7903 | }), | ||
| 7904 | cc, | 8393 | cc, |
| 7905 | ), | 8394 | ), |
| 7906 | else => { | 8395 | else => { |
| ... | @@ -7923,72 +8412,62 @@ fn atomicOp( | ... | @@ -7923,72 +8412,62 @@ fn atomicOp( |
| 7923 | } else { | 8412 | } else { |
| 7924 | try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{ | 8413 | try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{ |
| 7925 | .base = ptr_mem.sib.base, | 8414 | .base = ptr_mem.sib.base, |
| 7926 | .scale_index = ptr_mem.sib.scale_index, | 8415 | .scale_index = ptr_mem.scaleIndex(), |
| 7927 | .disp = ptr_mem.sib.disp + 0, | 8416 | .disp = ptr_mem.sib.disp + 0, |
| 7928 | })); | 8417 | })); |
| 7929 | try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{ | 8418 | try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{ |
| 7930 | .base = ptr_mem.sib.base, | 8419 | .base = ptr_mem.sib.base, |
| 7931 | .scale_index = ptr_mem.sib.scale_index, | 8420 | .scale_index = ptr_mem.scaleIndex(), |
| 7932 | .disp = ptr_mem.sib.disp + 8, | 8421 | .disp = ptr_mem.sib.disp + 8, |
| 7933 | })); | 8422 | })); |
| 7934 | const loop = @intCast(u32, self.mir_instructions.len); | 8423 | const loop = @intCast(u32, self.mir_instructions.len); |
| 7935 | switch (val_mcv) { | 8424 | const val_mem_mcv: MCValue = switch (val_mcv) { |
| 7936 | .load_frame => |frame_addr| { | 8425 | .memory, .indirect, .load_frame => val_mcv, |
| 7937 | const val_lo_mem = Memory.sib(.qword, .{ | 8426 | else => .{ .indirect = .{ |
| 7938 | .base = .{ .frame = frame_addr.index }, | 8427 | .reg = try self.copyToTmpRegister(Type.usize, val_mcv.address()), |
| 7939 | .disp = frame_addr.off + 0, | 8428 | } }, |
| 7940 | }); | 8429 | }; |
| 7941 | const val_hi_mem = Memory.sib(.qword, .{ | 8430 | const val_lo_mem = val_mem_mcv.mem(.qword); |
| 7942 | .base = .{ .frame = frame_addr.index }, | 8431 | const val_hi_mem = val_mem_mcv.address().offset(8).deref().mem(.qword); |
| 7943 | .disp = frame_addr.off + 8, | 8432 | if (rmw_op != std.builtin.AtomicRmwOp.Xchg) { |
| 7944 | }); | 8433 | try self.asmRegisterRegister(.mov, .rbx, .rax); |
| 7945 | 8434 | try self.asmRegisterRegister(.mov, .rcx, .rdx); | |
| 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 | ), | ||
| 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 | _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{ | 8471 | _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{ |
| 7993 | .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)), | 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,14 +8709,48 @@ fn airMemcpy(self: *Self, inst: Air.Inst.Index) !void { |
| 8230 | } | 8709 | } |
| 8231 | 8710 | ||
| 8232 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { | 8711 | fn airTagName(self: *Self, inst: Air.Inst.Index) !void { |
| 8712 | const mod = self.bin_file.options.module.?; | ||
| 8233 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 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 | const operand = try self.resolveInst(un_op); | 8740 | const operand = try self.resolveInst(un_op); |
| 8235 | _ = operand; | 8741 | try self.genSetReg(param_regs[1], enum_ty, operand); |
| 8236 | return self.fail("TODO implement airTagName for x86_64", .{}); | 8742 | |
| 8237 | //return self.finishAir(inst, result, .{ un_op, .none, .none }); | 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 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { | 8752 | fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 8753 | const mod = self.bin_file.options.module.?; | ||
| 8241 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 8754 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 8242 | 8755 | ||
| 8243 | const err_ty = self.air.typeOf(un_op); | 8756 | const err_ty = self.air.typeOf(un_op); |
| ... | @@ -8249,37 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -8249,37 +8762,7 @@ fn airErrorName(self: *Self, inst: Air.Inst.Index) !void { |
| 8249 | const addr_reg = try self.register_manager.allocReg(null, gp); | 8762 | const addr_reg = try self.register_manager.allocReg(null, gp); |
| 8250 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); | 8763 | const addr_lock = self.register_manager.lockRegAssumeUnused(addr_reg); |
| 8251 | defer self.register_manager.unlockReg(addr_lock); | 8764 | defer self.register_manager.unlockReg(addr_lock); |
| 8252 | 8765 | try self.genLazySymbolRef(.lea, addr_reg, link.File.LazySymbol.initDecl(.const_data, null, mod)); | |
| 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 | } | ||
| 8283 | 8766 | ||
| 8284 | const start_reg = try self.register_manager.allocReg(null, gp); | 8767 | const start_reg = try self.register_manager.allocReg(null, gp); |
| 8285 | const start_lock = self.register_manager.lockRegAssumeUnused(start_reg); | 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,12 +9079,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV |
| 8596 | } | 9079 | } |
| 8597 | 9080 | ||
| 8598 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | 9081 | fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 8599 | const mcv: MCValue = switch (try codegen.genTypedValue( | 9082 | return switch (try codegen.genTypedValue(self.bin_file, self.src_loc, arg_tv, self.owner.getDecl())) { |
| 8600 | self.bin_file, | ||
| 8601 | self.src_loc, | ||
| 8602 | arg_tv, | ||
| 8603 | self.mod_fn.owner_decl, | ||
| 8604 | )) { | ||
| 8605 | .mcv => |mcv| switch (mcv) { | 9083 | .mcv => |mcv| switch (mcv) { |
| 8606 | .none => .none, | 9084 | .none => .none, |
| 8607 | .undef => .undef, | 9085 | .undef => .undef, |
| ... | @@ -8616,7 +9094,6 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { | ... | @@ -8616,7 +9094,6 @@ fn genTypedValue(self: *Self, arg_tv: TypedValue) InnerError!MCValue { |
| 8616 | return error.CodegenFail; | 9094 | return error.CodegenFail; |
| 8617 | }, | 9095 | }, |
| 8618 | }; | 9096 | }; |
| 8619 | return mcv; | ||
| 8620 | } | 9097 | } |
| 8621 | 9098 | ||
| 8622 | const CallMCValues = struct { | 9099 | const CallMCValues = struct { |
| ... | @@ -8664,6 +9141,7 @@ fn resolveCallingConventionValues( | ... | @@ -8664,6 +9141,7 @@ fn resolveCallingConventionValues( |
| 8664 | }, | 9141 | }, |
| 8665 | .C => { | 9142 | .C => { |
| 8666 | var param_reg_i: usize = 0; | 9143 | var param_reg_i: usize = 0; |
| 9144 | var param_sse_reg_i: usize = 0; | ||
| 8667 | result.stack_align = 16; | 9145 | result.stack_align = 16; |
| 8668 | 9146 | ||
| 8669 | switch (self.target.os.tag) { | 9147 | switch (self.target.os.tag) { |
| ... | @@ -8681,26 +9159,39 @@ fn resolveCallingConventionValues( | ... | @@ -8681,26 +9159,39 @@ fn resolveCallingConventionValues( |
| 8681 | // TODO: is this even possible for C calling convention? | 9159 | // TODO: is this even possible for C calling convention? |
| 8682 | result.return_value = InstTracking.init(.none); | 9160 | result.return_value = InstTracking.init(.none); |
| 8683 | } else { | 9161 | } else { |
| 8684 | const ret_reg = abi.getCAbiIntReturnRegs(self.target.*)[0]; | 9162 | const classes = switch (self.target.os.tag) { |
| 8685 | const ret_ty_size = @intCast(u31, ret_ty.abiSize(self.target.*)); | 9163 | .windows => &[1]abi.Class{abi.classifyWindows(ret_ty, self.target.*)}, |
| 8686 | if (ret_ty_size <= 8) { | 9164 | else => mem.sliceTo(&abi.classifySystemV(ret_ty, self.target.*, .ret), .none), |
| 8687 | const aliased_reg = registerAlias(ret_reg, ret_ty_size); | 9165 | }; |
| 8688 | result.return_value = .{ .short = .{ .register = aliased_reg }, .long = .none }; | 9166 | if (classes.len > 1) { |
| 8689 | } else { | 9167 | return self.fail("TODO handle multiple classes per type", .{}); |
| 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 | }; | ||
| 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 | // Input params | 9190 | // Input params |
| 8700 | for (param_types, result.args) |ty, *arg| { | 9191 | for (param_types, result.args) |ty, *arg| { |
| 8701 | assert(ty.hasRuntimeBitsIgnoreComptime()); | 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 | .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)}, | 9195 | .windows => &[1]abi.Class{abi.classifyWindows(ty, self.target.*)}, |
| 8705 | else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none), | 9196 | else => mem.sliceTo(&abi.classifySystemV(ty, self.target.*, .arg), .none), |
| 8706 | }; | 9197 | }; |
| ... | @@ -8708,13 +9199,29 @@ fn resolveCallingConventionValues( | ... | @@ -8708,13 +9199,29 @@ fn resolveCallingConventionValues( |
| 8708 | return self.fail("TODO handle multiple classes per type", .{}); | 9199 | return self.fail("TODO handle multiple classes per type", .{}); |
| 8709 | } | 9200 | } |
| 8710 | switch (classes[0]) { | 9201 | switch (classes[0]) { |
| 8711 | .integer => blk: { | 9202 | .integer => if (param_reg_i < abi.getCAbiIntParamRegs(self.target.*).len) { |
| 8712 | if (param_reg_i >= abi.getCAbiIntParamRegs(self.target.*).len) break :blk; | 9203 | arg.* = .{ .register = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i] }; |
| 8713 | const param_reg = abi.getCAbiIntParamRegs(self.target.*)[param_reg_i]; | ||
| 8714 | param_reg_i += 1; | 9204 | param_reg_i += 1; |
| 8715 | arg.* = .{ .register = param_reg }; | ||
| 8716 | continue; | 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 | .memory => {}, // fallthrough | 9225 | .memory => {}, // fallthrough |
| 8719 | else => |class| return self.fail("TODO handle calling convention class {s}", .{ | 9226 | else => |class| return self.fail("TODO handle calling convention class {s}", .{ |
| 8720 | @tagName(class), | 9227 | @tagName(class), |
| ... | @@ -8863,15 +9370,16 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { | ... | @@ -8863,15 +9370,16 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void { |
| 8863 | } | 9370 | } |
| 8864 | 9371 | ||
| 8865 | fn regBitSize(self: *Self, ty: Type) u64 { | 9372 | fn regBitSize(self: *Self, ty: Type) u64 { |
| 9373 | const abi_size = ty.abiSize(self.target.*); | ||
| 8866 | return switch (ty.zigTypeTag()) { | 9374 | return switch (ty.zigTypeTag()) { |
| 8867 | else => switch (ty.abiSize(self.target.*)) { | 9375 | else => switch (abi_size) { |
| 8868 | 1 => 8, | 9376 | 1 => 8, |
| 8869 | 2 => 16, | 9377 | 2 => 16, |
| 8870 | 3...4 => 32, | 9378 | 3...4 => 32, |
| 8871 | 5...8 => 64, | 9379 | 5...8 => 64, |
| 8872 | else => unreachable, | 9380 | else => unreachable, |
| 8873 | }, | 9381 | }, |
| 8874 | .Float => switch (ty.abiSize(self.target.*)) { | 9382 | .Float => switch (abi_size) { |
| 8875 | 1...16 => 128, | 9383 | 1...16 => 128, |
| 8876 | 17...32 => 256, | 9384 | 17...32 => 256, |
| 8877 | else => unreachable, | 9385 | else => unreachable, |
| ... | @@ -8882,17 +9390,3 @@ fn regBitSize(self: *Self, ty: Type) u64 { | ... | @@ -8882,17 +9390,3 @@ fn regBitSize(self: *Self, ty: Type) u64 { |
| 8882 | fn regExtraBits(self: *Self, ty: Type) u64 { | 9390 | fn regExtraBits(self: *Self, ty: Type) u64 { |
| 8883 | return self.regBitSize(ty) - ty.bitSize(self.target.*); | 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 | } |
src/arch/x86_64/Encoding.zig+16-11| ... | @@ -58,7 +58,7 @@ pub fn findByMnemonic( | ... | @@ -58,7 +58,7 @@ pub fn findByMnemonic( |
| 58 | next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| { | 58 | next: for (mnemonic_to_encodings_map[@enumToInt(mnemonic)]) |data| { |
| 59 | switch (data.mode) { | 59 | switch (data.mode) { |
| 60 | .rex => if (!rex_required) continue, | 60 | .rex => if (!rex_required) continue, |
| 61 | .long, .sse2_long => {}, | 61 | .long, .sse_long, .sse2_long => {}, |
| 62 | else => if (rex_required) continue, | 62 | else => if (rex_required) continue, |
| 63 | } | 63 | } |
| 64 | for (input_ops, data.ops) |input_op, data_op| | 64 | for (input_ops, data.ops) |input_op, data_op| |
| ... | @@ -90,7 +90,7 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct { | ... | @@ -90,7 +90,7 @@ pub fn findByOpcode(opc: []const u8, prefixes: struct { |
| 90 | if (prefixes.rex.w) { | 90 | if (prefixes.rex.w) { |
| 91 | switch (data.mode) { | 91 | switch (data.mode) { |
| 92 | .short, .fpu, .sse, .sse2, .sse4_1, .none => continue, | 92 | .short, .fpu, .sse, .sse2, .sse4_1, .none => continue, |
| 93 | .long, .sse2_long, .rex => {}, | 93 | .long, .sse_long, .sse2_long, .rex => {}, |
| 94 | } | 94 | } |
| 95 | } else if (prefixes.rex.present and !prefixes.rex.isSet()) { | 95 | } else if (prefixes.rex.present and !prefixes.rex.isSet()) { |
| 96 | switch (data.mode) { | 96 | switch (data.mode) { |
| ... | @@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 { | ... | @@ -138,7 +138,7 @@ pub fn modRmExt(encoding: Encoding) u3 { |
| 138 | pub fn operandBitSize(encoding: Encoding) u64 { | 138 | pub fn operandBitSize(encoding: Encoding) u64 { |
| 139 | switch (encoding.data.mode) { | 139 | switch (encoding.data.mode) { |
| 140 | .short => return 16, | 140 | .short => return 16, |
| 141 | .long, .sse2_long => return 64, | 141 | .long, .sse_long, .sse2_long => return 64, |
| 142 | else => {}, | 142 | else => {}, |
| 143 | } | 143 | } |
| 144 | const bit_size: u64 = switch (encoding.data.op_en) { | 144 | const bit_size: u64 = switch (encoding.data.op_en) { |
| ... | @@ -163,7 +163,7 @@ pub fn format( | ... | @@ -163,7 +163,7 @@ pub fn format( |
| 163 | _ = options; | 163 | _ = options; |
| 164 | _ = fmt; | 164 | _ = fmt; |
| 165 | switch (encoding.data.mode) { | 165 | switch (encoding.data.mode) { |
| 166 | .long, .sse2_long => try writer.writeAll("REX.W + "), | 166 | .long, .sse_long, .sse2_long => try writer.writeAll("REX.W + "), |
| 167 | else => {}, | 167 | else => {}, |
| 168 | } | 168 | } |
| 169 | 169 | ||
| ... | @@ -269,21 +269,25 @@ pub const Mnemonic = enum { | ... | @@ -269,21 +269,25 @@ pub const Mnemonic = enum { |
| 269 | // SSE | 269 | // SSE |
| 270 | addss, | 270 | addss, |
| 271 | cmpss, | 271 | cmpss, |
| 272 | cvtsi2ss, | ||
| 272 | divss, | 273 | divss, |
| 273 | maxss, minss, | 274 | maxss, minss, |
| 274 | movss, | 275 | movss, |
| 275 | mulss, | 276 | mulss, |
| 276 | subss, | 277 | subss, |
| 277 | ucomiss, | 278 | ucomiss, |
| 279 | xorps, | ||
| 278 | // SSE2 | 280 | // SSE2 |
| 279 | addsd, | 281 | addsd, |
| 280 | //cmpsd, | 282 | //cmpsd, |
| 283 | cvtsd2ss, cvtsi2sd, cvtss2sd, | ||
| 281 | divsd, | 284 | divsd, |
| 282 | maxsd, minsd, | 285 | maxsd, minsd, |
| 283 | movq, //movd, movsd, | 286 | movq, //movd, movsd, |
| 284 | mulsd, | 287 | mulsd, |
| 285 | subsd, | 288 | subsd, |
| 286 | ucomisd, | 289 | ucomisd, |
| 290 | xorpd, | ||
| 287 | // SSE4.1 | 291 | // SSE4.1 |
| 288 | roundss, | 292 | roundss, |
| 289 | roundsd, | 293 | roundsd, |
| ... | @@ -318,7 +322,7 @@ pub const Op = enum { | ... | @@ -318,7 +322,7 @@ pub const Op = enum { |
| 318 | m, | 322 | m, |
| 319 | moffs, | 323 | moffs, |
| 320 | sreg, | 324 | sreg, |
| 321 | xmm, xmm_m32, xmm_m64, | 325 | xmm, xmm_m32, xmm_m64, xmm_m128, |
| 322 | // zig fmt: on | 326 | // zig fmt: on |
| 323 | 327 | ||
| 324 | pub fn fromOperand(operand: Instruction.Operand) Op { | 328 | pub fn fromOperand(operand: Instruction.Operand) Op { |
| ... | @@ -400,7 +404,7 @@ pub const Op = enum { | ... | @@ -400,7 +404,7 @@ pub const Op = enum { |
| 400 | .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32, | 404 | .imm32, .imm32s, .eax, .r32, .m32, .rm32, .rel32, .xmm_m32 => 32, |
| 401 | .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64, | 405 | .imm64, .rax, .r64, .m64, .rm64, .xmm_m64 => 64, |
| 402 | .m80 => 80, | 406 | .m80 => 80, |
| 403 | .m128, .xmm => 128, | 407 | .m128, .xmm, .xmm_m128 => 128, |
| 404 | }; | 408 | }; |
| 405 | } | 409 | } |
| 406 | 410 | ||
| ... | @@ -423,8 +427,8 @@ pub const Op = enum { | ... | @@ -423,8 +427,8 @@ pub const Op = enum { |
| 423 | .al, .ax, .eax, .rax, | 427 | .al, .ax, .eax, .rax, |
| 424 | .r8, .r16, .r32, .r64, | 428 | .r8, .r16, .r32, .r64, |
| 425 | .rm8, .rm16, .rm32, .rm64, | 429 | .rm8, .rm16, .rm32, .rm64, |
| 426 | .xmm, .xmm_m32, .xmm_m64, | 430 | .xmm, .xmm_m32, .xmm_m64, .xmm_m128, |
| 427 | => true, | 431 | => true, |
| 428 | else => false, | 432 | else => false, |
| 429 | }; | 433 | }; |
| 430 | // zig fmt: on | 434 | // zig fmt: on |
| ... | @@ -449,7 +453,7 @@ pub const Op = enum { | ... | @@ -449,7 +453,7 @@ pub const Op = enum { |
| 449 | .rm8, .rm16, .rm32, .rm64, | 453 | .rm8, .rm16, .rm32, .rm64, |
| 450 | .m8, .m16, .m32, .m64, .m80, .m128, | 454 | .m8, .m16, .m32, .m64, .m80, .m128, |
| 451 | .m, | 455 | .m, |
| 452 | .xmm_m32, .xmm_m64, | 456 | .xmm_m32, .xmm_m64, .xmm_m128, |
| 453 | => true, | 457 | => true, |
| 454 | else => false, | 458 | else => false, |
| 455 | }; | 459 | }; |
| ... | @@ -470,13 +474,13 @@ pub const Op = enum { | ... | @@ -470,13 +474,13 @@ pub const Op = enum { |
| 470 | .r8, .r16, .r32, .r64 => .general_purpose, | 474 | .r8, .r16, .r32, .r64 => .general_purpose, |
| 471 | .rm8, .rm16, .rm32, .rm64 => .general_purpose, | 475 | .rm8, .rm16, .rm32, .rm64 => .general_purpose, |
| 472 | .sreg => .segment, | 476 | .sreg => .segment, |
| 473 | .xmm, .xmm_m32, .xmm_m64 => .floating_point, | 477 | .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => .floating_point, |
| 474 | }; | 478 | }; |
| 475 | } | 479 | } |
| 476 | 480 | ||
| 477 | pub fn isFloatingPointRegister(op: Op) bool { | 481 | pub fn isFloatingPointRegister(op: Op) bool { |
| 478 | return switch (op) { | 482 | return switch (op) { |
| 479 | .xmm, .xmm_m32, .xmm_m64 => true, | 483 | .xmm, .xmm_m32, .xmm_m64, .xmm_m128 => true, |
| 480 | else => false, | 484 | else => false, |
| 481 | }; | 485 | }; |
| 482 | } | 486 | } |
| ... | @@ -535,6 +539,7 @@ pub const Mode = enum { | ... | @@ -535,6 +539,7 @@ pub const Mode = enum { |
| 535 | rex, | 539 | rex, |
| 536 | long, | 540 | long, |
| 537 | sse, | 541 | sse, |
| 542 | sse_long, | ||
| 538 | sse2, | 543 | sse2, |
| 539 | sse2_long, | 544 | sse2_long, |
| 540 | sse4_1, | 545 | sse4_1, |
src/arch/x86_64/Lower.zig+6| ... | @@ -95,6 +95,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { | ... | @@ -95,6 +95,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { |
| 95 | 95 | ||
| 96 | .addss, | 96 | .addss, |
| 97 | .cmpss, | 97 | .cmpss, |
| 98 | .cvtsi2ss, | ||
| 98 | .divss, | 99 | .divss, |
| 99 | .maxss, | 100 | .maxss, |
| 100 | .minss, | 101 | .minss, |
| ... | @@ -103,8 +104,12 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { | ... | @@ -103,8 +104,12 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { |
| 103 | .roundss, | 104 | .roundss, |
| 104 | .subss, | 105 | .subss, |
| 105 | .ucomiss, | 106 | .ucomiss, |
| 107 | .xorps, | ||
| 106 | .addsd, | 108 | .addsd, |
| 107 | .cmpsd, | 109 | .cmpsd, |
| 110 | .cvtsd2ss, | ||
| 111 | .cvtsi2sd, | ||
| 112 | .cvtss2sd, | ||
| 108 | .divsd, | 113 | .divsd, |
| 109 | .maxsd, | 114 | .maxsd, |
| 110 | .minsd, | 115 | .minsd, |
| ... | @@ -113,6 +118,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { | ... | @@ -113,6 +118,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction { |
| 113 | .roundsd, | 118 | .roundsd, |
| 114 | .subsd, | 119 | .subsd, |
| 115 | .ucomisd, | 120 | .ucomisd, |
| 121 | .xorpd, | ||
| 116 | => try lower.mirGeneric(inst), | 122 | => try lower.mirGeneric(inst), |
| 117 | 123 | ||
| 118 | .cmps, | 124 | .cmps, |
src/arch/x86_64/Mir.zig+12| ... | @@ -170,6 +170,8 @@ pub const Inst = struct { | ... | @@ -170,6 +170,8 @@ pub const Inst = struct { |
| 170 | addss, | 170 | addss, |
| 171 | /// Compare scalar single-precision floating-point values | 171 | /// Compare scalar single-precision floating-point values |
| 172 | cmpss, | 172 | cmpss, |
| 173 | /// Convert doubleword integer to scalar single-precision floating-point value | ||
| 174 | cvtsi2ss, | ||
| 173 | /// Divide scalar single-precision floating-point values | 175 | /// Divide scalar single-precision floating-point values |
| 174 | divss, | 176 | divss, |
| 175 | /// Return maximum single-precision floating-point value | 177 | /// Return maximum single-precision floating-point value |
| ... | @@ -186,10 +188,18 @@ pub const Inst = struct { | ... | @@ -186,10 +188,18 @@ pub const Inst = struct { |
| 186 | subss, | 188 | subss, |
| 187 | /// Unordered compare scalar single-precision floating-point values | 189 | /// Unordered compare scalar single-precision floating-point values |
| 188 | ucomiss, | 190 | ucomiss, |
| 191 | /// Bitwise logical xor of packed single precision floating-point values | ||
| 192 | xorps, | ||
| 189 | /// Add double precision floating point values | 193 | /// Add double precision floating point values |
| 190 | addsd, | 194 | addsd, |
| 191 | /// Compare scalar double-precision floating-point values | 195 | /// Compare scalar double-precision floating-point values |
| 192 | cmpsd, | 196 | cmpsd, |
| 197 | /// Convert scalar double-precision floating-point value to scalar single-precision floating-point value | ||
| 198 | cvtsd2ss, | ||
| 199 | /// Convert doubleword integer to scalar double-precision floating-point value | ||
| 200 | cvtsi2sd, | ||
| 201 | /// Convert scalar single-precision floating-point value to scalar double-precision floating-point value | ||
| 202 | cvtss2sd, | ||
| 193 | /// Divide scalar double-precision floating-point values | 203 | /// Divide scalar double-precision floating-point values |
| 194 | divsd, | 204 | divsd, |
| 195 | /// Return maximum double-precision floating-point value | 205 | /// Return maximum double-precision floating-point value |
| ... | @@ -206,6 +216,8 @@ pub const Inst = struct { | ... | @@ -206,6 +216,8 @@ pub const Inst = struct { |
| 206 | subsd, | 216 | subsd, |
| 207 | /// Unordered compare scalar double-precision floating-point values | 217 | /// Unordered compare scalar double-precision floating-point values |
| 208 | ucomisd, | 218 | ucomisd, |
| 219 | /// Bitwise logical xor of packed double precision floating-point values | ||
| 220 | xorpd, | ||
| 209 | 221 | ||
| 210 | /// Compare string operands | 222 | /// Compare string operands |
| 211 | cmps, | 223 | cmps, |
src/arch/x86_64/encoder.zig+1-1| ... | @@ -323,7 +323,7 @@ pub const Instruction = struct { | ... | @@ -323,7 +323,7 @@ pub const Instruction = struct { |
| 323 | var rex = Rex{}; | 323 | var rex = Rex{}; |
| 324 | rex.present = inst.encoding.data.mode == .rex; | 324 | rex.present = inst.encoding.data.mode == .rex; |
| 325 | switch (inst.encoding.data.mode) { | 325 | switch (inst.encoding.data.mode) { |
| 326 | .long, .sse2_long => rex.w = true, | 326 | .long, .sse_long, .sse2_long => rex.w = true, |
| 327 | else => {}, | 327 | else => {}, |
| 328 | } | 328 | } |
| 329 | 329 |
src/arch/x86_64/encodings.zig+14| ... | @@ -834,6 +834,9 @@ pub const table = [_]Entry{ | ... | @@ -834,6 +834,9 @@ pub const table = [_]Entry{ |
| 834 | 834 | ||
| 835 | .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse }, | 835 | .{ .cmpss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0xf3, 0x0f, 0xc2 }, 0, .sse }, |
| 836 | 836 | ||
| 837 | .{ .cvtsi2ss, .rm, &.{ .xmm, .rm32 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .sse }, | ||
| 838 | .{ .cvtsi2ss, .rm, &.{ .xmm, .rm64 }, &.{ 0xf3, 0x0f, 0x2a }, 0, .sse_long }, | ||
| 839 | |||
| 837 | .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse }, | 840 | .{ .divss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5e }, 0, .sse }, |
| 838 | 841 | ||
| 839 | .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse }, | 842 | .{ .maxss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5f }, 0, .sse }, |
| ... | @@ -849,11 +852,20 @@ pub const table = [_]Entry{ | ... | @@ -849,11 +852,20 @@ pub const table = [_]Entry{ |
| 849 | 852 | ||
| 850 | .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse }, | 853 | .{ .ucomiss, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0x0f, 0x2e }, 0, .sse }, |
| 851 | 854 | ||
| 855 | .{ .xorps, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x0f, 0x57 }, 0, .sse }, | ||
| 856 | |||
| 852 | // SSE2 | 857 | // SSE2 |
| 853 | .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 }, | 858 | .{ .addsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x58 }, 0, .sse2 }, |
| 854 | 859 | ||
| 855 | .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 }, | 860 | .{ .cmpsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0xf2, 0x0f, 0xc2 }, 0, .sse2 }, |
| 856 | 861 | ||
| 862 | .{ .cvtsd2ss, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5a }, 0, .sse2 }, | ||
| 863 | |||
| 864 | .{ .cvtsi2sd, .rm, &.{ .xmm, .rm32 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .sse2 }, | ||
| 865 | .{ .cvtsi2sd, .rm, &.{ .xmm, .rm64 }, &.{ 0xf2, 0x0f, 0x2a }, 0, .sse2_long }, | ||
| 866 | |||
| 867 | .{ .cvtss2sd, .rm, &.{ .xmm, .xmm_m32 }, &.{ 0xf3, 0x0f, 0x5a }, 0, .sse2 }, | ||
| 868 | |||
| 857 | .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 }, | 869 | .{ .divsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5e }, 0, .sse2 }, |
| 858 | 870 | ||
| 859 | .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 }, | 871 | .{ .maxsd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0xf2, 0x0f, 0x5f }, 0, .sse2 }, |
| ... | @@ -878,6 +890,8 @@ pub const table = [_]Entry{ | ... | @@ -878,6 +890,8 @@ pub const table = [_]Entry{ |
| 878 | 890 | ||
| 879 | .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 }, | 891 | .{ .ucomisd, .rm, &.{ .xmm, .xmm_m64 }, &.{ 0x66, 0x0f, 0x2e }, 0, .sse2 }, |
| 880 | 892 | ||
| 893 | .{ .xorpd, .rm, &.{ .xmm, .xmm_m128 }, &.{ 0x66, 0x0f, 0x57 }, 0, .sse2 }, | ||
| 894 | |||
| 881 | // SSE4.1 | 895 | // SSE4.1 |
| 882 | .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 }, | 896 | .{ .roundss, .rmi, &.{ .xmm, .xmm_m32, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0a }, 0, .sse4_1 }, |
| 883 | .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 }, | 897 | .{ .roundsd, .rmi, &.{ .xmm, .xmm_m64, .imm8 }, &.{ 0x66, 0x0f, 0x3a, 0x0b }, 0, .sse4_1 }, |
src/codegen.zig+117-40| ... | @@ -7,6 +7,7 @@ const link = @import("link.zig"); | ... | @@ -7,6 +7,7 @@ const link = @import("link.zig"); |
| 7 | const log = std.log.scoped(.codegen); | 7 | const log = std.log.scoped(.codegen); |
| 8 | const mem = std.mem; | 8 | const mem = std.mem; |
| 9 | const math = std.math; | 9 | const math = std.math; |
| 10 | const target_util = @import("target.zig"); | ||
| 10 | const trace = @import("tracy.zig").trace; | 11 | const trace = @import("tracy.zig").trace; |
| 11 | 12 | ||
| 12 | const Air = @import("Air.zig"); | 13 | const Air = @import("Air.zig"); |
| ... | @@ -89,25 +90,36 @@ pub fn generateFunction( | ... | @@ -89,25 +90,36 @@ pub fn generateFunction( |
| 89 | } | 90 | } |
| 90 | } | 91 | } |
| 91 | 92 | ||
| 93 | pub fn generateLazyFunction( | ||
| 94 | bin_file: *link.File, | ||
| 95 | src_loc: Module.SrcLoc, | ||
| 96 | lazy_sym: link.File.LazySymbol, | ||
| 97 | code: *std.ArrayList(u8), | ||
| 98 | debug_output: DebugInfoOutput, | ||
| 99 | ) CodeGenError!Result { | ||
| 100 | switch (bin_file.options.target.cpu.arch) { | ||
| 101 | .x86_64 => return @import("arch/x86_64/CodeGen.zig").generateLazy(bin_file, src_loc, lazy_sym, code, debug_output), | ||
| 102 | else => unreachable, | ||
| 103 | } | ||
| 104 | } | ||
| 105 | |||
| 92 | fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void { | 106 | fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian, code: []u8) void { |
| 93 | _ = target; | 107 | _ = target; |
| 94 | const Int = @Type(.{ .Int = .{ | 108 | const bits = @typeInfo(F).Float.bits; |
| 95 | .signedness = .unsigned, | 109 | const Int = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = bits } }); |
| 96 | .bits = @typeInfo(F).Float.bits, | ||
| 97 | } }); | ||
| 98 | const int = @bitCast(Int, f); | 110 | const int = @bitCast(Int, f); |
| 99 | mem.writeInt(Int, code[0..@sizeOf(Int)], int, endian); | 111 | mem.writeInt(Int, code[0..@divExact(bits, 8)], int, endian); |
| 100 | } | 112 | } |
| 101 | 113 | ||
| 102 | pub fn generateLazySymbol( | 114 | pub fn generateLazySymbol( |
| 103 | bin_file: *link.File, | 115 | bin_file: *link.File, |
| 104 | src_loc: Module.SrcLoc, | 116 | src_loc: Module.SrcLoc, |
| 105 | lazy_sym: link.File.LazySymbol, | 117 | lazy_sym: link.File.LazySymbol, |
| 118 | alignment: *u32, | ||
| 106 | code: *std.ArrayList(u8), | 119 | code: *std.ArrayList(u8), |
| 107 | debug_output: DebugInfoOutput, | 120 | debug_output: DebugInfoOutput, |
| 108 | reloc_info: RelocInfo, | 121 | reloc_info: RelocInfo, |
| 109 | ) CodeGenError!Result { | 122 | ) CodeGenError!Result { |
| 110 | _ = debug_output; | ||
| 111 | _ = reloc_info; | 123 | _ = reloc_info; |
| 112 | 124 | ||
| 113 | const tracy = trace(@src()); | 125 | const tracy = trace(@src()); |
| ... | @@ -122,7 +134,13 @@ pub fn generateLazySymbol( | ... | @@ -122,7 +134,13 @@ pub fn generateLazySymbol( |
| 122 | lazy_sym.ty.fmt(mod), | 134 | lazy_sym.ty.fmt(mod), |
| 123 | }); | 135 | }); |
| 124 | 136 | ||
| 125 | if (lazy_sym.kind == .const_data and lazy_sym.ty.isAnyError()) { | 137 | if (lazy_sym.kind == .code) { |
| 138 | alignment.* = target_util.defaultFunctionAlignment(target); | ||
| 139 | return generateLazyFunction(bin_file, src_loc, lazy_sym, code, debug_output); | ||
| 140 | } | ||
| 141 | |||
| 142 | if (lazy_sym.ty.isAnyError()) { | ||
| 143 | alignment.* = 4; | ||
| 126 | const err_names = mod.error_name_list.items; | 144 | const err_names = mod.error_name_list.items; |
| 127 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); | 145 | mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); |
| 128 | var offset = code.items.len; | 146 | var offset = code.items.len; |
| ... | @@ -136,6 +154,14 @@ pub fn generateLazySymbol( | ... | @@ -136,6 +154,14 @@ pub fn generateLazySymbol( |
| 136 | } | 154 | } |
| 137 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); | 155 | mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); |
| 138 | return Result.ok; | 156 | return Result.ok; |
| 157 | } else if (lazy_sym.ty.zigTypeTag() == .Enum) { | ||
| 158 | alignment.* = 1; | ||
| 159 | for (lazy_sym.ty.enumFields().keys()) |tag_name| { | ||
| 160 | try code.ensureUnusedCapacity(tag_name.len + 1); | ||
| 161 | code.appendSliceAssumeCapacity(tag_name); | ||
| 162 | code.appendAssumeCapacity(0); | ||
| 163 | } | ||
| 164 | return Result.ok; | ||
| 139 | } else return .{ .fail = try ErrorMsg.create( | 165 | } else return .{ .fail = try ErrorMsg.create( |
| 140 | bin_file.allocator, | 166 | bin_file.allocator, |
| 141 | src_loc, | 167 | src_loc, |
| ... | @@ -187,18 +213,14 @@ pub fn generateSymbol( | ... | @@ -187,18 +213,14 @@ pub fn generateSymbol( |
| 187 | }; | 213 | }; |
| 188 | }, | 214 | }, |
| 189 | .Float => { | 215 | .Float => { |
| 190 | const float_bits = typed_value.ty.floatBits(target); | 216 | switch (typed_value.ty.floatBits(target)) { |
| 191 | switch (float_bits) { | ||
| 192 | 16 => writeFloat(f16, typed_value.val.toFloat(f16), target, endian, try code.addManyAsArray(2)), | 217 | 16 => writeFloat(f16, typed_value.val.toFloat(f16), target, endian, try code.addManyAsArray(2)), |
| 193 | 32 => writeFloat(f32, typed_value.val.toFloat(f32), target, endian, try code.addManyAsArray(4)), | 218 | 32 => writeFloat(f32, typed_value.val.toFloat(f32), target, endian, try code.addManyAsArray(4)), |
| 194 | 64 => writeFloat(f64, typed_value.val.toFloat(f64), target, endian, try code.addManyAsArray(8)), | 219 | 64 => writeFloat(f64, typed_value.val.toFloat(f64), target, endian, try code.addManyAsArray(8)), |
| 195 | 80 => return Result{ | 220 | 80 => { |
| 196 | .fail = try ErrorMsg.create( | 221 | writeFloat(f80, typed_value.val.toFloat(f80), target, endian, try code.addManyAsArray(10)); |
| 197 | bin_file.allocator, | 222 | const abi_size = math.cast(usize, typed_value.ty.abiSize(target)) orelse return error.Overflow; |
| 198 | src_loc, | 223 | try code.appendNTimes(0, abi_size - 10); |
| 199 | "TODO handle f80 in generateSymbol", | ||
| 200 | .{}, | ||
| 201 | ), | ||
| 202 | }, | 224 | }, |
| 203 | 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)), | 225 | 128 => writeFloat(f128, typed_value.val.toFloat(f128), target, endian, try code.addManyAsArray(16)), |
| 204 | else => unreachable, | 226 | else => unreachable, |
| ... | @@ -291,6 +313,20 @@ pub fn generateSymbol( | ... | @@ -291,6 +313,20 @@ pub fn generateSymbol( |
| 291 | }, | 313 | }, |
| 292 | }, | 314 | }, |
| 293 | .Pointer => switch (typed_value.val.tag()) { | 315 | .Pointer => switch (typed_value.val.tag()) { |
| 316 | .null_value => { | ||
| 317 | switch (target.cpu.arch.ptrBitWidth()) { | ||
| 318 | 32 => { | ||
| 319 | mem.writeInt(u32, try code.addManyAsArray(4), 0, endian); | ||
| 320 | if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 4); | ||
| 321 | }, | ||
| 322 | 64 => { | ||
| 323 | mem.writeInt(u64, try code.addManyAsArray(8), 0, endian); | ||
| 324 | if (typed_value.ty.isSlice()) try code.appendNTimes(0xaa, 8); | ||
| 325 | }, | ||
| 326 | else => unreachable, | ||
| 327 | } | ||
| 328 | return Result.ok; | ||
| 329 | }, | ||
| 294 | .zero, .one, .int_u64, .int_big_positive => { | 330 | .zero, .one, .int_u64, .int_big_positive => { |
| 295 | switch (target.cpu.arch.ptrBitWidth()) { | 331 | switch (target.cpu.arch.ptrBitWidth()) { |
| 296 | 32 => { | 332 | 32 => { |
| ... | @@ -397,30 +433,15 @@ pub fn generateSymbol( | ... | @@ -397,30 +433,15 @@ pub fn generateSymbol( |
| 397 | }, | 433 | }, |
| 398 | } | 434 | } |
| 399 | }, | 435 | }, |
| 400 | .elem_ptr => { | 436 | .elem_ptr => return lowerParentPtr( |
| 401 | const elem_ptr = typed_value.val.castTag(.elem_ptr).?.data; | 437 | bin_file, |
| 402 | const elem_size = typed_value.ty.childType().abiSize(target); | 438 | src_loc, |
| 403 | const addend = @intCast(u32, elem_ptr.index * elem_size); | 439 | typed_value, |
| 404 | const array_ptr = elem_ptr.array_ptr; | 440 | typed_value.val, |
| 405 | 441 | code, | |
| 406 | switch (array_ptr.tag()) { | 442 | debug_output, |
| 407 | .decl_ref => { | 443 | reloc_info, |
| 408 | const decl_index = array_ptr.castTag(.decl_ref).?.data; | 444 | ), |
| 409 | return lowerDeclRef(bin_file, src_loc, typed_value, decl_index, code, debug_output, .{ | ||
| 410 | .parent_atom_index = reloc_info.parent_atom_index, | ||
| 411 | .addend = (reloc_info.addend orelse 0) + addend, | ||
| 412 | }); | ||
| 413 | }, | ||
| 414 | else => return Result{ | ||
| 415 | .fail = try ErrorMsg.create( | ||
| 416 | bin_file.allocator, | ||
| 417 | src_loc, | ||
| 418 | "TODO implement generateSymbol for pointer type value: '{s}'", | ||
| 419 | .{@tagName(typed_value.val.tag())}, | ||
| 420 | ), | ||
| 421 | }, | ||
| 422 | } | ||
| 423 | }, | ||
| 424 | else => return Result{ | 445 | else => return Result{ |
| 425 | .fail = try ErrorMsg.create( | 446 | .fail = try ErrorMsg.create( |
| 426 | bin_file.allocator, | 447 | bin_file.allocator, |
| ... | @@ -838,9 +859,62 @@ pub fn generateSymbol( | ... | @@ -838,9 +859,62 @@ pub fn generateSymbol( |
| 838 | } | 859 | } |
| 839 | } | 860 | } |
| 840 | 861 | ||
| 862 | fn lowerParentPtr( | ||
| 863 | bin_file: *link.File, | ||
| 864 | src_loc: Module.SrcLoc, | ||
| 865 | typed_value: TypedValue, | ||
| 866 | parent_ptr: Value, | ||
| 867 | code: *std.ArrayList(u8), | ||
| 868 | debug_output: DebugInfoOutput, | ||
| 869 | reloc_info: RelocInfo, | ||
| 870 | ) CodeGenError!Result { | ||
| 871 | const target = bin_file.options.target; | ||
| 872 | |||
| 873 | switch (parent_ptr.tag()) { | ||
| 874 | .elem_ptr => { | ||
| 875 | const elem_ptr = parent_ptr.castTag(.elem_ptr).?.data; | ||
| 876 | return lowerParentPtr( | ||
| 877 | bin_file, | ||
| 878 | src_loc, | ||
| 879 | typed_value, | ||
| 880 | elem_ptr.array_ptr, | ||
| 881 | code, | ||
| 882 | debug_output, | ||
| 883 | reloc_info.offset(@intCast(u32, elem_ptr.index * elem_ptr.elem_ty.abiSize(target))), | ||
| 884 | ); | ||
| 885 | }, | ||
| 886 | .decl_ref => { | ||
| 887 | const decl_index = parent_ptr.castTag(.decl_ref).?.data; | ||
| 888 | return lowerDeclRef( | ||
| 889 | bin_file, | ||
| 890 | src_loc, | ||
| 891 | typed_value, | ||
| 892 | decl_index, | ||
| 893 | code, | ||
| 894 | debug_output, | ||
| 895 | reloc_info, | ||
| 896 | ); | ||
| 897 | }, | ||
| 898 | else => |t| { | ||
| 899 | return Result{ | ||
| 900 | .fail = try ErrorMsg.create( | ||
| 901 | bin_file.allocator, | ||
| 902 | src_loc, | ||
| 903 | "TODO implement lowerParentPtr for type '{s}'", | ||
| 904 | .{@tagName(t)}, | ||
| 905 | ), | ||
| 906 | }; | ||
| 907 | }, | ||
| 908 | } | ||
| 909 | } | ||
| 910 | |||
| 841 | const RelocInfo = struct { | 911 | const RelocInfo = struct { |
| 842 | parent_atom_index: u32, | 912 | parent_atom_index: u32, |
| 843 | addend: ?u32 = null, | 913 | addend: ?u32 = null, |
| 914 | |||
| 915 | fn offset(ri: RelocInfo, addend: u32) RelocInfo { | ||
| 916 | return .{ .parent_atom_index = ri.parent_atom_index, .addend = (ri.addend orelse 0) + addend }; | ||
| 917 | } | ||
| 844 | }; | 918 | }; |
| 845 | 919 | ||
| 846 | fn lowerDeclRef( | 920 | fn lowerDeclRef( |
| ... | @@ -1095,6 +1169,9 @@ pub fn genTypedValue( | ... | @@ -1095,6 +1169,9 @@ pub fn genTypedValue( |
| 1095 | .Slice => {}, | 1169 | .Slice => {}, |
| 1096 | else => { | 1170 | else => { |
| 1097 | switch (typed_value.val.tag()) { | 1171 | switch (typed_value.val.tag()) { |
| 1172 | .null_value => { | ||
| 1173 | return GenResult.mcv(.{ .immediate = 0 }); | ||
| 1174 | }, | ||
| 1098 | .int_u64 => { | 1175 | .int_u64 => { |
| 1099 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); | 1176 | return GenResult.mcv(.{ .immediate = typed_value.val.toUnsignedInt(target) }); |
| 1100 | }, | 1177 | }, |
src/link.zig+2-2| ... | @@ -1120,8 +1120,8 @@ pub const File = struct { | ... | @@ -1120,8 +1120,8 @@ pub const File = struct { |
| 1120 | kind: Kind, | 1120 | kind: Kind, |
| 1121 | ty: Type, | 1121 | ty: Type, |
| 1122 | 1122 | ||
| 1123 | pub fn initDecl(kind: Kind, decl: Module.Decl.OptionalIndex, mod: *Module) LazySymbol { | 1123 | pub fn initDecl(kind: Kind, decl: ?Module.Decl.Index, mod: *Module) LazySymbol { |
| 1124 | return .{ .kind = kind, .ty = if (decl.unwrap()) |decl_index| | 1124 | return .{ .kind = kind, .ty = if (decl) |decl_index| |
| 1125 | mod.declPtr(decl_index).val.castTag(.ty).?.data | 1125 | mod.declPtr(decl_index).val.castTag(.ty).?.data |
| 1126 | else | 1126 | else |
| 1127 | Type.anyerror }; | 1127 | Type.anyerror }; |
src/link/Coff.zig+66-45| ... | @@ -143,9 +143,11 @@ const Section = struct { | ... | @@ -143,9 +143,11 @@ const Section = struct { |
| 143 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); | 143 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 144 | 144 | ||
| 145 | const LazySymbolMetadata = struct { | 145 | const LazySymbolMetadata = struct { |
| 146 | text_atom: ?Atom.Index = null, | 146 | const State = enum { unused, pending_flush, flushed }; |
| 147 | rdata_atom: ?Atom.Index = null, | 147 | text_atom: Atom.Index = undefined, |
| 148 | alignment: u32, | 148 | rdata_atom: Atom.Index = undefined, |
| 149 | text_state: State = .unused, | ||
| 150 | rdata_state: State = .unused, | ||
| 149 | }; | 151 | }; |
| 150 | 152 | ||
| 151 | const DeclMetadata = struct { | 153 | const DeclMetadata = struct { |
| ... | @@ -1137,7 +1139,11 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In | ... | @@ -1137,7 +1139,11 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In |
| 1137 | return atom.getSymbolIndex().?; | 1139 | return atom.getSymbolIndex().?; |
| 1138 | } | 1140 | } |
| 1139 | 1141 | ||
| 1140 | pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !void { | 1142 | pub fn updateDecl( |
| 1143 | self: *Coff, | ||
| 1144 | module: *Module, | ||
| 1145 | decl_index: Module.Decl.Index, | ||
| 1146 | ) link.File.UpdateDeclError!void { | ||
| 1141 | if (build_options.skip_non_native and builtin.object_format != .coff) { | 1147 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1142 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1148 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1143 | } | 1149 | } |
| ... | @@ -1189,32 +1195,16 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! | ... | @@ -1189,32 +1195,16 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) ! |
| 1189 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 1195 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); |
| 1190 | } | 1196 | } |
| 1191 | 1197 | ||
| 1192 | fn updateLazySymbol(self: *Coff, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void { | ||
| 1193 | const mod = self.base.options.module.?; | ||
| 1194 | if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( | ||
| 1195 | link.File.LazySymbol.initDecl(.code, decl, mod), | ||
| 1196 | atom, | ||
| 1197 | self.text_section_index.?, | ||
| 1198 | metadata.alignment, | ||
| 1199 | ); | ||
| 1200 | if (metadata.rdata_atom) |atom| try self.updateLazySymbolAtom( | ||
| 1201 | link.File.LazySymbol.initDecl(.const_data, decl, mod), | ||
| 1202 | atom, | ||
| 1203 | self.rdata_section_index.?, | ||
| 1204 | metadata.alignment, | ||
| 1205 | ); | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | fn updateLazySymbolAtom( | 1198 | fn updateLazySymbolAtom( |
| 1209 | self: *Coff, | 1199 | self: *Coff, |
| 1210 | sym: link.File.LazySymbol, | 1200 | sym: link.File.LazySymbol, |
| 1211 | atom_index: Atom.Index, | 1201 | atom_index: Atom.Index, |
| 1212 | section_index: u16, | 1202 | section_index: u16, |
| 1213 | required_alignment: u32, | ||
| 1214 | ) !void { | 1203 | ) !void { |
| 1215 | const gpa = self.base.allocator; | 1204 | const gpa = self.base.allocator; |
| 1216 | const mod = self.base.options.module.?; | 1205 | const mod = self.base.options.module.?; |
| 1217 | 1206 | ||
| 1207 | var required_alignment: u32 = undefined; | ||
| 1218 | var code_buffer = std.ArrayList(u8).init(gpa); | 1208 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 1219 | defer code_buffer.deinit(); | 1209 | defer code_buffer.deinit(); |
| 1220 | 1210 | ||
| ... | @@ -1235,9 +1225,15 @@ fn updateLazySymbolAtom( | ... | @@ -1235,9 +1225,15 @@ fn updateLazySymbolAtom( |
| 1235 | .parent_decl_node = undefined, | 1225 | .parent_decl_node = undefined, |
| 1236 | .lazy = .unneeded, | 1226 | .lazy = .unneeded, |
| 1237 | }; | 1227 | }; |
| 1238 | const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ | 1228 | const res = try codegen.generateLazySymbol( |
| 1239 | .parent_atom_index = local_sym_index, | 1229 | &self.base, |
| 1240 | }); | 1230 | src, |
| 1231 | sym, | ||
| 1232 | &required_alignment, | ||
| 1233 | &code_buffer, | ||
| 1234 | .none, | ||
| 1235 | .{ .parent_atom_index = local_sym_index }, | ||
| 1236 | ); | ||
| 1241 | const code = switch (res) { | 1237 | const code = switch (res) { |
| 1242 | .ok => code_buffer.items, | 1238 | .ok => code_buffer.items, |
| 1243 | .fail => |em| { | 1239 | .fail => |em| { |
| ... | @@ -1265,20 +1261,27 @@ fn updateLazySymbolAtom( | ... | @@ -1265,20 +1261,27 @@ fn updateLazySymbolAtom( |
| 1265 | try self.writeAtom(atom_index, code); | 1261 | try self.writeAtom(atom_index, code); |
| 1266 | } | 1262 | } |
| 1267 | 1263 | ||
| 1268 | pub fn getOrCreateAtomForLazySymbol( | 1264 | pub fn getOrCreateAtomForLazySymbol(self: *Coff, sym: link.File.LazySymbol) !Atom.Index { |
| 1269 | self: *Coff, | ||
| 1270 | sym: link.File.LazySymbol, | ||
| 1271 | alignment: u32, | ||
| 1272 | ) !Atom.Index { | ||
| 1273 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); | 1265 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); |
| 1274 | errdefer _ = self.lazy_syms.pop(); | 1266 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 1275 | if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment }; | 1267 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 1276 | const atom = switch (sym.kind) { | 1268 | const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { |
| 1277 | .code => &gop.value_ptr.text_atom, | 1269 | .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state }, |
| 1278 | .const_data => &gop.value_ptr.rdata_atom, | 1270 | .const_data => .{ .atom = &gop.value_ptr.rdata_atom, .state = &gop.value_ptr.rdata_state }, |
| 1279 | }; | 1271 | }; |
| 1280 | if (atom.* == null) atom.* = try self.createAtom(); | 1272 | switch (metadata.state.*) { |
| 1281 | return atom.*.?; | 1273 | .unused => metadata.atom.* = try self.createAtom(), |
| 1274 | .pending_flush => return metadata.atom.*, | ||
| 1275 | .flushed => {}, | ||
| 1276 | } | ||
| 1277 | metadata.state.* = .pending_flush; | ||
| 1278 | const atom = metadata.atom.*; | ||
| 1279 | // anyerror needs to be deferred until flushModule | ||
| 1280 | if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { | ||
| 1281 | .code => self.text_section_index.?, | ||
| 1282 | .const_data => self.rdata_section_index.?, | ||
| 1283 | }); | ||
| 1284 | return atom; | ||
| 1282 | } | 1285 | } |
| 1283 | 1286 | ||
| 1284 | pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index { | 1287 | pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index { |
| ... | @@ -1410,7 +1413,7 @@ pub fn updateDeclExports( | ... | @@ -1410,7 +1413,7 @@ pub fn updateDeclExports( |
| 1410 | module: *Module, | 1413 | module: *Module, |
| 1411 | decl_index: Module.Decl.Index, | 1414 | decl_index: Module.Decl.Index, |
| 1412 | exports: []const *Module.Export, | 1415 | exports: []const *Module.Export, |
| 1413 | ) !void { | 1416 | ) link.File.UpdateDeclExportsError!void { |
| 1414 | if (build_options.skip_non_native and builtin.object_format != .coff) { | 1417 | if (build_options.skip_non_native and builtin.object_format != .coff) { |
| 1415 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 1418 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 1416 | } | 1419 | } |
| ... | @@ -1605,16 +1608,34 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -1605,16 +1608,34 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1605 | sub_prog_node.activate(); | 1608 | sub_prog_node.activate(); |
| 1606 | defer sub_prog_node.end(); | 1609 | defer sub_prog_node.end(); |
| 1607 | 1610 | ||
| 1608 | // Most lazy symbols can be updated when the corresponding decl is, | 1611 | const gpa = self.base.allocator; |
| 1609 | // so we only have to worry about the one without an associated decl. | 1612 | |
| 1610 | if (self.lazy_syms.get(.none)) |metadata| { | 1613 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 1611 | self.updateLazySymbol(.none, metadata) catch |err| switch (err) { | 1614 | |
| 1612 | error.CodegenFail => return error.FlushFailure, | 1615 | if (self.lazy_syms.getPtr(.none)) |metadata| { |
| 1613 | else => |e| return e, | 1616 | // Most lazy symbols can be updated on first use, but |
| 1617 | // anyerror needs to wait for everything to be flushed. | ||
| 1618 | if (metadata.text_state != .unused) self.updateLazySymbolAtom( | ||
| 1619 | link.File.LazySymbol.initDecl(.code, null, module), | ||
| 1620 | metadata.text_atom, | ||
| 1621 | self.text_section_index.?, | ||
| 1622 | ) catch |err| return switch (err) { | ||
| 1623 | error.CodegenFail => error.FlushFailure, | ||
| 1624 | else => |e| e, | ||
| 1625 | }; | ||
| 1626 | if (metadata.rdata_state != .unused) self.updateLazySymbolAtom( | ||
| 1627 | link.File.LazySymbol.initDecl(.const_data, null, module), | ||
| 1628 | metadata.rdata_atom, | ||
| 1629 | self.rdata_section_index.?, | ||
| 1630 | ) catch |err| return switch (err) { | ||
| 1631 | error.CodegenFail => error.FlushFailure, | ||
| 1632 | else => |e| e, | ||
| 1614 | }; | 1633 | }; |
| 1615 | } | 1634 | } |
| 1616 | 1635 | for (self.lazy_syms.values()) |*metadata| { | |
| 1617 | const gpa = self.base.allocator; | 1636 | if (metadata.text_state != .unused) metadata.text_state = .flushed; |
| 1637 | if (metadata.rdata_state != .unused) metadata.rdata_state = .flushed; | ||
| 1638 | } | ||
| 1618 | 1639 | ||
| 1619 | while (self.unresolved.popOrNull()) |entry| { | 1640 | while (self.unresolved.popOrNull()) |entry| { |
| 1620 | assert(entry.value); // We only expect imports generated by the incremental linker for now. | 1641 | assert(entry.value); // We only expect imports generated by the incremental linker for now. |
src/link/Elf.zig+65-42| ... | @@ -65,9 +65,11 @@ const Section = struct { | ... | @@ -65,9 +65,11 @@ const Section = struct { |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | const LazySymbolMetadata = struct { | 67 | const LazySymbolMetadata = struct { |
| 68 | text_atom: ?Atom.Index = null, | 68 | const State = enum { unused, pending_flush, flushed }; |
| 69 | rodata_atom: ?Atom.Index = null, | 69 | text_atom: Atom.Index = undefined, |
| 70 | alignment: u32, | 70 | rodata_atom: Atom.Index = undefined, |
| 71 | text_state: State = .unused, | ||
| 72 | rodata_state: State = .unused, | ||
| 71 | }; | 73 | }; |
| 72 | 74 | ||
| 73 | const DeclMetadata = struct { | 75 | const DeclMetadata = struct { |
| ... | @@ -1033,19 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node | ... | @@ -1033,19 +1035,35 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node |
| 1033 | sub_prog_node.activate(); | 1035 | sub_prog_node.activate(); |
| 1034 | defer sub_prog_node.end(); | 1036 | defer sub_prog_node.end(); |
| 1035 | 1037 | ||
| 1036 | // Most lazy symbols can be updated when the corresponding decl is, | ||
| 1037 | // so we only have to worry about the one without an associated decl. | ||
| 1038 | if (self.lazy_syms.get(.none)) |metadata| { | ||
| 1039 | self.updateLazySymbol(.none, metadata) catch |err| switch (err) { | ||
| 1040 | error.CodegenFail => return error.FlushFailure, | ||
| 1041 | else => |e| return e, | ||
| 1042 | }; | ||
| 1043 | } | ||
| 1044 | |||
| 1045 | // TODO This linker code currently assumes there is only 1 compilation unit and it | 1038 | // TODO This linker code currently assumes there is only 1 compilation unit and it |
| 1046 | // corresponds to the Zig source code. | 1039 | // corresponds to the Zig source code. |
| 1047 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; | 1040 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 1048 | 1041 | ||
| 1042 | if (self.lazy_syms.getPtr(.none)) |metadata| { | ||
| 1043 | // Most lazy symbols can be updated on first use, but | ||
| 1044 | // anyerror needs to wait for everything to be flushed. | ||
| 1045 | if (metadata.text_state != .unused) self.updateLazySymbolAtom( | ||
| 1046 | File.LazySymbol.initDecl(.code, null, module), | ||
| 1047 | metadata.text_atom, | ||
| 1048 | self.text_section_index.?, | ||
| 1049 | ) catch |err| return switch (err) { | ||
| 1050 | error.CodegenFail => error.FlushFailure, | ||
| 1051 | else => |e| e, | ||
| 1052 | }; | ||
| 1053 | if (metadata.rodata_state != .unused) self.updateLazySymbolAtom( | ||
| 1054 | File.LazySymbol.initDecl(.const_data, null, module), | ||
| 1055 | metadata.rodata_atom, | ||
| 1056 | self.rodata_section_index.?, | ||
| 1057 | ) catch |err| return switch (err) { | ||
| 1058 | error.CodegenFail => error.FlushFailure, | ||
| 1059 | else => |e| e, | ||
| 1060 | }; | ||
| 1061 | } | ||
| 1062 | for (self.lazy_syms.values()) |*metadata| { | ||
| 1063 | if (metadata.text_state != .unused) metadata.text_state = .flushed; | ||
| 1064 | if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed; | ||
| 1065 | } | ||
| 1066 | |||
| 1049 | const target_endian = self.base.options.target.cpu.arch.endian(); | 1067 | const target_endian = self.base.options.target.cpu.arch.endian(); |
| 1050 | const foreign_endian = target_endian != builtin.cpu.arch.endian(); | 1068 | const foreign_endian = target_endian != builtin.cpu.arch.endian(); |
| 1051 | 1069 | ||
| ... | @@ -2377,16 +2395,27 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { | ... | @@ -2377,16 +2395,27 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void { |
| 2377 | } | 2395 | } |
| 2378 | } | 2396 | } |
| 2379 | 2397 | ||
| 2380 | pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol, alignment: u32) !Atom.Index { | 2398 | pub fn getOrCreateAtomForLazySymbol(self: *Elf, sym: File.LazySymbol) !Atom.Index { |
| 2381 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); | 2399 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); |
| 2382 | errdefer _ = self.lazy_syms.pop(); | 2400 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 2383 | if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment }; | 2401 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 2384 | const atom = switch (sym.kind) { | 2402 | const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { |
| 2385 | .code => &gop.value_ptr.text_atom, | 2403 | .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state }, |
| 2386 | .const_data => &gop.value_ptr.rodata_atom, | 2404 | .const_data => .{ .atom = &gop.value_ptr.rodata_atom, .state = &gop.value_ptr.rodata_state }, |
| 2387 | }; | 2405 | }; |
| 2388 | if (atom.* == null) atom.* = try self.createAtom(); | 2406 | switch (metadata.state.*) { |
| 2389 | return atom.*.?; | 2407 | .unused => metadata.atom.* = try self.createAtom(), |
| 2408 | .pending_flush => return metadata.atom.*, | ||
| 2409 | .flushed => {}, | ||
| 2410 | } | ||
| 2411 | metadata.state.* = .pending_flush; | ||
| 2412 | const atom = metadata.atom.*; | ||
| 2413 | // anyerror needs to be deferred until flushModule | ||
| 2414 | if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { | ||
| 2415 | .code => self.text_section_index.?, | ||
| 2416 | .const_data => self.rodata_section_index.?, | ||
| 2417 | }); | ||
| 2418 | return atom; | ||
| 2390 | } | 2419 | } |
| 2391 | 2420 | ||
| 2392 | pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { | 2421 | pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index { |
| ... | @@ -2580,7 +2609,11 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven | ... | @@ -2580,7 +2609,11 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven |
| 2580 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 2609 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); |
| 2581 | } | 2610 | } |
| 2582 | 2611 | ||
| 2583 | pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !void { | 2612 | pub fn updateDecl( |
| 2613 | self: *Elf, | ||
| 2614 | module: *Module, | ||
| 2615 | decl_index: Module.Decl.Index, | ||
| 2616 | ) File.UpdateDeclError!void { | ||
| 2584 | if (build_options.skip_non_native and builtin.object_format != .elf) { | 2617 | if (build_options.skip_non_native and builtin.object_format != .elf) { |
| 2585 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 2618 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2586 | } | 2619 | } |
| ... | @@ -2657,32 +2690,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v | ... | @@ -2657,32 +2690,16 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v |
| 2657 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 2690 | return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); |
| 2658 | } | 2691 | } |
| 2659 | 2692 | ||
| 2660 | fn updateLazySymbol(self: *Elf, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void { | ||
| 2661 | const mod = self.base.options.module.?; | ||
| 2662 | if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( | ||
| 2663 | File.LazySymbol.initDecl(.code, decl, mod), | ||
| 2664 | atom, | ||
| 2665 | self.text_section_index.?, | ||
| 2666 | metadata.alignment, | ||
| 2667 | ); | ||
| 2668 | if (metadata.rodata_atom) |atom| try self.updateLazySymbolAtom( | ||
| 2669 | File.LazySymbol.initDecl(.const_data, decl, mod), | ||
| 2670 | atom, | ||
| 2671 | self.rodata_section_index.?, | ||
| 2672 | metadata.alignment, | ||
| 2673 | ); | ||
| 2674 | } | ||
| 2675 | |||
| 2676 | fn updateLazySymbolAtom( | 2693 | fn updateLazySymbolAtom( |
| 2677 | self: *Elf, | 2694 | self: *Elf, |
| 2678 | sym: File.LazySymbol, | 2695 | sym: File.LazySymbol, |
| 2679 | atom_index: Atom.Index, | 2696 | atom_index: Atom.Index, |
| 2680 | shdr_index: u16, | 2697 | shdr_index: u16, |
| 2681 | required_alignment: u32, | ||
| 2682 | ) !void { | 2698 | ) !void { |
| 2683 | const gpa = self.base.allocator; | 2699 | const gpa = self.base.allocator; |
| 2684 | const mod = self.base.options.module.?; | 2700 | const mod = self.base.options.module.?; |
| 2685 | 2701 | ||
| 2702 | var required_alignment: u32 = undefined; | ||
| 2686 | var code_buffer = std.ArrayList(u8).init(gpa); | 2703 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 2687 | defer code_buffer.deinit(); | 2704 | defer code_buffer.deinit(); |
| 2688 | 2705 | ||
| ... | @@ -2707,9 +2724,15 @@ fn updateLazySymbolAtom( | ... | @@ -2707,9 +2724,15 @@ fn updateLazySymbolAtom( |
| 2707 | .parent_decl_node = undefined, | 2724 | .parent_decl_node = undefined, |
| 2708 | .lazy = .unneeded, | 2725 | .lazy = .unneeded, |
| 2709 | }; | 2726 | }; |
| 2710 | const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ | 2727 | const res = try codegen.generateLazySymbol( |
| 2711 | .parent_atom_index = local_sym_index, | 2728 | &self.base, |
| 2712 | }); | 2729 | src, |
| 2730 | sym, | ||
| 2731 | &required_alignment, | ||
| 2732 | &code_buffer, | ||
| 2733 | .none, | ||
| 2734 | .{ .parent_atom_index = local_sym_index }, | ||
| 2735 | ); | ||
| 2713 | const code = switch (res) { | 2736 | const code = switch (res) { |
| 2714 | .ok => code_buffer.items, | 2737 | .ok => code_buffer.items, |
| 2715 | .fail => |em| { | 2738 | .fail => |em| { |
| ... | @@ -2814,7 +2837,7 @@ pub fn updateDeclExports( | ... | @@ -2814,7 +2837,7 @@ pub fn updateDeclExports( |
| 2814 | module: *Module, | 2837 | module: *Module, |
| 2815 | decl_index: Module.Decl.Index, | 2838 | decl_index: Module.Decl.Index, |
| 2816 | exports: []const *Module.Export, | 2839 | exports: []const *Module.Export, |
| 2817 | ) !void { | 2840 | ) File.UpdateDeclExportsError!void { |
| 2818 | if (build_options.skip_non_native and builtin.object_format != .elf) { | 2841 | if (build_options.skip_non_native and builtin.object_format != .elf) { |
| 2819 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 2842 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2820 | } | 2843 | } |
src/link/MachO.zig+64-45| ... | @@ -236,9 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) { | ... | @@ -236,9 +236,11 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) { |
| 236 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); | 236 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 237 | 237 | ||
| 238 | const LazySymbolMetadata = struct { | 238 | const LazySymbolMetadata = struct { |
| 239 | text_atom: ?Atom.Index = null, | 239 | const State = enum { unused, pending_flush, flushed }; |
| 240 | data_const_atom: ?Atom.Index = null, | 240 | text_atom: Atom.Index = undefined, |
| 241 | alignment: u32, | 241 | data_const_atom: Atom.Index = undefined, |
| 242 | text_state: State = .unused, | ||
| 243 | data_const_state: State = .unused, | ||
| 242 | }; | 244 | }; |
| 243 | 245 | ||
| 244 | const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index); | 246 | const TlvSymbolTable = std.AutoArrayHashMapUnmanaged(SymbolWithLoc, Atom.Index); |
| ... | @@ -494,16 +496,32 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No | ... | @@ -494,16 +496,32 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No |
| 494 | sub_prog_node.activate(); | 496 | sub_prog_node.activate(); |
| 495 | defer sub_prog_node.end(); | 497 | defer sub_prog_node.end(); |
| 496 | 498 | ||
| 497 | // Most lazy symbols can be updated when the corresponding decl is, | 499 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; |
| 498 | // so we only have to worry about the one without an associated decl. | 500 | |
| 499 | if (self.lazy_syms.get(.none)) |metadata| { | 501 | if (self.lazy_syms.getPtr(.none)) |metadata| { |
| 500 | self.updateLazySymbol(.none, metadata) catch |err| switch (err) { | 502 | // Most lazy symbols can be updated on first use, but |
| 501 | error.CodegenFail => return error.FlushFailure, | 503 | // anyerror needs to wait for everything to be flushed. |
| 502 | else => |e| return e, | 504 | if (metadata.text_state != .unused) self.updateLazySymbolAtom( |
| 505 | File.LazySymbol.initDecl(.code, null, module), | ||
| 506 | metadata.text_atom, | ||
| 507 | self.text_section_index.?, | ||
| 508 | ) catch |err| return switch (err) { | ||
| 509 | error.CodegenFail => error.FlushFailure, | ||
| 510 | else => |e| e, | ||
| 511 | }; | ||
| 512 | if (metadata.data_const_state != .unused) self.updateLazySymbolAtom( | ||
| 513 | File.LazySymbol.initDecl(.const_data, null, module), | ||
| 514 | metadata.data_const_atom, | ||
| 515 | self.data_const_section_index.?, | ||
| 516 | ) catch |err| return switch (err) { | ||
| 517 | error.CodegenFail => error.FlushFailure, | ||
| 518 | else => |e| e, | ||
| 503 | }; | 519 | }; |
| 504 | } | 520 | } |
| 505 | 521 | for (self.lazy_syms.values()) |*metadata| { | |
| 506 | const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented; | 522 | if (metadata.text_state != .unused) metadata.text_state = .flushed; |
| 523 | if (metadata.data_const_state != .unused) metadata.data_const_state = .flushed; | ||
| 524 | } | ||
| 507 | 525 | ||
| 508 | if (self.d_sym) |*d_sym| { | 526 | if (self.d_sym) |*d_sym| { |
| 509 | try d_sym.dwarf.flushModule(module); | 527 | try d_sym.dwarf.flushModule(module); |
| ... | @@ -2037,32 +2055,16 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) | ... | @@ -2037,32 +2055,16 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index) |
| 2037 | try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); | 2055 | try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index)); |
| 2038 | } | 2056 | } |
| 2039 | 2057 | ||
| 2040 | fn updateLazySymbol(self: *MachO, decl: Module.Decl.OptionalIndex, metadata: LazySymbolMetadata) !void { | ||
| 2041 | const mod = self.base.options.module.?; | ||
| 2042 | if (metadata.text_atom) |atom| try self.updateLazySymbolAtom( | ||
| 2043 | File.LazySymbol.initDecl(.code, decl, mod), | ||
| 2044 | atom, | ||
| 2045 | self.text_section_index.?, | ||
| 2046 | metadata.alignment, | ||
| 2047 | ); | ||
| 2048 | if (metadata.data_const_atom) |atom| try self.updateLazySymbolAtom( | ||
| 2049 | File.LazySymbol.initDecl(.const_data, decl, mod), | ||
| 2050 | atom, | ||
| 2051 | self.data_const_section_index.?, | ||
| 2052 | metadata.alignment, | ||
| 2053 | ); | ||
| 2054 | } | ||
| 2055 | |||
| 2056 | fn updateLazySymbolAtom( | 2058 | fn updateLazySymbolAtom( |
| 2057 | self: *MachO, | 2059 | self: *MachO, |
| 2058 | sym: File.LazySymbol, | 2060 | sym: File.LazySymbol, |
| 2059 | atom_index: Atom.Index, | 2061 | atom_index: Atom.Index, |
| 2060 | section_index: u8, | 2062 | section_index: u8, |
| 2061 | required_alignment: u32, | ||
| 2062 | ) !void { | 2063 | ) !void { |
| 2063 | const gpa = self.base.allocator; | 2064 | const gpa = self.base.allocator; |
| 2064 | const mod = self.base.options.module.?; | 2065 | const mod = self.base.options.module.?; |
| 2065 | 2066 | ||
| 2067 | var required_alignment: u32 = undefined; | ||
| 2066 | var code_buffer = std.ArrayList(u8).init(gpa); | 2068 | var code_buffer = std.ArrayList(u8).init(gpa); |
| 2067 | defer code_buffer.deinit(); | 2069 | defer code_buffer.deinit(); |
| 2068 | 2070 | ||
| ... | @@ -2087,9 +2089,15 @@ fn updateLazySymbolAtom( | ... | @@ -2087,9 +2089,15 @@ fn updateLazySymbolAtom( |
| 2087 | .parent_decl_node = undefined, | 2089 | .parent_decl_node = undefined, |
| 2088 | .lazy = .unneeded, | 2090 | .lazy = .unneeded, |
| 2089 | }; | 2091 | }; |
| 2090 | const res = try codegen.generateLazySymbol(&self.base, src, sym, &code_buffer, .none, .{ | 2092 | const res = try codegen.generateLazySymbol( |
| 2091 | .parent_atom_index = local_sym_index, | 2093 | &self.base, |
| 2092 | }); | 2094 | src, |
| 2095 | sym, | ||
| 2096 | &required_alignment, | ||
| 2097 | &code_buffer, | ||
| 2098 | .none, | ||
| 2099 | .{ .parent_atom_index = local_sym_index }, | ||
| 2100 | ); | ||
| 2093 | const code = switch (res) { | 2101 | const code = switch (res) { |
| 2094 | .ok => code_buffer.items, | 2102 | .ok => code_buffer.items, |
| 2095 | .fail => |em| { | 2103 | .fail => |em| { |
| ... | @@ -2108,7 +2116,7 @@ fn updateLazySymbolAtom( | ... | @@ -2108,7 +2116,7 @@ fn updateLazySymbolAtom( |
| 2108 | errdefer self.freeAtom(atom_index); | 2116 | errdefer self.freeAtom(atom_index); |
| 2109 | 2117 | ||
| 2110 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); | 2118 | log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr }); |
| 2111 | log.debug(" (required alignment 0x{x}", .{required_alignment}); | 2119 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 2112 | 2120 | ||
| 2113 | atom.size = code.len; | 2121 | atom.size = code.len; |
| 2114 | symbol.n_value = vaddr; | 2122 | symbol.n_value = vaddr; |
| ... | @@ -2117,16 +2125,30 @@ fn updateLazySymbolAtom( | ... | @@ -2117,16 +2125,30 @@ fn updateLazySymbolAtom( |
| 2117 | try self.writeAtom(atom_index, code); | 2125 | try self.writeAtom(atom_index, code); |
| 2118 | } | 2126 | } |
| 2119 | 2127 | ||
| 2120 | pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol, alignment: u32) !Atom.Index { | 2128 | pub fn getOrCreateAtomForLazySymbol(self: *MachO, sym: File.LazySymbol) !Atom.Index { |
| 2121 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); | 2129 | const gop = try self.lazy_syms.getOrPut(self.base.allocator, sym.getDecl()); |
| 2122 | errdefer _ = self.lazy_syms.pop(); | 2130 | errdefer _ = if (!gop.found_existing) self.lazy_syms.pop(); |
| 2123 | if (!gop.found_existing) gop.value_ptr.* = .{ .alignment = alignment }; | 2131 | if (!gop.found_existing) gop.value_ptr.* = .{}; |
| 2124 | const atom = switch (sym.kind) { | 2132 | const metadata: struct { atom: *Atom.Index, state: *LazySymbolMetadata.State } = switch (sym.kind) { |
| 2125 | .code => &gop.value_ptr.text_atom, | 2133 | .code => .{ .atom = &gop.value_ptr.text_atom, .state = &gop.value_ptr.text_state }, |
| 2126 | .const_data => &gop.value_ptr.data_const_atom, | 2134 | .const_data => .{ |
| 2135 | .atom = &gop.value_ptr.data_const_atom, | ||
| 2136 | .state = &gop.value_ptr.data_const_state, | ||
| 2137 | }, | ||
| 2127 | }; | 2138 | }; |
| 2128 | if (atom.* == null) atom.* = try self.createAtom(); | 2139 | switch (metadata.state.*) { |
| 2129 | return atom.*.?; | 2140 | .unused => metadata.atom.* = try self.createAtom(), |
| 2141 | .pending_flush => return metadata.atom.*, | ||
| 2142 | .flushed => {}, | ||
| 2143 | } | ||
| 2144 | metadata.state.* = .pending_flush; | ||
| 2145 | const atom = metadata.atom.*; | ||
| 2146 | // anyerror needs to be deferred until flushModule | ||
| 2147 | if (sym.getDecl() != .none) try self.updateLazySymbolAtom(sym, atom, switch (sym.kind) { | ||
| 2148 | .code => self.text_section_index.?, | ||
| 2149 | .const_data => self.data_const_section_index.?, | ||
| 2150 | }); | ||
| 2151 | return atom; | ||
| 2130 | } | 2152 | } |
| 2131 | 2153 | ||
| 2132 | fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { | 2154 | fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.Decl.Index) !void { |
| ... | @@ -2357,7 +2379,7 @@ pub fn updateDeclExports( | ... | @@ -2357,7 +2379,7 @@ pub fn updateDeclExports( |
| 2357 | module: *Module, | 2379 | module: *Module, |
| 2358 | decl_index: Module.Decl.Index, | 2380 | decl_index: Module.Decl.Index, |
| 2359 | exports: []const *Module.Export, | 2381 | exports: []const *Module.Export, |
| 2360 | ) !void { | 2382 | ) File.UpdateDeclExportsError!void { |
| 2361 | if (build_options.skip_non_native and builtin.object_format != .macho) { | 2383 | if (build_options.skip_non_native and builtin.object_format != .macho) { |
| 2362 | @panic("Attempted to compile for object format that was disabled by build configuration"); | 2384 | @panic("Attempted to compile for object format that was disabled by build configuration"); |
| 2363 | } | 2385 | } |
| ... | @@ -4147,9 +4169,6 @@ pub fn logSymtab(self: *MachO) void { | ... | @@ -4147,9 +4169,6 @@ pub fn logSymtab(self: *MachO) void { |
| 4147 | 4169 | ||
| 4148 | log.debug("stubs entries:", .{}); | 4170 | log.debug("stubs entries:", .{}); |
| 4149 | log.debug("{}", .{self.stub_table}); | 4171 | log.debug("{}", .{self.stub_table}); |
| 4150 | |||
| 4151 | // log.debug("threadlocal entries:", .{}); | ||
| 4152 | // log.debug("{}", .{self.tlv_table}); | ||
| 4153 | } | 4172 | } |
| 4154 | 4173 | ||
| 4155 | pub fn logAtoms(self: *MachO) void { | 4174 | pub fn logAtoms(self: *MachO) void { |
| ... | @@ -4189,6 +4208,6 @@ pub fn logAtom(self: *MachO, atom_index: Atom.Index) void { | ... | @@ -4189,6 +4208,6 @@ pub fn logAtom(self: *MachO, atom_index: Atom.Index) void { |
| 4189 | sym.n_value, | 4208 | sym.n_value, |
| 4190 | atom.size, | 4209 | atom.size, |
| 4191 | atom.file, | 4210 | atom.file, |
| 4192 | sym.n_sect, | 4211 | sym.n_sect + 1, |
| 4193 | }); | 4212 | }); |
| 4194 | } | 4213 | } |
src/print_air.zig+9-3| ... | @@ -94,14 +94,20 @@ const Writer = struct { | ... | @@ -94,14 +94,20 @@ const Writer = struct { |
| 94 | for (w.air.instructions.items(.tag), 0..) |tag, i| { | 94 | for (w.air.instructions.items(.tag), 0..) |tag, i| { |
| 95 | const inst = @intCast(Air.Inst.Index, i); | 95 | const inst = @intCast(Air.Inst.Index, i); |
| 96 | switch (tag) { | 96 | switch (tag) { |
| 97 | .constant, .const_ty => try w.writeInst(s, inst), | 97 | .constant, .const_ty => { |
| 98 | try w.writeInst(s, inst); | ||
| 99 | try s.writeByte('\n'); | ||
| 100 | }, | ||
| 98 | else => continue, | 101 | else => continue, |
| 99 | } | 102 | } |
| 100 | } | 103 | } |
| 101 | } | 104 | } |
| 102 | 105 | ||
| 103 | fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void { | 106 | fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void { |
| 104 | for (body) |inst| try w.writeInst(s, inst); | 107 | for (body) |inst| { |
| 108 | try w.writeInst(s, inst); | ||
| 109 | try s.writeByte('\n'); | ||
| 110 | } | ||
| 105 | } | 111 | } |
| 106 | 112 | ||
| 107 | fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 113 | fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
| ... | @@ -336,7 +342,7 @@ const Writer = struct { | ... | @@ -336,7 +342,7 @@ const Writer = struct { |
| 336 | .work_group_id, | 342 | .work_group_id, |
| 337 | => try w.writeWorkDimension(s, inst), | 343 | => try w.writeWorkDimension(s, inst), |
| 338 | } | 344 | } |
| 339 | try s.writeAll(")\n"); | 345 | try s.writeByte(')'); |
| 340 | } | 346 | } |
| 341 | 347 | ||
| 342 | fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { | 348 | fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { |
test/behavior/align.zig-5| ... | @@ -282,7 +282,6 @@ fn give() anyerror!u128 { | ... | @@ -282,7 +282,6 @@ fn give() anyerror!u128 { |
| 282 | 282 | ||
| 283 | test "page aligned array on stack" { | 283 | test "page aligned array on stack" { |
| 284 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 284 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 285 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 286 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 285 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 287 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 286 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 288 | 287 | ||
| ... | @@ -491,10 +490,6 @@ test "read 128-bit field from default aligned struct in global memory" { | ... | @@ -491,10 +490,6 @@ test "read 128-bit field from default aligned struct in global memory" { |
| 491 | } | 490 | } |
| 492 | 491 | ||
| 493 | test "struct field explicit alignment" { | 492 | test "struct field explicit alignment" { |
| 494 | if (builtin.zig_backend == .stage2_x86_64) { | ||
| 495 | // Careful enabling this test, fails randomly. | ||
| 496 | return error.SkipZigTest; | ||
| 497 | } | ||
| 498 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 493 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 499 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 494 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 500 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 495 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/atomics.zig-1| ... | @@ -112,7 +112,6 @@ test "128-bit cmpxchg" { | ... | @@ -112,7 +112,6 @@ test "128-bit cmpxchg" { |
| 112 | if (!supports_128_bit_atomics) return error.SkipZigTest; | 112 | if (!supports_128_bit_atomics) return error.SkipZigTest; |
| 113 | 113 | ||
| 114 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 114 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 115 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 116 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 115 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 117 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 116 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 118 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 117 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
test/behavior/basic.zig+8-4| ... | @@ -363,7 +363,8 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { | ... | @@ -363,7 +363,8 @@ fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA { |
| 363 | } | 363 | } |
| 364 | 364 | ||
| 365 | test "take address of parameter" { | 365 | test "take address of parameter" { |
| 366 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 366 | if (builtin.zig_backend == .stage2_x86_64 and |
| 367 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 367 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 368 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 368 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 369 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 369 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 370 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -391,7 +392,8 @@ test "array 2D const double ptr" { | ... | @@ -391,7 +392,8 @@ test "array 2D const double ptr" { |
| 391 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 392 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 392 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 393 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 393 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 394 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 394 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 395 | if (builtin.zig_backend == .stage2_x86_64 and |
| 396 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 395 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 397 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 396 | 398 | ||
| 397 | const rect_2d_vertexes = [_][1]f32{ | 399 | const rect_2d_vertexes = [_][1]f32{ |
| ... | @@ -405,7 +407,8 @@ test "array 2D const double ptr with offset" { | ... | @@ -405,7 +407,8 @@ test "array 2D const double ptr with offset" { |
| 405 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 407 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 406 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 408 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 407 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 409 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 408 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 410 | if (builtin.zig_backend == .stage2_x86_64 and |
| 411 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 409 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 412 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 410 | 413 | ||
| 411 | const rect_2d_vertexes = [_][2]f32{ | 414 | const rect_2d_vertexes = [_][2]f32{ |
| ... | @@ -419,7 +422,8 @@ test "array 3D const double ptr with offset" { | ... | @@ -419,7 +422,8 @@ test "array 3D const double ptr with offset" { |
| 419 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 422 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 420 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 423 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 421 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 424 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 422 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 425 | if (builtin.zig_backend == .stage2_x86_64 and |
| 426 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 423 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 427 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 424 | 428 | ||
| 425 | const rect_3d_vertexes = [_][2][2]f32{ | 429 | const rect_3d_vertexes = [_][2][2]f32{ |
test/behavior/bugs/13069.zig+2| ... | @@ -6,6 +6,8 @@ test { | ... | @@ -6,6 +6,8 @@ test { |
| 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 6 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 7 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 8 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 10 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 9 | 11 | ||
| 10 | var opt_x: ?[3]f32 = [_]f32{0.0} ** 3; | 12 | var opt_x: ?[3]f32 = [_]f32{0.0} ** 3; |
| 11 | 13 |
test/behavior/cast.zig+5-2| ... | @@ -95,7 +95,9 @@ test "comptime_int @intToFloat" { | ... | @@ -95,7 +95,9 @@ test "comptime_int @intToFloat" { |
| 95 | 95 | ||
| 96 | test "@intToFloat" { | 96 | test "@intToFloat" { |
| 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 97 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 98 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 98 | if (builtin.zig_backend == .stage2_x86_64 and |
| 99 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 100 | |||
| 99 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 101 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 100 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 102 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 101 | 103 | ||
| ... | @@ -634,7 +636,8 @@ test "vector casts" { | ... | @@ -634,7 +636,8 @@ test "vector casts" { |
| 634 | } | 636 | } |
| 635 | 637 | ||
| 636 | test "@floatCast cast down" { | 638 | test "@floatCast cast down" { |
| 637 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 639 | if (builtin.zig_backend == .stage2_x86_64 and |
| 640 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 638 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 641 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 639 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 642 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 640 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 643 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/enum.zig+2-5| ... | @@ -940,6 +940,8 @@ test "constant enum initialization with differing sizes" { | ... | @@ -940,6 +940,8 @@ test "constant enum initialization with differing sizes" { |
| 940 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 940 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 941 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 941 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 942 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 942 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 943 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 944 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 943 | 945 | ||
| 944 | try test3_1(test3_foo); | 946 | try test3_1(test3_foo); |
| 945 | try test3_2(test3_bar); | 947 | try test3_2(test3_bar); |
| ... | @@ -979,7 +981,6 @@ fn test3_2(f: Test3Foo) !void { | ... | @@ -979,7 +981,6 @@ fn test3_2(f: Test3Foo) !void { |
| 979 | } | 981 | } |
| 980 | 982 | ||
| 981 | test "@tagName" { | 983 | test "@tagName" { |
| 982 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 983 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 984 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 984 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 985 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 985 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 986 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -995,7 +996,6 @@ fn testEnumTagNameBare(n: anytype) []const u8 { | ... | @@ -995,7 +996,6 @@ fn testEnumTagNameBare(n: anytype) []const u8 { |
| 995 | const BareNumber = enum { One, Two, Three }; | 996 | const BareNumber = enum { One, Two, Three }; |
| 996 | 997 | ||
| 997 | test "@tagName non-exhaustive enum" { | 998 | test "@tagName non-exhaustive enum" { |
| 998 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 999 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 999 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1000 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 1000 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1001 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1001 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -1006,7 +1006,6 @@ test "@tagName non-exhaustive enum" { | ... | @@ -1006,7 +1006,6 @@ test "@tagName non-exhaustive enum" { |
| 1006 | const NonExhaustive = enum(u8) { A, B, _ }; | 1006 | const NonExhaustive = enum(u8) { A, B, _ }; |
| 1007 | 1007 | ||
| 1008 | test "@tagName is null-terminated" { | 1008 | test "@tagName is null-terminated" { |
| 1009 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 1010 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 1009 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1011 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 1010 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1012 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1011 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -1021,7 +1020,6 @@ test "@tagName is null-terminated" { | ... | @@ -1021,7 +1020,6 @@ test "@tagName is null-terminated" { |
| 1021 | } | 1020 | } |
| 1022 | 1021 | ||
| 1023 | test "tag name with assigned enum values" { | 1022 | test "tag name with assigned enum values" { |
| 1024 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 1025 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 1023 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1026 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 1024 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1027 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1025 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -1111,7 +1109,6 @@ test "enum literal in array literal" { | ... | @@ -1111,7 +1109,6 @@ test "enum literal in array literal" { |
| 1111 | 1109 | ||
| 1112 | test "tag name functions are unique" { | 1110 | test "tag name functions are unique" { |
| 1113 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1111 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1114 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | ||
| 1115 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 1112 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 1116 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 1113 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 1117 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1114 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/eval.zig+2| ... | @@ -535,6 +535,8 @@ test "static eval list init" { | ... | @@ -535,6 +535,8 @@ test "static eval list init" { |
| 535 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 535 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 536 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 536 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 537 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 537 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 538 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 539 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 538 | 540 | ||
| 539 | try expect(static_vec3.data[2] == 1.0); | 541 | try expect(static_vec3.data[2] == 1.0); |
| 540 | try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); | 542 | try expect(vec3(0.0, 0.0, 3.0).data[2] == 3.0); |
test/behavior/floatop.zig+8-5| ... | @@ -904,7 +904,8 @@ test "negation f16" { | ... | @@ -904,7 +904,8 @@ test "negation f16" { |
| 904 | } | 904 | } |
| 905 | 905 | ||
| 906 | test "negation f32" { | 906 | test "negation f32" { |
| 907 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 907 | if (builtin.zig_backend == .stage2_x86_64 and |
| 908 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 908 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 909 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 909 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 910 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 910 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 911 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -924,7 +925,8 @@ test "negation f32" { | ... | @@ -924,7 +925,8 @@ test "negation f32" { |
| 924 | } | 925 | } |
| 925 | 926 | ||
| 926 | test "negation f64" { | 927 | test "negation f64" { |
| 927 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 928 | if (builtin.zig_backend == .stage2_x86_64 and |
| 929 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 928 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 930 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 929 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 931 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 930 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 932 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -1021,7 +1023,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" { | ... | @@ -1021,7 +1023,6 @@ test "comptime fixed-width float zero divided by zero produces NaN" { |
| 1021 | 1023 | ||
| 1022 | test "comptime fixed-width float non-zero divided by zero produces signed Inf" { | 1024 | test "comptime fixed-width float non-zero divided by zero produces signed Inf" { |
| 1023 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1025 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1024 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1025 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1026 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1026 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1027 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1027 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1028 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -1060,7 +1061,8 @@ test "nan negation f16" { | ... | @@ -1060,7 +1061,8 @@ test "nan negation f16" { |
| 1060 | } | 1061 | } |
| 1061 | 1062 | ||
| 1062 | test "nan negation f32" { | 1063 | test "nan negation f32" { |
| 1063 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1064 | if (builtin.zig_backend == .stage2_x86_64 and |
| 1065 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 1064 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1066 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1065 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1067 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1066 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1068 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -1080,7 +1082,8 @@ test "nan negation f32" { | ... | @@ -1080,7 +1082,8 @@ test "nan negation f32" { |
| 1080 | 1082 | ||
| 1081 | test "nan negation f64" { | 1083 | test "nan negation f64" { |
| 1082 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1084 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1083 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 1085 | if (builtin.zig_backend == .stage2_x86_64 and |
| 1086 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 1084 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1087 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1085 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1088 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1086 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1089 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/fn.zig+4| ... | @@ -338,6 +338,8 @@ test "function call with anon list literal" { | ... | @@ -338,6 +338,8 @@ test "function call with anon list literal" { |
| 338 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 338 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 339 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 339 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 340 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 340 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 341 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 342 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 341 | 343 | ||
| 342 | const S = struct { | 344 | const S = struct { |
| 343 | fn doTheTest() !void { | 345 | fn doTheTest() !void { |
| ... | @@ -358,6 +360,8 @@ test "function call with anon list literal - 2D" { | ... | @@ -358,6 +360,8 @@ test "function call with anon list literal - 2D" { |
| 358 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 360 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 359 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 361 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 360 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 362 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 363 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 364 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 361 | 365 | ||
| 362 | const S = struct { | 366 | const S = struct { |
| 363 | fn doTheTest() !void { | 367 | fn doTheTest() !void { |
test/behavior/generics.zig+4| ... | @@ -59,6 +59,8 @@ test "fn with comptime args" { | ... | @@ -59,6 +59,8 @@ test "fn with comptime args" { |
| 59 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 59 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 60 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 60 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 61 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 61 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 62 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 63 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 62 | 64 | ||
| 63 | try expect(gimmeTheBigOne(1234, 5678) == 5678); | 65 | try expect(gimmeTheBigOne(1234, 5678) == 5678); |
| 64 | try expect(shouldCallSameInstance(34, 12) == 34); | 66 | try expect(shouldCallSameInstance(34, 12) == 34); |
| ... | @@ -69,6 +71,8 @@ test "anytype params" { | ... | @@ -69,6 +71,8 @@ test "anytype params" { |
| 69 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 71 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 70 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 72 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 71 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 73 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 74 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 75 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 72 | 76 | ||
| 73 | try expect(max_i32(12, 34) == 34); | 77 | try expect(max_i32(12, 34) == 34); |
| 74 | try expect(max_f64(1.2, 3.4) == 3.4); | 78 | try expect(max_f64(1.2, 3.4) == 3.4); |
test/behavior/inline_switch.zig-1| ... | @@ -94,7 +94,6 @@ test "inline else error" { | ... | @@ -94,7 +94,6 @@ test "inline else error" { |
| 94 | 94 | ||
| 95 | test "inline else enum" { | 95 | test "inline else enum" { |
| 96 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 96 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 97 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 98 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 97 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 99 | 98 | ||
| 100 | const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 }; | 99 | const E2 = enum(u8) { a = 2, b = 3, c = 4, d = 5 }; |
test/behavior/math.zig+2-2| ... | @@ -203,6 +203,8 @@ test "float equality" { | ... | @@ -203,6 +203,8 @@ test "float equality" { |
| 203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 203 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 204 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 205 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 205 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 206 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 207 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 206 | 208 | ||
| 207 | const x: f64 = 0.012; | 209 | const x: f64 = 0.012; |
| 208 | const y: f64 = x + 1.0; | 210 | const y: f64 = x + 1.0; |
| ... | @@ -377,7 +379,6 @@ fn testBinaryNot(x: u16) !void { | ... | @@ -377,7 +379,6 @@ fn testBinaryNot(x: u16) !void { |
| 377 | 379 | ||
| 378 | test "binary not 128-bit" { | 380 | test "binary not 128-bit" { |
| 379 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 381 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 380 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 381 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 382 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 382 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 383 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 383 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 384 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -1533,7 +1534,6 @@ test "signed zeros are represented properly" { | ... | @@ -1533,7 +1534,6 @@ test "signed zeros are represented properly" { |
| 1533 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1534 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1534 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1535 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1535 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1536 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1536 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1537 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1537 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1538 | 1538 | ||
| 1539 | const S = struct { | 1539 | const S = struct { |
test/behavior/maximum_minimum.zig+4| ... | @@ -8,6 +8,8 @@ test "@max" { | ... | @@ -8,6 +8,8 @@ test "@max" { |
| 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 8 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 9 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 10 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 12 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 11 | 13 | ||
| 12 | const S = struct { | 14 | const S = struct { |
| 13 | fn doTheTest() !void { | 15 | fn doTheTest() !void { |
| ... | @@ -54,6 +56,8 @@ test "@min" { | ... | @@ -54,6 +56,8 @@ test "@min" { |
| 54 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 56 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 55 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 57 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 56 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 58 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 59 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 60 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 57 | 61 | ||
| 58 | const S = struct { | 62 | const S = struct { |
| 59 | fn doTheTest() !void { | 63 | fn doTheTest() !void { |
test/behavior/memset.zig+2-2| ... | @@ -114,7 +114,7 @@ test "memset with large array element, runtime known" { | ... | @@ -114,7 +114,7 @@ test "memset with large array element, runtime known" { |
| 114 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 114 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 115 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | 115 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 116 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 116 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 117 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 117 | if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; |
| 118 | 118 | ||
| 119 | const A = [128]u64; | 119 | const A = [128]u64; |
| 120 | var buf: [5]A = undefined; | 120 | var buf: [5]A = undefined; |
| ... | @@ -132,7 +132,7 @@ test "memset with large array element, comptime known" { | ... | @@ -132,7 +132,7 @@ test "memset with large array element, comptime known" { |
| 132 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 132 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 133 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; | 133 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; |
| 134 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; | 134 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; |
| 135 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; | 135 | if (builtin.zig_backend == .stage2_x86_64 and builtin.os.tag == .windows) return error.SkipZigTest; |
| 136 | 136 | ||
| 137 | const A = [128]u64; | 137 | const A = [128]u64; |
| 138 | var buf: [5]A = undefined; | 138 | var buf: [5]A = undefined; |
test/behavior/pointers.zig+4-1| ... | @@ -206,7 +206,8 @@ test "allowzero pointer and slice" { | ... | @@ -206,7 +206,8 @@ test "allowzero pointer and slice" { |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | test "assign null directly to C pointer and test null equality" { | 208 | test "assign null directly to C pointer and test null equality" { |
| 209 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 209 | if (builtin.zig_backend == .stage2_x86_64 and |
| 210 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 210 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 211 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 211 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 212 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 212 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 213 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -345,6 +346,8 @@ test "pointer sentinel with +inf" { | ... | @@ -345,6 +346,8 @@ test "pointer sentinel with +inf" { |
| 345 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 346 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 346 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 347 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 347 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 348 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 349 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 350 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 348 | 351 | ||
| 349 | const S = struct { | 352 | const S = struct { |
| 350 | fn doTheTest() !void { | 353 | fn doTheTest() !void { |
test/behavior/struct.zig+2-1| ... | @@ -744,7 +744,8 @@ var g_foo: S0 = S0.init(); | ... | @@ -744,7 +744,8 @@ var g_foo: S0 = S0.init(); |
| 744 | 744 | ||
| 745 | test "packed struct with fp fields" { | 745 | test "packed struct with fp fields" { |
| 746 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 746 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 747 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 747 | if (builtin.zig_backend == .stage2_x86_64 and |
| 748 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 748 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 749 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 749 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 750 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 750 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 751 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/switch.zig+2-4| ... | @@ -88,7 +88,6 @@ fn nonConstSwitch(foo: SwitchStatementFoo) !void { | ... | @@ -88,7 +88,6 @@ fn nonConstSwitch(foo: SwitchStatementFoo) !void { |
| 88 | const SwitchStatementFoo = enum { A, B, C, D }; | 88 | const SwitchStatementFoo = enum { A, B, C, D }; |
| 89 | 89 | ||
| 90 | test "switch with multiple expressions" { | 90 | test "switch with multiple expressions" { |
| 91 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 92 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 91 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 93 | 92 | ||
| 94 | const x = switch (returnsFive()) { | 93 | const x = switch (returnsFive()) { |
| ... | @@ -231,6 +230,8 @@ test "switch prong with variable" { | ... | @@ -231,6 +230,8 @@ test "switch prong with variable" { |
| 231 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 230 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 232 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 231 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 233 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 232 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 233 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 234 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 234 | 235 | ||
| 235 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); | 236 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .One = 13 }); |
| 236 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); | 237 | try switchProngWithVarFn(SwitchProngWithVarEnum{ .Two = 13.0 }); |
| ... | @@ -273,7 +274,6 @@ fn testSwitchEnumPtrCapture() !void { | ... | @@ -273,7 +274,6 @@ fn testSwitchEnumPtrCapture() !void { |
| 273 | } | 274 | } |
| 274 | 275 | ||
| 275 | test "switch handles all cases of number" { | 276 | test "switch handles all cases of number" { |
| 276 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 277 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 277 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 278 | 278 | ||
| 279 | try testSwitchHandleAllCases(); | 279 | try testSwitchHandleAllCases(); |
| ... | @@ -453,7 +453,6 @@ test "else prong of switch on error set excludes other cases" { | ... | @@ -453,7 +453,6 @@ test "else prong of switch on error set excludes other cases" { |
| 453 | } | 453 | } |
| 454 | 454 | ||
| 455 | test "switch prongs with error set cases make a new error set type for capture value" { | 455 | test "switch prongs with error set cases make a new error set type for capture value" { |
| 456 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 457 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 456 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 458 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 457 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 459 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 458 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -530,7 +529,6 @@ test "switch with null and T peer types and inferred result location type" { | ... | @@ -530,7 +529,6 @@ test "switch with null and T peer types and inferred result location type" { |
| 530 | test "switch prongs with cases with identical payload types" { | 529 | test "switch prongs with cases with identical payload types" { |
| 531 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 530 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 532 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 531 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 533 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 534 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 532 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 535 | 533 | ||
| 536 | const Union = union(enum) { | 534 | const Union = union(enum) { |
test/behavior/type.zig-2| ... | @@ -258,7 +258,6 @@ test "Type.ErrorSet" { | ... | @@ -258,7 +258,6 @@ test "Type.ErrorSet" { |
| 258 | 258 | ||
| 259 | test "Type.Struct" { | 259 | test "Type.Struct" { |
| 260 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 260 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 261 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 262 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 261 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 263 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 262 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 264 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 263 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| ... | @@ -383,7 +382,6 @@ test "Type.Enum" { | ... | @@ -383,7 +382,6 @@ test "Type.Enum" { |
| 383 | 382 | ||
| 384 | test "Type.Union" { | 383 | test "Type.Union" { |
| 385 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 384 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 386 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 387 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 385 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 388 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 386 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 389 | 387 |
test/behavior/union.zig+14-2| ... | @@ -14,6 +14,8 @@ test "basic unions with floats" { | ... | @@ -14,6 +14,8 @@ test "basic unions with floats" { |
| 14 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 14 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 15 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 16 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 16 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 17 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 18 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 17 | 19 | ||
| 18 | var foo = FooWithFloats{ .int = 1 }; | 20 | var foo = FooWithFloats{ .int = 1 }; |
| 19 | try expect(foo.int == 1); | 21 | try expect(foo.int == 1); |
| ... | @@ -29,6 +31,8 @@ test "init union with runtime value - floats" { | ... | @@ -29,6 +31,8 @@ test "init union with runtime value - floats" { |
| 29 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 31 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 30 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 32 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 31 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 33 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 34 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 35 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 32 | 36 | ||
| 33 | var foo: FooWithFloats = undefined; | 37 | var foo: FooWithFloats = undefined; |
| 34 | 38 | ||
| ... | @@ -216,6 +220,8 @@ test "union with specified enum tag" { | ... | @@ -216,6 +220,8 @@ test "union with specified enum tag" { |
| 216 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 220 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 217 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 221 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 218 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 222 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 223 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 224 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 219 | 225 | ||
| 220 | try doTest(); | 226 | try doTest(); |
| 221 | comptime try doTest(); | 227 | comptime try doTest(); |
| ... | @@ -225,6 +231,8 @@ test "packed union generates correctly aligned type" { | ... | @@ -225,6 +231,8 @@ test "packed union generates correctly aligned type" { |
| 225 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; | 231 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 226 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | 232 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 227 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 233 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 234 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 235 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 228 | 236 | ||
| 229 | const U = packed union { | 237 | const U = packed union { |
| 230 | f1: *const fn () error{TestUnexpectedResult}!void, | 238 | f1: *const fn () error{TestUnexpectedResult}!void, |
| ... | @@ -903,6 +911,8 @@ test "anonymous union literal syntax" { | ... | @@ -903,6 +911,8 @@ test "anonymous union literal syntax" { |
| 903 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 911 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 904 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 912 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 905 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 913 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 914 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 915 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 906 | 916 | ||
| 907 | const S = struct { | 917 | const S = struct { |
| 908 | const Number = union { | 918 | const Number = union { |
| ... | @@ -1055,6 +1065,8 @@ test "containers with single-field enums" { | ... | @@ -1055,6 +1065,8 @@ test "containers with single-field enums" { |
| 1055 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1065 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1056 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1066 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1057 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1067 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1068 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 1069 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 1058 | 1070 | ||
| 1059 | const S = struct { | 1071 | const S = struct { |
| 1060 | const A = union(enum) { f1 }; | 1072 | const A = union(enum) { f1 }; |
| ... | @@ -1082,7 +1094,6 @@ test "containers with single-field enums" { | ... | @@ -1082,7 +1094,6 @@ test "containers with single-field enums" { |
| 1082 | test "@unionInit on union with tag but no fields" { | 1094 | test "@unionInit on union with tag but no fields" { |
| 1083 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1095 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1084 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1096 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1085 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1086 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1097 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1087 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1098 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1088 | 1099 | ||
| ... | @@ -1277,7 +1288,6 @@ test "return an extern union from C calling convention" { | ... | @@ -1277,7 +1288,6 @@ test "return an extern union from C calling convention" { |
| 1277 | test "noreturn field in union" { | 1288 | test "noreturn field in union" { |
| 1278 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1289 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1279 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1290 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1280 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 1281 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 1291 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 1282 | 1292 | ||
| 1283 | const U = union(enum) { | 1293 | const U = union(enum) { |
| ... | @@ -1515,6 +1525,8 @@ test "reinterpreting enum value inside packed union" { | ... | @@ -1515,6 +1525,8 @@ test "reinterpreting enum value inside packed union" { |
| 1515 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 1525 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 1516 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 1526 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 1517 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 1527 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 1528 | if (builtin.zig_backend == .stage2_x86_64 and | ||
| 1529 | comptime !std.Target.x86.featureSetHasAll(builtin.cpu.features, .{ .sse, .sse2, .sse4_1 })) return error.SkipZigTest; // TODO | ||
| 1518 | 1530 | ||
| 1519 | const U = packed union { | 1531 | const U = packed union { |
| 1520 | tag: enum { a, b }, | 1532 | tag: enum { a, b }, |
test/behavior/vector.zig+4| ... | @@ -321,6 +321,7 @@ test "load vector elements via comptime index" { | ... | @@ -321,6 +321,7 @@ test "load vector elements via comptime index" { |
| 321 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 321 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 322 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 322 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 323 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 323 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 324 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 324 | 325 | ||
| 325 | const S = struct { | 326 | const S = struct { |
| 326 | fn doTheTest() !void { | 327 | fn doTheTest() !void { |
| ... | @@ -342,6 +343,7 @@ test "store vector elements via comptime index" { | ... | @@ -342,6 +343,7 @@ test "store vector elements via comptime index" { |
| 342 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 343 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 343 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 344 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 344 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 345 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 346 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 345 | 347 | ||
| 346 | const S = struct { | 348 | const S = struct { |
| 347 | fn doTheTest() !void { | 349 | fn doTheTest() !void { |
| ... | @@ -369,6 +371,7 @@ test "load vector elements via runtime index" { | ... | @@ -369,6 +371,7 @@ test "load vector elements via runtime index" { |
| 369 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 371 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 370 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 372 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 371 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 373 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 374 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 372 | 375 | ||
| 373 | const S = struct { | 376 | const S = struct { |
| 374 | fn doTheTest() !void { | 377 | fn doTheTest() !void { |
| ... | @@ -390,6 +393,7 @@ test "store vector elements via runtime index" { | ... | @@ -390,6 +393,7 @@ test "store vector elements via runtime index" { |
| 390 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 393 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 391 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 394 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 392 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | 395 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 396 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | ||
| 393 | 397 | ||
| 394 | const S = struct { | 398 | const S = struct { |
| 395 | fn doTheTest() !void { | 399 | fn doTheTest() !void { |
test/src/Cases.zig+6| ... | @@ -396,6 +396,12 @@ fn addFromDirInner( | ... | @@ -396,6 +396,12 @@ fn addFromDirInner( |
| 396 | // Other backends don't support new liveness format | 396 | // Other backends don't support new liveness format |
| 397 | continue; | 397 | continue; |
| 398 | } | 398 | } |
| 399 | if (backend == .stage2 and target.getOsTag() == .macos and | ||
| 400 | target.getCpuArch() == .x86_64 and builtin.cpu.arch == .aarch64) | ||
| 401 | { | ||
| 402 | // Rosetta has issues with ZLD | ||
| 403 | continue; | ||
| 404 | } | ||
| 399 | 405 | ||
| 400 | const next = ctx.cases.items.len; | 406 | const next = ctx.cases.items.len; |
| 401 | try ctx.cases.append(.{ | 407 | try ctx.cases.append(.{ |