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}