aboutsummaryrefslogtreecommitdiff
path: root/src/arch/aarch64/abi.zig
blob: f26a9a8a8a477dbf67972c72cbd5635fe178ac2c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
const std = @import("std");
const builtin = @import("builtin");
const bits = @import("bits.zig");
const Register = bits.Register;
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
const Type = @import("../../type.zig").Type;

pub const Class = enum { memory, integer, none, float_array };

pub fn classifyType(ty: Type, target: std.Target) [2]Class {
    if (!ty.hasRuntimeBitsIgnoreComptime()) return .{ .none, .none };
    switch (ty.zigTypeTag()) {
        .Struct => {
            if (ty.containerLayout() == .Packed) return .{ .integer, .none };

            if (ty.structFieldCount() <= 4) {
                const fields = ty.structFields();
                var float_size: ?u64 = null;
                for (fields.values()) |field| {
                    if (field.ty.zigTypeTag() != .Float) break;
                    const field_size = field.ty.bitSize(target);
                    const prev_size = float_size orelse {
                        float_size = field_size;
                        continue;
                    };
                    if (field_size != prev_size) break;
                } else {
                    return .{ .float_array, .none };
                }
            }
            const bit_size = ty.bitSize(target);
            if (bit_size > 128) return .{ .memory, .none };
            if (bit_size > 64) return .{ .integer, .integer };
            return .{ .integer, .none };
        },
        .Union => {
            const bit_size = ty.bitSize(target);
            if (bit_size > 128) return .{ .memory, .none };
            if (bit_size > 64) return .{ .integer, .integer };
            return .{ .integer, .none };
        },
        .Int, .Enum, .ErrorSet, .Vector, .Float, .Bool => return .{ .integer, .none },
        .Array => return .{ .memory, .none },
        .Optional => {
            std.debug.assert(ty.isPtrLikeOptional());
            return .{ .integer, .none };
        },
        .Pointer => {
            std.debug.assert(!ty.isSlice());
            return .{ .integer, .none };
        },
        .ErrorUnion,
        .Frame,
        .AnyFrame,
        .NoReturn,
        .Void,
        .Type,
        .ComptimeFloat,
        .ComptimeInt,
        .Undefined,
        .Null,
        .BoundFn,
        .Fn,
        .Opaque,
        .EnumLiteral,
        => unreachable,
    }
}

const callee_preserved_regs_impl = if (builtin.os.tag.isDarwin()) struct {
    pub const callee_preserved_regs = [_]Register{
        .x20, .x21, .x22, .x23,
        .x24, .x25, .x26, .x27,
        .x28,
    };
} else struct {
    pub const callee_preserved_regs = [_]Register{
        .x19, .x20, .x21, .x22, .x23,
        .x24, .x25, .x26, .x27, .x28,
    };
};
pub const callee_preserved_regs = callee_preserved_regs_impl.callee_preserved_regs;

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, .x2, .x3, .x4, .x5, .x6, .x7 };

const allocatable_registers = callee_preserved_regs;
pub const RegisterManager = RegisterManagerFn(@import("CodeGen.zig"), Register, &allocatable_registers);

// Register classes
const RegisterBitSet = RegisterManager.RegisterBitSet;
pub const RegisterClass = struct {
    pub const gp: RegisterBitSet = blk: {
        var set = RegisterBitSet.initEmpty();
        set.setRangeValue(.{
            .start = 0,
            .end = callee_preserved_regs.len,
        }, true);
        break :blk set;
    };
};