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");