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 {
25882588 // For MachO, the binary, with the exception of object files, has to be a PIE.
25892589 // Therefore we cannot load an absolute address.
25902590 // Instead, we need to make use of PC-relative addressing.
2591 // if (reg.id() == 0) { // x0 is special-cased
2591 // 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());
25922604 try self.mod_fn.owner_decl.link.macho.addPieFixup(self.bin_file.allocator, .{
25932605 .address = addr,
25942606 .start = self.code.items.len,
25952607 .len = 4,
25962608 });
2597 // bl [label]
2598 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bl(0).toU32());
2599 // } else {
2600 // unreachable; // TODO
2601 // }
2609 // b [label]
2610 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.b(0).toU32());
2611 // mov r, x0
2612 mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.orr(reg, .x0, Instruction.RegisterShift.none()).toU32());
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 }
26022649 } else {
26032650 // The value is in memory at a hard-coded address.
26042651 // 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) {
1919 w16, w17, w18, w19, w20, w21, w22, w23,
2020 w24, w25, w26, w27, w28, w29, w30, wzr,
2121
22 pub const sp = .xzr;
23
2224 pub fn id(self: Register) u5 {
2325 return @truncate(u5, @enumToInt(self));
2426 }
......@@ -195,6 +197,17 @@ test "FloatingPointRegister.toX" {
195197
196198/// Represents an instruction in the AArch64 instruction set
197199pub 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 },
198211 MoveWideImmediate: packed struct {
199212 rd: u5,
200213 imm16: u16,
......@@ -251,6 +264,7 @@ pub const Instruction = union(enum) {
251264
252265 pub fn toU32(self: Instruction) u32 {
253266 return switch (self) {
267 .OrShiftedRegister => |v| @bitCast(u32, v),
254268 .MoveWideImmediate => |v| @bitCast(u32, v),
255269 .PCRelativeAddress => |v| @bitCast(u32, v),
256270 .LoadStoreRegister => |v| @bitCast(u32, v),
......@@ -379,8 +393,65 @@ pub const Instruction = union(enum) {
379393 }
380394 };
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
382415 // 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
384455 fn moveWideImmediate(
385456 opc: u2,
386457 rd: Register,
......@@ -543,6 +614,16 @@ pub const Instruction = union(enum) {
543614 };
544615 }
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
546627 // Move wide (immediate)
547628
548629 pub fn movn(rd: Register, imm16: u16, shift: u6) Instruction {
......@@ -653,6 +734,14 @@ test "serialize instructions" {
653734 };
654735
655736 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 },
656745 .{ // movz x1 #4
657746 .inst = Instruction.movz(.x1, 4, 0),
658747 .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 {
10281028 } else {
10291029 const displacement = @intCast(u27, target_addr - this_addr);
10301030 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());
10321032 }
10331033 }
10341034
......@@ -1670,10 +1670,10 @@ fn writeOffsetTableEntry(self: *MachO, index: usize) !void {
16701670 } else {
16711671 const pos_symbol_off = @intCast(u20, vmaddr - self.offset_table.items[index]);
16721672 const symbol_off = @intCast(i21, pos_symbol_off) * -1;
1673 // adr .x0 [-disp]
1674 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x1, symbol_off).toU32());
1675 // ret
1676 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ret(null).toU32());
1673 // adr x0, #-disp
1674 mem.writeIntLittle(u32, code[0..4], aarch64.Instruction.adr(.x0, symbol_off).toU32());
1675 // ret x28
1676 mem.writeIntLittle(u32, code[4..8], aarch64.Instruction.ret(.x28).toU32());
16771677 }
16781678 log.debug("writing offset table entry 0x{x} at 0x{x}\n", .{ self.offset_table.items[index], off });
16791679 try self.base.file.?.pwriteAll(&code, off);