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: link.File.AtomId,
71 sym_index: link.File.SymbolId,
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 func_index: InternPool.Index,
111 atom_index: link.File.AtomId,
112 w: *std.Io.Writer,
113 debug_output: link.File.DebugInfoOutput,
114) (codegen.Error || std.Io.Writer.Error)!void {
115 _ = atom_index;
116 const zcu = pt.zcu;
117 const comp = zcu.comp;
118 const gpa = comp.gpa;
119 const func = zcu.funcInfo(func_index);
120 const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?;
121 const nav = func.owner_nav;
122 const mod = zcu.navFileScope(nav).mod.?;
123 var e: Emit = .{
124 .lower = .{
125 .pt = pt,
126 .allocator = gpa,
127 .mir = mir,
128 .cc = fn_info.cc,
129 .src_loc = zcu.navSrcLoc(nav),
130 .output_mode = comp.config.output_mode,
131 .link_mode = comp.config.link_mode,
132 .pic = mod.pic,
133 },
134 .bin_file = lf,
135 .debug_output = debug_output,
136 .w = w,
137 .prev_di_pc = 0,
138 .prev_di_line = func.lbrace_line,
139 .prev_di_column = func.lbrace_column,
140 };
141 defer e.deinit();
142 e.emitMir() catch |err| switch (err) {
143 error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?),
144 error.InvalidInstruction => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}),
145 else => |err1| return err1,
146 };
147}
148
149pub const FrameLoc = struct {
150 base: Register,
151 disp: i32,
152};
153
154pub const Barrier = enum(u4) {
155 // Fence
156 w = 0b0001,
157 r = 0b0010,
158 rw = 0b0011,
159
160 // Amo
161 none,
162 aq,
163 rl,
164};
165
166pub const AmoOp = enum(u5) {
167 SWAP,
168 ADD,
169 AND,
170 OR,
171 XOR,
172 MAX,
173 MIN,
174};
175
176pub const FcvtOp = enum(u5) {
177 w = 0b00000,
178 wu = 0b00001,
179 l = 0b00010,
180 lu = 0b00011,
181};
182
183pub const LoadSymbolPayload = struct {
184 register: u32,
185 atom_index: link.File.AtomId,
186 sym_index: link.File.SymbolId,
187};
188
189/// Used in conjunction with payload to transfer a list of used registers in a compact manner.
190pub const RegisterList = struct {
191 bitset: BitSet = .empty,
192
193 const BitSet = IntegerBitSet(32);
194 const Self = @This();
195
196 fn getIndexForReg(registers: []const Register, reg: Register) BitSet.MaskInt {
197 for (registers, 0..) |cpreg, i| {
198 if (reg.id() == cpreg.id()) return @intCast(i);
199 }
200 unreachable; // register not in input register list!
201 }
202
203 pub fn push(self: *Self, registers: []const Register, reg: Register) void {
204 const index = getIndexForReg(registers, reg);
205 self.bitset.set(index);
206 }
207
208 pub fn isSet(self: Self, registers: []const Register, reg: Register) bool {
209 const index = getIndexForReg(registers, reg);
210 return self.bitset.isSet(index);
211 }
212
213 pub fn iterator(self: Self, comptime options: std.bit_set.IteratorOptions) BitSet.Iterator(options) {
214 return self.bitset.iterator(options);
215 }
216
217 pub fn count(self: Self) i32 {
218 return @intCast(self.bitset.count());
219 }
220
221 pub fn size(self: Self) i32 {
222 return @intCast(self.bitset.count() * 8);
223 }
224};
225
226const Mir = @This();
227const std = @import("std");
228const builtin = @import("builtin");
229const Type = @import("../../Type.zig");
230const bits = @import("bits.zig");
231
232const assert = std.debug.assert;
233
234const Register = bits.Register;
235const CSR = bits.CSR;
236const Immediate = bits.Immediate;
237const Memory = bits.Memory;
238const FrameIndex = bits.FrameIndex;
239const FrameAddr = @import("CodeGen.zig").FrameAddr;
240const IntegerBitSet = std.bit_set.Integer;
241const Mnemonic = @import("mnem.zig").Mnemonic;
242
243const InternPool = @import("../../InternPool.zig");
244const Emit = @import("Emit.zig");
245const codegen = @import("../../codegen.zig");
246const link = @import("../../link.zig");
247const Zcu = @import("../../Zcu.zig");