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;