master
  1//! Machine Intermediate Representation.
  2//! This data is produced by CodeGen.zig
  3
  4instructions: std.MultiArrayList(Inst).Slice,
  5frame_locs: std.MultiArrayList(FrameLoc).Slice,
  6
  7pub const Inst = struct {
  8    tag: Mnemonic,
  9    data: Data,
 10
 11    pub const Index = u32;
 12
 13    pub const Data = union(enum) {
 14        none: void,
 15        r_type: struct {
 16            rd: Register,
 17            rs1: Register,
 18            rs2: Register,
 19        },
 20        i_type: struct {
 21            rd: Register,
 22            rs1: Register,
 23            imm12: Immediate,
 24        },
 25        s_type: struct {
 26            rs1: Register,
 27            rs2: Register,
 28            imm5: Immediate,
 29            imm7: Immediate,
 30        },
 31        b_type: struct {
 32            rs1: Register,
 33            rs2: Register,
 34            inst: Inst.Index,
 35        },
 36        u_type: struct {
 37            rd: Register,
 38            imm20: Immediate,
 39        },
 40        j_type: struct {
 41            rd: Register,
 42            inst: Inst.Index,
 43        },
 44        rm: struct {
 45            r: Register,
 46            m: Memory,
 47        },
 48        reg_list: Mir.RegisterList,
 49        reg: Register,
 50        rr: struct {
 51            rd: Register,
 52            rs: Register,
 53        },
 54        compare: struct {
 55            rd: Register,
 56            rs1: Register,
 57            rs2: Register,
 58            op: enum {
 59                eq,
 60                neq,
 61                gt,
 62                gte,
 63                lt,
 64                lte,
 65            },
 66            ty: Type,
 67        },
 68        reloc: struct {
 69            register: Register,
 70            atom_index: u32,
 71            sym_index: u32,
 72        },
 73        fence: struct {
 74            pred: Barrier,
 75            succ: Barrier,
 76        },
 77        amo: struct {
 78            rd: Register,
 79            rs1: Register,
 80            rs2: Register,
 81            aq: Barrier,
 82            rl: Barrier,
 83        },
 84        csr: struct {
 85            csr: CSR,
 86            rs1: Register,
 87            rd: Register,
 88        },
 89        pseudo_dbg_line_column: struct {
 90            line: u32,
 91            column: u32,
 92        },
 93    };
 94
 95    pub fn format(inst: Inst, writer: *std.Io.Writer) std.Io.Writer.Error!void {
 96        try writer.print("Tag: {s}, Data: {s}", .{ @tagName(inst.tag), @tagName(inst.data) });
 97    }
 98};
 99
100pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
101    mir.instructions.deinit(gpa);
102    mir.frame_locs.deinit(gpa);
103    mir.* = undefined;
104}
105
106pub fn emit(
107    mir: Mir,
108    lf: *link.File,
109    pt: Zcu.PerThread,
110    src_loc: Zcu.LazySrcLoc,
111    func_index: InternPool.Index,
112    atom_index: u32,
113    w: *std.Io.Writer,
114    debug_output: link.File.DebugInfoOutput,
115) (codegen.CodeGenError || std.Io.Writer.Error)!void {
116    _ = atom_index;
117    const zcu = pt.zcu;
118    const comp = zcu.comp;
119    const gpa = comp.gpa;
120    const func = zcu.funcInfo(func_index);
121    const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?;
122    const nav = func.owner_nav;
123    const mod = zcu.navFileScope(nav).mod.?;
124    var e: Emit = .{
125        .lower = .{
126            .pt = pt,
127            .allocator = gpa,
128            .mir = mir,
129            .cc = fn_info.cc,
130            .src_loc = src_loc,
131            .output_mode = comp.config.output_mode,
132            .link_mode = comp.config.link_mode,
133            .pic = mod.pic,
134        },
135        .bin_file = lf,
136        .debug_output = debug_output,
137        .w = w,
138        .prev_di_pc = 0,
139        .prev_di_line = func.lbrace_line,
140        .prev_di_column = func.lbrace_column,
141    };
142    defer e.deinit();
143    e.emitMir() catch |err| switch (err) {
144        error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?),
145        error.InvalidInstruction => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
146        else => |err1| return err1,
147    };
148}
149
150pub const FrameLoc = struct {
151    base: Register,
152    disp: i32,
153};
154
155pub const Barrier = enum(u4) {
156    // Fence
157    w = 0b0001,
158    r = 0b0010,
159    rw = 0b0011,
160
161    // Amo
162    none,
163    aq,
164    rl,
165};
166
167pub const AmoOp = enum(u5) {
168    SWAP,
169    ADD,
170    AND,
171    OR,
172    XOR,
173    MAX,
174    MIN,
175};
176
177pub const FcvtOp = enum(u5) {
178    w = 0b00000,
179    wu = 0b00001,
180    l = 0b00010,
181    lu = 0b00011,
182};
183
184pub const LoadSymbolPayload = struct {
185    register: u32,
186    atom_index: u32,
187    sym_index: u32,
188};
189
190/// Used in conjunction with payload to transfer a list of used registers in a compact manner.
191pub const RegisterList = struct {
192    bitset: BitSet = BitSet.initEmpty(),
193
194    const BitSet = IntegerBitSet(32);
195    const Self = @This();
196
197    fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt {
198        for (registers, 0..) |cpreg, i| {
199            if (reg.id() == cpreg.id()) return @intCast(i);
200        }
201        unreachable; // register not in input register list!
202    }
203
204    pub fn push(self: *Self, registers: []const Register, reg: Register) void {
205        const index = getIndexForReg(registers, reg);
206        self.bitset.set(index);
207    }
208
209    pub fn isSet(self: Self, registers: []const Register, reg: Register) bool {
210        const index = getIndexForReg(registers, reg);
211        return self.bitset.isSet(index);
212    }
213
214    pub fn iterator(self: Self, comptime options: std.bit_set.IteratorOptions) BitSet.Iterator(options) {
215        return self.bitset.iterator(options);
216    }
217
218    pub fn count(self: Self) i32 {
219        return @intCast(self.bitset.count());
220    }
221
222    pub fn size(self: Self) i32 {
223        return @intCast(self.bitset.count() * 8);
224    }
225};
226
227const Mir = @This();
228const std = @import("std");
229const builtin = @import("builtin");
230const Type = @import("../../Type.zig");
231const bits = @import("bits.zig");
232
233const assert = std.debug.assert;
234
235const Register = bits.Register;
236const CSR = bits.CSR;
237const Immediate = bits.Immediate;
238const Memory = bits.Memory;
239const FrameIndex = bits.FrameIndex;
240const FrameAddr = @import("CodeGen.zig").FrameAddr;
241const IntegerBitSet = std.bit_set.IntegerBitSet;
242const Mnemonic = @import("mnem.zig").Mnemonic;
243
244const InternPool = @import("../../InternPool.zig");
245const Emit = @import("Emit.zig");
246const codegen = @import("../../codegen.zig");
247const link = @import("../../link.zig");
248const Zcu = @import("../../Zcu.zig");