| ... | ... | @@ -210,6 +210,8 @@ pub const MCValue = union(enum) { |
| 210 | 210 | register_offset: bits.RegisterOffset, |
| 211 | 211 | /// The value is a tuple { wrapped, overflow } where wrapped value is stored in the GP register. |
| 212 | 212 | register_overflow: struct { reg: Register, eflags: Condition }, |
| 213 | /// The value is a tuple { wrapped, overflow } where wrapped value is stored across two registers. |
| 214 | register_pair_overflow: struct { pair: [2]Register, eflags: Condition }, |
| 213 | 215 | /// The value is a bool vector stored in a vector register with a different scalar type. |
| 214 | 216 | register_mask: Mask, |
| 215 | 217 | /// The value is in memory at a hard-coded address. |
| ... | ... | @@ -265,6 +267,7 @@ pub const MCValue = union(enum) { |
| 265 | 267 | .register_mask, |
| 266 | 268 | .eflags, |
| 267 | 269 | .register_overflow, |
| 270 | .register_pair_overflow, |
| 268 | 271 | .indirect_load_frame, |
| 269 | 272 | .lea_frame, |
| 270 | 273 | .lea_nav, |
| ... | ... | @@ -363,6 +366,7 @@ pub const MCValue = union(enum) { |
| 363 | 366 | .indirect, |
| 364 | 367 | .indirect_mask, |
| 365 | 368 | => |*pl| (&pl.reg)[0..1], |
| 369 | .register_pair_overflow => |*rpo| &rpo.pair, |
| 366 | 370 | else => &.{}, |
| 367 | 371 | }; |
| 368 | 372 | } |
| ... | ... | @@ -371,6 +375,7 @@ pub const MCValue = union(enum) { |
| 371 | 375 | return switch (mcv) { |
| 372 | 376 | .eflags => |cc| cc, |
| 373 | 377 | .register_overflow => |reg_ov| reg_ov.eflags, |
| 378 | .register_pair_overflow => |rpo| rpo.eflags, |
| 374 | 379 | else => null, |
| 375 | 380 | }; |
| 376 | 381 | } |
| ... | ... | @@ -396,6 +401,7 @@ pub const MCValue = union(enum) { |
| 396 | 401 | .register_quadruple, |
| 397 | 402 | .register_offset, |
| 398 | 403 | .register_overflow, |
| 404 | .register_pair_overflow, |
| 399 | 405 | .register_mask, |
| 400 | 406 | .indirect_mask, |
| 401 | 407 | .lea_frame, |
| ... | ... | @@ -437,6 +443,7 @@ pub const MCValue = union(enum) { |
| 437 | 443 | .register_triple, |
| 438 | 444 | .register_quadruple, |
| 439 | 445 | .register_overflow, |
| 446 | .register_pair_overflow, |
| 440 | 447 | .register_mask, |
| 441 | 448 | .memory, |
| 442 | 449 | .indirect, |
| ... | ... | @@ -487,6 +494,7 @@ pub const MCValue = union(enum) { |
| 487 | 494 | .register_triple, |
| 488 | 495 | .register_quadruple, |
| 489 | 496 | .register_overflow, |
| 497 | .register_pair_overflow, |
| 490 | 498 | .register_mask, |
| 491 | 499 | .memory, |
| 492 | 500 | .indirect, |
| ... | ... | @@ -530,6 +538,7 @@ pub const MCValue = union(enum) { |
| 530 | 538 | .register_quadruple, |
| 531 | 539 | .register_offset, |
| 532 | 540 | .register_overflow, |
| 541 | .register_pair_overflow, |
| 533 | 542 | .register_mask, |
| 534 | 543 | .indirect_load_frame, |
| 535 | 544 | .lea_frame, |
| ... | ... | @@ -604,6 +613,11 @@ pub const MCValue = union(enum) { |
| 604 | 613 | @tagName(pl.eflags), |
| 605 | 614 | @tagName(pl.reg), |
| 606 | 615 | }), |
| 616 | .register_pair_overflow => |pl| try w.print("{t}:({t}:{t})", .{ |
| 617 | pl.eflags, |
| 618 | pl.pair[0], |
| 619 | pl.pair[1], |
| 620 | }), |
| 607 | 621 | .register_mask => |pl| try w.print("mask({s},{f}):{s}{s}", .{ |
| 608 | 622 | @tagName(pl.info.kind), |
| 609 | 623 | pl.info.scalar, |
| ... | ... | @@ -693,6 +707,7 @@ const InstTracking = struct { |
| 693 | 707 | .register_quadruple, |
| 694 | 708 | .register_offset, |
| 695 | 709 | .register_overflow, |
| 710 | .register_pair_overflow, |
| 696 | 711 | .register_mask, |
| 697 | 712 | .indirect, |
| 698 | 713 | .indirect_mask, |
| ... | ... | @@ -750,6 +765,10 @@ const InstTracking = struct { |
| 750 | 765 | function.register_manager.freeReg(reg_ov.reg); |
| 751 | 766 | function.eflags_inst = null; |
| 752 | 767 | }, |
| 768 | .register_pair_overflow => |rpo| { |
| 769 | for (rpo.pair) |r| function.register_manager.freeReg(r); |
| 770 | function.eflags_inst = null; |
| 771 | }, |
| 753 | 772 | .register_mask => |reg_mask| function.register_manager.freeReg(reg_mask.reg), |
| 754 | 773 | .eflags => function.eflags_inst = null, |
| 755 | 774 | else => {}, // TODO process stack allocation death |
| ... | ... | @@ -793,6 +812,7 @@ const InstTracking = struct { |
| 793 | 812 | .register_quadruple, |
| 794 | 813 | .register_offset, |
| 795 | 814 | .register_overflow, |
| 815 | .register_pair_overflow, |
| 796 | 816 | .register_mask, |
| 797 | 817 | .indirect, |
| 798 | 818 | .indirect_mask, |
| ... | ... | @@ -51941,7 +51961,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 51941 | 51961 | }), |
| 51942 | 51962 | else => |e| return e, |
| 51943 | 51963 | }; |
| 51944 | | try res[0].withOverflow(&res[1], cg); |
| 51964 | try res[0].withOverflow(&res[1], ty_pl.ty, cg); |
| 51945 | 51965 | try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg); |
| 51946 | 51966 | }, |
| 51947 | 51967 | .sub_with_overflow => |air_tag| { |
| ... | ... | @@ -52846,7 +52866,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 52846 | 52866 | }), |
| 52847 | 52867 | else => |e| return e, |
| 52848 | 52868 | }; |
| 52849 | | try res[0].withOverflow(&res[1], cg); |
| 52869 | try res[0].withOverflow(&res[1], ty_pl.ty, cg); |
| 52850 | 52870 | try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg); |
| 52851 | 52871 | }, |
| 52852 | 52872 | .mul_with_overflow => |air_tag| { |
| ... | ... | @@ -56443,7 +56463,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 56443 | 56463 | }), |
| 56444 | 56464 | else => |e| return e, |
| 56445 | 56465 | }; |
| 56446 | | try res[0].withOverflow(&res[1], cg); |
| 56466 | try res[0].withOverflow(&res[1], ty_pl.ty, cg); |
| 56447 | 56467 | try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg); |
| 56448 | 56468 | }, |
| 56449 | 56469 | .shl_with_overflow => |air_tag| { |
| ... | ... | @@ -59788,7 +59808,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 59788 | 59808 | }), |
| 59789 | 59809 | else => |e| return e, |
| 59790 | 59810 | }; |
| 59791 | | try res[0].withOverflow(&res[1], cg); |
| 59811 | try res[0].withOverflow(&res[1], ty_pl.ty, cg); |
| 59792 | 59812 | try res[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg); |
| 59793 | 59813 | }, |
| 59794 | 59814 | .alloc => { |
| ... | ... | @@ -103057,7 +103077,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 103057 | 103077 | const ty_pl = air_datas[@backingInt(inst)].ty_pl; |
| 103058 | 103078 | const bin_op = cg.air.extraData(Air.Bin, ty_pl.payload).data; |
| 103059 | 103079 | var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs }); |
| 103060 | | try ops[0].toPair(&ops[1], cg); |
| 103080 | try ops[0].toPair(&ops[1], ty_pl.ty, cg); |
| 103061 | 103081 | try ops[0].finish(inst, &.{ bin_op.lhs, bin_op.rhs }, &ops, cg); |
| 103062 | 103082 | }, |
| 103063 | 103083 | .slice_len => { |
| ... | ... | @@ -103474,7 +103494,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 103474 | 103494 | var len = try cg.tempInit(.usize, .{ |
| 103475 | 103495 | .immediate = cg.typeOf(ty_op.operand).childType(zcu).arrayLen(zcu), |
| 103476 | 103496 | }); |
| 103477 | | try ops[0].toPair(&len, cg); |
| 103497 | try ops[0].toPair(&len, ty_op.ty, cg); |
| 103478 | 103498 | try ops[0].finish(inst, &.{ty_op.operand}, &ops, cg); |
| 103479 | 103499 | }, |
| 103480 | 103500 | .int_from_float, .int_from_float_optimized => |air_tag| { |
| ... | ... | @@ -170236,7 +170256,113 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 170236 | 170256 | }; |
| 170237 | 170257 | for (ops) |op| try op.die(cg); |
| 170238 | 170258 | }, |
| 170239 | | .cmpxchg_weak, .cmpxchg_strong => try cg.airCmpxchg(inst), |
| 170259 | .cmpxchg_weak, .cmpxchg_strong => |air_tag| { |
| 170260 | const ty_pl = air_datas[@backingInt(inst)].ty_pl; |
| 170261 | const extra = cg.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 170262 | var ops = try cg.tempsFromOperands(inst, .{ extra.ptr, extra.expected_value, extra.new_value }); |
| 170263 | var res: [2]Temp = undefined; |
| 170264 | (if (ty_pl.ty.optionalReprIsPayload(zcu)) |
| 170265 | cg.select(res[0..1], &.{ty_pl.ty}, &ops, comptime &.{.{ |
| 170266 | .required_features = .{ .@"64bit", .cmov, null, null }, |
| 170267 | .src_constraints = .{ .any, .{ .size = .qword }, .{ .size = .qword } }, |
| 170268 | .patterns = &.{ |
| 170269 | .{ .src = .{ .to_gpr, .{ .to_reg = .rax }, .to_gpr } }, |
| 170270 | }, |
| 170271 | .extra_temps = .{ |
| 170272 | .{ .type = .usize, .kind = .{ .rc = .general_purpose } }, |
| 170273 | .unused, |
| 170274 | .unused, |
| 170275 | .unused, |
| 170276 | .unused, |
| 170277 | .unused, |
| 170278 | .unused, |
| 170279 | .unused, |
| 170280 | .unused, |
| 170281 | .unused, |
| 170282 | .unused, |
| 170283 | }, |
| 170284 | .dst_temps = .{ .{ .ref = .src1 }, .unused }, |
| 170285 | .clobbers = .{ .eflags = true }, |
| 170286 | .each = .{ .once = &.{ |
| 170287 | .{ ._, ._, .xor, .tmp0d, .tmp0d, ._, ._ }, |
| 170288 | .{ ._, .@"lock _", .cmpxchg, .lea(.src0q), .src2q, ._, ._ }, |
| 170289 | .{ ._, ._e, .cmov, .dst0q, .tmp0q, ._, ._ }, |
| 170290 | } }, |
| 170291 | }}) |
| 170292 | else |
| 170293 | cg.select(&res, &.{ ty_pl.ty.childType(zcu), .u1 }, &ops, comptime &.{ .{ |
| 170294 | .required_features = .{ .@"64bit", null, null, null }, |
| 170295 | .src_constraints = .{ .any, .{ .int = .byte }, .{ .int = .byte } }, |
| 170296 | .patterns = &.{ |
| 170297 | .{ .src = .{ .to_gpr, .{ .to_reg = .rax }, .to_gpr } }, |
| 170298 | }, |
| 170299 | .dst_temps = .{ .{ .ref = .src1 }, .{ .cc = .ne } }, |
| 170300 | .clobbers = .{ .eflags = true }, |
| 170301 | .each = .{ .once = &.{ |
| 170302 | .{ ._, .@"lock _", .cmpxchg, .lea(.src0b), .src2b, ._, ._ }, |
| 170303 | } }, |
| 170304 | }, .{ |
| 170305 | .required_features = .{ .@"64bit", null, null, null }, |
| 170306 | .src_constraints = .{ .any, .{ .int = .word }, .{ .int = .word } }, |
| 170307 | .patterns = &.{ |
| 170308 | .{ .src = .{ .to_gpr, .{ .to_reg = .rax }, .to_gpr } }, |
| 170309 | }, |
| 170310 | .dst_temps = .{ .{ .ref = .src1 }, .{ .cc = .ne } }, |
| 170311 | .clobbers = .{ .eflags = true }, |
| 170312 | .each = .{ .once = &.{ |
| 170313 | .{ ._, .@"lock _", .cmpxchg, .lea(.src0w), .src2w, ._, ._ }, |
| 170314 | } }, |
| 170315 | }, .{ |
| 170316 | .required_features = .{ .@"64bit", null, null, null }, |
| 170317 | .src_constraints = .{ .any, .{ .int = .dword }, .{ .int = .dword } }, |
| 170318 | .patterns = &.{ |
| 170319 | .{ .src = .{ .to_gpr, .{ .to_reg = .rax }, .to_gpr } }, |
| 170320 | }, |
| 170321 | .dst_temps = .{ .{ .ref = .src1 }, .{ .cc = .ne } }, |
| 170322 | .clobbers = .{ .eflags = true }, |
| 170323 | .each = .{ .once = &.{ |
| 170324 | .{ ._, .@"lock _", .cmpxchg, .lea(.src0d), .src2d, ._, ._ }, |
| 170325 | } }, |
| 170326 | }, .{ |
| 170327 | .required_features = .{ .@"64bit", null, null, null }, |
| 170328 | .src_constraints = .{ .any, .{ .int = .qword }, .{ .int = .qword } }, |
| 170329 | .patterns = &.{ |
| 170330 | .{ .src = .{ .to_gpr, .{ .to_reg = .rax }, .to_gpr } }, |
| 170331 | }, |
| 170332 | .dst_temps = .{ .{ .ref = .src1 }, .{ .cc = .ne } }, |
| 170333 | .clobbers = .{ .eflags = true }, |
| 170334 | .each = .{ .once = &.{ |
| 170335 | .{ ._, .@"lock _", .cmpxchg, .lea(.src0q), .src2q, ._, ._ }, |
| 170336 | } }, |
| 170337 | }, .{ |
| 170338 | .required_features = .{ .@"64bit", .cx16, null, null }, |
| 170339 | .src_constraints = .{ .any, .{ .int = .xword }, .{ .int = .xword } }, |
| 170340 | .patterns = &.{.{ |
| 170341 | .src = .{ |
| 170342 | .to_gpr, |
| 170343 | .{ .to_reg_pair = .{ .rax, .rdx } }, |
| 170344 | .{ .to_reg_pair = .{ .rbx, .rcx } }, |
| 170345 | }, |
| 170346 | }}, |
| 170347 | .dst_temps = .{ .{ .ref = .src1 }, .{ .cc = .ne } }, |
| 170348 | .clobbers = .{ .eflags = true }, |
| 170349 | .each = .{ .once = &.{ |
| 170350 | .{ ._, .@"lock _16b", .cmpxchg, .lea(.src0x), ._, ._, ._ }, |
| 170351 | } }, |
| 170352 | } })) catch |err| switch (err) { |
| 170353 | error.SelectFailed => return cg.fail("failed to select {s} {f} {f} {f} {f}", .{ |
| 170354 | @tagName(air_tag), |
| 170355 | ty_pl.ty.fmt(zcu), |
| 170356 | ops[0].tracking(cg), |
| 170357 | ops[1].tracking(cg), |
| 170358 | ops[2].tracking(cg), |
| 170359 | }), |
| 170360 | else => |e| return e, |
| 170361 | }; |
| 170362 | if (!ty_pl.ty.optionalReprIsPayload(zcu)) |
| 170363 | try res[0].withOverflow(&res[1], ty_pl.ty, cg); |
| 170364 | try res[0].finish(inst, &.{ extra.ptr, extra.expected_value, extra.new_value }, &ops, cg); |
| 170365 | }, |
| 170240 | 170366 | .atomic_load => try cg.airAtomicLoad(inst), |
| 170241 | 170367 | .atomic_store_unordered => try cg.airAtomicStore(inst, .unordered), |
| 170242 | 170368 | .atomic_store_monotonic => try cg.airAtomicStore(inst, .monotonic), |
| ... | ... | @@ -170578,7 +170704,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 170578 | 170704 | }), |
| 170579 | 170705 | else => |e| return e, |
| 170580 | 170706 | }; |
| 170581 | | if (res[0].tracking(cg).short != .register_pair) try ops[0].toPair(&res[0], cg); |
| 170707 | if (res[0].tracking(cg).short != .register_pair) try ops[0].toPair(&res[0], .slice_const_u8_sentinel_0, cg); |
| 170582 | 170708 | try res[0].finish(inst, &.{un_op}, &ops, cg); |
| 170583 | 170709 | }, |
| 170584 | 170710 | .error_name => |air_tag| { |
| ... | ... | @@ -170681,7 +170807,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void { |
| 170681 | 170807 | else => |e| return e, |
| 170682 | 170808 | }; |
| 170683 | 170809 | const orig_res = res; |
| 170684 | | try res[0].toPair(&res[1], cg); |
| 170810 | try res[0].toPair(&res[1], .slice_const_u8_sentinel_0, cg); |
| 170685 | 170811 | for (&ops) |*op| for (orig_res) |orig_r| { |
| 170686 | 170812 | if (op.index != orig_r.index) continue; |
| 170687 | 170813 | op.* = res[0]; |
| ... | ... | @@ -173190,7 +173316,10 @@ fn getValue(self: *CodeGen, value: MCValue, inst: ?Air.Inst.Index) !void { |
| 173190 | 173316 | for (value.getRegs()) |reg| try self.register_manager.getReg(reg, inst); |
| 173191 | 173317 | switch (value) { |
| 173192 | 173318 | else => {}, |
| 173193 | | .eflags, .register_overflow => self.eflags_inst = inst, |
| 173319 | .eflags, |
| 173320 | .register_overflow, |
| 173321 | .register_pair_overflow, |
| 173322 | => self.eflags_inst = inst, |
| 173194 | 173323 | } |
| 173195 | 173324 | } |
| 173196 | 173325 | |
| ... | ... | @@ -173218,6 +173347,10 @@ fn freeValue(self: *CodeGen, value: MCValue, comptime opts: FreeOptions) !void { |
| 173218 | 173347 | try self.freeReg(reg_ov.reg, opts); |
| 173219 | 173348 | self.eflags_inst = null; |
| 173220 | 173349 | }, |
| 173350 | .register_pair_overflow => |rpo| { |
| 173351 | for (rpo.pair) |r| try self.freeReg(r, opts); |
| 173352 | self.eflags_inst = null; |
| 173353 | }, |
| 173221 | 173354 | .register_mask => |reg_mask| try self.freeReg(reg_mask.reg, opts), |
| 173222 | 173355 | .eflags => self.eflags_inst = null, |
| 173223 | 173356 | else => {}, // TODO process stack allocation death |
| ... | ... | @@ -173760,7 +173893,12 @@ fn reuseOperandAdvanced( |
| 173760 | 173893 | return false; |
| 173761 | 173894 | |
| 173762 | 173895 | switch (mcv) { |
| 173763 | | .register, .register_pair, .register_overflow, .register_mask => for (mcv.getRegs()) |reg| { |
| 173896 | .register, |
| 173897 | .register_pair, |
| 173898 | .register_overflow, |
| 173899 | .register_pair_overflow, |
| 173900 | .register_mask, |
| 173901 | => for (mcv.getRegs()) |reg| { |
| 173764 | 173902 | // If it's in the registers table, need to associate the register(s) with the |
| 173765 | 173903 | // new instruction. |
| 173766 | 173904 | if (maybe_tracked_inst) |tracked_inst| { |
| ... | ... | @@ -173775,7 +173913,10 @@ fn reuseOperandAdvanced( |
| 173775 | 173913 | else => return false, |
| 173776 | 173914 | } |
| 173777 | 173915 | switch (mcv) { |
| 173778 | | .eflags, .register_overflow => self.eflags_inst = maybe_tracked_inst, |
| 173916 | .eflags, |
| 173917 | .register_overflow, |
| 173918 | .register_pair_overflow, |
| 173919 | => self.eflags_inst = maybe_tracked_inst, |
| 173779 | 173920 | else => {}, |
| 173780 | 173921 | } |
| 173781 | 173922 | |
| ... | ... | @@ -173802,6 +173943,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE |
| 173802 | 173943 | .register_triple, |
| 173803 | 173944 | .register_quadruple, |
| 173804 | 173945 | .register_overflow, |
| 173946 | .register_pair_overflow, |
| 173805 | 173947 | .register_mask, |
| 173806 | 173948 | .indirect_load_frame, |
| 173807 | 173949 | .indirect_mask, |
| ... | ... | @@ -173861,6 +174003,7 @@ fn store( |
| 173861 | 174003 | .register_triple, |
| 173862 | 174004 | .register_quadruple, |
| 173863 | 174005 | .register_overflow, |
| 174006 | .register_pair_overflow, |
| 173864 | 174007 | .register_mask, |
| 173865 | 174008 | .indirect_load_frame, |
| 173866 | 174009 | .indirect_mask, |
| ... | ... | @@ -173912,6 +174055,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv: |
| 173912 | 174055 | .register_offset, |
| 173913 | 174056 | .eflags, |
| 173914 | 174057 | .register_overflow, |
| 174058 | .register_pair_overflow, |
| 173915 | 174059 | .register_mask, |
| 173916 | 174060 | .indirect_load_frame, |
| 173917 | 174061 | .indirect_mask, |
| ... | ... | @@ -174608,6 +174752,7 @@ fn genBinOpMir( |
| 174608 | 174752 | .immediate, |
| 174609 | 174753 | .eflags, |
| 174610 | 174754 | .register_overflow, |
| 174755 | .register_pair_overflow, |
| 174611 | 174756 | .register_mask, |
| 174612 | 174757 | .lea_frame, |
| 174613 | 174758 | .lea_nav, |
| ... | ... | @@ -174656,6 +174801,7 @@ fn genBinOpMir( |
| 174656 | 174801 | .dead, |
| 174657 | 174802 | .undef, |
| 174658 | 174803 | .register_overflow, |
| 174804 | .register_pair_overflow, |
| 174659 | 174805 | .register_mask, |
| 174660 | 174806 | .indirect_load_frame, |
| 174661 | 174807 | .indirect_mask, |
| ... | ... | @@ -174834,6 +174980,7 @@ fn genBinOpMir( |
| 174834 | 174980 | .dead, |
| 174835 | 174981 | .undef, |
| 174836 | 174982 | .register_overflow, |
| 174983 | .register_pair_overflow, |
| 174837 | 174984 | .register_mask, |
| 174838 | 174985 | .indirect_load_frame, |
| 174839 | 174986 | .indirect_mask, |
| ... | ... | @@ -174944,6 +175091,7 @@ fn genBinOpMir( |
| 174944 | 175091 | .dead, |
| 174945 | 175092 | .undef, |
| 174946 | 175093 | .register_overflow, |
| 175094 | .register_pair_overflow, |
| 174947 | 175095 | .register_mask, |
| 174948 | 175096 | .indirect_load_frame, |
| 174949 | 175097 | .indirect_mask, |
| ... | ... | @@ -178053,6 +178201,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C |
| 178053 | 178201 | .immediate, |
| 178054 | 178202 | .eflags, |
| 178055 | 178203 | .register_overflow, |
| 178204 | .register_pair_overflow, |
| 178056 | 178205 | .register_mask, |
| 178057 | 178206 | .indirect_load_frame, |
| 178058 | 178207 | .indirect_mask, |
| ... | ... | @@ -178077,6 +178226,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C |
| 178077 | 178226 | .dead, |
| 178078 | 178227 | .undef, |
| 178079 | 178228 | .register_overflow, |
| 178229 | .register_pair_overflow, |
| 178080 | 178230 | .register_tee, |
| 178081 | 178231 | .elementwise_gpr, |
| 178082 | 178232 | .elementwise_sse, |
| ... | ... | @@ -178280,6 +178430,7 @@ fn genSetReg( |
| 178280 | 178430 | .ywordwise_sse, |
| 178281 | 178431 | .zwordwise_sse, |
| 178282 | 178432 | .reserved_frame, |
| 178433 | .register_pair_overflow, |
| 178283 | 178434 | => unreachable, |
| 178284 | 178435 | .undef => if (opts.safety) switch (dst_reg.class()) { |
| 178285 | 178436 | .general_purpose, .gphi => switch (abi_size) { |
| ... | ... | @@ -179083,6 +179234,23 @@ fn genSetMem( |
| 179083 | 179234 | @tagName(src_mcv), ty.fmt(zcu), |
| 179084 | 179235 | }), |
| 179085 | 179236 | }, |
| 179237 | .register_pair_overflow => |rpo| switch (ty.zigTypeTag(zcu)) { |
| 179238 | .optional => { |
| 179239 | assert(!ty.optionalReprIsPayload(zcu)); |
| 179240 | const child_ty = ty.optionalChild(zcu); |
| 179241 | try cg.genSetMem(base, disp, child_ty, .{ .register_pair = rpo.pair }, opts); |
| 179242 | try cg.genSetMem( |
| 179243 | base, |
| 179244 | disp + @as(i32, @intCast(child_ty.abiSize(zcu))), |
| 179245 | .bool, |
| 179246 | .{ .eflags = rpo.eflags }, |
| 179247 | opts, |
| 179248 | ); |
| 179249 | }, |
| 179250 | else => return cg.fail("TODO implement genSetMem for {s} of {f}", .{ |
| 179251 | @tagName(src_mcv), ty.fmt(zcu), |
| 179252 | }), |
| 179253 | }, |
| 179086 | 179254 | .register_offset => |reg_off| { |
| 179087 | 179255 | const src_reg = cg.copyToTmpRegister(ty, src_mcv) catch |err| switch (err) { |
| 179088 | 179256 | error.OutOfRegisters => { |
| ... | ... | @@ -179417,111 +179585,6 @@ fn airBitCast(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 179417 | 179585 | return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 179418 | 179586 | } |
| 179419 | 179587 | |
| 179420 | | fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void { |
| 179421 | | const pt = self.pt; |
| 179422 | | const zcu = pt.zcu; |
| 179423 | | const ty_pl = self.air.instructions.items(.data)[@backingInt(inst)].ty_pl; |
| 179424 | | const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data; |
| 179425 | | |
| 179426 | | const dst_ty = self.typeOfIndex(inst); |
| 179427 | | const ptr_ty = self.typeOf(extra.ptr); |
| 179428 | | const val_ty = self.typeOf(extra.expected_value); |
| 179429 | | const val_abi_size: u32 = @intCast(val_ty.abiSize(zcu)); |
| 179430 | | |
| 179431 | | try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx }); |
| 179432 | | const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx }); |
| 179433 | | defer for (regs_lock) |lock| self.register_manager.unlockReg(lock); |
| 179434 | | |
| 179435 | | const exp_mcv = try self.resolveInst(extra.expected_value); |
| 179436 | | if (val_abi_size > 8) { |
| 179437 | | const exp_addr_mcv: MCValue = switch (exp_mcv) { |
| 179438 | | .memory, .indirect, .load_frame => exp_mcv.address(), |
| 179439 | | else => .{ .register = try self.copyToTmpRegister(.usize, exp_mcv.address()) }, |
| 179440 | | }; |
| 179441 | | const exp_addr_lock = |
| 179442 | | if (exp_addr_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 179443 | | defer if (exp_addr_lock) |lock| self.register_manager.unlockReg(lock); |
| 179444 | | |
| 179445 | | try self.genSetReg(.rax, .usize, exp_addr_mcv.deref(), .{}); |
| 179446 | | try self.genSetReg(.rdx, .usize, exp_addr_mcv.offset(8).deref(), .{}); |
| 179447 | | } else try self.genSetReg(.rax, val_ty, exp_mcv, .{}); |
| 179448 | | |
| 179449 | | const new_mcv = try self.resolveInst(extra.new_value); |
| 179450 | | const new_reg = if (val_abi_size > 8) new: { |
| 179451 | | const new_addr_mcv: MCValue = switch (new_mcv) { |
| 179452 | | .memory, .indirect, .load_frame => new_mcv.address(), |
| 179453 | | else => .{ .register = try self.copyToTmpRegister(.usize, new_mcv.address()) }, |
| 179454 | | }; |
| 179455 | | const new_addr_lock = |
| 179456 | | if (new_addr_mcv.getReg()) |reg| self.register_manager.lockReg(reg) else null; |
| 179457 | | defer if (new_addr_lock) |lock| self.register_manager.unlockReg(lock); |
| 179458 | | |
| 179459 | | try self.genSetReg(.rbx, .usize, new_addr_mcv.deref(), .{}); |
| 179460 | | try self.genSetReg(.rcx, .usize, new_addr_mcv.offset(8).deref(), .{}); |
| 179461 | | break :new null; |
| 179462 | | } else try self.copyToTmpRegister(val_ty, new_mcv); |
| 179463 | | const new_lock = if (new_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; |
| 179464 | | defer if (new_lock) |lock| self.register_manager.unlockReg(lock); |
| 179465 | | |
| 179466 | | const ptr_mcv = try self.resolveInst(extra.ptr); |
| 179467 | | const mem_size: Memory.Size = .fromSize(val_abi_size); |
| 179468 | | const ptr_mem: Memory = switch (ptr_mcv) { |
| 179469 | | .immediate, .register, .register_offset, .lea_frame => try ptr_mcv.deref().mem(self, .{ .size = mem_size }), |
| 179470 | | else => .{ |
| 179471 | | .base = .{ .reg = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }, |
| 179472 | | .mod = .{ .rm = .{ .size = mem_size } }, |
| 179473 | | }, |
| 179474 | | }; |
| 179475 | | switch (ptr_mem.mod) { |
| 179476 | | .rm => {}, |
| 179477 | | .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), |
| 179478 | | } |
| 179479 | | const ptr_lock = switch (ptr_mem.base) { |
| 179480 | | .none, .frame, .nav, .uav => null, |
| 179481 | | .reg => |reg| self.register_manager.lockReg(reg), |
| 179482 | | .table, .rip_inst, .lazy_sym, .extern_func => unreachable, |
| 179483 | | }; |
| 179484 | | defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock); |
| 179485 | | |
| 179486 | | try self.spillEflagsIfOccupied(); |
| 179487 | | const null_reg = if (dst_ty.optionalReprIsPayload(zcu) and !self.liveness.isUnused(inst)) null_reg: { |
| 179488 | | const null_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp); |
| 179489 | | try self.asmRegisterRegister(.{ ._, .xor }, null_reg.to32(), null_reg.to32()); |
| 179490 | | break :null_reg null_reg; |
| 179491 | | } else null; |
| 179492 | | const null_lock = if (null_reg) |reg| self.register_manager.lockRegAssumeUnused(reg) else null; |
| 179493 | | defer if (null_lock) |lock| self.register_manager.unlockReg(lock); |
| 179494 | | |
| 179495 | | if (val_abi_size <= 8) try self.asmMemoryRegister( |
| 179496 | | .{ .@"lock _", .cmpxchg }, |
| 179497 | | ptr_mem, |
| 179498 | | registerAlias(new_reg.?, val_abi_size), |
| 179499 | | ) else try self.asmMemory(.{ .@"lock _16b", .cmpxchg }, ptr_mem); |
| 179500 | | |
| 179501 | | const result: MCValue = result: { |
| 179502 | | if (self.liveness.isUnused(inst)) break :result .unreach; |
| 179503 | | |
| 179504 | | if (null_reg) |reg| try self.asmCmovccRegisterRegister( |
| 179505 | | .e, |
| 179506 | | registerAlias(.rax, val_abi_size), |
| 179507 | | registerAlias(reg, val_abi_size), |
| 179508 | | ); |
| 179509 | | |
| 179510 | | if (val_abi_size <= 8) { |
| 179511 | | if (null_reg) |_| break :result .{ .register = .rax }; |
| 179512 | | self.eflags_inst = inst; |
| 179513 | | break :result .{ .register_overflow = .{ .reg = .rax, .eflags = .ne } }; |
| 179514 | | } |
| 179515 | | |
| 179516 | | const dst_mcv = try self.allocRegOrMem(inst, false); |
| 179517 | | try self.genCopy(.usize, dst_mcv, .{ .register = .rax }, .{}); |
| 179518 | | try self.genCopy(.usize, dst_mcv.address().offset(8).deref(), .{ .register = .rdx }, .{}); |
| 179519 | | if (null_reg == null) try self.genCopy(.bool, dst_mcv.address().offset(16).deref(), .{ .eflags = .ne }, .{}); |
| 179520 | | break :result dst_mcv; |
| 179521 | | }; |
| 179522 | | return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value }); |
| 179523 | | } |
| 179524 | | |
| 179525 | 179588 | fn atomicOp( |
| 179526 | 179589 | self: *CodeGen, |
| 179527 | 179590 | ptr_mcv: MCValue, |
| ... | ... | @@ -179557,7 +179620,7 @@ fn atomicOp( |
| 179557 | 179620 | }; |
| 179558 | 179621 | switch (ptr_mem.mod) { |
| 179559 | 179622 | .rm => {}, |
| 179560 | | .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}), |
| 179623 | .off => return self.fail("TODO atomicOp with {s}", .{@tagName(ptr_mcv)}), |
| 179561 | 179624 | } |
| 179562 | 179625 | const mem_lock = switch (ptr_mem.base) { |
| 179563 | 179626 | .none, .frame, .nav, .uav => null, |
| ... | ... | @@ -181936,6 +181999,7 @@ const Temp = struct { |
| 181936 | 181999 | .register_triple, |
| 181937 | 182000 | .register_quadruple, |
| 181938 | 182001 | .register_overflow, |
| 182002 | .register_pair_overflow, |
| 181939 | 182003 | => true, |
| 181940 | 182004 | .load_frame => |frame_addr| !frame_addr.index.isNamed(), |
| 181941 | 182005 | }, |
| ... | ... | @@ -182316,7 +182380,7 @@ const Temp = struct { |
| 182316 | 182380 | return true; |
| 182317 | 182381 | } |
| 182318 | 182382 | |
| 182319 | | fn toPair(first_temp: *Temp, second_temp: *Temp, cg: *CodeGen) InnerError!void { |
| 182383 | fn toPair(first_temp: *Temp, second_temp: *Temp, result_ty: Type, cg: *CodeGen) InnerError!void { |
| 182320 | 182384 | while (true) for ([_]*Temp{ first_temp, second_temp }) |part_temp| { |
| 182321 | 182385 | if (try part_temp.toRegClass(true, .general_purpose, cg)) break; |
| 182322 | 182386 | } else break; |
| ... | ... | @@ -182331,13 +182395,13 @@ const Temp = struct { |
| 182331 | 182395 | assert(cg.reuseTemp(result_temp.index, first_temp.index, first_temp_tracking)); |
| 182332 | 182396 | assert(cg.reuseTemp(result_temp.index, second_temp.index, second_temp_tracking)); |
| 182333 | 182397 | result_temp_index.tracking(cg).* = .init(result); |
| 182334 | | cg.temp_type[@backingInt(result_temp_index)] = .slice_const_u8; |
| 182398 | cg.temp_type[@backingInt(result_temp_index)] = result_ty; |
| 182335 | 182399 | cg.next_temp_index = @fromBackingInt(@intCast(@backingInt(result_temp_index) + 1)); |
| 182336 | 182400 | first_temp.* = result_temp; |
| 182337 | 182401 | second_temp.* = result_temp; |
| 182338 | 182402 | } |
| 182339 | 182403 | |
| 182340 | | fn withOverflow(temp: *Temp, overflow_temp: *Temp, cg: *CodeGen) InnerError!void { |
| 182404 | fn withOverflow(temp: *Temp, overflow_temp: *Temp, result_ty: Type, cg: *CodeGen) InnerError!void { |
| 182341 | 182405 | const temp_index = temp.unwrap(cg).temp; |
| 182342 | 182406 | const temp_tracking = temp_index.tracking(cg); |
| 182343 | 182407 | const overflow_temp_tracking = overflow_temp.unwrap(cg).temp.tracking(cg); |
| ... | ... | @@ -182349,7 +182413,7 @@ const Temp = struct { |
| 182349 | 182413 | assert(cg.reuseTemp(result_temp.index, temp.index, temp_tracking)); |
| 182350 | 182414 | assert(cg.reuseTemp(result_temp.index, overflow_temp.index, overflow_temp_tracking)); |
| 182351 | 182415 | result_temp_index.tracking(cg).* = .init(.{ .register_overflow = .{ .reg = reg, .eflags = overflow_cc } }); |
| 182352 | | cg.temp_type[@backingInt(result_temp_index)] = .slice_const_u8; |
| 182416 | cg.temp_type[@backingInt(result_temp_index)] = result_ty; |
| 182353 | 182417 | cg.next_temp_index = @fromBackingInt(@intCast(@backingInt(result_temp_index) + 1)); |
| 182354 | 182418 | temp.* = result_temp; |
| 182355 | 182419 | overflow_temp.* = result_temp; |
| ... | ... | @@ -182361,7 +182425,22 @@ const Temp = struct { |
| 182361 | 182425 | assert(cg.reuseTemp(result_temp.index, temp.index, temp_tracking)); |
| 182362 | 182426 | assert(cg.reuseTemp(result_temp.index, overflow_temp.index, overflow_temp_tracking)); |
| 182363 | 182427 | result_temp_index.tracking(cg).* = .init(.{ .register_pair = .{ reg, overflow_reg } }); |
| 182364 | | cg.temp_type[@backingInt(result_temp_index)] = .slice_const_u8; |
| 182428 | cg.temp_type[@backingInt(result_temp_index)] = result_ty; |
| 182429 | cg.next_temp_index = @fromBackingInt(@intCast(@backingInt(result_temp_index) + 1)); |
| 182430 | temp.* = result_temp; |
| 182431 | overflow_temp.* = result_temp; |
| 182432 | return; |
| 182433 | }, |
| 182434 | else => {}, |
| 182435 | }, |
| 182436 | .register_pair => |pair| switch (overflow_temp_tracking.short) { |
| 182437 | .eflags => |overflow_cc| { |
| 182438 | const result_temp_index = cg.next_temp_index; |
| 182439 | const result_temp: Temp = .{ .index = result_temp_index.toIndex() }; |
| 182440 | assert(cg.reuseTemp(result_temp.index, temp.index, temp_tracking)); |
| 182441 | assert(cg.reuseTemp(result_temp.index, overflow_temp.index, overflow_temp_tracking)); |
| 182442 | result_temp_index.tracking(cg).* = .init(.{ .register_pair_overflow = .{ .pair = pair, .eflags = overflow_cc } }); |
| 182443 | cg.temp_type[@backingInt(result_temp_index)] = result_ty; |
| 182365 | 182444 | cg.next_temp_index = @fromBackingInt(@intCast(@backingInt(result_temp_index) + 1)); |
| 182366 | 182445 | temp.* = result_temp; |
| 182367 | 182446 | overflow_temp.* = result_temp; |
| ... | ... | @@ -182401,6 +182480,7 @@ const Temp = struct { |
| 182401 | 182480 | .register_triple, |
| 182402 | 182481 | .register_quadruple, |
| 182403 | 182482 | .register_overflow, |
| 182483 | .register_pair_overflow, |
| 182404 | 182484 | .register_mask, |
| 182405 | 182485 | .indirect_load_frame, |
| 182406 | 182486 | .indirect_mask, |
| ... | ... | @@ -188883,6 +188963,7 @@ const Temp = struct { |
| 188883 | 188963 | .register_quadruple, |
| 188884 | 188964 | .register_offset, |
| 188885 | 188965 | .register_overflow, |
| 188966 | .register_pair_overflow, |
| 188886 | 188967 | .register_mask, |
| 188887 | 188968 | .memory, |
| 188888 | 188969 | .indirect, |
| ... | ... | @@ -189001,6 +189082,7 @@ fn reuseTemp( |
| 189001 | 189082 | .register_pair, |
| 189002 | 189083 | .register_offset, |
| 189003 | 189084 | .register_overflow, |
| 189085 | .register_pair_overflow, |
| 189004 | 189086 | .register_mask, |
| 189005 | 189087 | .indirect, |
| 189006 | 189088 | => for (tracking.short.getRegs()) |tracked_reg| { |
| ... | ... | @@ -189012,7 +189094,10 @@ fn reuseTemp( |
| 189012 | 189094 | else => {}, |
| 189013 | 189095 | } |
| 189014 | 189096 | switch (tracking.short) { |
| 189015 | | .eflags, .register_overflow => cg.eflags_inst = new_inst, |
| 189097 | .eflags, |
| 189098 | .register_overflow, |
| 189099 | .register_pair_overflow, |
| 189100 | => cg.eflags_inst = new_inst, |
| 189016 | 189101 | else => {}, |
| 189017 | 189102 | } |
| 189018 | 189103 | tracking.reuse(cg, new_inst, old_inst); |
| ... | ... | @@ -191592,7 +191677,13 @@ const Select = struct { |
| 191592 | 191677 | } }, |
| 191593 | 191678 | .eflags => unreachable, |
| 191594 | 191679 | .register => |reg| .{ .reg = s.lowerReg(reg.toSize(op.flags.base.size, s.cg.target)) }, |
| 191595 | | .register_pair, .register_triple, .register_quadruple, .register_offset, .register_overflow => unreachable, |
| 191680 | .register_pair, |
| 191681 | .register_triple, |
| 191682 | .register_quadruple, |
| 191683 | .register_offset, |
| 191684 | .register_overflow, |
| 191685 | .register_pair_overflow, |
| 191686 | => unreachable, |
| 191596 | 191687 | .register_mask => |reg_mask| .{ .reg = s.lowerReg(reg_mask.reg.toSize(op.flags.base.size, s.cg.target)) }, |
| 191597 | 191688 | .lea_nav => |nav| .{ .imm = .{ .nav = .{ .index = nav } } }, |
| 191598 | 191689 | .lea_uav => |uav| .{ .imm = .{ .uav = uav } }, |