master
1pub fn writeSetSub6(comptime op: enum { set, sub }, code: *[1]u8, addend: anytype) void {
2 const mask: u8 = 0b11_000000;
3 const actual: i8 = @truncate(addend);
4 var value: u8 = mem.readInt(u8, code, .little);
5 switch (op) {
6 .set => value = (value & mask) | @as(u8, @bitCast(actual & ~mask)),
7 .sub => value = (value & mask) | (@as(u8, @bitCast(@as(i8, @bitCast(value)) -| actual)) & ~mask),
8 }
9 mem.writeInt(u8, code, value, .little);
10}
11
12pub fn writeSubUleb(code: []u8, addend: i64) void {
13 var reader: std.Io.Reader = .fixed(code);
14 const value = reader.takeLeb128(u64) catch unreachable;
15 overwriteUleb(code, value -% @as(u64, @intCast(addend)));
16}
17
18pub fn writeSetUleb(code: []u8, addend: i64) void {
19 overwriteUleb(code, @intCast(addend));
20}
21
22fn overwriteUleb(code: []u8, addend: u64) void {
23 var value: u64 = addend;
24 var i: usize = 0;
25
26 while (true) {
27 const byte = code[i];
28 if (byte & 0x80 == 0) break;
29 code[i] = 0x80 | @as(u8, @truncate(value & 0x7f));
30 i += 1;
31 value >>= 7;
32 }
33 code[i] = @truncate(value & 0x7f);
34}
35
36pub fn writeAddend(
37 comptime Int: type,
38 comptime op: enum { add, sub },
39 code: *[@typeInfo(Int).int.bits / 8]u8,
40 value: anytype,
41) void {
42 var V: Int = mem.readInt(Int, code, .little);
43 const addend: Int = @truncate(value);
44 switch (op) {
45 .add => V +|= addend, // TODO: I think saturating arithmetic is correct here
46 .sub => V -|= addend,
47 }
48 mem.writeInt(Int, code, V, .little);
49}
50
51pub fn writeInstU(code: *[4]u8, value: u32) void {
52 var data: Instruction = .{ .U = mem.bytesToValue(@FieldType(Instruction, "U"), code) };
53 const compensated: u32 = @bitCast(@as(i32, @bitCast(value)) + 0x800);
54 data.U.imm12_31 = bitSlice(compensated, 31, 12);
55 mem.writeInt(u32, code, data.toU32(), .little);
56}
57
58pub fn writeInstI(code: *[4]u8, value: u32) void {
59 var data: Instruction = .{ .I = mem.bytesToValue(@FieldType(Instruction, "I"), code) };
60 data.I.imm0_11 = bitSlice(value, 11, 0);
61 mem.writeInt(u32, code, data.toU32(), .little);
62}
63
64pub fn writeInstS(code: *[4]u8, value: u32) void {
65 var data: Instruction = .{ .S = mem.bytesToValue(@FieldType(Instruction, "S"), code) };
66 data.S.imm0_4 = bitSlice(value, 4, 0);
67 data.S.imm5_11 = bitSlice(value, 11, 5);
68 mem.writeInt(u32, code, data.toU32(), .little);
69}
70
71pub fn writeInstJ(code: *[4]u8, value: u32) void {
72 var data: Instruction = .{ .J = mem.bytesToValue(@FieldType(Instruction, "J"), code) };
73 data.J.imm1_10 = bitSlice(value, 10, 1);
74 data.J.imm11 = bitSlice(value, 11, 11);
75 data.J.imm12_19 = bitSlice(value, 19, 12);
76 data.J.imm20 = bitSlice(value, 20, 20);
77 mem.writeInt(u32, code, data.toU32(), .little);
78}
79
80pub fn writeInstB(code: *[4]u8, value: u32) void {
81 var data: Instruction = .{ .B = mem.bytesToValue(@FieldType(Instruction, "B"), code) };
82 data.B.imm1_4 = bitSlice(value, 4, 1);
83 data.B.imm5_10 = bitSlice(value, 10, 5);
84 data.B.imm11 = bitSlice(value, 11, 11);
85 data.B.imm12 = bitSlice(value, 12, 12);
86 mem.writeInt(u32, code, data.toU32(), .little);
87}
88
89fn bitSlice(
90 value: anytype,
91 comptime high: comptime_int,
92 comptime low: comptime_int,
93) std.math.IntFittingRange(0, 1 << high - low) {
94 return @truncate((value >> low) & (1 << (high - low + 1)) - 1);
95}
96
97pub const Eflags = packed struct(u32) {
98 rvc: bool,
99 fabi: FloatAbi,
100 rve: bool,
101 tso: bool,
102 _reserved: u19 = 0,
103 _unused: u8 = 0,
104
105 pub const FloatAbi = enum(u2) {
106 soft = 0b00,
107 single = 0b01,
108 double = 0b10,
109 quad = 0b11,
110 };
111};
112
113const mem = std.mem;
114const std = @import("std");
115
116const encoding = @import("../codegen/riscv64/encoding.zig");
117const Instruction = encoding.Instruction;