| ... | @@ -7,7 +7,7 @@ const testing = std.testing; | ... | @@ -7,7 +7,7 @@ const testing = std.testing; |
| 7 | // zig fmt: off | 7 | // zig fmt: off |
| 8 | | 8 | |
| 9 | /// General purpose registers in the AArch64 instruction set | 9 | /// General purpose registers in the AArch64 instruction set |
| 10 | pub const Register = enum(u6) { | 10 | pub const Register = enum(u7) { |
| 11 | // 64-bit registers | 11 | // 64-bit registers |
| 12 | x0, x1, x2, x3, x4, x5, x6, x7, | 12 | x0, x1, x2, x3, x4, x5, x6, x7, |
| 13 | x8, x9, x10, x11, x12, x13, x14, x15, | 13 | x8, x9, x10, x11, x12, x13, x14, x15, |
| ... | @@ -20,10 +20,23 @@ pub const Register = enum(u6) { | ... | @@ -20,10 +20,23 @@ pub const Register = enum(u6) { |
| 20 | w16, w17, w18, w19, w20, w21, w22, w23, | 20 | w16, w17, w18, w19, w20, w21, w22, w23, |
| 21 | w24, w25, w26, w27, w28, w29, w30, wzr, | 21 | w24, w25, w26, w27, w28, w29, w30, wzr, |
| 22 | | 22 | |
| 23 | pub const sp = Register.xzr; | 23 | // Stack pointer |
| | 24 | sp, wsp, |
| 24 | | 25 | |
| 25 | pub fn id(self: Register) u5 { | 26 | pub fn id(self: Register) u6 { |
| 26 | return @truncate(u5, @enumToInt(self)); | 27 | return switch (@enumToInt(self)) { |
| | 28 | 0...63 => return @as(u6, @truncate(u5, @enumToInt(self))), |
| | 29 | 64...65 => 32, |
| | 30 | else => unreachable, |
| | 31 | }; |
| | 32 | } |
| | 33 | |
| | 34 | pub fn enc(self: Register) u5 { |
| | 35 | return switch (@enumToInt(self)) { |
| | 36 | 0...63 => return @truncate(u5, @enumToInt(self)), |
| | 37 | 64...65 => 31, |
| | 38 | else => unreachable, |
| | 39 | }; |
| 27 | } | 40 | } |
| 28 | | 41 | |
| 29 | /// Returns the bit-width of the register. | 42 | /// Returns the bit-width of the register. |
| ... | @@ -31,17 +44,32 @@ pub const Register = enum(u6) { | ... | @@ -31,17 +44,32 @@ pub const Register = enum(u6) { |
| 31 | return switch (@enumToInt(self)) { | 44 | return switch (@enumToInt(self)) { |
| 32 | 0...31 => 64, | 45 | 0...31 => 64, |
| 33 | 32...63 => 32, | 46 | 32...63 => 32, |
| | 47 | 64 => 64, |
| | 48 | 65 => 32, |
| | 49 | else => unreachable, |
| 34 | }; | 50 | }; |
| 35 | } | 51 | } |
| 36 | | 52 | |
| 37 | /// Convert from any register to its 64 bit alias. | 53 | /// Convert from any register to its 64 bit alias. |
| 38 | pub fn to64(self: Register) Register { | 54 | pub fn to64(self: Register) Register { |
| 39 | return @intToEnum(Register, self.id()); | 55 | return switch (@enumToInt(self)) { |
| | 56 | 0...31 => self, |
| | 57 | 32...63 => @intToEnum(Register, @enumToInt(self) - 32), |
| | 58 | 64 => .sp, |
| | 59 | 65 => .sp, |
| | 60 | else => unreachable, |
| | 61 | }; |
| 40 | } | 62 | } |
| 41 | | 63 | |
| 42 | /// Convert from any register to its 32 bit alias. | 64 | /// Convert from any register to its 32 bit alias. |
| 43 | pub fn to32(self: Register) Register { | 65 | pub fn to32(self: Register) Register { |
| 44 | return @intToEnum(Register, @as(u6, self.id()) + 32); | 66 | return switch (@enumToInt(self)) { |
| | 67 | 0...31 => @intToEnum(Register, @enumToInt(self) + 32), |
| | 68 | 32...63 => self, |
| | 69 | 64 => .wsp, |
| | 70 | 65 => .wsp, |
| | 71 | else => unreachable, |
| | 72 | }; |
| 45 | } | 73 | } |
| 46 | | 74 | |
| 47 | /// Returns the index into `callee_preserved_regs`. | 75 | /// Returns the index into `callee_preserved_regs`. |
| ... | @@ -53,7 +81,7 @@ pub const Register = enum(u6) { | ... | @@ -53,7 +81,7 @@ pub const Register = enum(u6) { |
| 53 | } | 81 | } |
| 54 | | 82 | |
| 55 | pub fn dwarfLocOp(self: Register) u8 { | 83 | pub fn dwarfLocOp(self: Register) u8 { |
| 56 | return @as(u8, self.id()) + DW.OP.reg0; | 84 | return @as(u8, self.enc()) + DW.OP.reg0; |
| 57 | } | 85 | } |
| 58 | }; | 86 | }; |
| 59 | | 87 | |
| ... | @@ -76,15 +104,15 @@ pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_re | ... | @@ -76,15 +104,15 @@ pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_re |
| 76 | pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | 104 | pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; |
| 77 | pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; | 105 | pub const c_abi_int_return_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 }; |
| 78 | | 106 | |
| 79 | test "Register.id" { | 107 | test "Register.enc" { |
| 80 | try testing.expectEqual(@as(u5, 0), Register.x0.id()); | 108 | try testing.expectEqual(@as(u5, 0), Register.x0.enc()); |
| 81 | try testing.expectEqual(@as(u5, 0), Register.w0.id()); | 109 | try testing.expectEqual(@as(u5, 0), Register.w0.enc()); |
| 82 | | 110 | |
| 83 | try testing.expectEqual(@as(u5, 31), Register.xzr.id()); | 111 | try testing.expectEqual(@as(u5, 31), Register.xzr.enc()); |
| 84 | try testing.expectEqual(@as(u5, 31), Register.wzr.id()); | 112 | try testing.expectEqual(@as(u5, 31), Register.wzr.enc()); |
| 85 | | 113 | |
| 86 | try testing.expectEqual(@as(u5, 31), Register.sp.id()); | 114 | try testing.expectEqual(@as(u5, 31), Register.sp.enc()); |
| 87 | try testing.expectEqual(@as(u5, 31), Register.sp.id()); | 115 | try testing.expectEqual(@as(u5, 31), Register.sp.enc()); |
| 88 | } | 116 | } |
| 89 | | 117 | |
| 90 | test "Register.size" { | 118 | test "Register.size" { |
| ... | @@ -479,7 +507,7 @@ pub const Instruction = union(enum) { | ... | @@ -479,7 +507,7 @@ pub const Instruction = union(enum) { |
| 479 | assert(shift % 16 == 0 and shift <= 16); | 507 | assert(shift % 16 == 0 and shift <= 16); |
| 480 | return Instruction{ | 508 | return Instruction{ |
| 481 | .move_wide_immediate = .{ | 509 | .move_wide_immediate = .{ |
| 482 | .rd = rd.id(), | 510 | .rd = rd.enc(), |
| 483 | .imm16 = imm16, | 511 | .imm16 = imm16, |
| 484 | .hw = @intCast(u2, shift / 16), | 512 | .hw = @intCast(u2, shift / 16), |
| 485 | .opc = opc, | 513 | .opc = opc, |
| ... | @@ -491,7 +519,7 @@ pub const Instruction = union(enum) { | ... | @@ -491,7 +519,7 @@ pub const Instruction = union(enum) { |
| 491 | assert(shift % 16 == 0 and shift <= 48); | 519 | assert(shift % 16 == 0 and shift <= 48); |
| 492 | return Instruction{ | 520 | return Instruction{ |
| 493 | .move_wide_immediate = .{ | 521 | .move_wide_immediate = .{ |
| 494 | .rd = rd.id(), | 522 | .rd = rd.enc(), |
| 495 | .imm16 = imm16, | 523 | .imm16 = imm16, |
| 496 | .hw = @intCast(u2, shift / 16), | 524 | .hw = @intCast(u2, shift / 16), |
| 497 | .opc = opc, | 525 | .opc = opc, |
| ... | @@ -508,7 +536,7 @@ pub const Instruction = union(enum) { | ... | @@ -508,7 +536,7 @@ pub const Instruction = union(enum) { |
| 508 | const imm21_u = @bitCast(u21, imm21); | 536 | const imm21_u = @bitCast(u21, imm21); |
| 509 | return Instruction{ | 537 | return Instruction{ |
| 510 | .pc_relative_address = .{ | 538 | .pc_relative_address = .{ |
| 511 | .rd = rd.id(), | 539 | .rd = rd.enc(), |
| 512 | .immlo = @truncate(u2, imm21_u), | 540 | .immlo = @truncate(u2, imm21_u), |
| 513 | .immhi = @truncate(u19, imm21_u >> 2), | 541 | .immhi = @truncate(u19, imm21_u >> 2), |
| 514 | .op = op, | 542 | .op = op, |
| ... | @@ -580,7 +608,7 @@ pub const Instruction = union(enum) { | ... | @@ -580,7 +608,7 @@ pub const Instruction = union(enum) { |
| 580 | pub fn reg(rm: Register) LoadStoreOffset { | 608 | pub fn reg(rm: Register) LoadStoreOffset { |
| 581 | return .{ | 609 | return .{ |
| 582 | .register = .{ | 610 | .register = .{ |
| 583 | .rm = rm.id(), | 611 | .rm = rm.enc(), |
| 584 | .shift = .{ | 612 | .shift = .{ |
| 585 | .lsl = 0, | 613 | .lsl = 0, |
| 586 | }, | 614 | }, |
| ... | @@ -592,7 +620,7 @@ pub const Instruction = union(enum) { | ... | @@ -592,7 +620,7 @@ pub const Instruction = union(enum) { |
| 592 | assert(rm.size() == 32 and (shift == 0 or shift == 2)); | 620 | assert(rm.size() == 32 and (shift == 0 or shift == 2)); |
| 593 | return .{ | 621 | return .{ |
| 594 | .register = .{ | 622 | .register = .{ |
| 595 | .rm = rm.id(), | 623 | .rm = rm.enc(), |
| 596 | .shift = .{ | 624 | .shift = .{ |
| 597 | .uxtw = shift, | 625 | .uxtw = shift, |
| 598 | }, | 626 | }, |
| ... | @@ -604,7 +632,7 @@ pub const Instruction = union(enum) { | ... | @@ -604,7 +632,7 @@ pub const Instruction = union(enum) { |
| 604 | assert(rm.size() == 64 and (shift == 0 or shift == 3)); | 632 | assert(rm.size() == 64 and (shift == 0 or shift == 3)); |
| 605 | return .{ | 633 | return .{ |
| 606 | .register = .{ | 634 | .register = .{ |
| 607 | .rm = rm.id(), | 635 | .rm = rm.enc(), |
| 608 | .shift = .{ | 636 | .shift = .{ |
| 609 | .lsl = shift, | 637 | .lsl = shift, |
| 610 | }, | 638 | }, |
| ... | @@ -616,7 +644,7 @@ pub const Instruction = union(enum) { | ... | @@ -616,7 +644,7 @@ pub const Instruction = union(enum) { |
| 616 | assert(rm.size() == 32 and (shift == 0 or shift == 2)); | 644 | assert(rm.size() == 32 and (shift == 0 or shift == 2)); |
| 617 | return .{ | 645 | return .{ |
| 618 | .register = .{ | 646 | .register = .{ |
| 619 | .rm = rm.id(), | 647 | .rm = rm.enc(), |
| 620 | .shift = .{ | 648 | .shift = .{ |
| 621 | .sxtw = shift, | 649 | .sxtw = shift, |
| 622 | }, | 650 | }, |
| ... | @@ -628,7 +656,7 @@ pub const Instruction = union(enum) { | ... | @@ -628,7 +656,7 @@ pub const Instruction = union(enum) { |
| 628 | assert(rm.size() == 64 and (shift == 0 or shift == 3)); | 656 | assert(rm.size() == 64 and (shift == 0 or shift == 3)); |
| 629 | return .{ | 657 | return .{ |
| 630 | .register = .{ | 658 | .register = .{ |
| 631 | .rm = rm.id(), | 659 | .rm = rm.enc(), |
| 632 | .shift = .{ | 660 | .shift = .{ |
| 633 | .sxtx = shift, | 661 | .sxtx = shift, |
| 634 | }, | 662 | }, |
| ... | @@ -676,8 +704,8 @@ pub const Instruction = union(enum) { | ... | @@ -676,8 +704,8 @@ pub const Instruction = union(enum) { |
| 676 | }; | 704 | }; |
| 677 | return Instruction{ | 705 | return Instruction{ |
| 678 | .load_store_register = .{ | 706 | .load_store_register = .{ |
| 679 | .rt = rt.id(), | 707 | .rt = rt.enc(), |
| 680 | .rn = rn.id(), | 708 | .rn = rn.enc(), |
| 681 | .offset = off, | 709 | .offset = off, |
| 682 | .opc = opc, | 710 | .opc = opc, |
| 683 | .op1 = op1, | 711 | .op1 = op1, |
| ... | @@ -711,9 +739,9 @@ pub const Instruction = union(enum) { | ... | @@ -711,9 +739,9 @@ pub const Instruction = union(enum) { |
| 711 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 2)); | 739 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 2)); |
| 712 | return Instruction{ | 740 | return Instruction{ |
| 713 | .load_store_register_pair = .{ | 741 | .load_store_register_pair = .{ |
| 714 | .rt1 = rt1.id(), | 742 | .rt1 = rt1.enc(), |
| 715 | .rn = rn.id(), | 743 | .rn = rn.enc(), |
| 716 | .rt2 = rt2.id(), | 744 | .rt2 = rt2.enc(), |
| 717 | .imm7 = imm7, | 745 | .imm7 = imm7, |
| 718 | .load = @boolToInt(load), | 746 | .load = @boolToInt(load), |
| 719 | .encoding = encoding, | 747 | .encoding = encoding, |
| ... | @@ -726,9 +754,9 @@ pub const Instruction = union(enum) { | ... | @@ -726,9 +754,9 @@ pub const Instruction = union(enum) { |
| 726 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 3)); | 754 | const imm7 = @truncate(u7, @bitCast(u9, offset >> 3)); |
| 727 | return Instruction{ | 755 | return Instruction{ |
| 728 | .load_store_register_pair = .{ | 756 | .load_store_register_pair = .{ |
| 729 | .rt1 = rt1.id(), | 757 | .rt1 = rt1.enc(), |
| 730 | .rn = rn.id(), | 758 | .rn = rn.enc(), |
| 731 | .rt2 = rt2.id(), | 759 | .rt2 = rt2.enc(), |
| 732 | .imm7 = imm7, | 760 | .imm7 = imm7, |
| 733 | .load = @boolToInt(load), | 761 | .load = @boolToInt(load), |
| 734 | .encoding = encoding, | 762 | .encoding = encoding, |
| ... | @@ -743,7 +771,7 @@ pub const Instruction = union(enum) { | ... | @@ -743,7 +771,7 @@ pub const Instruction = union(enum) { |
| 743 | fn loadLiteral(rt: Register, imm19: u19) Instruction { | 771 | fn loadLiteral(rt: Register, imm19: u19) Instruction { |
| 744 | return Instruction{ | 772 | return Instruction{ |
| 745 | .load_literal = .{ | 773 | .load_literal = .{ |
| 746 | .rt = rt.id(), | 774 | .rt = rt.enc(), |
| 747 | .imm19 = imm19, | 775 | .imm19 = imm19, |
| 748 | .opc = switch (rt.size()) { | 776 | .opc = switch (rt.size()) { |
| 749 | 32 => 0b00, | 777 | 32 => 0b00, |
| ... | @@ -782,7 +810,7 @@ pub const Instruction = union(enum) { | ... | @@ -782,7 +810,7 @@ pub const Instruction = union(enum) { |
| 782 | return Instruction{ | 810 | return Instruction{ |
| 783 | .unconditional_branch_register = .{ | 811 | .unconditional_branch_register = .{ |
| 784 | .op4 = op4, | 812 | .op4 = op4, |
| 785 | .rn = rn.id(), | 813 | .rn = rn.enc(), |
| 786 | .op3 = op3, | 814 | .op3 = op3, |
| 787 | .op2 = op2, | 815 | .op2 = op2, |
| 788 | .opc = opc, | 816 | .opc = opc, |
| ... | @@ -818,10 +846,10 @@ pub const Instruction = union(enum) { | ... | @@ -818,10 +846,10 @@ pub const Instruction = union(enum) { |
| 818 | assert(amount < 32); | 846 | assert(amount < 32); |
| 819 | return Instruction{ | 847 | return Instruction{ |
| 820 | .logical_shifted_register = .{ | 848 | .logical_shifted_register = .{ |
| 821 | .rd = rd.id(), | 849 | .rd = rd.enc(), |
| 822 | .rn = rn.id(), | 850 | .rn = rn.enc(), |
| 823 | .imm6 = amount, | 851 | .imm6 = amount, |
| 824 | .rm = rm.id(), | 852 | .rm = rm.enc(), |
| 825 | .n = n, | 853 | .n = n, |
| 826 | .shift = @enumToInt(shift), | 854 | .shift = @enumToInt(shift), |
| 827 | .opc = opc, | 855 | .opc = opc, |
| ... | @@ -832,10 +860,10 @@ pub const Instruction = union(enum) { | ... | @@ -832,10 +860,10 @@ pub const Instruction = union(enum) { |
| 832 | 64 => { | 860 | 64 => { |
| 833 | return Instruction{ | 861 | return Instruction{ |
| 834 | .logical_shifted_register = .{ | 862 | .logical_shifted_register = .{ |
| 835 | .rd = rd.id(), | 863 | .rd = rd.enc(), |
| 836 | .rn = rn.id(), | 864 | .rn = rn.enc(), |
| 837 | .imm6 = amount, | 865 | .imm6 = amount, |
| 838 | .rm = rm.id(), | 866 | .rm = rm.enc(), |
| 839 | .n = n, | 867 | .n = n, |
| 840 | .shift = @enumToInt(shift), | 868 | .shift = @enumToInt(shift), |
| 841 | .opc = opc, | 869 | .opc = opc, |
| ... | @@ -857,8 +885,8 @@ pub const Instruction = union(enum) { | ... | @@ -857,8 +885,8 @@ pub const Instruction = union(enum) { |
| 857 | ) Instruction { | 885 | ) Instruction { |
| 858 | return Instruction{ | 886 | return Instruction{ |
| 859 | .add_subtract_immediate = .{ | 887 | .add_subtract_immediate = .{ |
| 860 | .rd = rd.id(), | 888 | .rd = rd.enc(), |
| 861 | .rn = rn.id(), | 889 | .rn = rn.enc(), |
| 862 | .imm12 = imm12, | 890 | .imm12 = imm12, |
| 863 | .sh = @boolToInt(shift), | 891 | .sh = @boolToInt(shift), |
| 864 | .s = s, | 892 | .s = s, |
| ... | @@ -885,10 +913,10 @@ pub const Instruction = union(enum) { | ... | @@ -885,10 +913,10 @@ pub const Instruction = union(enum) { |
| 885 | ) Instruction { | 913 | ) Instruction { |
| 886 | return Instruction{ | 914 | return Instruction{ |
| 887 | .add_subtract_shifted_register = .{ | 915 | .add_subtract_shifted_register = .{ |
| 888 | .rd = rd.id(), | 916 | .rd = rd.enc(), |
| 889 | .rn = rn.id(), | 917 | .rn = rn.enc(), |
| 890 | .imm6 = imm6, | 918 | .imm6 = imm6, |
| 891 | .rm = rm.id(), | 919 | .rm = rm.enc(), |
| 892 | .shift = @enumToInt(shift), | 920 | .shift = @enumToInt(shift), |
| 893 | .s = s, | 921 | .s = s, |
| 894 | .op = op, | 922 | .op = op, |
| ... | @@ -926,7 +954,7 @@ pub const Instruction = union(enum) { | ... | @@ -926,7 +954,7 @@ pub const Instruction = union(enum) { |
| 926 | assert(offset & 0b11 == 0b00); | 954 | assert(offset & 0b11 == 0b00); |
| 927 | return Instruction{ | 955 | return Instruction{ |
| 928 | .compare_and_branch = .{ | 956 | .compare_and_branch = .{ |
| 929 | .rt = rt.id(), | 957 | .rt = rt.enc(), |
| 930 | .imm19 = @bitCast(u19, @intCast(i19, offset >> 2)), | 958 | .imm19 = @bitCast(u19, @intCast(i19, offset >> 2)), |
| 931 | .op = op, | 959 | .op = op, |
| 932 | .sf = switch (rt.size()) { | 960 | .sf = switch (rt.size()) { |
| ... | @@ -949,11 +977,11 @@ pub const Instruction = union(enum) { | ... | @@ -949,11 +977,11 @@ pub const Instruction = union(enum) { |
| 949 | ) Instruction { | 977 | ) Instruction { |
| 950 | return Instruction{ | 978 | return Instruction{ |
| 951 | .conditional_select = .{ | 979 | .conditional_select = .{ |
| 952 | .rd = rd.id(), | 980 | .rd = rd.enc(), |
| 953 | .rn = rn.id(), | 981 | .rn = rn.enc(), |
| 954 | .op2 = op2, | 982 | .op2 = op2, |
| 955 | .cond = @enumToInt(cond), | 983 | .cond = @enumToInt(cond), |
| 956 | .rm = rm.id(), | 984 | .rm = rm.enc(), |
| 957 | .s = s, | 985 | .s = s, |
| 958 | .op = op, | 986 | .op = op, |
| 959 | .sf = switch (rd.size()) { | 987 | .sf = switch (rd.size()) { |
| ... | @@ -976,11 +1004,11 @@ pub const Instruction = union(enum) { | ... | @@ -976,11 +1004,11 @@ pub const Instruction = union(enum) { |
| 976 | ) Instruction { | 1004 | ) Instruction { |
| 977 | return Instruction{ | 1005 | return Instruction{ |
| 978 | .data_processing_3_source = .{ | 1006 | .data_processing_3_source = .{ |
| 979 | .rd = rd.id(), | 1007 | .rd = rd.enc(), |
| 980 | .rn = rn.id(), | 1008 | .rn = rn.enc(), |
| 981 | .ra = ra.id(), | 1009 | .ra = ra.enc(), |
| 982 | .o0 = o0, | 1010 | .o0 = o0, |
| 983 | .rm = rm.id(), | 1011 | .rm = rm.enc(), |
| 984 | .op31 = op31, | 1012 | .op31 = op31, |
| 985 | .op54 = op54, | 1013 | .op54 = op54, |
| 986 | .sf = switch (rd.size()) { | 1014 | .sf = switch (rd.size()) { |