master
  1pub const abi = @import("aarch64/abi.zig");
  2pub const Assemble = @import("aarch64/Assemble.zig");
  3pub const Disassemble = @import("aarch64/Disassemble.zig");
  4pub const encoding = @import("aarch64/encoding.zig");
  5pub const Mir = @import("aarch64/Mir.zig");
  6pub const Select = @import("aarch64/Select.zig");
  7
  8pub fn legalizeFeatures(_: *const std.Target) ?*Air.Legalize.Features {
  9    return null;
 10}
 11
 12pub fn generate(
 13    _: *link.File,
 14    pt: Zcu.PerThread,
 15    _: Zcu.LazySrcLoc,
 16    func_index: InternPool.Index,
 17    air: *const Air,
 18    liveness: *const ?Air.Liveness,
 19) !Mir {
 20    const zcu = pt.zcu;
 21    const gpa = zcu.gpa;
 22    const ip = &zcu.intern_pool;
 23    const func = zcu.funcInfo(func_index);
 24    const func_zir = func.zir_body_inst.resolveFull(ip).?;
 25    const file = zcu.fileByIndex(func_zir.file);
 26    const named_params_len = file.zir.?.getParamBody(func_zir.inst).len;
 27    const func_type = ip.indexToKey(func.ty).func_type;
 28    assert(liveness.* == null);
 29
 30    const mod = zcu.navFileScope(func.owner_nav).mod.?;
 31    var isel: Select = .{
 32        .pt = pt,
 33        .target = &mod.resolved_target.result,
 34        .air = air.*,
 35        .nav_index = zcu.funcInfo(func_index).owner_nav,
 36
 37        .def_order = .empty,
 38        .blocks = .empty,
 39        .loops = .empty,
 40        .active_loops = .empty,
 41        .loop_live = .{
 42            .set = .empty,
 43            .list = .empty,
 44        },
 45        .dom_start = 0,
 46        .dom_len = 0,
 47        .dom = .empty,
 48
 49        .saved_registers = comptime .initEmpty(),
 50        .instructions = .empty,
 51        .literals = .empty,
 52        .nav_relocs = .empty,
 53        .uav_relocs = .empty,
 54        .lazy_relocs = .empty,
 55        .global_relocs = .empty,
 56        .literal_relocs = .empty,
 57
 58        .returns = false,
 59        .va_list = undefined,
 60        .stack_size = 0,
 61        .stack_align = .@"16",
 62
 63        .live_registers = comptime .initFill(.free),
 64        .live_values = .empty,
 65        .values = .empty,
 66    };
 67    defer isel.deinit();
 68    const is_sysv = !isel.target.os.tag.isDarwin() and isel.target.os.tag != .windows;
 69    const is_sysv_var_args = is_sysv and func_type.is_var_args;
 70
 71    const air_main_body = air.getMainBody();
 72    var param_it: Select.CallAbiIterator = .init;
 73    const air_args = for (air_main_body, 0..) |air_inst_index, body_index| {
 74        if (air.instructions.items(.tag)[@intFromEnum(air_inst_index)] != .arg) break air_main_body[0..body_index];
 75        const arg = air.instructions.items(.data)[@intFromEnum(air_inst_index)].arg;
 76        const param_ty = arg.ty.toType();
 77        const param_vi = param_vi: {
 78            if (arg.zir_param_index >= named_params_len) {
 79                assert(func_type.is_var_args);
 80                if (!is_sysv) break :param_vi try param_it.nonSysvVarArg(&isel, param_ty);
 81            }
 82            break :param_vi try param_it.param(&isel, param_ty);
 83        };
 84        tracking_log.debug("${d} <- %{d}", .{ @intFromEnum(param_vi.?), @intFromEnum(air_inst_index) });
 85        try isel.live_values.putNoClobber(gpa, air_inst_index, param_vi.?);
 86    } else unreachable;
 87
 88    const saved_gra_start = if (mod.strip) param_it.ngrn else Select.CallAbiIterator.ngrn_start;
 89    const saved_gra_end = if (is_sysv_var_args) Select.CallAbiIterator.ngrn_end else param_it.ngrn;
 90    const saved_gra_len = @intFromEnum(saved_gra_end) - @intFromEnum(saved_gra_start);
 91
 92    const saved_vra_start = if (mod.strip) param_it.nsrn else Select.CallAbiIterator.nsrn_start;
 93    const saved_vra_end = if (is_sysv_var_args) Select.CallAbiIterator.nsrn_end else param_it.nsrn;
 94    const saved_vra_len = @intFromEnum(saved_vra_end) - @intFromEnum(saved_vra_start);
 95
 96    const frame_record = 2;
 97    const named_stack_args: Select.Value.Indirect = .{
 98        .base = .fp,
 99        .offset = 8 * std.mem.alignForward(u7, frame_record + saved_gra_len, 2),
100    };
101    const stack_var_args = named_stack_args.withOffset(param_it.nsaa);
102    const gr_top = named_stack_args;
103    const vr_top: Select.Value.Indirect = .{ .base = .fp, .offset = 0 };
104    isel.va_list = if (is_sysv) .{ .sysv = .{
105        .__stack = stack_var_args,
106        .__gr_top = gr_top,
107        .__vr_top = vr_top,
108        .__gr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.ngrn_end) - @intFromEnum(param_it.ngrn)) * -8,
109        .__vr_offs = @as(i32, @intFromEnum(Select.CallAbiIterator.nsrn_end) - @intFromEnum(param_it.nsrn)) * -16,
110    } } else .{ .other = stack_var_args };
111
112    // translate arg locations from caller-based to callee-based
113    for (air_args) |air_inst_index| {
114        assert(air.instructions.items(.tag)[@intFromEnum(air_inst_index)] == .arg);
115        const arg_vi = isel.live_values.get(air_inst_index).?;
116        const passed_vi = switch (arg_vi.parent(&isel)) {
117            .unallocated, .stack_slot => arg_vi,
118            .value, .constant => unreachable,
119            .address => |address_vi| address_vi,
120        };
121        switch (passed_vi.parent(&isel)) {
122            .unallocated => if (!mod.strip) {
123                var part_it = passed_vi.parts(&isel);
124                const first_passed_part_vi = part_it.next().?;
125                const hint_ra = first_passed_part_vi.hint(&isel).?;
126                passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector())
127                    vr_top.withOffset(@as(i8, -16) * (@intFromEnum(saved_vra_end) - @intFromEnum(hint_ra)))
128                else
129                    gr_top.withOffset(@as(i8, -8) * (@intFromEnum(saved_gra_end) - @intFromEnum(hint_ra))) });
130            },
131            .stack_slot => |stack_slot| {
132                assert(stack_slot.base == .sp);
133                passed_vi.changeStackSlot(&isel, named_stack_args.withOffset(stack_slot.offset));
134            },
135            .address, .value, .constant => unreachable,
136        }
137    }
138
139    ret: {
140        var ret_it: Select.CallAbiIterator = .init;
141        const ret_vi = try ret_it.ret(&isel, .fromInterned(func_type.return_type)) orelse break :ret;
142        tracking_log.debug("${d} <- %main", .{@intFromEnum(ret_vi)});
143        try isel.live_values.putNoClobber(gpa, Select.Block.main, ret_vi);
144    }
145
146    assert(!(try isel.blocks.getOrPut(gpa, Select.Block.main)).found_existing);
147    try isel.analyze(air_main_body);
148    try isel.finishAnalysis();
149    isel.verify(false);
150
151    isel.blocks.values()[0] = .{
152        .live_registers = isel.live_registers,
153        .target_label = @intCast(isel.instructions.items.len),
154    };
155    try isel.body(air_main_body);
156    if (isel.live_values.fetchRemove(Select.Block.main)) |ret_vi| {
157        switch (ret_vi.value.parent(&isel)) {
158            .unallocated, .stack_slot => {},
159            .value, .constant => unreachable,
160            .address => |address_vi| try address_vi.liveIn(
161                &isel,
162                address_vi.hint(&isel).?,
163                comptime &.initFill(.free),
164            ),
165        }
166        ret_vi.value.deref(&isel);
167    }
168    isel.verify(true);
169
170    const prologue = isel.instructions.items.len;
171    const epilogue = try isel.layout(param_it, is_sysv_var_args, saved_gra_len, saved_vra_len, mod);
172
173    const instructions = try isel.instructions.toOwnedSlice(gpa);
174    var mir: Mir = .{
175        .prologue = instructions[prologue..epilogue],
176        .body = instructions[0..prologue],
177        .epilogue = instructions[epilogue..],
178        .literals = &.{},
179        .nav_relocs = &.{},
180        .uav_relocs = &.{},
181        .lazy_relocs = &.{},
182        .global_relocs = &.{},
183        .literal_relocs = &.{},
184    };
185    errdefer mir.deinit(gpa);
186    mir.literals = try isel.literals.toOwnedSlice(gpa);
187    mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa);
188    mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa);
189    mir.lazy_relocs = try isel.lazy_relocs.toOwnedSlice(gpa);
190    mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa);
191    mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa);
192    return mir;
193}
194
195test {
196    _ = Assemble;
197}
198
199const Air = @import("../Air.zig");
200const assert = std.debug.assert;
201const InternPool = @import("../InternPool.zig");
202const link = @import("../link.zig");
203const std = @import("std");
204const tracking_log = std.log.scoped(.tracking);
205const Zcu = @import("../Zcu.zig");