lib/isa/src/x86/form.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2
3 pub const FormKey = u64;
4
5 pub const Prefix = enum(u5) {
6 none = 0,
7 rex = 1,
8 rex_b = 2,
9 rex_r = 3,
10 rex_rb = 4,
11 rex_rxb = 5,
12 rex_w = 6,
13 rex_wb = 7,
14 rex_wr = 8,
15 rex_wrb = 9,
16 operand16 = 10,
17 operand16_cs = 11,
18 operand16_rex_b = 12,
19 operand16_rex_r = 13,
20 operand16_rex_rb = 14,
21 lock_rex = 15,
22 lock_rex_b = 16,
23 lock_rex_w = 17,
24 repeat = 18,
25 repeat_rex_b = 19,
26 rex_x = 20,
27 rex_xb = 21,
28 rex_rx = 22,
29 rex_wx = 23,
30 rex_wxb = 24,
31 rex_wrx = 25,
32 rex_wrxb = 26,
33 repeat_rex_w = 27,
34 operand16_2_cs = 28,
35 operand16_4_cs = 29,
36 operand16_5_cs = 30,
37 operand16_3_cs = 31,
38
39 pub fn bytes(self: Prefix) []const u8 {
40 return switch (self) {
41 .none => &.{},
42 .rex => &.{0x40},
43 .rex_b => &.{0x41},
44 .rex_r => &.{0x44},
45 .rex_rb => &.{0x45},
46 .rex_rxb => &.{0x47},
47 .rex_w => &.{0x48},
48 .rex_wb => &.{0x49},
49 .rex_wr => &.{0x4c},
50 .rex_wrb => &.{0x4d},
51 .operand16 => &.{0x66},
52 .operand16_cs => &.{ 0x66, 0x2e },
53 .operand16_rex_b => &.{ 0x66, 0x41 },
54 .operand16_rex_r => &.{ 0x66, 0x44 },
55 .operand16_rex_rb => &.{ 0x66, 0x45 },
56 .lock_rex => &.{ 0xf0, 0x40 },
57 .lock_rex_b => &.{ 0xf0, 0x41 },
58 .lock_rex_w => &.{ 0xf0, 0x48 },
59 .repeat => &.{0xf3},
60 .repeat_rex_b => &.{ 0xf3, 0x41 },
61 .rex_x => &.{0x42},
62 .rex_xb => &.{0x43},
63 .rex_rx => &.{0x46},
64 .rex_wx => &.{0x4a},
65 .rex_wxb => &.{0x4b},
66 .rex_wrx => &.{0x4e},
67 .rex_wrxb => &.{0x4f},
68 .repeat_rex_w => &.{ 0xf3, 0x48 },
69 .operand16_2_cs => &.{ 0x66, 0x66, 0x2e },
70 .operand16_4_cs => &.{ 0x66, 0x66, 0x66, 0x66, 0x2e },
71 .operand16_5_cs => &.{ 0x66, 0x66, 0x66, 0x66, 0x66, 0x2e },
72 .operand16_3_cs => &.{ 0x66, 0x66, 0x66, 0x2e },
73 };
74 }
75
76 pub fn fromBytes(value: []const u8) ?Prefix {
77 inline for (@typeInfo(Prefix).@"enum".field_names) |name| {
78 const candidate: Prefix = @fromBackingInt(@intCast(@backingInt(@field(Prefix, name))));
79 if (std.mem.eql(u8, value, candidate.bytes())) return candidate;
80 }
81 return null;
82 }
83
84 pub fn rexByte(self: Prefix) u8 {
85 return switch (self) {
86 .rex, .lock_rex => 0x40,
87 .rex_b, .operand16_rex_b, .lock_rex_b, .repeat_rex_b => 0x41,
88 .rex_x => 0x42,
89 .rex_xb => 0x43,
90 .rex_r, .operand16_rex_r => 0x44,
91 .rex_rb, .operand16_rex_rb => 0x45,
92 .rex_rx => 0x46,
93 .rex_rxb => 0x47,
94 .rex_w, .lock_rex_w => 0x48,
95 .rex_wb => 0x49,
96 .rex_wx => 0x4a,
97 .rex_wxb => 0x4b,
98 .rex_wr => 0x4c,
99 .rex_wrb => 0x4d,
100 .rex_wrx => 0x4e,
101 .rex_wrxb => 0x4f,
102 .repeat_rex_w => 0x48,
103 else => 0,
104 };
105 }
106
107 pub fn wide(self: Prefix) bool {
108 return self.rexByte() & 0x08 != 0;
109 }
110
111 pub fn hasOperand16(self: Prefix) bool {
112 return switch (self) {
113 .operand16,
114 .operand16_cs,
115 .operand16_rex_b,
116 .operand16_rex_r,
117 .operand16_rex_rb,
118 .operand16_2_cs,
119 .operand16_4_cs,
120 .operand16_5_cs,
121 .operand16_3_cs,
122 => true,
123 else => false,
124 };
125 }
126
127 pub fn repeatedOperand16(self: Prefix) bool {
128 return self == .operand16_2_cs or
129 self == .operand16_4_cs or
130 self == .operand16_5_cs or
131 self == .operand16_3_cs;
132 }
133
134 pub fn locked(self: Prefix) bool {
135 return switch (self) {
136 .lock_rex, .lock_rex_b, .lock_rex_w => true,
137 else => false,
138 };
139 }
140
141 pub fn repeated(self: Prefix) bool {
142 return switch (self) {
143 .repeat, .repeat_rex_b, .repeat_rex_w => true,
144 else => false,
145 };
146 }
147 };
148
149 pub const Map = enum(u1) {
150 one = 0,
151 two = 1,
152 };
153
154 pub const Width = enum(u3) {
155 none = 0,
156 byte = 1,
157 word = 2,
158 dword = 3,
159 qword = 4,
160 vector128 = 5,
161
162 pub fn bytes(self: Width) u8 {
163 return switch (self) {
164 .none => 0,
165 .byte => 1,
166 .word => 2,
167 .dword => 4,
168 .qword => 8,
169 .vector128 => 16,
170 };
171 }
172 };
173
174 pub const Extension = enum(u4) {
175 zero = 0,
176 one = 1,
177 two = 2,
178 three = 3,
179 four = 4,
180 five = 5,
181 six = 6,
182 seven = 7,
183 none = 8,
184
185 pub fn fromRaw(value: u3) Extension {
186 return @fromBackingInt(@intCast(value));
187 }
188 };
189
190 pub const Mode = enum(u3) {
191 none = 0,
192 memory = 1,
193 displacement8 = 2,
194 displacement32 = 3,
195 register = 4,
196 };
197
198 pub const Role = enum(u2) {
199 none = 0,
200 ordinary = 1,
201 rsp = 2,
202 rbp = 3,
203 };
204
205 pub const AddressKind = enum(u3) {
206 none = 0,
207 base = 1,
208 base_indexed = 2,
209 rip_relative = 3,
210 absolute = 4,
211 absolute_indexed = 5,
212 };
213
214 pub const Access = enum(u2) {
215 none = 0,
216 read = 1,
217 write = 2,
218 read_write = 3,
219 };
220
221 pub const Form = packed struct(u64) {
222 prefix: Prefix = .none,
223 map: Map = .one,
224 opcode: u8 = 0,
225 width: Width = .none,
226 extension: Extension = .none,
227 mode: Mode = .none,
228 register_role: Role = .none,
229 register_access: Access = .none,
230 operand_role: Role = .none,
231 operand_access: Access = .none,
232 address: AddressKind = .none,
233 base_role: Role = .none,
234 index_role: Role = .none,
235 embedded_role: Role = .none,
236 embedded_access: Access = .none,
237 immediate: u8 = 0,
238 reserved: u13 = 0,
239
240 pub fn key(self: Form) FormKey {
241 return @bitCast(self);
242 }
243
244 pub fn encodedKey(self: Form) [8]u8 {
245 var result: [8]u8 = undefined;
246 std.mem.writeInt(u64, &result, self.key(), .little);
247 return result;
248 }
249 };
250
251 pub const Diagnostic = struct {
252 candidate: Form = .{},
253 prefix: [15]u8 = @splat(0),
254 prefix_count: u4 = 0,
255 active: bool = false,
256 normalized: bool = false,
257
258 pub fn captureForm(self: *Diagnostic, value: Form) void {
259 self.* = .{
260 .candidate = value,
261 .active = true,
262 .normalized = true,
263 };
264 }
265
266 pub fn capturePrefix(self: *Diagnostic, value: []const u8) void {
267 std.debug.assert(value.len <= self.prefix.len);
268 self.* = .{
269 .prefix_count = @intCast(value.len),
270 .active = true,
271 };
272 @memcpy(self.prefix[0..value.len], value);
273 }
274
275 pub fn normalizedForm(self: Diagnostic) ?Form {
276 if (!self.active or !self.normalized) return null;
277 return self.candidate;
278 }
279
280 pub fn prefixBytes(self: *const Diagnostic) []const u8 {
281 return self.prefix[0..self.prefix_count];
282 }
283 };
284
285 pub fn modeled(value: Form) bool {
286 if (value.reserved != 0) return false;
287 return switch (value.map) {
288 .one => modeledOne(value.opcode),
289 .two => modeledTwo(value.opcode),
290 };
291 }
292
293 fn modeledOne(opcode: u8) bool {
294 if (opcode <= 0x05) return true;
295 if (opcode >= 0x08 and opcode <= 0x0b) return true;
296 if (opcode == 0x0d) return true;
297 if (opcode >= 0x18 and opcode <= 0x1d) return true;
298 if (opcode >= 0x20 and opcode <= 0x25) return true;
299 if (opcode >= 0x28 and opcode <= 0x2d) return true;
300 if (opcode >= 0x30 and opcode <= 0x35) return true;
301 if (opcode == 0x38 or opcode == 0x39 or
302 (opcode >= 0x3b and opcode <= 0x3d)) return true;
303 if (opcode >= 0x50 and opcode <= 0x5f) return true;
304 if ((opcode >= 0x72 and opcode <= 0x77) or
305 (opcode >= 0x7c and opcode <= 0x7f)) return true;
306 if (opcode >= 0xb0 and opcode <= 0xbf) return true;
307 return switch (opcode) {
308 0x69,
309 0x6a,
310 0x6b,
311 0x80,
312 0x81,
313 0x83,
314 0x84,
315 0x85,
316 0x88,
317 0x89,
318 0x8a,
319 0x8b,
320 0x8d,
321 0x90,
322 0x9c,
323 0xa4,
324 0xa5,
325 0xa8,
326 0xa9,
327 0xaa,
328 0xab,
329 0xc0,
330 0xc1,
331 0xc3,
332 0xc6,
333 0xc7,
334 0xcd,
335 0xd0,
336 0xd1,
337 0xd2,
338 0xd3,
339 0xe8,
340 0xe9,
341 0xeb,
342 0xee,
343 0xf4,
344 0xf5,
345 0xf6,
346 0xf7,
347 0xfa,
348 0xfb,
349 0xfe,
350 0xff,
351 => true,
352 else => false,
353 };
354 }
355
356 fn modeledTwo(opcode: u8) bool {
357 if ((opcode >= 0x82 and opcode <= 0x87) or
358 (opcode >= 0x8c and opcode <= 0x8f)) return true;
359 if ((opcode >= 0x92 and opcode <= 0x97) or
360 (opcode >= 0x9c and opcode <= 0x9f)) return true;
361 if (opcode >= 0xc8 and opcode <= 0xcf) return true;
362 return switch (opcode) {
363 0x0b,
364 0x10,
365 0x11,
366 0x1f,
367 0x30,
368 0x32,
369 0x42,
370 0x43,
371 0x44,
372 0x45,
373 0x47,
374 0x6f,
375 0x70,
376 0x7f,
377 0x90,
378 0xa2,
379 0xaf,
380 0xb0,
381 0xb6,
382 0xb7,
383 0xbe,
384 0xbf,
385 => true,
386 else => false,
387 };
388 }
389
390 comptime {
391 std.debug.assert(@sizeOf(Form) == @sizeOf(FormKey));
392 std.debug.assert(@bitSizeOf(Form) == 64);
393 }