authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-17 11:26:02+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-01-17 14:57:53+01:00
logb25cf7db0253f331f44b279fcbcdf71faa1afb92
tree7c579064f6b87be5642b6b85562b820ddea413b0
parente292f33de75fa00863a855161d6df9f6884df841

stage2 aarch64: add basic function pro/epilogue

Fix typo in `nop` implementation. Simplify `aarch64` macOS tests.

3 files changed, 88 insertions(+), 81 deletions(-)

src/codegen.zig+64-2
...@@ -637,6 +637,67 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -637,6 +637,67 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
637 try self.dbgSetEpilogueBegin();637 try self.dbgSetEpilogueBegin();
638 }638 }
639 },639 },
640 .aarch64, .aarch64_be, .aarch64_32 => {
641 const cc = self.fn_type.fnCallingConvention();
642 if (cc != .Naked) {
643 // TODO Finish function prologue and epilogue for aarch64.
644 // Reserve the stack for local variables, etc.
645
646 // stp fp, lr, [sp, #-16]!
647 writeInt(u32, try self.code.addManyAsArray(4), Instruction.stp(
648 .x29,
649 .x30,
650 Register.sp,
651 Instruction.LoadStorePairOffset.pre_index(-16),
652 ).toU32());
653
654 try self.dbgSetPrologueEnd();
655
656 try self.genBody(self.mod_fn.body);
657
658 try self.dbgSetEpilogueBegin();
659
660 // exitlude jumps
661 if (self.exitlude_jump_relocs.items.len == 1) {
662 // There is only one relocation. Hence,
663 // this relocation must be at the end of
664 // the code. Therefore, we can just delete
665 // the space initially reserved for the
666 // jump
667 self.code.items.len -= 4;
668 } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {
669 const amt = @intCast(i32, self.code.items.len) - @intCast(i32, jmp_reloc + 8);
670 if (amt == -4) {
671 // This return is at the end of the
672 // code block. We can't just delete
673 // the space because there may be
674 // other jumps we already relocated to
675 // the address. Instead, insert a nop
676 writeInt(u32, self.code.items[jmp_reloc..][0..4], Instruction.nop().toU32());
677 } else {
678 if (math.cast(i28, amt)) |offset| {
679 writeInt(u32, self.code.items[jmp_reloc..][0..4], Instruction.b(offset).toU32());
680 } else |err| {
681 return self.failSymbol("exitlude jump is too large", .{});
682 }
683 }
684 }
685
686 // ldp fp, lr, [sp], #16
687 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ldp(
688 .x29,
689 .x30,
690 Register.sp,
691 Instruction.LoadStorePairOffset.post_index(16),
692 ).toU32());
693 // ret lr
694 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ret(null).toU32());
695 } else {
696 try self.dbgSetPrologueEnd();
697 try self.genBody(self.mod_fn.body);
698 try self.dbgSetEpilogueBegin();
699 }
700 },
640 else => {701 else => {
641 try self.dbgSetPrologueEnd();702 try self.dbgSetPrologueEnd();
642 try self.genBody(self.mod_fn.body);703 try self.genBody(self.mod_fn.body);
...@@ -1962,8 +2023,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1962,8 +2023,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1962 try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);2023 try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);
1963 },2024 },
1964 .aarch64 => {2025 .aarch64 => {
1965 // TODO: relocations2026 // Just add space for an instruction, patch this later
1966 writeInt(u32, try self.code.addManyAsArray(4), Instruction.ret(null).toU32());2027 try self.code.resize(self.code.items.len + 4);
2028 try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4);
1967 },2029 },
1968 else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),2030 else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}),
1969 }2031 }
src/codegen/aarch64.zig+1-1
...@@ -814,7 +814,7 @@ pub const Instruction = union(enum) {...@@ -814,7 +814,7 @@ pub const Instruction = union(enum) {
814 // Nop814 // Nop
815815
816 pub fn nop() Instruction {816 pub fn nop() Instruction {
817 return Instruction{ .NoOperation = {} };817 return Instruction{ .NoOperation = .{} };
818 }818 }
819819
820 // Logical (shifted register)820 // Logical (shifted register)
test/stage2/aarch64.zig+23-78
...@@ -17,97 +17,60 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -17,97 +17,60 @@ pub fn addCases(ctx: *TestContext) !void {
1717
18 // Regular old hello world18 // Regular old hello world
19 case.addCompareOutput(19 case.addCompareOutput(
20 \\extern "c" fn write(usize, usize, usize) void;
21 \\extern "c" fn exit(usize) noreturn;
22 \\
20 \\export fn _start() noreturn {23 \\export fn _start() noreturn {
21 \\ print();24 \\ print();
22 \\25 \\
23 \\ exit();26 \\ exit(0);
24 \\}27 \\}
25 \\28 \\
26 \\fn print() void {29 \\fn print() void {
27 \\ asm volatile ("svc #0x80"30 \\ const msg = @ptrToInt("Hello, World!\n");
28 \\ :31 \\ const len = 14;
29 \\ : [number] "{x16}" (4),32 \\ write(1, msg, len);
30 \\ [arg1] "{x0}" (1),
31 \\ [arg2] "{x1}" (@ptrToInt("Hello, World!\n")),
32 \\ [arg3] "{x2}" (14)
33 \\ : "memory"
34 \\ );
35 \\ return;
36 \\}
37 \\
38 \\fn exit() noreturn {
39 \\ asm volatile ("svc #0x80"
40 \\ :
41 \\ : [number] "{x16}" (1),
42 \\ [arg1] "{x0}" (0)
43 \\ : "memory"
44 \\ );
45 \\ unreachable;
46 \\}33 \\}
47 ,34 ,
48 "Hello, World!\n",35 "Hello, World!\n",
49 );36 );
37
50 // Now change the message only38 // Now change the message only
51 case.addCompareOutput(39 case.addCompareOutput(
40 \\extern "c" fn write(usize, usize, usize) void;
41 \\extern "c" fn exit(usize) noreturn;
42 \\
52 \\export fn _start() noreturn {43 \\export fn _start() noreturn {
53 \\ print();44 \\ print();
54 \\45 \\
55 \\ exit();46 \\ exit(0);
56 \\}47 \\}
57 \\48 \\
58 \\fn print() void {49 \\fn print() void {
59 \\ asm volatile ("svc #0x80"50 \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
60 \\ :51 \\ const len = 104;
61 \\ : [number] "{x16}" (4),52 \\ write(1, msg, len);
62 \\ [arg1] "{x0}" (1),
63 \\ [arg2] "{x1}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
64 \\ [arg3] "{x2}" (104)
65 \\ : "memory"
66 \\ );
67 \\ return;
68 \\}
69 \\
70 \\fn exit() noreturn {
71 \\ asm volatile ("svc #0x80"
72 \\ :
73 \\ : [number] "{x16}" (1),
74 \\ [arg1] "{x0}" (0)
75 \\ : "memory"
76 \\ );
77 \\ unreachable;
78 \\}53 \\}
79 ,54 ,
80 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",55 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
81 );56 );
57
82 // Now we print it twice.58 // Now we print it twice.
83 case.addCompareOutput(59 case.addCompareOutput(
60 \\extern "c" fn write(usize, usize, usize) void;
61 \\extern "c" fn exit(usize) noreturn;
62 \\
84 \\export fn _start() noreturn {63 \\export fn _start() noreturn {
85 \\ print();64 \\ print();
86 \\ print();65 \\ print();
87 \\66 \\
88 \\ exit();67 \\ exit(0);
89 \\}68 \\}
90 \\69 \\
91 \\fn print() void {70 \\fn print() void {
92 \\ asm volatile ("svc #0x80"71 \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
93 \\ :72 \\ const len = 104;
94 \\ : [number] "{x16}" (4),73 \\ write(1, msg, len);
95 \\ [arg1] "{x0}" (1),
96 \\ [arg2] "{x1}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
97 \\ [arg3] "{x2}" (104)
98 \\ : "memory"
99 \\ );
100 \\ return;
101 \\}
102 \\
103 \\fn exit() noreturn {
104 \\ asm volatile ("svc #0x80"
105 \\ :
106 \\ : [number] "{x16}" (1),
107 \\ [arg1] "{x0}" (0)
108 \\ : "memory"
109 \\ );
110 \\ unreachable;
111 \\}74 \\}
112 ,75 ,
113 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.76 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
...@@ -200,24 +163,6 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -200,24 +163,6 @@ pub fn addCases(ctx: *TestContext) !void {
200 );163 );
201 }164 }
202165
203 {
204 var case = ctx.exe("hello world linked to libc", macos_aarch64);
205
206 // TODO rewrite this test once we handle more int conversions and return args.
207 case.addCompareOutput(
208 \\extern "c" fn write(usize, usize, usize) void;
209 \\extern "c" fn exit(usize) noreturn;
210 \\
211 \\export fn _start() noreturn {
212 \\ write(1, @ptrToInt("Hello,"), 6);
213 \\ write(1, @ptrToInt(" World!\n,"), 8);
214 \\ exit(0);
215 \\}
216 ,
217 "Hello, World!\n",
218 );
219 }
220
221 {166 {
222 var case = ctx.exe("only libc exit", macos_aarch64);167 var case = ctx.exe("only libc exit", macos_aarch64);
223168