mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
275 lines
10 KiB
Zig
275 lines
10 KiB
Zig
prologue: []const Instruction,
|
|
body: []const Instruction,
|
|
epilogue: []const Instruction,
|
|
literals: []const u32,
|
|
nav_relocs: []const Reloc.Nav,
|
|
uav_relocs: []const Reloc.Uav,
|
|
global_relocs: []const Reloc.Global,
|
|
literal_relocs: []const Reloc.Literal,
|
|
|
|
pub const Reloc = struct {
|
|
label: u32,
|
|
addend: u64 align(@alignOf(u32)) = 0,
|
|
|
|
pub const Nav = struct {
|
|
nav: InternPool.Nav.Index,
|
|
reloc: Reloc,
|
|
};
|
|
|
|
pub const Uav = struct {
|
|
uav: InternPool.Key.Ptr.BaseAddr.Uav,
|
|
reloc: Reloc,
|
|
};
|
|
|
|
pub const Global = struct {
|
|
global: [*:0]const u8,
|
|
reloc: Reloc,
|
|
};
|
|
|
|
pub const Literal = struct {
|
|
label: u32,
|
|
};
|
|
};
|
|
|
|
pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
|
|
assert(mir.body.ptr + mir.body.len == mir.prologue.ptr);
|
|
assert(mir.prologue.ptr + mir.prologue.len == mir.epilogue.ptr);
|
|
gpa.free(mir.body.ptr[0 .. mir.body.len + mir.prologue.len + mir.epilogue.len]);
|
|
gpa.free(mir.literals);
|
|
gpa.free(mir.nav_relocs);
|
|
gpa.free(mir.uav_relocs);
|
|
gpa.free(mir.global_relocs);
|
|
gpa.free(mir.literal_relocs);
|
|
mir.* = undefined;
|
|
}
|
|
|
|
pub fn emit(
|
|
mir: Mir,
|
|
lf: *link.File,
|
|
pt: Zcu.PerThread,
|
|
src_loc: Zcu.LazySrcLoc,
|
|
func_index: InternPool.Index,
|
|
code: *std.ArrayListUnmanaged(u8),
|
|
debug_output: link.File.DebugInfoOutput,
|
|
) !void {
|
|
_ = debug_output;
|
|
const zcu = pt.zcu;
|
|
const ip = &zcu.intern_pool;
|
|
const gpa = zcu.gpa;
|
|
const func = zcu.funcInfo(func_index);
|
|
const nav = ip.getNav(func.owner_nav);
|
|
const mod = zcu.navFileScope(func.owner_nav).mod.?;
|
|
const target = &mod.resolved_target.result;
|
|
mir_log.debug("{f}:", .{nav.fqn.fmt(ip)});
|
|
|
|
const func_align = switch (nav.status.fully_resolved.alignment) {
|
|
.none => switch (mod.optimize_mode) {
|
|
.Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
|
|
.ReleaseSmall => target_util.minFunctionAlignment(target),
|
|
},
|
|
else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
|
|
};
|
|
const code_len = mir.prologue.len + mir.body.len + mir.epilogue.len;
|
|
const literals_align_gap = -%code_len & (@divExact(
|
|
@as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)),
|
|
Instruction.size,
|
|
) - 1);
|
|
try code.ensureUnusedCapacity(gpa, Instruction.size *
|
|
(code_len + literals_align_gap + mir.literals.len));
|
|
emitInstructionsForward(code, mir.prologue);
|
|
emitInstructionsBackward(code, mir.body);
|
|
const body_end: u32 = @intCast(code.items.len);
|
|
emitInstructionsBackward(code, mir.epilogue);
|
|
code.appendNTimesAssumeCapacity(0, Instruction.size * literals_align_gap);
|
|
code.appendSliceAssumeCapacity(@ptrCast(mir.literals));
|
|
mir_log.debug("", .{});
|
|
|
|
for (mir.nav_relocs) |nav_reloc| try emitReloc(
|
|
lf,
|
|
zcu,
|
|
func.owner_nav,
|
|
switch (try @import("../../codegen.zig").genNavRef(
|
|
lf,
|
|
pt,
|
|
src_loc,
|
|
nav_reloc.nav,
|
|
&mod.resolved_target.result,
|
|
)) {
|
|
.sym_index => |sym_index| sym_index,
|
|
.fail => |em| return zcu.codegenFailMsg(func.owner_nav, em),
|
|
},
|
|
mir.body[nav_reloc.reloc.label],
|
|
body_end - Instruction.size * (1 + nav_reloc.reloc.label),
|
|
nav_reloc.reloc.addend,
|
|
);
|
|
for (mir.uav_relocs) |uav_reloc| try emitReloc(
|
|
lf,
|
|
zcu,
|
|
func.owner_nav,
|
|
switch (try lf.lowerUav(
|
|
pt,
|
|
uav_reloc.uav.val,
|
|
ZigType.fromInterned(uav_reloc.uav.orig_ty).ptrAlignment(zcu),
|
|
src_loc,
|
|
)) {
|
|
.sym_index => |sym_index| sym_index,
|
|
.fail => |em| return zcu.codegenFailMsg(func.owner_nav, em),
|
|
},
|
|
mir.body[uav_reloc.reloc.label],
|
|
body_end - Instruction.size * (1 + uav_reloc.reloc.label),
|
|
uav_reloc.reloc.addend,
|
|
);
|
|
for (mir.global_relocs) |global_reloc| try emitReloc(
|
|
lf,
|
|
zcu,
|
|
func.owner_nav,
|
|
if (lf.cast(.elf)) |ef|
|
|
try ef.getGlobalSymbol(std.mem.span(global_reloc.global), null)
|
|
else if (lf.cast(.macho)) |mf|
|
|
try mf.getGlobalSymbol(std.mem.span(global_reloc.global), null)
|
|
else if (lf.cast(.coff)) |cf|
|
|
try cf.getGlobalSymbol(std.mem.span(global_reloc.global), "compiler_rt")
|
|
else
|
|
return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
|
|
mir.body[global_reloc.reloc.label],
|
|
body_end - Instruction.size * (1 + global_reloc.reloc.label),
|
|
global_reloc.reloc.addend,
|
|
);
|
|
const literal_reloc_offset: i19 = @intCast(mir.epilogue.len + literals_align_gap);
|
|
for (mir.literal_relocs) |literal_reloc| {
|
|
var instruction = mir.body[literal_reloc.label];
|
|
instruction.load_store.register_literal.group.imm19 += literal_reloc_offset;
|
|
instruction.write(
|
|
code.items[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size],
|
|
);
|
|
}
|
|
}
|
|
|
|
fn emitInstructionsForward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void {
|
|
for (instructions) |instruction| emitInstruction(code, instruction);
|
|
}
|
|
fn emitInstructionsBackward(code: *std.ArrayListUnmanaged(u8), instructions: []const Instruction) void {
|
|
var instruction_index = instructions.len;
|
|
while (instruction_index > 0) {
|
|
instruction_index -= 1;
|
|
emitInstruction(code, instructions[instruction_index]);
|
|
}
|
|
}
|
|
fn emitInstruction(code: *std.ArrayListUnmanaged(u8), instruction: Instruction) void {
|
|
mir_log.debug(" {f}", .{instruction});
|
|
instruction.write(code.addManyAsArrayAssumeCapacity(Instruction.size));
|
|
}
|
|
|
|
fn emitReloc(
|
|
lf: *link.File,
|
|
zcu: *Zcu,
|
|
owner_nav: InternPool.Nav.Index,
|
|
sym_index: u32,
|
|
instruction: Instruction,
|
|
offset: u32,
|
|
addend: u64,
|
|
) !void {
|
|
const gpa = zcu.gpa;
|
|
switch (instruction.decode()) {
|
|
else => unreachable,
|
|
.branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
|
|
const zo = ef.zigObjectPtr().?;
|
|
const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
|
|
const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
|
|
.b => .JUMP26,
|
|
.bl => .CALL26,
|
|
};
|
|
try atom.addReloc(gpa, .{
|
|
.r_offset = offset,
|
|
.r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
|
|
.r_addend = @bitCast(addend),
|
|
}, zo);
|
|
} else if (lf.cast(.macho)) |mf| {
|
|
const zo = mf.getZigObject().?;
|
|
const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
|
|
try atom.addReloc(mf, .{
|
|
.tag = .@"extern",
|
|
.offset = offset,
|
|
.target = sym_index,
|
|
.addend = @bitCast(addend),
|
|
.type = .branch,
|
|
.meta = .{
|
|
.pcrel = true,
|
|
.has_subtractor = false,
|
|
.length = 2,
|
|
.symbolnum = @intCast(sym_index),
|
|
},
|
|
});
|
|
},
|
|
.data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
|
|
const zo = ef.zigObjectPtr().?;
|
|
const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
|
|
const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {
|
|
else => unreachable,
|
|
.pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
|
|
.adr => .ADR_PREL_LO21,
|
|
.adrp => .ADR_PREL_PG_HI21,
|
|
},
|
|
.add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) {
|
|
.add => .ADD_ABS_LO12_NC,
|
|
.sub => unreachable,
|
|
},
|
|
};
|
|
try atom.addReloc(gpa, .{
|
|
.r_offset = offset,
|
|
.r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
|
|
.r_addend = @bitCast(addend),
|
|
}, zo);
|
|
} else if (lf.cast(.macho)) |mf| {
|
|
const zo = mf.getZigObject().?;
|
|
const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
|
|
switch (decoded.decode()) {
|
|
else => unreachable,
|
|
.pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
|
|
.adr => unreachable,
|
|
.adrp => try atom.addReloc(mf, .{
|
|
.tag = .@"extern",
|
|
.offset = offset,
|
|
.target = sym_index,
|
|
.addend = @bitCast(addend),
|
|
.type = .page,
|
|
.meta = .{
|
|
.pcrel = true,
|
|
.has_subtractor = false,
|
|
.length = 2,
|
|
.symbolnum = @intCast(sym_index),
|
|
},
|
|
}),
|
|
},
|
|
.add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) {
|
|
.add => try atom.addReloc(mf, .{
|
|
.tag = .@"extern",
|
|
.offset = offset,
|
|
.target = sym_index,
|
|
.addend = @bitCast(addend),
|
|
.type = .pageoff,
|
|
.meta = .{
|
|
.pcrel = false,
|
|
.has_subtractor = false,
|
|
.length = 2,
|
|
.symbolnum = @intCast(sym_index),
|
|
},
|
|
}),
|
|
.sub => unreachable,
|
|
},
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
const Air = @import("../../Air.zig");
|
|
const assert = std.debug.assert;
|
|
const mir_log = std.log.scoped(.mir);
|
|
const Instruction = @import("encoding.zig").Instruction;
|
|
const InternPool = @import("../../InternPool.zig");
|
|
const link = @import("../../link.zig");
|
|
const Mir = @This();
|
|
const std = @import("std");
|
|
const target_util = @import("../../target.zig");
|
|
const Zcu = @import("../../Zcu.zig");
|
|
const ZigType = @import("../../Type.zig");
|