master
1prologue: []const Instruction,
2body: []const Instruction,
3epilogue: []const Instruction,
4literals: []const u32,
5nav_relocs: []const Reloc.Nav,
6uav_relocs: []const Reloc.Uav,
7lazy_relocs: []const Reloc.Lazy,
8global_relocs: []const Reloc.Global,
9literal_relocs: []const Reloc.Literal,
10
11pub const Reloc = struct {
12 label: u32,
13 addend: u64 align(@alignOf(u32)) = 0,
14
15 pub const Nav = struct {
16 nav: InternPool.Nav.Index,
17 reloc: Reloc,
18 };
19
20 pub const Uav = struct {
21 uav: InternPool.Key.Ptr.BaseAddr.Uav,
22 reloc: Reloc,
23 };
24
25 pub const Lazy = struct {
26 symbol: link.File.LazySymbol,
27 reloc: Reloc,
28 };
29
30 pub const Global = struct {
31 name: [*:0]const u8,
32 reloc: Reloc,
33 };
34
35 pub const Literal = struct {
36 label: u32,
37 };
38};
39
40pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
41 assert(mir.body.ptr + mir.body.len == mir.prologue.ptr);
42 assert(mir.prologue.ptr + mir.prologue.len == mir.epilogue.ptr);
43 gpa.free(mir.body.ptr[0 .. mir.body.len + mir.prologue.len + mir.epilogue.len]);
44 gpa.free(mir.literals);
45 gpa.free(mir.nav_relocs);
46 gpa.free(mir.uav_relocs);
47 gpa.free(mir.lazy_relocs);
48 gpa.free(mir.global_relocs);
49 gpa.free(mir.literal_relocs);
50 mir.* = undefined;
51}
52
53pub fn emit(
54 mir: Mir,
55 lf: *link.File,
56 pt: Zcu.PerThread,
57 src_loc: Zcu.LazySrcLoc,
58 func_index: InternPool.Index,
59 atom_index: u32,
60 w: *std.Io.Writer,
61 debug_output: link.File.DebugInfoOutput,
62) !void {
63 _ = debug_output;
64 const zcu = pt.zcu;
65 const ip = &zcu.intern_pool;
66 const func = zcu.funcInfo(func_index);
67 const nav = ip.getNav(func.owner_nav);
68 const mod = zcu.navFileScope(func.owner_nav).mod.?;
69 const target = &mod.resolved_target.result;
70 mir_log.debug("{f}:", .{nav.fqn.fmt(ip)});
71
72 const func_align = switch (nav.status.fully_resolved.alignment) {
73 .none => switch (mod.optimize_mode) {
74 .Debug, .ReleaseSafe, .ReleaseFast => target_util.defaultFunctionAlignment(target),
75 .ReleaseSmall => target_util.minFunctionAlignment(target),
76 },
77 else => |a| a.maxStrict(target_util.minFunctionAlignment(target)),
78 };
79 const code_len = mir.prologue.len + mir.body.len + mir.epilogue.len;
80 const literals_align_gap = -%code_len & (@divExact(
81 @as(u5, @intCast(func_align.minStrict(.@"16").toByteUnits().?)),
82 Instruction.size,
83 ) - 1);
84 try w.rebase(w.end, Instruction.size * (code_len + literals_align_gap + mir.literals.len));
85 emitInstructionsForward(w, mir.prologue) catch unreachable;
86 emitInstructionsBackward(w, mir.body) catch unreachable;
87 const body_end: u32 = @intCast(w.end);
88 emitInstructionsBackward(w, mir.epilogue) catch unreachable;
89 w.splatByteAll(0, Instruction.size * literals_align_gap) catch unreachable;
90 w.writeAll(@ptrCast(mir.literals)) catch unreachable;
91 mir_log.debug("", .{});
92
93 for (mir.nav_relocs) |nav_reloc| try emitReloc(
94 lf,
95 zcu,
96 atom_index,
97 switch (try @import("../../codegen.zig").genNavRef(
98 lf,
99 pt,
100 src_loc,
101 nav_reloc.nav,
102 &mod.resolved_target.result,
103 )) {
104 .sym_index => |sym_index| sym_index,
105 .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em),
106 },
107 mir.body[nav_reloc.reloc.label],
108 body_end - Instruction.size * (1 + nav_reloc.reloc.label),
109 nav_reloc.reloc.addend,
110 if (ip.getNav(nav_reloc.nav).getExtern(ip)) |_| .got_load else .direct,
111 );
112 for (mir.uav_relocs) |uav_reloc| try emitReloc(
113 lf,
114 zcu,
115 atom_index,
116 switch (try lf.lowerUav(
117 pt,
118 uav_reloc.uav.val,
119 ZigType.fromInterned(uav_reloc.uav.orig_ty).ptrAlignment(zcu),
120 src_loc,
121 )) {
122 .sym_index => |sym_index| sym_index,
123 .fail => |em| return zcu.codegenFailMsg(func.owner_nav, em),
124 },
125 mir.body[uav_reloc.reloc.label],
126 body_end - Instruction.size * (1 + uav_reloc.reloc.label),
127 uav_reloc.reloc.addend,
128 .direct,
129 );
130 for (mir.lazy_relocs) |lazy_reloc| try emitReloc(
131 lf,
132 zcu,
133 atom_index,
134 if (lf.cast(.elf)) |ef|
135 ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|
136 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
137 else if (lf.cast(.macho)) |mf|
138 mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|
139 return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
140 else
141 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),
142 mir.body[lazy_reloc.reloc.label],
143 body_end - Instruction.size * (1 + lazy_reloc.reloc.label),
144 lazy_reloc.reloc.addend,
145 .direct,
146 );
147 for (mir.global_relocs) |global_reloc| try emitReloc(
148 lf,
149 zcu,
150 atom_index,
151 if (lf.cast(.elf)) |ef|
152 try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null)
153 else if (lf.cast(.macho)) |mf|
154 try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null)
155 else
156 return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {t}", .{lf.tag}),
157 mir.body[global_reloc.reloc.label],
158 body_end - Instruction.size * (1 + global_reloc.reloc.label),
159 global_reloc.reloc.addend,
160 .direct,
161 );
162 const literal_reloc_offset: i19 = @intCast(mir.epilogue.len + literals_align_gap);
163 for (mir.literal_relocs) |literal_reloc| {
164 var instruction = mir.body[literal_reloc.label];
165 instruction.load_store.register_literal.group.imm19 += literal_reloc_offset;
166 instruction.write(
167 w.buffered()[body_end - Instruction.size * (1 + literal_reloc.label) ..][0..Instruction.size],
168 );
169 }
170}
171
172fn emitInstructionsForward(w: *std.Io.Writer, instructions: []const Instruction) !void {
173 for (instructions) |instruction| try emitInstruction(w, instruction);
174}
175fn emitInstructionsBackward(w: *std.Io.Writer, instructions: []const Instruction) !void {
176 var instruction_index = instructions.len;
177 while (instruction_index > 0) {
178 instruction_index -= 1;
179 try emitInstruction(w, instructions[instruction_index]);
180 }
181}
182fn emitInstruction(w: *std.Io.Writer, instruction: Instruction) !void {
183 mir_log.debug(" {f}", .{instruction});
184 instruction.write(try w.writableArray(Instruction.size));
185}
186
187fn emitReloc(
188 lf: *link.File,
189 zcu: *Zcu,
190 atom_index: u32,
191 sym_index: u32,
192 instruction: Instruction,
193 offset: u32,
194 addend: u64,
195 kind: enum { direct, got_load },
196) !void {
197 const gpa = zcu.gpa;
198 switch (instruction.decode()) {
199 else => unreachable,
200 .data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
201 const zo = ef.zigObjectPtr().?;
202 const atom = zo.symbol(atom_index).atom(ef).?;
203 const r_type: std.elf.R_AARCH64 = switch (decoded.decode()) {
204 else => unreachable,
205 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
206 .adr => switch (kind) {
207 .direct => .ADR_PREL_LO21,
208 .got_load => unreachable,
209 },
210 .adrp => switch (kind) {
211 .direct => .ADR_PREL_PG_HI21,
212 .got_load => .ADR_GOT_PAGE,
213 },
214 },
215 .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) {
216 .add => switch (kind) {
217 .direct => .ADD_ABS_LO12_NC,
218 .got_load => unreachable,
219 },
220 .sub => unreachable,
221 },
222 };
223 try atom.addReloc(gpa, .{
224 .r_offset = offset,
225 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
226 .r_addend = @bitCast(addend),
227 }, zo);
228 } else if (lf.cast(.macho)) |mf| {
229 const zo = mf.getZigObject().?;
230 const atom = zo.symbols.items[atom_index].getAtom(mf).?;
231 switch (decoded.decode()) {
232 else => unreachable,
233 .pc_relative_addressing => |pc_relative_addressing| switch (pc_relative_addressing.group.op) {
234 .adr => unreachable,
235 .adrp => try atom.addReloc(mf, .{
236 .tag = .@"extern",
237 .offset = offset,
238 .target = sym_index,
239 .addend = @bitCast(addend),
240 .type = switch (kind) {
241 .direct => .page,
242 .got_load => .got_load_page,
243 },
244 .meta = .{
245 .pcrel = true,
246 .has_subtractor = false,
247 .length = 2,
248 .symbolnum = @intCast(sym_index),
249 },
250 }),
251 },
252 .add_subtract_immediate => |add_subtract_immediate| switch (add_subtract_immediate.group.op) {
253 .add => try atom.addReloc(mf, .{
254 .tag = .@"extern",
255 .offset = offset,
256 .target = sym_index,
257 .addend = @bitCast(addend),
258 .type = switch (kind) {
259 .direct => .pageoff,
260 .got_load => .got_load_pageoff,
261 },
262 .meta = .{
263 .pcrel = false,
264 .has_subtractor = false,
265 .length = 2,
266 .symbolnum = @intCast(sym_index),
267 },
268 }),
269 .sub => unreachable,
270 },
271 }
272 },
273 .branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
274 const zo = ef.zigObjectPtr().?;
275 const atom = zo.symbol(atom_index).atom(ef).?;
276 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
277 .b => .JUMP26,
278 .bl => .CALL26,
279 };
280 try atom.addReloc(gpa, .{
281 .r_offset = offset,
282 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
283 .r_addend = @bitCast(addend),
284 }, zo);
285 } else if (lf.cast(.macho)) |mf| {
286 const zo = mf.getZigObject().?;
287 const atom = zo.symbols.items[atom_index].getAtom(mf).?;
288 try atom.addReloc(mf, .{
289 .tag = .@"extern",
290 .offset = offset,
291 .target = sym_index,
292 .addend = @bitCast(addend),
293 .type = .branch,
294 .meta = .{
295 .pcrel = true,
296 .has_subtractor = false,
297 .length = 2,
298 .symbolnum = @intCast(sym_index),
299 },
300 });
301 },
302 .load_store => |decoded| if (lf.cast(.elf)) |ef| {
303 const zo = ef.zigObjectPtr().?;
304 const atom = zo.symbol(atom_index).atom(ef).?;
305 const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {
306 .integer => |integer| switch (integer.decode()) {
307 .unallocated, .prfm => unreachable,
308 .strb, .ldrb, .ldrsb => switch (kind) {
309 .direct => .LDST8_ABS_LO12_NC,
310 .got_load => unreachable,
311 },
312 .strh, .ldrh, .ldrsh => switch (kind) {
313 .direct => .LDST16_ABS_LO12_NC,
314 .got_load => unreachable,
315 },
316 .ldrsw => switch (kind) {
317 .direct => .LDST32_ABS_LO12_NC,
318 .got_load => unreachable,
319 },
320 inline .str, .ldr => |encoded, mnemonic| switch (encoded.sf) {
321 .word => .LDST32_ABS_LO12_NC,
322 .doubleword => switch (kind) {
323 .direct => .LDST64_ABS_LO12_NC,
324 .got_load => switch (mnemonic) {
325 else => comptime unreachable,
326 .str => unreachable,
327 .ldr => .LD64_GOT_LO12_NC,
328 },
329 },
330 },
331 },
332 .vector => |vector| switch (kind) {
333 .direct => switch (vector.group.opc1.decode(vector.group.size)) {
334 .byte => .LDST8_ABS_LO12_NC,
335 .half => .LDST16_ABS_LO12_NC,
336 .single => .LDST32_ABS_LO12_NC,
337 .double => .LDST64_ABS_LO12_NC,
338 .quad => .LDST128_ABS_LO12_NC,
339 },
340 .got_load => unreachable,
341 },
342 };
343 try atom.addReloc(gpa, .{
344 .r_offset = offset,
345 .r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
346 .r_addend = @bitCast(addend),
347 }, zo);
348 } else if (lf.cast(.macho)) |mf| {
349 const zo = mf.getZigObject().?;
350 const atom = zo.symbols.items[atom_index].getAtom(mf).?;
351 try atom.addReloc(mf, .{
352 .tag = .@"extern",
353 .offset = offset,
354 .target = sym_index,
355 .addend = @bitCast(addend),
356 .type = switch (kind) {
357 .direct => .pageoff,
358 .got_load => .got_load_pageoff,
359 },
360 .meta = .{
361 .pcrel = false,
362 .has_subtractor = false,
363 .length = 2,
364 .symbolnum = @intCast(sym_index),
365 },
366 });
367 },
368 }
369}
370
371const Air = @import("../../Air.zig");
372const assert = std.debug.assert;
373const mir_log = std.log.scoped(.mir);
374const Instruction = @import("encoding.zig").Instruction;
375const InternPool = @import("../../InternPool.zig");
376const link = @import("../../link.zig");
377const Mir = @This();
378const std = @import("std");
379const target_util = @import("../../target.zig");
380const Zcu = @import("../../Zcu.zig");
381const ZigType = @import("../../Type.zig");