master
1//! Machine Intermediate Representation.
2//! This data is produced by SPARCv9 Codegen or SPARCv9 assembly parsing
3//! These instructions have a 1:1 correspondence with machine code instructions
4//! for the target. MIR can be lowered to source-annotated textual assembly code
5//! instructions, or it can be lowered to machine code.
6//! The main purpose of MIR is to postpone the assignment of offsets until Isel,
7//! so that, for example, the smaller encodings of jump instructions can be used.
8
9const std = @import("std");
10const builtin = @import("builtin");
11const assert = std.debug.assert;
12
13const Mir = @This();
14const bits = @import("bits.zig");
15const InternPool = @import("../../InternPool.zig");
16const Emit = @import("Emit.zig");
17const codegen = @import("../../codegen.zig");
18const link = @import("../../link.zig");
19const Zcu = @import("../../Zcu.zig");
20
21const Instruction = bits.Instruction;
22const ASI = bits.Instruction.ASI;
23const Register = bits.Register;
24
25instructions: std.MultiArrayList(Inst).Slice,
26
27/// The meaning of this data is determined by `Inst.Tag` value.
28extra: []const u32,
29
30pub const Inst = struct {
31 tag: Tag,
32 /// The meaning of this depends on `tag`.
33 data: Data,
34
35 pub const Tag = enum(u16) {
36 /// Pseudo-instruction: End of prologue
37 dbg_prologue_end,
38 /// Pseudo-instruction: Beginning of epilogue
39 dbg_epilogue_begin,
40 /// Pseudo-instruction: Update debug line
41 dbg_line,
42
43 // All the real instructions are ordered by their section number
44 // in The SPARC Architecture Manual, Version 9.
45
46 /// A.2 Add
47 /// This uses the arithmetic_3op field.
48 // TODO add other operations.
49 add,
50 addcc,
51
52 /// A.3 Branch on Integer Register with Prediction (BPr)
53 /// This uses the branch_predict_reg field.
54 bpr,
55
56 /// A.7 Branch on Integer Condition Codes with Prediction (BPcc)
57 /// This uses the branch_predict_int field.
58 bpcc,
59
60 /// A.8 Call and Link
61 /// This uses the branch_link field.
62 call,
63
64 /// A.24 Jump and Link
65 /// This uses the arithmetic_3op field.
66 jmpl,
67
68 /// A.27 Load Integer
69 /// This uses the arithmetic_3op field.
70 /// Note that the ldd variant of this instruction is deprecated, so do not emit
71 /// it unless specifically requested (e.g. by inline assembly).
72 // TODO add other operations.
73 ldub,
74 lduh,
75 lduw,
76 ldx,
77
78 /// A.28 Load Integer from Alternate Space
79 /// This uses the mem_asi field.
80 /// Note that the ldda variant of this instruction is deprecated, so do not emit
81 /// it unless specifically requested (e.g. by inline assembly).
82 // TODO add other operations.
83 lduba,
84 lduha,
85 lduwa,
86 ldxa,
87
88 /// A.31 Logical Operations
89 /// This uses the arithmetic_3op field.
90 // TODO add other operations.
91 @"and",
92 @"or",
93 xor,
94 xnor,
95
96 /// A.32 Memory Barrier
97 /// This uses the membar_mask field.
98 membar,
99
100 /// A.35 Move Integer Register on Condition (MOVcc)
101 /// This uses the conditional_move_int field.
102 movcc,
103
104 /// A.36 Move Integer Register on Register Condition (MOVr)
105 /// This uses the conditional_move_reg field.
106 movr,
107
108 /// A.37 Multiply and Divide (64-bit)
109 /// This uses the arithmetic_3op field.
110 mulx,
111 sdivx,
112 udivx,
113
114 /// A.40 No Operation
115 /// This uses the nop field.
116 nop,
117
118 /// A.45 RETURN
119 /// This uses the arithmetic_2op field.
120 @"return",
121
122 /// A.46 SAVE and RESTORE
123 /// This uses the arithmetic_3op field.
124 save,
125 restore,
126
127 /// A.48 SETHI
128 /// This uses the sethi field.
129 sethi,
130
131 /// A.49 Shift
132 /// This uses the shift field.
133 sll,
134 srl,
135 sra,
136 sllx,
137 srlx,
138 srax,
139
140 /// A.54 Store Integer
141 /// This uses the arithmetic_3op field.
142 /// Note that the std variant of this instruction is deprecated, so do not emit
143 /// it unless specifically requested (e.g. by inline assembly).
144 // TODO add other operations.
145 stb,
146 sth,
147 stw,
148 stx,
149
150 /// A.55 Store Integer into Alternate Space
151 /// This uses the mem_asi field.
152 /// Note that the stda variant of this instruction is deprecated, so do not emit
153 /// it unless specifically requested (e.g. by inline assembly).
154 // TODO add other operations.
155 stba,
156 stha,
157 stwa,
158 stxa,
159
160 /// A.56 Subtract
161 /// This uses the arithmetic_3op field.
162 // TODO add other operations.
163 sub,
164 subcc,
165
166 /// A.61 Trap on Integer Condition Codes (Tcc)
167 /// This uses the trap field.
168 tcc,
169
170 // SPARCv9 synthetic instructions
171 // Note that the instructions that is added here are only those that
172 // will simplify backend development. Synthetic instructions that is
173 // only used to provide syntactic sugar in, e.g. inline assembly should
174 // be deconstructed inside the parser instead.
175 // See also: G.3 Synthetic Instructions
176 // TODO add more synthetic instructions
177
178 /// Comparison
179 /// This uses the arithmetic_2op field.
180 cmp, // cmp rs1, rs2/imm -> subcc rs1, rs2/imm, %g0
181
182 /// Copy register/immediate contents to another register
183 /// This uses the arithmetic_2op field, with rs1
184 /// being the *destination* register.
185 // TODO is it okay to abuse rs1 in this way?
186 mov, // mov rs2/imm, rs1 -> or %g0, rs2/imm, rs1
187
188 /// Bitwise negation
189 /// This uses the arithmetic_2op field, with rs1
190 /// being the *destination* register.
191 // TODO is it okay to abuse rs1 in this way?
192 // not rs2, rs1 -> xnor rs2, %g0, rs1
193 // not imm, rs1 -> xnor %g0, imm, rs1
194 not,
195 };
196
197 /// The position of an MIR instruction within the `Mir` instructions array.
198 pub const Index = u32;
199
200 /// All instructions have a 8-byte payload, which is contained within
201 /// this union. `Tag` determines which union field is active, as well as
202 /// how to interpret the data within.
203 // TODO this is a quick-n-dirty solution that needs to be cleaned up.
204 pub const Data = union {
205 /// Debug info: line and column
206 ///
207 /// Used by e.g. dbg_line
208 dbg_line_column: struct {
209 line: u32,
210 column: u32,
211 },
212
213 /// Two operand arithmetic.
214 /// if is_imm true then it uses the imm field of rs2_or_imm,
215 /// otherwise it uses rs2 field.
216 ///
217 /// Used by e.g. return
218 arithmetic_2op: struct {
219 is_imm: bool,
220 rs1: Register,
221 rs2_or_imm: union {
222 rs2: Register,
223 imm: i13,
224 },
225 },
226
227 /// Three operand arithmetic.
228 /// if is_imm true then it uses the imm field of rs2_or_imm,
229 /// otherwise it uses rs2 field.
230 ///
231 /// Used by e.g. add, sub
232 arithmetic_3op: struct {
233 is_imm: bool,
234 rd: Register,
235 rs1: Register,
236 rs2_or_imm: union {
237 rs2: Register,
238 imm: i13,
239 },
240 },
241
242 /// Branch and link (always unconditional).
243 /// Used by e.g. call
244 branch_link: struct {
245 inst: Index,
246 // link is always %o7
247 },
248
249 /// Branch with prediction, checking the integer status code
250 /// Used by e.g. bpcc
251 branch_predict_int: struct {
252 annul: bool = false,
253 pt: bool = true,
254 ccr: Instruction.CCR,
255 cond: Instruction.ICondition,
256 inst: Index,
257 },
258
259 /// Branch with prediction, comparing a register's content with zero
260 /// Used by e.g. bpr
261 branch_predict_reg: struct {
262 annul: bool = false,
263 pt: bool = true,
264 cond: Instruction.RCondition,
265 rs1: Register,
266 inst: Index,
267 },
268
269 /// ASI-tagged memory operations.
270 /// Used by e.g. ldxa, stxa
271 mem_asi: struct {
272 rd: Register,
273 rs1: Register,
274 rs2: Register = .g0,
275 asi: ASI,
276 },
277
278 /// Membar mask, controls the barrier behavior
279 /// Used by e.g. membar
280 membar_mask: struct {
281 mmask: Instruction.MemOrderingConstraint = .{},
282 cmask: Instruction.MemCompletionConstraint = .{},
283 },
284
285 /// Conditional move, checking the integer status code
286 /// if is_imm true then it uses the imm field of rs2_or_imm,
287 /// otherwise it uses rs2 field.
288 ///
289 /// Used by e.g. movcc
290 conditional_move_int: struct {
291 is_imm: bool,
292 ccr: Instruction.CCR,
293 cond: Instruction.Condition,
294 rd: Register,
295 rs2_or_imm: union {
296 rs2: Register,
297 imm: i11,
298 },
299 },
300
301 /// Conditional move, comparing a register's content with zero
302 /// if is_imm true then it uses the imm field of rs2_or_imm,
303 /// otherwise it uses rs2 field.
304 ///
305 /// Used by e.g. movr
306 conditional_move_reg: struct {
307 is_imm: bool,
308 cond: Instruction.RCondition,
309 rd: Register,
310 rs1: Register,
311 rs2_or_imm: union {
312 rs2: Register,
313 imm: i10,
314 },
315 },
316
317 /// No additional data
318 ///
319 /// Used by e.g. flushw
320 nop: void,
321
322 /// SETHI operands.
323 ///
324 /// Used by sethi
325 sethi: struct {
326 rd: Register,
327 imm: u22,
328 },
329
330 /// Shift operands.
331 /// if is_imm true then it uses the imm field of rs2_or_imm,
332 /// otherwise it uses rs2 field.
333 ///
334 /// Used by e.g. sllx
335 shift: struct {
336 is_imm: bool,
337 rd: Register,
338 rs1: Register,
339 rs2_or_imm: union {
340 rs2: Register,
341 imm: u6,
342 },
343 },
344
345 /// Trap.
346 /// if is_imm true then it uses the imm field of rs2_or_imm,
347 /// otherwise it uses rs2 field.
348 ///
349 /// Used by e.g. tcc
350 trap: struct {
351 is_imm: bool = true,
352 cond: Instruction.ICondition,
353 ccr: Instruction.CCR = .icc,
354 rs1: Register = .g0,
355 rs2_or_imm: union {
356 rs2: Register,
357 imm: u7,
358 },
359 },
360 };
361
362 // Make sure we don't accidentally make instructions bigger than expected.
363 // Note that in safety builds, Zig is allowed to insert a secret field for safety checks.
364 comptime {
365 if (!std.debug.runtime_safety) {
366 assert(@sizeOf(Data) == 8);
367 }
368 }
369};
370
371pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
372 mir.instructions.deinit(gpa);
373 gpa.free(mir.extra);
374 mir.* = undefined;
375}
376
377pub fn emit(
378 mir: Mir,
379 lf: *link.File,
380 pt: Zcu.PerThread,
381 src_loc: Zcu.LazySrcLoc,
382 func_index: InternPool.Index,
383 atom_index: u32,
384 w: *std.Io.Writer,
385 debug_output: link.File.DebugInfoOutput,
386) (codegen.CodeGenError || std.Io.Writer.Error)!void {
387 _ = atom_index;
388 const zcu = pt.zcu;
389 const func = zcu.funcInfo(func_index);
390 const nav = func.owner_nav;
391 const mod = zcu.navFileScope(nav).mod.?;
392 var e: Emit = .{
393 .mir = mir,
394 .bin_file = lf,
395 .debug_output = debug_output,
396 .target = &mod.resolved_target.result,
397 .src_loc = src_loc,
398 .w = w,
399 .prev_di_pc = 0,
400 .prev_di_line = func.lbrace_line,
401 .prev_di_column = func.lbrace_column,
402 };
403 defer e.deinit();
404 e.emitMir() catch |err| switch (err) {
405 error.EmitFail => return zcu.codegenFailMsg(nav, e.err_msg.?),
406 else => |err1| return err1,
407 };
408}
409
410/// Returns the requested data, as well as the new index which is at the start of the
411/// trailers for the object.
412pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } {
413 const fields = std.meta.fields(T);
414 var i: usize = index;
415 var result: T = undefined;
416 inline for (fields) |field| {
417 @field(result, field.name) = switch (field.type) {
418 u32 => mir.extra[i],
419 i32 => @as(i32, @bitCast(mir.extra[i])),
420 else => @compileError("bad field type"),
421 };
422 i += 1;
423 }
424 return .{
425 .data = result,
426 .end = i,
427 };
428}