1const Mir = @This();
2const Instruction = @import("encoding.zig").Instruction;
3const Disassemble = @import("Disassemble.zig");
4
5prologue: []const Instruction,
6body: []const Instruction,
7epilogue: []const Instruction,
8nav_relocs: []const Reloc.Nav,
9uav_relocs: []const Reloc.Uav,
10lazy_relocs: []const Reloc.Lazy,
11global_relocs: []const Reloc.Global,
12internal_relocs: []const Reloc.Internal,
13
14pub const Reloc = struct {
15 label: u32,
16 type: std.elf.R_LARCH,
17 addend: i64 = 0,
18
19 pub const Nav = struct {
20 nav: InternPool.Nav.Index,
21 reloc: Reloc,
22 };
23
24 pub const Uav = struct {
25 uav: InternPool.Key.Ptr.BaseAddr.Uav,
26 reloc: Reloc,
27 };
28
29 pub const Lazy = struct {
30 symbol: link.File.LazySymbol,
31 reloc: Reloc,
32 };
33
34 pub const Global = struct {
35 name: [*:0]const u8,
36 reloc: Reloc,
37 };
38
39 pub const Internal = struct {
40 // Target MIR index
41 target: usize = 0,
42 reloc: Reloc,
43 };
44};
45
46pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
47 assert(mir.body.ptr + mir.body.len == mir.prologue.ptr);
48 assert(mir.prologue.ptr + mir.prologue.len == mir.epilogue.ptr);
49 gpa.free(mir.body.ptr[0 .. mir.body.len + mir.prologue.len + mir.epilogue.len]);
50 gpa.free(mir.nav_relocs);
51 gpa.free(mir.uav_relocs);
52 gpa.free(mir.lazy_relocs);
53 gpa.free(mir.global_relocs);
54 gpa.free(mir.internal_relocs);
55 mir.* = undefined;
56}
57
58pub fn emit(
59 mir: Mir,
60 lf: *link.File,
61 pt: Zcu.PerThread,
62 func_index: InternPool.Index,
63 atom_index: link.File.AtomId,
64 w: *std.Io.Writer,
65 debug_output: link.File.DebugInfoOutput,
66) !void {
67 _ = debug_output;
68 const zcu = pt.zcu;
69 const ip = &zcu.intern_pool;
70 const func = zcu.funcInfo(func_index);
71 const nav = ip.getNav(func.owner_nav);
72 mir_log.debug("{f}:", .{nav.fqn.fmt(ip)});
73
74 const code_len = mir.prologue.len + mir.body.len + mir.epilogue.len;
75 try w.rebase(w.end, @sizeOf(Instruction) * code_len);
76 emitInstructionsBackward(w, mir.prologue) catch unreachable;
77 emitInstructionsBackward(w, mir.body) catch unreachable;
78 const body_end: u32 = @intCast(w.end);
79 emitInstructionsBackward(w, mir.epilogue) catch unreachable;
80 mir_log.debug("", .{});
81
82 for (mir.nav_relocs) |nav_reloc| emitReloc(
83 lf,
84 zcu,
85 atom_index,
86 try @import("../../codegen.zig").genNavRef(
87 lf,
88 pt,
89 nav_reloc.nav,
90 ),
91 nav_reloc.reloc.type,
92 body_end - @sizeOf(Instruction) * (1 + nav_reloc.reloc.label),
93 nav_reloc.reloc.addend,
94 ) catch |err|
95 return zcu.codegenFail(func.owner_nav, "emit reloc failed: {t}", .{err});
96 for (mir.uav_relocs) |uav_reloc| emitReloc(
97 lf,
98 zcu,
99 atom_index,
100 try lf.lowerUav(
101 pt,
102 uav_reloc.uav.val,
103 ZigType.fromInterned(uav_reloc.uav.orig_ty).ptrAlignment(zcu),
104 ),
105 uav_reloc.reloc.type,
106 body_end - @sizeOf(Instruction) * (1 + uav_reloc.reloc.label),
107 uav_reloc.reloc.addend,
108 ) catch |err|
109 return zcu.codegenFail(func.owner_nav, "emit reloc failed: {t}", .{err});
110 for (mir.lazy_relocs) |lazy_reloc| emitReloc(
111 lf,
112 zcu,
113 atom_index,
114 if (lf.cast(.elf)) |ef|
115 @fromBackingInt(ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|
116 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)}))
117 else if (lf.cast(.elf2)) |elf|
118 elf.lazySymbol(lazy_reloc.symbol) catch |err|
119 return zcu.codegenFail(func.owner_nav, "emit lazy symbol: {t}", .{err})
120 else
121 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
122 lazy_reloc.reloc.type,
123 body_end - @sizeOf(Instruction) * (1 + lazy_reloc.reloc.label),
124 lazy_reloc.reloc.addend,
125 ) catch |err|
126 return zcu.codegenFail(func.owner_nav, "emit reloc failed: {t}", .{err});
127 for (mir.global_relocs) |global_reloc| emitReloc(
128 lf,
129 zcu,
130 atom_index,
131 if (lf.cast(.elf)) |ef|
132 @fromBackingInt(try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null))
133 else if (lf.cast(.elf2)) |elf| elf.externSymbol(.{
134 .name = std.mem.span(global_reloc.name),
135 .lib_name = null,
136 .type = .FUNC,
137 }) catch |err|
138 return zcu.codegenFail(func.owner_nav, "emit global symbol failed: {t}", .{err}) else return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
139 global_reloc.reloc.type,
140 body_end - @sizeOf(Instruction) * (1 + global_reloc.reloc.label),
141 global_reloc.reloc.addend,
142 ) catch |err|
143 return zcu.codegenFail(func.owner_nav, "emit reloc failed: {t}", .{err});
144
145 const func_nav = try @import("../../codegen.zig").genNavRef(
146 lf,
147 pt,
148 func.owner_nav,
149 );
150 for (mir.internal_relocs) |internal_reloc| emitReloc(
151 lf,
152 zcu,
153 atom_index,
154 func_nav,
155 internal_reloc.reloc.type,
156 body_end - @sizeOf(Instruction) * (1 + internal_reloc.reloc.label),
157 @sizeOf(Instruction) * (@as(i64, @intCast(mir.prologue.len + mir.body.len - internal_reloc.target))),
158 ) catch |err|
159 return zcu.codegenFail(func.owner_nav, "emit reloc failed: {t}", .{err});
160}
161
162fn emitInstructionsForward(w: *std.Io.Writer, instructions: []const Instruction) !void {
163 for (instructions) |instruction| try emitInstruction(w, instruction);
164}
165fn emitInstructionsBackward(w: *std.Io.Writer, instructions: []const Instruction) !void {
166 var instruction_index = instructions.len;
167 while (instruction_index > 0) {
168 instruction_index -= 1;
169 try emitInstruction(w, instructions[instruction_index]);
170 }
171}
172fn emitInstruction(w: *std.Io.Writer, instruction: Instruction) !void {
173 mir_log.debug(" {f}", .{(Disassemble{}).fmtInstruction(instruction)});
174 try w.writeInt(@FieldType(Instruction, "word"), instruction.word, .little);
175}
176
177fn emitReloc(
178 lf: *link.File,
179 zcu: *Zcu,
180 atom_index: link.File.AtomId,
181 sym_index: link.File.SymbolId,
182 reloc_type: std.elf.R_LARCH,
183 offset: u32,
184 addend: i64,
185) !void {
186 if (lf.cast(.elf2)) |ef| {
187 try ef.addReloc(atom_index, offset, sym_index, addend, .{ .LARCH = reloc_type });
188 } else if (lf.cast(.elf)) |ef| {
189 const zo = ef.zigObjectPtr().?;
190 const atom = zo.symbol(@backingInt(atom_index)).atom(ef).?;
191 try atom.addReloc(zcu.gpa, .{
192 .r_offset = offset,
193 .r_info = @as(u64, @backingInt(sym_index)) << 32 | @backingInt(reloc_type),
194 .r_addend = @bitCast(addend),
195 }, zo);
196 } else unreachable;
197}
198
199const Air = @import("../../Air.zig");
200const assert = std.debug.assert;
201const mir_log = std.log.scoped(.mir);
202const InternPool = @import("../../InternPool.zig");
203const link = @import("../../link.zig");
204const std = @import("std");
205const target_util = @import("../../target.zig");
206const Zcu = @import("../../Zcu.zig");
207const ZigType = @import("../../Type.zig");