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
2929
3030fn getStdOutHandle() os.fd_t {
3131 if (builtin.os.tag == .windows) {
32 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) {
33 // TODO: this is just a temporary workaround until we advance x86 backend further along.
32 if (builtin.zig_backend == .stage2_aarch64) {
33 // TODO: this is just a temporary workaround until we advance aarch64 backend further along.
3434 return os.windows.GetStdHandle(os.windows.STD_OUTPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
3535 }
3636 return os.windows.peb().ProcessParameters.hStdOutput;
......@@ -55,8 +55,8 @@ pub fn getStdOut() File {
5555
5656fn getStdErrHandle() os.fd_t {
5757 if (builtin.os.tag == .windows) {
58 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) {
59 // TODO: this is just a temporary workaround until we advance x86 backend further along.
58 if (builtin.zig_backend == .stage2_aarch64) {
59 // TODO: this is just a temporary workaround until we advance aarch64 backend further along.
6060 return os.windows.GetStdHandle(os.windows.STD_ERROR_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
6161 }
6262 return os.windows.peb().ProcessParameters.hStdError;
......@@ -81,8 +81,8 @@ pub fn getStdErr() File {
8181
8282fn getStdInHandle() os.fd_t {
8383 if (builtin.os.tag == .windows) {
84 if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_aarch64) {
85 // TODO: this is just a temporary workaround until we advance x86 backend further along.
84 if (builtin.zig_backend == .stage2_aarch64) {
85 // TODO: this is just a temporary workaround until we advance aarch64 backend further along.
8686 return os.windows.GetStdHandle(os.windows.STD_INPUT_HANDLE) catch os.windows.INVALID_HANDLE_VALUE;
8787 }
8888 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 {
409409 _ = try self.addInst(.{
410410 .tag = .setcc,
411411 .ops = .r_cc,
412 .data = .{ .r_cc = .{
413 .r1 = reg,
414 .cc = cc,
415 } },
412 .data = .{ .r_cc = .{ .r = reg, .cc = cc } },
416413 });
417414}
418415
......@@ -424,14 +421,11 @@ fn asmSetccMemory(self: *Self, m: Memory, cc: bits.Condition) !void {
424421 .rip => .m_rip_cc,
425422 else => unreachable,
426423 },
427 .data = .{ .x_cc = .{
428 .payload = switch (m) {
429 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
430 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
431 else => unreachable,
432 },
433 .cc = cc,
434 } },
424 .data = .{ .x_cc = .{ .cc = cc, .payload = switch (m) {
425 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
426 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
427 else => unreachable,
428 } } },
435429 });
436430}
437431
......@@ -439,11 +433,7 @@ fn asmCmovccRegisterRegister(self: *Self, reg1: Register, reg2: Register, cc: bi
439433 _ = try self.addInst(.{
440434 .tag = .cmovcc,
441435 .ops = .rr_cc,
442 .data = .{ .rr_cc = .{
443 .r1 = reg1,
444 .r2 = reg2,
445 .cc = cc,
446 } },
436 .data = .{ .rr_cc = .{ .r1 = reg1, .r2 = reg2, .cc = cc } },
447437 });
448438}
449439
......@@ -455,15 +445,11 @@ fn asmCmovccRegisterMemory(self: *Self, reg: Register, m: Memory, cc: bits.Condi
455445 .rip => .rm_rip_cc,
456446 else => unreachable,
457447 },
458 .data = .{ .rx_cc = .{
459 .r1 = reg,
460 .cc = cc,
461 .payload = switch (m) {
462 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
463 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
464 else => unreachable,
465 },
466 } },
448 .data = .{ .rx_cc = .{ .r = reg, .cc = cc, .payload = switch (m) {
449 .sib => try self.addExtra(Mir.MemorySib.encode(m)),
450 .rip => try self.addExtra(Mir.MemoryRip.encode(m)),
451 else => unreachable,
452 } } },
467453 });
468454}
469455
......@@ -479,10 +465,7 @@ fn asmJccReloc(self: *Self, target: Mir.Inst.Index, cc: bits.Condition) !Mir.Ins
479465 return self.addInst(.{
480466 .tag = .jcc,
481467 .ops = .inst_cc,
482 .data = .{ .inst_cc = .{
483 .inst = target,
484 .cc = cc,
485 } },
468 .data = .{ .inst_cc = .{ .inst = target, .cc = cc } },
486469 });
487470}
488471
......@@ -503,13 +486,15 @@ fn asmRegister(self: *Self, tag: Mir.Inst.Tag, reg: Register) !void {
503486}
504487
505488fn asmImmediate(self: *Self, tag: Mir.Inst.Tag, imm: Immediate) !void {
506 const ops: Mir.Inst.Ops = if (imm == .signed) .imm_s else .imm_u;
507489 _ = try self.addInst(.{
508490 .tag = tag,
509 .ops = ops,
510 .data = .{ .imm = switch (imm) {
511 .signed => |x| @bitCast(u32, x),
512 .unsigned => |x| @intCast(u32, x),
491 .ops = switch (imm) {
492 .signed => .i_s,
493 .unsigned => .i_u,
494 },
495 .data = .{ .i = switch (imm) {
496 .signed => |s| @bitCast(u32, s),
497 .unsigned => |u| @intCast(u32, u),
513498 } },
514499 });
515500}
......@@ -518,37 +503,43 @@ fn asmRegisterRegister(self: *Self, tag: Mir.Inst.Tag, reg1: Register, reg2: Reg
518503 _ = try self.addInst(.{
519504 .tag = tag,
520505 .ops = .rr,
521 .data = .{ .rr = .{
522 .r1 = reg1,
523 .r2 = reg2,
524 } },
506 .data = .{ .rr = .{ .r1 = reg1, .r2 = reg2 } },
525507 });
526508}
527509
528510fn asmRegisterImmediate(self: *Self, tag: Mir.Inst.Tag, reg: Register, imm: Immediate) !void {
529511 const ops: Mir.Inst.Ops = switch (imm) {
530512 .signed => .ri_s,
531 .unsigned => |x| if (x <= math.maxInt(u32)) .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,
513 .unsigned => |u| if (math.cast(u32, u)) |_| .ri_u else .ri64,
547514 };
548515 _ = try self.addInst(.{
549516 .tag = tag,
550517 .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 } },
552543 });
553544}
554545
......@@ -559,109 +550,133 @@ fn asmRegisterRegisterImmediate(
559550 reg2: Register,
560551 imm: Immediate,
561552) !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 };
579553 _ = try self.addInst(.{
580554 .tag = tag,
581 .ops = ops,
582 .data = data,
555 .ops = switch (imm) {
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 } } },
583563 });
584564}
585565
586566fn 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 } };
597567 _ = try self.addInst(.{
598568 .tag = tag,
599 .ops = ops,
600 .data = data,
569 .ops = switch (m) {
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 } },
601579 });
602580}
603581
604fn asmMemoryImmediate(self: *Self, tag: Mir.Inst.Tag, m: Memory, imm: Immediate) !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 };
582fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !void {
621583 _ = try self.addInst(.{
622584 .tag = tag,
623 .ops = ops,
624 .data = data,
585 .ops = switch (m) {
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 } } },
625595 });
626596}
627597
628fn asmRegisterMemory(self: *Self, tag: Mir.Inst.Tag, reg: Register, m: Memory) !void {
629 const ops: Mir.Inst.Ops = switch (m) {
630 .sib => .rm_sib,
631 .rip => .rm_rip,
632 else => unreachable,
633 };
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)),
598fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !void {
599 _ = try self.addInst(.{
600 .tag = tag,
601 .ops = switch (m) {
602 .sib => .mr_sib,
603 .rip => .mr_rip,
638604 else => unreachable,
639 } },
640 };
605 },
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 {
641615 _ = try self.addInst(.{
642616 .tag = tag,
643 .ops = ops,
644 .data = data,
617 .ops = switch (m) {
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 } } },
645636 });
646637}
647638
648fn asmMemoryRegister(self: *Self, tag: Mir.Inst.Tag, m: Memory, reg: Register) !void {
649 const ops: Mir.Inst.Ops = switch (m) {
650 .sib => .mr_sib,
651 .rip => .mr_rip,
652 else => unreachable,
653 };
654 const data: Mir.Inst.Data = .{
655 .rx = .{ .r1 = reg, .payload = switch (ops) {
656 .mr_sib => try self.addExtra(Mir.MemorySib.encode(m)),
657 .mr_rip => try self.addExtra(Mir.MemoryRip.encode(m)),
639fn asmMemoryRegisterRegister(
640 self: *Self,
641 tag: Mir.Inst.Tag,
642 m: Memory,
643 reg1: Register,
644 reg2: Register,
645) !void {
646 _ = try self.addInst(.{
647 .tag = tag,
648 .ops = switch (m) {
649 .sib => .mrr_sib,
650 .rip => .mrr_rip,
658651 else => unreachable,
659 } },
660 };
652 },
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 {
661668 _ = try self.addInst(.{
662669 .tag = tag,
663 .ops = ops,
664 .data = data,
670 .ops = switch (m) {
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 } } },
665680 });
666681}
667682
......@@ -768,18 +783,12 @@ fn gen(self: *Self) InnerError!void {
768783 self.mir_instructions.set(backpatch_stack_sub, .{
769784 .tag = .sub,
770785 .ops = .ri_u,
771 .data = .{ .ri = .{
772 .r1 = .rsp,
773 .imm = aligned_stack_end,
774 } },
786 .data = .{ .ri = .{ .r = .rsp, .i = aligned_stack_end } },
775787 });
776788 self.mir_instructions.set(backpatch_stack_add, .{
777789 .tag = .add,
778790 .ops = .ri_u,
779 .data = .{ .ri = .{
780 .r1 = .rsp,
781 .imm = aligned_stack_end,
782 } },
791 .data = .{ .ri = .{ .r = .rsp, .i = aligned_stack_end } },
783792 });
784793
785794 const save_reg_list = try self.addExtra(Mir.SaveRegisterList{
......@@ -1392,38 +1401,80 @@ fn airFpext(self: *Self, inst: Air.Inst.Index) !void {
13921401
13931402fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
13941403 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
1395 if (self.liveness.isUnused(inst))
1396 return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
1397
1398 const operand_ty = self.air.typeOf(ty_op.operand);
1399 const operand = try self.resolveInst(ty_op.operand);
1400 const info_a = operand_ty.intInfo(self.target.*);
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) {
1404 const result = if (self.liveness.isUnused(inst)) .dead else result: {
1405 const src_ty = self.air.typeOf(ty_op.operand);
1406 const src_int_info = src_ty.intInfo(self.target.*);
1407 const src_abi_size = @intCast(u32, src_ty.abiSize(self.target.*));
1408 const src_mcv = try self.resolveInst(ty_op.operand);
1409 const src_lock = switch (src_mcv) {
14151410 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
14161411 else => null,
14171412 };
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);
1421 try self.genSetReg(dest_ty, reg, .{ .immediate = 0 });
1422 try self.genSetReg(operand_ty, reg, operand);
1423 break :blk MCValue{ .register = reg };
1424 };
1415 const dst_ty = self.air.typeOfIndex(inst);
1416 const dst_int_info = dst_ty.intInfo(self.target.*);
1417 const dst_abi_size = @intCast(u32, dst_ty.abiSize(self.target.*));
1418 const dst_mcv = if (dst_abi_size <= src_abi_size and
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 });
14271478}
14281479
14291480fn airTrunc(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1550,28 +1601,161 @@ fn airMulDivBinOp(self: *Self, inst: Air.Inst.Index) !void {
15501601
15511602fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
15521603 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1553 const result: MCValue = if (self.liveness.isUnused(inst))
1554 .dead
1555 else
1556 return self.fail("TODO implement add_sat for {}", .{self.target.cpu.arch});
1604 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1605 const ty = self.air.typeOf(bin_op.lhs);
1606
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 };
15571652 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
15581653}
15591654
15601655fn airSubSat(self: *Self, inst: Air.Inst.Index) !void {
15611656 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1562 const result: MCValue = if (self.liveness.isUnused(inst))
1563 .dead
1564 else
1565 return self.fail("TODO implement sub_sat for {}", .{self.target.cpu.arch});
1657 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1658 const ty = self.air.typeOf(bin_op.lhs);
1659
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 };
15661703 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
15671704}
15681705
15691706fn airMulSat(self: *Self, inst: Air.Inst.Index) !void {
15701707 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1571 const result: MCValue = if (self.liveness.isUnused(inst))
1572 .dead
1573 else
1574 return self.fail("TODO implement mul_sat for {}", .{self.target.cpu.arch});
1708 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else result: {
1709 const ty = self.air.typeOf(bin_op.lhs);
1710
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 };
15751759 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
15761760}
15771761
......@@ -1599,6 +1783,7 @@ fn airAddSubShlWithOverflow(self: *Self, inst: Air.Inst.Index) !void {
15991783 .add_with_overflow => try self.genBinOp(null, .add, bin_op.lhs, bin_op.rhs),
16001784 .sub_with_overflow => try self.genBinOp(null, .sub, bin_op.lhs, bin_op.rhs),
16011785 .shl_with_overflow => blk: {
1786 try self.register_manager.getReg(.rcx, null);
16021787 const lhs = try self.resolveInst(bin_op.lhs);
16031788 const rhs = try self.resolveInst(bin_op.rhs);
16041789 const shift_ty = self.air.typeOf(bin_op.rhs);
......@@ -1889,6 +2074,7 @@ fn airShlShrBinOp(self: *Self, inst: Air.Inst.Index) !void {
18892074 try self.spillRegisters(&.{.rcx});
18902075
18912076 const tag = self.air.instructions.items(.tag)[inst];
2077 try self.register_manager.getReg(.rcx, null);
18922078 const lhs = try self.resolveInst(bin_op.lhs);
18932079 const rhs = try self.resolveInst(bin_op.rhs);
18942080 const lhs_ty = self.air.typeOf(bin_op.lhs);
......@@ -2018,7 +2204,7 @@ fn airUnwrapErrUnionErr(self: *Self, inst: Air.Inst.Index) !void {
20182204 const result = try self.copyToRegisterWithInstTracking(inst, err_union_ty, operand);
20192205 if (err_off > 0) {
20202206 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 });
20222208 } else {
20232209 try self.truncateRegister(Type.anyerror, result.register);
20242210 }
......@@ -2050,9 +2236,7 @@ fn genUnwrapErrorUnionPayloadMir(
20502236 const payload_ty = err_union_ty.errorUnionPayload();
20512237
20522238 const result: MCValue = result: {
2053 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) {
2054 break :result MCValue.none;
2055 }
2239 if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result .none;
20562240
20572241 const payload_off = errUnionPayloadOffset(payload_ty, self.target.*);
20582242 switch (err_union) {
......@@ -2065,17 +2249,17 @@ fn genUnwrapErrorUnionPayloadMir(
20652249 const eu_lock = self.register_manager.lockReg(reg);
20662250 defer if (eu_lock) |lock| self.register_manager.unlockReg(lock);
20672251
2068 const result_reg: Register = if (maybe_inst) |inst|
2069 (try self.copyToRegisterWithInstTracking(inst, err_union_ty, err_union)).register
2252 const result_mcv: MCValue = if (maybe_inst) |inst|
2253 try self.copyToRegisterWithInstTracking(inst, err_union_ty, err_union)
20702254 else
2071 try self.copyToTmpRegister(err_union_ty, err_union);
2255 .{ .register = try self.copyToTmpRegister(err_union_ty, err_union) };
20722256 if (payload_off > 0) {
20732257 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 });
20752259 } else {
2076 try self.truncateRegister(payload_ty, result_reg);
2260 try self.truncateRegister(payload_ty, result_mcv.register);
20772261 }
2078 break :result MCValue{ .register = result_reg };
2262 break :result result_mcv;
20792263 },
20802264 else => return self.fail("TODO implement genUnwrapErrorUnionPayloadMir for {}", .{err_union}),
20812265 }
......@@ -2253,8 +2437,8 @@ fn airWrapOptional(self: *Self, inst: Air.Inst.Index) !void {
22532437
22542438 .stack_offset => |off| try self.asmMemoryImmediate(
22552439 .mov,
2256 Memory.sib(.byte, .{ .base = .rsp, .disp = pl_abi_size - off }),
2257 Immediate.u(0),
2440 Memory.sib(.byte, .{ .base = .rbp, .disp = pl_abi_size - off }),
2441 Immediate.u(1),
22582442 ),
22592443 }
22602444 }
......@@ -2473,10 +2657,9 @@ fn genSliceElemPtr(self: *Self, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
24732657}
24742658
24752659fn airSliceElemVal(self: *Self, inst: Air.Inst.Index) !void {
2476 const is_volatile = false; // TODO
24772660 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: {
2479 const slice_ty = self.air.typeOf(bin_op.lhs);
2661 const slice_ty = self.air.typeOf(bin_op.lhs);
2662 const result = if (!slice_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
24802663 var buf: Type.SlicePtrFieldTypeBuffer = undefined;
24812664 const slice_ptr_field_type = slice_ty.slicePtrFieldType(&buf);
24822665 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 {
25632746}
25642747
25652748fn airPtrElemVal(self: *Self, inst: Air.Inst.Index) !void {
2566 const is_volatile = false; // TODO
25672749 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
25762750 const ptr_ty = self.air.typeOf(bin_op.lhs);
2577 const ptr = try self.resolveInst(bin_op.lhs);
2578 const ptr_lock: ?RegisterLock = switch (ptr) {
2579 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2580 else => null,
2581 };
2582 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
2751 const result = if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst)) .dead else result: {
2752 // this is identical to the `airPtrElemPtr` codegen expect here an
2753 // additional `mov` is needed at the end to get the actual value
2754
2755 const elem_ty = ptr_ty.elemType2();
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();
2585 const elem_abi_size = @intCast(u32, elem_ty.abiSize(self.target.*));
2586 const index_ty = self.air.typeOf(bin_op.rhs);
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);
2765 const offset_reg = try self.elemOffset(index_ty, index_mcv, elem_abi_size);
2766 const offset_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2767 defer self.register_manager.unlockReg(offset_lock);
25932768
2594 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
2595 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2596 defer self.register_manager.unlockReg(offset_reg_lock);
2597
2598 const dst_mcv = try self.copyToRegisterWithInstTracking(inst, ptr_ty, ptr);
2599 try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
2769 const ptr_mcv = try self.resolveInst(bin_op.lhs);
2770 const elem_ptr_reg = if (ptr_mcv.isRegister() and self.liveness.operandDies(inst, 0))
2771 ptr_mcv.register
2772 else
2773 try self.copyToTmpRegister(ptr_ty, ptr_mcv);
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: {
2602 if (elem_abi_size > 8) {
2603 return self.fail("TODO copy value with size {} from pointer", .{elem_abi_size});
2604 } else {
2605 try self.asmRegisterMemory(
2606 .mov,
2607 registerAlias(dst_mcv.register, elem_abi_size),
2608 Memory.sib(Memory.PtrSize.fromSize(elem_abi_size), .{ .base = dst_mcv.register }),
2609 );
2610 break :result .{ .register = registerAlias(dst_mcv.register, @intCast(u32, elem_abi_size)) };
2611 }
2778 const dst_mcv = try self.allocRegOrMem(inst, true);
2779 const dst_lock = switch (dst_mcv) {
2780 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2781 else => null,
2782 };
2783 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
2784 try self.load(dst_mcv, .{ .register = elem_ptr_reg }, ptr_ty);
2785 break :result dst_mcv;
26122786 };
2613
26142787 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
26152788}
26162789
......@@ -2618,36 +2791,34 @@ fn airPtrElemPtr(self: *Self, inst: Air.Inst.Index) !void {
26182791 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
26192792 const extra = self.air.extraData(Air.Bin, ty_pl.payload).data;
26202793
2621 if (self.liveness.isUnused(inst)) {
2622 return self.finishAir(inst, .dead, .{ extra.lhs, extra.rhs, .none });
2623 }
2624
2625 const ptr_ty = self.air.typeOf(extra.lhs);
2626 const ptr = try self.resolveInst(extra.lhs);
2627 const ptr_lock: ?RegisterLock = switch (ptr) {
2628 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
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);
2794 const result = if (self.liveness.isUnused(inst)) .dead else result: {
2795 const ptr_ty = self.air.typeOf(extra.lhs);
2796 const ptr = try self.resolveInst(extra.lhs);
2797 const ptr_lock: ?RegisterLock = switch (ptr) {
2798 .register => |reg| self.register_manager.lockRegAssumeUnused(reg),
2799 else => null,
2800 };
2801 defer if (ptr_lock) |lock| self.register_manager.unlockReg(lock);
26422802
2643 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
2644 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
2645 defer self.register_manager.unlockReg(offset_reg_lock);
2803 const elem_ty = ptr_ty.elemType2();
2804 const elem_abi_size = elem_ty.abiSize(self.target.*);
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);
2648 try self.genBinOpMir(.add, ptr_ty, dst_mcv, .{ .register = offset_reg });
2813 const offset_reg = try self.elemOffset(index_ty, index, elem_abi_size);
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 });
26512822}
26522823
26532824fn airSetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
......@@ -2728,7 +2899,7 @@ fn airGetUnionTag(self: *Self, inst: Air.Inst.Index) !void {
27282899 else
27292900 0;
27302901 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 });
27322903 break :blk MCValue{
27332904 .register = registerAlias(result.register, @intCast(u32, layout.tag_size)),
27342905 };
......@@ -2820,12 +2991,11 @@ fn airCtz(self: *Self, inst: Air.Inst.Index) !void {
28202991 const extra_bits = self.regExtraBits(src_ty);
28212992 const masked_mcv = if (extra_bits > 0) masked: {
28222993 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),
28242996 };
28252997 const tmp_mcv = tmp: {
2826 if (src_mcv.isImmediate() or self.reuseOperand(inst, ty_op.operand, 0, src_mcv)) {
2827 break :tmp src_mcv;
2828 }
2998 if (src_mcv.isImmediate() or self.liveness.operandDies(inst, 0)) break :tmp src_mcv;
28292999 try self.genSetReg(src_ty, dst_reg, src_mcv);
28303000 break :tmp dst_mcv;
28313001 };
......@@ -3526,34 +3696,37 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
35263696fn airStructFieldPtr(self: *Self, inst: Air.Inst.Index) !void {
35273697 const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
35283698 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);
35303700 return self.finishAir(inst, result, .{ extra.struct_operand, .none, .none });
35313701}
35323702
35333703fn airStructFieldPtrIndex(self: *Self, inst: Air.Inst.Index, index: u8) !void {
35343704 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);
35363706 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
35373707}
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 {
35403710 if (self.liveness.isUnused(inst)) {
35413711 return MCValue.dead;
35423712 }
35433713
35443714 const mcv = try self.resolveInst(operand);
35453715 const ptr_ty = self.air.typeOf(operand);
3546 const struct_ty = ptr_ty.childType();
3547 if (struct_ty.zigTypeTag() == .Struct and struct_ty.containerLayout() == .Packed) {
3548 return self.fail("TODO structFieldPtr implement packed structs", .{});
3549 }
3550 const struct_field_offset = @intCast(u32, struct_ty.structFieldOffset(index, self.target.*));
3716 const container_ty = ptr_ty.childType();
3717 const field_offset = switch (container_ty.containerLayout()) {
3718 .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*)),
3719 .Packed => if (container_ty.zigTypeTag() == .Struct and ptr_ty.ptrInfo().data.host_size == 0)
3720 container_ty.packedStructFieldByteOffset(index, self.target.*)
3721 else
3722 0,
3723 };
35513724
35523725 const dst_mcv: MCValue = result: {
35533726 switch (mcv) {
35543727 .stack_offset => {
35553728 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
3556 .immediate = struct_field_offset,
3729 .immediate = field_offset,
35573730 });
35583731 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
35593732 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
35633736 break :result dst_mcv;
35643737 },
35653738 .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);
35673740 break :result MCValue{ .ptr_stack_offset = ptr_stack_offset };
35683741 },
35693742 .register => |reg| {
......@@ -3571,7 +3744,7 @@ fn structFieldPtr(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
35713744 defer self.register_manager.unlockReg(reg_lock);
35723745
35733746 const offset_reg = try self.copyToTmpRegister(ptr_ty, .{
3574 .immediate = struct_field_offset,
3747 .immediate = field_offset,
35753748 });
35763749 const offset_reg_lock = self.register_manager.lockRegAssumeUnused(offset_reg);
35773750 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
35923765 try self.genBinOpMir(.add, ptr_ty, .{ .register = result_reg }, .{ .register = offset_reg });
35933766 break :result MCValue{ .register = result_reg };
35943767 },
3595 else => return self.fail("TODO implement codegen struct_field_ptr for {}", .{mcv}),
3768 else => return self.fail("TODO implement fieldPtr for {}", .{mcv}),
35963769 }
35973770 };
35983771 return dst_mcv;
......@@ -3609,18 +3782,22 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
36093782 }
36103783
36113784 const mcv = try self.resolveInst(operand);
3612 const struct_ty = self.air.typeOf(operand);
3613 if (struct_ty.zigTypeTag() == .Struct and struct_ty.containerLayout() == .Packed) {
3614 return self.fail("TODO airStructFieldVal implement packed structs", .{});
3615 }
3616 const struct_field_offset = struct_ty.structFieldOffset(index, self.target.*);
3617 const struct_field_ty = struct_ty.structFieldType(index);
3785 const container_ty = self.air.typeOf(operand);
3786 const field_ty = container_ty.structFieldType(index);
3787 const field_bit_offset = switch (container_ty.containerLayout()) {
3788 .Auto, .Extern => @intCast(u32, container_ty.structFieldOffset(index, self.target.*) * 8),
3789 .Packed => if (container_ty.castTag(.@"struct")) |struct_obj|
3790 struct_obj.data.packedFieldBitOffset(self.target.*, index)
3791 else
3792 0,
3793 };
36183794
36193795 const result: MCValue = result: {
36203796 switch (mcv) {
36213797 .stack_offset => |off| {
3622 const stack_offset = off - @intCast(i32, struct_field_offset);
3623 break :result MCValue{ .stack_offset = stack_offset };
3798 const byte_offset = std.math.divExact(u32, field_bit_offset, 8) catch
3799 return self.fail("TODO implement struct_field_val for a packed struct", .{});
3800 break :result MCValue{ .stack_offset = off - @intCast(i32, byte_offset) };
36243801 },
36253802 .register => |reg| {
36263803 const reg_lock = self.register_manager.lockRegAssumeUnused(reg);
......@@ -3643,27 +3820,23 @@ fn airStructFieldVal(self: *Self, inst: Air.Inst.Index) !void {
36433820 defer if (dst_mcv_lock) |lock| self.register_manager.unlockReg(lock);
36443821
36453822 // Shift by struct_field_offset.
3646 const shift = @intCast(u8, struct_field_offset * 8);
3647 try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv.register, .{ .immediate = shift });
3823 try self.genShiftBinOpMir(.shr, Type.usize, dst_mcv, .{ .immediate = field_bit_offset });
36483824
3649 // Mask with reg.bitSize() - struct_field_size
3650 const max_reg_bit_width = Register.rax.bitSize();
3651 const mask_shift = @intCast(u6, (max_reg_bit_width - struct_field_ty.bitSize(self.target.*)));
3652 const mask = (~@as(u64, 0)) >> mask_shift;
3825 // Mask to field_bit_size bits
3826 const field_bit_size = field_ty.bitSize(self.target.*);
3827 const mask = ~@as(u64, 0) >> @intCast(u6, 64 - field_bit_size);
36533828
36543829 const tmp_reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = mask });
36553830 try self.genBinOpMir(.@"and", Type.usize, dst_mcv, .{ .register = tmp_reg });
36563831
3657 const signedness: std.builtin.Signedness = blk: {
3658 if (struct_field_ty.zigTypeTag() != .Int) break :blk .unsigned;
3659 break :blk struct_field_ty.intInfo(self.target.*).signedness;
3660 };
3661 const field_size = @intCast(u32, struct_field_ty.abiSize(self.target.*));
3662 if (signedness == .signed and field_size < 8) {
3832 const signedness =
3833 if (field_ty.isAbiInt()) field_ty.intInfo(self.target.*).signedness else .unsigned;
3834 const field_byte_size = @intCast(u32, field_ty.abiSize(self.target.*));
3835 if (signedness == .signed and field_byte_size < 8) {
36633836 try self.asmRegisterRegister(
36643837 .movsx,
36653838 dst_mcv.register,
3666 registerAlias(dst_mcv.register, field_size),
3839 registerAlias(dst_mcv.register, field_byte_size),
36673840 );
36683841 }
36693842
......@@ -3707,10 +3880,10 @@ fn genUnOp(self: *Self, maybe_inst: ?Air.Inst.Index, tag: Air.Inst.Tag, src_air:
37073880 const src_ty = self.air.typeOf(src_air);
37083881 const src_mcv = try self.resolveInst(src_air);
37093882 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.?)});
37113884 }
37123885 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.?)});
37143887 }
37153888
37163889 switch (src_mcv) {
......@@ -3805,29 +3978,186 @@ fn genUnOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValue
38053978}
38063979
38073980/// Clobbers .rcx for non-immediate shift value.
3808fn genShiftBinOpMir(self: *Self, tag: Mir.Inst.Tag, ty: Type, reg: Register, shift: MCValue) !void {
3809 switch (tag) {
3810 .sal, .sar, .shl, .shr => {},
3811 else => unreachable,
3812 }
3813
3814 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
3815 blk: {
3816 switch (shift) {
3981fn genShiftBinOpMir(
3982 self: *Self,
3983 tag: Mir.Inst.Tag,
3984 ty: Type,
3985 lhs_mcv: MCValue,
3986 shift_mcv: MCValue,
3987) !void {
3988 const rhs_mcv: MCValue = rhs: {
3989 switch (shift_mcv) {
38173990 .immediate => |imm| switch (imm) {
38183991 0 => return,
3819 else => return self.asmRegisterImmediate(tag, registerAlias(reg, abi_size), Immediate.u(imm)),
3820 },
3821 .register => |shift_reg| {
3822 if (shift_reg == .rcx) break :blk;
3992 else => break :rhs shift_mcv,
38233993 },
3994 .register => |shift_reg| if (shift_reg == .rcx) break :rhs shift_mcv,
38243995 else => {},
38253996 }
38263997 self.register_manager.getRegAssumeFree(.rcx, null);
3827 try self.genSetReg(Type.u8, .rcx, shift);
3828 }
3998 try self.genSetReg(Type.u8, .rcx, shift_mcv);
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 });
38314161}
38324162
38334163/// Result is always a register.
......@@ -3837,68 +4167,61 @@ fn genShiftBinOp(
38374167 self: *Self,
38384168 tag: Air.Inst.Tag,
38394169 maybe_inst: ?Air.Inst.Index,
3840 lhs: MCValue,
3841 rhs: MCValue,
4170 lhs_mcv: MCValue,
4171 rhs_mcv: MCValue,
38424172 lhs_ty: Type,
38434173 rhs_ty: Type,
38444174) !MCValue {
3845 if (lhs_ty.zigTypeTag() == .Vector or lhs_ty.zigTypeTag() == .Float) {
4175 if (lhs_ty.zigTypeTag() == .Vector) {
38464176 return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
38474177 }
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) {
38494183 return self.fail("TODO implement genShiftBinOp for {}", .{lhs_ty.fmtDebug()});
38504184 }
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) {
38554191 .register => |reg| self.register_manager.lockReg(reg),
38564192 else => null,
38574193 };
38584194 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) {
38614197 .register => |reg| self.register_manager.lockReg(reg),
38624198 else => null,
38634199 };
38644200 defer if (rhs_lock) |lock| self.register_manager.unlockReg(lock);
38654201
3866 self.register_manager.getRegAssumeFree(.rcx, null);
3867 const rcx_lock = self.register_manager.lockRegAssumeUnused(.rcx);
3868 defer self.register_manager.unlockReg(rcx_lock);
3869
3870 const dst: MCValue = blk: {
4202 const dst_mcv: MCValue = dst: {
38714203 if (maybe_inst) |inst| {
38724204 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3873 // TODO dst can also be a memory location
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);
4205 if (self.reuseOperand(inst, bin_op.lhs, 0, lhs_mcv)) break :dst lhs_mcv;
38784206 }
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;
38804210 };
38814211
38824212 const signedness = lhs_ty.intInfo(self.target.*).signedness;
3883 switch (tag) {
3884 .shl => try self.genShiftBinOpMir(switch (signedness) {
4213 try self.genShiftBinOpMir(switch (tag) {
4214 .shl, .shl_exact => switch (signedness) {
38854215 .signed => .sal,
38864216 .unsigned => .shl,
3887 }, lhs_ty, dst.register, rhs),
3888
3889 .shl_exact => try self.genShiftBinOpMir(.shl, lhs_ty, dst.register, rhs),
3890
3891 .shr,
3892 .shr_exact,
3893 => try self.genShiftBinOpMir(switch (signedness) {
4217 },
4218 .shr, .shr_exact => switch (signedness) {
38944219 .signed => .sar,
38954220 .unsigned => .shr,
3896 }, lhs_ty, dst.register, rhs),
3897
4221 },
38984222 else => unreachable,
3899 }
3900
3901 return dst;
4223 }, lhs_ty, dst_mcv, rhs_mcv);
4224 return dst_mcv;
39024225}
39034226
39044227/// Result is always a register.
......@@ -3915,7 +4238,8 @@ fn genMulDivBinOp(
39154238 if (ty.zigTypeTag() == .Vector or ty.zigTypeTag() == .Float) {
39164239 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
39174240 }
3918 if (ty.abiSize(self.target.*) > 8) {
4241 const abi_size = @intCast(u32, ty.abiSize(self.target.*));
4242 if (abi_size > 8) {
39194243 return self.fail("TODO implement genMulDivBinOp for {}", .{ty.fmtDebug()});
39204244 }
39214245 if (tag == .div_float) {
......@@ -3925,10 +4249,8 @@ fn genMulDivBinOp(
39254249 assert(self.register_manager.isRegFree(.rax));
39264250 assert(self.register_manager.isRegFree(.rdx));
39274251
3928 const reg_locks = self.register_manager.lockRegsAssumeUnused(2, .{ .rax, .rdx });
3929 defer for (reg_locks) |reg| {
3930 self.register_manager.unlockReg(reg);
3931 };
4252 const reg_locks = self.register_manager.lockRegs(2, .{ .rax, .rdx });
4253 defer for (reg_locks) |reg_lock| if (reg_lock) |lock| self.register_manager.unlockReg(lock);
39324254
39334255 const int_info = ty.intInfo(self.target.*);
39344256 const signedness = int_info.signedness;
......@@ -3953,35 +4275,24 @@ fn genMulDivBinOp(
39534275
39544276 const mir_tag: Mir.Inst.Tag = switch (signedness) {
39554277 .signed => switch (tag) {
3956 .mul, .mulwrap => Mir.Inst.Tag.imul,
3957 .div_trunc, .div_exact, .rem => Mir.Inst.Tag.idiv,
4278 .mul, .mulwrap => .imul,
4279 .div_trunc, .div_exact, .rem => .idiv,
39584280 else => unreachable,
39594281 },
39604282 .unsigned => switch (tag) {
3961 .mul, .mulwrap => Mir.Inst.Tag.mul,
3962 .div_trunc, .div_exact, .rem => Mir.Inst.Tag.div,
4283 .mul, .mulwrap => .mul,
4284 .div_trunc, .div_exact, .rem => .div,
39634285 else => unreachable,
39644286 },
39654287 };
39664288
39674289 try self.genIntMulDivOpMir(mir_tag, ty, .signed, lhs, rhs);
39684290
3969 switch (signedness) {
3970 .signed => switch (tag) {
3971 .mul, .mulwrap, .div_trunc, .div_exact => return MCValue{ .register = .rax },
3972 .rem => return MCValue{ .register = .rdx },
3973 else => unreachable,
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 }
4291 return .{ .register = registerAlias(switch (tag) {
4292 .mul, .mulwrap, .div_trunc, .div_exact => .rax,
4293 .rem => .rdx,
4294 else => unreachable,
4295 }, abi_size) };
39854296 },
39864297
39874298 .mod => {
......@@ -3998,14 +4309,14 @@ fn genMulDivBinOp(
39984309 const result: MCValue = if (maybe_inst) |inst|
39994310 try self.copyToRegisterWithInstTracking(inst, ty, lhs)
40004311 else
4001 MCValue{ .register = try self.copyToTmpRegister(ty, lhs) };
4312 .{ .register = try self.copyToTmpRegister(ty, lhs) };
40024313 try self.genBinOpMir(.sub, ty, result, div_floor);
40034314
40044315 return result;
40054316 },
40064317 .unsigned => {
40074318 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) };
40094320 },
40104321 }
40114322 },
......@@ -4397,7 +4708,7 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
43974708 );
43984709 }
43994710 },
4400 else => return self.fail("TODO getBinOpMir implement large immediate ABI", .{}),
4711 else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),
44014712 }
44024713 },
44034714 .memory,
......@@ -4478,28 +4789,28 @@ fn genBinOpMir(self: *Self, mir_tag: Mir.Inst.Tag, dst_ty: Type, dst_mcv: MCValu
44784789 );
44794790 }
44804791 },
4481 else => return self.fail("TODO getBinOpMir implement large immediate ABI", .{}),
4792 else => return self.fail("TODO genBinOpMir implement large immediate ABI", .{}),
44824793 }
44834794 },
44844795 .memory,
44854796 .stack_offset,
44864797 .ptr_stack_offset,
44874798 => {
4488 return self.fail("TODO implement x86 ADD/SUB/CMP source memory", .{});
4799 return self.fail("TODO implement x86 genBinOpMir source memory", .{});
44894800 },
44904801 .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", .{});
44924803 },
44934804 .eflags => {
4494 return self.fail("TODO implement x86 ADD/SUB/CMP source eflags", .{});
4805 return self.fail("TODO implement x86 genBinOpMir source eflags", .{});
44954806 },
44964807 }
44974808 },
44984809 .memory => {
4499 return self.fail("TODO implement x86 ADD/SUB/CMP destination memory", .{});
4810 return self.fail("TODO implement x86 genBinOpMir destination memory", .{});
45004811 },
45014812 .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", .{});
45034814 },
45044815 }
45054816}
......@@ -5437,7 +5748,7 @@ fn isErr(self: *Self, maybe_inst: ?Air.Inst.Index, ty: Type, operand: MCValue) !
54375748 const tmp_reg = try self.copyToTmpRegister(ty, operand);
54385749 if (err_off > 0) {
54395750 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 });
54415752 } else {
54425753 try self.truncateRegister(Type.anyerror, tmp_reg);
54435754 }
......@@ -5945,13 +6256,23 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
59456256 const inputs = @ptrCast([]const Air.Inst.Ref, self.air.extra[extra_i..][0..extra.data.inputs_len]);
59466257 extra_i += inputs.len;
59476258
5948 const dead = !is_volatile and self.liveness.isUnused(inst);
5949 const result: MCValue = if (dead) .dead else result: {
6259 var result: MCValue = .none;
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
59506271 if (outputs.len > 1) {
59516272 return self.fail("TODO implement codegen for asm with more than 1 output", .{});
59526273 }
59536274
5954 const output_constraint: ?[]const u8 = for (outputs) |output| {
6275 for (outputs) |output| {
59556276 if (output != .none) {
59566277 return self.fail("TODO implement codegen for non-expr asm", .{});
59576278 }
......@@ -5962,8 +6283,21 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
59626283 // for the string, we still use the next u32 for the null terminator.
59636284 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
59646285
5965 break constraint;
5966 } else null;
6286 const mcv: MCValue = if (mem.eql(u8, constraint, "=r"))
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
59686302 for (inputs) |input| {
59696303 const input_bytes = std.mem.sliceAsBytes(self.air.extra[extra_i..]);
......@@ -5997,52 +6331,73 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
59976331 }
59986332 }
59996333
6000 const asm_source = std.mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
6001
6002 {
6003 var iter = std.mem.tokenize(u8, asm_source, "\n\r");
6004 while (iter.next()) |ins| {
6005 if (mem.eql(u8, ins, "syscall")) {
6006 try self.asmOpOnly(.syscall);
6007 } else if (mem.indexOf(u8, ins, "push")) |_| {
6008 const arg = ins[4..];
6009 if (mem.indexOf(u8, arg, "$")) |l| {
6010 const n = std.fmt.parseInt(u8, ins[4 + l + 1 ..], 10) catch {
6011 return self.fail("TODO implement more inline asm int parsing", .{});
6012 };
6013 try self.asmImmediate(.push, Immediate.u(n));
6014 } else if (mem.indexOf(u8, arg, "%%")) |l| {
6015 const reg_name = ins[4 + l + 2 ..];
6016 const reg = parseRegName(reg_name) orelse
6017 return self.fail("unrecognized register: '{s}'", .{reg_name});
6018 try self.asmRegister(.push, reg);
6019 } else return self.fail("TODO more push operands", .{});
6020 } else if (mem.indexOf(u8, ins, "pop")) |_| {
6021 const arg = ins[3..];
6022 if (mem.indexOf(u8, arg, "%%")) |l| {
6023 const reg_name = ins[3 + l + 2 ..];
6024 const reg = parseRegName(reg_name) orelse
6025 return self.fail("unrecognized register: '{s}'", .{reg_name});
6026 try self.asmRegister(.pop, reg);
6027 } else return self.fail("TODO more pop operands", .{});
6028 } else {
6029 return self.fail("TODO implement support for more x86 assembly instructions", .{});
6334 const asm_source = mem.sliceAsBytes(self.air.extra[extra_i..])[0..extra.data.source_len];
6335 var line_it = mem.tokenize(u8, asm_source, "\n\r");
6336 while (line_it.next()) |line| {
6337 var mnem_it = mem.tokenize(u8, line, " \t");
6338 const mnem = mnem_it.next() orelse continue;
6339 if (mem.startsWith(u8, mnem, "#")) continue;
6340 var arg_it = mem.tokenize(u8, mnem_it.rest(), ", ");
6341 if (std.ascii.eqlIgnoreCase(mnem, "syscall")) {
6342 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6343 return self.fail("Too many operands: '{s}'", .{line});
6344 try self.asmOpOnly(.syscall);
6345 } else if (std.ascii.eqlIgnoreCase(mnem, "push")) {
6346 const src = arg_it.next() orelse
6347 return self.fail("Not enough operands: '{s}'", .{line});
6348 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
6349 return self.fail("Too many operands: '{s}'", .{line});
6350 if (mem.startsWith(u8, src, "$")) {
6351 const imm = std.fmt.parseInt(u32, src["$".len..], 0) catch
6352 return self.fail("Invalid immediate: '{s}'", .{src});
6353 try self.asmImmediate(.push, Immediate.u(imm));
6354 } else if (mem.startsWith(u8, src, "%%")) {
6355 const reg = parseRegName(src["%%".len..]) orelse
6356 return self.fail("Invalid register: '{s}'", .{src});
6357 try self.asmRegister(.push, reg);
6358 } else return self.fail("Unsupported operand: '{s}'", .{src});
6359 } else if (std.ascii.eqlIgnoreCase(mnem, "pop")) {
6360 const dst = arg_it.next() orelse
6361 return self.fail("Not enough operands: '{s}'", .{line});
6362 if (arg_it.next()) |trailing| if (!mem.startsWith(u8, trailing, "#"))
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});
60306395 }
6396 } else {
6397 return self.fail("Unsupported instruction: '{s}'", .{mnem});
60316398 }
60326399 }
6033
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 };
6400 }
60466401
60476402 simple: {
60486403 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
62776632 .disp = -stack_offset,
62786633 }), immediate);
62796634 },
6280 8 => {
6635 3, 5...7 => unreachable,
6636 else => {
62816637 // 64 bit write to memory would take two mov's anyways so we
62826638 // insted just use two 32 bit writes to avoid register allocation
6283 try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{
6284 .base = base_reg,
6285 .disp = -stack_offset + 4,
6286 }), Immediate.u(@truncate(u32, x_big >> 32)));
6287 try self.asmMemoryImmediate(.mov, Memory.sib(.dword, .{
6288 .base = base_reg,
6289 .disp = -stack_offset,
6290 }), Immediate.u(@truncate(u32, x_big)));
6291 },
6292 else => {
6293 return self.fail("TODO implement set abi_size=large stack variable with immediate", .{});
6639 var offset: i32 = 0;
6640 while (offset < abi_size) : (offset += 4) try self.asmMemoryImmediate(
6641 .mov,
6642 Memory.sib(.dword, .{ .base = base_reg, .disp = offset - stack_offset }),
6643 if (ty.isSignedInt())
6644 Immediate.s(@truncate(
6645 i32,
6646 @bitCast(i64, x_big) >> (math.cast(u6, offset * 8) orelse 63),
6647 ))
6648 else
6649 Immediate.u(@truncate(
6650 u32,
6651 if (math.cast(u6, offset * 8)) |shift| x_big >> shift else 0,
6652 )),
6653 );
62946654 },
62956655 }
62966656 },
......@@ -6391,7 +6751,7 @@ fn genInlineMemcpyRegisterRegister(
63916751 }), registerAlias(tmp_reg, nearest_power_of_two));
63926752
63936753 if (nearest_power_of_two > 1) {
6394 try self.genShiftBinOpMir(.shr, ty, tmp_reg, .{
6754 try self.genShiftBinOpMir(.shr, ty, .{ .register = tmp_reg }, .{
63956755 .immediate = nearest_power_of_two * 8,
63966756 });
63976757 }
......@@ -6894,20 +7254,37 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
68947254 const ptr_ty = self.air.typeOf(extra.ptr);
68957255 const ptr_mcv = try self.resolveInst(extra.ptr);
68967256 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
68987263 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);
69007271 const rax_lock = self.register_manager.lockRegAssumeUnused(.rax);
69017272 defer self.register_manager.unlockReg(rax_lock);
69027273
69037274 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);
69057283 const new_lock = self.register_manager.lockRegAssumeUnused(new_reg);
69067284 defer self.register_manager.unlockReg(new_lock);
69077285
6908 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
69097286 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
6910 const ptr_mem: Memory = switch (ptr_mcv) {
7287 const ptr_mem = switch (ptr_mcv) {
69117288 .register => |reg| Memory.sib(ptr_size, .{ .base = reg }),
69127289 .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
69137290 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 {
69167293 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
69177294
69187295 try self.spillEflagsIfOccupied();
6919 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
6920 .r1 = new_reg,
6921 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
6922 } } });
7296 if (val_abi_size <= 8) {
7297 _ = try self.addInst(.{ .tag = .cmpxchg, .ops = .lock_mr_sib, .data = .{ .rx = .{
7298 .r = registerAlias(new_reg, val_abi_size),
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
69247307 const result: MCValue = result: {
69257308 if (self.liveness.isUnused(inst)) break :result .dead;
69267309
6927 self.eflags_inst = inst;
6928 break :result .{ .register_overflow = .{ .reg = .rax, .eflags = .ne } };
7310 if (val_abi_size <= 8) {
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;
69297320 };
69307321 return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
69317322}
......@@ -6938,9 +7329,10 @@ fn atomicOp(
69387329 ptr_ty: Type,
69397330 val_ty: Type,
69407331 unused: bool,
6941 op: ?std.builtin.AtomicRmwOp,
7332 rmw_op: ?std.builtin.AtomicRmwOp,
69427333 order: std.builtin.AtomicOrder,
69437334) InnerError!void {
7335 const dst_mcv = MCValue{ .register = dst_reg };
69447336 const dst_lock = self.register_manager.lockReg(dst_reg);
69457337 defer if (dst_lock) |lock| self.register_manager.unlockReg(lock);
69467338
......@@ -6958,7 +7350,7 @@ fn atomicOp(
69587350
69597351 const val_abi_size = @intCast(u32, val_ty.abiSize(self.target.*));
69607352 const ptr_size = Memory.PtrSize.fromSize(val_abi_size);
6961 const ptr_mem: Memory = switch (ptr_mcv) {
7353 const ptr_mem = switch (ptr_mcv) {
69627354 .register => |reg| Memory.sib(ptr_size, .{ .base = reg }),
69637355 .ptr_stack_offset => |off| Memory.sib(ptr_size, .{ .base = .rbp, .disp = -off }),
69647356 else => Memory.sib(ptr_size, .{ .base = try self.copyToTmpRegister(ptr_ty, ptr_mcv) }),
......@@ -6966,48 +7358,197 @@ fn atomicOp(
69667358 const mem_lock = if (ptr_mem.base()) |reg| self.register_manager.lockReg(reg) else null;
69677359 defer if (mem_lock) |lock| self.register_manager.unlockReg(lock);
69687360
6969 try self.genSetReg(val_ty, dst_reg, val_mcv);
6970
6971 const need_loop = val_ty.isRuntimeFloat() or if (op) |rmw| switch (rmw) {
6972 .Xchg, .Add, .Sub => false,
6973 .And, .Or, .Xor => !unused,
6974 .Nand, .Max, .Min => true,
6975 } else false;
6976 if (!need_loop) {
6977 const tag: Mir.Inst.Tag = if (op) |rmw| switch (rmw) {
6978 .Xchg => if (unused) .mov else .xchg,
6979 .Add => if (unused) .add else .xadd,
6980 .Sub => if (unused) .sub else .xadd,
6981 .And => .@"and",
6982 .Or => .@"or",
6983 .Xor => .xor,
6984 else => unreachable,
6985 } else switch (order) {
6986 .Unordered, .Monotonic, .Release, .AcqRel => .mov,
6987 .Acquire => unreachable,
6988 .SeqCst => .xchg,
6989 };
6990 if (op == std.builtin.AtomicRmwOp.Sub and tag == .xadd) {
6991 try self.genUnOpMir(.neg, val_ty, .{ .register = dst_reg });
6992 }
6993 _ = try self.addInst(.{ .tag = tag, .ops = switch (tag) {
6994 .mov, .xchg => .mr_sib,
6995 .xadd, .add, .sub, .@"and", .@"or", .xor => .lock_mr_sib,
6996 else => unreachable,
6997 }, .data = .{ .rx = .{
6998 .r1 = registerAlias(dst_reg, val_abi_size),
6999 .payload = try self.addExtra(Mir.MemorySib.encode(ptr_mem)),
7000 } } });
7001 return;
7002 }
7361 const method: enum { lock, loop, libcall } = if (val_ty.isRuntimeFloat())
7362 .loop
7363 else switch (rmw_op orelse .Xchg) {
7364 .Xchg,
7365 .Add,
7366 .Sub,
7367 => if (val_abi_size <= 8) .lock else if (val_abi_size <= 16) .loop else .libcall,
7368 .And,
7369 .Or,
7370 .Xor,
7371 => if (val_abi_size <= 8 and unused) .lock else if (val_abi_size <= 16) .loop else .libcall,
7372 .Nand,
7373 .Max,
7374 .Min,
7375 => if (val_abi_size <= 16) .loop else .libcall,
7376 };
7377 switch (method) {
7378 .lock => {
7379 const tag: Mir.Inst.Tag = if (rmw_op) |op| switch (op) {
7380 .Xchg => if (unused) .mov else .xchg,
7381 .Add => if (unused) .add else .xadd,
7382 .Sub => if (unused) .sub else .xadd,
7383 .And => .@"and",
7384 .Or => .@"or",
7385 .Xor => .xor,
7386 else => unreachable,
7387 } else switch (order) {
7388 .Unordered, .Monotonic, .Release, .AcqRel => .mov,
7389 .Acquire => unreachable,
7390 .SeqCst => .xchg,
7391 };
7392
7393 try self.genSetReg(val_ty, dst_reg, val_mcv);
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 }
70057542}
70067543
70077544fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
70087545 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
70097546 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
70117552 const unused = self.liveness.isUnused(inst);
70127553 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 {
75878128 switch (int_info.signedness) {
75888129 .signed => {
75898130 const shift = @intCast(u6, max_reg_bit_width - int_info.bits);
7590 try self.genShiftBinOpMir(.sal, Type.isize, reg, .{ .immediate = shift });
7591 try self.genShiftBinOpMir(.sar, Type.isize, reg, .{ .immediate = shift });
8131 try self.genShiftBinOpMir(.sal, Type.isize, .{ .register = reg }, .{ .immediate = shift });
8132 try self.genShiftBinOpMir(.sar, Type.isize, .{ .register = reg }, .{ .immediate = shift });
75928133 },
75938134 .unsigned => {
75948135 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 {
121121 .sbb,
122122 .sfence,
123123 .shl,
124 .shld,
124125 .shr,
126 .shrd,
125127 .sub,
126128 .syscall,
127129 .@"test",
......@@ -231,10 +233,10 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
231233 const prefix: Instruction.Prefix = switch (ops) {
232234 .lock_m_sib,
233235 .lock_m_rip,
234 .lock_mi_u_sib,
235 .lock_mi_u_rip,
236 .lock_mi_s_sib,
237 .lock_mi_s_rip,
236 .lock_mi_sib_u,
237 .lock_mi_rip_u,
238 .lock_mi_sib_s,
239 .lock_mi_rip_s,
238240 .lock_mr_sib,
239241 .lock_mr_rip,
240242 .lock_moffs_rax,
......@@ -249,31 +251,36 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
249251
250252 switch (ops) {
251253 .none => {},
252 .imm_s => op1 = .{ .imm = Immediate.s(@bitCast(i32, data.imm)) },
253 .imm_u => op1 = .{ .imm = Immediate.u(data.imm) },
254 .i_s => op1 = .{ .imm = Immediate.s(@bitCast(i32, data.i)) },
255 .i_u => op1 = .{ .imm = Immediate.u(data.i) },
254256 .r => op1 = .{ .reg = data.r },
255257 .rr => {
256258 op1 = .{ .reg = data.rr.r1 };
257259 op2 = .{ .reg = data.rr.r2 };
258260 },
261 .rrr => {
262 op1 = .{ .reg = data.rrr.r1 };
263 op2 = .{ .reg = data.rrr.r2 };
264 op3 = .{ .reg = data.rrr.r3 };
265 },
259266 .ri_s, .ri_u => {
260267 const imm = switch (ops) {
261 .ri_s => Immediate.s(@bitCast(i32, data.ri.imm)),
262 .ri_u => Immediate.u(data.ri.imm),
268 .ri_s => Immediate.s(@bitCast(i32, data.ri.i)),
269 .ri_u => Immediate.u(data.ri.i),
263270 else => unreachable,
264271 };
265 op1 = .{ .reg = data.ri.r1 };
272 op1 = .{ .reg = data.ri.r };
266273 op2 = .{ .imm = imm };
267274 },
268275 .ri64 => {
269276 const imm64 = emit.mir.extraData(Mir.Imm64, data.rx.payload).data;
270 op1 = .{ .reg = data.rx.r1 };
277 op1 = .{ .reg = data.rx.r };
271278 op2 = .{ .imm = Immediate.u(Mir.Imm64.decode(imm64)) };
272279 },
273280 .rri_s, .rri_u => {
274281 const imm = switch (ops) {
275 .rri_s => Immediate.s(@bitCast(i32, data.rri.imm)),
276 .rri_u => Immediate.u(data.rri.imm),
282 .rri_s => Immediate.s(@bitCast(i32, data.rri.i)),
283 .rri_u => Immediate.u(data.rri.i),
277284 else => unreachable,
278285 };
279286 op1 = .{ .reg = data.rri.r1 };
......@@ -288,21 +295,21 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
288295 const mrip = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
289296 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
290297 },
291 .mi_s_sib, .mi_u_sib, .lock_mi_s_sib, .lock_mi_u_sib => {
292 const msib = emit.mir.extraData(Mir.MemorySib, data.xi.payload).data;
298 .mi_sib_s, .mi_sib_u, .lock_mi_sib_s, .lock_mi_sib_u => {
299 const msib = emit.mir.extraData(Mir.MemorySib, data.ix.payload).data;
293300 const imm = switch (ops) {
294 .mi_s_sib, .lock_mi_s_sib => Immediate.s(@bitCast(i32, data.xi.imm)),
295 .mi_u_sib, .lock_mi_u_sib => Immediate.u(data.xi.imm),
301 .mi_sib_s, .lock_mi_sib_s => Immediate.s(@bitCast(i32, data.ix.i)),
302 .mi_sib_u, .lock_mi_sib_u => Immediate.u(data.ix.i),
296303 else => unreachable,
297304 };
298305 op1 = .{ .mem = Mir.MemorySib.decode(msib) };
299306 op2 = .{ .imm = imm };
300307 },
301 .mi_u_rip, .mi_s_rip, .lock_mi_u_rip, .lock_mi_s_rip => {
302 const mrip = emit.mir.extraData(Mir.MemoryRip, data.xi.payload).data;
308 .mi_rip_u, .mi_rip_s, .lock_mi_rip_u, .lock_mi_rip_s => {
309 const mrip = emit.mir.extraData(Mir.MemoryRip, data.ix.payload).data;
303310 const imm = switch (ops) {
304 .mi_s_rip, .lock_mi_s_rip => Immediate.s(@bitCast(i32, data.xi.imm)),
305 .mi_u_rip, .lock_mi_u_rip => Immediate.u(data.xi.imm),
311 .mi_rip_s, .lock_mi_rip_s => Immediate.s(@bitCast(i32, data.ix.i)),
312 .mi_rip_u, .lock_mi_rip_u => Immediate.u(data.ix.i),
306313 else => unreachable,
307314 };
308315 op1 = .{ .mem = Mir.MemoryRip.decode(mrip) };
......@@ -310,7 +317,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
310317 },
311318 .rm_sib, .mr_sib, .lock_mr_sib => {
312319 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 };
314321 const op_m = .{ .mem = Mir.MemorySib.decode(msib) };
315322 switch (ops) {
316323 .rm_sib => {
......@@ -326,7 +333,7 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
326333 },
327334 .rm_rip, .mr_rip, .lock_mr_rip => {
328335 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 };
330337 const op_m = .{ .mem = Mir.MemoryRip.decode(mrip) };
331338 switch (ops) {
332339 .rm_rip => {
......@@ -340,6 +347,30 @@ fn mirEncodeGeneric(emit: *Emit, tag: Mir.Inst.Tag, inst: Mir.Inst.Index) InnerE
340347 else => unreachable,
341348 }
342349 },
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 },
343374 else => return emit.fail("TODO handle generic encoding: {s}, {s}", .{
344375 @tagName(mnemonic),
345376 @tagName(ops),
......@@ -451,12 +482,12 @@ fn mirMovsx(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
451482 },
452483 .rm_sib => {
453484 const msib = emit.mir.extraData(Mir.MemorySib, data.rx.payload).data;
454 op1 = .{ .reg = data.rx.r1 };
485 op1 = .{ .reg = data.rx.r };
455486 op2 = .{ .mem = Mir.MemorySib.decode(msib) };
456487 },
457488 .rm_rip => {
458489 const mrip = emit.mir.extraData(Mir.MemoryRip, data.rx.payload).data;
459 op1 = .{ .reg = data.rx.r1 };
490 op1 = .{ .reg = data.rx.r };
460491 op2 = .{ .mem = Mir.MemoryRip.decode(mrip) };
461492 },
462493 else => unreachable, // TODO
......@@ -495,7 +526,7 @@ fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
495526 const extra = emit.mir.extraData(Mir.MemorySib, data.payload).data;
496527 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
497528 return emit.encode(mnemonic, .{
498 .op1 = .{ .reg = data.r1 },
529 .op1 = .{ .reg = data.r },
499530 .op2 = .{ .mem = Mir.MemorySib.decode(extra) },
500531 });
501532 },
......@@ -504,7 +535,7 @@ fn mirCmovcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
504535 const extra = emit.mir.extraData(Mir.MemoryRip, data.payload).data;
505536 const mnemonic = mnemonicFromConditionCode("cmov", data.cc);
506537 return emit.encode(mnemonic, .{
507 .op1 = .{ .reg = data.r1 },
538 .op1 = .{ .reg = data.r },
508539 .op2 = .{ .mem = Mir.MemoryRip.decode(extra) },
509540 });
510541 },
......@@ -519,7 +550,7 @@ fn mirSetcc(emit: *Emit, inst: Mir.Inst.Index) InnerError!void {
519550 const data = emit.mir.instructions.items(.data)[inst].r_cc;
520551 const mnemonic = mnemonicFromConditionCode("set", data.cc);
521552 return emit.encode(mnemonic, .{
522 .op1 = .{ .reg = data.r1 },
553 .op1 = .{ .reg = data.r },
523554 });
524555 },
525556 .m_sib_cc => {
src/arch/x86_64/Encoding.zig+7-6
......@@ -262,15 +262,15 @@ pub fn format(
262262 try writer.print("+{s} ", .{tag});
263263 },
264264 .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 "),
266266 }
267267
268268 switch (encoding.op_en) {
269 .i, .d, .zi, .oi, .mi, .rmi => {
269 .i, .d, .zi, .oi, .mi, .rmi, .mri => {
270270 const op = switch (encoding.op_en) {
271271 .i, .d => encoding.op1,
272272 .zi, .oi, .mi => encoding.op2,
273 .rmi => encoding.op3,
273 .rmi, .mri => encoding.op3,
274274 else => unreachable,
275275 };
276276 const tag = switch (op) {
......@@ -285,7 +285,7 @@ pub fn format(
285285 };
286286 try writer.print("{s} ", .{tag});
287287 },
288 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm => {},
288 .np, .fd, .td, .o, .m, .m1, .mc, .mr, .rm, .mrc => {},
289289 }
290290
291291 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
......@@ -334,7 +334,7 @@ pub const Mnemonic = enum {
334334 rcl, rcr, ret, rol, ror,
335335 sal, sar, sbb,
336336 scas, scasb, scasd, scasq, scasw,
337 shl, shr, sub, syscall,
337 shl, shld, shr, shrd, sub, syscall,
338338 seta, setae, setb, setbe, setc, sete, setg, setge, setl, setle, setna, setnae,
339339 setnb, setnbe, setnc, setne, setng, setnge, setnl, setnle, setno, setnp, setns,
340340 setnz, seto, setp, setpe, setpo, sets, setz,
......@@ -374,7 +374,8 @@ pub const OpEn = enum {
374374 i, zi,
375375 d, m,
376376 fd, td,
377 m1, mc, mi, mr, rm, rmi,
377 m1, mc, mi, mr, rm,
378 rmi, mri, mrc,
378379 // zig fmt: on
379380};
380381
src/arch/x86_64/Mir.zig+53-25
......@@ -138,8 +138,12 @@ pub const Inst = struct {
138138 sfence,
139139 /// Logical shift left
140140 shl,
141 /// Double precision shift left
142 shld,
141143 /// Logical shift right
142144 shr,
145 /// Double precision shift right
146 shrd,
143147 /// Subtract
144148 sub,
145149 /// Syscall
......@@ -284,10 +288,10 @@ pub const Inst = struct {
284288 ri64,
285289 /// Immediate (sign-extended) operand.
286290 /// Uses `imm` payload.
287 imm_s,
291 i_s,
288292 /// Immediate (unsigned) operand.
289293 /// Uses `imm` payload.
290 imm_u,
294 i_u,
291295 /// Relative displacement operand.
292296 /// Uses `imm` payload.
293297 rel,
......@@ -316,23 +320,35 @@ pub const Inst = struct {
316320 /// Uses `x_cc` with extra data of type `MemoryRip`.
317321 m_rip_cc,
318322 /// Memory (SIB), immediate (unsigned) operands.
319 /// Uses `xi` payload with extra data of type `MemorySib`.
320 mi_u_sib,
323 /// Uses `ix` payload with extra data of type `MemorySib`.
324 mi_sib_u,
321325 /// Memory (RIP), immediate (unsigned) operands.
322 /// Uses `xi` payload with extra data of type `MemoryRip`.
323 mi_u_rip,
326 /// Uses `ix` payload with extra data of type `MemoryRip`.
327 mi_rip_u,
324328 /// Memory (SIB), immediate (sign-extend) operands.
325 /// Uses `xi` payload with extra data of type `MemorySib`.
326 mi_s_sib,
329 /// Uses `ix` payload with extra data of type `MemorySib`.
330 mi_sib_s,
327331 /// Memory (RIP), immediate (sign-extend) operands.
328 /// Uses `xi` payload with extra data of type `MemoryRip`.
329 mi_s_rip,
332 /// Uses `ix` payload with extra data of type `MemoryRip`.
333 mi_rip_s,
330334 /// Memory (SIB), register operands.
331335 /// Uses `rx` payload with extra data of type `MemorySib`.
332336 mr_sib,
333337 /// Memory (RIP), register operands.
334338 /// Uses `rx` payload with extra data of type `MemoryRip`.
335339 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,
336352 /// Rax, Memory moffs.
337353 /// Uses `payload` with extra data of type `MemoryMoffs`.
338354 rax_moffs,
......@@ -347,16 +363,16 @@ pub const Inst = struct {
347363 lock_m_rip,
348364 /// Memory (SIB), immediate (unsigned) operands with lock prefix.
349365 /// Uses `xi` payload with extra data of type `MemorySib`.
350 lock_mi_u_sib,
366 lock_mi_sib_u,
351367 /// Memory (RIP), immediate (unsigned) operands with lock prefix.
352368 /// Uses `xi` payload with extra data of type `MemoryRip`.
353 lock_mi_u_rip,
369 lock_mi_rip_u,
354370 /// Memory (SIB), immediate (sign-extend) operands with lock prefix.
355371 /// Uses `xi` payload with extra data of type `MemorySib`.
356 lock_mi_s_sib,
372 lock_mi_sib_s,
357373 /// Memory (RIP), immediate (sign-extend) operands with lock prefix.
358374 /// Uses `xi` payload with extra data of type `MemoryRip`.
359 lock_mi_s_rip,
375 lock_mi_rip_s,
360376 /// Memory (SIB), register operands with lock prefix.
361377 /// Uses `rx` payload with extra data of type `MemorySib`.
362378 lock_mr_sib,
......@@ -400,7 +416,7 @@ pub const Inst = struct {
400416 cc: bits.Condition,
401417 },
402418 /// A 32-bit immediate value.
403 imm: u32,
419 i: u32,
404420 r: Register,
405421 rr: struct {
406422 r1: Register,
......@@ -414,16 +430,16 @@ pub const Inst = struct {
414430 rri: struct {
415431 r1: Register,
416432 r2: Register,
417 imm: u32,
433 i: u32,
418434 },
419435 /// Condition code (CC), followed by custom payload found in extra.
420436 x_cc: struct {
421 payload: u32,
422437 cc: bits.Condition,
438 payload: u32,
423439 },
424440 /// Register with condition code (CC).
425441 r_cc: struct {
426 r1: Register,
442 r: Register,
427443 cc: bits.Condition,
428444 },
429445 /// Register, register with condition code (CC).
......@@ -434,24 +450,36 @@ pub const Inst = struct {
434450 },
435451 /// Register, immediate.
436452 ri: struct {
437 r1: Register,
438 imm: u32,
453 r: Register,
454 i: u32,
439455 },
440456 /// Register, followed by custom payload found in extra.
441457 rx: struct {
442 r1: Register,
458 r: Register,
443459 payload: u32,
444460 },
445461 /// Register with condition code (CC), followed by custom payload found in extra.
446462 rx_cc: struct {
447 r1: Register,
463 r: Register,
448464 cc: bits.Condition,
449465 payload: u32,
450466 },
451 /// Custom payload followed by an immediate.
452 xi: struct {
467 /// Immediate, followed by Custom payload found in extra.
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,
453482 payload: u32,
454 imm: u32,
455483 },
456484 /// String instruction prefix and width.
457485 string: struct {
src/arch/x86_64/bits.zig+11-12
......@@ -411,20 +411,17 @@ pub const Memory = union(enum) {
411411 dword,
412412 qword,
413413 tbyte,
414 dqword,
414415
415416 pub fn fromSize(size: u32) PtrSize {
416 return if (size <= 1)
417 .byte
418 else if (size <= 2)
419 .word
420 else if (size <= 4)
421 .dword
422 else if (size <= 8)
423 .qword
424 else if (size == 10)
425 .tbyte
426 else
427 unreachable;
417 return switch (size) {
418 1...1 => .byte,
419 2...2 => .word,
420 3...4 => .dword,
421 5...8 => .qword,
422 9...16 => .dqword,
423 else => unreachable,
424 };
428425 }
429426
430427 pub fn fromBitSize(bit_size: u64) PtrSize {
......@@ -434,6 +431,7 @@ pub const Memory = union(enum) {
434431 32 => .dword,
435432 64 => .qword,
436433 80 => .tbyte,
434 128 => .dqword,
437435 else => unreachable,
438436 };
439437 }
......@@ -445,6 +443,7 @@ pub const Memory = union(enum) {
445443 .dword => 32,
446444 .qword => 64,
447445 .tbyte => 80,
446 .dqword => 128,
448447 };
449448 }
450449 };
src/arch/x86_64/encoder.zig+10-12
......@@ -117,7 +117,7 @@ pub const Instruction = struct {
117117
118118 pub fn new(mnemonic: Mnemonic, args: Init) !Instruction {
119119 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}", .{
121121 @tagName(args.prefix),
122122 @tagName(mnemonic),
123123 @tagName(Encoding.Op.fromOperand(args.op1)),
......@@ -174,7 +174,7 @@ pub const Instruction = struct {
174174 .td => try encoder.imm64(inst.op1.mem.moffs.offset),
175175 else => {
176176 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,
178178 .rm, .rmi => inst.op2,
179179 else => unreachable,
180180 };
......@@ -182,7 +182,7 @@ pub const Instruction = struct {
182182 .reg => |reg| {
183183 const rm = switch (encoding.op_en) {
184184 .m, .mi, .m1, .mc => encoding.modRmExt(),
185 .mr => inst.op2.reg.lowEnc(),
185 .mr, .mri, .mrc => inst.op2.reg.lowEnc(),
186186 .rm, .rmi => inst.op1.reg.lowEnc(),
187187 else => unreachable,
188188 };
......@@ -191,7 +191,7 @@ pub const Instruction = struct {
191191 .mem => |mem| {
192192 const op = switch (encoding.op_en) {
193193 .m, .mi, .m1, .mc => .none,
194 .mr => inst.op2,
194 .mr, .mri, .mrc => inst.op2,
195195 .rm, .rmi => inst.op1,
196196 else => unreachable,
197197 };
......@@ -202,7 +202,7 @@ pub const Instruction = struct {
202202
203203 switch (encoding.op_en) {
204204 .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),
206206 else => {},
207207 }
208208 },
......@@ -251,7 +251,7 @@ pub const Instruction = struct {
251251 else => unreachable,
252252 };
253253 } 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: {
255255 break :blk switch (inst.op1) {
256256 .reg => |r| r,
257257 .mem => |m| m.base().?,
......@@ -275,13 +275,11 @@ pub const Instruction = struct {
275275
276276 switch (op_en) {
277277 .np, .i, .zi, .fd, .td, .d => {},
278 .o, .oi => {
279 rex.b = inst.op1.reg.isExtended();
280 },
281 .m, .mi, .m1, .mc, .mr, .rm, .rmi => {
278 .o, .oi => rex.b = inst.op1.reg.isExtended(),
279 .m, .mi, .m1, .mc, .mr, .rm, .rmi, .mri, .mrc => {
282280 const r_op = switch (op_en) {
283281 .rm, .rmi => inst.op1,
284 .mr => inst.op2,
282 .mr, .mri, .mrc => inst.op2,
285283 else => null,
286284 };
287285 if (r_op) |op| {
......@@ -290,7 +288,7 @@ pub const Instruction = struct {
290288
291289 const b_x_op = switch (op_en) {
292290 .rm, .rmi => inst.op2,
293 .m, .mi, .m1, .mc, .mr => inst.op1,
291 .m, .mi, .m1, .mc, .mr, .mri, .mrc => inst.op1,
294292 else => unreachable,
295293 };
296294 switch (b_x_op) {
src/arch/x86_64/encodings.zig+16-2
......@@ -257,8 +257,8 @@ pub const table = &[_]Entry{
257257
258258 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .none },
259259 .{ .cmpxchg, .mr, .rm8, .r8, .none, .none, &.{ 0x0f, 0xb0 }, 0, .rex },
260 .{ .cmpxchg, .mr, .rm16, .r16, .none, .none, &.{ 0x0f, 0xb1 }, 0, .rex },
261 .{ .cmpxchg, .mr, .rm32, .r32, .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, .none },
262262 .{ .cmpxchg, .mr, .rm64, .r64, .none, .none, &.{ 0x0f, 0xb1 }, 0, .long },
263263
264264 .{ .cmpxchg8b , .m, .m64, .none, .none, .none, &.{ 0x0f, 0xc7 }, 1, .none },
......@@ -693,6 +693,13 @@ pub const table = &[_]Entry{
693693 .{ .shl, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 4, .none },
694694 .{ .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
696703 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .none },
697704 .{ .shr, .m1, .rm8, .unity, .none, .none, &.{ 0xd0 }, 5, .rex },
698705 .{ .shr, .m1, .rm16, .unity, .none, .none, &.{ 0xd1 }, 5, .none },
......@@ -709,6 +716,13 @@ pub const table = &[_]Entry{
709716 .{ .shr, .mi, .rm32, .imm8, .none, .none, &.{ 0xc1 }, 5, .none },
710717 .{ .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
712726 .{ .stos, .np, .m8, .none, .none, .none, &.{ 0xaa }, 0, .none },
713727 .{ .stos, .np, .m16, .none, .none, .none, &.{ 0xab }, 0, .none },
714728 .{ .stos, .np, .m32, .none, .none, .none, &.{ 0xab }, 0, .none },
src/codegen.zig+2-3
......@@ -1063,13 +1063,12 @@ pub fn genTypedValue(
10631063 },
10641064 .Optional => {
10651065 if (typed_value.ty.isPtrLikeOptional()) {
1066 if (typed_value.val.isNull())
1067 return GenResult.mcv(.{ .immediate = 0 });
1066 if (typed_value.val.tag() == .null_value) return GenResult.mcv(.{ .immediate = 0 });
10681067
10691068 var buf: Type.Payload.ElemType = undefined;
10701069 return genTypedValue(bin_file, src_loc, .{
10711070 .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,
10731072 }, owner_decl_index);
10741073 } else if (typed_value.ty.abiSize(target) == 1) {
10751074 return GenResult.mcv(.{ .immediate = @boolToInt(!typed_value.val.isNull()) });
src/register_manager.zig+14-5
......@@ -149,17 +149,26 @@ pub fn RegisterManager(
149149 return RegisterLock{ .register = reg };
150150 }
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
152163 /// Like `lockRegAssumeUnused` but locks multiple registers.
153164 pub fn lockRegsAssumeUnused(
154165 self: *Self,
155166 comptime count: comptime_int,
156167 regs: [count]Register,
157168 ) [count]RegisterLock {
158 var buf: [count]RegisterLock = undefined;
159 for (regs, 0..) |reg, i| {
160 buf[i] = self.lockRegAssumeUnused(reg);
161 }
162 return buf;
169 var results: [count]RegisterLock = undefined;
170 for (&results, regs) |*result, reg| result.* = self.lockRegAssumeUnused(reg);
171 return results;
163172 }
164173
165174 /// Unlocks the register allowing its re-allocation and re-use.
test/behavior/array.zig-2
......@@ -70,7 +70,6 @@ test "array concat with undefined" {
7070test "array concat with tuple" {
7171 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7272 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
73 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
7473
7574 const array: [2]u8 = .{ 1, 2 };
7675 {
......@@ -641,7 +640,6 @@ test "tuple to array handles sentinel" {
641640}
642641
643642test "array init of container level array variable" {
644 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
645643 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
646644 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
647645 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/atomics.zig-4
......@@ -5,7 +5,6 @@ const expectEqual = std.testing.expectEqual;
55
66test "cmpxchg" {
77 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
8 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -96,7 +95,6 @@ test "cmpxchg with ptr" {
9695
9796test "cmpxchg with ignored result" {
9897 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
99 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10098 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
10199 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102100 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -143,7 +141,6 @@ var a_global_variable = @as(u32, 1234);
143141
144142test "cmpxchg on a global variable" {
145143 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
147144 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
148145 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
149146 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
......@@ -384,7 +381,6 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void {
384381
385382test "atomics with different types" {
386383 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
387 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
388384 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
389385 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
390386 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" {
157157}
158158
159159test "@bitCast packed structs at runtime and comptime" {
160 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
161160 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
162161 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
163162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -215,7 +214,6 @@ test "@bitCast extern structs at runtime and comptime" {
215214}
216215
217216test "bitcast packed struct to integer and back" {
218 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
219217 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
220218 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
221219 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;
44
55test "slicing slices" {
66 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
98 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
test/behavior/bugs/12051.zig-1
......@@ -3,7 +3,6 @@ const builtin = @import("builtin");
33
44test {
55 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
98 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 {
1515
1616test {
1717 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1918 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
2019 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2120 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 {
2020
2121test {
2222 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
23 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2423 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
2524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2625 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;
1010
1111test {
1212 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
13 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1413 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
1514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1615 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 {
1414test "fixed" {
1515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1616 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
17 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1817 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1918
2019 bar(t);
test/behavior/bugs/6456.zig-1
......@@ -11,7 +11,6 @@ const text =
1111;
1212
1313test "issue 6456" {
14 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1615 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");
44test "@ptrCast from const to nullable" {
55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
66 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
98
109 const c: u8 = 4;
......@@ -15,7 +14,6 @@ test "@ptrCast from const to nullable" {
1514test "@ptrCast from var in empty struct to nullable" {
1615 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1716 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
18 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1917 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
2018
2119 const container = struct {
test/behavior/bugs/8646.zig-1
......@@ -8,7 +8,6 @@ const array = [_][]const []const u8{
88
99test {
1010 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
11 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1211 if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO
1312 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1413 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 {
4444}
4545
4646test {
47 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
4847 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
4948 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
5049 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");
33
44test "empty file level struct" {
55 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
6 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87
98 const T = @import("empty_file_level_struct.zig");
......@@ -15,7 +14,6 @@ test "empty file level struct" {
1514
1615test "empty file level union" {
1716 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
18 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1917 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2018
2119 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" {
9696}
9797
9898test "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;
10099 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
101100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
102101 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");
22const builtin = @import("builtin");
33
44test "strlit to vector" {
5 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
65 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
76 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
87 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/math.zig-1
......@@ -560,7 +560,6 @@ fn testUnsignedNegationWrappingEval(x: u16) !void {
560560test "negation wrapping" {
561561 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
562562 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
563 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
564563
565564 try expectEqual(@as(u1, 1), negateWrap(u1, 1));
566565}
test/behavior/optional.zig-1
......@@ -431,7 +431,6 @@ test "alignment of wrapping an optional payload" {
431431test "Optional slice size is optimized" {
432432 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
433433 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
434 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
435434 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
436435
437436 try expect(@sizeOf(?[]u8) == @sizeOf([]u8));
test/behavior/packed-struct.zig-7
......@@ -120,7 +120,6 @@ test "consistent size of packed structs" {
120120}
121121
122122test "correct sizeOf and offsets in packed structs" {
123 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
124123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
125124 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
126125 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -188,7 +187,6 @@ test "correct sizeOf and offsets in packed structs" {
188187}
189188
190189test "nested packed structs" {
191 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
192190 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
193191 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
194192 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -254,7 +252,6 @@ test "regular in irregular packed struct" {
254252}
255253
256254test "byte-aligned field pointer offsets" {
257 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
258255 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
259256 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
260257 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -397,7 +394,6 @@ test "@ptrToInt on a packed struct field" {
397394}
398395
399396test "optional pointer in packed struct" {
400 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
401397 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
402398 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
403399 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -530,7 +526,6 @@ test "nested packed struct field access test" {
530526test "runtime init of unnamed packed struct type" {
531527 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
532528 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
533 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
534529 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
535530
536531 var z: u8 = 123;
......@@ -545,7 +540,6 @@ test "runtime init of unnamed packed struct type" {
545540test "packed struct passed to callconv(.C) function" {
546541 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
547542 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
548 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
549543 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
550544
551545 const S = struct {
......@@ -571,7 +565,6 @@ test "packed struct passed to callconv(.C) function" {
571565test "overaligned pointer to packed struct" {
572566 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
573567 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
574 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
575568
576569 const S = packed struct { a: u32, b: u32 };
577570 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();
66
77test "packed struct explicit backing integer" {
88 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
9 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
109 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1110 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1211 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" {
412412test "indexing array with sentinel returns correct type" {
413413 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
414414 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
415 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
416415 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
417416
418417 var s: [:0]const u8 = "abc";
......@@ -497,7 +496,6 @@ test "pointer to constant decl preserves alignment" {
497496test "ptrCast comptime known slice to C pointer" {
498497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
499498 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
500 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
501499 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
502500
503501 const s: [:0]const u8 = "foo";
test/behavior/slice.zig-3
......@@ -688,7 +688,6 @@ test "slice field ptr var" {
688688test "global slice field access" {
689689 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
690690 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
691 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
692691 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
693692
694693 const S = struct {
......@@ -733,7 +732,6 @@ test "empty slice ptr is non null" {
733732test "slice decays to many pointer" {
734733 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
735734 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
736 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
737735
738736 var buf: [8]u8 = "abcdefg\x00".*;
739737 const p: [*:0]const u8 = buf[0..7 :0];
......@@ -744,7 +742,6 @@ test "write through pointer to optional slice arg" {
744742 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
745743 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
746744 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
747 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
748745
749746 const S = struct {
750747 fn bar(foo: *?[]const u8) !void {
test/behavior/struct.zig-5
......@@ -387,7 +387,6 @@ const APackedStruct = packed struct {
387387test "packed struct" {
388388 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
389389 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
390 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
391390 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
392391
393392 var foo = APackedStruct{
......@@ -496,7 +495,6 @@ const Bitfields = packed struct {
496495test "packed struct fields are ordered from LSB to MSB" {
497496 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
498497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
499 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
500498 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
501499
502500 var all: u64 = 0x7765443322221111;
......@@ -632,7 +630,6 @@ test "default struct initialization fields" {
632630}
633631
634632test "packed array 24bits" {
635 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
636633 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
637634 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
638635 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -827,7 +824,6 @@ test "non-packed struct with u128 entry in union" {
827824}
828825
829826test "packed struct field passed to generic function" {
830 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
831827 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
832828 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
833829 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -939,7 +935,6 @@ test "comptime struct field" {
939935}
940936
941937test "tuple element initialized with fn call" {
942 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
943938 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
944939 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
945940 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" {
620620}
621621
622622test "switch capture copies its payload" {
623 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
624623 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
625624 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
626625 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/threadlocal.zig-1
......@@ -21,7 +21,6 @@ test "thread local variable" {
2121
2222test "pointer to thread local array" {
2323 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
24 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2524 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2625 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2726 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" {
2323}
2424
2525test "initializer list expression" {
26 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
2726 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
2827 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
2928 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -52,7 +51,6 @@ test "reference to a struct type" {
5251
5352test "cast negative integer to pointer" {
5453 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
55 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
5654 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
5755 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
5856 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" {
9896
9997test "nested comma operator" {
10098 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
10299 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
104101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -109,7 +106,6 @@ test "nested comma operator" {
109106
110107test "cast functions" {
111108 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
112 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
113109 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
114110 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
115111 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -123,7 +119,6 @@ test "cast functions" {
123119
124120test "large integer macro" {
125121 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
126 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
127122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
128123 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
129124 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -133,7 +128,6 @@ test "large integer macro" {
133128
134129test "string literal macro with embedded tab character" {
135130 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
136 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
137131 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
138132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
139133 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -143,7 +137,6 @@ test "string literal macro with embedded tab character" {
143137
144138test "string and char literals that are not UTF-8 encoded. Issue #12784" {
145139 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
146 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
147140 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
148141 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
149142 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -188,7 +181,6 @@ test "Macro that uses division operator. Issue #13162" {
188181
189182test "Macro that uses remainder operator. Issue #13346" {
190183 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
191 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
192184 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
193185 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
194186 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" {
381381test "nested runtime conditionals in tuple initializer" {
382382 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
383383 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
384 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
385384
386385 var data: u8 = 0;
387386 const x = .{
test/behavior/tuple_declarations.zig-2
......@@ -7,7 +7,6 @@ const expectEqualStrings = testing.expectEqualStrings;
77test "tuple declaration type info" {
88 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
99 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1110
1211 {
1312 const T = struct { comptime u32 align(2) = 1, []const u8 };
......@@ -57,7 +56,6 @@ test "tuple declaration type info" {
5756test "Tuple declaration usage" {
5857 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5958 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
6159
6260 const T = struct { u32, []const u8 };
6361 var t: T = .{ 1, "foo" };
test/behavior/type.zig-2
......@@ -200,7 +200,6 @@ test "Type.ErrorUnion" {
200200
201201test "Type.Opaque" {
202202 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
203 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
204203 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
205204 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
206205 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -348,7 +347,6 @@ test "Type.Struct" {
348347}
349348
350349test "Type.Enum" {
351 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
352350 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
353351 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" {
568568test "@typeInfo decls and usingnamespace" {
569569 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
570570 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
571 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
572571
573572 const A = struct {
574573 const x = 5;
test/behavior/typename.zig-2
......@@ -64,7 +64,6 @@ test "anon field init" {
6464}
6565
6666test "basic" {
67 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
6867 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
6968 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
7069 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
......@@ -228,7 +227,6 @@ test "local variable" {
228227}
229228
230229test "comptime parameters not converted to anytype in function type" {
231 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
232230 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
233231 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
234232 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" {
14081408}
14091409
14101410test "packed union in packed struct" {
1411 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14121411 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14131412 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
14141413 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
......@@ -1494,7 +1493,6 @@ test "union reassignment can use previous value" {
14941493}
14951494
14961495test "packed union with zero-bit field" {
1497 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
14981496 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
14991497 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15001498 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" {
12671267test "addition of vectors represented as strings" {
12681268 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
12691269 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1270 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
12711270
12721271 const V = @Vector(3, u8);
12731272 const foo: V = "foo".*;
test/tests.zig+1
......@@ -112,6 +112,7 @@ const test_targets = blk: {
112112 .os_tag = .windows,
113113 .abi = .gnu,
114114 },
115 .single_threaded = true, // https://github.com/ziglang/zig/issues/15075
115116 .backend = .stage2_x86_64,
116117 },
117118