lib/choir/src/backends/aarch64/registers/model.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2
3 pub const Encoded = enum(u5) {
4 _,
5
6 pub fn fromInt(val: u5) Encoded {
7 return @fromBackingInt(@intCast(val));
8 }
9
10 pub fn toInt(self: Encoded) u5 {
11 return @backingInt(self);
12 }
13 };
14
15 pub const GPR = enum(u5) {
16 x0 = 0,
17 x1 = 1,
18 x2 = 2,
19 x3 = 3,
20 x4 = 4,
21 x5 = 5,
22 x6 = 6,
23 x7 = 7,
24 x8 = 8,
25 x9 = 9,
26 x10 = 10,
27 x11 = 11,
28 x12 = 12,
29 x13 = 13,
30 x14 = 14,
31 x15 = 15,
32 x16 = 16,
33 x17 = 17,
34 x18 = 18,
35 x19 = 19,
36 x20 = 20,
37 x21 = 21,
38 x22 = 22,
39 x23 = 23,
40 x24 = 24,
41 x25 = 25,
42 x26 = 26,
43 x27 = 27,
44 x28 = 28,
45 x29 = 29,
46 x30 = 30,
47
48 pub const fp = GPR.x29;
49 pub const lr = GPR.x30;
50
51 pub const arg0 = GPR.x0;
52 pub const arg1 = GPR.x1;
53 pub const arg2 = GPR.x2;
54 pub const arg3 = GPR.x3;
55 pub const arg4 = GPR.x4;
56 pub const arg5 = GPR.x5;
57 pub const arg6 = GPR.x6;
58 pub const arg7 = GPR.x7;
59
60 pub const ret = GPR.x0;
61
62 pub fn encode(self: GPR) Encoded {
63 return @fromBackingInt(@intCast(@backingInt(self)));
64 }
65
66 pub fn isCallerSaved(self: GPR) bool {
67 const n = @backingInt(self);
68 return n <= 17;
69 }
70
71 pub fn isCalleeSaved(self: GPR) bool {
72 const n = @backingInt(self);
73 return n >= 19 and n <= 28;
74 }
75
76 pub fn isArgument(self: GPR) bool {
77 const n = @backingInt(self);
78 return n <= 7;
79 }
80
81 pub fn toW(self: GPR) []const u8 {
82 const names = [_][]const u8{
83 "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
84 "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
85 "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
86 "w24", "w25", "w26", "w27", "w28", "w29", "w30",
87 };
88 return names[@backingInt(self)];
89 }
90
91 pub fn toX(self: GPR) []const u8 {
92 const names = [_][]const u8{
93 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
94 "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
95 "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
96 "x24", "x25", "x26", "x27", "x28", "x29", "x30",
97 };
98 return names[@backingInt(self)];
99 }
100 };
101
102 pub const SP = struct {
103 pub const encoded: Encoded = @fromBackingInt(@intCast(31));
104 };
105
106 pub const ZR = struct {
107 pub const encoded: Encoded = @fromBackingInt(@intCast(31));
108 };
109
110 pub const FPR = enum(u5) {
111 v0 = 0,
112 v1 = 1,
113 v2 = 2,
114 v3 = 3,
115 v4 = 4,
116 v5 = 5,
117 v6 = 6,
118 v7 = 7,
119 v8 = 8,
120 v9 = 9,
121 v10 = 10,
122 v11 = 11,
123 v12 = 12,
124 v13 = 13,
125 v14 = 14,
126 v15 = 15,
127 v16 = 16,
128 v17 = 17,
129 v18 = 18,
130 v19 = 19,
131 v20 = 20,
132 v21 = 21,
133 v22 = 22,
134 v23 = 23,
135 v24 = 24,
136 v25 = 25,
137 v26 = 26,
138 v27 = 27,
139 v28 = 28,
140 v29 = 29,
141 v30 = 30,
142 v31 = 31,
143
144 pub const arg0 = FPR.v0;
145 pub const arg1 = FPR.v1;
146 pub const arg2 = FPR.v2;
147 pub const arg3 = FPR.v3;
148 pub const arg4 = FPR.v4;
149 pub const arg5 = FPR.v5;
150 pub const arg6 = FPR.v6;
151 pub const arg7 = FPR.v7;
152
153 pub const ret = FPR.v0;
154
155 pub fn encode(self: FPR) Encoded {
156 return @fromBackingInt(@intCast(@backingInt(self)));
157 }
158
159 pub fn isCallerSaved(self: FPR) bool {
160 const n = @backingInt(self);
161 return n <= 7 or n >= 16;
162 }
163
164 pub fn isCalleeSaved(self: FPR) bool {
165 const n = @backingInt(self);
166 return n >= 8 and n <= 15;
167 }
168
169 pub fn isArgument(self: FPR) bool {
170 const n = @backingInt(self);
171 return n <= 7;
172 }
173
174 pub fn toS(self: FPR) []const u8 {
175 const names = [_][]const u8{
176 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
177 "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
178 "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
179 "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
180 };
181 return names[@backingInt(self)];
182 }
183
184 pub fn toD(self: FPR) []const u8 {
185 const names = [_][]const u8{
186 "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
187 "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
188 "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
189 "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
190 };
191 return names[@backingInt(self)];
192 }
193 };
194
195 pub const GPRSize = enum(u1) {
196 w = 0,
197 x = 1,
198
199 pub fn bits(self: GPRSize) u8 {
200 return switch (self) {
201 .w => 32,
202 .x => 64,
203 };
204 }
205 };
206
207 pub const FPRSize = enum(u2) {
208 s = 0b00,
209 d = 0b01,
210 h = 0b11,
211
212 pub fn bits(self: FPRSize) u8 {
213 return switch (self) {
214 .h => 16,
215 .s => 32,
216 .d => 64,
217 };
218 }
219 };
220
221 pub const Register = union(enum) {
222 gpr: GPR,
223 fpr: FPR,
224 sp,
225 zr,
226
227 pub fn encode(self: Register) Encoded {
228 return switch (self) {
229 .gpr => |r| r.encode(),
230 .fpr => |r| r.encode(),
231 .sp => SP.encoded,
232 .zr => ZR.encoded,
233 };
234 }
235 };
236
237 pub const allocatable_gprs = [_]GPR{
238 .x0, .x1, .x2, .x3, .x4, .x5, .x6, .x7,
239 .x8, .x9, .x10, .x11, .x12, .x13, .x14, .x15,
240 .x19, .x20, .x21, .x22, .x23, .x24, .x25, .x26,
241 .x27, .x28,
242 };
243
244 pub const callee_saved_gprs = [_]GPR{
245 .x19, .x20, .x21, .x22, .x23, .x24, .x25, .x26, .x27, .x28,
246 };
247
248 pub const allocatable_fprs = [_]FPR{
249 .v0, .v1, .v2, .v3, .v4, .v5, .v6, .v7,
250 .v8, .v9, .v10, .v11, .v12, .v13, .v14, .v15,
251 .v16, .v17, .v18, .v19, .v20, .v21, .v22, .v23,
252 .v24, .v25, .v26, .v27, .v28, .v29, .v30, .v31,
253 };
254
255 pub const callee_saved_fprs = [_]FPR{
256 .v8, .v9, .v10, .v11, .v12, .v13, .v14, .v15,
257 };
258
259 test "GPR encoding" {
260 const testing = std.testing;
261 try testing.expectEqual(@as(u5, 0), GPR.x0.encode().toInt());
262 try testing.expectEqual(@as(u5, 29), GPR.fp.encode().toInt());
263 try testing.expectEqual(@as(u5, 30), GPR.lr.encode().toInt());
264 }
265
266 test "GPR classification" {
267 const testing = std.testing;
268 try testing.expect(GPR.x0.isCallerSaved());
269 try testing.expect(GPR.x0.isArgument());
270 try testing.expect(!GPR.x0.isCalleeSaved());
271
272 try testing.expect(GPR.x19.isCalleeSaved());
273 try testing.expect(!GPR.x19.isCallerSaved());
274 try testing.expect(!GPR.x19.isArgument());
275 }
276
277 test "FPR encoding" {
278 const testing = std.testing;
279 try testing.expectEqual(@as(u5, 0), FPR.v0.encode().toInt());
280 try testing.expectEqual(@as(u5, 31), FPR.v31.encode().toInt());
281 }
282
283 test "FPR classification" {
284 const testing = std.testing;
285 try testing.expect(FPR.v0.isCallerSaved());
286 try testing.expect(FPR.v0.isArgument());
287
288 try testing.expect(FPR.v8.isCalleeSaved());
289 try testing.expect(!FPR.v8.isCallerSaved());
290 }