lib/isa/src/x86/operand.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const x86 = @import("root.zig");
3
4 pub const RegisterBank = enum(u1) {
5 gpr = 0,
6 vector = 1,
7 };
8
9 pub const RegisterLane = enum(u3) {
10 low8 = 0,
11 high8 = 1,
12 word = 2,
13 dword = 3,
14 qword = 4,
15 vector128 = 5,
16
17 pub fn bytes(self: RegisterLane) u8 {
18 return switch (self) {
19 .low8, .high8 => 1,
20 .word => 2,
21 .dword => 4,
22 .qword => 8,
23 .vector128 => 16,
24 };
25 }
26 };
27
28 pub const Register = struct {
29 bank: RegisterBank = .gpr,
30 number: u4 = 0,
31 lane: RegisterLane = .qword,
32
33 pub fn role(self: Register) x86.Role {
34 if (self.bank == .vector or self.lane == .high8) return .ordinary;
35 return switch (self.number) {
36 4 => .rsp,
37 5 => .rbp,
38 else => .ordinary,
39 };
40 }
41 };
42
43 pub const RegisterAccess = struct {
44 register: Register = .{},
45 access: x86.Access = .none,
46 };
47
48 pub const Segment = enum(u3) {
49 none = 0,
50 es = 1,
51 cs = 2,
52 ss = 3,
53 ds = 4,
54 fs = 5,
55 gs = 6,
56
57 pub fn prefixByte(self: Segment) u8 {
58 return switch (self) {
59 .none => 0,
60 .es => 0x26,
61 .cs => 0x2e,
62 .ss => 0x36,
63 .ds => 0x3e,
64 .fs => 0x64,
65 .gs => 0x65,
66 };
67 }
68 };
69
70 pub const Scale = enum(u2) {
71 one = 0,
72 two = 1,
73 four = 2,
74 eight = 3,
75
76 pub fn factor(self: Scale) u4 {
77 return @as(u4, 1) << @backingInt(self);
78 }
79 };
80
81 pub const Memory = struct {
82 kind: x86.AddressKind,
83 width: x86.Width = .none,
84 base: ?Register = null,
85 index: ?Register = null,
86 scale: Scale = .one,
87 displacement: i32 = 0,
88 segment: Segment = .none,
89 };
90
91 pub const Operand = union(enum) {
92 none,
93 register: Register,
94 memory: Memory,
95 };
96
97 pub const ImmediateExtension = enum(u1) {
98 none = 0,
99 sign = 1,
100 };
101
102 pub const Immediate = struct {
103 value: u64,
104 encoded_bytes: u4,
105 extension: ImmediateExtension,
106
107 pub fn signed(self: Immediate) i64 {
108 std.debug.assert(std.math.isPowerOfTwo(self.encoded_bytes));
109 std.debug.assert(self.encoded_bytes <= 8);
110 return switch (self.encoded_bytes) {
111 1 => @as(i8, @bitCast(@as(u8, @truncate(self.value)))),
112 2 => @as(i16, @bitCast(@as(u16, @truncate(self.value)))),
113 4 => @as(i32, @bitCast(@as(u32, @truncate(self.value)))),
114 8 => @bitCast(self.value),
115 else => unreachable,
116 };
117 }
118 };