Commit d542e88706

Jakub Konka <kubkon@jakubkonka.com>
2020-10-31 23:52:48
Implement genAsm on aarch64
Add remaining PCS info: param and return registers in procedure calls.
1 parent 5ad501c
Changed files (2)
src/codegen/aarch64.zig
@@ -59,6 +59,8 @@ pub const callee_preserved_regs = [_]Register{
     .x19, .x20, .x21, .x22, .x23,
     .x24, .x25, .x26, .x27, .x28,
 };
+pub const c_abi_int_param_regs = [_]Register{ .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7 };
+pub const c_abi_int_return_regs = [_]Register{ .x0, .x1 };
 
 test "Register.id" {
     testing.expectEqual(@as(u5, 0), Register.x0.id());
@@ -215,7 +217,7 @@ pub const Instruction = union(enum) {
 
     // Supervisor Call
 
-    fn svc(imm16: u16) Instruction {
+    pub fn svc(imm16: u16) Instruction {
         return supervisorCall(imm16);
     }
 };
src/codegen.zig
@@ -2114,6 +2114,47 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                         return MCValue.none;
                     }
                 },
+                .aarch64 => {
+                    for (inst.inputs) |input, i| {
+                        if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {
+                            return self.fail(inst.base.src, "unrecognized asm input constraint: '{}'", .{input});
+                        }
+                        const reg_name = input[1 .. input.len - 1];
+                        const reg = parseRegName(reg_name) orelse
+                            return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name});
+                        const arg = try self.resolveInst(inst.args[i]);
+                        try self.genSetReg(inst.base.src, reg, arg);
+                    }
+
+                    // TODO move this to lib/std/{elf, macho}.zig, etc.
+                    const is_syscall_inst = switch (self.bin_file.tag) {
+                        .macho => mem.eql(u8, inst.asm_source, "svc #0x80"),
+                        .elf => mem.eql(u8, inst.asm_source, "svc #0"),
+                        else => |tag| return self.fail(inst.base.src, "TODO implement aarch64 support for other syscall instructions for file format: '{}'", .{tag}),
+                    };
+                    if (is_syscall_inst) {
+                        const imm16: u16 = switch (self.bin_file.tag) {
+                            .macho => 0x80,
+                            .elf => 0,
+                            else => unreachable,
+                        };
+                        mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.svc(imm16).toU32());
+                    } else {
+                        return self.fail(inst.base.src, "TODO implement support for more aarch64 assembly instructions", .{});
+                    }
+
+                    if (inst.output) |output| {
+                        if (output.len < 4 or output[0] != '=' or output[1] != '{' or output[output.len - 1] != '}') {
+                            return self.fail(inst.base.src, "unrecognized asm output constraint: '{}'", .{output});
+                        }
+                        const reg_name = output[2 .. output.len - 1];
+                        const reg = parseRegName(reg_name) orelse
+                            return self.fail(inst.base.src, "unrecognized register: '{}'", .{reg_name});
+                        return MCValue{ .register = reg };
+                    } else {
+                        return MCValue.none;
+                    }
+                },
                 .riscv64 => {
                     for (inst.inputs) |input, i| {
                         if (input.len < 3 or input[0] != '{' or input[input.len - 1] != '}') {