authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-26 17:31:42+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-03-26 17:31:42+02:00
log32591c1d99297b370e34674dc135705c3849968d
treed8fde435747702cd2d2a765b3ca29f3c351c6490
parent4a5628e7306a242ce0d2f14f09eaf17ad4ae87b2
parent65f77878b4d37a2e179c90f5f0b2515d0901a43e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #15076 from jacobly0/x86_64-backend

x86_64: implement things

44 files changed, 1217 insertions(+), 660 deletions(-)

lib/std/io.zig+6-6
...@@ -29,8 +29,8 @@ pub const default_mode: ModeOverride = if (is_async) Mode.evented else .blocking...@@ -29,8 +29,8 @@ pub const default_mode: ModeOverride = if (is_async) Mode.evented else .blocking
2929
30fn getStdOutHandle() os.fd_t {30fn getStdOutHandle() os.fd_t {
31 if (builtin.os.tag == .windows) {31 if (builtin.os.tag == .windows) {
32 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) {32 if (builtin.zig_backend == .stage2_aarch64) {
33 // TODO: this is just a temporary workaround until we advance x86 backend further along.33 // TODO: this is just a temporary workaround until we advance aarch64 backend further along.
34 return os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;34 return os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
35 }35 }
36 return os.windows.peb().ProcessParameters.hStdOutput;36 return os.windows.peb().ProcessParameters.hStdOutput;
...@@ -55,8 +55,8 @@ pub fn getStdOut() File {...@@ -55,8 +55,8 @@ pub fn getStdOut() File {
5555
56fn getStdErrHandle() os.fd_t {56fn getStdErrHandle() os.fd_t {
57 if (builtin.os.tag == .windows) {57 if (builtin.os.tag == .windows) {
58 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) {58 if (builtin.zig_backend == .stage2_aarch64) {
59 // TODO: this is just a temporary workaround until we advance x86 backend further along.59 // TODO: this is just a temporary workaround until we advance aarch64 backend further along.
60 return os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;60 return os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
61 }61 }
62 return os.windows.peb().ProcessParameters.hStdError;62 return os.windows.peb().ProcessParameters.hStdError;
...@@ -81,8 +81,8 @@ pub fn getStdErr() File {...@@ -81,8 +81,8 @@ pub fn getStdErr() File {
8181
82fn getStdInHandle() os.fd_t {82fn getStdInHandle() os.fd_t {
83 if (builtin.os.tag == .windows) {83 if (builtin.os.tag == .windows) {
84 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) {84 if (builtin.zig_backend == .stage2_aarch64) {
85 // TODO: this is just a temporary workaround until we advance x86 backend further along.85 // TODO: this is just a temporary workaround until we advance aarch64 backend further along.
86 return os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;86 return os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
87 }87 }
88 return os.windows.peb().ProcessParameters.hStdInput;88 return os.windows.peb().ProcessParameters.hStdInput;
src/arch/x86_64/CodeGen.zig+1039-498
...@@ -409,10 +409,7 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {...@@ -409,10 +409,7 @@ fn asmSetccRegister(self: *Self, reg: Register, cc: bits.Condition) !void {
409 _ = try self.addInst(.{409 _ = try self.addInst(.{
410 .tag = .setcc,410 .tag = .setcc,
411 .ops = .r_cc,411 .ops = .r_cc,
412 .data = .{ .r_cc = .{412 .data = .{ .r_cc = .{ .r = reg, .cc = cc } },
413 .r1 = reg,
414 .cc = cc,
415 } },
416 });413 });
417}414}
418415
...@@ -424,14 +421,11 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {...@@ -424,14 +421,11 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
424 .rip => .m_rip_cc,421 .rip => .m_rip_cc,
425 else => unreachable,422 else => unreachable,
426 },423 },
427 .data = .{ .x_cc = .{424 .data = .{ .x_cc = .{ .cc = cc, .payload = switch (m) {
428 .payload = switch (m) {425 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
429 .sib => try self.addExtra(Mir.MemorySib.encode(m)),426 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
430 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),427 else => unreachable,
431 else => unreachable,428 } } },
432 },
433 .cc = cc,
434 } },
435 });429 });
436}430}
437431
...@@ -439,11 +433,7 @@ fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bi...@@ -439,11 +433,7 @@ fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bi
439 _ = try self.addInst(.{433 _ = try self.addInst(.{
440 .tag = .cmovcc,434 .tag = .cmovcc,
441 .ops = .rr_cc,435 .ops = .rr_cc,
442 .data = .{ .rr_cc = .{436 .data = .{ .rr_cc = .{ .r1 = reg1, .r2 = reg2, .cc = cc } },
443 .r1 = reg1,
444 .r2 = reg2,
445 .cc = cc,
446 } },
447 });437 });
448}438}
449439
...@@ -455,15 +445,11 @@ fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condi...@@ -455,15 +445,11 @@ fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condi
455 .rip => .rm_rip_cc,445 .rip => .rm_rip_cc,
456 else => unreachable,446 else => unreachable,
457 },447 },
458 .data = .{ .rx_cc = .{448 .data = .{ .rx_cc = .{ .r = reg, .cc = cc, .payload = switch (m) {
459 .r1 = reg,449 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
460 .cc = cc,450 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
461 .payload = switch (m) {451 else => unreachable,
462 .sib => try self.addExtra(Mir.MemorySib.encode(m)),452 } } },
463 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
464 else => unreachable,
465 },
466 } },
467 });453 });
468}454}
469455
...@@ -479,10 +465,7 @@ fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Ins...@@ -479,10 +465,7 @@ fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Ins
479 return self.addInst(.{465 return self.addInst(.{
480 .tag = .jcc,466 .tag = .jcc,
481 .ops = .inst_cc,467 .ops = .inst_cc,
482 .data = .{ .inst_cc = .{468 .data = .{ .inst_cc = .{ .inst = target, .cc = cc } },
483 .inst = target,
484 .cc = cc,
485 } },
486 });469 });
487}470}
488471
...@@ -503,13 +486,15 @@ fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {...@@ -503,13 +486,15 @@ fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {
503}486}
504487
505fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {488fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {
506 const ops: Mir.Inst.Ops = if (imm == .signed) .imm_s else .imm_u;
507 _ = try self.addInst(.{489 _ = try self.addInst(.{
508 .tag = tag,490 .tag = tag,
509 .ops = ops,491 .ops = switch (imm) {
510 .data = .{ .imm = switch (imm) {492 .signed => .i_s,
511 .signed => |x| @bitCast(u32, x),493 .unsigned => .i_u,
512 .unsigned => |x| @intCast(u32, x),494 },
495 .data = .{ .i = switch (imm) {
496 .signed => |s| @bitCast(u32, s),
497 .unsigned => |u| @intCast(u32, u),
513 } },498 } },
514 });499 });
515}500}
...@@ -518,37 +503,43 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.Tag, reg1: Register, reg2: Reg...@@ -518,37 +503,43 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.Tag, reg1: Register, reg2: Reg
518 _ = try self.addInst(.{503 _ = try self.addInst(.{
519 .tag = tag,504 .tag = tag,
520 .ops = .rr,505 .ops = .rr,
521 .data = .{ .rr = .{506 .data = .{ .rr = .{ .r1 = reg1, .r2 = reg2 } },
522 .r1 = reg1,
523 .r2 = reg2,
524 } },
525 });507 });
526}508}
527509
528fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Immediate) !void {510fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Immediate) !void {
529 const ops: Mir.Inst.Ops = switch (imm) {511 const ops: Mir.Inst.Ops = switch (imm) {
530 .signed => .ri_s,512 .signed => .ri_s,
531 .unsigned => |x| if (x <= math.maxInt(u32)) .ri_u else .ri64,513 .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
532 };
533 const data: Mir.Inst.Data = switch (ops) {
534 .ri_s => .{ .ri = .{
535 .r1 = reg,
536 .imm = @bitCast(u32, imm.signed),
537 } },
538 .ri_u => .{ .ri = .{
539 .r1 = reg,
540 .imm = @intCast(u32, imm.unsigned),
541 } },
542 .ri64 => .{ .rx = .{
543 .r1 = reg,
544 .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
545 } },
546 else => unreachable,
547 };514 };
548 _ = try self.addInst(.{515 _ = try self.addInst(.{
549 .tag = tag,516 .tag = tag,
550 .ops = ops,517 .ops = ops,
551 .data = data,518 .data = switch (ops) {
519 .ri_s, .ri_u => .{ .ri = .{ .r = reg, .i = switch (imm) {
520 .signed => |s| @bitCast(u32, s),
521 .unsigned => |u| @intCast(u32, u),
522 } } },
523 .ri64 => .{ .rx = .{
524 .r = reg,
525 .payload = try self.addExtra(Mir.Imm64.encode(imm.unsigned)),
526 } },
527 else => unreachable,
528 },
529 });
530}
531
532fn asmRegisterRegisterRegister(
533 self: *Self,
534 tag: Mir.Inst.Tag,
535 reg1: Register,
536 reg2: Register,
537 reg3: Register,
538) !void {
539 _ = try self.addInst(.{
540 .tag = tag,
541 .ops = .rrr,
542 .data = .{ .rrr = .{ .r1 = reg1, .r2 = reg2, .r3 = reg3 } },
552 });543 });
553}544}
554545
...@@ -559,109 +550,133 @@ fn asmRegisterRegisterImmediate(...@@ -559,109 +550,133 @@ fn asmRegisterRegisterImmediate(
559 reg2: Register,550 reg2: Register,
560 imm: Immediate,551 imm: Immediate,
561) !void {552) !void {
562 const ops: Mir.Inst.Ops = switch (imm) {
563 .signed => .rri_s,
564 .unsigned => .rri_u,
565 };
566 const data: Mir.Inst.Data = switch (ops) {
567 .rri_s => .{ .rri = .{
568 .r1 = reg1,
569 .r2 = reg2,
570 .imm = @bitCast(u32, imm.signed),
571 } },
572 .rri_u => .{ .rri = .{
573 .r1 = reg1,
574 .r2 = reg2,
575 .imm = @intCast(u32, imm.unsigned),
576 } },
577 else => unreachable,
578 };
579 _ = try self.addInst(.{553 _ = try self.addInst(.{
580 .tag = tag,554 .tag = tag,
581 .ops = ops,555 .ops = switch (imm) {
582 .data = data,556 .signed => .rri_s,
557 .unsigned => .rri_u,
558 },
559 .data = .{ .rri = .{ .r1 = reg1, .r2 = reg2, .i = switch (imm) {
560 .signed => |s| @bitCast(u32, s),
561 .unsigned => |u| @intCast(u32, u),
562 } } },
583 });563 });
584}564}
585565
586fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {566fn asmMemory(self: *Self, tag: Mir.Inst.Tag, m: Memory) !void {
587 const ops: Mir.Inst.Ops = switch (m) {
588 .sib => .m_sib,
589 .rip => .m_rip,
590 else => unreachable,
591 };
592 const data: Mir.Inst.Data = .{ .payload = switch (ops) {
593 .m_sib => try self.addExtra(Mir.MemorySib.encode(m)),
594 .m_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
595 else => unreachable,
596 } };
597 _ = try self.addInst(.{567 _ = try self.addInst(.{
598 .tag = tag,568 .tag = tag,
599 .ops = ops,569 .ops = switch (m) {
600 .data = data,570 .sib => .m_sib,
571 .rip => .m_rip,
572 else => unreachable,
573 },
574 .data = .{ .payload = switch (m) {
575 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
576 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
577 else => unreachable,
578 } },
601 });579 });
602}580}
603581
604fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate) !void {582fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !void {
605 const ops: Mir.Inst.Ops = switch (m) {
606 .sib => if (imm == .signed) .mi_s_sib else .mi_u_sib,
607 .rip => if (imm == .signed) .mi_s_rip else .mi_u_rip,
608 else => unreachable,
609 };
610 const payload: u32 = switch (ops) {
611 .mi_s_sib, .mi_u_sib => try self.addExtra(Mir.MemorySib.encode(m)),
612 .mi_s_rip, .mi_u_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
613 else => unreachable,
614 };
615 const data: Mir.Inst.Data = .{
616 .xi = .{ .payload = payload, .imm = switch (imm) {
617 .signed => |x| @bitCast(u32, x),
618 .unsigned => |x| @intCast(u32, x),
619 } },
620 };
621 _ = try self.addInst(.{583 _ = try self.addInst(.{
622 .tag = tag,584 .tag = tag,
623 .ops = ops,585 .ops = switch (m) {
624 .data = data,586 .sib => .rm_sib,
587 .rip => .rm_rip,
588 else => unreachable,
589 },
590 .data = .{ .rx = .{ .r = reg, .payload = switch (m) {
591 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
592 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
593 else => unreachable,
594 } } },
625 });595 });
626}596}
627597
628fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !void {598fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !void {
629 const ops: Mir.Inst.Ops = switch (m) {599 _ = try self.addInst(.{
630 .sib => .rm_sib,600 .tag = tag,
631 .rip => .rm_rip,601 .ops = switch (m) {
632 else => unreachable,602 .sib => .mr_sib,
633 };603 .rip => .mr_rip,
634 const data: Mir.Inst.Data = .{
635 .rx = .{ .r1 = reg, .payload = switch (ops) {
636 .rm_sib => try self.addExtra(Mir.MemorySib.encode(m)),
637 .rm_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
638 else => unreachable,604 else => unreachable,
639 } },605 },
640 };606 .data = .{ .rx = .{ .r = reg, .payload = switch (m) {
607 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
608 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
609 else => unreachable,
610 } } },
611 });
612}
613
614fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate) !void {
641 _ = try self.addInst(.{615 _ = try self.addInst(.{
642 .tag = tag,616 .tag = tag,
643 .ops = ops,617 .ops = switch (m) {
644 .data = data,618 .sib => switch (imm) {
619 .signed => .mi_sib_s,
620 .unsigned => .mi_sib_u,
621 },
622 .rip => switch (imm) {
623 .signed => .mi_rip_s,
624 .unsigned => .mi_rip_u,
625 },
626 else => unreachable,
627 },
628 .data = .{ .ix = .{ .i = switch (imm) {
629 .signed => |s| @bitCast(u32, s),
630 .unsigned => |u| @intCast(u32, u),
631 }, .payload = switch (m) {
632 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
633 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
634 else => unreachable,
635 } } },
645 });636 });
646}637}
647638
648fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !void {639fn asmMemoryRegisterRegister(
649 const ops: Mir.Inst.Ops = switch (m) {640 self: *Self,
650 .sib => .mr_sib,641 tag: Mir.Inst.Tag,
651 .rip => .mr_rip,642 m: Memory,
652 else => unreachable,643 reg1: Register,
653 };644 reg2: Register,
654 const data: Mir.Inst.Data = .{645) !void {
655 .rx = .{ .r1 = reg, .payload = switch (ops) {646 _ = try self.addInst(.{
656 .mr_sib => try self.addExtra(Mir.MemorySib.encode(m)),647 .tag = tag,
657 .mr_rip => try self.addExtra(Mir.MemoryRip.encode(m)),648 .ops = switch (m) {
649 .sib => .mrr_sib,
650 .rip => .mrr_rip,
658 else => unreachable,651 else => unreachable,
659 } },652 },
660 };653 .data = .{ .rrx = .{ .r1 = reg1, .r2 = reg2, .payload = switch (m) {
654 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
655 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
656 else => unreachable,
657 } } },
658 });
659}
660
661fn asmMemoryRegisterImmediate(
662 self: *Self,
663 tag: Mir.Inst.Tag,
664 m: Memory,
665 reg: Register,
666 imm: Immediate,
667) !void {
661 _ = try self.addInst(.{668 _ = try self.addInst(.{
662 .tag = tag,669 .tag = tag,
663 .ops = ops,670 .ops = switch (m) {
664 .data = data,671 .sib => .mri_sib,
672 .rip => .mri_rip,
673 else => unreachable,
674 },
675 .data = .{ .rix = .{ .r = reg, .i = @intCast(u8, imm.unsigned), .payload = switch (m) {
676 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
677 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
678 else => unreachable,
679 } } },
665 });680 });
666}681}
667682
...@@ -768,18 +783,12 @@ fn gen(self: *Self) InnerError!void {...@@ -768,18 +783,12 @@ fn gen(self: *Self) InnerError!void {
768 self.mir_instructions.set(backpatch_stack_sub, .{783 self.mir_instructions.set(backpatch_stack_sub, .{
769 .tag = .sub,784 .tag = .sub,
770 .ops = .ri_u,785 .ops = .ri_u,
771 .data = .{ .ri = .{786 .data = .{ .ri = .{ .r = .rsp, .i = aligned_stack_end } },
772 .r1 = .rsp,
773 .imm = aligned_stack_end,
774 } },
775 });787 });
776 self.mir_instructions.set(backpatch_stack_add, .{788 self.mir_instructions.set(backpatch_stack_add, .{
777 .tag = .add,789 .tag = .add,
778 .ops = .ri_u,790 .ops = .ri_u,
779 .data = .{ .ri = .{791 .data = .{ .ri = .{ .r = .rsp, .i = aligned_stack_end } },
780 .r1 = .rsp,
781 .imm = aligned_stack_end,
782 } },
783 });792 });
784793
785 const save_reg_list = try self.addExtra(Mir.SaveRegisterList{794 const save_reg_list = try self.addExtra(Mir.SaveRegisterList{
...@@ -1392,38 +1401,80 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {...@@ -1392,38 +1401,80 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
13921401
1393fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {1402fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
1394 const ty_op = self.air.instructions.items(.data)[inst].ty_op;1403 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1395 if (self.liveness.isUnused(inst))1404 const result = if (self.liveness.isUnused(inst)) .dead else result: {
1396 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });1405 const src_ty = self.air.typeOf(ty_op.operand);
13971406 const src_int_info = src_ty.intInfo(self.target.*);
1398 const operand_ty = self.air.typeOf(ty_op.operand);1407 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
1399 const operand = try self.resolveInst(ty_op.operand);1408 const src_mcv = try self.resolveInst(ty_op.operand);
1400 const info_a = operand_ty.intInfo(self.target.*);1409 const src_lock = switch (src_mcv) {
1401 const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
1402
1403 const operand_abi_size = operand_ty.abiSize(self.target.*);
1404 const dest_ty = self.air.typeOfIndex(inst);
1405 const dest_abi_size = dest_ty.abiSize(self.target.*);
1406 const dst_mcv: MCValue = blk: {
1407 if (info_a.bits == info_b.bits) {
1408 break :blk operand;
1409 }
1410 if (operand_abi_size > 8 or dest_abi_size > 8) {
1411 return self.fail("TODO implement intCast for abi sizes larger than 8", .{});
1412 }
1413
1414 const operand_lock: ?RegisterLock = switch (operand) {
1415 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),1410 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1416 else => null,1411 else => null,
1417 };1412 };
1418 defer if (operand_lock) |lock| self.register_manager.unlockReg(lock);1413 defer if (src_lock) |lock| self.register_manager.unlockReg(lock);
14191414
1420 const reg = try self.register_manager.allocReg(inst, gp);1415 const dst_ty = self.air.typeOfIndex(inst);
1421 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });1416 const dst_int_info = dst_ty.intInfo(self.target.*);
1422 try self.genSetReg(operand_ty, reg, operand);1417 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
1423 break :blk MCValue{ .register = reg };1418 const dst_mcv = if (dst_abi_size <= src_abi_size and
1424 };1419 self.reuseOperand(inst, ty_op.operand, 0, src_mcv))
1420 src_mcv
1421 else
1422 try self.allocRegOrMem(inst, true);
14251423
1426 return self.finishAir(inst, dst_mcv, .{ ty_op.operand, .none, .none });1424 const min_ty = if (dst_int_info.bits < src_int_info.bits) dst_ty else src_ty;
1425 const signedness: std.builtin.Signedness = if (dst_int_info.signedness == .signed and
1426 src_int_info.signedness == .signed) .signed else .unsigned;
1427 switch (dst_mcv) {
1428 .register => |dst_reg| {
1429 const min_abi_size = @min(dst_abi_size, src_abi_size);
1430 const tag: Mir.Inst.Tag = switch (signedness) {
1431 .signed => .movsx,
1432 .unsigned => if (min_abi_size > 2) .mov else .movzx,
1433 };
1434 const dst_alias = switch (tag) {
1435 .movsx => dst_reg.to64(),
1436 .mov, .movzx => if (min_abi_size > 4) dst_reg.to64() else dst_reg.to32(),
1437 else => unreachable,
1438 };
1439 switch (src_mcv) {
1440 .register => |src_reg| {
1441 try self.asmRegisterRegister(
1442 tag,
1443 dst_alias,
1444 registerAlias(src_reg, min_abi_size),
1445 );
1446 },
1447 .stack_offset => |src_off| {
1448 try self.asmRegisterMemory(tag, dst_alias, Memory.sib(
1449 Memory.PtrSize.fromSize(min_abi_size),
1450 .{ .base = .rbp, .disp = -src_off },
1451 ));
1452 },
1453 else => return self.fail("TODO airIntCast from {s} to {s}", .{
1454 @tagName(src_mcv),
1455 @tagName(dst_mcv),
1456 }),
1457 }
1458 if (self.regExtraBits(min_ty) > 0) try self.truncateRegister(min_ty, dst_reg);
1459 },
1460 else => {
1461 try self.setRegOrMem(min_ty, dst_mcv, src_mcv);
1462 const extra = dst_abi_size * 8 - dst_int_info.bits;
1463 if (extra > 0) {
1464 try self.genShiftBinOpMir(switch (signedness) {
1465 .signed => .sal,
1466 .unsigned => .shl,
1467 }, dst_ty, dst_mcv, .{ .immediate = extra });
1468 try self.genShiftBinOpMir(switch (signedness) {
1469 .signed => .sar,
1470 .unsigned => .shr,
1471 }, dst_ty, dst_mcv, .{ .immediate = extra });
1472 }
1473 },
1474 }
1475 break :result dst_mcv;
1476 };
1477 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1427}1478}
14281479
1429fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {1480fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
...@@ -1550,28 +1601,161 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1550,28 +1601,161 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
15501601
1551fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {1602fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
1552 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1603 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1553 const result: MCValue = if (self.liveness.isUnused(inst))1604 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1554 .dead1605 const ty = self.air.typeOf(bin_op.lhs);
1555 else1606
1556 return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch});1607 const lhs_mcv = try self.resolveInst(bin_op.lhs);
1608 const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv))
1609 lhs_mcv
1610 else
1611 try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv);
1612 const dst_reg = dst_mcv.register;
1613 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
1614 defer self.register_manager.unlockReg(dst_lock);
1615
1616 const rhs_mcv = try self.resolveInst(bin_op.rhs);
1617 const rhs_lock = switch (rhs_mcv) {
1618 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1619 else => null,
1620 };
1621 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
1622
1623 const limit_reg = try self.register_manager.allocReg(null, gp);
1624 const limit_mcv = MCValue{ .register = limit_reg };
1625 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
1626 defer self.register_manager.unlockReg(limit_lock);
1627
1628 const reg_bits = self.regBitSize(ty);
1629 const cc: Condition = if (ty.isSignedInt()) cc: {
1630 try self.genSetReg(ty, limit_reg, dst_mcv);
1631 try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
1632 try self.genBinOpMir(.xor, ty, limit_mcv, .{
1633 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
1634 });
1635 break :cc .o;
1636 } else cc: {
1637 try self.genSetReg(ty, limit_reg, .{
1638 .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits),
1639 });
1640 break :cc .c;
1641 };
1642 try self.genBinOpMir(.add, ty, dst_mcv, rhs_mcv);
1643
1644 const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2));
1645 try self.asmCmovccRegisterRegister(
1646 registerAlias(dst_reg, abi_size),
1647 registerAlias(limit_reg, abi_size),
1648 cc,
1649 );
1650 break :result dst_mcv;
1651 };
1557 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1652 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1558}1653}
15591654
1560fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {1655fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
1561 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1656 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1562 const result: MCValue = if (self.liveness.isUnused(inst))1657 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1563 .dead1658 const ty = self.air.typeOf(bin_op.lhs);
1564 else1659
1565 return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch});1660 const lhs_mcv = try self.resolveInst(bin_op.lhs);
1661 const dst_mcv = if (lhs_mcv.isRegister() and self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv))
1662 lhs_mcv
1663 else
1664 try self.copyToRegisterWithInstTracking(inst, ty, lhs_mcv);
1665 const dst_reg = dst_mcv.register;
1666 const dst_lock = self.register_manager.lockRegAssumeUnused(dst_reg);
1667 defer self.register_manager.unlockReg(dst_lock);
1668
1669 const rhs_mcv = try self.resolveInst(bin_op.rhs);
1670 const rhs_lock = switch (rhs_mcv) {
1671 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1672 else => null,
1673 };
1674 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
1675
1676 const limit_reg = try self.register_manager.allocReg(null, gp);
1677 const limit_mcv = MCValue{ .register = limit_reg };
1678 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
1679 defer self.register_manager.unlockReg(limit_lock);
1680
1681 const reg_bits = self.regBitSize(ty);
1682 const cc: Condition = if (ty.isSignedInt()) cc: {
1683 try self.genSetReg(ty, limit_reg, dst_mcv);
1684 try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
1685 try self.genBinOpMir(.xor, ty, limit_mcv, .{
1686 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
1687 });
1688 break :cc .o;
1689 } else cc: {
1690 try self.genSetReg(ty, limit_reg, .{ .immediate = 0 });
1691 break :cc .c;
1692 };
1693 try self.genBinOpMir(.sub, ty, dst_mcv, rhs_mcv);
1694
1695 const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2));
1696 try self.asmCmovccRegisterRegister(
1697 registerAlias(dst_reg, abi_size),
1698 registerAlias(limit_reg, abi_size),
1699 cc,
1700 );
1701 break :result dst_mcv;
1702 };
1566 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1703 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1567}1704}
15681705
1569fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {1706fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
1570 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1707 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1571 const result: MCValue = if (self.liveness.isUnused(inst))1708 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1572 .dead1709 const ty = self.air.typeOf(bin_op.lhs);
1573 else1710
1574 return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch});1711 try self.spillRegisters(&.{ .rax, .rdx });
1712 const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
1713 defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
1714
1715 const lhs_mcv = try self.resolveInst(bin_op.lhs);
1716 const lhs_lock = switch (lhs_mcv) {
1717 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
1718 else => null,
1719 };
1720 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
1721
1722 const rhs_mcv = try self.resolveInst(bin_op.rhs);
1723 const rhs_lock = switch (rhs_mcv) {
1724 .register => |reg| self.register_manager.lockReg(reg),
1725 else => null,
1726 };
1727 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
1728
1729 const limit_reg = try self.register_manager.allocReg(null, gp);
1730 const limit_mcv = MCValue{ .register = limit_reg };
1731 const limit_lock = self.register_manager.lockRegAssumeUnused(limit_reg);
1732 defer self.register_manager.unlockReg(limit_lock);
1733
1734 const reg_bits = self.regBitSize(ty);
1735 const cc: Condition = if (ty.isSignedInt()) cc: {
1736 try self.genSetReg(ty, limit_reg, lhs_mcv);
1737 try self.genBinOpMir(.xor, ty, limit_mcv, rhs_mcv);
1738 try self.genBinOpMir(.sar, ty, limit_mcv, .{ .immediate = reg_bits - 1 });
1739 try self.genBinOpMir(.xor, ty, limit_mcv, .{
1740 .immediate = (@as(u64, 1) << @intCast(u6, reg_bits - 1)) - 1,
1741 });
1742 break :cc .o;
1743 } else cc: {
1744 try self.genSetReg(ty, limit_reg, .{
1745 .immediate = @as(u64, std.math.maxInt(u64)) >> @intCast(u6, 64 - reg_bits),
1746 });
1747 break :cc .c;
1748 };
1749
1750 const dst_mcv = try self.genMulDivBinOp(.mul, inst, ty, lhs_mcv, rhs_mcv);
1751 const abi_size = @intCast(u32, @max(ty.abiSize(self.target.*), 2));
1752 try self.asmCmovccRegisterRegister(
1753 registerAlias(dst_mcv.register, abi_size),
1754 registerAlias(limit_reg, abi_size),
1755 cc,
1756 );
1757 break :result dst_mcv;
1758 };
1575 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1759 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
1576}1760}
15771761
...@@ -1599,6 +1783,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {...@@ -1599,6 +1783,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
1599 .add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs),1783 .add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs),
1600 .sub_with_overflow => try self.genBinOp(null, .sub, bin_op.lhs, bin_op.rhs),1784 .sub_with_overflow => try self.genBinOp(null, .sub, bin_op.lhs, bin_op.rhs),
1601 .shl_with_overflow => blk: {1785 .shl_with_overflow => blk: {
1786 try self.register_manager.getReg(.rcx, null);
1602 const lhs = try self.resolveInst(bin_op.lhs);1787 const lhs = try self.resolveInst(bin_op.lhs);
1603 const rhs = try self.resolveInst(bin_op.rhs);1788 const rhs = try self.resolveInst(bin_op.rhs);
1604 const shift_ty = self.air.typeOf(bin_op.rhs);1789 const shift_ty = self.air.typeOf(bin_op.rhs);
...@@ -1889,6 +2074,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {...@@ -1889,6 +2074,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
1889 try self.spillRegisters(&.{.rcx});2074 try self.spillRegisters(&.{.rcx});
18902075
1891 const tag = self.air.instructions.items(.tag)[inst];2076 const tag = self.air.instructions.items(.tag)[inst];
2077 try self.register_manager.getReg(.rcx, null);
1892 const lhs = try self.resolveInst(bin_op.lhs);2078 const lhs = try self.resolveInst(bin_op.lhs);
1893 const rhs = try self.resolveInst(bin_op.rhs);2079 const rhs = try self.resolveInst(bin_op.rhs);
1894 const lhs_ty = self.air.typeOf(bin_op.lhs);2080 const lhs_ty = self.air.typeOf(bin_op.lhs);
...@@ -2018,7 +2204,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2018,7 +2204,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
2018 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);2204 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
2019 if (err_off > 0) {2205 if (err_off > 0) {
2020 const shift = @intCast(u6, err_off * 8);2206 const shift = @intCast(u6, err_off * 8);
2021 try self.genShiftBinOpMir(.shr, err_union_ty, result.register, .{ .immediate = shift });2207 try self.genShiftBinOpMir(.shr, err_union_ty, result, .{ .immediate = shift });
2022 } else {2208 } else {
2023 try self.truncateRegister(Type.anyerror, result.register);2209 try self.truncateRegister(Type.anyerror, result.register);
2024 }2210 }
...@@ -2050,9 +2236,7 @@ fn genUnwrapErrorUnionPayloadMir(...@@ -2050,9 +2236,7 @@ fn genUnwrapErrorUnionPayloadMir(
2050 const payload_ty = err_union_ty.errorUnionPayload();2236 const payload_ty = err_union_ty.errorUnionPayload();
20512237
2052 const result: MCValue = result: {2238 const result: MCValue = result: {
2053 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {2239 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result .none;
2054 break :result MCValue.none;
2055 }
20562240
2057 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);2241 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
2058 switch (err_union) {2242 switch (err_union) {
...@@ -2065,17 +2249,17 @@ fn genUnwrapErrorUnionPayloadMir(...@@ -2065,17 +2249,17 @@ fn genUnwrapErrorUnionPayloadMir(
2065 const eu_lock = self.register_manager.lockReg(reg);2249 const eu_lock = self.register_manager.lockReg(reg);
2066 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);2250 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
20672251
2068 const result_reg: Register = if (maybe_inst) |inst|2252 const result_mcv: MCValue = if (maybe_inst) |inst|
2069 (try self.copyToRegisterWithInstTracking(inst, err_union_ty, err_union)).register2253 try self.copyToRegisterWithInstTracking(inst, err_union_ty, err_union)
2070 else2254 else
2071 try self.copyToTmpRegister(err_union_ty, err_union);2255 .{ .register = try self.copyToTmpRegister(err_union_ty, err_union) };
2072 if (payload_off > 0) {2256 if (payload_off > 0) {
2073 const shift = @intCast(u6, payload_off * 8);2257 const shift = @intCast(u6, payload_off * 8);
2074 try self.genShiftBinOpMir(.shr, err_union_ty, result_reg, .{ .immediate = shift });2258 try self.genShiftBinOpMir(.shr, err_union_ty, result_mcv, .{ .immediate = shift });
2075 } else {2259 } else {
2076 try self.truncateRegister(payload_ty, result_reg);2260 try self.truncateRegister(payload_ty, result_mcv.register);
2077 }2261 }
2078 break :result MCValue{ .register = result_reg };2262 break :result result_mcv;
2079 },2263 },
2080 else => return self.fail("TODO implement genUnwrapErrorUnionPayloadMir for {}", .{err_union}),2264 else => return self.fail("TODO implement genUnwrapErrorUnionPayloadMir for {}", .{err_union}),
2081 }2265 }
...@@ -2253,8 +2437,8 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {...@@ -2253,8 +2437,8 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
22532437
2254 .stack_offset => |off| try self.asmMemoryImmediate(2438 .stack_offset => |off| try self.asmMemoryImmediate(
2255 .mov,2439 .mov,
2256 Memory.sib(.byte, .{ .base = .rsp, .disp = pl_abi_size - off }),2440 Memory.sib(.byte, .{ .base = .rbp, .disp = pl_abi_size - off }),
2257 Immediate.u(0),2441 Immediate.u(1),
2258 ),2442 ),
2259 }2443 }
2260 }2444 }
...@@ -2473,10 +2657,9 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {...@@ -2473,10 +2657,9 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
2473}2657}
24742658
2475fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {2659fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2476 const is_volatile = false; // TODO
2477 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2660 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2478 const result: MCValue = if (!is_volatile and self.liveness.isUnused(inst)) .dead else result: {2661 const slice_ty = self.air.typeOf(bin_op.lhs);
2479 const slice_ty = self.air.typeOf(bin_op.lhs);2662 const result = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
2480 var buf: Type.SlicePtrFieldTypeBuffer = undefined;2663 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
2481 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);2664 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
2482 const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs);2665 const elem_ptr = try self.genSliceElemPtr(bin_op.lhs, bin_op.rhs);
...@@ -2563,54 +2746,44 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -2563,54 +2746,44 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
2563}2746}
25642747
2565fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {2748fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2566 const is_volatile = false; // TODO
2567 const bin_op = self.air.instructions.items(.data)[inst].bin_op;2749 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
2568
2569 if (!is_volatile and self.liveness.isUnused(inst)) {
2570 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
2571 }
2572
2573 // this is identical to the `airPtrElemPtr` codegen expect here an
2574 // additional `mov` is needed at the end to get the actual value
2575
2576 const ptr_ty = self.air.typeOf(bin_op.lhs);2750 const ptr_ty = self.air.typeOf(bin_op.lhs);
2577 const ptr = try self.resolveInst(bin_op.lhs);2751 const result = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
2578 const ptr_lock: ?RegisterLock = switch (ptr) {2752 // this is identical to the `airPtrElemPtr` codegen expect here an
2579 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),2753 // additional `mov` is needed at the end to get the actual value
2580 else => null,2754
2581 };2755 const elem_ty = ptr_ty.elemType2();
2582 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);2756 const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
2757 const index_ty = self.air.typeOf(bin_op.rhs);
2758 const index_mcv = try self.resolveInst(bin_op.rhs);
2759 const index_lock = switch (index_mcv) {
2760 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2761 else => null,
2762 };
2763 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
25832764
2584 const elem_ty = ptr_ty.elemType2();2765 const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size);
2585 const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));2766 const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2586 const index_ty = self.air.typeOf(bin_op.rhs);2767 defer self.register_manager.unlockReg(offset_lock);
2587 const index = try self.resolveInst(bin_op.rhs);
2588 const index_lock: ?RegisterLock = switch (index) {
2589 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2590 else => null,
2591 };
2592 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
25932768
2594 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);2769 const ptr_mcv = try self.resolveInst(bin_op.lhs);
2595 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);2770 const elem_ptr_reg = if (ptr_mcv.isRegister() and self.liveness.operandDies(inst, 0))
2596 defer self.register_manager.unlockReg(offset_reg_lock);2771 ptr_mcv.register
25972772 else
2598 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);2773 try self.copyToTmpRegister(ptr_ty, ptr_mcv);
2599 try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });2774 const elem_ptr_lock = self.register_manager.lockRegAssumeUnused(elem_ptr_reg);
2775 defer self.register_manager.unlockReg(elem_ptr_lock);
2776 try self.asmRegisterRegister(.add, elem_ptr_reg, offset_reg);
26002777
2601 const result: MCValue = result: {2778 const dst_mcv = try self.allocRegOrMem(inst, true);
2602 if (elem_abi_size > 8) {2779 const dst_lock = switch (dst_mcv) {
2603 return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size});2780 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2604 } else {2781 else => null,
2605 try self.asmRegisterMemory(2782 };
2606 .mov,2783 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
2607 registerAlias(dst_mcv.register, elem_abi_size),2784 try self.load(dst_mcv, .{ .register = elem_ptr_reg }, ptr_ty);
2608 Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{ .base = dst_mcv.register }),2785 break :result dst_mcv;
2609 );
2610 break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };
2611 }
2612 };2786 };
2613
2614 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });2787 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
2615}2788}
26162789
...@@ -2618,36 +2791,34 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {...@@ -2618,36 +2791,34 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
2618 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;2791 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
2619 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;2792 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
26202793
2621 if (self.liveness.isUnused(inst)) {2794 const result = if (self.liveness.isUnused(inst)) .dead else result: {
2622 return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });2795 const ptr_ty = self.air.typeOf(extra.lhs);
2623 }2796 const ptr = try self.resolveInst(extra.lhs);
26242797 const ptr_lock: ?RegisterLock = switch (ptr) {
2625 const ptr_ty = self.air.typeOf(extra.lhs);2798 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2626 const ptr = try self.resolveInst(extra.lhs);2799 else => null,
2627 const ptr_lock: ?RegisterLock = switch (ptr) {2800 };
2628 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),2801 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
2629 else => null,
2630 };
2631 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
2632
2633 const elem_ty = ptr_ty.elemType2();
2634 const elem_abi_size = elem_ty.abiSize(self.target.*);
2635 const index_ty = self.air.typeOf(extra.rhs);
2636 const index = try self.resolveInst(extra.rhs);
2637 const index_lock: ?RegisterLock = switch (index) {
2638 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2639 else => null,
2640 };
2641 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
26422802
2643 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);2803 const elem_ty = ptr_ty.elemType2();
2644 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);2804 const elem_abi_size = elem_ty.abiSize(self.target.*);
2645 defer self.register_manager.unlockReg(offset_reg_lock);2805 const index_ty = self.air.typeOf(extra.rhs);
2806 const index = try self.resolveInst(extra.rhs);
2807 const index_lock: ?RegisterLock = switch (index) {
2808 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2809 else => null,
2810 };
2811 defer if (index_lock) |lock| self.register_manager.unlockReg(lock);
26462812
2647 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);2813 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
2648 try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });2814 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2815 defer self.register_manager.unlockReg(offset_reg_lock);
26492816
2650 return self.finishAir(inst, dst_mcv, .{ extra.lhs, extra.rhs, .none });2817 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
2818 try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
2819 break :result dst_mcv;
2820 };
2821 return self.finishAir(inst, result, .{ extra.lhs, extra.rhs, .none });
2651}2822}
26522823
2653fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {2824fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
...@@ -2728,7 +2899,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {...@@ -2728,7 +2899,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
2728 else2899 else
2729 0;2900 0;
2730 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);2901 const result = try self.copyToRegisterWithInstTracking(inst, union_ty, operand);
2731 try self.genShiftBinOpMir(.shr, Type.usize, result.register, .{ .immediate = shift });2902 try self.genShiftBinOpMir(.shr, Type.usize, result, .{ .immediate = shift });
2732 break :blk MCValue{2903 break :blk MCValue{
2733 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),2904 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
2734 };2905 };
...@@ -2820,12 +2991,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {...@@ -2820,12 +2991,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
2820 const extra_bits = self.regExtraBits(src_ty);2991 const extra_bits = self.regExtraBits(src_ty);
2821 const masked_mcv = if (extra_bits > 0) masked: {2992 const masked_mcv = if (extra_bits > 0) masked: {
2822 const mask_mcv = MCValue{2993 const mask_mcv = MCValue{
2823 .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) << @intCast(u6, src_bits),2994 .immediate = ((@as(u64, 1) << @intCast(u6, extra_bits)) - 1) <<
2995 @intCast(u6, src_bits),
2824 };2996 };
2825 const tmp_mcv = tmp: {2997 const tmp_mcv = tmp: {
2826 if (src_mcv.isImmediate() or self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {2998 if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0)) break :tmp src_mcv;
2827 break :tmp src_mcv;
2828 }
2829 try self.genSetReg(src_ty, dst_reg, src_mcv);2999 try self.genSetReg(src_ty, dst_reg, src_mcv);
2830 break :tmp dst_mcv;3000 break :tmp dst_mcv;
2831 };3001 };
...@@ -3526,34 +3696,37 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {...@@ -3526,34 +3696,37 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
3526fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {3696fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
3527 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;3697 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
3528 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;3698 const extra = self.air.extraData(Air.StructField, ty_pl.payload).data;
3529 const result = try self.structFieldPtr(inst, extra.struct_operand, extra.field_index);3699 const result = try self.fieldPtr(inst, extra.struct_operand, extra.field_index);
3530 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });3700 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
3531}3701}
35323702
3533fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {3703fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
3534 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3704 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3535 const result = try self.structFieldPtr(inst, ty_op.operand, index);3705 const result = try self.fieldPtr(inst, ty_op.operand, index);
3536 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });3706 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3537}3707}
35383708
3539fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {3709fn fieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, index: u32) !MCValue {
3540 if (self.liveness.isUnused(inst)) {3710 if (self.liveness.isUnused(inst)) {
3541 return MCValue.dead;3711 return MCValue.dead;
3542 }3712 }
35433713
3544 const mcv = try self.resolveInst(operand);3714 const mcv = try self.resolveInst(operand);
3545 const ptr_ty = self.air.typeOf(operand);3715 const ptr_ty = self.air.typeOf(operand);
3546 const struct_ty = ptr_ty.childType();3716 const container_ty = ptr_ty.childType();
3547 if (struct_ty.zigTypeTag() == .Struct and struct_ty.containerLayout() == .Packed) {3717 const field_offset = switch (container_ty.containerLayout()) {
3548 return self.fail("TODO structFieldPtr implement packed structs", .{});3718 .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*)),
3549 }3719 .Packed => if (container_ty.zigTypeTag() == .Struct and ptr_ty.ptrInfo().data.host_size == 0)
3550 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));3720 container_ty.packedStructFieldByteOffset(index, self.target.*)
3721 else
3722 0,
3723 };
35513724
3552 const dst_mcv: MCValue = result: {3725 const dst_mcv: MCValue = result: {
3553 switch (mcv) {3726 switch (mcv) {
3554 .stack_offset => {3727 .stack_offset => {
3555 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{3728 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
3556 .immediate = struct_field_offset,3729 .immediate = field_offset,
3557 });3730 });
3558 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);3731 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
3559 defer self.register_manager.unlockReg(offset_reg_lock);3732 defer self.register_manager.unlockReg(offset_reg_lock);
...@@ -3563,7 +3736,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -3563,7 +3736,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
3563 break :result dst_mcv;3736 break :result dst_mcv;
3564 },3737 },
3565 .ptr_stack_offset => |off| {3738 .ptr_stack_offset => |off| {
3566 const ptr_stack_offset = off - @intCast(i32, struct_field_offset);3739 const ptr_stack_offset = off - @intCast(i32, field_offset);
3567 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };3740 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
3568 },3741 },
3569 .register => |reg| {3742 .register => |reg| {
...@@ -3571,7 +3744,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -3571,7 +3744,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
3571 defer self.register_manager.unlockReg(reg_lock);3744 defer self.register_manager.unlockReg(reg_lock);
35723745
3573 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{3746 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
3574 .immediate = struct_field_offset,3747 .immediate = field_offset,
3575 });3748 });
3576 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);3749 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
3577 defer self.register_manager.unlockReg(offset_reg_lock);3750 defer self.register_manager.unlockReg(offset_reg_lock);
...@@ -3592,7 +3765,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -3592,7 +3765,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
3592 try self.genBinOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg });3765 try self.genBinOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg });
3593 break :result MCValue{ .register = result_reg };3766 break :result MCValue{ .register = result_reg };
3594 },3767 },
3595 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),3768 else => return self.fail("TODO implement fieldPtr for {}", .{mcv}),
3596 }3769 }
3597 };3770 };
3598 return dst_mcv;3771 return dst_mcv;
...@@ -3609,18 +3782,22 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3609,18 +3782,22 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3609 }3782 }
36103783
3611 const mcv = try self.resolveInst(operand);3784 const mcv = try self.resolveInst(operand);
3612 const struct_ty = self.air.typeOf(operand);3785 const container_ty = self.air.typeOf(operand);
3613 if (struct_ty.zigTypeTag() == .Struct and struct_ty.containerLayout() == .Packed) {3786 const field_ty = container_ty.structFieldType(index);
3614 return self.fail("TODO airStructFieldVal implement packed structs", .{});3787 const field_bit_offset = switch (container_ty.containerLayout()) {
3615 }3788 .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8),
3616 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);3789 .Packed => if (container_ty.castTag(.@"struct")) |struct_obj|
3617 const struct_field_ty = struct_ty.structFieldType(index);3790 struct_obj.data.packedFieldBitOffset(self.target.*, index)
3791 else
3792 0,
3793 };
36183794
3619 const result: MCValue = result: {3795 const result: MCValue = result: {
3620 switch (mcv) {3796 switch (mcv) {
3621 .stack_offset => |off| {3797 .stack_offset => |off| {
3622 const stack_offset = off - @intCast(i32, struct_field_offset);3798 const byte_offset = std.math.divExact(u32, field_bit_offset, 8) catch
3623 break :result MCValue{ .stack_offset = stack_offset };3799 return self.fail("TODO implement struct_field_val for a packed struct", .{});
3800 break :result MCValue{ .stack_offset = off - @intCast(i32, byte_offset) };
3624 },3801 },
3625 .register => |reg| {3802 .register => |reg| {
3626 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);3803 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
...@@ -3643,27 +3820,23 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {...@@ -3643,27 +3820,23 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
3643 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);3820 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
36443821
3645 // Shift by struct_field_offset.3822 // Shift by struct_field_offset.
3646 const shift = @intCast(u8, struct_field_offset * 8);3823 try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv, .{ .immediate = field_bit_offset });
3647 try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv.register, .{ .immediate = shift });
36483824
3649 // Mask with reg.bitSize() - struct_field_size3825 // Mask to field_bit_size bits
3650 const max_reg_bit_width = Register.rax.bitSize();3826 const field_bit_size = field_ty.bitSize(self.target.*);
3651 const mask_shift = @intCast(u6, (max_reg_bit_width - struct_field_ty.bitSize(self.target.*)));3827 const mask = ~@as(u64, 0) >> @intCast(u6, 64 - field_bit_size);
3652 const mask = (~@as(u64, 0)) >> mask_shift;
36533828
3654 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });3829 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
3655 try self.genBinOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg });3830 try self.genBinOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg });
36563831
3657 const signedness: std.builtin.Signedness = blk: {3832 const signedness =
3658 if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned;3833 if (field_ty.isAbiInt()) field_ty.intInfo(self.target.*).signedness else .unsigned;
3659 break :blk struct_field_ty.intInfo(self.target.*).signedness;3834 const field_byte_size = @intCast(u32, field_ty.abiSize(self.target.*));
3660 };3835 if (signedness == .signed and field_byte_size < 8) {
3661 const field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
3662 if (signedness == .signed and field_size < 8) {
3663 try self.asmRegisterRegister(3836 try self.asmRegisterRegister(
3664 .movsx,3837 .movsx,
3665 dst_mcv.register,3838 dst_mcv.register,
3666 registerAlias(dst_mcv.register, field_size),3839 registerAlias(dst_mcv.register, field_byte_size),
3667 );3840 );
3668 }3841 }
36693842
...@@ -3707,10 +3880,10 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:...@@ -3707,10 +3880,10 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
3707 const src_ty = self.air.typeOf(src_air);3880 const src_ty = self.air.typeOf(src_air);
3708 const src_mcv = try self.resolveInst(src_air);3881 const src_mcv = try self.resolveInst(src_air);
3709 if (src_ty.zigTypeTag() == .Vector) {3882 if (src_ty.zigTypeTag() == .Vector) {
3710 return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});3883 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
3711 }3884 }
3712 if (src_ty.abiSize(self.target.*) > 8) {3885 if (src_ty.abiSize(self.target.*) > 8) {
3713 return self.fail("TODO implement genBinOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});3886 return self.fail("TODO implement genUnOp for {}", .{src_ty.fmt(self.bin_file.options.module.?)});
3714 }3887 }
37153888
3716 switch (src_mcv) {3889 switch (src_mcv) {
...@@ -3805,29 +3978,186 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue...@@ -3805,29 +3978,186 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
3805}3978}
38063979
3807/// Clobbers .rcx for non-immediate shift value.3980/// Clobbers .rcx for non-immediate shift value.
3808fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void {3981fn genShiftBinOpMir(
3809 switch (tag) {3982 self: *Self,
3810 .sal, .sar, .shl, .shr => {},3983 tag: Mir.Inst.Tag,
3811 else => unreachable,3984 ty: Type,
3812 }3985 lhs_mcv: MCValue,
38133986 shift_mcv: MCValue,
3814 const abi_size = @intCast(u32, ty.abiSize(self.target.*));3987) !void {
3815 blk: {3988 const rhs_mcv: MCValue = rhs: {
3816 switch (shift) {3989 switch (shift_mcv) {
3817 .immediate => |imm| switch (imm) {3990 .immediate => |imm| switch (imm) {
3818 0 => return,3991 0 => return,
3819 else => return self.asmRegisterImmediate(tag, registerAlias(reg, abi_size), Immediate.u(imm)),3992 else => break :rhs shift_mcv,
3820 },
3821 .register => |shift_reg| {
3822 if (shift_reg == .rcx) break :blk;
3823 },3993 },
3994 .register => |shift_reg| if (shift_reg == .rcx) break :rhs shift_mcv,
3824 else => {},3995 else => {},
3825 }3996 }
3826 self.register_manager.getRegAssumeFree(.rcx, null);3997 self.register_manager.getRegAssumeFree(.rcx, null);
3827 try self.genSetReg(Type.u8, .rcx, shift);3998 try self.genSetReg(Type.u8, .rcx, shift_mcv);
3828 }3999 break :rhs .{ .register = .rcx };
4000 };
4001
4002 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4003 if (abi_size <= 8) {
4004 switch (lhs_mcv) {
4005 .register => |lhs_reg| switch (rhs_mcv) {
4006 .immediate => |rhs_imm| try self.asmRegisterImmediate(
4007 tag,
4008 registerAlias(lhs_reg, abi_size),
4009 Immediate.u(rhs_imm),
4010 ),
4011 .register => |rhs_reg| try self.asmRegisterRegister(
4012 tag,
4013 registerAlias(lhs_reg, abi_size),
4014 registerAlias(rhs_reg, 1),
4015 ),
4016 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
4017 @tagName(lhs_mcv),
4018 @tagName(rhs_mcv),
4019 }),
4020 },
4021 .stack_offset => |lhs_off| switch (rhs_mcv) {
4022 .immediate => |rhs_imm| try self.asmMemoryImmediate(
4023 tag,
4024 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -lhs_off }),
4025 Immediate.u(rhs_imm),
4026 ),
4027 .register => |rhs_reg| try self.asmMemoryRegister(
4028 tag,
4029 Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = .rbp, .disp = -lhs_off }),
4030 registerAlias(rhs_reg, 1),
4031 ),
4032 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
4033 @tagName(lhs_mcv),
4034 @tagName(rhs_mcv),
4035 }),
4036 },
4037 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
4038 @tagName(lhs_mcv),
4039 @tagName(rhs_mcv),
4040 }),
4041 }
4042 } else if (abi_size <= 16) {
4043 const tmp_reg = try self.register_manager.allocReg(null, gp);
4044 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
4045 defer self.register_manager.unlockReg(tmp_lock);
4046
4047 const info: struct { offsets: [2]i32, double_tag: Mir.Inst.Tag } = switch (tag) {
4048 .shl, .sal => .{ .offsets = .{ 0, 8 }, .double_tag = .shld },
4049 .shr, .sar => .{ .offsets = .{ 8, 0 }, .double_tag = .shrd },
4050 else => unreachable,
4051 };
4052 switch (lhs_mcv) {
4053 .stack_offset => |dst_off| switch (rhs_mcv) {
4054 .immediate => |rhs_imm| if (rhs_imm == 0) {} else if (rhs_imm < 64) {
4055 try self.asmRegisterMemory(
4056 .mov,
4057 tmp_reg,
4058 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
4059 );
4060 try self.asmMemoryRegisterImmediate(
4061 info.double_tag,
4062 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[1] - dst_off }),
4063 tmp_reg,
4064 Immediate.u(rhs_imm),
4065 );
4066 try self.asmMemoryImmediate(
4067 tag,
4068 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
4069 Immediate.u(rhs_imm),
4070 );
4071 } else {
4072 assert(rhs_imm < 128);
4073 try self.asmRegisterMemory(
4074 .mov,
4075 tmp_reg,
4076 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
4077 );
4078 if (rhs_imm > 64) {
4079 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(rhs_imm - 64));
4080 }
4081 try self.asmMemoryRegister(
4082 .mov,
4083 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[1] - dst_off }),
4084 tmp_reg,
4085 );
4086 switch (tag) {
4087 .shl, .sal, .shr => {
4088 try self.asmRegisterRegister(.xor, tmp_reg.to32(), tmp_reg.to32());
4089 try self.asmMemoryRegister(
4090 .mov,
4091 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
4092 tmp_reg,
4093 );
4094 },
4095 .sar => try self.asmMemoryImmediate(
4096 tag,
4097 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
4098 Immediate.u(63),
4099 ),
4100 else => unreachable,
4101 }
4102 },
4103 else => {
4104 const first_reg = try self.register_manager.allocReg(null, gp);
4105 const first_lock = self.register_manager.lockRegAssumeUnused(first_reg);
4106 defer self.register_manager.unlockReg(first_lock);
4107
4108 const second_reg = try self.register_manager.allocReg(null, gp);
4109 const second_lock = self.register_manager.lockRegAssumeUnused(second_reg);
4110 defer self.register_manager.unlockReg(second_lock);
38294111
3830 try self.asmRegisterRegister(tag, registerAlias(reg, abi_size), .cl);4112 try self.genSetReg(Type.u8, .cl, rhs_mcv);
4113 try self.asmRegisterMemory(
4114 .mov,
4115 first_reg,
4116 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
4117 );
4118 try self.asmRegisterMemory(
4119 .mov,
4120 second_reg,
4121 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[1] - dst_off }),
4122 );
4123 switch (tag) {
4124 .shl, .sal, .shr => try self.asmRegisterRegister(
4125 .xor,
4126 tmp_reg.to32(),
4127 tmp_reg.to32(),
4128 ),
4129 .sar => {
4130 try self.asmRegisterRegister(.mov, tmp_reg, first_reg);
4131 try self.asmRegisterImmediate(tag, tmp_reg, Immediate.u(63));
4132 },
4133 else => unreachable,
4134 }
4135 try self.asmRegisterRegisterRegister(info.double_tag, second_reg, first_reg, .cl);
4136 try self.asmRegisterRegister(tag, first_reg, .cl);
4137 try self.asmRegisterImmediate(.cmp, .cl, Immediate.u(64));
4138 try self.asmCmovccRegisterRegister(second_reg, first_reg, .ae);
4139 try self.asmCmovccRegisterRegister(first_reg, tmp_reg, .ae);
4140 try self.asmMemoryRegister(
4141 .mov,
4142 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[1] - dst_off }),
4143 second_reg,
4144 );
4145 try self.asmMemoryRegister(
4146 .mov,
4147 Memory.sib(.qword, .{ .base = .rbp, .disp = info.offsets[0] - dst_off }),
4148 first_reg,
4149 );
4150 },
4151 },
4152 else => return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
4153 @tagName(lhs_mcv),
4154 @tagName(rhs_mcv),
4155 }),
4156 }
4157 } else return self.fail("TODO genShiftBinOpMir between {s} and {s}", .{
4158 @tagName(lhs_mcv),
4159 @tagName(rhs_mcv),
4160 });
3831}4161}
38324162
3833/// Result is always a register.4163/// Result is always a register.
...@@ -3837,68 +4167,61 @@ fn genShiftBinOp(...@@ -3837,68 +4167,61 @@ fn genShiftBinOp(
3837 self: *Self,4167 self: *Self,
3838 tag: Air.Inst.Tag,4168 tag: Air.Inst.Tag,
3839 maybe_inst: ?Air.Inst.Index,4169 maybe_inst: ?Air.Inst.Index,
3840 lhs: MCValue,4170 lhs_mcv: MCValue,
3841 rhs: MCValue,4171 rhs_mcv: MCValue,
3842 lhs_ty: Type,4172 lhs_ty: Type,
3843 rhs_ty: Type,4173 rhs_ty: Type,
3844) !MCValue {4174) !MCValue {
3845 if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {4175 if (lhs_ty.zigTypeTag() == .Vector) {
3846 return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});4176 return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
3847 }4177 }
3848 if (lhs_ty.abiSize(self.target.*) > 8) {4178
4179 assert(rhs_ty.abiSize(self.target.*) == 1);
4180
4181 const lhs_abi_size = lhs_ty.abiSize(self.target.*);
4182 if (lhs_abi_size > 16) {
3849 return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});4183 return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
3850 }4184 }
38514185
3852 assert(rhs_ty.abiSize(self.target.*) == 1);4186 try self.register_manager.getReg(.rcx, null);
4187 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
4188 defer self.register_manager.unlockReg(rcx_lock);
38534189
3854 const lhs_lock: ?RegisterLock = switch (lhs) {4190 const lhs_lock = switch (lhs_mcv) {
3855 .register => |reg| self.register_manager.lockReg(reg),4191 .register => |reg| self.register_manager.lockReg(reg),
3856 else => null,4192 else => null,
3857 };4193 };
3858 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);4194 defer if (lhs_lock) |lock| self.register_manager.unlockReg(lock);
38594195
3860 const rhs_lock: ?RegisterLock = switch (rhs) {4196 const rhs_lock = switch (rhs_mcv) {
3861 .register => |reg| self.register_manager.lockReg(reg),4197 .register => |reg| self.register_manager.lockReg(reg),
3862 else => null,4198 else => null,
3863 };4199 };
3864 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);4200 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
38654201
3866 self.register_manager.getRegAssumeFree(.rcx, null);4202 const dst_mcv: MCValue = dst: {
3867 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
3868 defer self.register_manager.unlockReg(rcx_lock);
3869
3870 const dst: MCValue = blk: {
3871 if (maybe_inst) |inst| {4203 if (maybe_inst) |inst| {
3872 const bin_op = self.air.instructions.items(.data)[inst].bin_op;4204 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3873 // TODO dst can also be a memory location4205 if (self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) break :dst lhs_mcv;
3874 if (self.reuseOperand(inst, bin_op.lhs, 0, lhs) and lhs.isRegister()) {
3875 break :blk lhs;
3876 }
3877 break :blk try self.copyToRegisterWithInstTracking(inst, lhs_ty, lhs);
3878 }4206 }
3879 break :blk MCValue{ .register = try self.copyToTmpRegister(lhs_ty, lhs) };4207 const dst_mcv = try self.allocRegOrMemAdvanced(lhs_ty, maybe_inst, true);
4208 try self.setRegOrMem(lhs_ty, dst_mcv, lhs_mcv);
4209 break :dst dst_mcv;
3880 };4210 };
38814211
3882 const signedness = lhs_ty.intInfo(self.target.*).signedness;4212 const signedness = lhs_ty.intInfo(self.target.*).signedness;
3883 switch (tag) {4213 try self.genShiftBinOpMir(switch (tag) {
3884 .shl => try self.genShiftBinOpMir(switch (signedness) {4214 .shl, .shl_exact => switch (signedness) {
3885 .signed => .sal,4215 .signed => .sal,
3886 .unsigned => .shl,4216 .unsigned => .shl,
3887 }, lhs_ty, dst.register, rhs),4217 },
38884218 .shr, .shr_exact => switch (signedness) {
3889 .shl_exact => try self.genShiftBinOpMir(.shl, lhs_ty, dst.register, rhs),
3890
3891 .shr,
3892 .shr_exact,
3893 => try self.genShiftBinOpMir(switch (signedness) {
3894 .signed => .sar,4219 .signed => .sar,
3895 .unsigned => .shr,4220 .unsigned => .shr,
3896 }, lhs_ty, dst.register, rhs),4221 },
3897
3898 else => unreachable,4222 else => unreachable,
3899 }4223 }, lhs_ty, dst_mcv, rhs_mcv);
39004224 return dst_mcv;
3901 return dst;
3902}4225}
39034226
3904/// Result is always a register.4227/// Result is always a register.
...@@ -3915,7 +4238,8 @@ fn genMulDivBinOp(...@@ -3915,7 +4238,8 @@ fn genMulDivBinOp(
3915 if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {4238 if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {
3916 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});4239 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
3917 }4240 }
3918 if (ty.abiSize(self.target.*) > 8) {4241 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4242 if (abi_size > 8) {
3919 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});4243 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
3920 }4244 }
3921 if (tag == .div_float) {4245 if (tag == .div_float) {
...@@ -3925,10 +4249,8 @@ fn genMulDivBinOp(...@@ -3925,10 +4249,8 @@ fn genMulDivBinOp(
3925 assert(self.register_manager.isRegFree(.rax));4249 assert(self.register_manager.isRegFree(.rax));
3926 assert(self.register_manager.isRegFree(.rdx));4250 assert(self.register_manager.isRegFree(.rdx));
39274251
3928 const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });4252 const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
3929 defer for (reg_locks) |reg| {4253 defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
3930 self.register_manager.unlockReg(reg);
3931 };
39324254
3933 const int_info = ty.intInfo(self.target.*);4255 const int_info = ty.intInfo(self.target.*);
3934 const signedness = int_info.signedness;4256 const signedness = int_info.signedness;
...@@ -3953,35 +4275,24 @@ fn genMulDivBinOp(...@@ -3953,35 +4275,24 @@ fn genMulDivBinOp(
39534275
3954 const mir_tag: Mir.Inst.Tag = switch (signedness) {4276 const mir_tag: Mir.Inst.Tag = switch (signedness) {
3955 .signed => switch (tag) {4277 .signed => switch (tag) {
3956 .mul, .mulwrap => Mir.Inst.Tag.imul,4278 .mul, .mulwrap => .imul,
3957 .div_trunc, .div_exact, .rem => Mir.Inst.Tag.idiv,4279 .div_trunc, .div_exact, .rem => .idiv,
3958 else => unreachable,4280 else => unreachable,
3959 },4281 },
3960 .unsigned => switch (tag) {4282 .unsigned => switch (tag) {
3961 .mul, .mulwrap => Mir.Inst.Tag.mul,4283 .mul, .mulwrap => .mul,
3962 .div_trunc, .div_exact, .rem => Mir.Inst.Tag.div,4284 .div_trunc, .div_exact, .rem => .div,
3963 else => unreachable,4285 else => unreachable,
3964 },4286 },
3965 };4287 };
39664288
3967 try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs);4289 try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs);
39684290
3969 switch (signedness) {4291 return .{ .register = registerAlias(switch (tag) {
3970 .signed => switch (tag) {4292 .mul, .mulwrap, .div_trunc, .div_exact => .rax,
3971 .mul, .mulwrap, .div_trunc, .div_exact => return MCValue{ .register = .rax },4293 .rem => .rdx,
3972 .rem => return MCValue{ .register = .rdx },4294 else => unreachable,
3973 else => unreachable,4295 }, abi_size) };
3974 },
3975 .unsigned => switch (tag) {
3976 .mul, .mulwrap, .div_trunc, .div_exact => return MCValue{
3977 .register = registerAlias(.rax, @intCast(u32, ty.abiSize(self.target.*))),
3978 },
3979 .rem => return MCValue{
3980 .register = registerAlias(.rdx, @intCast(u32, ty.abiSize(self.target.*))),
3981 },
3982 else => unreachable,
3983 },
3984 }
3985 },4296 },
39864297
3987 .mod => {4298 .mod => {
...@@ -3998,14 +4309,14 @@ fn genMulDivBinOp(...@@ -3998,14 +4309,14 @@ fn genMulDivBinOp(
3998 const result: MCValue = if (maybe_inst) |inst|4309 const result: MCValue = if (maybe_inst) |inst|
3999 try self.copyToRegisterWithInstTracking(inst, ty, lhs)4310 try self.copyToRegisterWithInstTracking(inst, ty, lhs)
4000 else4311 else
4001 MCValue{ .register = try self.copyToTmpRegister(ty, lhs) };4312 .{ .register = try self.copyToTmpRegister(ty, lhs) };
4002 try self.genBinOpMir(.sub, ty, result, div_floor);4313 try self.genBinOpMir(.sub, ty, result, div_floor);
40034314
4004 return result;4315 return result;
4005 },4316 },
4006 .unsigned => {4317 .unsigned => {
4007 try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs);4318 try self.genIntMulDivOpMir(.div, ty, .unsigned, lhs, rhs);
4008 return MCValue{ .register = registerAlias(.rdx, @intCast(u32, ty.abiSize(self.target.*))) };4319 return .{ .register = registerAlias(.rdx, abi_size) };
4009 },4320 },
4010 }4321 }
4011 },4322 },
...@@ -4397,7 +4708,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -4397,7 +4708,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
4397 );4708 );
4398 }4709 }
4399 },4710 },
4400 else => return self.fail("TODO getBinOpMir implement large immediate ABI", .{}),4711 else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),
4401 }4712 }
4402 },4713 },
4403 .memory,4714 .memory,
...@@ -4478,28 +4789,28 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu...@@ -4478,28 +4789,28 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
4478 );4789 );
4479 }4790 }
4480 },4791 },
4481 else => return self.fail("TODO getBinOpMir implement large immediate ABI", .{}),4792 else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),
4482 }4793 }
4483 },4794 },
4484 .memory,4795 .memory,
4485 .stack_offset,4796 .stack_offset,
4486 .ptr_stack_offset,4797 .ptr_stack_offset,
4487 => {4798 => {
4488 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});4799 return self.fail("TODO implement x86 genBinOpMir source memory", .{});
4489 },4800 },
4490 .linker_load => {4801 .linker_load => {
4491 return self.fail("TODO implement x86 ADD/SUB/CMP source symbol at index in linker", .{});4802 return self.fail("TODO implement x86 genBinOpMir source symbol at index in linker", .{});
4492 },4803 },
4493 .eflags => {4804 .eflags => {
4494 return self.fail("TODO implement x86 ADD/SUB/CMP source eflags", .{});4805 return self.fail("TODO implement x86 genBinOpMir source eflags", .{});
4495 },4806 },
4496 }4807 }
4497 },4808 },
4498 .memory => {4809 .memory => {
4499 return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});4810 return self.fail("TODO implement x86 genBinOpMir destination memory", .{});
4500 },4811 },
4501 .linker_load => {4812 .linker_load => {
4502 return self.fail("TODO implement x86 ADD/SUB/CMP destination symbol at index", .{});4813 return self.fail("TODO implement x86 genBinOpMir destination symbol at index", .{});
4503 },4814 },
4504 }4815 }
4505}4816}
...@@ -5437,7 +5748,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !...@@ -5437,7 +5748,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
5437 const tmp_reg = try self.copyToTmpRegister(ty, operand);5748 const tmp_reg = try self.copyToTmpRegister(ty, operand);
5438 if (err_off > 0) {5749 if (err_off > 0) {
5439 const shift = @intCast(u6, err_off * 8);5750 const shift = @intCast(u6, err_off * 8);
5440 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{ .immediate = shift });5751 try self.genShiftBinOpMir(.shr, ty, .{ .register = tmp_reg }, .{ .immediate = shift });
5441 } else {5752 } else {
5442 try self.truncateRegister(Type.anyerror, tmp_reg);5753 try self.truncateRegister(Type.anyerror, tmp_reg);
5443 }5754 }
...@@ -5945,13 +6256,23 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -5945,13 +6256,23 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
5945 const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);6256 const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
5946 extra_i += inputs.len;6257 extra_i += inputs.len;
59476258
5948 const dead = !is_volatile and self.liveness.isUnused(inst);6259 var result: MCValue = .none;
5949 const result: MCValue = if (dead) .dead else result: {6260 if (!is_volatile and self.liveness.isUnused(inst)) result = .dead else {
6261 var args = std.StringArrayHashMap(MCValue).init(self.gpa);
6262 try args.ensureTotalCapacity(outputs.len + inputs.len + clobbers_len);
6263 defer {
6264 for (args.values()) |arg| switch (arg) {
6265 .register => |reg| self.register_manager.unlockReg(.{ .register = reg }),
6266 else => {},
6267 };
6268 args.deinit();
6269 }
6270
5950 if (outputs.len > 1) {6271 if (outputs.len > 1) {
5951 return self.fail("TODO implement codegen for asm with more than 1 output", .{});6272 return self.fail("TODO implement codegen for asm with more than 1 output", .{});
5952 }6273 }
59536274
5954 const output_constraint: ?[]const u8 = for (outputs) |output| {6275 for (outputs) |output| {
5955 if (output != .none) {6276 if (output != .none) {
5956 return self.fail("TODO implement codegen for non-expr asm", .{});6277 return self.fail("TODO implement codegen for non-expr asm", .{});
5957 }6278 }
...@@ -5962,8 +6283,21 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -5962,8 +6283,21 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
5962 // for the string, we still use the next u32 for the null terminator.6283 // for the string, we still use the next u32 for the null terminator.
5963 extra_i += (constraint.len + name.len + (2 + 3)) / 4;6284 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
59646285
5965 break constraint;6286 const mcv: MCValue = if (mem.eql(u8, constraint, "=r"))
5966 } else null;6287 .{ .register = self.register_manager.tryAllocReg(inst, gp) orelse
6288 return self.fail("ran out of registers lowering inline asm", .{}) }
6289 else if (mem.startsWith(u8, constraint, "={") and mem.endsWith(u8, constraint, "}"))
6290 .{ .register = parseRegName(constraint["={".len .. constraint.len - "}".len]) orelse
6291 return self.fail("unrecognized register constraint: '{s}'", .{constraint}) }
6292 else
6293 return self.fail("unrecognized constraint: '{s}'", .{constraint});
6294 args.putAssumeCapacity(name, mcv);
6295 switch (mcv) {
6296 .register => |reg| _ = self.register_manager.lockRegAssumeUnused(reg),
6297 else => {},
6298 }
6299 if (output == .none) result = mcv;
6300 }
59676301
5968 for (inputs) |input| {6302 for (inputs) |input| {
5969 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);6303 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
...@@ -5997,52 +6331,73 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {...@@ -5997,52 +6331,73 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
5997 }6331 }
5998 }6332 }
59996333
6000 const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];6334 const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
60016335 var line_it = mem.tokenize(u8, asm_source, "\n\r");
6002 {6336 while (line_it.next()) |line| {
6003 var iter = std.mem.tokenize(u8, asm_source, "\n\r");6337 var mnem_it = mem.tokenize(u8, line, " \t");
6004 while (iter.next()) |ins| {6338 const mnem = mnem_it.next() orelse continue;
6005 if (mem.eql(u8, ins, "syscall")) {6339 if (mem.startsWith(u8, mnem, "#")) continue;
6006 try self.asmOpOnly(.syscall);6340 var arg_it = mem.tokenize(u8, mnem_it.rest(), ", ");
6007 } else if (mem.indexOf(u8, ins, "push")) |_| {6341 if (std.ascii.eqlIgnoreCase(mnem, "syscall")) {
6008 const arg = ins[4..];6342 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6009 if (mem.indexOf(u8, arg, "$")) |l| {6343 return self.fail("Too many operands: '{s}'", .{line});
6010 const n = std.fmt.parseInt(u8, ins[4 + l + 1 ..], 10) catch {6344 try self.asmOpOnly(.syscall);
6011 return self.fail("TODO implement more inline asm int parsing", .{});6345 } else if (std.ascii.eqlIgnoreCase(mnem, "push")) {
6012 };6346 const src = arg_it.next() orelse
6013 try self.asmImmediate(.push, Immediate.u(n));6347 return self.fail("Not enough operands: '{s}'", .{line});
6014 } else if (mem.indexOf(u8, arg, "%%")) |l| {6348 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6015 const reg_name = ins[4 + l + 2 ..];6349 return self.fail("Too many operands: '{s}'", .{line});
6016 const reg = parseRegName(reg_name) orelse6350 if (mem.startsWith(u8, src, "$")) {
6017 return self.fail("unrecognized register: '{s}'", .{reg_name});6351 const imm = std.fmt.parseInt(u32, src["$".len..], 0) catch
6018 try self.asmRegister(.push, reg);6352 return self.fail("Invalid immediate: '{s}'", .{src});
6019 } else return self.fail("TODO more push operands", .{});6353 try self.asmImmediate(.push, Immediate.u(imm));
6020 } else if (mem.indexOf(u8, ins, "pop")) |_| {6354 } else if (mem.startsWith(u8, src, "%%")) {
6021 const arg = ins[3..];6355 const reg = parseRegName(src["%%".len..]) orelse
6022 if (mem.indexOf(u8, arg, "%%")) |l| {6356 return self.fail("Invalid register: '{s}'", .{src});
6023 const reg_name = ins[3 + l + 2 ..];6357 try self.asmRegister(.push, reg);
6024 const reg = parseRegName(reg_name) orelse6358 } else return self.fail("Unsupported operand: '{s}'", .{src});
6025 return self.fail("unrecognized register: '{s}'", .{reg_name});6359 } else if (std.ascii.eqlIgnoreCase(mnem, "pop")) {
6026 try self.asmRegister(.pop, reg);6360 const dst = arg_it.next() orelse
6027 } else return self.fail("TODO more pop operands", .{});6361 return self.fail("Not enough operands: '{s}'", .{line});
6028 } else {6362 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6029 return self.fail("TODO implement support for more x86 assembly instructions", .{});6363 return self.fail("Too many operands: '{s}'", .{line});
6364 if (mem.startsWith(u8, dst, "%%")) {
6365 const reg = parseRegName(dst["%%".len..]) orelse
6366 return self.fail("Invalid register: '{s}'", .{dst});
6367 try self.asmRegister(.pop, reg);
6368 } else return self.fail("Unsupported operand: '{s}'", .{dst});
6369 } else if (std.ascii.eqlIgnoreCase(mnem, "movq")) {
6370 const src = arg_it.next() orelse
6371 return self.fail("Not enough operands: '{s}'", .{line});
6372 const dst = arg_it.next() orelse
6373 return self.fail("Not enough operands: '{s}'", .{line});
6374 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6375 return self.fail("Too many operands: '{s}'", .{line});
6376 if (mem.startsWith(u8, src, "%%")) {
6377 const colon = mem.indexOfScalarPos(u8, src, "%%".len + 2, ':');
6378 const src_reg = parseRegName(src["%%".len .. colon orelse src.len]) orelse
6379 return self.fail("Invalid register: '{s}'", .{src});
6380 if (colon) |colon_pos| {
6381 const src_disp = std.fmt.parseInt(i32, src[colon_pos + 1 ..], 0) catch
6382 return self.fail("Invalid immediate: '{s}'", .{src});
6383 if (mem.startsWith(u8, dst, "%[") and mem.endsWith(u8, dst, "]")) {
6384 switch (args.get(dst["%[".len .. dst.len - "]".len]) orelse
6385 return self.fail("no matching constraint for: '{s}'", .{dst})) {
6386 .register => |dst_reg| try self.asmRegisterMemory(
6387 .mov,
6388 dst_reg,
6389 Memory.sib(.qword, .{ .base = src_reg, .disp = src_disp }),
6390 ),
6391 else => return self.fail("Invalid constraint: '{s}'", .{dst}),
6392 }
6393 } else return self.fail("Unsupported operand: '{s}'", .{dst});
6394 } else return self.fail("Unsupported operand: '{s}'", .{src});
6030 }6395 }
6396 } else {
6397 return self.fail("Unsupported instruction: '{s}'", .{mnem});
6031 }6398 }
6032 }6399 }
60336400 }
6034 if (output_constraint) |output| {
6035 if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
6036 return self.fail("unrecognized asm output constraint: '{s}'", .{output});
6037 }
6038 const reg_name = output[2 .. output.len - 1];
6039 const reg = parseRegName(reg_name) orelse
6040 return self.fail("unrecognized register: '{s}'", .{reg_name});
6041 break :result .{ .register = reg };
6042 } else {
6043 break :result .none;
6044 }
6045 };
60466401
6047 simple: {6402 simple: {
6048 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);6403 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
...@@ -6277,20 +6632,25 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl...@@ -6277,20 +6632,25 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: i32, mcv: MCValue, opts: Inl
6277 .disp = -stack_offset,6632 .disp = -stack_offset,
6278 }), immediate);6633 }), immediate);
6279 },6634 },
6280 8 => {6635 3, 5...7 => unreachable,
6636 else => {
6281 // 64 bit write to memory would take two mov's anyways so we6637 // 64 bit write to memory would take two mov's anyways so we
6282 // insted just use two 32 bit writes to avoid register allocation6638 // insted just use two 32 bit writes to avoid register allocation
6283 try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{6639 var offset: i32 = 0;
6284 .base = base_reg,6640 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
6285 .disp = -stack_offset + 4,6641 .mov,
6286 }), Immediate.u(@truncate(u32, x_big >> 32)));6642 Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }),
6287 try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{6643 if (ty.isSignedInt())
6288 .base = base_reg,6644 Immediate.s(@truncate(
6289 .disp = -stack_offset,6645 i32,
6290 }), Immediate.u(@truncate(u32, x_big)));6646 @bitCast(i64, x_big) >> (math.cast(u6, offset * 8) orelse 63),
6291 },6647 ))
6292 else => {6648 else
6293 return self.fail("TODO implement set abi_size=large stack variable with immediate", .{});6649 Immediate.u(@truncate(
6650 u32,
6651 if (math.cast(u6, offset * 8)) |shift| x_big >> shift else 0,
6652 )),
6653 );
6294 },6654 },
6295 }6655 }
6296 },6656 },
...@@ -6391,7 +6751,7 @@ fn genInlineMemcpyRegisterRegister(...@@ -6391,7 +6751,7 @@ fn genInlineMemcpyRegisterRegister(
6391 }), registerAlias(tmp_reg, nearest_power_of_two));6751 }), registerAlias(tmp_reg, nearest_power_of_two));
63926752
6393 if (nearest_power_of_two > 1) {6753 if (nearest_power_of_two > 1) {
6394 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{6754 try self.genShiftBinOpMir(.shr, ty, .{ .register = tmp_reg }, .{
6395 .immediate = nearest_power_of_two * 8,6755 .immediate = nearest_power_of_two * 8,
6396 });6756 });
6397 }6757 }
...@@ -6894,20 +7254,37 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -6894,20 +7254,37 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
6894 const ptr_ty = self.air.typeOf(extra.ptr);7254 const ptr_ty = self.air.typeOf(extra.ptr);
6895 const ptr_mcv = try self.resolveInst(extra.ptr);7255 const ptr_mcv = try self.resolveInst(extra.ptr);
6896 const val_ty = self.air.typeOf(extra.expected_value);7256 const val_ty = self.air.typeOf(extra.expected_value);
7257 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
7258
7259 try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
7260 const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });
7261 for (regs_lock) |lock| self.register_manager.unlockReg(lock);
68977262
6898 const exp_mcv = try self.resolveInst(extra.expected_value);7263 const exp_mcv = try self.resolveInst(extra.expected_value);
6899 try self.genSetReg(val_ty, .rax, exp_mcv);7264 if (val_abi_size > 8) switch (exp_mcv) {
7265 .stack_offset => |exp_off| {
7266 try self.genSetReg(Type.usize, .rax, .{ .stack_offset = exp_off - 0 });
7267 try self.genSetReg(Type.usize, .rdx, .{ .stack_offset = exp_off - 8 });
7268 },
7269 else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
7270 } else try self.genSetReg(val_ty, .rax, exp_mcv);
6900 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);7271 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
6901 defer self.register_manager.unlockReg(rax_lock);7272 defer self.register_manager.unlockReg(rax_lock);
69027273
6903 const new_mcv = try self.resolveInst(extra.new_value);7274 const new_mcv = try self.resolveInst(extra.new_value);
6904 const new_reg = try self.copyToTmpRegister(val_ty, new_mcv);7275 const new_reg: Register = if (val_abi_size > 8) switch (new_mcv) {
7276 .stack_offset => |new_off| new: {
7277 try self.genSetReg(Type.usize, .rbx, .{ .stack_offset = new_off - 0 });
7278 try self.genSetReg(Type.usize, .rcx, .{ .stack_offset = new_off - 8 });
7279 break :new undefined;
7280 },
7281 else => return self.fail("TODO implement cmpxchg for {s}", .{@tagName(exp_mcv)}),
7282 } else try self.copyToTmpRegister(val_ty, new_mcv);
6905 const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);7283 const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);
6906 defer self.register_manager.unlockReg(new_lock);7284 defer self.register_manager.unlockReg(new_lock);
69077285
6908 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
6909 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);7286 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
6910 const ptr_mem: Memory = switch (ptr_mcv) {7287 const ptr_mem = switch (ptr_mcv) {
6911 .register => |reg| Memory.sib(ptr_size, .{ .base = reg }),7288 .register => |reg| Memory.sib(ptr_size, .{ .base = reg }),
6912 .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),7289 .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
6913 else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }),7290 else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }),
...@@ -6916,16 +7293,30 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -6916,16 +7293,30 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
6916 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);7293 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
69177294
6918 try self.spillEflagsIfOccupied();7295 try self.spillEflagsIfOccupied();
6919 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{7296 if (val_abi_size <= 8) {
6920 .r1 = new_reg,7297 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
6921 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),7298 .r = registerAlias(new_reg, val_abi_size),
6922 } } });7299 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
7300 } } });
7301 } else {
7302 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
7303 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
7304 } });
7305 }
69237306
6924 const result: MCValue = result: {7307 const result: MCValue = result: {
6925 if (self.liveness.isUnused(inst)) break :result .dead;7308 if (self.liveness.isUnused(inst)) break :result .dead;
69267309
6927 self.eflags_inst = inst;7310 if (val_abi_size <= 8) {
6928 break :result .{ .register_overflow = .{ .reg = .rax, .eflags = .ne } };7311 self.eflags_inst = inst;
7312 break :result .{ .register_overflow = .{ .reg = .rax, .eflags = .ne } };
7313 }
7314
7315 const dst_mcv = try self.allocRegOrMem(inst, false);
7316 try self.genSetStack(Type.bool, dst_mcv.stack_offset - 16, .{ .eflags = .ne }, .{});
7317 try self.genSetStack(Type.usize, dst_mcv.stack_offset - 8, .{ .register = .rdx }, .{});
7318 try self.genSetStack(Type.usize, dst_mcv.stack_offset - 0, .{ .register = .rax }, .{});
7319 break :result dst_mcv;
6929 };7320 };
6930 return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });7321 return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
6931}7322}
...@@ -6938,9 +7329,10 @@ fn atomicOp(...@@ -6938,9 +7329,10 @@ fn atomicOp(
6938 ptr_ty: Type,7329 ptr_ty: Type,
6939 val_ty: Type,7330 val_ty: Type,
6940 unused: bool,7331 unused: bool,
6941 op: ?std.builtin.AtomicRmwOp,7332 rmw_op: ?std.builtin.AtomicRmwOp,
6942 order: std.builtin.AtomicOrder,7333 order: std.builtin.AtomicOrder,
6943) InnerError!void {7334) InnerError!void {
7335 const dst_mcv = MCValue{ .register = dst_reg };
6944 const dst_lock = self.register_manager.lockReg(dst_reg);7336 const dst_lock = self.register_manager.lockReg(dst_reg);
6945 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);7337 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
69467338
...@@ -6958,7 +7350,7 @@ fn atomicOp(...@@ -6958,7 +7350,7 @@ fn atomicOp(
69587350
6959 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));7351 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
6960 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);7352 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
6961 const ptr_mem: Memory = switch (ptr_mcv) {7353 const ptr_mem = switch (ptr_mcv) {
6962 .register => |reg| Memory.sib(ptr_size, .{ .base = reg }),7354 .register => |reg| Memory.sib(ptr_size, .{ .base = reg }),
6963 .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),7355 .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
6964 else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }),7356 else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }),
...@@ -6966,48 +7358,197 @@ fn atomicOp(...@@ -6966,48 +7358,197 @@ fn atomicOp(
6966 const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;7358 const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;
6967 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);7359 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
69687360
6969 try self.genSetReg(val_ty, dst_reg, val_mcv);7361 const method: enum { lock, loop, libcall } = if (val_ty.isRuntimeFloat())
69707362 .loop
6971 const need_loop = val_ty.isRuntimeFloat() or if (op) |rmw| switch (rmw) {7363 else switch (rmw_op orelse .Xchg) {
6972 .Xchg, .Add, .Sub => false,7364 .Xchg,
6973 .And, .Or, .Xor => !unused,7365 .Add,
6974 .Nand, .Max, .Min => true,7366 .Sub,
6975 } else false;7367 => if (val_abi_size <= 8) .lock else if (val_abi_size <= 16) .loop else .libcall,
6976 if (!need_loop) {7368 .And,
6977 const tag: Mir.Inst.Tag = if (op) |rmw| switch (rmw) {7369 .Or,
6978 .Xchg => if (unused) .mov else .xchg,7370 .Xor,
6979 .Add => if (unused) .add else .xadd,7371 => if (val_abi_size <= 8 and unused) .lock else if (val_abi_size <= 16) .loop else .libcall,
6980 .Sub => if (unused) .sub else .xadd,7372 .Nand,
6981 .And => .@"and",7373 .Max,
6982 .Or => .@"or",7374 .Min,
6983 .Xor => .xor,7375 => if (val_abi_size <= 16) .loop else .libcall,
6984 else => unreachable,7376 };
6985 } else switch (order) {7377 switch (method) {
6986 .Unordered, .Monotonic, .Release, .AcqRel => .mov,7378 .lock => {
6987 .Acquire => unreachable,7379 const tag: Mir.Inst.Tag = if (rmw_op) |op| switch (op) {
6988 .SeqCst => .xchg,7380 .Xchg => if (unused) .mov else .xchg,
6989 };7381 .Add => if (unused) .add else .xadd,
6990 if (op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {7382 .Sub => if (unused) .sub else .xadd,
6991 try self.genUnOpMir(.neg, val_ty, .{ .register = dst_reg });7383 .And => .@"and",
6992 }7384 .Or => .@"or",
6993 _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {7385 .Xor => .xor,
6994 .mov, .xchg => .mr_sib,7386 else => unreachable,
6995 .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,7387 } else switch (order) {
6996 else => unreachable,7388 .Unordered, .Monotonic, .Release, .AcqRel => .mov,
6997 }, .data = .{ .rx = .{7389 .Acquire => unreachable,
6998 .r1 = registerAlias(dst_reg, val_abi_size),7390 .SeqCst => .xchg,
6999 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),7391 };
7000 } } });7392
7001 return;7393 try self.genSetReg(val_ty, dst_reg, val_mcv);
7002 }7394 if (rmw_op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {
7395 try self.genUnOpMir(.neg, val_ty, .{ .register = dst_reg });
7396 }
7397 _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {
7398 .mov, .xchg => .mr_sib,
7399 .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
7400 else => unreachable,
7401 }, .data = .{ .rx = .{
7402 .r = registerAlias(dst_reg, val_abi_size),
7403 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
7404 } } });
7405 },
7406 .loop => _ = try self.asmJccReloc(if (val_abi_size <= 8) loop: {
7407 try self.genSetReg(val_ty, dst_reg, val_mcv);
7408 try self.asmRegisterMemory(.mov, registerAlias(.rax, val_abi_size), ptr_mem);
7409 const loop = @intCast(u32, self.mir_instructions.len);
7410 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
7411 try self.genSetReg(val_ty, dst_reg, .{ .register = .rax });
7412 }
7413 if (rmw_op) |op| switch (op) {
7414 .Xchg => try self.genSetReg(val_ty, dst_reg, val_mcv),
7415 .Add => try self.genBinOpMir(.add, val_ty, dst_mcv, val_mcv),
7416 .Sub => try self.genBinOpMir(.sub, val_ty, dst_mcv, val_mcv),
7417 .And => try self.genBinOpMir(.@"and", val_ty, dst_mcv, val_mcv),
7418 .Nand => {
7419 try self.genBinOpMir(.@"and", val_ty, dst_mcv, val_mcv);
7420 try self.genUnOpMir(.not, val_ty, dst_mcv);
7421 },
7422 .Or => try self.genBinOpMir(.@"or", val_ty, dst_mcv, val_mcv),
7423 .Xor => try self.genBinOpMir(.xor, val_ty, dst_mcv, val_mcv),
7424 .Min, .Max => {
7425 const cc: Condition = switch (if (val_ty.isAbiInt())
7426 val_ty.intInfo(self.target.*).signedness
7427 else
7428 .unsigned) {
7429 .unsigned => switch (op) {
7430 .Min => .a,
7431 .Max => .b,
7432 else => unreachable,
7433 },
7434 .signed => switch (op) {
7435 .Min => .g,
7436 .Max => .l,
7437 else => unreachable,
7438 },
7439 };
70037440
7004 return self.fail("TODO implement x86 atomic loop", .{});7441 try self.genBinOpMir(.cmp, val_ty, dst_mcv, val_mcv);
7442 switch (val_mcv) {
7443 .register => |val_reg| try self.asmCmovccRegisterRegister(
7444 registerAlias(dst_reg, val_abi_size),
7445 registerAlias(val_reg, val_abi_size),
7446 cc,
7447 ),
7448 .stack_offset => |val_off| try self.asmCmovccRegisterMemory(
7449 registerAlias(dst_reg, val_abi_size),
7450 Memory.sib(
7451 Memory.PtrSize.fromSize(val_abi_size),
7452 .{ .base = .rbp, .disp = -val_off },
7453 ),
7454 cc,
7455 ),
7456 else => {
7457 const val_reg = try self.copyToTmpRegister(val_ty, val_mcv);
7458 try self.asmCmovccRegisterRegister(
7459 registerAlias(dst_reg, val_abi_size),
7460 registerAlias(val_reg, val_abi_size),
7461 cc,
7462 );
7463 },
7464 }
7465 },
7466 };
7467 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
7468 .r = registerAlias(dst_reg, val_abi_size),
7469 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
7470 } } });
7471 break :loop loop;
7472 } else loop: {
7473 try self.asmRegisterMemory(.mov, .rax, Memory.sib(.qword, .{
7474 .base = ptr_mem.sib.base,
7475 .scale_index = ptr_mem.sib.scale_index,
7476 .disp = ptr_mem.sib.disp + 0,
7477 }));
7478 try self.asmRegisterMemory(.mov, .rdx, Memory.sib(.qword, .{
7479 .base = ptr_mem.sib.base,
7480 .scale_index = ptr_mem.sib.scale_index,
7481 .disp = ptr_mem.sib.disp + 8,
7482 }));
7483 const loop = @intCast(u32, self.mir_instructions.len);
7484 switch (val_mcv) {
7485 .stack_offset => |val_off| {
7486 const val_lo_mem = Memory.sib(.qword, .{ .base = .rbp, .disp = 0 - val_off });
7487 const val_hi_mem = Memory.sib(.qword, .{ .base = .rbp, .disp = 8 - val_off });
7488
7489 if (rmw_op != std.builtin.AtomicRmwOp.Xchg) {
7490 try self.asmRegisterRegister(.mov, .rbx, .rax);
7491 try self.asmRegisterRegister(.mov, .rcx, .rdx);
7492 }
7493 if (rmw_op) |op| switch (op) {
7494 .Xchg => {
7495 try self.asmRegisterMemory(.mov, .rbx, val_lo_mem);
7496 try self.asmRegisterMemory(.mov, .rcx, val_hi_mem);
7497 },
7498 .Add => {
7499 try self.asmRegisterMemory(.add, .rbx, val_lo_mem);
7500 try self.asmRegisterMemory(.adc, .rcx, val_hi_mem);
7501 },
7502 .Sub => {
7503 try self.asmRegisterMemory(.sub, .rbx, val_lo_mem);
7504 try self.asmRegisterMemory(.sbb, .rcx, val_hi_mem);
7505 },
7506 .And => {
7507 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
7508 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
7509 },
7510 .Nand => {
7511 try self.asmRegisterMemory(.@"and", .rbx, val_lo_mem);
7512 try self.asmRegisterMemory(.@"and", .rcx, val_hi_mem);
7513 try self.asmRegister(.not, .rbx);
7514 try self.asmRegister(.not, .rcx);
7515 },
7516 .Or => {
7517 try self.asmRegisterMemory(.@"or", .rbx, val_lo_mem);
7518 try self.asmRegisterMemory(.@"or", .rcx, val_hi_mem);
7519 },
7520 .Xor => {
7521 try self.asmRegisterMemory(.xor, .rbx, val_lo_mem);
7522 try self.asmRegisterMemory(.xor, .rcx, val_hi_mem);
7523 },
7524 else => return self.fail(
7525 "TODO implement x86 atomic loop for large abi {s}",
7526 .{@tagName(op)},
7527 ),
7528 };
7529 },
7530 else => return self.fail(
7531 "TODO implement x86 atomic loop for large abi {s}",
7532 .{@tagName(val_mcv)},
7533 ),
7534 }
7535 _ = try self.addInst(.{ .tag = .cmpxchgb, .ops = .lock_m_sib, .data = .{
7536 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
7537 } });
7538 break :loop loop;
7539 }, .ne),
7540 .libcall => return self.fail("TODO implement x86 atomic libcall", .{}),
7541 }
7005}7542}
70067543
7007fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {7544fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
7008 const pl_op = self.air.instructions.items(.data)[inst].pl_op;7545 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
7009 const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;7546 const extra = self.air.extraData(Air.AtomicRmw, pl_op.payload).data;
70107547
7548 try self.spillRegisters(&.{ .rax, .rdx, .rbx, .rcx });
7549 const regs_lock = self.register_manager.lockRegsAssumeUnused(4, .{ .rax, .rdx, .rbx, .rcx });
7550 defer for (regs_lock) |lock| self.register_manager.unlockReg(lock);
7551
7011 const unused = self.liveness.isUnused(inst);7552 const unused = self.liveness.isUnused(inst);
7012 const dst_reg = try self.register_manager.allocReg(if (unused) null else inst, gp);7553 const dst_reg = try self.register_manager.allocReg(if (unused) null else inst, gp);
70137554
...@@ -7587,8 +8128,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {...@@ -7587,8 +8128,8 @@ fn truncateRegister(self: *Self, ty: Type, reg: Register) !void {
7587 switch (int_info.signedness) {8128 switch (int_info.signedness) {
7588 .signed => {8129 .signed => {
7589 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);8130 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
7590 try self.genShiftBinOpMir(.sal, Type.isize, reg, .{ .immediate = shift });8131 try self.genShiftBinOpMir(.sal, Type.isize, .{ .register = reg }, .{ .immediate = shift });
7591 try self.genShiftBinOpMir(.sar, Type.isize, reg, .{ .immediate = shift });8132 try self.genShiftBinOpMir(.sar, Type.isize, .{ .register = reg }, .{ .immediate = shift });
7592 },8133 },
7593 .unsigned => {8134 .unsigned => {
7594 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);8135 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
src/arch/x86_64/Emit.zig+58-27
...@@ -121,7 +121,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {...@@ -121,7 +121,9 @@ pub fn lowerMir(emit: *Emit) InnerError!void {
121 .sbb,121 .sbb,
122 .sfence,122 .sfence,
123 .shl,123 .shl,
124 .shld,
124 .shr,125 .shr,
126 .shrd,
125 .sub,127 .sub,
126 .syscall,128 .syscall,
127 .@"test",129 .@"test",
...@@ -231,10 +233,10 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -231,10 +233,10 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
231 const prefix: Instruction.Prefix = switch (ops) {233 const prefix: Instruction.Prefix = switch (ops) {
232 .lock_m_sib,234 .lock_m_sib,
233 .lock_m_rip,235 .lock_m_rip,
234 .lock_mi_u_sib,236 .lock_mi_sib_u,
235 .lock_mi_u_rip,237 .lock_mi_rip_u,
236 .lock_mi_s_sib,238 .lock_mi_sib_s,
237 .lock_mi_s_rip,239 .lock_mi_rip_s,
238 .lock_mr_sib,240 .lock_mr_sib,
239 .lock_mr_rip,241 .lock_mr_rip,
240 .lock_moffs_rax,242 .lock_moffs_rax,
...@@ -249,31 +251,36 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -249,31 +251,36 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
249251
250 switch (ops) {252 switch (ops) {
251 .none => {},253 .none => {},
252 .imm_s => op1 = .{ .imm = Immediate.s(@bitCast(i32, data.imm)) },254 .i_s => op1 = .{ .imm = Immediate.s(@bitCast(i32, data.i)) },
253 .imm_u => op1 = .{ .imm = Immediate.u(data.imm) },255 .i_u => op1 = .{ .imm = Immediate.u(data.i) },
254 .r => op1 = .{ .reg = data.r },256 .r => op1 = .{ .reg = data.r },
255 .rr => {257 .rr => {
256 op1 = .{ .reg = data.rr.r1 };258 op1 = .{ .reg = data.rr.r1 };
257 op2 = .{ .reg = data.rr.r2 };259 op2 = .{ .reg = data.rr.r2 };
258 },260 },
261 .rrr => {
262 op1 = .{ .reg = data.rrr.r1 };
263 op2 = .{ .reg = data.rrr.r2 };
264 op3 = .{ .reg = data.rrr.r3 };
265 },
259 .ri_s, .ri_u => {266 .ri_s, .ri_u => {
260 const imm = switch (ops) {267 const imm = switch (ops) {
261 .ri_s => Immediate.s(@bitCast(i32, data.ri.imm)),268 .ri_s => Immediate.s(@bitCast(i32, data.ri.i)),
262 .ri_u => Immediate.u(data.ri.imm),269 .ri_u => Immediate.u(data.ri.i),
263 else => unreachable,270 else => unreachable,
264 };271 };
265 op1 = .{ .reg = data.ri.r1 };272 op1 = .{ .reg = data.ri.r };
266 op2 = .{ .imm = imm };273 op2 = .{ .imm = imm };
267 },274 },
268 .ri64 => {275 .ri64 => {
269 const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;276 const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;
270 op1 = .{ .reg = data.rx.r1 };277 op1 = .{ .reg = data.rx.r };
271 op2 = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };278 op2 = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };
272 },279 },
273 .rri_s, .rri_u => {280 .rri_s, .rri_u => {
274 const imm = switch (ops) {281 const imm = switch (ops) {
275 .rri_s => Immediate.s(@bitCast(i32, data.rri.imm)),282 .rri_s => Immediate.s(@bitCast(i32, data.rri.i)),
276 .rri_u => Immediate.u(data.rri.imm),283 .rri_u => Immediate.u(data.rri.i),
277 else => unreachable,284 else => unreachable,
278 };285 };
279 op1 = .{ .reg = data.rri.r1 };286 op1 = .{ .reg = data.rri.r1 };
...@@ -288,21 +295,21 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -288,21 +295,21 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
288 const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;295 const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
289 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };296 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
290 },297 },
291 .mi_s_sib, .mi_u_sib, .lock_mi_s_sib, .lock_mi_u_sib => {298 .mi_sib_s, .mi_sib_u, .lock_mi_sib_s, .lock_mi_sib_u => {
292 const msib = emit.mir.extraData(Mir.MemorySib, data.xi.payload).data;299 const msib = emit.mir.extraData(Mir.MemorySib, data.ix.payload).data;
293 const imm = switch (ops) {300 const imm = switch (ops) {
294 .mi_s_sib, .lock_mi_s_sib => Immediate.s(@bitCast(i32, data.xi.imm)),301 .mi_sib_s, .lock_mi_sib_s => Immediate.s(@bitCast(i32, data.ix.i)),
295 .mi_u_sib, .lock_mi_u_sib => Immediate.u(data.xi.imm),302 .mi_sib_u, .lock_mi_sib_u => Immediate.u(data.ix.i),
296 else => unreachable,303 else => unreachable,
297 };304 };
298 op1 = .{ .mem = Mir.MemorySib.decode(msib) };305 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
299 op2 = .{ .imm = imm };306 op2 = .{ .imm = imm };
300 },307 },
301 .mi_u_rip, .mi_s_rip, .lock_mi_u_rip, .lock_mi_s_rip => {308 .mi_rip_u, .mi_rip_s, .lock_mi_rip_u, .lock_mi_rip_s => {
302 const mrip = emit.mir.extraData(Mir.MemoryRip, data.xi.payload).data;309 const mrip = emit.mir.extraData(Mir.MemoryRip, data.ix.payload).data;
303 const imm = switch (ops) {310 const imm = switch (ops) {
304 .mi_s_rip, .lock_mi_s_rip => Immediate.s(@bitCast(i32, data.xi.imm)),311 .mi_rip_s, .lock_mi_rip_s => Immediate.s(@bitCast(i32, data.ix.i)),
305 .mi_u_rip, .lock_mi_u_rip => Immediate.u(data.xi.imm),312 .mi_rip_u, .lock_mi_rip_u => Immediate.u(data.ix.i),
306 else => unreachable,313 else => unreachable,
307 };314 };
308 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };315 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
...@@ -310,7 +317,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -310,7 +317,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
310 },317 },
311 .rm_sib, .mr_sib, .lock_mr_sib => {318 .rm_sib, .mr_sib, .lock_mr_sib => {
312 const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;319 const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
313 const op_r = .{ .reg = data.rx.r1 };320 const op_r = .{ .reg = data.rx.r };
314 const op_m = .{ .mem = Mir.MemorySib.decode(msib) };321 const op_m = .{ .mem = Mir.MemorySib.decode(msib) };
315 switch (ops) {322 switch (ops) {
316 .rm_sib => {323 .rm_sib => {
...@@ -326,7 +333,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -326,7 +333,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
326 },333 },
327 .rm_rip, .mr_rip, .lock_mr_rip => {334 .rm_rip, .mr_rip, .lock_mr_rip => {
328 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;335 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
329 const op_r = .{ .reg = data.rx.r1 };336 const op_r = .{ .reg = data.rx.r };
330 const op_m = .{ .mem = Mir.MemoryRip.decode(mrip) };337 const op_m = .{ .mem = Mir.MemoryRip.decode(mrip) };
331 switch (ops) {338 switch (ops) {
332 .rm_rip => {339 .rm_rip => {
...@@ -340,6 +347,30 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE...@@ -340,6 +347,30 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
340 else => unreachable,347 else => unreachable,
341 }348 }
342 },349 },
350 .mrr_sib => {
351 const msib = emit.mir.extraData(Mir.MemorySib, data.rrx.payload).data;
352 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
353 op2 = .{ .reg = data.rrx.r1 };
354 op2 = .{ .reg = data.rrx.r2 };
355 },
356 .mrr_rip => {
357 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rrx.payload).data;
358 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
359 op2 = .{ .reg = data.rrx.r1 };
360 op2 = .{ .reg = data.rrx.r2 };
361 },
362 .mri_sib => {
363 const msib = emit.mir.extraData(Mir.MemorySib, data.rix.payload).data;
364 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
365 op2 = .{ .reg = data.rix.r };
366 op3 = .{ .imm = Immediate.u(data.rix.i) };
367 },
368 .mri_rip => {
369 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rix.payload).data;
370 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
371 op2 = .{ .reg = data.rix.r };
372 op3 = .{ .imm = Immediate.u(data.rix.i) };
373 },
343 else => return emit.fail("TODO handle generic encoding: {s}, {s}", .{374 else => return emit.fail("TODO handle generic encoding: {s}, {s}", .{
344 @tagName(mnemonic),375 @tagName(mnemonic),
345 @tagName(ops),376 @tagName(ops),
...@@ -451,12 +482,12 @@ fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -451,12 +482,12 @@ fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
451 },482 },
452 .rm_sib => {483 .rm_sib => {
453 const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;484 const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
454 op1 = .{ .reg = data.rx.r1 };485 op1 = .{ .reg = data.rx.r };
455 op2 = .{ .mem = Mir.MemorySib.decode(msib) };486 op2 = .{ .mem = Mir.MemorySib.decode(msib) };
456 },487 },
457 .rm_rip => {488 .rm_rip => {
458 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;489 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
459 op1 = .{ .reg = data.rx.r1 };490 op1 = .{ .reg = data.rx.r };
460 op2 = .{ .mem = Mir.MemoryRip.decode(mrip) };491 op2 = .{ .mem = Mir.MemoryRip.decode(mrip) };
461 },492 },
462 else => unreachable, // TODO493 else => unreachable, // TODO
...@@ -495,7 +526,7 @@ fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -495,7 +526,7 @@ fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
495 const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data;526 const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data;
496 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);527 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
497 return emit.encode(mnemonic, .{528 return emit.encode(mnemonic, .{
498 .op1 = .{ .reg = data.r1 },529 .op1 = .{ .reg = data.r },
499 .op2 = .{ .mem = Mir.MemorySib.decode(extra) },530 .op2 = .{ .mem = Mir.MemorySib.decode(extra) },
500 });531 });
501 },532 },
...@@ -504,7 +535,7 @@ fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -504,7 +535,7 @@ fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
504 const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data;535 const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
505 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);536 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
506 return emit.encode(mnemonic, .{537 return emit.encode(mnemonic, .{
507 .op1 = .{ .reg = data.r1 },538 .op1 = .{ .reg = data.r },
508 .op2 = .{ .mem = Mir.MemoryRip.decode(extra) },539 .op2 = .{ .mem = Mir.MemoryRip.decode(extra) },
509 });540 });
510 },541 },
...@@ -519,7 +550,7 @@ fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {...@@ -519,7 +550,7 @@ fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
519 const data = emit.mir.instructions.items(.data)[inst].r_cc;550 const data = emit.mir.instructions.items(.data)[inst].r_cc;
520 const mnemonic = mnemonicFromConditionCode("set", data.cc);551 const mnemonic = mnemonicFromConditionCode("set", data.cc);
521 return emit.encode(mnemonic, .{552 return emit.encode(mnemonic, .{
522 .op1 = .{ .reg = data.r1 },553 .op1 = .{ .reg = data.r },
523 });554 });
524 },555 },
525 .m_sib_cc => {556 .m_sib_cc => {
src/arch/x86_64/Encoding.zig+7-6
...@@ -262,15 +262,15 @@ pub fn format(...@@ -262,15 +262,15 @@ pub fn format(
262 try writer.print("+{s} ", .{tag});262 try writer.print("+{s} ", .{tag});
263 },263 },
264 .m, .mi, .m1, .mc => try writer.print("/{d} ", .{encoding.modRmExt()}),264 .m, .mi, .m1, .mc => try writer.print("/{d} ", .{encoding.modRmExt()}),
265 .mr, .rm, .rmi => try writer.writeAll("/r "),265 .mr, .rm, .rmi, .mri, .mrc => try writer.writeAll("/r "),
266 }266 }
267267
268 switch (encoding.op_en) {268 switch (encoding.op_en) {
269 .i, .d, .zi, .oi, .mi, .rmi => {269 .i, .d, .zi, .oi, .mi, .rmi, .mri => {
270 const op = switch (encoding.op_en) {270 const op = switch (encoding.op_en) {
271 .i, .d => encoding.op1,271 .i, .d => encoding.op1,
272 .zi, .oi, .mi => encoding.op2,272 .zi, .oi, .mi => encoding.op2,
273 .rmi => encoding.op3,273 .rmi, .mri => encoding.op3,
274 else => unreachable,274 else => unreachable,
275 };275 };
276 const tag = switch (op) {276 const tag = switch (op) {
...@@ -285,7 +285,7 @@ pub fn format(...@@ -285,7 +285,7 @@ pub fn format(
285 };285 };
286 try writer.print("{s} ", .{tag});286 try writer.print("{s} ", .{tag});
287 },287 },
288 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm => {},288 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc => {},
289 }289 }
290290
291 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});291 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
...@@ -334,7 +334,7 @@ pub const Mnemonic = enum {...@@ -334,7 +334,7 @@ pub const Mnemonic = enum {
334 rcl, rcr, ret, rol, ror,334 rcl, rcr, ret, rol, ror,
335 sal, sar, sbb,335 sal, sar, sbb,
336 scas, scasb, scasd, scasq, scasw,336 scas, scasb, scasd, scasq, scasw,
337 shl, shr, sub, syscall,337 shl, shld, shr, shrd, sub, syscall,
338 seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,338 seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
339 setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,339 setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
340 setnz, seto, setp, setpe, setpo, sets, setz,340 setnz, seto, setp, setpe, setpo, sets, setz,
...@@ -374,7 +374,8 @@ pub const OpEn = enum {...@@ -374,7 +374,8 @@ pub const OpEn = enum {
374 i, zi,374 i, zi,
375 d, m,375 d, m,
376 fd, td,376 fd, td,
377 m1, mc, mi, mr, rm, rmi,377 m1, mc, mi, mr, rm,
378 rmi, mri, mrc,
378 // zig fmt: on379 // zig fmt: on
379};380};
380381
src/arch/x86_64/Mir.zig+53-25
...@@ -138,8 +138,12 @@ pub const Inst = struct {...@@ -138,8 +138,12 @@ pub const Inst = struct {
138 sfence,138 sfence,
139 /// Logical shift left139 /// Logical shift left
140 shl,140 shl,
141 /// Double precision shift left
142 shld,
141 /// Logical shift right143 /// Logical shift right
142 shr,144 shr,
145 /// Double precision shift right
146 shrd,
143 /// Subtract147 /// Subtract
144 sub,148 sub,
145 /// Syscall149 /// Syscall
...@@ -284,10 +288,10 @@ pub const Inst = struct {...@@ -284,10 +288,10 @@ pub const Inst = struct {
284 ri64,288 ri64,
285 /// Immediate (sign-extended) operand.289 /// Immediate (sign-extended) operand.
286 /// Uses `imm` payload.290 /// Uses `imm` payload.
287 imm_s,291 i_s,
288 /// Immediate (unsigned) operand.292 /// Immediate (unsigned) operand.
289 /// Uses `imm` payload.293 /// Uses `imm` payload.
290 imm_u,294 i_u,
291 /// Relative displacement operand.295 /// Relative displacement operand.
292 /// Uses `imm` payload.296 /// Uses `imm` payload.
293 rel,297 rel,
...@@ -316,23 +320,35 @@ pub const Inst = struct {...@@ -316,23 +320,35 @@ pub const Inst = struct {
316 /// Uses `x_cc` with extra data of type `MemoryRip`.320 /// Uses `x_cc` with extra data of type `MemoryRip`.
317 m_rip_cc,321 m_rip_cc,
318 /// Memory (SIB), immediate (unsigned) operands.322 /// Memory (SIB), immediate (unsigned) operands.
319 /// Uses `xi` payload with extra data of type `MemorySib`.323 /// Uses `ix` payload with extra data of type `MemorySib`.
320 mi_u_sib,324 mi_sib_u,
321 /// Memory (RIP), immediate (unsigned) operands.325 /// Memory (RIP), immediate (unsigned) operands.
322 /// Uses `xi` payload with extra data of type `MemoryRip`.326 /// Uses `ix` payload with extra data of type `MemoryRip`.
323 mi_u_rip,327 mi_rip_u,
324 /// Memory (SIB), immediate (sign-extend) operands.328 /// Memory (SIB), immediate (sign-extend) operands.
325 /// Uses `xi` payload with extra data of type `MemorySib`.329 /// Uses `ix` payload with extra data of type `MemorySib`.
326 mi_s_sib,330 mi_sib_s,
327 /// Memory (RIP), immediate (sign-extend) operands.331 /// Memory (RIP), immediate (sign-extend) operands.
328 /// Uses `xi` payload with extra data of type `MemoryRip`.332 /// Uses `ix` payload with extra data of type `MemoryRip`.
329 mi_s_rip,333 mi_rip_s,
330 /// Memory (SIB), register operands.334 /// Memory (SIB), register operands.
331 /// Uses `rx` payload with extra data of type `MemorySib`.335 /// Uses `rx` payload with extra data of type `MemorySib`.
332 mr_sib,336 mr_sib,
333 /// Memory (RIP), register operands.337 /// Memory (RIP), register operands.
334 /// Uses `rx` payload with extra data of type `MemoryRip`.338 /// Uses `rx` payload with extra data of type `MemoryRip`.
335 mr_rip,339 mr_rip,
340 /// Memory (SIB), register, register operands.
341 /// Uses `rrx` payload with extra data of type `MemorySib`.
342 mrr_sib,
343 /// Memory (RIP), register, register operands.
344 /// Uses `rrx` payload with extra data of type `MemoryRip`.
345 mrr_rip,
346 /// Memory (SIB), register, immediate (byte) operands.
347 /// Uses `rix` payload with extra data of type `MemorySib`.
348 mri_sib,
349 /// Memory (RIP), register, immediate (byte) operands.
350 /// Uses `rix` payload with extra data of type `MemoryRip`.
351 mri_rip,
336 /// Rax, Memory moffs.352 /// Rax, Memory moffs.
337 /// Uses `payload` with extra data of type `MemoryMoffs`.353 /// Uses `payload` with extra data of type `MemoryMoffs`.
338 rax_moffs,354 rax_moffs,
...@@ -347,16 +363,16 @@ pub const Inst = struct {...@@ -347,16 +363,16 @@ pub const Inst = struct {
347 lock_m_rip,363 lock_m_rip,
348 /// Memory (SIB), immediate (unsigned) operands with lock prefix.364 /// Memory (SIB), immediate (unsigned) operands with lock prefix.
349 /// Uses `xi` payload with extra data of type `MemorySib`.365 /// Uses `xi` payload with extra data of type `MemorySib`.
350 lock_mi_u_sib,366 lock_mi_sib_u,
351 /// Memory (RIP), immediate (unsigned) operands with lock prefix.367 /// Memory (RIP), immediate (unsigned) operands with lock prefix.
352 /// Uses `xi` payload with extra data of type `MemoryRip`.368 /// Uses `xi` payload with extra data of type `MemoryRip`.
353 lock_mi_u_rip,369 lock_mi_rip_u,
354 /// Memory (SIB), immediate (sign-extend) operands with lock prefix.370 /// Memory (SIB), immediate (sign-extend) operands with lock prefix.
355 /// Uses `xi` payload with extra data of type `MemorySib`.371 /// Uses `xi` payload with extra data of type `MemorySib`.
356 lock_mi_s_sib,372 lock_mi_sib_s,
357 /// Memory (RIP), immediate (sign-extend) operands with lock prefix.373 /// Memory (RIP), immediate (sign-extend) operands with lock prefix.
358 /// Uses `xi` payload with extra data of type `MemoryRip`.374 /// Uses `xi` payload with extra data of type `MemoryRip`.
359 lock_mi_s_rip,375 lock_mi_rip_s,
360 /// Memory (SIB), register operands with lock prefix.376 /// Memory (SIB), register operands with lock prefix.
361 /// Uses `rx` payload with extra data of type `MemorySib`.377 /// Uses `rx` payload with extra data of type `MemorySib`.
362 lock_mr_sib,378 lock_mr_sib,
...@@ -400,7 +416,7 @@ pub const Inst = struct {...@@ -400,7 +416,7 @@ pub const Inst = struct {
400 cc: bits.Condition,416 cc: bits.Condition,
401 },417 },
402 /// A 32-bit immediate value.418 /// A 32-bit immediate value.
403 imm: u32,419 i: u32,
404 r: Register,420 r: Register,
405 rr: struct {421 rr: struct {
406 r1: Register,422 r1: Register,
...@@ -414,16 +430,16 @@ pub const Inst = struct {...@@ -414,16 +430,16 @@ pub const Inst = struct {
414 rri: struct {430 rri: struct {
415 r1: Register,431 r1: Register,
416 r2: Register,432 r2: Register,
417 imm: u32,433 i: u32,
418 },434 },
419 /// Condition code (CC), followed by custom payload found in extra.435 /// Condition code (CC), followed by custom payload found in extra.
420 x_cc: struct {436 x_cc: struct {
421 payload: u32,
422 cc: bits.Condition,437 cc: bits.Condition,
438 payload: u32,
423 },439 },
424 /// Register with condition code (CC).440 /// Register with condition code (CC).
425 r_cc: struct {441 r_cc: struct {
426 r1: Register,442 r: Register,
427 cc: bits.Condition,443 cc: bits.Condition,
428 },444 },
429 /// Register, register with condition code (CC).445 /// Register, register with condition code (CC).
...@@ -434,24 +450,36 @@ pub const Inst = struct {...@@ -434,24 +450,36 @@ pub const Inst = struct {
434 },450 },
435 /// Register, immediate.451 /// Register, immediate.
436 ri: struct {452 ri: struct {
437 r1: Register,453 r: Register,
438 imm: u32,454 i: u32,
439 },455 },
440 /// Register, followed by custom payload found in extra.456 /// Register, followed by custom payload found in extra.
441 rx: struct {457 rx: struct {
442 r1: Register,458 r: Register,
443 payload: u32,459 payload: u32,
444 },460 },
445 /// Register with condition code (CC), followed by custom payload found in extra.461 /// Register with condition code (CC), followed by custom payload found in extra.
446 rx_cc: struct {462 rx_cc: struct {
447 r1: Register,463 r: Register,
448 cc: bits.Condition,464 cc: bits.Condition,
449 payload: u32,465 payload: u32,
450 },466 },
451 /// Custom payload followed by an immediate.467 /// Immediate, followed by Custom payload found in extra.
452 xi: struct {468 ix: struct {
469 i: u32,
470 payload: u32,
471 },
472 /// Register, register, followed by Custom payload found in extra.
473 rrx: struct {
474 r1: Register,
475 r2: Register,
476 payload: u32,
477 },
478 /// Register, byte immediate, followed by Custom payload found in extra.
479 rix: struct {
480 r: Register,
481 i: u8,
453 payload: u32,482 payload: u32,
454 imm: u32,
455 },483 },
456 /// String instruction prefix and width.484 /// String instruction prefix and width.
457 string: struct {485 string: struct {
src/arch/x86_64/bits.zig+11-12
...@@ -411,20 +411,17 @@ pub const Memory = union(enum) {...@@ -411,20 +411,17 @@ pub const Memory = union(enum) {
411 dword,411 dword,
412 qword,412 qword,
413 tbyte,413 tbyte,
414 dqword,
414415
415 pub fn fromSize(size: u32) PtrSize {416 pub fn fromSize(size: u32) PtrSize {
416 return if (size <= 1)417 return switch (size) {
417 .byte418 1...1 => .byte,
418 else if (size <= 2)419 2...2 => .word,
419 .word420 3...4 => .dword,
420 else if (size <= 4)421 5...8 => .qword,
421 .dword422 9...16 => .dqword,
422 else if (size <= 8)423 else => unreachable,
423 .qword424 };
424 else if (size == 10)
425 .tbyte
426 else
427 unreachable;
428 }425 }
429426
430 pub fn fromBitSize(bit_size: u64) PtrSize {427 pub fn fromBitSize(bit_size: u64) PtrSize {
...@@ -434,6 +431,7 @@ pub const Memory = union(enum) {...@@ -434,6 +431,7 @@ pub const Memory = union(enum) {
434 32 => .dword,431 32 => .dword,
435 64 => .qword,432 64 => .qword,
436 80 => .tbyte,433 80 => .tbyte,
434 128 => .dqword,
437 else => unreachable,435 else => unreachable,
438 };436 };
439 }437 }
...@@ -445,6 +443,7 @@ pub const Memory = union(enum) {...@@ -445,6 +443,7 @@ pub const Memory = union(enum) {
445 .dword => 32,443 .dword => 32,
446 .qword => 64,444 .qword => 64,
447 .tbyte => 80,445 .tbyte => 80,
446 .dqword => 128,
448 };447 };
449 }448 }
450 };449 };
src/arch/x86_64/encoder.zig+10-12
...@@ -117,7 +117,7 @@ pub const Instruction = struct {...@@ -117,7 +117,7 @@ pub const Instruction = struct {
117117
118 pub fn new(mnemonic: Mnemonic, args: Init) !Instruction {118 pub fn new(mnemonic: Mnemonic, args: Init) !Instruction {
119 const encoding = (try Encoding.findByMnemonic(mnemonic, args)) orelse {119 const encoding = (try Encoding.findByMnemonic(mnemonic, args)) orelse {
120 log.debug("no encoding found for: {s} {s} {s} {s} {s} {s}", .{120 log.err("no encoding found for: {s} {s} {s} {s} {s} {s}", .{
121 @tagName(args.prefix),121 @tagName(args.prefix),
122 @tagName(mnemonic),122 @tagName(mnemonic),
123 @tagName(Encoding.Op.fromOperand(args.op1)),123 @tagName(Encoding.Op.fromOperand(args.op1)),
...@@ -174,7 +174,7 @@ pub const Instruction = struct {...@@ -174,7 +174,7 @@ pub const Instruction = struct {
174 .td => try encoder.imm64(inst.op1.mem.moffs.offset),174 .td => try encoder.imm64(inst.op1.mem.moffs.offset),
175 else => {175 else => {
176 const mem_op = switch (encoding.op_en) {176 const mem_op = switch (encoding.op_en) {
177 .m, .mi, .m1, .mc, .mr => inst.op1,177 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1,
178 .rm, .rmi => inst.op2,178 .rm, .rmi => inst.op2,
179 else => unreachable,179 else => unreachable,
180 };180 };
...@@ -182,7 +182,7 @@ pub const Instruction = struct {...@@ -182,7 +182,7 @@ pub const Instruction = struct {
182 .reg => |reg| {182 .reg => |reg| {
183 const rm = switch (encoding.op_en) {183 const rm = switch (encoding.op_en) {
184 .m, .mi, .m1, .mc => encoding.modRmExt(),184 .m, .mi, .m1, .mc => encoding.modRmExt(),
185 .mr => inst.op2.reg.lowEnc(),185 .mr, .mri, .mrc => inst.op2.reg.lowEnc(),
186 .rm, .rmi => inst.op1.reg.lowEnc(),186 .rm, .rmi => inst.op1.reg.lowEnc(),
187 else => unreachable,187 else => unreachable,
188 };188 };
...@@ -191,7 +191,7 @@ pub const Instruction = struct {...@@ -191,7 +191,7 @@ pub const Instruction = struct {
191 .mem => |mem| {191 .mem => |mem| {
192 const op = switch (encoding.op_en) {192 const op = switch (encoding.op_en) {
193 .m, .mi, .m1, .mc => .none,193 .m, .mi, .m1, .mc => .none,
194 .mr => inst.op2,194 .mr, .mri, .mrc => inst.op2,
195 .rm, .rmi => inst.op1,195 .rm, .rmi => inst.op1,
196 else => unreachable,196 else => unreachable,
197 };197 };
...@@ -202,7 +202,7 @@ pub const Instruction = struct {...@@ -202,7 +202,7 @@ pub const Instruction = struct {
202202
203 switch (encoding.op_en) {203 switch (encoding.op_en) {
204 .mi => try encodeImm(inst.op2.imm, encoding.op2, encoder),204 .mi => try encodeImm(inst.op2.imm, encoding.op2, encoder),
205 .rmi => try encodeImm(inst.op3.imm, encoding.op3, encoder),205 .rmi, .mri => try encodeImm(inst.op3.imm, encoding.op3, encoder),
206 else => {},206 else => {},
207 }207 }
208 },208 },
...@@ -251,7 +251,7 @@ pub const Instruction = struct {...@@ -251,7 +251,7 @@ pub const Instruction = struct {
251 else => unreachable,251 else => unreachable,
252 };252 };
253 } else null,253 } else null,
254 .m, .mi, .m1, .mc, .mr => if (inst.op1.isSegmentRegister()) blk: {254 .m, .mi, .m1, .mc, .mr, .mri, .mrc => if (inst.op1.isSegmentRegister()) blk: {
255 break :blk switch (inst.op1) {255 break :blk switch (inst.op1) {
256 .reg => |r| r,256 .reg => |r| r,
257 .mem => |m| m.base().?,257 .mem => |m| m.base().?,
...@@ -275,13 +275,11 @@ pub const Instruction = struct {...@@ -275,13 +275,11 @@ pub const Instruction = struct {
275275
276 switch (op_en) {276 switch (op_en) {
277 .np, .i, .zi, .fd, .td, .d => {},277 .np, .i, .zi, .fd, .td, .d => {},
278 .o, .oi => {278 .o, .oi => rex.b = inst.op1.reg.isExtended(),
279 rex.b = inst.op1.reg.isExtended();279 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc => {
280 },
281 .m, .mi, .m1, .mc, .mr, .rm, .rmi => {
282 const r_op = switch (op_en) {280 const r_op = switch (op_en) {
283 .rm, .rmi => inst.op1,281 .rm, .rmi => inst.op1,
284 .mr => inst.op2,282 .mr, .mri, .mrc => inst.op2,
285 else => null,283 else => null,
286 };284 };
287 if (r_op) |op| {285 if (r_op) |op| {
...@@ -290,7 +288,7 @@ pub const Instruction = struct {...@@ -290,7 +288,7 @@ pub const Instruction = struct {
290288
291 const b_x_op = switch (op_en) {289 const b_x_op = switch (op_en) {
292 .rm, .rmi => inst.op2,290 .rm, .rmi => inst.op2,
293 .m, .mi, .m1, .mc, .mr => inst.op1,291 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1,
294 else => unreachable,292 else => unreachable,
295 };293 };
296 switch (b_x_op) {294 switch (b_x_op) {
src/arch/x86_64/encodings.zig+16-2
...@@ -257,8 +257,8 @@ pub const table = &[_]Entry{...@@ -257,8 +257,8 @@ pub const table = &[_]Entry{
257257
258 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .none },258 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .none },
259 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .rex },259 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .rex },
260 .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .rex },260 .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none },
261 .{ .cmpxchg, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb1 }, 0, .rex },261 .{ .cmpxchg, .mr, .rm32, .r32, .none, .none, &.{ 0x0f, 0xb1 }, 0, .none },
262 .{ .cmpxchg, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb1 }, 0, .long },262 .{ .cmpxchg, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb1 }, 0, .long },
263263
264 .{ .cmpxchg8b , .m, .m64, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .none },264 .{ .cmpxchg8b , .m, .m64, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .none },
...@@ -693,6 +693,13 @@ pub const table = &[_]Entry{...@@ -693,6 +693,13 @@ pub const table = &[_]Entry{
693 .{ .shl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },693 .{ .shl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
694 .{ .shl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long },694 .{ .shl, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 4, .long },
695695
696 .{ .shld, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none },
697 .{ .shld, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none },
698 .{ .shld, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .none },
699 .{ .shld, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xa4 }, 0, .long },
700 .{ .shld, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .none },
701 .{ .shld, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xa5 }, 0, .long },
702
696 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .none },703 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .none },
697 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .rex },704 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .rex },
698 .{ .shr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 5, .none },705 .{ .shr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 5, .none },
...@@ -709,6 +716,13 @@ pub const table = &[_]Entry{...@@ -709,6 +716,13 @@ pub const table = &[_]Entry{
709 .{ .shr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },716 .{ .shr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },
710 .{ .shr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 5, .long },717 .{ .shr, .mi, .rm64, .imm8, .none, .none, &.{ 0xc1 }, 5, .long },
711718
719 .{ .shrd, .mri, .rm16, .r16, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none },
720 .{ .shrd, .mrc, .rm16, .r16, .cl, .none, &.{ 0x0f, 0xad }, 0, .none },
721 .{ .shrd, .mri, .rm32, .r32, .imm8, .none, &.{ 0x0f, 0xac }, 0, .none },
722 .{ .shrd, .mri, .rm64, .r64, .imm8, .none, &.{ 0x0f, 0xac }, 0, .long },
723 .{ .shrd, .mrc, .rm32, .r32, .cl, .none, &.{ 0x0f, 0xad }, 0, .none },
724 .{ .shrd, .mrc, .rm64, .r64, .cl, .none, &.{ 0x0f, 0xad }, 0, .long },
725
712 .{ .stos, .np, .m8, .none, .none, .none, &.{ 0xaa }, 0, .none },726 .{ .stos, .np, .m8, .none, .none, .none, &.{ 0xaa }, 0, .none },
713 .{ .stos, .np, .m16, .none, .none, .none, &.{ 0xab }, 0, .none },727 .{ .stos, .np, .m16, .none, .none, .none, &.{ 0xab }, 0, .none },
714 .{ .stos, .np, .m32, .none, .none, .none, &.{ 0xab }, 0, .none },728 .{ .stos, .np, .m32, .none, .none, .none, &.{ 0xab }, 0, .none },
src/codegen.zig+2-3
...@@ -1063,13 +1063,12 @@ pub fn genTypedValue(...@@ -1063,13 +1063,12 @@ pub fn genTypedValue(
1063 },1063 },
1064 .Optional => {1064 .Optional => {
1065 if (typed_value.ty.isPtrLikeOptional()) {1065 if (typed_value.ty.isPtrLikeOptional()) {
1066 if (typed_value.val.isNull())1066 if (typed_value.val.tag() == .null_value) return GenResult.mcv(.{ .immediate = 0 });
1067 return GenResult.mcv(.{ .immediate = 0 });
10681067
1069 var buf: Type.Payload.ElemType = undefined;1068 var buf: Type.Payload.ElemType = undefined;
1070 return genTypedValue(bin_file, src_loc, .{1069 return genTypedValue(bin_file, src_loc, .{
1071 .ty = typed_value.ty.optionalChild(&buf),1070 .ty = typed_value.ty.optionalChild(&buf),
1072 .val = typed_value.val,1071 .val = if (typed_value.val.castTag(.opt_payload)) |pl| pl.data else typed_value.val,
1073 }, owner_decl_index);1072 }, owner_decl_index);
1074 } else if (typed_value.ty.abiSize(target) == 1) {1073 } else if (typed_value.ty.abiSize(target) == 1) {
1075 return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull()) });1074 return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull()) });
src/register_manager.zig+14-5
...@@ -149,17 +149,26 @@ pub fn RegisterManager(...@@ -149,17 +149,26 @@ pub fn RegisterManager(
149 return RegisterLock{ .register = reg };149 return RegisterLock{ .register = reg };
150 }150 }
151151
152 /// Like `lockReg` but locks multiple registers.
153 pub fn lockRegs(
154 self: *Self,
155 comptime count: comptime_int,
156 regs: [count]Register,
157 ) [count]?RegisterLock {
158 var results: [count]?RegisterLock = undefined;
159 for (&results, regs) |*result, reg| result.* = self.lockReg(reg);
160 return results;
161 }
162
152 /// Like `lockRegAssumeUnused` but locks multiple registers.163 /// Like `lockRegAssumeUnused` but locks multiple registers.
153 pub fn lockRegsAssumeUnused(164 pub fn lockRegsAssumeUnused(
154 self: *Self,165 self: *Self,
155 comptime count: comptime_int,166 comptime count: comptime_int,
156 regs: [count]Register,167 regs: [count]Register,
157 ) [count]RegisterLock {168 ) [count]RegisterLock {
158 var buf: [count]RegisterLock = undefined;169 var results: [count]RegisterLock = undefined;
159 for (regs, 0..) |reg, i| {170 for (&results, regs) |*result, reg| result.* = self.lockRegAssumeUnused(reg);
160 buf[i] = self.lockRegAssumeUnused(reg);171 return results;
161 }
162 return buf;
163 }172 }
164173
165 /// Unlocks the register allowing its re-allocation and re-use.174 /// Unlocks the register allowing its re-allocation and re-use.
test/behavior/array.zig-2
...@@ -70,7 +70,6 @@ test "array concat with undefined" {...@@ -70,7 +70,6 @@ test "array concat with undefined" {
70test "array concat with tuple" {70test "array concat with tuple" {
71 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO71 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO72 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7473
75 const array: [2]u8 = .{ 1, 2 };74 const array: [2]u8 = .{ 1, 2 };
76 {75 {
...@@ -641,7 +640,6 @@ test "tuple to array handles sentinel" {...@@ -641,7 +640,6 @@ test "tuple to array handles sentinel" {
641}640}
642641
643test "array init of container level array variable" {642test "array init of container level array variable" {
644 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
645 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO643 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
646 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO644 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
647 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO645 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/atomics.zig-4
...@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;...@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
55
6test "cmpxchg" {6test "cmpxchg" {
7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -96,7 +95,6 @@ test "cmpxchg with ptr" {...@@ -96,7 +95,6 @@ test "cmpxchg with ptr" {
9695
97test "cmpxchg with ignored result" {96test "cmpxchg with ignored result" {
98 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO97 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -143,7 +141,6 @@ var a_global_variable = @as(u32, 1234);...@@ -143,7 +141,6 @@ var a_global_variable = @as(u32, 1234);
143141
144test "cmpxchg on a global variable" {142test "cmpxchg on a global variable" {
145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO143 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
147 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
148 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
149 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
...@@ -384,7 +381,6 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void {...@@ -384,7 +381,6 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void {
384381
385test "atomics with different types" {382test "atomics with different types" {
386 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO383 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
387 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
388 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO384 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
389 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO385 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
390 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO386 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bitcast.zig-2
...@@ -157,7 +157,6 @@ test "bitcast generates a temporary value" {...@@ -157,7 +157,6 @@ test "bitcast generates a temporary value" {
157}157}
158158
159test "@bitCast packed structs at runtime and comptime" {159test "@bitCast packed structs at runtime and comptime" {
160 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
162 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
163 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -215,7 +214,6 @@ test "@bitCast extern structs at runtime and comptime" {...@@ -215,7 +214,6 @@ test "@bitCast extern structs at runtime and comptime" {
215}214}
216215
217test "bitcast packed struct to integer and back" {216test "bitcast packed struct to integer and back" {
218 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
219 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;217 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
220 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;218 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
221 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO219 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/bugs/10684.zig-1
...@@ -4,7 +4,6 @@ const expectEqualStrings = std.testing.expectEqualStrings;...@@ -4,7 +4,6 @@ const expectEqualStrings = std.testing.expectEqualStrings;
44
5test "slicing slices" {5test "slicing slices" {
6 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/12051.zig-1
...@@ -3,7 +3,6 @@ const builtin = @import("builtin");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33
4test {4test {
5 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO5 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/12092.zig-1
...@@ -15,7 +15,6 @@ fn takeFoo(foo: *const Foo) !void {...@@ -15,7 +15,6 @@ fn takeFoo(foo: *const Foo) !void {
1515
16test {16test {
17 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO18 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
20 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
21 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO20 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/12142.zig-1
...@@ -20,7 +20,6 @@ fn letter(e: Letter) u8 {...@@ -20,7 +20,6 @@ fn letter(e: Letter) u8 {
2020
21test {21test {
22 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO22 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO23 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/12450.zig-1
...@@ -10,7 +10,6 @@ var buffer: [256]u8 = undefined;...@@ -10,7 +10,6 @@ var buffer: [256]u8 = undefined;
1010
11test {11test {
12 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/2578.zig-1
...@@ -14,7 +14,6 @@ fn bar(pointer: ?*anyopaque) void {...@@ -14,7 +14,6 @@ fn bar(pointer: ?*anyopaque) void {
14test "fixed" {14test "fixed" {
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_arm) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1918
20 bar(t);19 bar(t);
test/behavior/bugs/6456.zig-1
...@@ -11,7 +11,6 @@ const text =...@@ -11,7 +11,6 @@ const text =
11;11;
1212
13test "issue 6456" {13test "issue 6456" {
14 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO14 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1716
test/behavior/bugs/726.zig-2
...@@ -4,7 +4,6 @@ const builtin = @import("builtin");...@@ -4,7 +4,6 @@ const builtin = @import("builtin");
4test "@ptrCast from const to nullable" {4test "@ptrCast from const to nullable" {
5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98
10 const c: u8 = 4;9 const c: u8 = 4;
...@@ -15,7 +14,6 @@ test "@ptrCast from const to nullable" {...@@ -15,7 +14,6 @@ test "@ptrCast from const to nullable" {
15test "@ptrCast from var in empty struct to nullable" {14test "@ptrCast from var in empty struct to nullable" {
16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;15 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;16 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
19 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2018
21 const container = struct {19 const container = struct {
test/behavior/bugs/8646.zig-1
...@@ -8,7 +8,6 @@ const array = [_][]const []const u8{...@@ -8,7 +8,6 @@ const array = [_][]const []const u8{
88
9test {9test {
10 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO12 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO13 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/9584.zig-1
...@@ -44,7 +44,6 @@ pub fn b(x: *X) !void {...@@ -44,7 +44,6 @@ pub fn b(x: *X) !void {
44}44}
4545
46test {46test {
47 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO47 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
49 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO48 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/empty_tuple_fields.zig-2
...@@ -3,7 +3,6 @@ const builtin = @import("builtin");...@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33
4test "empty file level struct" {4test "empty file level struct" {
5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87
9 const T = @import("empty_file_level_struct.zig");8 const T = @import("empty_file_level_struct.zig");
...@@ -15,7 +14,6 @@ test "empty file level struct" {...@@ -15,7 +14,6 @@ test "empty file level struct" {
1514
16test "empty file level union" {15test "empty file level union" {
17 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO16 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
19 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO17 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2018
21 const T = @import("empty_file_level_union.zig");19 const T = @import("empty_file_level_union.zig");
test/behavior/fn.zig-1
...@@ -96,7 +96,6 @@ test "discard the result of a function that returns a struct" {...@@ -96,7 +96,6 @@ test "discard the result of a function that returns a struct" {
96}96}
9797
98test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {98test "inline function call that calls optional function pointer, return pointer at callsite interacts correctly with callsite return type" {
99 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
101 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
102 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/lower_strlit_to_vector.zig-1
...@@ -2,7 +2,6 @@ const std = @import("std");...@@ -2,7 +2,6 @@ const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
33
4test "strlit to vector" {4test "strlit to vector" {
5 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO5 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO6 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO7 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/math.zig-1
...@@ -560,7 +560,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {...@@ -560,7 +560,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
560test "negation wrapping" {560test "negation wrapping" {
561 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO561 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
562 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO562 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
563 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
564563
565 try expectEqual(@as(u1, 1), negateWrap(u1, 1));564 try expectEqual(@as(u1, 1), negateWrap(u1, 1));
566}565}
test/behavior/optional.zig-1
...@@ -431,7 +431,6 @@ test "alignment of wrapping an optional payload" {...@@ -431,7 +431,6 @@ test "alignment of wrapping an optional payload" {
431test "Optional slice size is optimized" {431test "Optional slice size is optimized" {
432 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;432 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
433 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;433 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
434 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
435 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
436435
437 try expect(@sizeOf(?[]u8) == @sizeOf([]u8));436 try expect(@sizeOf(?[]u8) == @sizeOf([]u8));
test/behavior/packed-struct.zig-7
...@@ -120,7 +120,6 @@ test "consistent size of packed structs" {...@@ -120,7 +120,6 @@ test "consistent size of packed structs" {
120}120}
121121
122test "correct sizeOf and offsets in packed structs" {122test "correct sizeOf and offsets in packed structs" {
123 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
124 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
125 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO125 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -188,7 +187,6 @@ test "correct sizeOf and offsets in packed structs" {...@@ -188,7 +187,6 @@ test "correct sizeOf and offsets in packed structs" {
188}187}
189188
190test "nested packed structs" {189test "nested packed structs" {
191 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
192 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
193 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO191 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO192 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -254,7 +252,6 @@ test "regular in irregular packed struct" {...@@ -254,7 +252,6 @@ test "regular in irregular packed struct" {
254}252}
255253
256test "byte-aligned field pointer offsets" {254test "byte-aligned field pointer offsets" {
257 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
258 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
259 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
260 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO257 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -397,7 +394,6 @@ test "@ptrToInt on a packed struct field" {...@@ -397,7 +394,6 @@ test "@ptrToInt on a packed struct field" {
397}394}
398395
399test "optional pointer in packed struct" {396test "optional pointer in packed struct" {
400 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
401 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
402 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;398 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
403 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -530,7 +526,6 @@ test "nested packed struct field access test" {...@@ -530,7 +526,6 @@ test "nested packed struct field access test" {
530test "runtime init of unnamed packed struct type" {526test "runtime init of unnamed packed struct type" {
531 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;527 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
532 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;528 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
533 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
534 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535530
536 var z: u8 = 123;531 var z: u8 = 123;
...@@ -545,7 +540,6 @@ test "runtime init of unnamed packed struct type" {...@@ -545,7 +540,6 @@ test "runtime init of unnamed packed struct type" {
545test "packed struct passed to callconv(.C) function" {540test "packed struct passed to callconv(.C) function" {
546 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
547 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;542 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
548 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
549 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
550544
551 const S = struct {545 const S = struct {
...@@ -571,7 +565,6 @@ test "packed struct passed to callconv(.C) function" {...@@ -571,7 +565,6 @@ test "packed struct passed to callconv(.C) function" {
571test "overaligned pointer to packed struct" {565test "overaligned pointer to packed struct" {
572 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;566 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
573 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;567 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
574 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
575568
576 const S = packed struct { a: u32, b: u32 };569 const S = packed struct { a: u32, b: u32 };
577 var foo: S align(4) = .{ .a = 123, .b = 456 };570 var foo: S align(4) = .{ .a = 123, .b = 456 };
test/behavior/packed_struct_explicit_backing_int.zig-1
...@@ -6,7 +6,6 @@ const native_endian = builtin.cpu.arch.endian();...@@ -6,7 +6,6 @@ const native_endian = builtin.cpu.arch.endian();
66
7test "packed struct explicit backing integer" {7test "packed struct explicit backing integer" {
8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO8 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO9 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO10 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
12 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO11 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/pointers.zig-2
...@@ -412,7 +412,6 @@ test "@ptrToInt on null optional at comptime" {...@@ -412,7 +412,6 @@ test "@ptrToInt on null optional at comptime" {
412test "indexing array with sentinel returns correct type" {412test "indexing array with sentinel returns correct type" {
413 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO413 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
415 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
416 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO415 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
417416
418 var s: [:0]const u8 = "abc";417 var s: [:0]const u8 = "abc";
...@@ -497,7 +496,6 @@ test "pointer to constant decl preserves alignment" {...@@ -497,7 +496,6 @@ test "pointer to constant decl preserves alignment" {
497test "ptrCast comptime known slice to C pointer" {496test "ptrCast comptime known slice to C pointer" {
498 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
499 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
500 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
501 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO499 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
502500
503 const s: [:0]const u8 = "foo";501 const s: [:0]const u8 = "foo";
test/behavior/slice.zig-3
...@@ -688,7 +688,6 @@ test "slice field ptr var" {...@@ -688,7 +688,6 @@ test "slice field ptr var" {
688test "global slice field access" {688test "global slice field access" {
689 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO689 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
690 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO690 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
691 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
692 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO691 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
693692
694 const S = struct {693 const S = struct {
...@@ -733,7 +732,6 @@ test "empty slice ptr is non null" {...@@ -733,7 +732,6 @@ test "empty slice ptr is non null" {
733test "slice decays to many pointer" {732test "slice decays to many pointer" {
734 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;733 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
735 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;734 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
736 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
737735
738 var buf: [8]u8 = "abcdefg\x00".*;736 var buf: [8]u8 = "abcdefg\x00".*;
739 const p: [*:0]const u8 = buf[0..7 :0];737 const p: [*:0]const u8 = buf[0..7 :0];
...@@ -744,7 +742,6 @@ test "write through pointer to optional slice arg" {...@@ -744,7 +742,6 @@ test "write through pointer to optional slice arg" {
744 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;742 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
745 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;743 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
746 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;744 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
747 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
748745
749 const S = struct {746 const S = struct {
750 fn bar(foo: *?[]const u8) !void {747 fn bar(foo: *?[]const u8) !void {
test/behavior/struct.zig-5
...@@ -387,7 +387,6 @@ const APackedStruct = packed struct {...@@ -387,7 +387,6 @@ const APackedStruct = packed struct {
387test "packed struct" {387test "packed struct" {
388 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;388 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
389 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO389 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
390 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
391 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO390 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
392391
393 var foo = APackedStruct{392 var foo = APackedStruct{
...@@ -496,7 +495,6 @@ const Bitfields = packed struct {...@@ -496,7 +495,6 @@ const Bitfields = packed struct {
496test "packed struct fields are ordered from LSB to MSB" {495test "packed struct fields are ordered from LSB to MSB" {
497 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO496 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
498 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
499 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
500 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
501499
502 var all: u64 = 0x7765443322221111;500 var all: u64 = 0x7765443322221111;
...@@ -632,7 +630,6 @@ test "default struct initialization fields" {...@@ -632,7 +630,6 @@ test "default struct initialization fields" {
632}630}
633631
634test "packed array 24bits" {632test "packed array 24bits" {
635 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
636 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;633 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
637 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;634 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
638 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO635 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -827,7 +824,6 @@ test "non-packed struct with u128 entry in union" {...@@ -827,7 +824,6 @@ test "non-packed struct with u128 entry in union" {
827}824}
828825
829test "packed struct field passed to generic function" {826test "packed struct field passed to generic function" {
830 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
831 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO827 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
832 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
833 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO829 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -939,7 +935,6 @@ test "comptime struct field" {...@@ -939,7 +935,6 @@ test "comptime struct field" {
939}935}
940936
941test "tuple element initialized with fn call" {937test "tuple element initialized with fn call" {
942 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
943 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
944 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO939 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
945 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO940 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/switch.zig-1
...@@ -620,7 +620,6 @@ test "switch on error set with single else" {...@@ -620,7 +620,6 @@ test "switch on error set with single else" {
620}620}
621621
622test "switch capture copies its payload" {622test "switch capture copies its payload" {
623 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
624 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO623 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
625 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
626 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO625 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/threadlocal.zig-1
...@@ -21,7 +21,6 @@ test "thread local variable" {...@@ -21,7 +21,6 @@ test "thread local variable" {
2121
22test "pointer to thread local array" {22test "pointer to thread local array" {
23 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO23 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
25 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO24 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
26 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO25 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) {26 if (builtin.zig_backend == .stage2_llvm) switch (builtin.cpu.arch) {
test/behavior/translate_c_macros.zig-8
...@@ -23,7 +23,6 @@ test "casting to void with a macro" {...@@ -23,7 +23,6 @@ test "casting to void with a macro" {
23}23}
2424
25test "initializer list expression" {25test "initializer list expression" {
26 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
27 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO26 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO27 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
29 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO28 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -52,7 +51,6 @@ test "reference to a struct type" {...@@ -52,7 +51,6 @@ test "reference to a struct type" {
5251
53test "cast negative integer to pointer" {52test "cast negative integer to pointer" {
54 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO53 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO54 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
57 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO55 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
58 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO56 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -98,7 +96,6 @@ test "casting or calling a value with a paren-surrounded macro" {...@@ -98,7 +96,6 @@ test "casting or calling a value with a paren-surrounded macro" {
9896
99test "nested comma operator" {97test "nested comma operator" {
100 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO98 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
104 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -109,7 +106,6 @@ test "nested comma operator" {...@@ -109,7 +106,6 @@ test "nested comma operator" {
109106
110test "cast functions" {107test "cast functions" {
111 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO108 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
113 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
114 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -123,7 +119,6 @@ test "cast functions" {...@@ -123,7 +119,6 @@ test "cast functions" {
123119
124test "large integer macro" {120test "large integer macro" {
125 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO121 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
128 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
129 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -133,7 +128,6 @@ test "large integer macro" {...@@ -133,7 +128,6 @@ test "large integer macro" {
133128
134test "string literal macro with embedded tab character" {129test "string literal macro with embedded tab character" {
135 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO130 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
137 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO131 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -143,7 +137,6 @@ test "string literal macro with embedded tab character" {...@@ -143,7 +137,6 @@ test "string literal macro with embedded tab character" {
143137
144test "string and char literals that are not UTF-8 encoded. Issue #12784" {138test "string and char literals that are not UTF-8 encoded. Issue #12784" {
145 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO139 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
147 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
148 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO141 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
149 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO142 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -188,7 +181,6 @@ test "Macro that uses division operator. Issue #13162" {...@@ -188,7 +181,6 @@ test "Macro that uses division operator. Issue #13162" {
188181
189test "Macro that uses remainder operator. Issue #13346" {182test "Macro that uses remainder operator. Issue #13346" {
190 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO183 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
191 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
192 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
193 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO185 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
194 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO186 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/tuple.zig-1
...@@ -381,7 +381,6 @@ test "tuple of struct concatenation and coercion to array" {...@@ -381,7 +381,6 @@ test "tuple of struct concatenation and coercion to array" {
381test "nested runtime conditionals in tuple initializer" {381test "nested runtime conditionals in tuple initializer" {
382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
384 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
385384
386 var data: u8 = 0;385 var data: u8 = 0;
387 const x = .{386 const x = .{
test/behavior/tuple_declarations.zig-2
...@@ -7,7 +7,6 @@ const expectEqualStrings = testing.expectEqualStrings;...@@ -7,7 +7,6 @@ const expectEqualStrings = testing.expectEqualStrings;
7test "tuple declaration type info" {7test "tuple declaration type info" {
8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;8 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1110
12 {11 {
13 const T = struct { comptime u32 align(2) = 1, []const u8 };12 const T = struct { comptime u32 align(2) = 1, []const u8 };
...@@ -57,7 +56,6 @@ test "tuple declaration type info" {...@@ -57,7 +56,6 @@ test "tuple declaration type info" {
57test "Tuple declaration usage" {56test "Tuple declaration usage" {
58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;57 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
59 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;58 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
6159
62 const T = struct { u32, []const u8 };60 const T = struct { u32, []const u8 };
63 var t: T = .{ 1, "foo" };61 var t: T = .{ 1, "foo" };
test/behavior/type.zig-2
...@@ -200,7 +200,6 @@ test "Type.ErrorUnion" {...@@ -200,7 +200,6 @@ test "Type.ErrorUnion" {
200200
201test "Type.Opaque" {201test "Type.Opaque" {
202 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO202 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
204 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
205 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
206 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -348,7 +347,6 @@ test "Type.Struct" {...@@ -348,7 +347,6 @@ test "Type.Struct" {
348}347}
349348
350test "Type.Enum" {349test "Type.Enum" {
351 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
352 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
353 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO351 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
354352
test/behavior/type_info.zig-1
...@@ -568,7 +568,6 @@ test "value from struct @typeInfo default_value can be loaded at comptime" {...@@ -568,7 +568,6 @@ test "value from struct @typeInfo default_value can be loaded at comptime" {
568test "@typeInfo decls and usingnamespace" {568test "@typeInfo decls and usingnamespace" {
569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
571 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
572571
573 const A = struct {572 const A = struct {
574 const x = 5;573 const x = 5;
test/behavior/typename.zig-2
...@@ -64,7 +64,6 @@ test "anon field init" {...@@ -64,7 +64,6 @@ test "anon field init" {
64}64}
6565
66test "basic" {66test "basic" {
67 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
68 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO67 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
69 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO68 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
70 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO69 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
...@@ -228,7 +227,6 @@ test "local variable" {...@@ -228,7 +227,6 @@ test "local variable" {
228}227}
229228
230test "comptime parameters not converted to anytype in function type" {229test "comptime parameters not converted to anytype in function type" {
231 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
232 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
233 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
234 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO232 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/union.zig-2
...@@ -1408,7 +1408,6 @@ test "union field ptr - zero sized field" {...@@ -1408,7 +1408,6 @@ test "union field ptr - zero sized field" {
1408}1408}
14091409
1410test "packed union in packed struct" {1410test "packed union in packed struct" {
1411 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1412 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1413 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1414 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1413 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
...@@ -1494,7 +1493,6 @@ test "union reassignment can use previous value" {...@@ -1494,7 +1493,6 @@ test "union reassignment can use previous value" {
1494}1493}
14951494
1496test "packed union with zero-bit field" {1495test "packed union with zero-bit field" {
1497 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1496 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1499 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1500 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO1498 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
test/behavior/vector.zig-1
...@@ -1267,7 +1267,6 @@ test "store to vector in slice" {...@@ -1267,7 +1267,6 @@ test "store to vector in slice" {
1267test "addition of vectors represented as strings" {1267test "addition of vectors represented as strings" {
1268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1270 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12711270
1272 const V = @Vector(3, u8);1271 const V = @Vector(3, u8);
1273 const foo: V = "foo".*;1272 const foo: V = "foo".*;
test/tests.zig+1
...@@ -112,6 +112,7 @@ const test_targets = blk: {...@@ -112,6 +112,7 @@ const test_targets = blk: {
112 .os_tag = .windows,112 .os_tag = .windows,
113 .abi = .gnu,113 .abi = .gnu,
114 },114 },
115 .single_threaded = true, // https://github.com/ziglang/zig/issues/15075
115 .backend = .stage2_x86_64,116 .backend = .stage2_x86_64,
116 },117 },
117118