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