authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-25 19:58:15+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-26 11:50:09+01:00
logc749b78df50160bedae40f90765442dd1f49de3a
tree18db7b29753f67f787ff2c3de696af673ce0b5cf
parent10942e3f86c03d30833cc221371f30b78a4bd710

stage2 macho: add orr and orn instructions


3 files changed, 147 insertions(+), 11 deletions(-)

src/codegen.zig+53-6
...@@ -2588,17 +2588,64 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2588,17 +2588,64 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2588 // For MachO, the binary, with the exception of object files, has to be a PIE.2588 // For MachO, the binary, with the exception of object files, has to be a PIE.
2589 // Therefore we cannot load an absolute address.2589 // Therefore we cannot load an absolute address.
2590 // Instead, we need to make use of PC-relative addressing.2590 // Instead, we need to make use of PC-relative addressing.
2591 // if (reg.id() == 0) { // x0 is special-cased2591 // TODO This needs to be optimised in the stack usage (perhaps use a shadow stack
2592 // like described here:
2593 // https://community.arm.com/developer/ip-products/processors/b/processors-ip-blog/posts/using-the-stack-in-aarch64-implementing-push-and-pop)
2594 // TODO As far as branching is concerned, instead of saving the return address
2595 // in a register, I'm thinking here of immitating x86_64, and having the address
2596 // passed on the stack.
2597 if (reg.id() == 0) { // x0 is special-cased
2598 // str x28, [sp, #-16]
2599 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.x28, Register.sp, .{
2600 .offset = Instruction.Offset.imm_pre_index(-16),
2601 }).toU32());
2602 // adr x28, #8
2603 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());
2592 try self.mod_fn.owner_decl.link.macho.addPieFixup(self.bin_file.allocator, .{2604 try self.mod_fn.owner_decl.link.macho.addPieFixup(self.bin_file.allocator, .{
2593 .address = addr,2605 .address = addr,
2594 .start = self.code.items.len,2606 .start = self.code.items.len,
2595 .len = 4,2607 .len = 4,
2596 });2608 });
2597 // bl [label]2609 // b [label]
2598 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bl(0).toU32());2610 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.b(0).toU32());
2599 // } else {2611 // mov r, x0
2600 // unreachable; // TODO2612 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(reg, .x0, Instruction.RegisterShift.none()).toU32());
2601 // }2613 // ldr x28, [sp], #16
2614 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
2615 .rn = Register.sp,
2616 .offset = Instruction.Offset.imm_post_index(16),
2617 }).toU32());
2618 } else {
2619 // str x28, [sp, #-16]
2620 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.x28, Register.sp, .{
2621 .offset = Instruction.Offset.imm_pre_index(-16),
2622 }).toU32());
2623 // str x0, [sp, #-16]
2624 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.str(.x0, Register.sp, .{
2625 .offset = Instruction.Offset.imm_pre_index(-16),
2626 }).toU32());
2627 // adr x28, #8
2628 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.adr(.x28, 8).toU32());
2629 try self.mod_fn.owner_decl.link.macho.addPieFixup(self.bin_file.allocator, .{
2630 .address = addr,
2631 .start = self.code.items.len,
2632 .len = 4,
2633 });
2634 // b [label]
2635 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.b(0).toU32());
2636 // mov r, x0
2637 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(reg, .x0, Instruction.RegisterShift.none()).toU32());
2638 // ldr x0, [sp], #16
2639 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x0, .{
2640 .rn = Register.sp,
2641 .offset = Instruction.Offset.imm_post_index(16),
2642 }).toU32());
2643 // ldr x28, [sp], #16
2644 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.ldr(.x28, .{
2645 .rn = Register.sp,
2646 .offset = Instruction.Offset.imm_post_index(16),
2647 }).toU32());
2648 }
2602 } else {2649 } else {
2603 // The value is in memory at a hard-coded address.2650 // The value is in memory at a hard-coded address.
2604 // If the type is a pointer, it means the pointer address is at this memory location.2651 // If the type is a pointer, it means the pointer address is at this memory location.
src/codegen/aarch64.zig+89
...@@ -19,6 +19,8 @@ pub const Register = enum(u6) {...@@ -19,6 +19,8 @@ pub const Register = enum(u6) {
19 w16, w17, w18, w19, w20, w21, w22, w23,19 w16, w17, w18, w19, w20, w21, w22, w23,
20 w24, w25, w26, w27, w28, w29, w30, wzr,20 w24, w25, w26, w27, w28, w29, w30, wzr,
2121
22 pub const sp = .xzr;
23
22 pub fn id(self: Register) u5 {24 pub fn id(self: Register) u5 {
23 return @truncate(u5, @enumToInt(self));25 return @truncate(u5, @enumToInt(self));
24 }26 }
...@@ -195,6 +197,17 @@ test "FloatingPointRegister.toX" {...@@ -195,6 +197,17 @@ test "FloatingPointRegister.toX" {
195197
196/// Represents an instruction in the AArch64 instruction set198/// Represents an instruction in the AArch64 instruction set
197pub const Instruction = union(enum) {199pub const Instruction = union(enum) {
200 OrShiftedRegister: packed struct {
201 rd: u5,
202 rn: u5,
203 imm6: u6,
204 rm: u5,
205 n: u1,
206 shift: u2,
207 fixed: u5 = 0b01010,
208 opc: u2 = 0b01,
209 sf: u1,
210 },
198 MoveWideImmediate: packed struct {211 MoveWideImmediate: packed struct {
199 rd: u5,212 rd: u5,
200 imm16: u16,213 imm16: u16,
...@@ -251,6 +264,7 @@ pub const Instruction = union(enum) {...@@ -251,6 +264,7 @@ pub const Instruction = union(enum) {
251264
252 pub fn toU32(self: Instruction) u32 {265 pub fn toU32(self: Instruction) u32 {
253 return switch (self) {266 return switch (self) {
267 .OrShiftedRegister => |v| @bitCast(u32, v),
254 .MoveWideImmediate => |v| @bitCast(u32, v),268 .MoveWideImmediate => |v| @bitCast(u32, v),
255 .PCRelativeAddress => |v| @bitCast(u32, v),269 .PCRelativeAddress => |v| @bitCast(u32, v),
256 .LoadStoreRegister => |v| @bitCast(u32, v),270 .LoadStoreRegister => |v| @bitCast(u32, v),
...@@ -379,8 +393,65 @@ pub const Instruction = union(enum) {...@@ -379,8 +393,65 @@ pub const Instruction = union(enum) {
379 }393 }
380 };394 };
381395
396 pub const RegisterShift = struct {
397 rn: u5,
398 imm6: u6,
399 shift: enum(u2) {
400 Lsl = 0,
401 Lsr = 1,
402 Asr = 2,
403 Ror = 3,
404 },
405
406 pub fn none() RegisterShift {
407 return .{
408 .rn = 0b11111,
409 .imm6 = 0,
410 .shift = .Lsl,
411 };
412 }
413 };
414
382 // Helper functions for assembly syntax functions415 // Helper functions for assembly syntax functions
383416
417 fn orShiftedRegister(
418 rd: Register,
419 rm: Register,
420 shift: RegisterShift,
421 invert: bool,
422 ) Instruction {
423 const n: u1 = if (invert) 1 else 0;
424 switch (rd.size()) {
425 32 => {
426 return Instruction{
427 .OrShiftedRegister = .{
428 .rd = rd.id(),
429 .rn = shift.rn,
430 .imm6 = shift.imm6,
431 .rm = rm.id(),
432 .n = n,
433 .shift = @enumToInt(shift.shift),
434 .sf = 0,
435 },
436 };
437 },
438 64 => {
439 return Instruction{
440 .OrShiftedRegister = .{
441 .rd = rd.id(),
442 .rn = shift.rn,
443 .imm6 = shift.imm6,
444 .rm = rm.id(),
445 .n = n,
446 .shift = @enumToInt(shift.shift),
447 .sf = 1,
448 },
449 };
450 },
451 else => unreachable, // unexpected register size
452 }
453 }
454
384 fn moveWideImmediate(455 fn moveWideImmediate(
385 opc: u2,456 opc: u2,
386 rd: Register,457 rd: Register,
...@@ -543,6 +614,16 @@ pub const Instruction = union(enum) {...@@ -543,6 +614,16 @@ pub const Instruction = union(enum) {
543 };614 };
544 }615 }
545616
617 // Bitwise (inclusive) OR of a register value
618
619 pub fn orr(rd: Register, rm: Register, shift: RegisterShift) Instruction {
620 return orShiftedRegister(rd, rm, shift, false);
621 }
622
623 pub fn orn(rd: Register, rm: Register, shift: RegisterShift) Instruction {
624 return orShiftedRegister(rd, rm, shift, true);
625 }
626
546 // Move wide (immediate)627 // Move wide (immediate)
547628
548 pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction {629 pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction {
...@@ -653,6 +734,14 @@ test "serialize instructions" {...@@ -653,6 +734,14 @@ test "serialize instructions" {
653 };734 };
654735
655 const testcases = [_]Testcase{736 const testcases = [_]Testcase{
737 .{ // orr x0 x1
738 .inst = Instruction.orr(.x0, .x1, Instruction.RegisterShift.none()),
739 .expected = 0b1_01_01010_00_0_00001_000000_11111_00000,
740 },
741 .{ // orn x0 x1
742 .inst = Instruction.orn(.x0, .x1, Instruction.RegisterShift.none()),
743 .expected = 0b1_01_01010_00_1_00001_000000_11111_00000,
744 },
656 .{ // movz x1 #4745 .{ // movz x1 #4
657 .inst = Instruction.movz(.x1, 4, 0),746 .inst = Instruction.movz(.x1, 4, 0),
658 .expected = 0b1_10_100101_00_0000000000000100_00001,747 .expected = 0b1_10_100101_00_0000000000000100_00001,
src/link/MachO.zig+5-5
...@@ -1028,7 +1028,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1028,7 +1028,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1028 } else {1028 } else {
1029 const displacement = @intCast(u27, target_addr - this_addr);1029 const displacement = @intCast(u27, target_addr - this_addr);
1030 var placeholder = code_buffer.items[fixup.start..][0..fixup.len];1030 var placeholder = code_buffer.items[fixup.start..][0..fixup.len];
1031 mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.bl(@intCast(i28, displacement)).toU32());1031 mem.writeIntSliceLittle(u32, placeholder, aarch64.Instruction.b(@intCast(i28, displacement)).toU32());
1032 }1032 }
1033 }1033 }
10341034
...@@ -1670,10 +1670,10 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {...@@ -1670,10 +1670,10 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
1670 } else {1670 } else {
1671 const pos_symbol_off = @intCast(u20, vmaddr - self.offset_table.items[index]);1671 const pos_symbol_off = @intCast(u20, vmaddr - self.offset_table.items[index]);
1672 const symbol_off = @intCast(i21, pos_symbol_off) * -1;1672 const symbol_off = @intCast(i21, pos_symbol_off) * -1;
1673 // adr .x0 [-disp]1673 // adr x0, #-disp
1674 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x1, symbol_off).toU32());1674 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x0, symbol_off).toU32());
1675 // ret1675 // ret x28
1676 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ret(null).toU32());1676 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ret(.x28).toU32());
1677 }1677 }
1678 log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off });1678 log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off });
1679 try self.base.file.?.pwriteAll(&code, off);1679 try self.base.file.?.pwriteAll(&code, off);