authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-07 08:18:35+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-03-17 19:59:13+01:00
logd484b3b3cbebddc3e1e8b160152e3f8e3be93b63
treea5942b2deaa941183cdb8194ea45f4c1e99cabab
parentdc34ac2b9e283ac4ca6c07ed9f4e201f860639d0

zld: use aarch64 for opcodes


3 files changed, 113 insertions(+), 239 deletions(-)

src/codegen/aarch64.zig+4-1
...@@ -221,7 +221,8 @@ pub const Instruction = union(enum) {...@@ -221,7 +221,8 @@ pub const Instruction = union(enum) {
221 offset: u12,221 offset: u12,
222 opc: u2,222 opc: u2,
223 op1: u2,223 op1: u2,
224 fixed: u4 = 0b111_0,224 v: u1,
225 fixed: u3 = 0b111,
225 size: u2,226 size: u2,
226 },227 },
227 LoadStorePairOfRegisters: packed struct {228 LoadStorePairOfRegisters: packed struct {
...@@ -505,6 +506,7 @@ pub const Instruction = union(enum) {...@@ -505,6 +506,7 @@ pub const Instruction = union(enum) {
505 .offset = offset.toU12(),506 .offset = offset.toU12(),
506 .opc = opc,507 .opc = opc,
507 .op1 = op1,508 .op1 = op1,
509 .v = 0,
508 .size = 0b10,510 .size = 0b10,
509 },511 },
510 };512 };
...@@ -517,6 +519,7 @@ pub const Instruction = union(enum) {...@@ -517,6 +519,7 @@ pub const Instruction = union(enum) {
517 .offset = offset.toU12(),519 .offset = offset.toU12(),
518 .opc = opc,520 .opc = opc,
519 .op1 = op1,521 .op1 = op1,
522 .v = 0,
520 .size = 0b11,523 .size = 0b11,
521 },524 },
522 };525 };
src/link/MachO/Zld.zig+109-41
...@@ -10,6 +10,7 @@ const fs = std.fs;...@@ -10,6 +10,7 @@ const fs = std.fs;
10const macho = std.macho;10const macho = std.macho;
11const math = std.math;11const math = std.math;
12const log = std.log.scoped(.zld);12const log = std.log.scoped(.zld);
13const aarch64 = @import("../../codegen/aarch64.zig");
1314
14const Allocator = mem.Allocator;15const Allocator = mem.Allocator;
15const CodeSignature = @import("CodeSignature.zig");16const CodeSignature = @import("CodeSignature.zig");
...@@ -19,7 +20,6 @@ const Trie = @import("Trie.zig");...@@ -19,7 +20,6 @@ const Trie = @import("Trie.zig");
1920
20usingnamespace @import("commands.zig");21usingnamespace @import("commands.zig");
21usingnamespace @import("bind.zig");22usingnamespace @import("bind.zig");
22usingnamespace @import("reloc.zig");
2323
24allocator: *Allocator,24allocator: *Allocator,
2525
...@@ -968,27 +968,27 @@ fn writeStubHelperCommon(self: *Zld) !void {...@@ -968,27 +968,27 @@ fn writeStubHelperCommon(self: *Zld) !void {
968 data_blk: {968 data_blk: {
969 const displacement = math.cast(i21, target_addr - this_addr) catch |_| break :data_blk;969 const displacement = math.cast(i21, target_addr - this_addr) catch |_| break :data_blk;
970 // adr x17, disp970 // adr x17, disp
971 mem.writeIntLittle(u32, code[0..4], Arm64.adr(17, @bitCast(u21, displacement)).toU32());971 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x17, displacement).toU32());
972 // nop972 // nop
973 mem.writeIntLittle(u32, code[4..8], Arm64.nop().toU32());973 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32());
974 break :data_blk_outer;974 break :data_blk_outer;
975 }975 }
976 data_blk: {976 data_blk: {
977 const new_this_addr = this_addr + @sizeOf(u32);977 const new_this_addr = this_addr + @sizeOf(u32);
978 const displacement = math.cast(i21, target_addr - new_this_addr) catch |_| break :data_blk;978 const displacement = math.cast(i21, target_addr - new_this_addr) catch |_| break :data_blk;
979 // nop979 // nop
980 mem.writeIntLittle(u32, code[0..4], Arm64.nop().toU32());980 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32());
981 // adr x17, disp981 // adr x17, disp
982 mem.writeIntLittle(u32, code[4..8], Arm64.adr(17, @bitCast(u21, displacement)).toU32());982 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.adr(.x17, displacement).toU32());
983 break :data_blk_outer;983 break :data_blk_outer;
984 }984 }
985 // Jump is too big, replace adr with adrp and add.985 // Jump is too big, replace adr with adrp and add.
986 const this_page = @intCast(i32, this_addr >> 12);986 const this_page = @intCast(i32, this_addr >> 12);
987 const target_page = @intCast(i32, target_addr >> 12);987 const target_page = @intCast(i32, target_addr >> 12);
988 const pages = @bitCast(u21, @intCast(i21, target_page - this_page));988 const pages = @intCast(i21, target_page - this_page);
989 mem.writeIntLittle(u32, code[0..4], Arm64.adrp(17, pages).toU32());989 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x17, pages).toU32());
990 const narrowed = @truncate(u12, target_addr);990 const narrowed = @truncate(u12, target_addr);
991 mem.writeIntLittle(u32, code[4..8], Arm64.add(17, 17, narrowed, 1).toU32());991 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.add(.x17, .x17, narrowed, false).toU32());
992 }992 }
993 // stp x16, x17, [sp, #-16]!993 // stp x16, x17, [sp, #-16]!
994 code[8] = 0xf0;994 code[8] = 0xf0;
...@@ -1003,9 +1003,11 @@ fn writeStubHelperCommon(self: *Zld) !void {...@@ -1003,9 +1003,11 @@ fn writeStubHelperCommon(self: *Zld) !void {
1003 const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :binder_blk;1003 const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :binder_blk;
1004 const literal = math.cast(u18, displacement) catch |_| break :binder_blk;1004 const literal = math.cast(u18, displacement) catch |_| break :binder_blk;
1005 // ldr x16, label1005 // ldr x16, label
1006 mem.writeIntLittle(u32, code[12..16], Arm64.ldr(16, literal, 1).toU32());1006 mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.ldr(.x16, .{
1007 .literal = literal,
1008 }).toU32());
1007 // nop1009 // nop
1008 mem.writeIntLittle(u32, code[16..20], Arm64.nop().toU32());1010 mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.nop().toU32());
1009 break :binder_blk_outer;1011 break :binder_blk_outer;
1010 }1012 }
1011 binder_blk: {1013 binder_blk: {
...@@ -1015,19 +1017,26 @@ fn writeStubHelperCommon(self: *Zld) !void {...@@ -1015,19 +1017,26 @@ fn writeStubHelperCommon(self: *Zld) !void {
1015 log.debug("2: disp=0x{x}, literal=0x{x}", .{ displacement, literal });1017 log.debug("2: disp=0x{x}, literal=0x{x}", .{ displacement, literal });
1016 // Pad with nop to please division.1018 // Pad with nop to please division.
1017 // nop1019 // nop
1018 mem.writeIntLittle(u32, code[12..16], Arm64.nop().toU32());1020 mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.nop().toU32());
1019 // ldr x16, label1021 // ldr x16, label
1020 mem.writeIntLittle(u32, code[16..20], Arm64.ldr(16, literal, 1).toU32());1022 mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{
1023 .literal = literal,
1024 }).toU32());
1021 break :binder_blk_outer;1025 break :binder_blk_outer;
1022 }1026 }
1023 // Use adrp followed by ldr(immediate).1027 // Use adrp followed by ldr(immediate).
1024 const this_page = @intCast(i32, this_addr >> 12);1028 const this_page = @intCast(i32, this_addr >> 12);
1025 const target_page = @intCast(i32, target_addr >> 12);1029 const target_page = @intCast(i32, target_addr >> 12);
1026 const pages = @bitCast(u21, @intCast(i21, target_page - this_page));1030 const pages = @intCast(i21, target_page - this_page);
1027 mem.writeIntLittle(u32, code[12..16], Arm64.adrp(16, pages).toU32());1031 mem.writeIntLittle(u32, code[12..16], aarch64.Instruction.adrp(.x16, pages).toU32());
1028 const narrowed = @truncate(u12, target_addr);1032 const narrowed = @truncate(u12, target_addr);
1029 const offset = try math.divExact(u12, narrowed, 8);1033 const offset = try math.divExact(u12, narrowed, 8);
1030 mem.writeIntLittle(u32, code[16..20], Arm64.ldrq(16, 16, offset).toU32());1034 mem.writeIntLittle(u32, code[16..20], aarch64.Instruction.ldr(.x16, .{
1035 .register = .{
1036 .rn = .x16,
1037 .offset = aarch64.Instruction.LoadStoreOffset.imm(offset),
1038 },
1039 }).toU32());
1031 }1040 }
1032 // br x161041 // br x16
1033 code[20] = 0x00;1042 code[20] = 0x00;
...@@ -1099,9 +1108,11 @@ fn writeStub(self: *Zld, index: u32) !void {...@@ -1099,9 +1108,11 @@ fn writeStub(self: *Zld, index: u32) !void {
1099 const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :inner;1108 const displacement = math.divExact(u64, target_addr - this_addr, 4) catch |_| break :inner;
1100 const literal = math.cast(u18, displacement) catch |_| break :inner;1109 const literal = math.cast(u18, displacement) catch |_| break :inner;
1101 // ldr x16, literal1110 // ldr x16, literal
1102 mem.writeIntLittle(u32, code[0..4], Arm64.ldr(16, literal, 1).toU32());1111 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.x16, .{
1112 .literal = literal,
1113 }).toU32());
1103 // nop1114 // nop
1104 mem.writeIntLittle(u32, code[4..8], Arm64.nop().toU32());1115 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.nop().toU32());
1105 break :outer;1116 break :outer;
1106 }1117 }
1107 inner: {1118 inner: {
...@@ -1109,22 +1120,29 @@ fn writeStub(self: *Zld, index: u32) !void {...@@ -1109,22 +1120,29 @@ fn writeStub(self: *Zld, index: u32) !void {
1109 const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :inner;1120 const displacement = math.divExact(u64, target_addr - new_this_addr, 4) catch |_| break :inner;
1110 const literal = math.cast(u18, displacement) catch |_| break :inner;1121 const literal = math.cast(u18, displacement) catch |_| break :inner;
1111 // nop1122 // nop
1112 mem.writeIntLittle(u32, code[0..4], Arm64.nop().toU32());1123 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.nop().toU32());
1113 // ldr x16, literal1124 // ldr x16, literal
1114 mem.writeIntLittle(u32, code[4..8], Arm64.ldr(16, literal, 1).toU32());1125 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{
1126 .literal = literal,
1127 }).toU32());
1115 break :outer;1128 break :outer;
1116 }1129 }
1117 // Use adrp followed by ldr(immediate).1130 // Use adrp followed by ldr(immediate).
1118 const this_page = @intCast(i32, this_addr >> 12);1131 const this_page = @intCast(i32, this_addr >> 12);
1119 const target_page = @intCast(i32, target_addr >> 12);1132 const target_page = @intCast(i32, target_addr >> 12);
1120 const pages = @bitCast(u21, @intCast(i21, target_page - this_page));1133 const pages = @intCast(i21, target_page - this_page);
1121 mem.writeIntLittle(u32, code[0..4], Arm64.adrp(16, pages).toU32());1134 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adrp(.x16, pages).toU32());
1122 const narrowed = @truncate(u12, target_addr);1135 const narrowed = @truncate(u12, target_addr);
1123 const offset = try math.divExact(u12, narrowed, 8);1136 const offset = try math.divExact(u12, narrowed, 8);
1124 mem.writeIntLittle(u32, code[4..8], Arm64.ldrq(16, 16, offset).toU32());1137 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ldr(.x16, .{
1138 .register = .{
1139 .rn = .x16,
1140 .offset = aarch64.Instruction.LoadStoreOffset.imm(offset),
1141 },
1142 }).toU32());
1125 }1143 }
1126 // br x161144 // br x16
1127 mem.writeIntLittle(u32, code[8..12], Arm64.br(16).toU32());1145 mem.writeIntLittle(u32, code[8..12], aarch64.Instruction.br(.x16).toU32());
1128 },1146 },
1129 else => unreachable,1147 else => unreachable,
1130 }1148 }
...@@ -1160,9 +1178,11 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void {...@@ -1160,9 +1178,11 @@ fn writeStubInStubHelper(self: *Zld, index: u32) !void {
1160 const displacement = try math.cast(i28, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - 4);1178 const displacement = try math.cast(i28, @intCast(i64, stub_helper.offset) - @intCast(i64, stub_off) - 4);
1161 const literal = @divExact(stub_size - @sizeOf(u32), 4);1179 const literal = @divExact(stub_size - @sizeOf(u32), 4);
1162 // ldr w16, literal1180 // ldr w16, literal
1163 mem.writeIntLittle(u32, code[0..4], Arm64.ldr(16, literal, 0).toU32());1181 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.ldr(.w16, .{
1182 .literal = literal,
1183 }).toU32());
1164 // b disp1184 // b disp
1165 mem.writeIntLittle(u32, code[4..8], Arm64.b(displacement).toU32());1185 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.b(displacement).toU32());
1166 mem.writeIntLittle(u32, code[8..12], 0x0); // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.1186 mem.writeIntLittle(u32, code[8..12], 0x0); // Just a placeholder populated in `populateLazyBindOffsetsInStubHelper`.
1167 },1187 },
1168 else => unreachable,1188 else => unreachable,
...@@ -1486,9 +1506,18 @@ fn doRelocs(self: *Zld) !void {...@@ -1486,9 +1506,18 @@ fn doRelocs(self: *Zld) !void {
1486 .ARM64_RELOC_BRANCH26 => {1506 .ARM64_RELOC_BRANCH26 => {
1487 assert(rel.r_length == 2);1507 assert(rel.r_length == 2);
1488 const inst = code[off..][0..4];1508 const inst = code[off..][0..4];
1489 const displacement = @intCast(i28, @intCast(i64, target_addr) - @intCast(i64, this_addr));1509 const displacement = @intCast(
1490 var parsed = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.Branch), inst);1510 i28,
1491 parsed.disp = @truncate(u26, @bitCast(u28, displacement) >> 2);1511 @intCast(i64, target_addr) - @intCast(i64, this_addr),
1512 );
1513 var parsed = mem.bytesAsValue(
1514 meta.TagPayload(
1515 aarch64.Instruction,
1516 aarch64.Instruction.UnconditionalBranchImmediate,
1517 ),
1518 inst,
1519 );
1520 parsed.imm26 = @truncate(u26, @bitCast(u28, displacement) >> 2);
1492 },1521 },
1493 .ARM64_RELOC_PAGE21,1522 .ARM64_RELOC_PAGE21,
1494 .ARM64_RELOC_GOT_LOAD_PAGE21,1523 .ARM64_RELOC_GOT_LOAD_PAGE21,
...@@ -1501,7 +1530,13 @@ fn doRelocs(self: *Zld) !void {...@@ -1501,7 +1530,13 @@ fn doRelocs(self: *Zld) !void {
1501 const target_page = @intCast(i32, ta >> 12);1530 const target_page = @intCast(i32, ta >> 12);
1502 const pages = @bitCast(u21, @intCast(i21, target_page - this_page));1531 const pages = @bitCast(u21, @intCast(i21, target_page - this_page));
1503 log.debug(" | moving by {} pages", .{pages});1532 log.debug(" | moving by {} pages", .{pages});
1504 var parsed = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.Address), inst);1533 var parsed = mem.bytesAsValue(
1534 meta.TagPayload(
1535 aarch64.Instruction,
1536 aarch64.Instruction.PCRelativeAddress,
1537 ),
1538 inst,
1539 );
1505 parsed.immhi = @truncate(u19, pages >> 2);1540 parsed.immhi = @truncate(u19, pages >> 2);
1506 parsed.immlo = @truncate(u2, pages);1541 parsed.immlo = @truncate(u2, pages);
1507 addend = null;1542 addend = null;
...@@ -1510,17 +1545,29 @@ fn doRelocs(self: *Zld) !void {...@@ -1510,17 +1545,29 @@ fn doRelocs(self: *Zld) !void {
1510 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,1545 .ARM64_RELOC_GOT_LOAD_PAGEOFF12,
1511 => {1546 => {
1512 const inst = code[off..][0..4];1547 const inst = code[off..][0..4];
1513 if (Arm64.isArithmetic(inst)) {1548 if (aarch64IsArithmetic(inst)) {
1514 log.debug(" | detected ADD opcode", .{});1549 log.debug(" | detected ADD opcode", .{});
1515 // add1550 // add
1516 var parsed = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.Add), inst);1551 var parsed = mem.bytesAsValue(
1552 meta.TagPayload(
1553 aarch64.Instruction,
1554 aarch64.Instruction.AddSubtractImmediate,
1555 ),
1556 inst,
1557 );
1517 const ta = if (addend) |a| target_addr + a else target_addr;1558 const ta = if (addend) |a| target_addr + a else target_addr;
1518 const narrowed = @truncate(u12, ta);1559 const narrowed = @truncate(u12, ta);
1519 parsed.offset = narrowed;1560 parsed.imm12 = narrowed;
1520 } else {1561 } else {
1521 log.debug(" | detected LDR/STR opcode", .{});1562 log.debug(" | detected LDR/STR opcode", .{});
1522 // ldr/str1563 // ldr/str
1523 var parsed = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.LoadRegister), inst);1564 var parsed = mem.bytesAsValue(
1565 meta.TagPayload(
1566 aarch64.Instruction,
1567 aarch64.Instruction.LoadStoreRegister,
1568 ),
1569 inst,
1570 );
1524 const ta = if (addend) |a| target_addr + a else target_addr;1571 const ta = if (addend) |a| target_addr + a else target_addr;
1525 const narrowed = @truncate(u12, ta);1572 const narrowed = @truncate(u12, ta);
1526 const offset: u12 = blk: {1573 const offset: u12 = blk: {
...@@ -1541,27 +1588,43 @@ fn doRelocs(self: *Zld) !void {...@@ -1541,27 +1588,43 @@ fn doRelocs(self: *Zld) !void {
1541 addend = null;1588 addend = null;
1542 },1589 },
1543 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {1590 .ARM64_RELOC_TLVP_LOAD_PAGEOFF12 => {
1544 // TODO why is this necessary?
1545 const RegInfo = struct {1591 const RegInfo = struct {
1546 rt: u5,1592 rd: u5,
1547 rn: u5,1593 rn: u5,
1548 size: u1,1594 size: u1,
1549 };1595 };
1550 const inst = code[off..][0..4];1596 const inst = code[off..][0..4];
1551 const parsed: RegInfo = blk: {1597 const parsed: RegInfo = blk: {
1552 if (Arm64.isArithmetic(inst)) {1598 if (aarch64IsArithmetic(inst)) {
1553 const curr = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.Add), inst);1599 const curr = mem.bytesAsValue(
1554 break :blk .{ .rt = curr.rt, .rn = curr.rn, .size = curr.size };1600 meta.TagPayload(
1601 aarch64.Instruction,
1602 aarch64.Instruction.AddSubtractImmediate,
1603 ),
1604 inst,
1605 );
1606 break :blk .{ .rd = curr.rd, .rn = curr.rn, .size = curr.sf };
1555 } else {1607 } else {
1556 const curr = mem.bytesAsValue(meta.TagPayload(Arm64, Arm64.LoadRegister), inst);1608 const curr = mem.bytesAsValue(
1557 break :blk .{ .rt = curr.rt, .rn = curr.rn, .size = @truncate(u1, curr.size) };1609 meta.TagPayload(
1610 aarch64.Instruction,
1611 aarch64.Instruction.LoadStoreRegister,
1612 ),
1613 inst,
1614 );
1615 break :blk .{ .rd = curr.rt, .rn = curr.rn, .size = @truncate(u1, curr.size) };
1558 }1616 }
1559 };1617 };
1560 const ta = if (addend) |a| target_addr + a else target_addr;1618 const ta = if (addend) |a| target_addr + a else target_addr;
1561 const narrowed = @truncate(u12, ta);1619 const narrowed = @truncate(u12, ta);
1562 log.debug(" | rewriting TLV access to ADD opcode", .{});1620 log.debug(" | rewriting TLV access to ADD opcode", .{});
1563 // For TLV, we always generate an add instruction.1621 // For TLV, we always generate an add instruction.
1564 mem.writeIntLittle(u32, inst, Arm64.add(parsed.rt, parsed.rn, narrowed, parsed.size).toU32());1622 mem.writeIntLittle(u32, inst, aarch64.Instruction.add(
1623 @intToEnum(aarch64.Register, parsed.rd),
1624 @intToEnum(aarch64.Register, parsed.rn),
1625 narrowed,
1626 false,
1627 ).toU32());
1565 },1628 },
1566 .ARM64_RELOC_SUBTRACTOR => {1629 .ARM64_RELOC_SUBTRACTOR => {
1567 sub = @intCast(i64, target_addr);1630 sub = @intCast(i64, target_addr);
...@@ -2965,3 +3028,8 @@ fn isExtern(sym: *const macho.nlist_64) callconv(.Inline) bool {...@@ -2965,3 +3028,8 @@ fn isExtern(sym: *const macho.nlist_64) callconv(.Inline) bool {
2965fn isWeakDef(sym: *const macho.nlist_64) callconv(.Inline) bool {3028fn isWeakDef(sym: *const macho.nlist_64) callconv(.Inline) bool {
2966 return (sym.n_desc & macho.N_WEAK_DEF) != 0;3029 return (sym.n_desc & macho.N_WEAK_DEF) != 0;
2967}3030}
3031
3032fn aarch64IsArithmetic(inst: *const [4]u8) callconv(.Inline) bool {
3033 const group_decode = @truncate(u5, inst[3]);
3034 return ((group_decode >> 2) == 4);
3035}
src/link/MachO/reloc.zig deleted-197
...@@ -1,197 +0,0 @@
1const std = @import("std");
2const log = std.log.scoped(.reloc);
3
4pub const Arm64 = union(enum) {
5 Branch: packed struct {
6 disp: u26,
7 fixed: u5 = 0b00101,
8 link: u1,
9 },
10 BranchRegister: packed struct {
11 _1: u5 = 0b0000_0,
12 reg: u5,
13 _2: u11 = 0b1111_1000_000,
14 link: u1,
15 _3: u10 = 0b1101_0110_00,
16 },
17 Address: packed struct {
18 reg: u5,
19 immhi: u19,
20 _1: u5 = 0b10000,
21 immlo: u2,
22 page: u1,
23 },
24 LoadRegister: packed struct {
25 rt: u5,
26 rn: u5,
27 offset: u12,
28 opc: u2,
29 _2: u2 = 0b01,
30 v: u1,
31 _1: u3 = 0b111,
32 size: u2,
33 },
34 LoadLiteral: packed struct {
35 reg: u5,
36 literal: u19,
37 _1: u6 = 0b011_0_00,
38 size: u1,
39 _2: u1 = 0b0,
40 },
41 Add: packed struct {
42 rt: u5,
43 rn: u5,
44 offset: u12,
45 _1: u9 = 0b0_0_100010_0,
46 size: u1,
47 },
48 Nop: packed struct {
49 fixed: u32 = 0b1101010100_0_00_011_0010_0000_000_11111,
50 },
51
52 pub fn toU32(self: Arm64) u32 {
53 const as_u32 = switch (self) {
54 .Branch => |x| @bitCast(u32, x),
55 .BranchRegister => |x| @bitCast(u32, x),
56 .Address => |x| @bitCast(u32, x),
57 .LoadRegister => |x| @bitCast(u32, x),
58 .LoadLiteral => |x| @bitCast(u32, x),
59 .Add => |x| @bitCast(u32, x),
60 .Nop => |x| @bitCast(u32, x),
61 };
62 return as_u32;
63 }
64
65 pub fn b(disp: i28) Arm64 {
66 return Arm64{
67 .Branch = .{
68 .disp = @truncate(u26, @bitCast(u28, disp) >> 2),
69 .link = 0,
70 },
71 };
72 }
73
74 pub fn bl(disp: i28) Arm64 {
75 return Arm64{
76 .Branch = .{
77 .disp = @truncate(u26, @bitCast(u28, disp) >> 2),
78 .link = 1,
79 },
80 };
81 }
82
83 pub fn br(reg: u5) Arm64 {
84 return Arm64{
85 .BranchRegister = .{
86 .reg = reg,
87 .link = 0,
88 },
89 };
90 }
91
92 pub fn blr(reg: u5) Arm64 {
93 return Arm64{
94 .BranchRegister = .{
95 .reg = reg,
96 .link = 1,
97 },
98 };
99 }
100
101 pub fn adr(reg: u5, disp: u21) Arm64 {
102 return Arm64{
103 .Address = .{
104 .reg = reg,
105 .immhi = @truncate(u19, disp >> 2),
106 .immlo = @truncate(u2, disp),
107 .page = 0,
108 },
109 };
110 }
111
112 pub fn adrp(reg: u5, disp: u21) Arm64 {
113 return Arm64{
114 .Address = .{
115 .reg = reg,
116 .immhi = @truncate(u19, disp >> 2),
117 .immlo = @truncate(u2, disp),
118 .page = 1,
119 },
120 };
121 }
122
123 pub fn ldr(reg: u5, literal: u19, size: u1) Arm64 {
124 return Arm64{
125 .LoadLiteral = .{
126 .reg = reg,
127 .literal = literal,
128 .size = size,
129 },
130 };
131 }
132
133 pub fn add(rt: u5, rn: u5, offset: u12, size: u1) Arm64 {
134 return Arm64{
135 .Add = .{
136 .rt = rt,
137 .rn = rn,
138 .offset = offset,
139 .size = size,
140 },
141 };
142 }
143
144 pub fn ldrq(rt: u5, rn: u5, offset: u12) Arm64 {
145 return Arm64{
146 .LoadRegister = .{
147 .rt = rt,
148 .rn = rn,
149 .offset = offset,
150 .opc = 0b01,
151 .v = 0b0,
152 .size = 0b11,
153 },
154 };
155 }
156 pub fn ldrh(rt: u5, rn: u5, offset: u12) Arm64 {
157 return Arm64{
158 .LoadRegister = .{
159 .rt = rt,
160 .rn = rn,
161 .offset = offset,
162 .opc = 0b01,
163 .v = 0b0,
164 .size = 0b01,
165 },
166 };
167 }
168 pub fn ldrb(rt: u5, rn: u5, offset: u12) Arm64 {
169 return Arm64{
170 .LoadRegister = .{
171 .rt = rt,
172 .rn = rn,
173 .offset = offset,
174 .opc = 0b01,
175 .v = 0b0,
176 .size = 0b00,
177 },
178 };
179 }
180
181 pub fn nop() Arm64 {
182 return Arm64{
183 .Nop = .{},
184 };
185 }
186
187 pub fn isArithmetic(inst: *const [4]u8) bool {
188 const group_decode = @truncate(u5, inst[3]);
189 log.debug("{b}", .{group_decode});
190 return ((group_decode >> 2) == 4);
191 // if ((group_decode >> 2) == 4) {
192 // log.debug("Arithmetic imm", .{});
193 // } else if (((group_decode & 0b01010) >> 3) == 1) {
194 // log.debug("Load/store", .{});
195 // }
196 }
197};