From f3899c182532c7e9c4cc490f8b00edb16a7d0f25 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Aug 2026 11:43:26 +0100 Subject: [PATCH 01/20] rexcode: riscv `INSTRUCTION_TABLE` which includes the clobber information --- core/rexcode/isa/riscv/clobber_types.odin | 47 ++ .../isa/riscv/tablegen/encoding_table.odin | 432 ----------- core/rexcode/isa/riscv/tablegen/gen.odin | 116 ++- .../tablegen/generated/encode_tables.odin | 402 +++++++++- .../isa/riscv/tablegen/generated/writer.odin | 1 + .../isa/riscv/tablegen/instruction_table.odin | 690 ++++++++++++++++++ core/rexcode/isa/riscv/tables.odin | 24 +- 7 files changed, 1255 insertions(+), 457 deletions(-) create mode 100644 core/rexcode/isa/riscv/clobber_types.odin delete mode 100644 core/rexcode/isa/riscv/tablegen/encoding_table.odin create mode 100644 core/rexcode/isa/riscv/tablegen/instruction_table.odin diff --git a/core/rexcode/isa/riscv/clobber_types.odin b/core/rexcode/isa/riscv/clobber_types.odin new file mode 100644 index 000000000..6d2b37bbd --- /dev/null +++ b/core/rexcode/isa/riscv/clobber_types.odin @@ -0,0 +1,47 @@ +package rexcode_riscv + +// Operand slots (indices into the Encoding operand list) that are read/written. +// Max 4 operands (R4-type FMA: rd, rs1, rs2, rs3). +Operand_Set :: distinct bit_set[0..<4; u8] + +FFlags :: distinct bit_set[FFlag; u8] +// fcsr accrued exception flags. This is the ONLY flag state in RISC-V — there +// are no integer condition codes, so there is no EFLAGS-style triad here. +FFlag :: enum u8 { + NV, // invalid operation + DZ, // divide by zero + OF, // overflow + UF, // underflow + NX, // inexact +} + +Clobber_Regs :: distinct bit_set[Clobber_Reg; u8] +// Implicitly-touched registers that are NOT distinct operands. RISC-V's base +// ISA has almost none of these (unlike x86's RAX/RDX/RSP-heavy encodings) — +// only the compressed link/stack forms. +Clobber_Reg :: enum u8 { + RA, // x1, implicit link on C.JAL / C.JALR + SP, // x2, implicit base on the *SP compressed forms +} + +Side_Effects :: distinct bit_set[Side_Effect; u8] +Side_Effect :: enum u8 { + CONTROL, // writes pc: branches, jumps, and trap redirects + TRAP, // synchronous environment trap (ECALL / EBREAK) + FENCE, // explicit memory-ordering barrier (FENCE) + IFENCE, // instruction-fetch synchronization (FENCE.I) + ATOMIC, // indivisible memory RMW (AMO*, and the LR/SC pair) + RESERVATION, // sets or tests an LR/SC reservation +} + +Clobber :: struct { + written: Operand_Set, // operand slots whose register/CSR is written + read: Operand_Set, // operand slots whose register/CSR/mem-base is read + implicit_wr: Clobber_Regs, // implicit reg writes (ra on C.JAL/C.JALR) + implicit_rd: Clobber_Regs, // implicit reg reads (sp on the *SP forms) + fflags_wr: FFlags, // accrued exception flags this op may raise + reads_frm: bool, // consumes the dynamic rounding mode from fcsr + writes_mem: bool, + reads_mem: bool, + side_effects: Side_Effects, +} \ No newline at end of file diff --git a/core/rexcode/isa/riscv/tablegen/encoding_table.odin b/core/rexcode/isa/riscv/tablegen/encoding_table.odin deleted file mode 100644 index 3aa4433d9..000000000 --- a/core/rexcode/isa/riscv/tablegen/encoding_table.odin +++ /dev/null @@ -1,432 +0,0 @@ -// rexcode · Brendan Punsky (dotbmp@github), original author - -package rexcode_riscv_tablegen - -// ============================================================================= -// RISC-V ENCODING_TABLE -// ============================================================================= -// -// (bits, mask) model -- same shape as MIPS. `bits` carries the static -// opcode/funct3/funct7 pattern; `mask` covers exactly the bits that are -// fixed. Operand-driven fields (rd, rs1, rs2, immediates, rounding mode, -// aq/rl) land in zero positions of `bits` and are ORed in by the encoder. -// -// Sections: -// §1 RV32I + RV64I base -// §2 Zicsr (CSR access) + Zifencei (FENCE.I) -// §3 M extension -// §4 A extension (atomics) -// §5 F extension (single-precision FP) -// §6 D extension (double-precision FP) -@(rodata) -ENCODING_TABLE:= #partial [Mnemonic][]Encoding{ - .INVALID = {}, - - // ========================================================================= - // §1 RV32I / RV64I base - // ========================================================================= - - // ---- Upper-immediate ---------------------------------------------------- - .LUI = { {.LUI, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000037, MASK_U, .I, {}} }, - .AUIPC = { {.AUIPC, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000017, MASK_U, .I, {}} }, - - // ---- Jumps -------------------------------------------------------------- - .JAL = { {.JAL, {.GPR,.REL21,.NONE,.NONE}, {.RD,.IMM_J,.NONE,.NONE}, 0x0000006F, MASK_J, .I, {branch=true}} }, - .JALR = { {.JALR, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000067, MASK_OPCODE | MASK_FUNCT3, .I, {branch=true}} }, - - // ---- Branches (B-type) -------------------------------------------------- - .BEQ = { {.BEQ, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00000063, MASK_B, .I, {branch=true}} }, - .BNE = { {.BNE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00001063, MASK_B, .I, {branch=true}} }, - .BLT = { {.BLT, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00004063, MASK_B, .I, {branch=true}} }, - .BGE = { {.BGE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00005063, MASK_B, .I, {branch=true}} }, - .BLTU = { {.BLTU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00006063, MASK_B, .I, {branch=true}} }, - .BGEU = { {.BGEU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00007063, MASK_B, .I, {branch=true}} }, - - // ---- Loads (I-type) ----------------------------------------------------- - .LB = { {.LB, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00000003, MASK_I, .I, {}} }, - .LH = { {.LH, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001003, MASK_I, .I, {}} }, - .LW = { {.LW, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002003, MASK_I, .I, {}} }, - .LBU = { {.LBU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00004003, MASK_I, .I, {}} }, - .LHU = { {.LHU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00005003, MASK_I, .I, {}} }, - .LWU = { {.LWU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00006003, MASK_I, .I, {rv64_only=true}} }, - .LD = { {.LD, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003003, MASK_I, .I, {rv64_only=true}} }, - - // ---- Stores (S-type) ---------------------------------------------------- - .SB = { {.SB, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00000023, MASK_S, .I, {}} }, - .SH = { {.SH, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001023, MASK_S, .I, {}} }, - .SW = { {.SW, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002023, MASK_S, .I, {}} }, - .SD = { {.SD, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003023, MASK_S, .I, {rv64_only=true}} }, - - // ---- Integer reg-imm (I-type ALU) --------------------------------------- - .ADDI = { {.ADDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000013, MASK_I, .I, {}} }, - .SLTI = { {.SLTI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00002013, MASK_I, .I, {}} }, - .SLTIU = { {.SLTIU, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00003013, MASK_I, .I, {}} }, - .XORI = { {.XORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00004013, MASK_I, .I, {}} }, - .ORI = { {.ORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00006013, MASK_I, .I, {}} }, - .ANDI = { {.ANDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00007013, MASK_I, .I, {}} }, - - // I-type shifts. RV32 uses 5-bit shamt + funct7; RV64 widens to 6-bit - // shamt + funct6. We list the RV64-compatible mask (funct6 fixed, - // shamt[5] operand-driven); on RV32 the user must keep shamt < 32. - .SLLI = { {.SLLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00001013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}} }, - .SRLI = { {.SRLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}} }, - .SRAI = { {.SRAI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x40005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}} }, - - // RV64 OP-IMM-32 (operates on low 32 bits, sign-extends result) - .ADDIW = { {.ADDIW, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x0000001B, MASK_I, .I, {rv64_only=true}} }, - .SLLIW = { {.SLLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000101B, MASK_R, .I, {rv64_only=true}} }, - .SRLIW = { {.SRLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000501B, MASK_R, .I, {rv64_only=true}} }, - .SRAIW = { {.SRAIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x4000501B, MASK_R, .I, {rv64_only=true}} }, - - // ---- Integer reg-reg (R-type) ------------------------------------------- - .ADD = { {.ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000033, MASK_R, .I, {}} }, - .SUB = { {.SUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40000033, MASK_R, .I, {}} }, - .SLL = { {.SLL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00001033, MASK_R, .I, {}} }, - .SLT = { {.SLT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00002033, MASK_R, .I, {}} }, - .SLTU = { {.SLTU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00003033, MASK_R, .I, {}} }, - .XOR = { {.XOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00004033, MASK_R, .I, {}} }, - .SRL = { {.SRL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00005033, MASK_R, .I, {}} }, - .SRA = { {.SRA, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40005033, MASK_R, .I, {}} }, - .OR = { {.OR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00006033, MASK_R, .I, {}} }, - .AND = { {.AND, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00007033, MASK_R, .I, {}} }, - - // RV64 OP-32 - .ADDW = { {.ADDW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000003B, MASK_R, .I, {rv64_only=true}} }, - .SUBW = { {.SUBW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000003B, MASK_R, .I, {rv64_only=true}} }, - .SLLW = { {.SLLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000103B, MASK_R, .I, {rv64_only=true}} }, - .SRLW = { {.SRLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000503B, MASK_R, .I, {rv64_only=true}} }, - .SRAW = { {.SRAW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000503B, MASK_R, .I, {rv64_only=true}} }, - - // ---- Memory ordering ---------------------------------------------------- - // FENCE encodes pred/succ in bits 27-24 / 23-20. The opcode reserves - // these as operand-driven; mask covers opcode + funct3. - .FENCE = { {.FENCE, {.FENCE_FLAGS,.FENCE_FLAGS,.NONE,.NONE}, {.FENCE_PRED,.FENCE_SUCC,.NONE,.NONE}, 0x0000000F, MASK_I, .I, {}} }, - .FENCE_I = { {.FENCE_I, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0000100F, 0xFFFFFFFF, .ZIFENCEI, {}} }, - - // ---- System ------------------------------------------------------------- - .ECALL = { {.ECALL, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00000073, 0xFFFFFFFF, .I, {branch=true}} }, - .EBREAK = { {.EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00100073, 0xFFFFFFFF, .I, {branch=true}} }, - - // ========================================================================= - // §2 Zicsr (CSR access) - // ========================================================================= - // CSRRW rd, csr, rs1 - // CSRRWI rd, csr, zimm5 (zimm5 lives in the RS1 field) - - .CSRRW = { {.CSRRW, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00001073, MASK_I, .ZICSR, {}} }, - .CSRRS = { {.CSRRS, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00002073, MASK_I, .ZICSR, {}} }, - .CSRRC = { {.CSRRC, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00003073, MASK_I, .ZICSR, {}} }, - .CSRRWI = { {.CSRRWI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00005073, MASK_I, .ZICSR, {}} }, - .CSRRSI = { {.CSRRSI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00006073, MASK_I, .ZICSR, {}} }, - .CSRRCI = { {.CSRRCI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00007073, MASK_I, .ZICSR, {}} }, - - // ========================================================================= - // §3 M extension (RV32M / RV64M) - // ========================================================================= - // All share opcode 0x33 and funct7 = 0x01. - - .MUL = { {.MUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000033, MASK_R, .M, {}} }, - .MULH = { {.MULH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02001033, MASK_R, .M, {}} }, - .MULHSU = { {.MULHSU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02002033, MASK_R, .M, {}} }, - .MULHU = { {.MULHU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02003033, MASK_R, .M, {}} }, - .DIV = { {.DIV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02004033, MASK_R, .M, {}} }, - .DIVU = { {.DIVU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02005033, MASK_R, .M, {}} }, - .REM = { {.REM, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02006033, MASK_R, .M, {}} }, - .REMU = { {.REMU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02007033, MASK_R, .M, {}} }, - - // RV64 M-32 variants (opcode 0x3B) - .MULW = { {.MULW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200003B, MASK_R, .M, {rv64_only=true}} }, - .DIVW = { {.DIVW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200403B, MASK_R, .M, {rv64_only=true}} }, - .DIVUW = { {.DIVUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200503B, MASK_R, .M, {rv64_only=true}} }, - .REMW = { {.REMW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200603B, MASK_R, .M, {rv64_only=true}} }, - .REMUW = { {.REMUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200703B, MASK_R, .M, {rv64_only=true}} }, - - // ========================================================================= - // §4 A extension (atomics) - // ========================================================================= - // opcode 0x2F; funct3 = 2 for .W and 3 for .D; funct5 (bits 31-27) - // picks the op; bits 26-25 are aq/rl (operand). Mask = opcode + - // funct3 + funct5 = 0xF800707F. - // - // LR.W/LR.D take only one register addr (rd, rs1); rs2 must be 0 - // and is part of the static mask. - // - // The address operand uses OFFSET_BASE_A (rs1 only; disp must be 0). - - .LR_W = { {.LR_W, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000202F, 0xF9F0707F, .A, {}} }, - .SC_W = { {.SC_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800202F, 0xF800707F, .A, {}} }, - .AMOSWAP_W = { {.AMOSWAP_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800202F, 0xF800707F, .A, {}} }, - .AMOADD_W = { {.AMOADD_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000202F, 0xF800707F, .A, {}} }, - .AMOXOR_W = { {.AMOXOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000202F, 0xF800707F, .A, {}} }, - .AMOAND_W = { {.AMOAND_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000202F, 0xF800707F, .A, {}} }, - .AMOOR_W = { {.AMOOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000202F, 0xF800707F, .A, {}} }, - .AMOMIN_W = { {.AMOMIN_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000202F, 0xF800707F, .A, {}} }, - .AMOMAX_W = { {.AMOMAX_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000202F, 0xF800707F, .A, {}} }, - .AMOMINU_W = { {.AMOMINU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000202F, 0xF800707F, .A, {}} }, - .AMOMAXU_W = { {.AMOMAXU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000202F, 0xF800707F, .A, {}} }, - - .LR_D = { {.LR_D, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000302F, 0xF9F0707F, .A, {rv64_only=true}} }, - .SC_D = { {.SC_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800302F, 0xF800707F, .A, {rv64_only=true}} }, - .AMOSWAP_D = { {.AMOSWAP_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800302F, 0xF800707F, .A, {rv64_only=true}} }, - .AMOADD_D = { {.AMOADD_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000302F, 0xF800707F, .A, {rv64_only=true}} }, - .AMOXOR_D = { {.AMOXOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000302F, 0xF800707F, .A, {rv64_only=true}} }, - .AMOAND_D = { {.AMOAND_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000302F, 0xF800707F, .A, {rv64_only=true}} }, - .AMOOR_D = { {.AMOOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000302F, 0xF800707F, .A, {rv64_only=true}} }, - .AMOMIN_D = { {.AMOMIN_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000302F, 0xF800707F, .A, {rv64_only=true}} }, - .AMOMAX_D = { {.AMOMAX_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000302F, 0xF800707F, .A, {rv64_only=true}} }, - .AMOMINU_D = { {.AMOMINU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000302F, 0xF800707F, .A, {rv64_only=true}} }, - .AMOMAXU_D = { {.AMOMAXU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000302F, 0xF800707F, .A, {rv64_only=true}} }, - - // ========================================================================= - // §5 F extension (single-precision) - // ========================================================================= - // - // OP-FP opcode = 0x53. funct7 selects op family. funct3 is normally the - // FP rounding mode (operand-driven, fp_round flag) but is fixed for a - // few ops (FMV/FCLASS/FEQ/FLT/FLE/FSGNJ*). - // - // Masks include opcode + funct7 always. funct3 is included only when - // it's a fixed selector rather than a rounding mode. rs2 is included - // when it's a fixed selector (FCVT/FMV/FCLASS/FSQRT). - // - // MASK macros used below: - // M_OP_F7 :: opcode + funct7 - // M_OP_F7_RS2 :: + rs2 - // M_OP_F7_F3 :: + funct3 - // M_OP_F7_F3_RS2 :: + both - - .FLW = { {.FLW, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002007, MASK_I, .F, {}} }, - .FSW = { {.FSW, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002027, MASK_S, .F, {}} }, - - // R4-type FMA: opcode + fmt (bits 26-25); fmt=00 for .S - .FMADD_S = { {.FMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000043, 0x0600007F, .F, {fp_round=true}} }, - .FMSUB_S = { {.FMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000047, 0x0600007F, .F, {fp_round=true}} }, - .FNMSUB_S = { {.FNMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004B, 0x0600007F, .F, {fp_round=true}} }, - .FNMADD_S = { {.FNMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004F, 0x0600007F, .F, {fp_round=true}} }, - - // R-type with rm - .FADD_S = { {.FADD_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}} }, - .FSUB_S = { {.FSUB_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x08000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}} }, - .FMUL_S = { {.FMUL_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x10000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}} }, - .FDIV_S = { {.FDIV_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x18000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}} }, - .FSQRT_S = { {.FSQRT_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x58000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} }, - - // FSGNJ family: funct7 fixed (0x10), funct3 selects sub-op (no rm) - .FSGNJ_S = { {.FSGNJ_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20000053, MASK_R, .F, {}} }, - .FSGNJN_S = { {.FSGNJN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20001053, MASK_R, .F, {}} }, - .FSGNJX_S = { {.FSGNJX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002053, MASK_R, .F, {}} }, - - // FMIN/FMAX: funct7=0x14, funct3 selects min(0)/max(1) - .FMIN_S = { {.FMIN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28000053, MASK_R, .F, {}} }, - .FMAX_S = { {.FMAX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001053, MASK_R, .F, {}} }, - - // FP -> int convert: rs2 is the type selector - .FCVT_W_S = { {.FCVT_W_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} }, - .FCVT_WU_S = { {.FCVT_WU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} }, - .FCVT_L_S = { {.FCVT_L_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}} }, - .FCVT_LU_S = { {.FCVT_LU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}} }, - - // FP <- int convert - .FCVT_S_W = { {.FCVT_S_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} }, - .FCVT_S_WU = { {.FCVT_S_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} }, - .FCVT_S_L = { {.FCVT_S_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}} }, - .FCVT_S_LU = { {.FCVT_S_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}} }, - - // FMV / FCLASS: funct3 fixed (000 for FMV, 001 for FCLASS), rs2=0 - .FMV_X_W = { {.FMV_X_W, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}} }, - .FMV_W_X = { {.FMV_W_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}} }, - .FCLASS_S = { {.FCLASS_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0001053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}} }, - - // FP compare: funct7=0x50, funct3 selects EQ(2)/LT(1)/LE(0) - .FEQ_S = { {.FEQ_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0002053, MASK_R, .F, {}} }, - .FLT_S = { {.FLT_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0001053, MASK_R, .F, {}} }, - .FLE_S = { {.FLE_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0000053, MASK_R, .F, {}} }, - - // ========================================================================= - // §6 D extension (double-precision) - // ========================================================================= - // - // Same pattern as F but funct7 low bit = 1 (fmt=01 = D). - - .FLD = { {.FLD, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003007, MASK_I, .D, {}} }, - .FSD = { {.FSD, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003027, MASK_S, .D, {}} }, - - .FMADD_D = { {.FMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000043, 0x0600007F, .D, {fp_round=true}} }, - .FMSUB_D = { {.FMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000047, 0x0600007F, .D, {fp_round=true}} }, - .FNMSUB_D = { {.FNMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004B, 0x0600007F, .D, {fp_round=true}} }, - .FNMADD_D = { {.FNMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004F, 0x0600007F, .D, {fp_round=true}} }, - - .FADD_D = { {.FADD_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}} }, - .FSUB_D = { {.FSUB_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}} }, - .FMUL_D = { {.FMUL_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x12000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}} }, - .FDIV_D = { {.FDIV_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1A000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}} }, - .FSQRT_D = { {.FSQRT_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5A000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} }, - - .FSGNJ_D = { {.FSGNJ_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22000053, MASK_R, .D, {}} }, - .FSGNJN_D = { {.FSGNJN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22001053, MASK_R, .D, {}} }, - .FSGNJX_D = { {.FSGNJX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22002053, MASK_R, .D, {}} }, - - .FMIN_D = { {.FMIN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A000053, MASK_R, .D, {}} }, - .FMAX_D = { {.FMAX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A001053, MASK_R, .D, {}} }, - - // FCVT between S and D - .FCVT_S_D = { {.FCVT_S_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} }, - .FCVT_D_S = { {.FCVT_D_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} }, - - // FP -> int (double-source) - .FCVT_W_D = { {.FCVT_W_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} }, - .FCVT_WU_D = { {.FCVT_WU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} }, - .FCVT_L_D = { {.FCVT_L_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}} }, - .FCVT_LU_D = { {.FCVT_LU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}} }, - - // FP <- int - .FCVT_D_W = { {.FCVT_D_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} }, - .FCVT_D_WU = { {.FCVT_D_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} }, - .FCVT_D_L = { {.FCVT_D_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}} }, - .FCVT_D_LU = { {.FCVT_D_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}} }, - - // FMV / FCLASS double - .FMV_X_D = { {.FMV_X_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {rv64_only=true}} }, - .FMV_D_X = { {.FMV_D_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {rv64_only=true}} }, - .FCLASS_D = { {.FCLASS_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2001053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {}} }, - - // FP compare double - .FEQ_D = { {.FEQ_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2002053, MASK_R, .D, {}} }, - .FLT_D = { {.FLT_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2001053, MASK_R, .D, {}} }, - .FLE_D = { {.FLE_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2000053, MASK_R, .D, {}} }, - - // ========================================================================= - // C extension (16-bit compressed) - // ========================================================================= - // - // bits/mask use only the low 16 bits; the encoder writes 2 bytes for any - // form whose (bits & 3) != 3. The constant-bit pattern places the C - // dispatch fields (funct + op) in the low half-word. - - // ---- Quadrant 0 (op = 00) ---------------------------------------------- - - // C.ADDI4SPN rd', sp, imm = 000 imm[5:4] imm[9:6] imm[2] imm[3] rd' 00 - // funct3=000, op=00 -> static bits 0x0000, mask covers funct3+op only - // so the imm fields and rd' are operand-driven. - .C_ADDI4SPN = { {.C_ADDI4SPN, {.GPR_C, .GPR_SP, .IMM_C8U, .NONE}, {.C_RD_PRIMED, .NONE, .C_IMM_CIW, .NONE}, 0x0000, 0xE003, .C, {}} }, - - // C.FLD rd', imm(rs1') = 001 imm[5:3] rs1' imm[7:6] rd' 00 (D) - .C_FLD = { {.C_FLD, {.FPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0x2000, 0xE003, .D, {}} }, - - // C.LW rd', imm(rs1') = 010 imm[5:3] rs1' imm[2,6] rd' 00 - .C_LW = { {.C_LW, {.GPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0x4000, 0xE003, .C, {}} }, - - // C.LD rd', imm(rs1') = 011 imm[5:3] rs1' imm[7:6] rd' 00 (RV64-only) - .C_LD = { {.C_LD, {.GPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0x6000, 0xE003, .C, {rv64_only=true}} }, - - // C.FSD rs2', imm(rs1') = 101 imm[5:3] rs1' imm[7:6] rs2' 00 - .C_FSD = { {.C_FSD, {.FPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0xA000, 0xE003, .D, {}} }, - - // C.SW rs2', imm(rs1') = 110 imm[5:3] rs1' imm[2,6] rs2' 00 - .C_SW = { {.C_SW, {.GPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0xC000, 0xE003, .C, {}} }, - - // C.SD rs2', imm(rs1') = 111 imm[5:3] rs1' imm[7:6] rs2' 00 (RV64-only) - .C_SD = { {.C_SD, {.GPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0xE000, 0xE003, .C, {rv64_only=true}} }, - - // C.FLW rd', imm(rs1') = 011 imm[5:3] rs1' imm[2,6] rd' 00 (RV32-only) - .C_FLW = { {.C_FLW, {.FPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0x6000, 0xE003, .F, {rv32_only=true}} }, - - // C.FSW rs2', imm(rs1') = 111 imm[5:3] rs1' imm[2,6] rs2' 00 (RV32-only) - .C_FSW = { {.C_FSW, {.FPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0xE000, 0xE003, .F, {rv32_only=true}} }, - - // ---- Quadrant 1 (op = 01) ---------------------------------------------- - - // C.NOP = 0x0001 = C.ADDI x0, 0 (fully fixed encoding). - .C_NOP = { {.C_NOP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0001, 0xFFFF, .C, {}} }, - - // C.ADDI rd, imm = 000 imm[5] rd!=0 imm[4:0] 01 - .C_ADDI = { {.C_ADDI, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x0001, 0xE003, .C, {}} }, - - // C.JAL imm = 001 imm[11:1] 01 (RV32-only) - .C_JAL = { {.C_JAL, {.REL12, .NONE, .NONE, .NONE}, {.C_BRANCH12, .NONE, .NONE, .NONE}, 0x2001, 0xE003, .C, {rv32_only=true, branch=true}} }, - - // C.ADDIW rd, imm = 001 imm[5] rd!=0 imm[4:0] 01 (RV64-only) - .C_ADDIW = { {.C_ADDIW, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x2001, 0xE003, .C, {rv64_only=true}} }, - - // C.LI rd, imm = 010 imm[5] rd!=0 imm[4:0] 01 - .C_LI = { {.C_LI, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x4001, 0xE003, .C, {}} }, - - // C.ADDI16SP sp, imm = 011 imm[9] 00010 imm[4,6,8:7,5] 01 - // rd is fixed at 2 (sp); ensure the form discriminates by checking rd=2. - .C_ADDI16SP = { {.C_ADDI16SP, {.GPR_SP, .IMM_C10S, .NONE, .NONE}, {.NONE, .C_IMM_ADDI16SP, .NONE, .NONE}, 0x6101, 0xEF83, .C, {}} }, - - // C.LUI rd, imm = 011 imm[17] rd!=0,2 imm[16:12] 01 - .C_LUI = { {.C_LUI, {.GPR_NONZERO, .IMM_C18S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_LUI, .NONE, .NONE}, 0x6001, 0xE003, .C, {}} }, - - // C.SRLI rd', shamt = 100 shamt[5] 00 rd' shamt[4:0] 01 - .C_SRLI = { {.C_SRLI, {.GPR_C, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_U, .NONE, .NONE}, 0x8001, 0xEC03, .C, {}} }, - - // C.SRAI rd', shamt = 100 shamt[5] 01 rd' shamt[4:0] 01 - .C_SRAI = { {.C_SRAI, {.GPR_C, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_U, .NONE, .NONE}, 0x8401, 0xEC03, .C, {}} }, - - // C.ANDI rd', imm = 100 imm[5] 10 rd' imm[4:0] 01 - .C_ANDI = { {.C_ANDI, {.GPR_C, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_S, .NONE, .NONE}, 0x8801, 0xEC03, .C, {}} }, - - // CA-format reg-reg (op=01, funct6=100011 / 100111 + funct2 picks op): - // C.SUB rd', rs2' = 100011 rd' 00 rs2' 01 - // C.XOR rd', rs2' = 100011 rd' 01 rs2' 01 - // C.OR rd', rs2' = 100011 rd' 10 rs2' 01 - // C.AND rd', rs2' = 100011 rd' 11 rs2' 01 - // C.SUBW rd', rs2' = 100111 rd' 00 rs2' 01 (RV64) - // C.ADDW rd', rs2' = 100111 rd' 01 rs2' 01 (RV64) - .C_SUB = { {.C_SUB, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C01, 0xFC63, .C, {}} }, - .C_XOR = { {.C_XOR, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C21, 0xFC63, .C, {}} }, - .C_OR = { {.C_OR, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C41, 0xFC63, .C, {}} }, - .C_AND = { {.C_AND, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C61, 0xFC63, .C, {}} }, - .C_SUBW = { {.C_SUBW, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x9C01, 0xFC63, .C, {rv64_only=true}} }, - .C_ADDW = { {.C_ADDW, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x9C21, 0xFC63, .C, {rv64_only=true}} }, - - // C.J offset = 101 offset[11:1] 01 - .C_J = { {.C_J, {.REL12, .NONE, .NONE, .NONE}, {.C_BRANCH12, .NONE, .NONE, .NONE}, 0xA001, 0xE003, .C, {branch=true}} }, - - // C.BEQZ rs1', offset[8:1] = 110 offset[8,4:3] rs1' offset[7:6,2:1,5] 01 - .C_BEQZ = { {.C_BEQZ, {.GPR_C, .REL9, .NONE, .NONE}, {.C_RS1_PRIMED, .C_BRANCH9, .NONE, .NONE}, 0xC001, 0xE003, .C, {branch=true}} }, - // C.BNEZ rs1', offset[8:1] = 111 offset[8,4:3] rs1' offset[7:6,2:1,5] 01 - .C_BNEZ = { {.C_BNEZ, {.GPR_C, .REL9, .NONE, .NONE}, {.C_RS1_PRIMED, .C_BRANCH9, .NONE, .NONE}, 0xE001, 0xE003, .C, {branch=true}} }, - - // ---- Quadrant 2 (op = 10) ---------------------------------------------- - - // C.SLLI rd, shamt = 000 shamt[5] rd!=0 shamt[4:0] 10 - .C_SLLI = { {.C_SLLI, {.GPR_NONZERO, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_U, .NONE, .NONE}, 0x0002, 0xE003, .C, {}} }, - - // C.FLDSP rd, imm = 001 imm[5] rd imm[4:3,8:6] 10 - .C_FLDSP = { {.C_FLDSP, {.FPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_D, .NONE, .NONE}, 0x2002, 0xE003, .D, {}} }, - - // C.LWSP rd, imm = 010 imm[5] rd!=0 imm[4:2,7:6] 10 - .C_LWSP = { {.C_LWSP, {.GPR_NONZERO, .MEM_C_SP_W, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_W, .NONE, .NONE}, 0x4002, 0xE003, .C, {}} }, - - // C.LDSP rd, imm = 011 imm[5] rd!=0 imm[4:3,8:6] 10 (RV64) - .C_LDSP = { {.C_LDSP, {.GPR_NONZERO, .MEM_C_SP_D, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_D, .NONE, .NONE}, 0x6002, 0xE003, .C, {rv64_only=true}} }, - - // CR-format funct4=1000 / 1001 with rd!=0: - // C.JR rs1 = 1000 rs1!=0 00000 10 (rs2=0) - // C.MV rd, rs2 = 1000 rd!=0 rs2!=0 10 - // C.EBREAK = 1001 00000 00000 10 (fully fixed 0x9002) - // C.JALR rs1 = 1001 rs1!=0 00000 10 (rs2=0) - // C.ADD rd, rs2 = 1001 rd!=0 rs2!=0 10 - .C_JR = { {.C_JR, {.GPR_NONZERO, .NONE, .NONE, .NONE}, {.C_RD_RS1, .NONE, .NONE, .NONE}, 0x8002, 0xF07F, .C, {branch=true}} }, - .C_MV = { {.C_MV, {.GPR_NONZERO, .GPR_NONZERO, .NONE, .NONE}, {.C_RD_RS1, .C_RS2, .NONE, .NONE}, 0x8002, 0xF003, .C, {}} }, - .C_EBREAK = { {.C_EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x9002, 0xFFFF, .C, {}} }, - .C_JALR = { {.C_JALR, {.GPR_NONZERO, .NONE, .NONE, .NONE}, {.C_RD_RS1, .NONE, .NONE, .NONE}, 0x9002, 0xF07F, .C, {branch=true}} }, - .C_ADD = { {.C_ADD, {.GPR_NONZERO, .GPR_NONZERO, .NONE, .NONE}, {.C_RD_RS1, .C_RS2, .NONE, .NONE}, 0x9002, 0xF003, .C, {}} }, - - // C.FSDSP rs2, imm = 101 imm[5:3,8:6] rs2 10 - .C_FSDSP = { {.C_FSDSP, {.FPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_D, .NONE, .NONE}, 0xA002, 0xE003, .D, {}} }, - - // C.SWSP rs2, imm = 110 imm[5:2,7:6] rs2 10 - .C_SWSP = { {.C_SWSP, {.GPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_W, .NONE, .NONE}, 0xC002, 0xE003, .C, {}} }, - - // C.SDSP rs2, imm = 111 imm[5:3,8:6] rs2 10 (RV64) - .C_SDSP = { {.C_SDSP, {.GPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_D, .NONE, .NONE}, 0xE002, 0xE003, .C, {rv64_only=true}} }, - - // C.FLWSP rd, imm = 011 imm[5] rd imm[4:2,7:6] 10 (RV32-only) - .C_FLWSP = { {.C_FLWSP, {.FPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_W, .NONE, .NONE}, 0x6002, 0xE003, .F, {rv32_only=true}} }, - - // C.FSWSP rs2, imm = 111 imm[5:2,7:6] rs2 10 (RV32-only) - .C_FSWSP = { {.C_FSWSP, {.FPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_W, .NONE, .NONE}, 0xE002, 0xE003, .F, {rv32_only=true}} }, -} diff --git a/core/rexcode/isa/riscv/tablegen/gen.odin b/core/rexcode/isa/riscv/tablegen/gen.odin index 9d11056c5..8ad85fcef 100644 --- a/core/rexcode/isa/riscv/tablegen/gen.odin +++ b/core/rexcode/isa/riscv/tablegen/gen.odin @@ -34,6 +34,7 @@ import lib "../" // Package-scope aliases so the moved SoT resolves Mnemonic/Encoding unqualified. Encoding :: lib.Encoding Mnemonic :: lib.Mnemonic +Clobber :: lib.Clobber // The SoT's bit/mask literals reference these field-mask constants. MASK_OPCODE :: lib.MASK_OPCODE @@ -55,12 +56,13 @@ MASK_J :: lib.MASK_J Blob :: struct { global, file, typ: string } BLOBS := [?]Blob{ - {"ENCODE_FORMS", "riscv.encode_forms.bin", "Encoding"}, - {"ENCODE_RUNS", "riscv.encode_runs.bin", "Encode_Run"}, - {"DECODE_ENTRIES", "riscv.entries.bin", "Decode_Entry"}, - {"DECODE_INDEX_OPCODE", "riscv.idx_opcode.bin", "Decode_Index"}, - {"DECODE_INDEX_OP_FP", "riscv.idx_op_fp.bin", "Decode_Index"}, - {"DECODE_INDEX_RVC", "riscv.idx_rvc.bin", "Decode_Index"}, + {"ENCODE_FORMS", "riscv.encode_forms.bin", "Encoding"}, + {"ENCODE_RUNS", "riscv.encode_runs.bin", "Encode_Run"}, + {"DECODE_ENTRIES", "riscv.entries.bin", "Decode_Entry"}, + {"DECODE_INDEX_OPCODE", "riscv.idx_opcode.bin", "Decode_Index"}, + {"DECODE_INDEX_OP_FP", "riscv.idx_op_fp.bin", "Decode_Index"}, + {"DECODE_INDEX_RVC", "riscv.idx_rvc.bin", "Decode_Index"}, + {"CLOBBER_FORMS", "riscv.clobber_forms.bin", "Clobber"}, } DIR_GEN :: #directory + "/generated/" @@ -98,30 +100,43 @@ emit_encode_tables :: proc() -> (total: int) { sb := strings.builder_make() strings.write_string(&sb, "package rexcode_riscv_generated\n\n") strings.write_string(&sb, "// GENERATED by ../gen.odin -- DO NOT EDIT.\n") - strings.write_string(&sb, "// Flattened encode forms + per-mnemonic run index (source: ENCODING_TABLE).\n\n") + strings.write_string(&sb, "// Flattened encode forms + per-mnemonic run index (source: INSTRUCTION_TABLE).\n\n") strings.write_string(&sb, "import lib \"../..\"\n\n") - for m in Mnemonic { total += len(ENCODING_TABLE[m]) } + for m in Mnemonic { total += len(INSTRUCTION_TABLE[m]) } strings.write_string(&sb, "@(rodata)\n") fmt.sbprintfln(&sb, "ENCODE_FORMS := [%d]lib.Encoding{{", total) for m in Mnemonic { - forms := ENCODING_TABLE[m] + forms := INSTRUCTION_TABLE[m] if len(forms) == 0 { continue } fmt.sbprintfln(&sb, "\t// .%v", m) - for f in forms { + for &form in forms { + f := &form.encoding write_row(&sb, f.mnemonic, f.ops, f.enc, f.bits, f.mask, f.feature, f.flags) } } strings.write_string(&sb, "}\n\n") + strings.write_string(&sb, "@(rodata)\n") + fmt.sbprintfln(&sb, "CLOBBER_FORMS := [%d]lib.Clobber{{", total) + for m in Mnemonic { + forms := INSTRUCTION_TABLE[m] + if len(forms) == 0 { continue } + fmt.sbprintfln(&sb, "\t// .%v", m) + for &form in forms { + write_clobber_row(&sb, form.clobber) + } + } + strings.write_string(&sb, "}\n\n") + run_w := 0 for m in Mnemonic { run_w = max(run_w, len(reflect.enum_string(m))) } strings.write_string(&sb, "@(rodata)\n") strings.write_string(&sb, "ENCODE_RUNS := [lib.Mnemonic]lib.Encode_Run{\n") start := 0 for m in Mnemonic { - c := len(ENCODING_TABLE[m]) + c := len(INSTRUCTION_TABLE[m]) name := reflect.enum_string(m) fmt.sbprintf(&sb, "\t.%s", name) for _ in 0.. (total: int) { all: [dynamic]Entry defer delete(all) for m in Mnemonic { - for f in ENCODING_TABLE[m] { + for &form in INSTRUCTION_TABLE[m] { + f := &form.encoding e := Entry{ mnemonic = f.mnemonic, ops = f.ops, @@ -235,6 +251,64 @@ write_row :: proc(sb: ^strings.Builder, mn: lib.Mnemonic, ops: [4]lib.Operand_Ty mn, ops[0], ops[1], ops[2], ops[3], enc[0], enc[1], enc[2], enc[3], bits, mask, feature, flags_lit(flags)) } +write_clobber_row :: proc(sb: ^strings.Builder, c: lib.Clobber) { + write_set :: proc(sb: ^strings.Builder, name: string, set: $T) { + strings.write_string(sb, name) + strings.write_string(sb, "=") + strings.write_string(sb, "{") + i := 0 + for elem in set { + if i > 0 { strings.write_string(sb, ", ") } + strings.write_string(sb, ".") + fmt.sbprintf(sb, "%s", elem) + i += 1 + } + strings.write_string(sb, "}") + } + + strings.write_string(sb, "\t{") + defer strings.write_string(sb, "},\n") + i := -1 + if c.written != nil { + if i += 1; i > 0 { strings.write_string(sb, ", ") } + strings.write_string(sb, "written=") + fmt.sbprintf(sb, "%w", c.written) + } + if c.read != nil { + if i += 1; i > 0 { strings.write_string(sb, ", ") } + strings.write_string(sb, "read=") + fmt.sbprintf(sb, "%w", c.read) + } + if c.implicit_wr != nil { + if i += 1; i > 0 { strings.write_string(sb, ", ") } + write_set(sb, "implicit_wr", c.implicit_wr) + } + if c.implicit_rd != nil { + if i += 1; i > 0 { strings.write_string(sb, ", ") } + write_set(sb, "implicit_rd", c.implicit_rd) + } + if c.fflags_wr != nil { + if i += 1; i > 0 { strings.write_string(sb, ", ") } + write_set(sb, "fflags_wr", c.fflags_wr) + } + if c.reads_frm { + if i += 1; i > 0 { strings.write_string(sb, ", ") } + fmt.sbprintf(sb, "reads_frm=true") + } + if c.writes_mem { + if i += 1; i > 0 { strings.write_string(sb, ", ") } + fmt.sbprintf(sb, "writes_mem=true") + } + if c.reads_mem { + if i += 1; i > 0 { strings.write_string(sb, ", ") } + fmt.sbprintf(sb, "reads_mem=true") + } + if c.side_effects != nil { + if i += 1; i > 0 { strings.write_string(sb, ", ") } + write_set(sb, "side_effects", c.side_effects) + } +} + flags_lit :: proc(f: lib.Encoding_Flags) -> string { parts: [dynamic]string defer delete(parts) @@ -268,7 +342,8 @@ emit_writer :: proc() { emit_file(DIR_GEN + "writer.odin", &sb) } -LOADER_TYPES :: `// ----------------------------------------------------------------------------- +LOADER_TYPES :: ``` +// ----------------------------------------------------------------------------- // Subsidiary table types (generated scaffolding) // ----------------------------------------------------------------------------- @@ -294,9 +369,10 @@ Decode_Index :: struct #packed { count: u16, } #assert(size_of(Decode_Index) == 4) -` +``` -LOADER_ACCESSORS :: `// ----------------------------------------------------------------------------- +LOADER_ACCESSORS :: ``` +// ----------------------------------------------------------------------------- // Accessors // ----------------------------------------------------------------------------- @@ -307,7 +383,15 @@ encoding_forms :: #force_inline proc "contextless" (m: Mnemonic) -> []Encoding { r := ENCODE_RUNS[u16(m)] return ENCODE_FORMS[r.start:][:r.count] } -` + +// Per-mnemonic clobber forms: the run of CLOBBER_FORMS belonging to ` + "`m`" + `. +// Replaces the old ENCODING_TABLE[m] slice; the returned view is into rodata. +@(private, require_results) +clobber_forms :: #force_inline proc "contextless" (m: Mnemonic) -> []Clobber { + r := ENCODE_RUNS[u16(m)] + return CLOBBER_FORMS[r.start:][:r.count] +} +``` emit_loader :: proc() { sb := strings.builder_make() diff --git a/core/rexcode/isa/riscv/tablegen/generated/encode_tables.odin b/core/rexcode/isa/riscv/tablegen/generated/encode_tables.odin index 9d8328206..4bed4668a 100644 --- a/core/rexcode/isa/riscv/tablegen/generated/encode_tables.odin +++ b/core/rexcode/isa/riscv/tablegen/generated/encode_tables.odin @@ -3,7 +3,7 @@ package rexcode_riscv_generated // GENERATED by ../gen.odin -- DO NOT EDIT. -// Flattened encode forms + per-mnemonic run index (source: ENCODING_TABLE). +// Flattened encode forms + per-mnemonic run index (source: INSTRUCTION_TABLE). import lib "../.." @@ -407,6 +407,406 @@ ENCODE_FORMS := [198]lib.Encoding{ { .C_FSWSP, {.FPR,.MEM_C_SP_W,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_W,.NONE,.NONE}, 0x0000E002, 0x0000E003, .F, {rv32_only=true} }, } +@(rodata) +CLOBBER_FORMS := [198]lib.Clobber{ + // .LUI + {written={0}}, + // .AUIPC + {written={0}}, + // .JAL + {written={0}, side_effects={.CONTROL}}, + // .JALR + {written={0}, read={1}, side_effects={.CONTROL}}, + // .BEQ + {read={0, 1}, side_effects={.CONTROL}}, + // .BNE + {read={0, 1}, side_effects={.CONTROL}}, + // .BLT + {read={0, 1}, side_effects={.CONTROL}}, + // .BGE + {read={0, 1}, side_effects={.CONTROL}}, + // .BLTU + {read={0, 1}, side_effects={.CONTROL}}, + // .BGEU + {read={0, 1}, side_effects={.CONTROL}}, + // .LB + {written={0}, read={1}, reads_mem=true}, + // .LH + {written={0}, read={1}, reads_mem=true}, + // .LW + {written={0}, read={1}, reads_mem=true}, + // .LBU + {written={0}, read={1}, reads_mem=true}, + // .LHU + {written={0}, read={1}, reads_mem=true}, + // .SB + {read={0, 1}, writes_mem=true}, + // .SH + {read={0, 1}, writes_mem=true}, + // .SW + {read={0, 1}, writes_mem=true}, + // .LWU + {written={0}, read={1}, reads_mem=true}, + // .LD + {written={0}, read={1}, reads_mem=true}, + // .SD + {read={0, 1}, writes_mem=true}, + // .ADDI + {written={0}, read={1}}, + // .SLTI + {written={0}, read={1}}, + // .SLTIU + {written={0}, read={1}}, + // .XORI + {written={0}, read={1}}, + // .ORI + {written={0}, read={1}}, + // .ANDI + {written={0}, read={1}}, + // .SLLI + {written={0}, read={1}}, + // .SRLI + {written={0}, read={1}}, + // .SRAI + {written={0}, read={1}}, + // .ADDIW + {written={0}, read={1}}, + // .SLLIW + {written={0}, read={1}}, + // .SRLIW + {written={0}, read={1}}, + // .SRAIW + {written={0}, read={1}}, + // .ADD + {written={0}, read={1, 2}}, + // .SUB + {written={0}, read={1, 2}}, + // .SLL + {written={0}, read={1, 2}}, + // .SLT + {written={0}, read={1, 2}}, + // .SLTU + {written={0}, read={1, 2}}, + // .XOR + {written={0}, read={1, 2}}, + // .SRL + {written={0}, read={1, 2}}, + // .SRA + {written={0}, read={1, 2}}, + // .OR + {written={0}, read={1, 2}}, + // .AND + {written={0}, read={1, 2}}, + // .ADDW + {written={0}, read={1, 2}}, + // .SUBW + {written={0}, read={1, 2}}, + // .SLLW + {written={0}, read={1, 2}}, + // .SRLW + {written={0}, read={1, 2}}, + // .SRAW + {written={0}, read={1, 2}}, + // .FENCE + {side_effects={.FENCE}}, + // .FENCE_I + {side_effects={.IFENCE}}, + // .ECALL + {side_effects={.CONTROL, .TRAP}}, + // .EBREAK + {side_effects={.CONTROL, .TRAP}}, + // .CSRRW + {written={0, 1}, read={1, 2}}, + // .CSRRS + {written={0, 1}, read={1, 2}}, + // .CSRRC + {written={0, 1}, read={1, 2}}, + // .CSRRWI + {written={0, 1}, read={1}}, + // .CSRRSI + {written={0, 1}, read={1}}, + // .CSRRCI + {written={0, 1}, read={1}}, + // .MUL + {written={0}, read={1, 2}}, + // .MULH + {written={0}, read={1, 2}}, + // .MULHSU + {written={0}, read={1, 2}}, + // .MULHU + {written={0}, read={1, 2}}, + // .DIV + {written={0}, read={1, 2}}, + // .DIVU + {written={0}, read={1, 2}}, + // .REM + {written={0}, read={1, 2}}, + // .REMU + {written={0}, read={1, 2}}, + // .MULW + {written={0}, read={1, 2}}, + // .DIVW + {written={0}, read={1, 2}}, + // .DIVUW + {written={0}, read={1, 2}}, + // .REMW + {written={0}, read={1, 2}}, + // .REMUW + {written={0}, read={1, 2}}, + // .LR_W + {written={0}, read={1}, reads_mem=true, side_effects={.ATOMIC, .RESERVATION}}, + // .SC_W + {written={0}, read={1, 2}, writes_mem=true, side_effects={.ATOMIC, .RESERVATION}}, + // .AMOSWAP_W + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOADD_W + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOXOR_W + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOAND_W + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOOR_W + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOMIN_W + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOMAX_W + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOMINU_W + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOMAXU_W + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .LR_D + {written={0}, read={1}, reads_mem=true, side_effects={.ATOMIC, .RESERVATION}}, + // .SC_D + {written={0}, read={1, 2}, writes_mem=true, side_effects={.ATOMIC, .RESERVATION}}, + // .AMOSWAP_D + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOADD_D + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOXOR_D + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOAND_D + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOOR_D + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOMIN_D + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOMAX_D + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOMINU_D + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .AMOMAXU_D + {written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}}, + // .FLW + {written={0}, read={1}, reads_mem=true}, + // .FSW + {read={0, 1}, writes_mem=true}, + // .FMADD_S + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FMSUB_S + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FNMSUB_S + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FNMADD_S + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FADD_S + {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FSUB_S + {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FMUL_S + {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FDIV_S + {written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true}, + // .FSQRT_S + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FSGNJ_S + {written={0}, read={1, 2}}, + // .FSGNJN_S + {written={0}, read={1, 2}}, + // .FSGNJX_S + {written={0}, read={1, 2}}, + // .FMIN_S + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FMAX_S + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FCVT_W_S + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_WU_S + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FMV_X_W + {written={0}, read={1}}, + // .FEQ_S + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FLT_S + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FLE_S + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FCLASS_S + {written={0}, read={1}}, + // .FCVT_S_W + {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}, + // .FCVT_S_WU + {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}, + // .FMV_W_X + {written={0}, read={1}}, + // .FCVT_L_S + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_LU_S + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_S_L + {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}, + // .FCVT_S_LU + {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}, + // .FLD + {written={0}, read={1}, reads_mem=true}, + // .FSD + {read={0, 1}, writes_mem=true}, + // .FMADD_D + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FMSUB_D + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FNMSUB_D + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FNMADD_D + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FADD_D + {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FSUB_D + {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FMUL_D + {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FDIV_D + {written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true}, + // .FSQRT_D + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FSGNJ_D + {written={0}, read={1, 2}}, + // .FSGNJN_D + {written={0}, read={1, 2}}, + // .FSGNJX_D + {written={0}, read={1, 2}}, + // .FMIN_D + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FMAX_D + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FCVT_S_D + {written={0}, read={1}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FCVT_D_S + {written={0}, read={1}, fflags_wr={.NV}, reads_frm=true}, + // .FEQ_D + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FLT_D + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FLE_D + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FCLASS_D + {written={0}, read={1}}, + // .FCVT_W_D + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_WU_D + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_D_W + {written={0}, read={1}, reads_frm=true}, + // .FCVT_D_WU + {written={0}, read={1}, reads_frm=true}, + // .FCVT_L_D + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_LU_D + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_D_L + {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}, + // .FCVT_D_LU + {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}, + // .FMV_X_D + {written={0}, read={1}}, + // .FMV_D_X + {written={0}, read={1}}, + // .C_NOP + {}, + // .C_EBREAK + {side_effects={.CONTROL, .TRAP}}, + // .C_ADDI4SPN + {written={0}, read={1}}, + // .C_LW + {written={0}, read={1}, reads_mem=true}, + // .C_LD + {written={0}, read={1}, reads_mem=true}, + // .C_SW + {read={0, 1}, writes_mem=true}, + // .C_SD + {read={0, 1}, writes_mem=true}, + // .C_FLW + {written={0}, read={1}, reads_mem=true}, + // .C_FSW + {read={0, 1}, writes_mem=true}, + // .C_FLD + {written={0}, read={1}, reads_mem=true}, + // .C_FSD + {read={0, 1}, writes_mem=true}, + // .C_ADDI + {written={0}, read={0}}, + // .C_ADDIW + {written={0}, read={0}}, + // .C_LI + {written={0}}, + // .C_LUI + {written={0}}, + // .C_ADDI16SP + {written={0}, read={0}}, + // .C_SRLI + {written={0}, read={0}}, + // .C_SRAI + {written={0}, read={0}}, + // .C_ANDI + {written={0}, read={0}}, + // .C_SUB + {written={0}, read={0, 1}}, + // .C_XOR + {written={0}, read={0, 1}}, + // .C_OR + {written={0}, read={0, 1}}, + // .C_AND + {written={0}, read={0, 1}}, + // .C_SUBW + {written={0}, read={0, 1}}, + // .C_ADDW + {written={0}, read={0, 1}}, + // .C_J + {side_effects={.CONTROL}}, + // .C_JAL + {implicit_wr={.RA}, side_effects={.CONTROL}}, + // .C_BEQZ + {read={0}, side_effects={.CONTROL}}, + // .C_BNEZ + {read={0}, side_effects={.CONTROL}}, + // .C_SLLI + {written={0}, read={0}}, + // .C_LWSP + {written={0}, implicit_rd={.SP}, reads_mem=true}, + // .C_LDSP + {written={0}, implicit_rd={.SP}, reads_mem=true}, + // .C_SWSP + {read={0}, implicit_rd={.SP}, writes_mem=true}, + // .C_SDSP + {read={0}, implicit_rd={.SP}, writes_mem=true}, + // .C_FLDSP + {written={0}, implicit_rd={.SP}, reads_mem=true}, + // .C_FSDSP + {read={0}, implicit_rd={.SP}, writes_mem=true}, + // .C_JR + {read={0}, side_effects={.CONTROL}}, + // .C_JALR + {read={0}, implicit_wr={.RA}, side_effects={.CONTROL}}, + // .C_MV + {written={0}, read={1}}, + // .C_ADD + {written={0}, read={0, 1}}, + // .C_FLWSP + {written={0}, implicit_rd={.SP}, reads_mem=true}, + // .C_FSWSP + {read={0}, implicit_rd={.SP}, writes_mem=true}, +} + @(rodata) ENCODE_RUNS := [lib.Mnemonic]lib.Encode_Run{ .INVALID = { 0, 0}, diff --git a/core/rexcode/isa/riscv/tablegen/generated/writer.odin b/core/rexcode/isa/riscv/tablegen/generated/writer.odin index 4997fdeb0..0d246c6cf 100644 --- a/core/rexcode/isa/riscv/tablegen/generated/writer.odin +++ b/core/rexcode/isa/riscv/tablegen/generated/writer.odin @@ -28,4 +28,5 @@ main :: proc() { w(TABLES + "riscv.idx_opcode.bin", raw(&DECODE_INDEX_OPCODE, size_of(DECODE_INDEX_OPCODE))) w(TABLES + "riscv.idx_op_fp.bin", raw(&DECODE_INDEX_OP_FP, size_of(DECODE_INDEX_OP_FP))) w(TABLES + "riscv.idx_rvc.bin", raw(&DECODE_INDEX_RVC, size_of(DECODE_INDEX_RVC))) + w(TABLES + "riscv.clobber_forms.bin", raw(&CLOBBER_FORMS, size_of(CLOBBER_FORMS))) } diff --git a/core/rexcode/isa/riscv/tablegen/instruction_table.odin b/core/rexcode/isa/riscv/tablegen/instruction_table.odin new file mode 100644 index 000000000..ca076d516 --- /dev/null +++ b/core/rexcode/isa/riscv/tablegen/instruction_table.odin @@ -0,0 +1,690 @@ +package rexcode_riscv_tablegen + +// Form couples one encoding shape with its architectural effects. +// `using encoding` keeps existing field access (form.opcode, form.ops, +// form.flags, ...) working unchanged when code moves from []Encoding to []Form. +Form :: struct { + using encoding: Encoding, + clobber: Clobber, +} + +@(rodata) +INSTRUCTION_TABLE := [Mnemonic][]Form{ + .INVALID = {}, + + // ========================================================================= + // §1 RV32I / RV64I base + // ========================================================================= + + // Upper-immediate + .LUI = { + {{.LUI, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000037, MASK_U, .I, {}}, {written={0}}}, + }, + .AUIPC = { + {{.AUIPC, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000017, MASK_U, .I, {}}, {written={0}}}, + }, + + // Jumps + .JAL = { + {{.JAL, {.GPR,.REL21,.NONE,.NONE}, {.RD,.IMM_J,.NONE,.NONE}, 0x0000006F, MASK_J, .I, {branch=true}}, {written={0}, side_effects={.CONTROL}}}, + }, + .JALR = { + {{.JALR, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000067, MASK_OPCODE | MASK_FUNCT3, .I, {branch=true}}, {written={0}, read={1}, side_effects={.CONTROL}}}, + }, + + // Branches (B-type) + .BEQ = { + {{.BEQ, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00000063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}}, + }, + .BNE = { + {{.BNE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00001063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}}, + }, + .BLT = { + {{.BLT, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00004063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}}, + }, + .BGE = { + {{.BGE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00005063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}}, + }, + .BLTU = { + {{.BLTU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00006063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}}, + }, + .BGEU = { + {{.BGEU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00007063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}}, + }, + + // Loads (I-type) + .LB = { + {{.LB, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00000003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .LH = { + {{.LH, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .LW = { + {{.LW, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .LBU = { + {{.LBU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00004003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .LHU = { + {{.LHU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00005003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .LWU = { + {{.LWU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00006003, MASK_I, .I, {rv64_only=true}}, {written={0}, read={1}, reads_mem=true}}, + }, + .LD = { + {{.LD, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003003, MASK_I, .I, {rv64_only=true}}, {written={0}, read={1}, reads_mem=true}}, + }, + + // Stores (S-type) + .SB = { + {{.SB, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00000023, MASK_S, .I, {}}, {read={0, 1}, writes_mem=true}}, + }, + .SH = { + {{.SH, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001023, MASK_S, .I, {}}, {read={0, 1}, writes_mem=true}}, + }, + .SW = { + {{.SW, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002023, MASK_S, .I, {}}, {read={0, 1}, writes_mem=true}}, + }, + .SD = { + {{.SD, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003023, MASK_S, .I, {rv64_only=true}}, {read={0, 1}, writes_mem=true}}, + }, + + // Integer reg-imm (I-type ALU) + .ADDI = { + {{.ADDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000013, MASK_I, .I, {}}, {written={0}, read={1}}}, + }, + .SLTI = { + {{.SLTI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00002013, MASK_I, .I, {}}, {written={0}, read={1}}}, + }, + .SLTIU = { + {{.SLTIU, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00003013, MASK_I, .I, {}}, {written={0}, read={1}}}, + }, + .XORI = { + {{.XORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00004013, MASK_I, .I, {}}, {written={0}, read={1}}}, + }, + .ORI = { + {{.ORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00006013, MASK_I, .I, {}}, {written={0}, read={1}}}, + }, + .ANDI = { + {{.ANDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00007013, MASK_I, .I, {}}, {written={0}, read={1}}}, + }, + + .SLLI = { + {{.SLLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00001013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}}, {written={0}, read={1}}}, + }, + .SRLI = { + {{.SRLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}}, {written={0}, read={1}}}, + }, + .SRAI = { + {{.SRAI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x40005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}}, {written={0}, read={1}}}, + }, + + .ADDIW = { + {{.ADDIW, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x0000001B, MASK_I, .I, {rv64_only=true}}, {written={0}, read={1}}}, + }, + .SLLIW = { + {{.SLLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000101B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1}}}, + }, + .SRLIW = { + {{.SRLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000501B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1}}}, + }, + .SRAIW = { + {{.SRAIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x4000501B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1}}}, + }, + + // Integer reg-reg (R-type) + .ADD = { + {{.ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + .SUB = { + {{.SUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40000033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + .SLL = { + {{.SLL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00001033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + .SLT = { + {{.SLT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00002033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + .SLTU = { + {{.SLTU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00003033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + .XOR = { + {{.XOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00004033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + .SRL = { + {{.SRL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00005033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + .SRA = { + {{.SRA, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40005033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + .OR = { + {{.OR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00006033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + .AND = { + {{.AND, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00007033, MASK_R, .I, {}}, {written={0}, read={1, 2}}}, + }, + + .ADDW = { + {{.ADDW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000003B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .SUBW = { + {{.SUBW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000003B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .SLLW = { + {{.SLLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000103B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .SRLW = { + {{.SRLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000503B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .SRAW = { + {{.SRAW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000503B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + + // Memory ordering + .FENCE = { + {{.FENCE, {.FENCE_FLAGS,.FENCE_FLAGS,.NONE,.NONE}, {.FENCE_PRED,.FENCE_SUCC,.NONE,.NONE}, 0x0000000F, MASK_I, .I, {}}, {side_effects={.FENCE}}}, + }, + .FENCE_I = { + {{.FENCE_I, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0000100F, 0xFFFFFFFF, .ZIFENCEI, {}}, {side_effects={.IFENCE}}}, + }, + + // System + .ECALL = { + {{.ECALL, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00000073, 0xFFFFFFFF, .I, {branch=true}}, {side_effects={.TRAP, .CONTROL}}}, + }, + .EBREAK = { + {{.EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00100073, 0xFFFFFFFF, .I, {branch=true}}, {side_effects={.TRAP, .CONTROL}}}, + }, + + // ========================================================================= + // §2 Zicsr (CSR access) — csr operand (slot 1) marked r+w conservatively + // ========================================================================= + .CSRRW = { + {{.CSRRW, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00001073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1, 2}}}, + }, + .CSRRS = { + {{.CSRRS, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00002073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1, 2}}}, + }, + .CSRRC = { + {{.CSRRC, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00003073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1, 2}}}, + }, + .CSRRWI = { + {{.CSRRWI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00005073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1}}}, + }, + .CSRRSI = { + {{.CSRRSI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00006073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1}}}, + }, + .CSRRCI = { + {{.CSRRCI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00007073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1}}}, + }, + + // ========================================================================= + // §3 M extension — pure dataflow; no trap, no flags (incl. DIV/REM by 0) + // ========================================================================= + .MUL = { + {{.MUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000033, MASK_R, .M, {}}, {written={0}, read={1, 2}}}, + }, + .MULH = { + {{.MULH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02001033, MASK_R, .M, {}}, {written={0}, read={1, 2}}}, + }, + .MULHSU = { + {{.MULHSU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02002033, MASK_R, .M, {}}, {written={0}, read={1, 2}}}, + }, + .MULHU = { + {{.MULHU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02003033, MASK_R, .M, {}}, {written={0}, read={1, 2}}}, + }, + .DIV = { + {{.DIV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02004033, MASK_R, .M, {}}, {written={0}, read={1, 2}}}, + }, + .DIVU = { + {{.DIVU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02005033, MASK_R, .M, {}}, {written={0}, read={1, 2}}}, + }, + .REM = { + {{.REM, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02006033, MASK_R, .M, {}}, {written={0}, read={1, 2}}}, + }, + .REMU = { + {{.REMU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02007033, MASK_R, .M, {}}, {written={0}, read={1, 2}}}, + }, + + .MULW = { + {{.MULW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200003B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .DIVW = { + {{.DIVW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200403B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .DIVUW = { + {{.DIVUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200503B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .REMW = { + {{.REMW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200603B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .REMUW = { + {{.REMUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200703B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + + // ========================================================================= + // §4 A extension (atomics) + // ========================================================================= + .LR_W = { + {{.LR_W, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000202F, 0xF9F0707F, .A, {}}, {written={0}, read={1}, reads_mem=true, side_effects={.ATOMIC, .RESERVATION}}}, + }, + .SC_W = { + {{.SC_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, writes_mem=true, side_effects={.ATOMIC, .RESERVATION}}}, + }, + .AMOSWAP_W = { + {{.AMOSWAP_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOADD_W = { + {{.AMOADD_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOXOR_W = { + {{.AMOXOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOAND_W = { + {{.AMOAND_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOOR_W = { + {{.AMOOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOMIN_W = { + {{.AMOMIN_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOMAX_W = { + {{.AMOMAX_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOMINU_W = { + {{.AMOMINU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOMAXU_W = { + {{.AMOMAXU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + + .LR_D = { + {{.LR_D, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000302F, 0xF9F0707F, .A, {rv64_only=true}}, {written={0}, read={1}, reads_mem=true, side_effects={.ATOMIC, .RESERVATION}}}, + }, + .SC_D = { + {{.SC_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, writes_mem=true, side_effects={.ATOMIC, .RESERVATION}}}, + }, + .AMOSWAP_D = { + {{.AMOSWAP_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOADD_D = { + {{.AMOADD_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOXOR_D = { + {{.AMOXOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOAND_D = { + {{.AMOAND_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOOR_D = { + {{.AMOOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOMIN_D = { + {{.AMOMIN_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOMAX_D = { + {{.AMOMAX_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOMINU_D = { + {{.AMOMINU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + .AMOMAXU_D = { + {{.AMOMAXU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}}, + }, + + // ========================================================================= + // §5 F extension (single-precision) — reads_frm == encoding fp_round + // ========================================================================= + .FLW = { + {{.FLW, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002007, MASK_I, .F, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .FSW = { + {{.FSW, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002027, MASK_S, .F, {}}, {read={0, 1}, writes_mem=true}}, + }, + + .FMADD_S = { + {{.FMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000043, 0x0600007F, .F, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FMSUB_S = { + {{.FMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000047, 0x0600007F, .F, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FNMSUB_S = { + {{.FNMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004B, 0x0600007F, .F, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FNMADD_S = { + {{.FNMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004F, 0x0600007F, .F, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + + .FADD_S = { + {{.FADD_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FSUB_S = { + {{.FSUB_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x08000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FMUL_S = { + {{.FMUL_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x10000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FDIV_S = { + {{.FDIV_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x18000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FSQRT_S = { + {{.FSQRT_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x58000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + + .FSGNJ_S = { + {{.FSGNJ_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20000053, MASK_R, .F, {}}, {written={0}, read={1, 2}}}, + }, + .FSGNJN_S = { + {{.FSGNJN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20001053, MASK_R, .F, {}}, {written={0}, read={1, 2}}}, + }, + .FSGNJX_S = { + {{.FSGNJX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002053, MASK_R, .F, {}}, {written={0}, read={1, 2}}}, + }, + + .FMIN_S = { + {{.FMIN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28000053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + .FMAX_S = { + {{.FMAX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + + .FCVT_W_S = { + {{.FCVT_W_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_WU_S = { + {{.FCVT_WU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_L_S = { + {{.FCVT_L_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_LU_S = { + {{.FCVT_LU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + + .FCVT_S_W = { + {{.FCVT_S_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}}, + }, + .FCVT_S_WU = { + {{.FCVT_S_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}}, + }, + .FCVT_S_L = { + {{.FCVT_S_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}}, + }, + .FCVT_S_LU = { + {{.FCVT_S_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}}, + }, + + .FMV_X_W = { + {{.FMV_X_W, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}}, {written={0}, read={1}}}, + }, + .FMV_W_X = { + {{.FMV_W_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}}, {written={0}, read={1}}}, + }, + .FCLASS_S = { + {{.FCLASS_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0001053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}}, {written={0}, read={1}}}, + }, + + .FEQ_S = { + {{.FEQ_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0002053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + .FLT_S = { + {{.FLT_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0001053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + .FLE_S = { + {{.FLE_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0000053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + + // ========================================================================= + // §6 D extension (double-precision) + // ========================================================================= + .FLD = { + {{.FLD, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003007, MASK_I, .D, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .FSD = { + {{.FSD, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003027, MASK_S, .D, {}}, {read={0, 1}, writes_mem=true}}, + }, + + .FMADD_D = { + {{.FMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000043, 0x0600007F, .D, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FMSUB_D = { + {{.FMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000047, 0x0600007F, .D, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FNMSUB_D = { + {{.FNMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004B, 0x0600007F, .D, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FNMADD_D = { + {{.FNMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004F, 0x0600007F, .D, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + + .FADD_D = { + {{.FADD_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FSUB_D = { + {{.FSUB_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FMUL_D = { + {{.FMUL_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x12000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FDIV_D = { + {{.FDIV_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1A000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FSQRT_D = { + {{.FSQRT_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5A000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + + .FSGNJ_D = { + {{.FSGNJ_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22000053, MASK_R, .D, {}}, {written={0}, read={1, 2}}}, + }, + .FSGNJN_D = { + {{.FSGNJN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22001053, MASK_R, .D, {}}, {written={0}, read={1, 2}}}, + }, + .FSGNJX_D = { + {{.FSGNJX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22002053, MASK_R, .D, {}}, {written={0}, read={1, 2}}}, + }, + + .FMIN_D = { + {{.FMIN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A000053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + .FMAX_D = { + {{.FMAX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A001053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + + .FCVT_S_D = { + {{.FCVT_S_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FCVT_D_S = { + {{.FCVT_D_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV}, reads_frm=true}}, + }, + + .FCVT_W_D = { + {{.FCVT_W_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_WU_D = { + {{.FCVT_WU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_L_D = { + {{.FCVT_L_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_LU_D = { + {{.FCVT_LU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + + // FCVT_D_W / FCVT_D_WU are always exact (32-bit int fits a double), so no + // fflags — but reads_frm follows the fp_round flag for class-uniformity. + .FCVT_D_W = { + {{.FCVT_D_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, reads_frm=true}}, + }, + .FCVT_D_WU = { + {{.FCVT_D_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, reads_frm=true}}, + }, + .FCVT_D_L = { + {{.FCVT_D_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}}, + }, + .FCVT_D_LU = { + {{.FCVT_D_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}}, + }, + + .FMV_X_D = { + {{.FMV_X_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {rv64_only=true}}, {written={0}, read={1}}}, + }, + .FMV_D_X = { + {{.FMV_D_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {rv64_only=true}}, {written={0}, read={1}}}, + }, + .FCLASS_D = { + {{.FCLASS_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2001053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {}}, {written={0}, read={1}}}, + }, + + .FEQ_D = { + {{.FEQ_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2002053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + .FLT_D = { + {{.FLT_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2001053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + .FLE_D = { + {{.FLE_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2000053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + + // ========================================================================= + // C extension: Quadrant 0 (op = 00) + // ========================================================================= + .C_ADDI4SPN = { + {{.C_ADDI4SPN, {.GPR_C, .GPR_SP, .IMM_C8U, .NONE}, {.C_RD_PRIMED, .NONE, .C_IMM_CIW, .NONE}, 0x0000, 0xE003, .C, {}}, {written={0}, read={1}}}, + }, + .C_FLD = { + {{.C_FLD, {.FPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0x2000, 0xE003, .D, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .C_LW = { + {{.C_LW, {.GPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0x4000, 0xE003, .C, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .C_LD = { + {{.C_LD, {.GPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0x6000, 0xE003, .C, {rv64_only=true}}, {written={0}, read={1}, reads_mem=true}}, + }, + .C_FSD = { + {{.C_FSD, {.FPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0xA000, 0xE003, .D, {}}, {read={0, 1}, writes_mem=true}}, + }, + .C_SW = { + {{.C_SW, {.GPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0xC000, 0xE003, .C, {}}, {read={0, 1}, writes_mem=true}}, + }, + .C_SD = { + {{.C_SD, {.GPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0xE000, 0xE003, .C, {rv64_only=true}}, {read={0, 1}, writes_mem=true}}, + }, + + // C.FLW / C.FSW — RV32-only, share the C.LD / C.SD slots + .C_FLW = { + {{.C_FLW, {.FPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0x6000, 0xE003, .F, {rv32_only=true}}, {written={0}, read={1}, reads_mem=true}}, + }, + .C_FSW = { + {{.C_FSW, {.FPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0xE000, 0xE003, .F, {rv32_only=true}}, {read={0, 1}, writes_mem=true}}, + }, + + // ========================================================================= + // C extension: Quadrant 1 (op = 01) + // ========================================================================= + .C_NOP = { + {{.C_NOP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0001, 0xFFFF, .C, {}}, {}}, + }, + .C_ADDI = { + {{.C_ADDI, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x0001, 0xE003, .C, {}}, {written={0}, read={0}}}, + }, + .C_JAL = { + {{.C_JAL, {.REL12, .NONE, .NONE, .NONE}, {.C_BRANCH12, .NONE, .NONE, .NONE}, 0x2001, 0xE003, .C, {rv32_only=true, branch=true}}, {implicit_wr={.RA}, side_effects={.CONTROL}}}, + }, + .C_ADDIW = { + {{.C_ADDIW, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x2001, 0xE003, .C, {rv64_only=true}}, {written={0}, read={0}}}, + }, + .C_LI = { + {{.C_LI, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x4001, 0xE003, .C, {}}, {written={0}}}, + }, + .C_ADDI16SP = { + {{.C_ADDI16SP, {.GPR_SP, .IMM_C10S, .NONE, .NONE}, {.NONE, .C_IMM_ADDI16SP, .NONE, .NONE}, 0x6101, 0xEF83, .C, {}}, {written={0}, read={0}}}, + }, + .C_LUI = { + {{.C_LUI, {.GPR_NONZERO, .IMM_C18S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_LUI, .NONE, .NONE}, 0x6001, 0xE003, .C, {}}, {written={0}}}, + }, + .C_SRLI = { + {{.C_SRLI, {.GPR_C, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_U, .NONE, .NONE}, 0x8001, 0xEC03, .C, {}}, {written={0}, read={0}}}, + }, + .C_SRAI = { + {{.C_SRAI, {.GPR_C, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_U, .NONE, .NONE}, 0x8401, 0xEC03, .C, {}}, {written={0}, read={0}}}, + }, + .C_ANDI = { + {{.C_ANDI, {.GPR_C, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_S, .NONE, .NONE}, 0x8801, 0xEC03, .C, {}}, {written={0}, read={0}}}, + }, + .C_SUB = { + {{.C_SUB, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C01, 0xFC63, .C, {}}, {written={0}, read={0, 1}}}, + }, + .C_XOR = { + {{.C_XOR, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C21, 0xFC63, .C, {}}, {written={0}, read={0, 1}}}, + }, + .C_OR = { + {{.C_OR, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C41, 0xFC63, .C, {}}, {written={0}, read={0, 1}}}, + }, + .C_AND = { + {{.C_AND, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C61, 0xFC63, .C, {}}, {written={0}, read={0, 1}}}, + }, + .C_SUBW = { + {{.C_SUBW, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x9C01, 0xFC63, .C, {rv64_only=true}}, {written={0}, read={0, 1}}}, + }, + .C_ADDW = { + {{.C_ADDW, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x9C21, 0xFC63, .C, {rv64_only=true}}, {written={0}, read={0, 1}}}, + }, + .C_J = { + {{.C_J, {.REL12, .NONE, .NONE, .NONE}, {.C_BRANCH12, .NONE, .NONE, .NONE}, 0xA001, 0xE003, .C, {branch=true}}, {side_effects={.CONTROL}}}, + }, + .C_BEQZ = { + {{.C_BEQZ, {.GPR_C, .REL9, .NONE, .NONE}, {.C_RS1_PRIMED, .C_BRANCH9, .NONE, .NONE}, 0xC001, 0xE003, .C, {branch=true}}, {read={0}, side_effects={.CONTROL}}}, + }, + .C_BNEZ = { + {{.C_BNEZ, {.GPR_C, .REL9, .NONE, .NONE}, {.C_RS1_PRIMED, .C_BRANCH9, .NONE, .NONE}, 0xE001, 0xE003, .C, {branch=true}}, {read={0}, side_effects={.CONTROL}}}, + }, + + // ========================================================================= + // C extension: Quadrant 2 (op = 10) + // ========================================================================= + .C_SLLI = { + {{.C_SLLI, {.GPR_NONZERO, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_U, .NONE, .NONE}, 0x0002, 0xE003, .C, {}}, {written={0}, read={0}}}, + }, + .C_FLDSP = { + {{.C_FLDSP, {.FPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_D, .NONE, .NONE}, 0x2002, 0xE003, .D, {}}, {written={0}, implicit_rd={.SP}, reads_mem=true}}, + }, + .C_LWSP = { + {{.C_LWSP, {.GPR_NONZERO, .MEM_C_SP_W, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_W, .NONE, .NONE}, 0x4002, 0xE003, .C, {}}, {written={0}, implicit_rd={.SP}, reads_mem=true}}, + }, + .C_LDSP = { + {{.C_LDSP, {.GPR_NONZERO, .MEM_C_SP_D, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_D, .NONE, .NONE}, 0x6002, 0xE003, .C, {rv64_only=true}}, {written={0}, implicit_rd={.SP}, reads_mem=true}}, + }, + .C_JR = { + {{.C_JR, {.GPR_NONZERO, .NONE, .NONE, .NONE}, {.C_RD_RS1, .NONE, .NONE, .NONE}, 0x8002, 0xF07F, .C, {branch=true}}, {read={0}, side_effects={.CONTROL}}}, + }, + .C_MV = { + {{.C_MV, {.GPR_NONZERO, .GPR_NONZERO, .NONE, .NONE}, {.C_RD_RS1, .C_RS2, .NONE, .NONE}, 0x8002, 0xF003, .C, {}}, {written={0}, read={1}}}, + }, + .C_EBREAK = { + {{.C_EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x9002, 0xFFFF, .C, {}}, {side_effects={.TRAP, .CONTROL}}}, + }, + .C_JALR = { + {{.C_JALR, {.GPR_NONZERO, .NONE, .NONE, .NONE}, {.C_RD_RS1, .NONE, .NONE, .NONE}, 0x9002, 0xF07F, .C, {branch=true}}, {read={0}, implicit_wr={.RA}, side_effects={.CONTROL}}}, + }, + .C_ADD = { + {{.C_ADD, {.GPR_NONZERO, .GPR_NONZERO, .NONE, .NONE}, {.C_RD_RS1, .C_RS2, .NONE, .NONE}, 0x9002, 0xF003, .C, {}}, {written={0}, read={0, 1}}}, + }, + .C_FSDSP = { + {{.C_FSDSP, {.FPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_D, .NONE, .NONE}, 0xA002, 0xE003, .D, {}}, {read={0}, implicit_rd={.SP}, writes_mem=true}}, + }, + .C_SWSP = { + {{.C_SWSP, {.GPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_W, .NONE, .NONE}, 0xC002, 0xE003, .C, {}}, {read={0}, implicit_rd={.SP}, writes_mem=true}}, + }, + .C_SDSP = { + {{.C_SDSP, {.GPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_D, .NONE, .NONE}, 0xE002, 0xE003, .C, {rv64_only=true}}, {read={0}, implicit_rd={.SP}, writes_mem=true}}, + }, + + // C.FLWSP / C.FSWSP — RV32-only, share the C.LDSP / C.SDSP slots + .C_FLWSP = { + {{.C_FLWSP, {.FPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_W, .NONE, .NONE}, 0x6002, 0xE003, .F, {rv32_only=true}}, {written={0}, implicit_rd={.SP}, reads_mem=true}}, + }, + .C_FSWSP = { + {{.C_FSWSP, {.FPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_W, .NONE, .NONE}, 0xE002, 0xE003, .F, {rv32_only=true}}, {read={0}, implicit_rd={.SP}, writes_mem=true}}, + }, +} diff --git a/core/rexcode/isa/riscv/tables.odin b/core/rexcode/isa/riscv/tables.odin index de5093efc..4d708c3d3 100644 --- a/core/rexcode/isa/riscv/tables.odin +++ b/core/rexcode/isa/riscv/tables.odin @@ -39,26 +39,34 @@ Decode_Index :: struct #packed { count: u16, } #assert(size_of(Decode_Index) == 4) - // ----------------------------------------------------------------------------- // Loaded tables (rodata, embedded from tables/*.bin at compile time) // ----------------------------------------------------------------------------- -@(rodata) ENCODE_FORMS := #load("tables/riscv.encode_forms.bin", []Encoding) -@(rodata) ENCODE_RUNS := #load("tables/riscv.encode_runs.bin", []Encode_Run) -@(rodata) DECODE_ENTRIES := #load("tables/riscv.entries.bin", []Decode_Entry) -@(rodata) DECODE_INDEX_OPCODE := #load("tables/riscv.idx_opcode.bin", []Decode_Index) -@(rodata) DECODE_INDEX_OP_FP := #load("tables/riscv.idx_op_fp.bin", []Decode_Index) -@(rodata) DECODE_INDEX_RVC := #load("tables/riscv.idx_rvc.bin", []Decode_Index) +@(rodata) ENCODE_FORMS := #load("tables/riscv.encode_forms.bin", []Encoding) +@(rodata) ENCODE_RUNS := #load("tables/riscv.encode_runs.bin", []Encode_Run) +@(rodata) DECODE_ENTRIES := #load("tables/riscv.entries.bin", []Decode_Entry) +@(rodata) DECODE_INDEX_OPCODE := #load("tables/riscv.idx_opcode.bin", []Decode_Index) +@(rodata) DECODE_INDEX_OP_FP := #load("tables/riscv.idx_op_fp.bin", []Decode_Index) +@(rodata) DECODE_INDEX_RVC := #load("tables/riscv.idx_rvc.bin", []Decode_Index) +@(rodata) CLOBBER_FORMS := #load("tables/riscv.clobber_forms.bin", []Clobber) // ----------------------------------------------------------------------------- // Accessors // ----------------------------------------------------------------------------- -// Per-mnemonic encode forms: the run of ENCODE_FORMS belonging to `m`. +// Per-mnemonic encode forms: the run of ENCODE_FORMS belonging to ` + "`m`" + `. // Replaces the old ENCODING_TABLE[m] slice; the returned view is into rodata. @(private, require_results) encoding_forms :: #force_inline proc "contextless" (m: Mnemonic) -> []Encoding { r := ENCODE_RUNS[u16(m)] return ENCODE_FORMS[r.start:][:r.count] } + +// Per-mnemonic clobber forms: the run of CLOBBER_FORMS belonging to ` + "`m`" + `. +// Replaces the old ENCODING_TABLE[m] slice; the returned view is into rodata. +@(private, require_results) +clobber_forms :: #force_inline proc "contextless" (m: Mnemonic) -> []Clobber { + r := ENCODE_RUNS[u16(m)] + return CLOBBER_FORMS[r.start:][:r.count] +} \ No newline at end of file From 1009ab0c628418c1daf94b18bb6f2508df762119 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Aug 2026 11:45:50 +0100 Subject: [PATCH 02/20] Add riscv.clobber_forms.bin --- .../isa/riscv/tables/riscv.clobber_forms.bin | Bin 0 -> 1782 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 core/rexcode/isa/riscv/tables/riscv.clobber_forms.bin diff --git a/core/rexcode/isa/riscv/tables/riscv.clobber_forms.bin b/core/rexcode/isa/riscv/tables/riscv.clobber_forms.bin new file mode 100644 index 0000000000000000000000000000000000000000..047a2b041c0c42c712945ad31938704bf71dd435 GIT binary patch literal 1782 zcmZQ%fC3B#BO?<;ijjet90pW7BLguEh!r3=fbBwNU}}dehDtHOte_8r4H6m*j04Jm zI)Z@(#^8W4z#$0YFf+qkh=l=-Tn1(g#=!Us;tWOui0zCFFb1OlRD^N{{j6X>BvC#F z23b&YX2io_gQ>yFkOymLVqg#iGhlHF2^Izh)N}|^0v3TV;JT0*ptOOchK+#%q8QGA z1QaAU34r8484b>WXh${>;xHx#2DlnH1LVHJ6dI7YU}9ik1p5o_WlRQgAizBcXMlqY z6fAHCTnf&B2LhY{4>~XdgJ1?52oi=ekP1(Dih?uXYVe7Gd Date: Thu, 20 Aug 2026 14:42:42 +0100 Subject: [PATCH 03/20] Mockout inline `asm` for riscv --- core/rexcode/isa/riscv/encoder.odin | 4 ++++ core/rexcode/isa/riscv/encoding_types.odin | 13 +++++----- core/rexcode/isa/riscv/tablegen/gen.odin | 17 ++++++++++++- .../x86/tablegen/cpp-compiler/cpp-gen.odin | 24 ++++++++++++------- src/asm_tables.cpp | 6 +++-- src/asm_tables_amd64.cpp | 18 ++++++++++++-- src/check_asm.cpp | 14 +++++------ src/main.cpp | 2 +- 8 files changed, 71 insertions(+), 27 deletions(-) diff --git a/core/rexcode/isa/riscv/encoder.odin b/core/rexcode/isa/riscv/encoder.odin index 62a104fe2..e37d7e8c8 100644 --- a/core/rexcode/isa/riscv/encoder.odin +++ b/core/rexcode/isa/riscv/encoder.odin @@ -455,6 +455,10 @@ resolve_relocation_inline :: #force_inline proc( return true } +is_implicit_op_inline :: #force_inline proc "contextless" (op: Operand_Type) -> bool { + return op == .GPR_SP +} + // ============================================================================= // Scatter / gather helpers for B-type and J-type immediates // ============================================================================= diff --git a/core/rexcode/isa/riscv/encoding_types.odin b/core/rexcode/isa/riscv/encoding_types.odin index a89151ba4..bf3e1bd11 100644 --- a/core/rexcode/isa/riscv/encoding_types.odin +++ b/core/rexcode/isa/riscv/encoding_types.odin @@ -52,11 +52,12 @@ Feature :: enum u8 { } Encoding_Flags :: bit_field u8 { - rv32_only: bool | 1, // RV32 base only - rv64_only: bool | 1, // RV64 base only (e.g. LD/SD/ADDIW/...) - branch: bool | 1, // changes PC - fp_round: bool | 1, // funct3 doubles as FP rounding-mode field - _: u8 | 4, + rv32_only: bool | 1, // RV32 base only + rv64_only: bool | 1, // RV64 base only (e.g. LD/SD/ADDIW/...) + branch: bool | 1, // changes PC + fp_round: bool | 1, // funct3 doubles as FP rounding-mode field + explicit_count: u8 | 3, + has_implicit: bool | 1, } // What the user passes in. @@ -149,7 +150,7 @@ Encoding :: struct #packed { enc: [4]Operand_Encoding, // 4 bits: u32, // 4 -- static bit pattern mask: u32, // 4 -- which bits are static - feature: Feature, // 1 + feature: Feature, // 1 flags: Encoding_Flags, // 1 } #assert(size_of(Encoding) == 20) diff --git a/core/rexcode/isa/riscv/tablegen/gen.odin b/core/rexcode/isa/riscv/tablegen/gen.odin index 8ad85fcef..0a7ee797a 100644 --- a/core/rexcode/isa/riscv/tablegen/gen.odin +++ b/core/rexcode/isa/riscv/tablegen/gen.odin @@ -113,7 +113,22 @@ emit_encode_tables :: proc() -> (total: int) { fmt.sbprintfln(&sb, "\t// .%v", m) for &form in forms { f := &form.encoding - write_row(&sb, f.mnemonic, f.ops, f.enc, f.bits, f.mask, f.feature, f.flags) + flags := f.flags + + encoding_operand_count: u8 = 0 + has_implicit := false + for op_type in f.ops { + if op_type == .NONE { break } + if lib.is_implicit_op_inline(op_type) { + has_implicit = true + } else { + encoding_operand_count += 1 + } + } + flags.explicit_count = encoding_operand_count + flags.has_implicit = has_implicit + + write_row(&sb, f.mnemonic, f.ops, f.enc, f.bits, f.mask, f.feature, flags) } } strings.write_string(&sb, "}\n\n") diff --git a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin index bd4cc4e11..05471442c 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -309,6 +309,20 @@ main :: proc() { // NOTE: SideEffectFlag_HINT deliberately excluded — inert, may be DCE'd. return ((side_effects & VOLATILE_SE) != 0); } + + u8 is_call_or_mem() const { + return (cast(u16)side_effects & SideEffectFlag_CONTROL) != 0 || + (cast(u16)implicit_wr & ClobberReg_RSP) != 0; + } + bool has_control() const { + return (cast(u16)side_effects & SideEffectFlag_CONTROL) != 0; + } + bool has_halt() const { + return (cast(u16)side_effects & SideEffectFlag_HALT) != 0; + } + bool is_conditional() const { + return has_control() && (cast(u16)flags_rd != 0); + } }; void clobber_implicit_regs(StringSet *clobber_registers_set, u16 implicit_regs) { @@ -381,13 +395,6 @@ main :: proc() { fmt.sbprintf(&sb, "return cast(u8)((flags>>%du)&((1u<<%d)-1));", bit_offset, bit_size) strings.write_string(&sb, " }\n") } - { - bit_offset := intrinsics.type_field_bit_offset(Encoding_Flags, "op_count") - bit_size := intrinsics.type_field_bit_size(Encoding_Flags, "op_count") - strings.write_string(&sb, "\t\tu8 op_count () const { ") - fmt.sbprintf(&sb, "return cast(u8)((flags>>%du)&((1u<<%d)-1));", bit_offset, bit_size) - strings.write_string(&sb, " }\n") - } { bit_offset := intrinsics.type_field_bit_offset(Encoding_Flags, "lock_ok") strings.write_string(&sb, "\t\tbool lock_ok () const { ") @@ -421,7 +428,8 @@ main :: proc() { strings.write_string(&sb, """ - bool init() { + bool init(i64 word_size) { + gb_unused(word_size); string_map_init(&mnemonic_map, MNEMONIC_COUNT*2); for (u16 m = M_INVALID+1; m < MNEMONIC_COUNT; m++) { string_map_set(&mnemonic_map, mnemonic_strings[m], cast(Mnemonic)m); diff --git a/src/asm_tables.cpp b/src/asm_tables.cpp index eb7e3c109..e2ede6508 100644 --- a/src/asm_tables.cpp +++ b/src/asm_tables.cpp @@ -54,7 +54,9 @@ gb_global String const asm_operand_kind_expected_strings[AsmOperand_COUNT] = { }; #include "asm_tables_amd64.cpp" +#include "asm_tables_riscv.cpp" -void init_asm_tables() { - g_asm_amd64.init(); +void init_asm_tables(i64 word_size) { + g_asm_amd64.init(word_size); + g_asm_riscv.init(word_size); } \ No newline at end of file diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index 06d583ad7..aa3148416 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -312,6 +312,20 @@ struct Asm_amd64 { // NOTE: SideEffectFlag_HINT deliberately excluded — inert, may be DCE'd. return ((side_effects & VOLATILE_SE) != 0); } + + u8 is_call_or_mem() const { + return (cast(u16)side_effects & SideEffectFlag_CONTROL) != 0 || + (cast(u16)implicit_wr & ClobberReg_RSP) != 0; + } + bool has_control() const { + return (cast(u16)side_effects & SideEffectFlag_CONTROL) != 0; + } + bool has_halt() const { + return (cast(u16)side_effects & SideEffectFlag_HALT) != 0; + } + bool is_conditional() const { + return has_control() && (cast(u16)flags_rd != 0); + } }; void clobber_implicit_regs(StringSet *clobber_registers_set, u16 implicit_regs) { @@ -424,7 +438,6 @@ struct Asm_amd64 { bool has_implicit () const { return ((flags>>21u)&1) != 0; } u8 explicit_count() const { return cast(u8)((flags>>18u)&((1u<<3)-1)); } - u8 op_count () const { return cast(u8)((flags>>22u)&((1u<<3)-1)); } bool lock_ok () const { return ((flags>>14u)&1) != 0; } bool rep_ok () const { return ((flags>>15u)&1) != 0; } }; @@ -447,7 +460,8 @@ struct Asm_amd64 { StringMap prefix_map; StringMap register_map; - bool init() { + bool init(i64 word_size) { + gb_unused(word_size); string_map_init(&mnemonic_map, MNEMONIC_COUNT*2); for (u16 m = M_INVALID+1; m < MNEMONIC_COUNT; m++) { string_map_set(&mnemonic_map, mnemonic_strings[m], cast(Mnemonic)m); diff --git a/src/check_asm.cpp b/src/check_asm.cpp index d2fec1525..e7f4b6e75 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -1080,8 +1080,7 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm // aligned at the call boundary) or manipulates RSP directly. Plain memory access // through a parameter pointer does NOT require stack realignment, so // implies_clobber_memory() is intentionally NOT used here. - if ((cast(u16)clobber.side_effects & asm_ctx->SideEffectFlag_CONTROL) != 0 || - (cast(u16)clobber.implicit_wr & asm_ctx->ClobberReg_RSP) != 0) { + if (clobber.is_call_or_mem()) { asm_acc->saw_call_or_mem = true; } @@ -1159,17 +1158,16 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm // is not merely CONTROL-with-fallthrough. We approximate "unconditional" as // CONTROL|HALT with no explicit label/operand fallthrough below. { - u16 se = cast(u16)clobber.side_effects; - bool control = (se & asm_ctx->SideEffectFlag_CONTROL) != 0; - bool halt = (se & asm_ctx->SideEffectFlag_HALT) != 0; + bool control = clobber.has_control(); + bool halt = clobber.has_halt(); // A conditional branch reads a flag and can fall through -> not terminal. - bool conditional = control && (cast(u16)clobber.flags_rd != 0); + bool conditional = clobber.is_conditional(); asm_acc->last_is_terminal = halt || (control && !conditional); } // A branch/call inside the template means subsequent instructions may be reached // out of textual order; stop trusting the linear def model past this point. - if (cast(u16)clobber.side_effects & asm_ctx->SideEffectFlag_CONTROL) { + if (clobber.has_control()) { asm_acc->straight_line = false; } asm_ctx->clobber_implicit_regs(&tmpl_entity->AsmTemplate.clobber_registers_set, produced); @@ -2126,6 +2124,8 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity gb_internal void check_asm_template_from_entity(CheckerContext *c, Entity *e, DeclInfo *d) { if (build_context.metrics.arch == TargetArch_amd64) { check_asm_template(&g_asm_amd64, c, e, d); + } else if (build_context.metrics.arch == TargetArch_riscv64) { + check_asm_template(&g_asm_riscv, c, e, d); } else { error(e->token, "asm templates are not currently supported for this target"); } diff --git a/src/main.cpp b/src/main.cpp index 28b1464cf..84ec22bdf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4321,7 +4321,7 @@ int main(int arg_count, char const **arg_ptr) { bool failed_to_cache_parsing = false; TIME_SECTION("init asm tables"); - init_asm_tables(); + init_asm_tables(build_context.metrics.ptr_size); MAIN_TIME_SECTION("parse files"); From 43ff42bf33d51d87f3572c9c93eeea32010e1130 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Aug 2026 14:44:10 +0100 Subject: [PATCH 04/20] Add asm_tables_riscv.cpp --- src/asm_tables_riscv.cpp | 716 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 716 insertions(+) create mode 100644 src/asm_tables_riscv.cpp diff --git a/src/asm_tables_riscv.cpp b/src/asm_tables_riscv.cpp new file mode 100644 index 000000000..7b6503797 --- /dev/null +++ b/src/asm_tables_riscv.cpp @@ -0,0 +1,716 @@ +// ============================================================================= +// GENERATED FILE - DO NOT EDIT +// ============================================================================= +// +// Produces a C++ equivalent of the encoding table from core:rexcode written in Odin +// odin run tablegen # Stage A: ENCODING_TABLE -> generated/ + this file +// odin run tablegen/generated # Stage B: typed Odin literals -> tables/*.bin +// odin run tablegen/cpp-compiler # Stage C: typed Odin literals -> C++ literals +// + + +struct Asm_riscv { + enum Mnemonic : u16 { + M_INVALID, M_LUI, M_AUIPC, M_JAL, M_JALR, M_BEQ, M_BNE, M_BLT, M_BGE, M_BLTU, M_BGEU, M_LB, M_LH, M_LW, M_LBU, M_LHU, + M_SB, M_SH, M_SW, M_LWU, M_LD, M_SD, M_ADDI, M_SLTI, M_SLTIU, M_XORI, M_ORI, M_ANDI, M_SLLI, M_SRLI, M_SRAI, M_ADDIW, + M_SLLIW, M_SRLIW, M_SRAIW, M_ADD, M_SUB, M_SLL, M_SLT, M_SLTU, M_XOR, M_SRL, M_SRA, M_OR, M_AND, M_ADDW, M_SUBW, M_SLLW, + M_SRLW, M_SRAW, M_FENCE, M_FENCE_I, M_ECALL, M_EBREAK, M_CSRRW, M_CSRRS, M_CSRRC, M_CSRRWI, M_CSRRSI, M_CSRRCI, M_MUL, M_MULH, M_MULHSU, M_MULHU, + M_DIV, M_DIVU, M_REM, M_REMU, M_MULW, M_DIVW, M_DIVUW, M_REMW, M_REMUW, M_LR_W, M_SC_W, M_AMOSWAP_W, M_AMOADD_W, M_AMOXOR_W, M_AMOAND_W, M_AMOOR_W, + M_AMOMIN_W, M_AMOMAX_W, M_AMOMINU_W, M_AMOMAXU_W, M_LR_D, M_SC_D, M_AMOSWAP_D, M_AMOADD_D, M_AMOXOR_D, M_AMOAND_D, M_AMOOR_D, M_AMOMIN_D, M_AMOMAX_D, M_AMOMINU_D, M_AMOMAXU_D, M_FLW, + M_FSW, M_FMADD_S, M_FMSUB_S, M_FNMSUB_S, M_FNMADD_S, M_FADD_S, M_FSUB_S, M_FMUL_S, M_FDIV_S, M_FSQRT_S, M_FSGNJ_S, M_FSGNJN_S, M_FSGNJX_S, M_FMIN_S, M_FMAX_S, M_FCVT_W_S, + M_FCVT_WU_S, M_FMV_X_W, M_FEQ_S, M_FLT_S, M_FLE_S, M_FCLASS_S, M_FCVT_S_W, M_FCVT_S_WU, M_FMV_W_X, M_FCVT_L_S, M_FCVT_LU_S, M_FCVT_S_L, M_FCVT_S_LU, M_FLD, M_FSD, M_FMADD_D, + M_FMSUB_D, M_FNMSUB_D, M_FNMADD_D, M_FADD_D, M_FSUB_D, M_FMUL_D, M_FDIV_D, M_FSQRT_D, M_FSGNJ_D, M_FSGNJN_D, M_FSGNJX_D, M_FMIN_D, M_FMAX_D, M_FCVT_S_D, M_FCVT_D_S, M_FEQ_D, + M_FLT_D, M_FLE_D, M_FCLASS_D, M_FCVT_W_D, M_FCVT_WU_D, M_FCVT_D_W, M_FCVT_D_WU, M_FCVT_L_D, M_FCVT_LU_D, M_FCVT_D_L, M_FCVT_D_LU, M_FMV_X_D, M_FMV_D_X, M_C_NOP, M_C_EBREAK, M_C_ADDI4SPN, + M_C_LW, M_C_LD, M_C_SW, M_C_SD, M_C_FLW, M_C_FSW, M_C_FLD, M_C_FSD, M_C_ADDI, M_C_ADDIW, M_C_LI, M_C_LUI, M_C_ADDI16SP, M_C_SRLI, M_C_SRAI, M_C_ANDI, + M_C_SUB, M_C_XOR, M_C_OR, M_C_AND, M_C_SUBW, M_C_ADDW, M_C_J, M_C_JAL, M_C_BEQZ, M_C_BNEZ, M_C_SLLI, M_C_LWSP, M_C_LDSP, M_C_SWSP, M_C_SDSP, M_C_FLDSP, + M_C_FSDSP, M_C_JR, M_C_JALR, M_C_MV, M_C_ADD, M_C_FLWSP, M_C_FSWSP, + + MNEMONIC_COUNT + }; + static String const mnemonic_strings[MNEMONIC_COUNT]; + + enum Prefix : u8 { + PREFIX_INVALID, + PREFIX_COUNT + }; + enum PrefixKind : u8 { PrefixKind_None }; + + + static const u16 REG_CLASS_NONE = 0x000; + static const u16 REG_CLASS_GPR64 = 0x100; + static const u16 REG_CLASS_GPR32 = 0x200; + static const u16 REG_CLASS_GPR16 = 0x300; + static const u16 REG_CLASS_GPR8 = 0x400; + static const u16 REG_CLASS_GPR8H = 0x500; // AH, CH, DH, BH - legacy high byte regs + static const u16 REG_CLASS_XMM = 0x600; + static const u16 REG_CLASS_YMM = 0x700; + static const u16 REG_CLASS_ZMM = 0x800; + static const u16 REG_CLASS_K = 0x900; // opmask + static const u16 REG_CLASS_SEG = 0xA00; // segment + static const u16 REG_CLASS_CR = 0xB00; // control + static const u16 REG_CLASS_DR = 0xC00; // debug + static const u16 REG_CLASS_BND = 0xD00; // bound + static const u16 REG_CLASS_MM = 0xE00; // MMX + static const u16 REG_CLASS_ST = 0xF00; // x87 FPU + + enum Register : u16 { + REG_INVALID, REG_ZERO, REG_RA, REG_SP, REG_GP, REG_TP, REG_T0, REG_T1, REG_T2, REG_S0, REG_S1, REG_A0, REG_A1, REG_A2, REG_A3, REG_A4, + REG_A5, REG_A6, REG_A7, REG_S2, REG_S3, REG_S4, REG_S5, REG_S6, REG_S7, REG_S8, REG_S9, REG_S10, REG_S11, REG_T3, REG_T4, REG_T5, + REG_T6, REG_FT0, REG_FT1, REG_FT2, REG_FT3, REG_FT4, REG_FT5, REG_FT6, REG_FT7, REG_FS0, REG_FS1, REG_FA0, REG_FA1, REG_FA2, REG_FA3, REG_FA4, + REG_FA5, REG_FA6, REG_FA7, REG_FS2, REG_FS3, REG_FS4, REG_FS5, REG_FS6, REG_FS7, REG_FS8, REG_FS9, REG_FS10, REG_FS11, REG_FT8, REG_FT9, REG_FT10, + REG_FT11, + REG_COUNT + }; + + + enum ClobberFFlags : u8 { + ClobberFFlag_NV = 1<<0, // invalid operation + ClobberFFlag_DZ = 1<<1, // divide by zero + ClobberFFlag_OF = 1<<2, // overflow + ClobberFFlag_UF = 1<<3, // underflow + ClobberFFlag_NX = 1<<4, // inexact + }; + + enum ClobberRegs : u8 { + ClobberReg_RA = 1<<0, // x1, implicit link on C.JAL / C.JALR + ClobberReg_SP = 1<<1, // x2, implicit base on the *SP compressed forms + }; + + static u8 const CLOBBER_REGS_NAMED = ClobberReg_RA|ClobberReg_SP; + + enum SideEffectFlags : u8 { + SideEffectFlag_CONTROL = 1<<0, // writes pc: branches, jumps, and trap redirects + SideEffectFlag_TRAP = 1<<1, // synchronous environment trap (ECALL / EBREAK) + SideEffectFlag_FENCE = 1<<2, // explicit memory-ordering barrier (FENCE) + SideEffectFlag_IFENCE = 1<<3, // instruction-fetch synchronization (FENCE.I) + SideEffectFlag_ATOMIC = 1<<4, // indivisible memory RMW (AMO*, and the LR/SC pair) + SideEffectFlag_RESERVATION = 1<<5, // sets or tests an LR/SC reservation + }; + + enum OperandSet : u8 { + OperandSet_OP0 = 1<<0, + OperandSet_OP1 = 1<<1, + OperandSet_OP2 = 1<<2, + OperandSet_OP3 = 1<<3, + }; + + u16 clobber_bit_for_reg_name(String const &pin) { + static const struct { String name; u16 bit; } table[] = { + {str_lit("ra"), ClobberReg_RA}, + {str_lit("sp"), ClobberReg_SP}, + {str_lit("x1"), ClobberReg_RA}, + {str_lit("x2"), ClobberReg_SP}, + }; + for (auto const &t : table) { + if (pin == t.name) { + return t.bit; + } + } + return 0; + } + + char const *clobber_reg_bit_name(u16 bit) { + switch (bit) { + case ClobberReg_RA: return "ra"; + case ClobberReg_SP: return "sp"; + } + return ""; + } + + i32 flag_bit_from_name(String const &name, i32 *width_) { + static const struct { String name; i32 bit; } table[] = { + // fflags: accrued FP exception flags (fcsr[4:0]) + {str_lit("nx"), 0}, // Inexact + {str_lit("uf"), 1}, // Underflow + {str_lit("of"), 2}, // Overflow + {str_lit("dz"), 3}, // Divide by Zero + {str_lit("nv"), 4}, // Invalid Operation + // frm: rounding mode (fcsr[7:5], 3-bit field, low bit) + {str_lit("frm"), 5}, // Rounding Mode + }; + + for (auto const &t : table) { + if (name == t.name) { + if (width_) { + if (t.name == "frm") { + *width_ = 3; + } else { + *width_ = 1; + } + } + return t.bit; + } + } + return -1; + } + + + struct Clobber { + OperandSet written; // operand slots whose register/CSR is written + OperandSet read; // operand slots whose register/CSR/mem-base is read + ClobberRegs implicit_wr; // implicit reg writes (ra on C.JAL/C.JALR) + ClobberRegs implicit_rd; // implicit reg reads (sp on the *SP forms) + ClobberFFlags fflags_wr; // accrued exception flags this op may raise + bool reads_frm; // consumes the dynamic rounding mode from fcsr + bool writes_mem; + bool reads_mem; + SideEffectFlags side_effects; + + bool implies_clobber_flags() const { + return (fflags_wr != 0); + } + bool implies_clobber_memory() const { + return writes_mem || reads_mem || + (side_effects & (SideEffectFlag_FENCE|SideEffectFlag_ATOMIC)) != 0; + } + bool implies_side_effects() const { + return side_effects != 0; + } + u8 is_call_or_mem() const { + return (cast(u16)side_effects & SideEffectFlag_CONTROL) != 0 || + (cast(u16)implicit_wr & ClobberReg_SP) != 0; + } + bool has_control() const { + return (cast(u16)side_effects & SideEffectFlag_CONTROL) != 0; + } + bool has_halt() const { + return false; + } + bool is_conditional() const { + return has_control(); + } + }; + + void clobber_implicit_regs(StringSet *clobber_registers_set, u16 implicit_regs) { + u8 regs = cast(u8)implicit_regs; + + for (u8 bit = 1; bit != 0; bit <<= 1) { + if ((regs & bit) == 0) { + continue; + } + char const *rname = clobber_reg_bit_name(bit); + string_set_update(clobber_registers_set, make_string_c(rname)); + } + } + static u16 const register_codes [REG_COUNT]; + static String const register_strings[REG_COUNT]; + + + enum OperandType : u8 { + OP_NONE, + OP_GPR, + OP_FPR, + OP_IMM12, + OP_IMM12U, + OP_IMM5, + OP_IMM6, + OP_IMM20, + OP_REL13, + OP_REL21, + OP_MEM, + OP_CSR, + OP_FENCE_FLAGS, + OP_ROUND_MODE, + OP_ZIMM5, + OP_GPR_C, + OP_GPR_SP, + OP_GPR_NONZERO, + OP_FPR_C, + OP_IMM_C6S, + OP_IMM_C6U, + OP_IMM_C8U, + OP_IMM_C10S, + OP_IMM_C18S, + OP_REL9, + OP_REL12, + OP_MEM_C_W, + OP_MEM_C_D, + OP_MEM_C_SP_W, + OP_MEM_C_SP_D, + }; + + + enum OperandEncoding : u8 { + ENC_NONE, + ENC_RD, + ENC_RS1, + ENC_RS2, + ENC_RS3, + ENC_SHAMT5, + ENC_SHAMT6, + ENC_IMM_I, + ENC_IMM_S, + ENC_IMM_B, + ENC_IMM_U, + ENC_IMM_J, + ENC_OFFSET_BASE_I, + ENC_OFFSET_BASE_S, + ENC_OFFSET_BASE_A, + ENC_CSR_FIELD, + ENC_ZIMM_FIELD, + ENC_FENCE_PRED, + ENC_FENCE_SUCC, + ENC_ROUND_FIELD, + ENC_AQRL, + ENC_C_RD_RS1, + ENC_C_RS2, + ENC_C_RD_PRIMED, + ENC_C_RS1_PRIMED, + ENC_C_RS2_PRIMED, + ENC_C_RD_RS1_PRIMED, + ENC_C_IMM_CI_S, + ENC_C_IMM_CI_U, + ENC_C_IMM_CIW, + ENC_C_IMM_LUI, + ENC_C_IMM_ADDI16SP, + ENC_C_IMM_CSS_W, + ENC_C_IMM_CSS_D, + ENC_C_IMM_CL_W, + ENC_C_IMM_CL_D, + ENC_C_BRANCH9, + ENC_C_BRANCH12, + ENC_C_OFFSET_BASE_W, + ENC_C_OFFSET_BASE_D, + ENC_C_SP_OFFSET_W, + ENC_C_SP_OFFSET_D, + }; + + + enum Feature : u8 { + ENC_I, + ENC_M, + ENC_A, + ENC_F, + ENC_D, + ENC_ZICSR, + ENC_ZIFENCEI, + ENC_C, + }; + + typedef u8 EncodingFlags; // cannot use a C++ bit field to due lack of portability + + #pragma pack(push, 1) + struct Encoding { + Mnemonic mnemonic; + OperandType ops[4]; + OperandEncoding enc[4]; + u32 bits; + u32 mask; + Feature feature; + EncodingFlags flags; + + bool has_implicit () const { return ((flags>>7u)&1) != 0; } + u8 explicit_count() const { return cast(u8)((flags>>4u)&((1u<<3)-1)); } + }; + #pragma pack(pop) + GB_STATIC_ASSERT(gb_size_of(Encoding) == 20); + + + // Companion run index: ENCODE_RUNS[mnemonic] -> contiguous run in ENCODE_FORMS. + struct EncodeRun { + u32 start; // start index in ENCODE_FORMS + u32 count; // number of forms for this mnemonic + }; + + + static EncodeRun const raw_encode_runs [199]; + static u8 const raw_encode_forms [3960]; + static u8 const raw_clobber_forms[1782]; + + StringMap mnemonic_map; + StringMap register_map; + + u16 XLEN; + u16 FLEN; + + bool init(i64 word_size) { + XLEN = cast(u16)word_size; + FLEN = cast(u16)word_size; + + string_map_init(&mnemonic_map, MNEMONIC_COUNT*2); + for (u16 m = M_INVALID+1; m < MNEMONIC_COUNT; m++) { + string_map_set(&mnemonic_map, mnemonic_strings[m], cast(Mnemonic)m); + } + string_map_init(®ister_map, REG_COUNT*2); + for (u16 r = REG_INVALID+1; r < REG_COUNT; r++) { + string_map_set(®ister_map, register_strings[r], cast(Register)r); + } + return true; + } + + Mnemonic mnemonic_lookup(String const &name) { + Mnemonic *found = string_map_get(&mnemonic_map, name); + return found ? *found : M_INVALID; + } + Prefix prefix_lookup(String const &name) { + return PREFIX_INVALID; + } + static String const prefix_strings[PREFIX_COUNT]; + + Register register_lookup(String const &name) { + Register *found = string_map_get(®ister_map, name); + return found ? *found : REG_INVALID; + } + Slice encoding_forms(/*Mnemonic*/ u16 m) const { + EncodeRun r = raw_encode_runs[m]; + Encoding *ENCODE_FORMS = cast(Encoding *)raw_encode_forms; + return Slice{ENCODE_FORMS+r.start, r.count}; + } + Slice clobber_forms(/*Mnemonic*/ u16 m) const { + EncodeRun r = raw_encode_runs[m]; + Clobber *CLOBBER_FORMS = cast(Clobber *)raw_clobber_forms; + return Slice{CLOBBER_FORMS+r.start, r.count}; + } + u16 reg_class(/*Register*/ u16 r) const { + return 0xFF00 & r; + } + // size in bits for register + u16 reg_size(Register r) const { + switch (reg_class(register_codes[r])) { + case REG_CLASS_GPR64: return 64; + case REG_CLASS_GPR32: return 32; + case REG_CLASS_GPR16: return 16; + case REG_CLASS_GPR8: return 8; + case REG_CLASS_GPR8H: return 8; + case REG_CLASS_XMM: return 128; + case REG_CLASS_YMM: return 256; + case REG_CLASS_ZMM: return 512; + case REG_CLASS_K: return 64; + case REG_CLASS_MM: return 64; + case REG_CLASS_ST: return 80; + case REG_CLASS_SEG: return 16; + case REG_CLASS_CR: return 64; + case REG_CLASS_DR: return 64; + case REG_CLASS_BND: return 128; + } + return 0; + } + + AsmOperandKind kind_from_operand_type(OperandType type) const { + switch (type) { + case OP_NONE: + return AsmOperand_Invalid; + + // Registers + case OP_GPR: + case OP_FPR: + case OP_GPR_C: + case OP_GPR_SP: + case OP_GPR_NONZERO: + case OP_FPR_C: + return AsmOperand_Register; + + case OP_CSR: // 12-bit CSR address; treat as immediate (no CSR reg class exists) + // TODO(bill): what should this be? + return AsmOperand_Immediate; + + // Immediates (incl. things that ultimately encode as an immediate field: + // CSR address, fence flags, rounding mode). + case OP_IMM12: + case OP_IMM12U: + case OP_IMM5: + case OP_IMM6: + case OP_IMM20: + case OP_FENCE_FLAGS: // iorw mask -> 4-bit immediate field + case OP_ROUND_MODE: // rm -> 3-bit immediate field + case OP_ZIMM5: + case OP_IMM_C6S: + case OP_IMM_C6U: + case OP_IMM_C8U: + case OP_IMM_C10S: + case OP_IMM_C18S: + return AsmOperand_Immediate; + + // Branch/jump targets are written as labels. + case OP_REL13: + case OP_REL21: + case OP_REL9: + case OP_REL12: + return AsmOperand_Label; + + // Memory + case OP_MEM: + case OP_MEM_C_W: + case OP_MEM_C_D: + case OP_MEM_C_SP_W: + case OP_MEM_C_SP_D: + return AsmOperand_Memory; + } + return AsmOperand_Invalid; + } + + AsmRegClass reg_class_from_operand_type(OperandType type) const { + switch (type) { + case OP_GPR: + case OP_GPR_C: + case OP_GPR_SP: + case OP_GPR_NONZERO: + return AsmRegClass_Integer; + + case OP_FPR: + case OP_FPR_C: + return AsmRegClass_Float; + + // No vector/mask operand types are present in this list; everything + // else (immediates, memory, labels, CSR, etc.) has no register class. + default: + return AsmRegClass_Unknown; + } + } + + bool operand_type_is_implicit(OperandType t) const { + switch (t) { + // sp is fixed by the mnemonic (c.addi16sp / c.*sp bases) and isn't a + // register the user freely chooses, so it's encoded implicitly. + // If your parser actually reads `sp` from the operand text, flip this. + case OP_GPR_SP: + return true; + default: + return false; + } + } + + AsmRegClass operand_type_reg_class(OperandType t) const { + // Same mapping as reg_class_from_operand_type — these two look + // redundant; consider collapsing them into one. + return reg_class_from_operand_type(t); + } + + u16 operand_type_bit_width(OperandType t) const { + switch (t) { + case OP_NONE: + return 0; + + // Registers -> architectural register data width (like OP_R*, OP_XMM). + // RISC-V doesn't encode width in the operand type: GPR is XLEN, FPR is + // FLEN, both target-config dependent -> treat as data-dependent = 0, + // same as x86 OP_K. (Or hardcode 32/64 if your assembler is fixed-config.) + // The _C / _SP / _NONZERO variants only restrict *which* regs, not width. + case OP_GPR: + case OP_GPR_C: + case OP_GPR_SP: + case OP_GPR_NONZERO: + return XLEN; + case OP_FPR: + case OP_FPR_C: + return FLEN; + + // Memory -> access size (like OP_M*). Base OP_MEM's size comes from the + // opcode, so it's sizeless like x86 OP_M. Compressed forms name the size. + case OP_MEM: + return 0; + case OP_MEM_C_W: + case OP_MEM_C_SP_W: + return 32; + case OP_MEM_C_D: + case OP_MEM_C_SP_D: + return 64; + + // Immediates -> value width (unchanged; matches x86 OP_IMM*). + case OP_IMM12: + case OP_IMM12U: + case OP_CSR: + return 12; + case OP_IMM5: + case OP_ZIMM5: + return 5; + case OP_IMM6: + return 6; + case OP_IMM20: + return 20; + case OP_FENCE_FLAGS: + return 4; + case OP_ROUND_MODE: + return 3; + case OP_IMM_C6S: + case OP_IMM_C6U: + return 6; + case OP_IMM_C8U: + return 8; + case OP_IMM_C10S: + return 10; + case OP_IMM_C18S: + return 18; + + // Rels -> displacement value width (unchanged; matches x86 OP_REL*). + case OP_REL13: + return 13; + case OP_REL21: + return 21; + case OP_REL9: + return 9; + case OP_REL12: + return 12; + } + return 0; + } + + int form_explicit_slot(Encoding const &form, int explicit_index) const { + int seen = 0; + for (int j = 0; j < gb_count_of(form.ops); j++) { + auto t = form.ops[j]; + if (!t) { + break; + } + if (operand_type_is_implicit(t)) { + continue; + } + if (seen == explicit_index) { + return j; + } + seen += 1; + } + return -1; + } + + bool prefix_kind_okay(u8 prefix, Encoding const &form, bool *requires_memory_dest_) const { + // RISC-V does not have prefixes + return false; + } +}; + + + +gb_global Asm_riscv g_asm_riscv; + + + +String const Asm_riscv::prefix_strings[Asm_riscv::PREFIX_COUNT]{}; +String const Asm_riscv::mnemonic_strings[Asm_riscv::MNEMONIC_COUNT] { + str_lit(""), str_lit("lui"), str_lit("auipc"), str_lit("jal"), str_lit("jalr"), str_lit("beq"), str_lit("bne"), str_lit("blt"), str_lit("bge"), str_lit("bltu"), str_lit("bgeu"), str_lit("lb"), str_lit("lh"), str_lit("lw"), str_lit("lbu"), str_lit("lhu"), + str_lit("sb"), str_lit("sh"), str_lit("sw"), str_lit("lwu"), str_lit("ld"), str_lit("sd"), str_lit("addi"), str_lit("slti"), str_lit("sltiu"), str_lit("xori"), str_lit("ori"), str_lit("andi"), str_lit("slli"), str_lit("srli"), str_lit("srai"), str_lit("addiw"), + str_lit("slliw"), str_lit("srliw"), str_lit("sraiw"), str_lit("add"), str_lit("sub"), str_lit("sll"), str_lit("slt"), str_lit("sltu"), str_lit("xor"), str_lit("srl"), str_lit("sra"), str_lit("or"), str_lit("and"), str_lit("addw"), str_lit("subw"), str_lit("sllw"), + str_lit("srlw"), str_lit("sraw"), str_lit("fence"), str_lit("fence_i"), str_lit("ecall"), str_lit("ebreak"), str_lit("csrrw"), str_lit("csrrs"), str_lit("csrrc"), str_lit("csrrwi"), str_lit("csrrsi"), str_lit("csrrci"), str_lit("mul"), str_lit("mulh"), str_lit("mulhsu"), str_lit("mulhu"), + str_lit("div"), str_lit("divu"), str_lit("rem"), str_lit("remu"), str_lit("mulw"), str_lit("divw"), str_lit("divuw"), str_lit("remw"), str_lit("remuw"), str_lit("lr_w"), str_lit("sc_w"), str_lit("amoswap_w"), str_lit("amoadd_w"), str_lit("amoxor_w"), str_lit("amoand_w"), str_lit("amoor_w"), + str_lit("amomin_w"), str_lit("amomax_w"), str_lit("amominu_w"), str_lit("amomaxu_w"), str_lit("lr_d"), str_lit("sc_d"), str_lit("amoswap_d"), str_lit("amoadd_d"), str_lit("amoxor_d"), str_lit("amoand_d"), str_lit("amoor_d"), str_lit("amomin_d"), str_lit("amomax_d"), str_lit("amominu_d"), str_lit("amomaxu_d"), str_lit("flw"), + str_lit("fsw"), str_lit("fmadd_s"), str_lit("fmsub_s"), str_lit("fnmsub_s"), str_lit("fnmadd_s"), str_lit("fadd_s"), str_lit("fsub_s"), str_lit("fmul_s"), str_lit("fdiv_s"), str_lit("fsqrt_s"), str_lit("fsgnj_s"), str_lit("fsgnjn_s"), str_lit("fsgnjx_s"), str_lit("fmin_s"), str_lit("fmax_s"), str_lit("fcvt_w_s"), + str_lit("fcvt_wu_s"), str_lit("fmv_x_w"), str_lit("feq_s"), str_lit("flt_s"), str_lit("fle_s"), str_lit("fclass_s"), str_lit("fcvt_s_w"), str_lit("fcvt_s_wu"), str_lit("fmv_w_x"), str_lit("fcvt_l_s"), str_lit("fcvt_lu_s"), str_lit("fcvt_s_l"), str_lit("fcvt_s_lu"), str_lit("fld"), str_lit("fsd"), str_lit("fmadd_d"), + str_lit("fmsub_d"), str_lit("fnmsub_d"), str_lit("fnmadd_d"), str_lit("fadd_d"), str_lit("fsub_d"), str_lit("fmul_d"), str_lit("fdiv_d"), str_lit("fsqrt_d"), str_lit("fsgnj_d"), str_lit("fsgnjn_d"), str_lit("fsgnjx_d"), str_lit("fmin_d"), str_lit("fmax_d"), str_lit("fcvt_s_d"), str_lit("fcvt_d_s"), str_lit("feq_d"), + str_lit("flt_d"), str_lit("fle_d"), str_lit("fclass_d"), str_lit("fcvt_w_d"), str_lit("fcvt_wu_d"), str_lit("fcvt_d_w"), str_lit("fcvt_d_wu"), str_lit("fcvt_l_d"), str_lit("fcvt_lu_d"), str_lit("fcvt_d_l"), str_lit("fcvt_d_lu"), str_lit("fmv_x_d"), str_lit("fmv_d_x"), str_lit("c_nop"), str_lit("c_ebreak"), str_lit("c_addi4spn"), + str_lit("c_lw"), str_lit("c_ld"), str_lit("c_sw"), str_lit("c_sd"), str_lit("c_flw"), str_lit("c_fsw"), str_lit("c_fld"), str_lit("c_fsd"), str_lit("c_addi"), str_lit("c_addiw"), str_lit("c_li"), str_lit("c_lui"), str_lit("c_addi16sp"), str_lit("c_srli"), str_lit("c_srai"), str_lit("c_andi"), + str_lit("c_sub"), str_lit("c_xor"), str_lit("c_or"), str_lit("c_and"), str_lit("c_subw"), str_lit("c_addw"), str_lit("c_j"), str_lit("c_jal"), str_lit("c_beqz"), str_lit("c_bnez"), str_lit("c_slli"), str_lit("c_lwsp"), str_lit("c_ldsp"), str_lit("c_swsp"), str_lit("c_sdsp"), str_lit("c_fldsp"), + str_lit("c_fsdsp"), str_lit("c_jr"), str_lit("c_jalr"), str_lit("c_mv"), str_lit("c_add"), str_lit("c_flwsp"), str_lit("c_fswsp"), +}; +u16 const Asm_riscv::register_codes[Asm_riscv::REG_COUNT] { + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, + 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, + 527, 528, 529, 530, 531, 532, 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, + 543, +}; +String const Asm_riscv::register_strings[Asm_riscv::REG_COUNT] { + str_lit(""), str_lit("zero"), str_lit("ra"), str_lit("sp"), str_lit("gp"), str_lit("tp"), str_lit("t0"), str_lit("t1"), str_lit("t2"), str_lit("s0"), str_lit("s1"), str_lit("a0"), str_lit("a1"), str_lit("a2"), str_lit("a3"), str_lit("a4"), + str_lit("a5"), str_lit("a6"), str_lit("a7"), str_lit("s2"), str_lit("s3"), str_lit("s4"), str_lit("s5"), str_lit("s6"), str_lit("s7"), str_lit("s8"), str_lit("s9"), str_lit("s10"), str_lit("s11"), str_lit("t3"), str_lit("t4"), str_lit("t5"), + str_lit("t6"), str_lit("ft0"), str_lit("ft1"), str_lit("ft2"), str_lit("ft3"), str_lit("ft4"), str_lit("ft5"), str_lit("ft6"), str_lit("ft7"), str_lit("fs0"), str_lit("fs1"), str_lit("fa0"), str_lit("fa1"), str_lit("fa2"), str_lit("fa3"), str_lit("fa4"), + str_lit("fa5"), str_lit("fa6"), str_lit("fa7"), str_lit("fs2"), str_lit("fs3"), str_lit("fs4"), str_lit("fs5"), str_lit("fs6"), str_lit("fs7"), str_lit("fs8"), str_lit("fs9"), str_lit("fs10"), str_lit("fs11"), str_lit("ft8"), str_lit("ft9"), str_lit("ft10"), + str_lit("ft11"), +}; +Asm_riscv::EncodeRun const Asm_riscv::raw_encode_runs[199] = { + { 0, 0}, { 0, 1}, { 1, 1}, { 2, 1}, { 3, 1}, { 4, 1}, { 5, 1}, { 6, 1}, { 7, 1}, { 8, 1}, { 9, 1}, { 10, 1}, { 11, 1}, { 12, 1}, { 13, 1}, { 14, 1}, + { 15, 1}, { 16, 1}, { 17, 1}, { 18, 1}, { 19, 1}, { 20, 1}, { 21, 1}, { 22, 1}, { 23, 1}, { 24, 1}, { 25, 1}, { 26, 1}, { 27, 1}, { 28, 1}, { 29, 1}, { 30, 1}, + { 31, 1}, { 32, 1}, { 33, 1}, { 34, 1}, { 35, 1}, { 36, 1}, { 37, 1}, { 38, 1}, { 39, 1}, { 40, 1}, { 41, 1}, { 42, 1}, { 43, 1}, { 44, 1}, { 45, 1}, { 46, 1}, + { 47, 1}, { 48, 1}, { 49, 1}, { 50, 1}, { 51, 1}, { 52, 1}, { 53, 1}, { 54, 1}, { 55, 1}, { 56, 1}, { 57, 1}, { 58, 1}, { 59, 1}, { 60, 1}, { 61, 1}, { 62, 1}, + { 63, 1}, { 64, 1}, { 65, 1}, { 66, 1}, { 67, 1}, { 68, 1}, { 69, 1}, { 70, 1}, { 71, 1}, { 72, 1}, { 73, 1}, { 74, 1}, { 75, 1}, { 76, 1}, { 77, 1}, { 78, 1}, + { 79, 1}, { 80, 1}, { 81, 1}, { 82, 1}, { 83, 1}, { 84, 1}, { 85, 1}, { 86, 1}, { 87, 1}, { 88, 1}, { 89, 1}, { 90, 1}, { 91, 1}, { 92, 1}, { 93, 1}, { 94, 1}, + { 95, 1}, { 96, 1}, { 97, 1}, { 98, 1}, { 99, 1}, { 100, 1}, { 101, 1}, { 102, 1}, { 103, 1}, { 104, 1}, { 105, 1}, { 106, 1}, { 107, 1}, { 108, 1}, { 109, 1}, { 110, 1}, + { 111, 1}, { 112, 1}, { 113, 1}, { 114, 1}, { 115, 1}, { 116, 1}, { 117, 1}, { 118, 1}, { 119, 1}, { 120, 1}, { 121, 1}, { 122, 1}, { 123, 1}, { 124, 1}, { 125, 1}, { 126, 1}, + { 127, 1}, { 128, 1}, { 129, 1}, { 130, 1}, { 131, 1}, { 132, 1}, { 133, 1}, { 134, 1}, { 135, 1}, { 136, 1}, { 137, 1}, { 138, 1}, { 139, 1}, { 140, 1}, { 141, 1}, { 142, 1}, + { 143, 1}, { 144, 1}, { 145, 1}, { 146, 1}, { 147, 1}, { 148, 1}, { 149, 1}, { 150, 1}, { 151, 1}, { 152, 1}, { 153, 1}, { 154, 1}, { 155, 1}, { 156, 1}, { 157, 1}, { 158, 1}, + { 159, 1}, { 160, 1}, { 161, 1}, { 162, 1}, { 163, 1}, { 164, 1}, { 165, 1}, { 166, 1}, { 167, 1}, { 168, 1}, { 169, 1}, { 170, 1}, { 171, 1}, { 172, 1}, { 173, 1}, { 174, 1}, + { 175, 1}, { 176, 1}, { 177, 1}, { 178, 1}, { 179, 1}, { 180, 1}, { 181, 1}, { 182, 1}, { 183, 1}, { 184, 1}, { 185, 1}, { 186, 1}, { 187, 1}, { 188, 1}, { 189, 1}, { 190, 1}, + { 191, 1}, { 192, 1}, { 193, 1}, { 194, 1}, { 195, 1}, { 196, 1}, { 197, 1}, +}; +u8 const Asm_riscv::raw_encode_forms[3960] = { + 0x01, 0x00, 0x01, 0x07, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x07, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x09, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x01, 0x01, + 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x67, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x06, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, + 0x09, 0x00, 0x63, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x09, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x0a, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x70, + 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x0b, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x7f, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x01, 0x0a, + 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x02, 0x15, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x02, 0x16, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, + 0x07, 0x00, 0x13, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x60, + 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfc, 0x00, 0x00, 0x1d, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x50, 0x00, 0x00, 0x7f, 0x70, + 0x00, 0xfc, 0x00, 0x00, 0x1e, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x50, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfc, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, + 0x21, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x22, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, 0x50, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x23, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x24, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x00, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x25, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x26, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x27, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x00, 0x33, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x28, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x29, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x2a, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, + 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x2b, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x7f, 0x70, + 0x00, 0xfe, 0x00, 0x02, 0x2e, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x2f, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x30, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, + 0x31, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x32, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x11, 0x12, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x36, 0x00, 0x01, 0x0b, 0x01, 0x00, 0x01, 0x0f, 0x02, 0x00, 0x73, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x37, 0x00, 0x01, 0x0b, 0x01, 0x00, 0x01, 0x0f, + 0x02, 0x00, 0x73, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x38, 0x00, 0x01, 0x0b, 0x01, 0x00, 0x01, 0x0f, 0x02, 0x00, 0x73, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x39, 0x00, 0x01, 0x0b, 0x0e, 0x00, 0x01, 0x0f, 0x10, 0x00, 0x73, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x3a, 0x00, 0x01, 0x0b, 0x0e, 0x00, 0x01, 0x0f, 0x10, 0x00, 0x73, 0x60, + 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x3b, 0x00, 0x01, 0x0b, 0x0e, 0x00, 0x01, 0x0f, 0x10, 0x00, 0x73, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x3c, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x00, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x3d, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x02, 0x7f, 0x70, + 0x00, 0xfe, 0x01, 0x00, 0x3e, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x20, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x3f, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x30, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x40, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x40, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, + 0x41, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x42, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x60, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x43, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x70, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x44, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x45, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x40, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x47, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x00, 0x3b, 0x60, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x48, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x70, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x49, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x2f, 0x20, 0x00, 0x10, 0x7f, 0x70, 0xf0, 0xf9, 0x02, 0x00, 0x4a, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, + 0x00, 0x18, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x4b, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x08, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x4c, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x4d, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x20, 0x7f, 0x70, + 0x00, 0xf8, 0x02, 0x00, 0x4e, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x4f, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x50, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x80, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, + 0x51, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x52, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0xc0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x53, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0xe0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x54, 0x00, 0x01, 0x0a, + 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x2f, 0x30, 0x00, 0x10, 0x7f, 0x70, 0xf0, 0xf9, 0x02, 0x02, 0x55, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x18, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x56, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x08, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x57, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, + 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x58, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x59, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5a, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, + 0x00, 0x40, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5b, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x80, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5c, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5d, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0xc0, 0x7f, 0x70, + 0x00, 0xf8, 0x02, 0x02, 0x5e, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0xe0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5f, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x27, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x03, 0x00, + 0x61, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x43, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x08, 0x62, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x47, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x08, 0x63, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4b, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x08, 0x64, 0x00, 0x02, 0x02, + 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x08, 0x65, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x08, 0x66, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x08, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x08, 0x67, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, + 0x03, 0x00, 0x53, 0x00, 0x00, 0x10, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x08, 0x68, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x18, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x08, 0x69, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0x58, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, 0x6a, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, + 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x6b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x6c, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x6d, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x28, 0x7f, 0x70, + 0x00, 0xfe, 0x03, 0x00, 0x6e, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x28, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x6f, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, 0x70, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, + 0x71, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xe0, 0x7f, 0x70, 0xf0, 0xff, 0x03, 0x00, 0x72, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x73, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x74, 0x00, 0x01, 0x02, + 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x75, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x10, 0x00, 0xe0, 0x7f, 0x70, 0xf0, 0xff, 0x03, 0x00, 0x76, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, 0x77, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x53, 0x00, 0x10, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, 0x78, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xf0, 0x7f, 0x70, 0xf0, 0xff, 0x03, 0x00, 0x79, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x0a, 0x7a, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, + 0x30, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x0a, 0x7b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x0a, 0x7c, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x0a, 0x7d, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x7f, 0x70, + 0x00, 0x00, 0x04, 0x00, 0x7e, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x27, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x43, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x08, 0x80, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x47, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x08, + 0x81, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4b, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x08, 0x82, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4f, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x08, 0x83, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x08, 0x84, 0x00, 0x02, 0x02, + 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x0a, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x08, 0x85, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x12, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x08, 0x86, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x1a, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x08, 0x87, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x53, 0x00, 0x00, 0x5a, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x88, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x22, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x89, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x22, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x8a, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, + 0x00, 0x22, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x8b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x2a, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x8c, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x2a, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x8d, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0x40, 0x7f, 0x00, + 0xf0, 0xff, 0x04, 0x08, 0x8e, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0x42, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x8f, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0xa2, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x90, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0xa2, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, + 0x91, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0xa2, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x92, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x10, 0x00, 0xe2, 0x7f, 0x70, 0xf0, 0xff, 0x04, 0x00, 0x93, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x94, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x95, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x96, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x97, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x53, 0x00, 0x20, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x0a, 0x98, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x0a, 0x99, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x0a, 0x9a, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, + 0x30, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x0a, 0x9b, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xe2, 0x7f, 0x70, 0xf0, 0xff, 0x04, 0x02, 0x9c, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xf2, 0x7f, 0x70, 0xf0, 0xff, 0x04, 0x02, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0x07, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x90, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x07, 0x00, 0x9f, 0x00, 0x0f, 0x10, 0x15, 0x00, 0x17, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xa0, 0x00, 0x0f, 0x1a, 0x00, 0x00, 0x17, 0x26, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, + 0xa1, 0x00, 0x0f, 0x1b, 0x00, 0x00, 0x17, 0x27, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xa2, 0x00, 0x0f, 0x1a, 0x00, 0x00, 0x19, 0x26, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xa3, 0x00, 0x0f, 0x1b, 0x00, 0x00, 0x19, 0x27, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xa4, 0x00, 0x12, 0x1a, + 0x00, 0x00, 0x17, 0x26, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x01, 0xa5, 0x00, 0x12, 0x1a, 0x00, 0x00, 0x19, 0x26, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x01, 0xa6, 0x00, 0x12, 0x1b, 0x00, 0x00, 0x17, 0x27, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0xa7, 0x00, 0x12, 0x1b, 0x00, 0x00, 0x19, 0x27, + 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0xa8, 0x00, 0x11, 0x13, 0x00, 0x00, 0x15, 0x1b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xa9, 0x00, 0x11, 0x13, 0x00, 0x00, 0x15, 0x1b, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xaa, 0x00, 0x11, 0x13, 0x00, 0x00, 0x15, 0x1b, 0x00, 0x00, 0x01, 0x40, + 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xab, 0x00, 0x11, 0x17, 0x00, 0x00, 0x15, 0x1e, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xac, 0x00, 0x10, 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x61, 0x00, 0x00, 0x83, 0xef, 0x00, 0x00, 0x07, 0x00, 0xad, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x1a, 0x1c, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0xec, + 0x00, 0x00, 0x07, 0x00, 0xae, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x1a, 0x1c, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x07, 0x00, 0xaf, 0x00, 0x0f, 0x13, 0x00, 0x00, 0x1a, 0x1b, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x07, 0x00, 0xb0, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, + 0xb1, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x21, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0xb2, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x41, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0xb3, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x61, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0xb4, 0x00, 0x0f, 0x0f, + 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x01, 0x9c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x02, 0xb5, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x21, 0x9c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x02, 0xb6, 0x00, 0x19, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x04, 0xb7, 0x00, 0x19, 0x00, 0x00, 0x00, 0x25, 0x00, + 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x05, 0xb8, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x04, 0xb9, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x04, 0xba, 0x00, 0x11, 0x14, 0x00, 0x00, 0x15, 0x1c, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xbb, 0x00, 0x11, 0x1c, 0x00, 0x00, 0x15, 0x28, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xbc, 0x00, 0x11, 0x1d, 0x00, 0x00, 0x15, 0x29, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xbd, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x16, 0x20, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0x03, 0xe0, + 0x00, 0x00, 0x07, 0x00, 0xbe, 0x00, 0x01, 0x1d, 0x00, 0x00, 0x16, 0x21, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xbf, 0x00, 0x02, 0x1d, 0x00, 0x00, 0x15, 0x29, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0xc0, 0x00, 0x02, 0x1d, 0x00, 0x00, 0x16, 0x21, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, + 0xc1, 0x00, 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x07, 0x04, 0xc2, 0x00, 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x90, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x07, 0x04, 0xc3, 0x00, 0x11, 0x11, 0x00, 0x00, 0x15, 0x16, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0x00, 0xc4, 0x00, 0x11, 0x11, + 0x00, 0x00, 0x15, 0x16, 0x00, 0x00, 0x02, 0x90, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0x00, 0xc5, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x15, 0x28, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x01, 0xc6, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x16, 0x20, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x01, +}; +u8 const Asm_riscv::raw_clobber_forms[1782] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x30, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x30, 0x01, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x10, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, + 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, +}; From cfb8a109b620c13b419b182554d2a08ff0c6bd9e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Aug 2026 17:51:47 +0100 Subject: [PATCH 05/20] Begin work on pseudo-aliases --- core/rexcode/isa/riscv/encoding_types.odin | 13 +- core/rexcode/isa/riscv/mnemonics.odin | 85 ++ core/rexcode/isa/riscv/pseudo_aliases.odin | 171 +++ .../riscv/tablegen/cpp-compiler/cpp-gen.odin | 1007 +++++++++++++++++ core/rexcode/isa/riscv/tablegen/gen.odin | 8 +- .../tablegen/generated/decode_tables.odin | 238 ++-- .../tablegen/generated/encode_tables.odin | 809 +++++++++---- .../isa/riscv/tablegen/instruction_table.odin | 322 ++++++ core/rexcode/isa/riscv/tables.odin | 4 +- .../isa/riscv/tables/riscv.clobber_forms.bin | Bin 1782 -> 2547 bytes .../isa/riscv/tables/riscv.encode_forms.bin | Bin 3960 -> 5943 bytes .../isa/riscv/tables/riscv.encode_runs.bin | Bin 1592 -> 2256 bytes .../isa/riscv/tables/riscv.entries.bin | Bin 3960 -> 5943 bytes .../isa/riscv/tables/riscv.idx_op_fp.bin | Bin 512 -> 512 bytes .../isa/riscv/tables/riscv.idx_opcode.bin | Bin 512 -> 512 bytes .../isa/riscv/tables/riscv.idx_rvc.bin | Bin 128 -> 128 bytes .../x86/tablegen/cpp-compiler/cpp-gen.odin | 18 + 17 files changed, 2403 insertions(+), 272 deletions(-) create mode 100644 core/rexcode/isa/riscv/pseudo_aliases.odin create mode 100644 core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin diff --git a/core/rexcode/isa/riscv/encoding_types.odin b/core/rexcode/isa/riscv/encoding_types.odin index bf3e1bd11..cd0527c73 100644 --- a/core/rexcode/isa/riscv/encoding_types.odin +++ b/core/rexcode/isa/riscv/encoding_types.odin @@ -40,7 +40,7 @@ LABEL_UNDEFINED :: isa.LABEL_UNDEFINED Label_Map :: isa.Label_Map // Extension this entry belongs to (metadata, not used by the matcher). -Feature :: enum u8 { +Feature :: enum u16 { I, // RV32I / RV64I base integer M, // multiply / divide A, // atomics @@ -49,6 +49,13 @@ Feature :: enum u8 { ZICSR, // CSR access (CSRRW/S/C + immediate forms) ZIFENCEI, // FENCE.I (instruction-fetch fence) C, // 16-bit compressed instructions + ZBA, // address-generation bit-manip + ZBB, // basic bit-manip + ZBC, // carry-less multiply + ZBS, // single-bit bit-manip + ZICOND, // conditional zeroing + ZFH, // half-precision (binary16) FP + PRIV, // privileged trap-return / TLB maintenance } Encoding_Flags :: bit_field u8 { @@ -150,10 +157,10 @@ Encoding :: struct #packed { enc: [4]Operand_Encoding, // 4 bits: u32, // 4 -- static bit pattern mask: u32, // 4 -- which bits are static - feature: Feature, // 1 + feature: Feature, // 2 flags: Encoding_Flags, // 1 } -#assert(size_of(Encoding) == 20) +#assert(size_of(Encoding) == 21) // inst_size_from_bits returns 2 for compressed (RVC) instructions, 4 for the // standard 32-bit base ISA. RISC-V uses a length-encoding convention where diff --git a/core/rexcode/isa/riscv/mnemonics.odin b/core/rexcode/isa/riscv/mnemonics.odin index e492c4e82..02335bb93 100644 --- a/core/rexcode/isa/riscv/mnemonics.odin +++ b/core/rexcode/isa/riscv/mnemonics.odin @@ -139,4 +139,89 @@ Mnemonic :: enum u16 { C_FLDSP, C_FSDSP, C_JR, C_JALR, C_MV, C_ADD, C_FLWSP, C_FSWSP, + + + SH1ADD, + SH2ADD, + SH3ADD, + ADD_UW, + SH1ADD_UW, + SH2ADD_UW, + SH3ADD_UW, + SLLI_UW, + ANDN, + ORN, + XNOR, + CLZ, + CTZ, + CPOP, + SEXT_B, + SEXT_H, + ZEXT_H, + MIN, + MINU, + MAX, + MAXU, + ROL, + ROR, + RORI, + ORC_B, + REV8, + CLZW, + CTZW, + CPOPW, + ROLW, + RORW, + RORIW, + CLMUL, + CLMULH, + CLMULR, + BCLR, + BCLRI, + BEXT, + BEXTI, + BINV, + BINVI, + BSET, + BSETI, + CZERO_EQZ, + CZERO_NEZ, + FLH, + FSH, + FMADD_H, + FMSUB_H, + FNMSUB_H, + FNMADD_H, + FADD_H, + FSUB_H, + FMUL_H, + FDIV_H, + FSQRT_H, + FSGNJ_H, + FSGNJN_H, + FSGNJX_H, + FMIN_H, + FMAX_H, + FCVT_W_H, + FCVT_WU_H, + FCVT_L_H, + FCVT_LU_H, + FCVT_H_W, + FCVT_H_WU, + FCVT_H_L, + FCVT_H_LU, + FCVT_S_H, + FCVT_H_S, + FCVT_D_H, + FCVT_H_D, + FMV_X_H, + FMV_H_X, + FCLASS_H, + FEQ_H, + FLT_H, + FLE_H, + MRET, + SRET, + WFI, + SFENCE_VMA, } diff --git a/core/rexcode/isa/riscv/pseudo_aliases.odin b/core/rexcode/isa/riscv/pseudo_aliases.odin new file mode 100644 index 000000000..a7a3f037a --- /dev/null +++ b/core/rexcode/isa/riscv/pseudo_aliases.odin @@ -0,0 +1,171 @@ +package rexcode_riscv + +// ============================================================================= +// RISC-V PSEUDO-INSTRUCTION ALIAS TABLE +// +// Every entry here lowers to exactly ONE real INSTRUCTION_TABLE mnemonic by +// filling that target's operand slots. The real entry supplies the encoding +// and the clobber set for free — a pseudo's dataflow is its target's dataflow. +// +// Pseudos that CANNOT be expressed this way (value-dependent expansions and a +// couple of fixed-word HINTs) are listed as comments at the bottom; they stay +// procedures or dedicated table rows. +// ============================================================================= + +// How each operand slot of the target instruction is filled. +Alias_Src :: enum u8 { + NONE, // slot unused + ARG0, // user's 1st operand + ARG1, // user's 2nd operand + ARG2, // user's 3rd operand + X0, // hardwired zero (x0) + X1, // link register (ra / x1) + LIT, // the `lit` field below (immediate literal) + CSR_LIT, // the `csr` field below (fixed 12-bit CSR address) +} + +Pseudo_Alias :: struct { + target: Mnemonic, // real instruction emitted + src: [4]Alias_Src, // how to fill target's four operand slots + lit: i16, // immediate when a src slot is .LIT + csr: u16, // CSR address when a src slot is .CSR_LIT + nargs: u8, // operands the user supplies (ARG0.. generated/ + this file + // odin run tablegen/generated # Stage B: typed Odin literals -> tables/*.bin + // odin run tablegen/cpp-compiler # Stage C: typed Odin literals -> C++ literals + // + \n\n + """) + + + // strings.write_string(&sb, "struct Asm_a + fmt.sbprintf(&sb, "struct Asm_%s {{\n", ISA_NAME) + { + strings.write_string(&sb, "\tenum Mnemonic : u16 {\n") + defer strings.write_string(&sb, "\t};\n"); + + iota := 0 + + count := uint(0) + ROW_COUNT :: 16 + for mnemonic in gen.Mnemonic { + if count == 0 { + strings.write_string(&sb, "\t\t") + } + assert(int(mnemonic) == iota) + fmt.sbprintf(&sb, "M_%s, ", mnemonic) + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + + iota += 1 + count = (count + 1) % ROW_COUNT + } + strings.write_string(&sb, "\n\n"); + strings.write_string(&sb, "\t\tMNEMONIC_COUNT\n"); + } + + strings.write_string(&sb, "\tstatic String const mnemonic_strings[MNEMONIC_COUNT];\n") + + { + strings.write_string(&sb, "\n") + strings.write_string(&sb, """ + enum Prefix : u8 { + PREFIX_INVALID, + PREFIX_COUNT + }; + enum PrefixKind : u8 { PrefixKind_None }; + \n + """) + } + { + strings.write_string(&sb, "\n") + strings.write_string(&sb, """ + static const u16 REG_CLASS_NONE = 0x000; + static const u16 REG_CLASS_GPR64 = 0x100; + static const u16 REG_CLASS_GPR32 = 0x200; + static const u16 REG_CLASS_GPR16 = 0x300; + static const u16 REG_CLASS_GPR8 = 0x400; + static const u16 REG_CLASS_GPR8H = 0x500; // AH, CH, DH, BH - legacy high byte regs + static const u16 REG_CLASS_XMM = 0x600; + static const u16 REG_CLASS_YMM = 0x700; + static const u16 REG_CLASS_ZMM = 0x800; + static const u16 REG_CLASS_K = 0x900; // opmask + static const u16 REG_CLASS_SEG = 0xA00; // segment + static const u16 REG_CLASS_CR = 0xB00; // control + static const u16 REG_CLASS_DR = 0xC00; // debug + static const u16 REG_CLASS_BND = 0xD00; // bound + static const u16 REG_CLASS_MM = 0xE00; // MMX + static const u16 REG_CLASS_ST = 0xF00; // x87 FPU + \n + """) + { + count := uint(0) + ROW_COUNT :: 16 + strings.write_string(&sb, "\tenum Register : u16 {\n") + for reg in Register { + if count == 0 { + strings.write_string(&sb, "\t\t") + } + fmt.sbprintf(&sb, "REG_%s, ", reg) + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + count = (count + 1) % ROW_COUNT + } + strings.write_string(&sb, "\n") + strings.write_string(&sb, "\t\tREG_COUNT\n") + strings.write_string(&sb, "\t};\n") + } + } + strings.write_string(&sb, "\n") + strings.write_string(&sb, """ + + enum ClobberFFlags : u8 { + ClobberFFlag_NV = 1<<0, // invalid operation + ClobberFFlag_DZ = 1<<1, // divide by zero + ClobberFFlag_OF = 1<<2, // overflow + ClobberFFlag_UF = 1<<3, // underflow + ClobberFFlag_NX = 1<<4, // inexact + }; + + enum ClobberRegs : u8 { + ClobberReg_RA = 1<<0, // x1, implicit link on C.JAL / C.JALR + ClobberReg_SP = 1<<1, // x2, implicit base on the *SP compressed forms + }; + + static u8 const CLOBBER_REGS_NAMED = ClobberReg_RA|ClobberReg_SP; + + enum SideEffectFlags : u8 { + SideEffectFlag_CONTROL = 1<<0, // writes pc: branches, jumps, and trap redirects + SideEffectFlag_TRAP = 1<<1, // synchronous environment trap (ECALL / EBREAK) + SideEffectFlag_FENCE = 1<<2, // explicit memory-ordering barrier (FENCE) + SideEffectFlag_IFENCE = 1<<3, // instruction-fetch synchronization (FENCE.I) + SideEffectFlag_ATOMIC = 1<<4, // indivisible memory RMW (AMO*, and the LR/SC pair) + SideEffectFlag_RESERVATION = 1<<5, // sets or tests an LR/SC reservation + }; + + enum OperandSet : u8 { + OperandSet_OP0 = 1<<0, + OperandSet_OP1 = 1<<1, + OperandSet_OP2 = 1<<2, + OperandSet_OP3 = 1<<3, + }; + + u16 clobber_bit_for_reg_name(String const &pin) { + static const struct { String name; u16 bit; } table[] = { + {str_lit(\"ra\"), ClobberReg_RA}, + {str_lit(\"sp\"), ClobberReg_SP}, + {str_lit(\"x1\"), ClobberReg_RA}, + {str_lit(\"x2\"), ClobberReg_SP}, + }; + for (auto const &t : table) { + if (pin == t.name) { + return t.bit; + } + } + return 0; + } + + char const *clobber_reg_bit_name(u16 bit) { + switch (bit) { + case ClobberReg_RA: return \"ra\"; + case ClobberReg_SP: return \"sp\"; + } + return \"\"; + } + + i32 flag_bit_from_name(String const &name, i32 *width_) { + static const struct { String name; i32 bit; } table[] = { + // fflags: accrued FP exception flags (fcsr[4:0]) + {str_lit(\"nx\"), 0}, // Inexact + {str_lit(\"uf\"), 1}, // Underflow + {str_lit(\"of\"), 2}, // Overflow + {str_lit(\"dz\"), 3}, // Divide by Zero + {str_lit(\"nv\"), 4}, // Invalid Operation + // frm: rounding mode (fcsr[7:5], 3-bit field, low bit) + {str_lit(\"frm\"), 5}, // Rounding Mode + }; + + for (auto const &t : table) { + if (name == t.name) { + if (width_) { + if (t.name == \"frm\") { + *width_ = 3; + } else { + *width_ = 1; + } + } + return t.bit; + } + } + return -1; + } + + + struct Clobber { + OperandSet written; // operand slots whose register/CSR is written + OperandSet read; // operand slots whose register/CSR/mem-base is read + ClobberRegs implicit_wr; // implicit reg writes (ra on C.JAL/C.JALR) + ClobberRegs implicit_rd; // implicit reg reads (sp on the *SP forms) + ClobberFFlags fflags_wr; // accrued exception flags this op may raise + bool reads_frm; // consumes the dynamic rounding mode from fcsr + bool writes_mem; + bool reads_mem; + SideEffectFlags side_effects; + + bool implies_clobber_flags() const { + return (fflags_wr != 0); + } + bool implies_clobber_memory() const { + return writes_mem || reads_mem || + (side_effects & (SideEffectFlag_FENCE|SideEffectFlag_ATOMIC)) != 0; + } + bool implies_side_effects() const { + return side_effects != 0; + } + u8 is_call_or_mem() const { + return (cast(u16)side_effects & SideEffectFlag_CONTROL) != 0 || + (cast(u16)implicit_wr & ClobberReg_SP) != 0; + } + bool has_control() const { + return (cast(u16)side_effects & SideEffectFlag_CONTROL) != 0; + } + bool has_halt() const { + return (cast(u16)side_effects & SideEffectFlag_TRAP) != 0; + } + bool is_conditional() const { + return has_control(); + } + }; + + void clobber_implicit_regs(StringSet *clobber_registers_set, u16 implicit_regs) { + u8 regs = cast(u8)implicit_regs; + + for (u8 bit = 1; bit != 0; bit <<= 1) { + if ((regs & bit) == 0) { + continue; + } + char const *rname = clobber_reg_bit_name(bit); + string_set_update(clobber_registers_set, make_string_c(rname)); + } + } + """) + strings.write_string(&sb, "\n") + + strings.write_string(&sb, "\n") + { + strings.write_string(&sb, """ + enum AliasSrc : u8 { + AliasSrc_NONE, // slot unused + AliasSrc_ARG0, // user's 1st operand + AliasSrc_ARG1, // user's 2nd operand + AliasSrc_ARG2, // user's 3rd operand + AliasSrc_X0, // hardwired zero (x0) + AliasSrc_X1, // link register (ra / x1) + AliasSrc_LIT, // the `lit` field below (immediate literal) + AliasSrc_CSR_LIT, // the `csr` field below (fixed 12-bit CSR address) + }; + + struct PseudoAlias { + Mnemonic target; // real instruction emitted + AliasSrc src[4]; // how to fill target's four operand slots + i16 lit; // immediate when a src slot is AliasSrc_LIT + u16 csr; // CSR address when a src slot is AliasSrc_CSR_LIT + u8 nargs; // operands the user supplies (ARG0..>%du)&1) != 0;", bit_offset) + strings.write_string(&sb, " }\n") + } + { + bit_offset := intrinsics.type_field_bit_offset(Encoding_Flags, "explicit_count") + bit_size := intrinsics.type_field_bit_size(Encoding_Flags, "explicit_count") + strings.write_string(&sb, "\t\tu8 explicit_count() const { ") + fmt.sbprintf(&sb, "return cast(u8)((flags>>%du)&((1u<<%d)-1));", bit_offset, bit_size) + strings.write_string(&sb, " }\n") + } + // { + // bit_offset := intrinsics.type_field_bit_offset(Encoding_Flags, "op_count") + // bit_size := intrinsics.type_field_bit_size(Encoding_Flags, "op_count") + // strings.write_string(&sb, "\t\tu8 op_count () const { ") + // fmt.sbprintf(&sb, "return cast(u8)((flags>>%du)&((1u<<%d)-1));", bit_offset, bit_size) + // strings.write_string(&sb, " }\n") + // } + // { + // bit_offset := intrinsics.type_field_bit_offset(Encoding_Flags, "lock_ok") + // strings.write_string(&sb, "\t\tbool lock_ok () const { ") + // fmt.sbprintf(&sb, "return ((flags>>%du)&1) != 0;", bit_offset) + // strings.write_string(&sb, " }\n") + // } + // { + // bit_offset := intrinsics.type_field_bit_offset(Encoding_Flags, "rep_ok") + // strings.write_string(&sb, "\t\tbool rep_ok () const { ") + // fmt.sbprintf(&sb, "return ((flags>>%du)&1) != 0;", bit_offset) + // strings.write_string(&sb, " }\n") + // } + } + strings.write_string(&sb, "\n\n") + { + strings.write_string(&sb, "\t// Companion run index: ENCODE_RUNS[mnemonic] -> contiguous run in ENCODE_FORMS.\n") + strings.write_string(&sb, "\tstruct EncodeRun {\n") + strings.write_string(&sb, "\t\tu32 start; // start index in ENCODE_FORMS\n") + strings.write_string(&sb, "\t\tu32 count; // number of forms for this mnemonic\n") + strings.write_string(&sb, "\t};\n") + } + + strings.write_string(&sb, "\n\n") + fmt.sbprintf(&sb, "\tstatic EncodeRun const raw_encode_runs [%d];\n", len(raw_encode_runs)) + fmt.sbprintf(&sb, "\tstatic u8 const raw_encode_forms [%d];\n", len(raw_encode_forms)) + fmt.sbprintf(&sb, "\tstatic u8 const raw_clobber_forms [%d];\n", len(raw_clobber_forms)) + fmt.sbprintf(&sb, "\tstatic u8 const raw_pseudo_aliases[%d];\n", len(raw_pseudo_aliases)) + strings.write_string(&sb, "\n") + strings.write_string(&sb, "\tStringMap mnemonic_map;\n") + strings.write_string(&sb, "\tStringMap register_map;\n") + strings.write_string(&sb, "\tStringMap pseudo_register_map;\n") + + strings.write_string(&sb, """ + + u16 XLEN; + u16 FLEN; + + bool init(i64 word_size) { + XLEN = cast(u16)word_size; + FLEN = cast(u16)word_size; + + string_map_init(&mnemonic_map, MNEMONIC_COUNT*2); + for (u16 m = M_INVALID+1; m < MNEMONIC_COUNT; m++) { + string_map_set(&mnemonic_map, mnemonic_strings[m], cast(Mnemonic)m); + } + + string_map_init(&mnemonic_map, PSEUDO_MNEMONIC_COUNT*2); + for (u16 m = PM_INVALID+1; m < PSEUDO_MNEMONIC_COUNT; m++) { + string_map_set(&pseudo_mnemonic_map, pseudo_mnemonic_strings[m], cast(PseudoMnemonic)m); + } + + string_map_init(®ister_map, REG_COUNT*2); + for (u16 r = REG_INVALID+1; r < REG_COUNT; r++) { + string_map_set(®ister_map, register_strings[r], cast(Register)r); + } + return true; + } + + Mnemonic mnemonic_lookup(String const &name) { + Mnemonic *found = string_map_get(&mnemonic_map, name); + return found ? *found : M_INVALID; + } + Prefix prefix_lookup(String const &name) { + return PREFIX_INVALID; + } + static String const prefix_strings[PREFIX_COUNT]; + + Register register_lookup(String const &name) { + Register *found = string_map_get(®ister_map, name); + return found ? *found : REG_INVALID; + } + Slice encoding_forms(/*Mnemonic*/ u16 m) const { + EncodeRun r = raw_encode_runs[m]; + Encoding *ENCODE_FORMS = cast(Encoding *)raw_encode_forms; + return Slice{ENCODE_FORMS+r.start, r.count}; + } + Slice clobber_forms(/*Mnemonic*/ u16 m) const { + EncodeRun r = raw_encode_runs[m]; + Clobber *CLOBBER_FORMS = cast(Clobber *)raw_clobber_forms; + return Slice{CLOBBER_FORMS+r.start, r.count}; + } + u16 reg_class(/*Register*/ u16 r) const { + return 0xFF00 & r; + } + // size in bits for register + u16 reg_size(Register r) const { + switch (reg_class(register_codes[r])) { + case REG_CLASS_GPR64: return 64; + case REG_CLASS_GPR32: return 32; + case REG_CLASS_GPR16: return 16; + case REG_CLASS_GPR8: return 8; + case REG_CLASS_GPR8H: return 8; + case REG_CLASS_XMM: return 128; + case REG_CLASS_YMM: return 256; + case REG_CLASS_ZMM: return 512; + case REG_CLASS_K: return 64; + case REG_CLASS_MM: return 64; + case REG_CLASS_ST: return 80; + case REG_CLASS_SEG: return 16; + case REG_CLASS_CR: return 64; + case REG_CLASS_DR: return 64; + case REG_CLASS_BND: return 128; + } + return 0; + } + """) + strings.write_string(&sb, "\n\n") + + strings.write_string(&sb, """ + AsmOperandKind kind_from_operand_type(OperandType type) const { + switch (type) { + case OP_NONE: + return AsmOperand_Invalid; + + // Registers + case OP_GPR: + case OP_FPR: + case OP_GPR_C: + case OP_GPR_SP: + case OP_GPR_NONZERO: + case OP_FPR_C: + return AsmOperand_Register; + + case OP_CSR: // 12-bit CSR address; treat as immediate (no CSR reg class exists) + // TODO(bill): what should this be? + return AsmOperand_Immediate; + + // Immediates (incl. things that ultimately encode as an immediate field: + // CSR address, fence flags, rounding mode). + case OP_IMM12: + case OP_IMM12U: + case OP_IMM5: + case OP_IMM6: + case OP_IMM20: + case OP_FENCE_FLAGS: // iorw mask -> 4-bit immediate field + case OP_ROUND_MODE: // rm -> 3-bit immediate field + case OP_ZIMM5: + case OP_IMM_C6S: + case OP_IMM_C6U: + case OP_IMM_C8U: + case OP_IMM_C10S: + case OP_IMM_C18S: + return AsmOperand_Immediate; + + // Branch/jump targets are written as labels. + case OP_REL13: + case OP_REL21: + case OP_REL9: + case OP_REL12: + return AsmOperand_Label; + + // Memory + case OP_MEM: + case OP_MEM_C_W: + case OP_MEM_C_D: + case OP_MEM_C_SP_W: + case OP_MEM_C_SP_D: + return AsmOperand_Memory; + } + return AsmOperand_Invalid; + } + """) + strings.write_string(&sb, "\n\n") + + strings.write_string(&sb, """ + AsmRegClass reg_class_from_operand_type(OperandType type) const { + switch (type) { + case OP_GPR: + case OP_GPR_C: + case OP_GPR_SP: + case OP_GPR_NONZERO: + return AsmRegClass_Integer; + + case OP_FPR: + case OP_FPR_C: + return AsmRegClass_Float; + + // No vector/mask operand types are present in this list; everything + // else (immediates, memory, labels, CSR, etc.) has no register class. + default: + return AsmRegClass_Unknown; + } + } + """) + strings.write_string(&sb, "\n\n") + + strings.write_string(&sb, """ + bool operand_type_is_implicit(OperandType t) const { + switch (t) { + // sp is fixed by the mnemonic (c.addi16sp / c.*sp bases) and isn't a + // register the user freely chooses, so it's encoded implicitly. + // If your parser actually reads `sp` from the operand text, flip this. + case OP_GPR_SP: + return true; + default: + return false; + } + } + """) + + strings.write_string(&sb, "\n\n") + + strings.write_string(&sb, """ + AsmRegClass operand_type_reg_class(OperandType t) const { + // Same mapping as reg_class_from_operand_type — these two look + // redundant; consider collapsing them into one. + return reg_class_from_operand_type(t); + } + """) + + + strings.write_string(&sb, "\n\n") + + strings.write_string(&sb, """ + u16 operand_type_bit_width(OperandType t) const { + switch (t) { + case OP_NONE: + return 0; + + // Registers -> architectural register data width (like OP_R*, OP_XMM). + // RISC-V doesn't encode width in the operand type: GPR is XLEN, FPR is + // FLEN, both target-config dependent -> treat as data-dependent = 0, + // same as x86 OP_K. (Or hardcode 32/64 if your assembler is fixed-config.) + // The _C / _SP / _NONZERO variants only restrict *which* regs, not width. + case OP_GPR: + case OP_GPR_C: + case OP_GPR_SP: + case OP_GPR_NONZERO: + return XLEN; + case OP_FPR: + case OP_FPR_C: + return FLEN; + + // Memory -> access size (like OP_M*). Base OP_MEM's size comes from the opcode. + // Compressed forms name the size. + case OP_MEM: + return 0; + case OP_MEM_C_W: + case OP_MEM_C_SP_W: + return 32; + case OP_MEM_C_D: + case OP_MEM_C_SP_D: + return 64; + + // Immediates -> value width + case OP_IMM12: + case OP_IMM12U: + case OP_CSR: + return 12; + case OP_IMM5: + case OP_ZIMM5: + return 5; + case OP_IMM6: + return 6; + case OP_IMM20: + return 20; + case OP_FENCE_FLAGS: + return 4; + case OP_ROUND_MODE: + return 3; + case OP_IMM_C6S: + case OP_IMM_C6U: + return 6; + case OP_IMM_C8U: + return 8; + case OP_IMM_C10S: + return 10; + case OP_IMM_C18S: + return 18; + + // Rels -> displacement value width + case OP_REL13: + return 13; + case OP_REL21: + return 21; + case OP_REL9: + return 9; + case OP_REL12: + return 12; + } + return 0; + } + """) + + strings.write_string(&sb, "\n\n") + + strings.write_string(&sb, """ + int form_explicit_slot(Encoding const &form, int explicit_index) const { + int seen = 0; + for (int j = 0; j < gb_count_of(form.ops); j++) { + auto t = form.ops[j]; + if (!t) { + break; + } + if (operand_type_is_implicit(t)) { + continue; + } + if (seen == explicit_index) { + return j; + } + seen += 1; + } + return -1; + } + """) + + strings.write_string(&sb, "\n\n") + + strings.write_string(&sb, """ + bool prefix_kind_okay(u8 prefix, Encoding const &form, bool *requires_memory_dest_) const { + // RISC-V does not have prefixes + return false; + } + """) + + strings.write_string(&sb, "\n};\n") + + strings.write_string(&sb, "\n\n\n") + + fmt.sbprintf(&sb, "gb_global Asm_{0:s} g_asm_{0:s};\n", ISA_NAME) + + strings.write_string(&sb, "\n\n\n") + + fmt.sbprintf(&sb, "String const Asm_{0:s}::prefix_strings[Asm_{0:s}::PREFIX_COUNT]{{}};\n", ISA_NAME) + + { + fmt.sbprintf(&sb, "String const Asm_{0:s}::mnemonic_strings[Asm_{0:s}::MNEMONIC_COUNT] {{\n", ISA_NAME) + defer strings.write_string(&sb, "};\n"); + + count := uint(0) + ROW_COUNT :: 16 + for mnemonic in gen.Mnemonic { + if count == 0 { + strings.write_string(&sb, "\t") + } + + #partial switch mnemonic { + case .INVALID: + strings.write_string(&sb, "str_lit(\"\"), ") + case: + str := strings.to_lower(reflect.enum_string(mnemonic)) + fmt.sbprintf(&sb, "str_lit(%q), ", str) + delete(str) + } + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + + count = (count + 1) % ROW_COUNT + } + strings.write_string(&sb, "\n") + } + + { + fmt.sbprintf(&sb, "u16 const Asm_{0:s}::register_codes[Asm_{0:s}::REG_COUNT] {{\n", ISA_NAME) + defer strings.write_string(&sb, "};\n"); + + count := uint(0) + ROW_COUNT :: 16 + for reg in Register { + if count == 0 { + strings.write_string(&sb, "\t") + } + + fmt.sbprintf(&sb, "%d, ", REG_CODES[reg]) + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + + count = (count + 1) % ROW_COUNT + } + strings.write_string(&sb, "\n") + } + + { + fmt.sbprintf(&sb, "String const Asm_{0:s}::register_strings[Asm_{0:s}::REG_COUNT] {{\n", ISA_NAME) + defer strings.write_string(&sb, "};\n"); + + count := uint(0) + ROW_COUNT :: 16 + for reg in Register { + if count == 0 { + strings.write_string(&sb, "\t") + } + + if reg == .INVALID { + strings.write_string(&sb, "str_lit(\"\"), ") + } else { + str := strings.to_lower(reflect.enum_string(reg)) + fmt.sbprintf(&sb, "str_lit(%q), ", str) + delete(str) + } + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + + count = (count + 1) % ROW_COUNT + } + strings.write_string(&sb, "\n") + } + + { + fmt.sbprintf(&sb, "String const Asm_{0:s}::pseudo_mnemonic_strings[Asm_{0:s}::PSEUDO_MNEMONIC_COUNT] {{\n", ISA_NAME) + defer strings.write_string(&sb, "};\n"); + + count := uint(0) + ROW_COUNT :: 8 + for pm in riscv.Pseudo_Mnemonic { + if count == 0 { + strings.write_string(&sb, "\t") + } + + if pm == .INVALID { + strings.write_string(&sb, "str_lit(\"\"), ") + } else { + str := strings.to_lower(reflect.enum_string(pm)) + fmt.sbprintf(&sb, "str_lit(%q), ", str) + delete(str) + } + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + + count = (count + 1) % ROW_COUNT + } + strings.write_string(&sb, "\n") + } + + { + fmt.sbprintf(&sb, "Asm_{0:s}::EncodeRun const Asm_{0:s}::raw_encode_runs[{1:d}] = {{\n", ISA_NAME, len(raw_encode_runs)) + defer strings.write_string(&sb, "};\n"); + + ROW_COUNT :: 16 + count := 0 + for run in raw_encode_runs { + if count == 0 { + strings.write_string(&sb, "\t") + } + fmt.sbprintf(&sb, "{{% 4d, % 2d}}, ", run.start, run.count) + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + + count = (count + 1) % ROW_COUNT + } + defer strings.write_string(&sb, "\n") + } + { + fmt.sbprintf(&sb, "u8 const Asm_{0:s}::raw_encode_forms[%d] = {{\n", ISA_NAME, len(raw_encode_forms)) + defer strings.write_string(&sb, "};\n"); + ROW_COUNT :: 64 + count := 0 + for the_byte in raw_encode_forms { + if count == 0 { + strings.write_string(&sb, "\t") + } + fmt.sbprintf(&sb, "%#02x, ", the_byte) + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + + count = (count + 1) % ROW_COUNT + } + defer strings.write_string(&sb, "\n") + } + { + fmt.sbprintf(&sb, "u8 const Asm_{0:s}::raw_clobber_forms[%d] = {{\n", ISA_NAME, len(raw_clobber_forms)) + defer strings.write_string(&sb, "};\n"); + ROW_COUNT :: 64 + count := 0 + for the_byte in raw_clobber_forms { + if count == 0 { + strings.write_string(&sb, "\t") + } + fmt.sbprintf(&sb, "%#02x, ", the_byte) + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + + count = (count + 1) % ROW_COUNT + } + defer strings.write_string(&sb, "\n") + } + { + fmt.sbprintf(&sb, "u8 const Asm_{0:s}::raw_pseudo_aliases[%d] = {{\n", ISA_NAME, len(raw_pseudo_aliases)) + defer strings.write_string(&sb, "};\n"); + ROW_COUNT :: 64 + count := 0 + for the_byte in raw_pseudo_aliases { + if count == 0 { + strings.write_string(&sb, "\t") + } + fmt.sbprintf(&sb, "%#02x, ", the_byte) + + if count == ROW_COUNT-1 { + strings.write_string(&sb, "\n") + } + + count = (count + 1) % ROW_COUNT + } + defer strings.write_string(&sb, "\n") + } + + + + path := fmt.tprintf("%s/src/asm_tables_%s.cpp", ODIN_ROOT, ISA_NAME) + + if err := os.write_entire_file(path, strings.to_string(sb)); err != nil { + fmt.eprintfln("rexcode tablegen: failed to write %s: %v", path, err) + os.exit(1) + } +} + +Operand_Encoding :: type_of(gen.Encoding{}.enc[0]) +Feature :: type_of(gen.Encoding{}.feature) + + + +Register :: enum u16 { + INVALID, + ZERO, + RA, + SP, + GP, + TP, + T0, + T1, + T2, + S0, + S1, + A0, + A1, + A2, + A3, + A4, + A5, + A6, + A7, + S2, + S3, + S4, + S5, + S6, + S7, + S8, + S9, + S10, + S11, + T3, + T4, + T5, + T6, + FT0, + FT1, + FT2, + FT3, + FT4, + FT5, + FT6, + FT7, + FS0, + FS1, + FA0, + FA1, + FA2, + FA3, + FA4, + FA5, + FA6, + FA7, + FS2, + FS3, + FS4, + FS5, + FS6, + FS7, + FS8, + FS9, + FS10, + FS11, + FT8, + FT9, + FT10, + FT11, +} + +REG_NONE :: 0x0000 +REG_GPR :: 0x0100 // x0..x31 +REG_FPR :: 0x0200 // f0..f31 + +@(rodata) +REG_CODES := [Register]riscv.Register{ + .INVALID = 0, + + .ZERO = riscv.Register(REG_GPR | 0), + .RA = riscv.Register(REG_GPR | 1), + .SP = riscv.Register(REG_GPR | 2), + .GP = riscv.Register(REG_GPR | 3), + .TP = riscv.Register(REG_GPR | 4), + .T0 = riscv.Register(REG_GPR | 5), .T1 = riscv.Register(REG_GPR | 6), .T2 = riscv.Register(REG_GPR | 7), + .S0 = riscv.Register(REG_GPR | 8), .S1 = riscv.Register(REG_GPR | 9), + .A0 = riscv.Register(REG_GPR | 10), .A1 = riscv.Register(REG_GPR | 11), .A2 = riscv.Register(REG_GPR | 12), .A3 = riscv.Register(REG_GPR | 13), + .A4 = riscv.Register(REG_GPR | 14), .A5 = riscv.Register(REG_GPR | 15), .A6 = riscv.Register(REG_GPR | 16), .A7 = riscv.Register(REG_GPR | 17), + .S2 = riscv.Register(REG_GPR | 18), .S3 = riscv.Register(REG_GPR | 19), .S4 = riscv.Register(REG_GPR | 20), .S5 = riscv.Register(REG_GPR | 21), + .S6 = riscv.Register(REG_GPR | 22), .S7 = riscv.Register(REG_GPR | 23), .S8 = riscv.Register(REG_GPR | 24), .S9 = riscv.Register(REG_GPR | 25), + .S10 = riscv.Register(REG_GPR | 26), .S11 = riscv.Register(REG_GPR | 27), + .T3 = riscv.Register(REG_GPR | 28), .T4 = riscv.Register(REG_GPR | 29), .T5 = riscv.Register(REG_GPR | 30), .T6 = riscv.Register(REG_GPR | 31), + + .FT0 = riscv.Register(REG_FPR | 0), .FT1 = riscv.Register(REG_FPR | 1), .FT2 = riscv.Register(REG_FPR | 2), .FT3 = riscv.Register(REG_FPR | 3), + .FT4 = riscv.Register(REG_FPR | 4), .FT5 = riscv.Register(REG_FPR | 5), .FT6 = riscv.Register(REG_FPR | 6), .FT7 = riscv.Register(REG_FPR | 7), + .FS0 = riscv.Register(REG_FPR | 8), .FS1 = riscv.Register(REG_FPR | 9), + .FA0 = riscv.Register(REG_FPR | 10), .FA1 = riscv.Register(REG_FPR | 11), .FA2 = riscv.Register(REG_FPR | 12), .FA3 = riscv.Register(REG_FPR | 13), + .FA4 = riscv.Register(REG_FPR | 14), .FA5 = riscv.Register(REG_FPR | 15), .FA6 = riscv.Register(REG_FPR | 16), .FA7 = riscv.Register(REG_FPR | 17), + .FS2 = riscv.Register(REG_FPR | 18), .FS3 = riscv.Register(REG_FPR | 19), .FS4 = riscv.Register(REG_FPR | 20), .FS5 = riscv.Register(REG_FPR | 21), + .FS6 = riscv.Register(REG_FPR | 22), .FS7 = riscv.Register(REG_FPR | 23), .FS8 = riscv.Register(REG_FPR | 24), .FS9 = riscv.Register(REG_FPR | 25), + .FS10 = riscv.Register(REG_FPR | 26), .FS11 = riscv.Register(REG_FPR | 27), + .FT8 = riscv.Register(REG_FPR | 28), .FT9 = riscv.Register(REG_FPR | 29), .FT10 = riscv.Register(REG_FPR | 30), .FT11 = riscv.Register(REG_FPR | 31), + +} \ No newline at end of file diff --git a/core/rexcode/isa/riscv/tablegen/gen.odin b/core/rexcode/isa/riscv/tablegen/gen.odin index 0a7ee797a..c04385301 100644 --- a/core/rexcode/isa/riscv/tablegen/gen.odin +++ b/core/rexcode/isa/riscv/tablegen/gen.odin @@ -331,6 +331,10 @@ flags_lit :: proc(f: lib.Encoding_Flags) -> string { if f.rv64_only { append(&parts, "rv64_only=true") } if f.branch { append(&parts, "branch=true") } if f.fp_round { append(&parts, "fp_round=true") } + if f.explicit_count > 0 { + append(&parts, fmt.tprintf("explicit_count=%d", f.explicit_count)) + } + if f.has_implicit { append(&parts, "has_implicit=true") } return strings.join(parts[:], ", ", context.temp_allocator) } @@ -375,9 +379,9 @@ Decode_Entry :: struct #packed { bits: u32, // 4 mask: u32, // 4 feature: Feature, // 1 - flags: Encoding_Flags, // 1 + flags: Encoding_Flags, // 2 } -#assert(size_of(Decode_Entry) == 20) +#assert(size_of(Decode_Entry) == 21) Decode_Index :: struct #packed { start: u16, diff --git a/core/rexcode/isa/riscv/tablegen/generated/decode_tables.odin b/core/rexcode/isa/riscv/tablegen/generated/decode_tables.odin index a737af544..8d5c3e980 100644 --- a/core/rexcode/isa/riscv/tablegen/generated/decode_tables.odin +++ b/core/rexcode/isa/riscv/tablegen/generated/decode_tables.odin @@ -8,7 +8,7 @@ package rexcode_riscv_generated import lib "../.." @(rodata) -DECODE_ENTRIES := [198]lib.Decode_Entry{ +DECODE_ENTRIES := [283]lib.Decode_Entry{ { .LB, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00000003, 0x0000707F, .I, {} }, { .LH, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001003, 0x0000707F, .I, {} }, { .LW, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002003, 0x0000707F, .I, {} }, @@ -18,11 +18,25 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ { .LD, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003003, 0x0000707F, .I, {rv64_only=true} }, { .FLW, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002007, 0x0000707F, .F, {} }, { .FLD, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003007, 0x0000707F, .D, {} }, + { .FLH, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001007, 0x0000707F, .ZFH, {} }, { .FENCE_I, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0000100F, 0xFFFFFFFF, .ZIFENCEI, {} }, { .FENCE, {.FENCE_FLAGS,.FENCE_FLAGS,.NONE,.NONE}, {.FENCE_PRED,.FENCE_SUCC,.NONE,.NONE}, 0x0000000F, 0x0000707F, .I, {} }, + { .CLZ, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60001013, 0xFFF0707F, .ZBB, {} }, + { .CTZ, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60101013, 0xFFF0707F, .ZBB, {} }, + { .CPOP, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60201013, 0xFFF0707F, .ZBB, {} }, + { .SEXT_B, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60401013, 0xFFF0707F, .ZBB, {} }, + { .SEXT_H, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60501013, 0xFFF0707F, .ZBB, {} }, + { .ORC_B, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x28705013, 0xFFF0707F, .ZBB, {} }, + { .REV8, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x69805013, 0xFFF0707F, .ZBB, {rv32_only=true} }, + { .REV8, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6B805013, 0xFFF0707F, .ZBB, {rv64_only=true} }, { .SLLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00001013, 0xFC00707F, .I, {} }, { .SRLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00005013, 0xFC00707F, .I, {} }, { .SRAI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x40005013, 0xFC00707F, .I, {} }, + { .RORI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x60005013, 0xFC00707F, .ZBB, {} }, + { .BCLRI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x48001013, 0xFC00707F, .ZBS, {} }, + { .BEXTI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x48005013, 0xFC00707F, .ZBS, {} }, + { .BINVI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x68001013, 0xFC00707F, .ZBS, {} }, + { .BSETI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x28001013, 0xFC00707F, .ZBS, {} }, { .ADDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000013, 0x0000707F, .I, {} }, { .SLTI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00002013, 0x0000707F, .I, {} }, { .SLTIU, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00003013, 0x0000707F, .I, {} }, @@ -30,9 +44,14 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ { .ORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00006013, 0x0000707F, .I, {} }, { .ANDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00007013, 0x0000707F, .I, {} }, { .AUIPC, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000017, 0x0000007F, .I, {} }, + { .CLZW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6000101B, 0xFFF0707F, .ZBB, {rv64_only=true} }, + { .CTZW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6010101B, 0xFFF0707F, .ZBB, {rv64_only=true} }, + { .CPOPW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6020101B, 0xFFF0707F, .ZBB, {rv64_only=true} }, { .SLLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000101B, 0xFE00707F, .I, {rv64_only=true} }, { .SRLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000501B, 0xFE00707F, .I, {rv64_only=true} }, { .SRAIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x4000501B, 0xFE00707F, .I, {rv64_only=true} }, + { .RORIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x6000501B, 0xFE00707F, .ZBB, {rv64_only=true} }, + { .SLLI_UW, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x0800101B, 0xFC00707F, .ZBA, {rv64_only=true} }, { .ADDIW, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x0000001B, 0x0000707F, .I, {rv64_only=true} }, { .SB, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00000023, 0x0000707F, .I, {} }, { .SH, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001023, 0x0000707F, .I, {} }, @@ -40,6 +59,7 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ { .SD, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003023, 0x0000707F, .I, {rv64_only=true} }, { .FSW, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002027, 0x0000707F, .F, {} }, { .FSD, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003027, 0x0000707F, .D, {} }, + { .FSH, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001027, 0x0000707F, .ZFH, {} }, { .LR_W, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000202F, 0xF9F0707F, .A, {} }, { .LR_D, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000302F, 0xF9F0707F, .A, {rv64_only=true} }, { .SC_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800202F, 0xF800707F, .A, {} }, @@ -62,6 +82,7 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ { .AMOMAX_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000302F, 0xF800707F, .A, {rv64_only=true} }, { .AMOMINU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000302F, 0xF800707F, .A, {rv64_only=true} }, { .AMOMAXU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000302F, 0xF800707F, .A, {rv64_only=true} }, + { .ZEXT_H, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x08004033, 0xFFF0707F, .ZBB, {rv32_only=true} }, { .ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000033, 0xFE00707F, .I, {} }, { .SUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40000033, 0xFE00707F, .I, {} }, { .SLL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00001033, 0xFE00707F, .I, {} }, @@ -80,7 +101,29 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ { .DIVU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02005033, 0xFE00707F, .M, {} }, { .REM, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02006033, 0xFE00707F, .M, {} }, { .REMU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02007033, 0xFE00707F, .M, {} }, + { .SH1ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002033, 0xFE00707F, .ZBA, {} }, + { .SH2ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20004033, 0xFE00707F, .ZBA, {} }, + { .SH3ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20006033, 0xFE00707F, .ZBA, {} }, + { .ANDN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40007033, 0xFE00707F, .ZBB, {} }, + { .ORN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40006033, 0xFE00707F, .ZBB, {} }, + { .XNOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40004033, 0xFE00707F, .ZBB, {} }, + { .MIN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A004033, 0xFE00707F, .ZBB, {} }, + { .MINU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A005033, 0xFE00707F, .ZBB, {} }, + { .MAX, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A006033, 0xFE00707F, .ZBB, {} }, + { .MAXU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A007033, 0xFE00707F, .ZBB, {} }, + { .ROL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x60001033, 0xFE00707F, .ZBB, {} }, + { .ROR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x60005033, 0xFE00707F, .ZBB, {} }, + { .CLMUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A001033, 0xFE00707F, .ZBC, {} }, + { .CLMULH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A003033, 0xFE00707F, .ZBC, {} }, + { .CLMULR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A002033, 0xFE00707F, .ZBC, {} }, + { .BCLR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x48001033, 0xFE00707F, .ZBS, {} }, + { .BEXT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x48005033, 0xFE00707F, .ZBS, {} }, + { .BINV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x68001033, 0xFE00707F, .ZBS, {} }, + { .BSET, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001033, 0xFE00707F, .ZBS, {} }, + { .CZERO_EQZ, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0E005033, 0xFE00707F, .ZICOND, {} }, + { .CZERO_NEZ, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0E007033, 0xFE00707F, .ZICOND, {} }, { .LUI, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000037, 0x0000007F, .I, {} }, + { .ZEXT_H, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x0800403B, 0xFFF0707F, .ZBB, {rv64_only=true} }, { .ADDW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000003B, 0xFE00707F, .I, {rv64_only=true} }, { .SUBW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000003B, 0xFE00707F, .I, {rv64_only=true} }, { .SLLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000103B, 0xFE00707F, .I, {rv64_only=true} }, @@ -91,42 +134,69 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ { .DIVUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200503B, 0xFE00707F, .M, {rv64_only=true} }, { .REMW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200603B, 0xFE00707F, .M, {rv64_only=true} }, { .REMUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200703B, 0xFE00707F, .M, {rv64_only=true} }, + { .ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0800003B, 0xFE00707F, .ZBA, {rv64_only=true} }, + { .SH1ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2000203B, 0xFE00707F, .ZBA, {rv64_only=true} }, + { .SH2ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2000403B, 0xFE00707F, .ZBA, {rv64_only=true} }, + { .SH3ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2000603B, 0xFE00707F, .ZBA, {rv64_only=true} }, + { .ROLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x6000103B, 0xFE00707F, .ZBB, {rv64_only=true} }, + { .RORW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x6000503B, 0xFE00707F, .ZBB, {rv64_only=true} }, { .FMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000043, 0x0600007F, .F, {fp_round=true} }, { .FMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000043, 0x0600007F, .D, {fp_round=true} }, + { .FMADD_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x04000043, 0x0600007F, .ZFH, {fp_round=true} }, { .FMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000047, 0x0600007F, .F, {fp_round=true} }, { .FMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000047, 0x0600007F, .D, {fp_round=true} }, + { .FMSUB_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x04000047, 0x0600007F, .ZFH, {fp_round=true} }, { .FNMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004B, 0x0600007F, .F, {fp_round=true} }, { .FNMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004B, 0x0600007F, .D, {fp_round=true} }, + { .FNMSUB_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0400004B, 0x0600007F, .ZFH, {fp_round=true} }, { .FNMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004F, 0x0600007F, .F, {fp_round=true} }, { .FNMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004F, 0x0600007F, .D, {fp_round=true} }, + { .FNMADD_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0400004F, 0x0600007F, .ZFH, {fp_round=true} }, { .FADD_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000053, 0xFE00007F, .F, {fp_round=true} }, { .FADD_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000053, 0xFE00007F, .D, {fp_round=true} }, + { .FADD_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x04000053, 0xFE00007F, .ZFH, {fp_round=true} }, { .FSUB_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x08000053, 0xFE00007F, .F, {fp_round=true} }, { .FSUB_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A000053, 0xFE00007F, .D, {fp_round=true} }, + { .FSUB_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0C000053, 0xFE00007F, .ZFH, {fp_round=true} }, { .FMUL_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x10000053, 0xFE00007F, .F, {fp_round=true} }, { .FMUL_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x12000053, 0xFE00007F, .D, {fp_round=true} }, + { .FMUL_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x14000053, 0xFE00007F, .ZFH, {fp_round=true} }, { .FDIV_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x18000053, 0xFE00007F, .F, {fp_round=true} }, { .FDIV_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1A000053, 0xFE00007F, .D, {fp_round=true} }, + { .FDIV_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1C000053, 0xFE00007F, .ZFH, {fp_round=true} }, { .FSGNJ_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20000053, 0xFE00707F, .F, {} }, { .FSGNJN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20001053, 0xFE00707F, .F, {} }, { .FSGNJX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002053, 0xFE00707F, .F, {} }, { .FSGNJ_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22000053, 0xFE00707F, .D, {} }, { .FSGNJN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22001053, 0xFE00707F, .D, {} }, { .FSGNJX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22002053, 0xFE00707F, .D, {} }, + { .FSGNJ_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x24000053, 0xFE00707F, .ZFH, {} }, + { .FSGNJN_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x24001053, 0xFE00707F, .ZFH, {} }, + { .FSGNJX_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x24002053, 0xFE00707F, .ZFH, {} }, { .FMIN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28000053, 0xFE00707F, .F, {} }, { .FMAX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001053, 0xFE00707F, .F, {} }, { .FMIN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A000053, 0xFE00707F, .D, {} }, { .FMAX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A001053, 0xFE00707F, .D, {} }, + { .FMIN_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2C000053, 0xFE00707F, .ZFH, {} }, + { .FMAX_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2C001053, 0xFE00707F, .ZFH, {} }, { .FCVT_S_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40100053, 0xFFF0007F, .D, {fp_round=true} }, + { .FCVT_S_H, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40200053, 0xFFF0007F, .ZFH, {fp_round=true} }, { .FCVT_D_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42000053, 0xFFF0007F, .D, {fp_round=true} }, + { .FCVT_D_H, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42200053, 0xFFF0007F, .ZFH, {fp_round=true} }, + { .FCVT_H_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x44000053, 0xFFF0007F, .ZFH, {fp_round=true} }, + { .FCVT_H_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x44100053, 0xFFF0007F, .ZFH, {fp_round=true} }, { .FSQRT_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x58000053, 0xFFF0007F, .F, {fp_round=true} }, { .FSQRT_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5A000053, 0xFFF0007F, .D, {fp_round=true} }, + { .FSQRT_H, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5C000053, 0xFFF0007F, .ZFH, {fp_round=true} }, { .FEQ_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0002053, 0xFE00707F, .F, {} }, { .FLT_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0001053, 0xFE00707F, .F, {} }, { .FLE_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0000053, 0xFE00707F, .F, {} }, { .FEQ_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2002053, 0xFE00707F, .D, {} }, { .FLT_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2001053, 0xFE00707F, .D, {} }, { .FLE_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2000053, 0xFE00707F, .D, {} }, + { .FEQ_H, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA4002053, 0xFE00707F, .ZFH, {} }, + { .FLT_H, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA4001053, 0xFE00707F, .ZFH, {} }, + { .FLE_H, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA4000053, 0xFE00707F, .ZFH, {} }, { .FCVT_W_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0000053, 0xFFF0007F, .F, {fp_round=true} }, { .FCVT_WU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0100053, 0xFFF0007F, .F, {fp_round=true} }, { .FCVT_L_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0200053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true} }, @@ -135,6 +205,10 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ { .FCVT_WU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2100053, 0xFFF0007F, .D, {fp_round=true} }, { .FCVT_L_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2200053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true} }, { .FCVT_LU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2300053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true} }, + { .FCVT_W_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4000053, 0xFFF0007F, .ZFH, {fp_round=true} }, + { .FCVT_WU_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4100053, 0xFFF0007F, .ZFH, {fp_round=true} }, + { .FCVT_L_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4200053, 0xFFF0007F, .ZFH, {rv64_only=true, fp_round=true} }, + { .FCVT_LU_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4300053, 0xFFF0007F, .ZFH, {rv64_only=true, fp_round=true} }, { .FCVT_S_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0000053, 0xFFF0007F, .F, {fp_round=true} }, { .FCVT_S_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0100053, 0xFFF0007F, .F, {fp_round=true} }, { .FCVT_S_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0200053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true} }, @@ -143,12 +217,19 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ { .FCVT_D_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2100053, 0xFFF0007F, .D, {fp_round=true} }, { .FCVT_D_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2200053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true} }, { .FCVT_D_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2300053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true} }, + { .FCVT_H_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4000053, 0xFFF0007F, .ZFH, {fp_round=true} }, + { .FCVT_H_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4100053, 0xFFF0007F, .ZFH, {fp_round=true} }, + { .FCVT_H_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4200053, 0xFFF0007F, .ZFH, {rv64_only=true, fp_round=true} }, + { .FCVT_H_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4300053, 0xFFF0007F, .ZFH, {rv64_only=true, fp_round=true} }, { .FMV_X_W, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0000053, 0xFFF0707F, .F, {} }, { .FCLASS_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0001053, 0xFFF0707F, .F, {} }, { .FCLASS_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2001053, 0xFFF0707F, .D, {} }, { .FMV_X_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2000053, 0xFFF0707F, .D, {rv64_only=true} }, + { .FMV_X_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE4000053, 0xFFF0707F, .ZFH, {} }, + { .FCLASS_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE4001053, 0xFFF0707F, .ZFH, {} }, { .FMV_W_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF0000053, 0xFFF0707F, .F, {} }, { .FMV_D_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF2000053, 0xFFF0707F, .D, {rv64_only=true} }, + { .FMV_H_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF4000053, 0xFFF0707F, .ZFH, {} }, { .BEQ, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00000063, 0x0000707F, .I, {branch=true} }, { .BNE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00001063, 0x0000707F, .I, {branch=true} }, { .BLT, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00004063, 0x0000707F, .I, {branch=true} }, @@ -159,6 +240,10 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ { .JAL, {.GPR,.REL21,.NONE,.NONE}, {.RD,.IMM_J,.NONE,.NONE}, 0x0000006F, 0x0000007F, .I, {branch=true} }, { .ECALL, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00000073, 0xFFFFFFFF, .I, {branch=true} }, { .EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00100073, 0xFFFFFFFF, .I, {branch=true} }, + { .MRET, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x30200073, 0xFFFFFFFF, .PRIV, {branch=true} }, + { .SRET, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x10200073, 0xFFFFFFFF, .PRIV, {branch=true} }, + { .WFI, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x10500073, 0xFFFFFFFF, .PRIV, {} }, + { .SFENCE_VMA, {.GPR,.GPR,.NONE,.NONE}, {.RS1,.RS2,.NONE,.NONE}, 0x12000073, 0xFE007FFF, .PRIV, {} }, { .CSRRW, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00001073, 0x0000707F, .ZICSR, {} }, { .CSRRS, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00002073, 0x0000707F, .ZICSR, {} }, { .CSRRC, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00003073, 0x0000707F, .ZICSR, {} }, @@ -212,82 +297,95 @@ DECODE_ENTRIES := [198]lib.Decode_Entry{ @(rodata) DECODE_INDEX_OPCODE := [128]lib.Decode_Index{ 0x03 = { 0, 7}, - 0x07 = { 7, 2}, - 0x0F = { 9, 2}, - 0x13 = { 11, 9}, - 0x17 = { 20, 1}, - 0x1B = { 21, 4}, - 0x23 = { 25, 4}, - 0x27 = { 29, 2}, - 0x2F = { 31, 22}, - 0x33 = { 53, 18}, - 0x37 = { 71, 1}, - 0x3B = { 72, 10}, - 0x43 = { 82, 2}, - 0x47 = { 84, 2}, - 0x4B = { 86, 2}, - 0x4F = { 88, 2}, - 0x53 = { 90, 50}, - 0x63 = { 140, 6}, - 0x67 = { 146, 1}, - 0x6F = { 147, 1}, - 0x73 = { 148, 8}, + 0x07 = { 7, 3}, + 0x0F = { 10, 2}, + 0x13 = { 12, 22}, + 0x17 = { 34, 1}, + 0x1B = { 35, 9}, + 0x23 = { 44, 4}, + 0x27 = { 48, 3}, + 0x2F = { 51, 22}, + 0x33 = { 73, 40}, + 0x37 = { 113, 1}, + 0x3B = { 114, 17}, + 0x43 = { 131, 3}, + 0x47 = { 134, 3}, + 0x4B = { 137, 3}, + 0x4F = { 140, 3}, + 0x53 = { 143, 78}, + 0x63 = { 221, 6}, + 0x67 = { 227, 1}, + 0x6F = { 228, 1}, + 0x73 = { 229, 12}, } @(rodata) DECODE_INDEX_OP_FP := [128]lib.Decode_Index{ - 0x00 = { 90, 1}, - 0x01 = { 91, 1}, - 0x04 = { 92, 1}, - 0x05 = { 93, 1}, - 0x08 = { 94, 1}, - 0x09 = { 95, 1}, - 0x0C = { 96, 1}, - 0x0D = { 97, 1}, - 0x10 = { 98, 3}, - 0x11 = { 101, 3}, - 0x14 = { 104, 2}, - 0x15 = { 106, 2}, - 0x20 = { 108, 1}, - 0x21 = { 109, 1}, - 0x2C = { 110, 1}, - 0x2D = { 111, 1}, - 0x50 = { 112, 3}, - 0x51 = { 115, 3}, - 0x60 = { 118, 4}, - 0x61 = { 122, 4}, - 0x68 = { 126, 4}, - 0x69 = { 130, 4}, - 0x70 = { 134, 2}, - 0x71 = { 136, 2}, - 0x78 = { 138, 1}, - 0x79 = { 139, 1}, + 0x00 = { 143, 1}, + 0x01 = { 144, 1}, + 0x02 = { 145, 1}, + 0x04 = { 146, 1}, + 0x05 = { 147, 1}, + 0x06 = { 148, 1}, + 0x08 = { 149, 1}, + 0x09 = { 150, 1}, + 0x0A = { 151, 1}, + 0x0C = { 152, 1}, + 0x0D = { 153, 1}, + 0x0E = { 154, 1}, + 0x10 = { 155, 3}, + 0x11 = { 158, 3}, + 0x12 = { 161, 3}, + 0x14 = { 164, 2}, + 0x15 = { 166, 2}, + 0x16 = { 168, 2}, + 0x20 = { 170, 2}, + 0x21 = { 172, 2}, + 0x22 = { 174, 2}, + 0x2C = { 176, 1}, + 0x2D = { 177, 1}, + 0x2E = { 178, 1}, + 0x50 = { 179, 3}, + 0x51 = { 182, 3}, + 0x52 = { 185, 3}, + 0x60 = { 188, 4}, + 0x61 = { 192, 4}, + 0x62 = { 196, 4}, + 0x68 = { 200, 4}, + 0x69 = { 204, 4}, + 0x6A = { 208, 4}, + 0x70 = { 212, 2}, + 0x71 = { 214, 2}, + 0x72 = { 216, 2}, + 0x78 = { 218, 1}, + 0x79 = { 219, 1}, + 0x7A = { 220, 1}, } @(rodata) DECODE_INDEX_RVC := [32]lib.Decode_Index{ - 0x00 = { 156, 1}, - 0x01 = { 157, 2}, - 0x02 = { 159, 1}, - 0x04 = { 160, 1}, - 0x05 = { 161, 2}, - 0x06 = { 163, 1}, - 0x08 = { 164, 1}, - 0x09 = { 165, 1}, - 0x0A = { 166, 1}, - 0x0C = { 167, 2}, - 0x0D = { 169, 2}, - 0x0E = { 171, 2}, - 0x11 = { 173, 9}, - 0x12 = { 182, 5}, - 0x14 = { 187, 1}, - 0x15 = { 188, 1}, - 0x16 = { 189, 1}, - 0x18 = { 190, 1}, - 0x19 = { 191, 1}, - 0x1A = { 192, 1}, - 0x1C = { 193, 2}, - 0x1D = { 195, 1}, - 0x1E = { 196, 2}, + 0x00 = { 241, 1}, + 0x01 = { 242, 2}, + 0x02 = { 244, 1}, + 0x04 = { 245, 1}, + 0x05 = { 246, 2}, + 0x06 = { 248, 1}, + 0x08 = { 249, 1}, + 0x09 = { 250, 1}, + 0x0A = { 251, 1}, + 0x0C = { 252, 2}, + 0x0D = { 254, 2}, + 0x0E = { 256, 2}, + 0x11 = { 258, 9}, + 0x12 = { 267, 5}, + 0x14 = { 272, 1}, + 0x15 = { 273, 1}, + 0x16 = { 274, 1}, + 0x18 = { 275, 1}, + 0x19 = { 276, 1}, + 0x1A = { 277, 1}, + 0x1C = { 278, 2}, + 0x1D = { 280, 1}, + 0x1E = { 281, 2}, } diff --git a/core/rexcode/isa/riscv/tablegen/generated/encode_tables.odin b/core/rexcode/isa/riscv/tablegen/generated/encode_tables.odin index 4bed4668a..d66ef1d02 100644 --- a/core/rexcode/isa/riscv/tablegen/generated/encode_tables.odin +++ b/core/rexcode/isa/riscv/tablegen/generated/encode_tables.odin @@ -8,107 +8,107 @@ package rexcode_riscv_generated import lib "../.." @(rodata) -ENCODE_FORMS := [198]lib.Encoding{ +ENCODE_FORMS := [283]lib.Encoding{ // .LUI - { .LUI, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000037, 0x0000007F, .I, {} }, + { .LUI, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000037, 0x0000007F, .I, {explicit_count=2} }, // .AUIPC - { .AUIPC, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000017, 0x0000007F, .I, {} }, + { .AUIPC, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000017, 0x0000007F, .I, {explicit_count=2} }, // .JAL - { .JAL, {.GPR,.REL21,.NONE,.NONE}, {.RD,.IMM_J,.NONE,.NONE}, 0x0000006F, 0x0000007F, .I, {branch=true} }, + { .JAL, {.GPR,.REL21,.NONE,.NONE}, {.RD,.IMM_J,.NONE,.NONE}, 0x0000006F, 0x0000007F, .I, {branch=true, explicit_count=2} }, // .JALR - { .JALR, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000067, 0x0000707F, .I, {branch=true} }, + { .JALR, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000067, 0x0000707F, .I, {branch=true, explicit_count=3} }, // .BEQ - { .BEQ, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00000063, 0x0000707F, .I, {branch=true} }, + { .BEQ, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00000063, 0x0000707F, .I, {branch=true, explicit_count=3} }, // .BNE - { .BNE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00001063, 0x0000707F, .I, {branch=true} }, + { .BNE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00001063, 0x0000707F, .I, {branch=true, explicit_count=3} }, // .BLT - { .BLT, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00004063, 0x0000707F, .I, {branch=true} }, + { .BLT, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00004063, 0x0000707F, .I, {branch=true, explicit_count=3} }, // .BGE - { .BGE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00005063, 0x0000707F, .I, {branch=true} }, + { .BGE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00005063, 0x0000707F, .I, {branch=true, explicit_count=3} }, // .BLTU - { .BLTU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00006063, 0x0000707F, .I, {branch=true} }, + { .BLTU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00006063, 0x0000707F, .I, {branch=true, explicit_count=3} }, // .BGEU - { .BGEU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00007063, 0x0000707F, .I, {branch=true} }, + { .BGEU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00007063, 0x0000707F, .I, {branch=true, explicit_count=3} }, // .LB - { .LB, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00000003, 0x0000707F, .I, {} }, + { .LB, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00000003, 0x0000707F, .I, {explicit_count=2} }, // .LH - { .LH, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001003, 0x0000707F, .I, {} }, + { .LH, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001003, 0x0000707F, .I, {explicit_count=2} }, // .LW - { .LW, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002003, 0x0000707F, .I, {} }, + { .LW, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002003, 0x0000707F, .I, {explicit_count=2} }, // .LBU - { .LBU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00004003, 0x0000707F, .I, {} }, + { .LBU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00004003, 0x0000707F, .I, {explicit_count=2} }, // .LHU - { .LHU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00005003, 0x0000707F, .I, {} }, + { .LHU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00005003, 0x0000707F, .I, {explicit_count=2} }, // .SB - { .SB, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00000023, 0x0000707F, .I, {} }, + { .SB, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00000023, 0x0000707F, .I, {explicit_count=2} }, // .SH - { .SH, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001023, 0x0000707F, .I, {} }, + { .SH, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001023, 0x0000707F, .I, {explicit_count=2} }, // .SW - { .SW, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002023, 0x0000707F, .I, {} }, + { .SW, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002023, 0x0000707F, .I, {explicit_count=2} }, // .LWU - { .LWU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00006003, 0x0000707F, .I, {rv64_only=true} }, + { .LWU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00006003, 0x0000707F, .I, {rv64_only=true, explicit_count=2} }, // .LD - { .LD, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003003, 0x0000707F, .I, {rv64_only=true} }, + { .LD, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003003, 0x0000707F, .I, {rv64_only=true, explicit_count=2} }, // .SD - { .SD, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003023, 0x0000707F, .I, {rv64_only=true} }, + { .SD, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003023, 0x0000707F, .I, {rv64_only=true, explicit_count=2} }, // .ADDI - { .ADDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000013, 0x0000707F, .I, {} }, + { .ADDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000013, 0x0000707F, .I, {explicit_count=3} }, // .SLTI - { .SLTI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00002013, 0x0000707F, .I, {} }, + { .SLTI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00002013, 0x0000707F, .I, {explicit_count=3} }, // .SLTIU - { .SLTIU, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00003013, 0x0000707F, .I, {} }, + { .SLTIU, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00003013, 0x0000707F, .I, {explicit_count=3} }, // .XORI - { .XORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00004013, 0x0000707F, .I, {} }, + { .XORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00004013, 0x0000707F, .I, {explicit_count=3} }, // .ORI - { .ORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00006013, 0x0000707F, .I, {} }, + { .ORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00006013, 0x0000707F, .I, {explicit_count=3} }, // .ANDI - { .ANDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00007013, 0x0000707F, .I, {} }, + { .ANDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00007013, 0x0000707F, .I, {explicit_count=3} }, // .SLLI - { .SLLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00001013, 0xFC00707F, .I, {} }, + { .SLLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00001013, 0xFC00707F, .I, {explicit_count=3} }, // .SRLI - { .SRLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00005013, 0xFC00707F, .I, {} }, + { .SRLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00005013, 0xFC00707F, .I, {explicit_count=3} }, // .SRAI - { .SRAI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x40005013, 0xFC00707F, .I, {} }, + { .SRAI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x40005013, 0xFC00707F, .I, {explicit_count=3} }, // .ADDIW - { .ADDIW, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x0000001B, 0x0000707F, .I, {rv64_only=true} }, + { .ADDIW, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x0000001B, 0x0000707F, .I, {rv64_only=true, explicit_count=3} }, // .SLLIW - { .SLLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000101B, 0xFE00707F, .I, {rv64_only=true} }, + { .SLLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000101B, 0xFE00707F, .I, {rv64_only=true, explicit_count=3} }, // .SRLIW - { .SRLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000501B, 0xFE00707F, .I, {rv64_only=true} }, + { .SRLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000501B, 0xFE00707F, .I, {rv64_only=true, explicit_count=3} }, // .SRAIW - { .SRAIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x4000501B, 0xFE00707F, .I, {rv64_only=true} }, + { .SRAIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x4000501B, 0xFE00707F, .I, {rv64_only=true, explicit_count=3} }, // .ADD - { .ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000033, 0xFE00707F, .I, {} }, + { .ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000033, 0xFE00707F, .I, {explicit_count=3} }, // .SUB - { .SUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40000033, 0xFE00707F, .I, {} }, + { .SUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40000033, 0xFE00707F, .I, {explicit_count=3} }, // .SLL - { .SLL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00001033, 0xFE00707F, .I, {} }, + { .SLL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00001033, 0xFE00707F, .I, {explicit_count=3} }, // .SLT - { .SLT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00002033, 0xFE00707F, .I, {} }, + { .SLT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00002033, 0xFE00707F, .I, {explicit_count=3} }, // .SLTU - { .SLTU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00003033, 0xFE00707F, .I, {} }, + { .SLTU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00003033, 0xFE00707F, .I, {explicit_count=3} }, // .XOR - { .XOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00004033, 0xFE00707F, .I, {} }, + { .XOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00004033, 0xFE00707F, .I, {explicit_count=3} }, // .SRL - { .SRL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00005033, 0xFE00707F, .I, {} }, + { .SRL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00005033, 0xFE00707F, .I, {explicit_count=3} }, // .SRA - { .SRA, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40005033, 0xFE00707F, .I, {} }, + { .SRA, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40005033, 0xFE00707F, .I, {explicit_count=3} }, // .OR - { .OR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00006033, 0xFE00707F, .I, {} }, + { .OR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00006033, 0xFE00707F, .I, {explicit_count=3} }, // .AND - { .AND, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00007033, 0xFE00707F, .I, {} }, + { .AND, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00007033, 0xFE00707F, .I, {explicit_count=3} }, // .ADDW - { .ADDW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000003B, 0xFE00707F, .I, {rv64_only=true} }, + { .ADDW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000003B, 0xFE00707F, .I, {rv64_only=true, explicit_count=3} }, // .SUBW - { .SUBW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000003B, 0xFE00707F, .I, {rv64_only=true} }, + { .SUBW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000003B, 0xFE00707F, .I, {rv64_only=true, explicit_count=3} }, // .SLLW - { .SLLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000103B, 0xFE00707F, .I, {rv64_only=true} }, + { .SLLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000103B, 0xFE00707F, .I, {rv64_only=true, explicit_count=3} }, // .SRLW - { .SRLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000503B, 0xFE00707F, .I, {rv64_only=true} }, + { .SRLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000503B, 0xFE00707F, .I, {rv64_only=true, explicit_count=3} }, // .SRAW - { .SRAW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000503B, 0xFE00707F, .I, {rv64_only=true} }, + { .SRAW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000503B, 0xFE00707F, .I, {rv64_only=true, explicit_count=3} }, // .FENCE - { .FENCE, {.FENCE_FLAGS,.FENCE_FLAGS,.NONE,.NONE}, {.FENCE_PRED,.FENCE_SUCC,.NONE,.NONE}, 0x0000000F, 0x0000707F, .I, {} }, + { .FENCE, {.FENCE_FLAGS,.FENCE_FLAGS,.NONE,.NONE}, {.FENCE_PRED,.FENCE_SUCC,.NONE,.NONE}, 0x0000000F, 0x0000707F, .I, {explicit_count=2} }, // .FENCE_I { .FENCE_I, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0000100F, 0xFFFFFFFF, .ZIFENCEI, {} }, // .ECALL @@ -116,299 +116,467 @@ ENCODE_FORMS := [198]lib.Encoding{ // .EBREAK { .EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00100073, 0xFFFFFFFF, .I, {branch=true} }, // .CSRRW - { .CSRRW, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00001073, 0x0000707F, .ZICSR, {} }, + { .CSRRW, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00001073, 0x0000707F, .ZICSR, {explicit_count=3} }, // .CSRRS - { .CSRRS, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00002073, 0x0000707F, .ZICSR, {} }, + { .CSRRS, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00002073, 0x0000707F, .ZICSR, {explicit_count=3} }, // .CSRRC - { .CSRRC, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00003073, 0x0000707F, .ZICSR, {} }, + { .CSRRC, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00003073, 0x0000707F, .ZICSR, {explicit_count=3} }, // .CSRRWI - { .CSRRWI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00005073, 0x0000707F, .ZICSR, {} }, + { .CSRRWI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00005073, 0x0000707F, .ZICSR, {explicit_count=3} }, // .CSRRSI - { .CSRRSI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00006073, 0x0000707F, .ZICSR, {} }, + { .CSRRSI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00006073, 0x0000707F, .ZICSR, {explicit_count=3} }, // .CSRRCI - { .CSRRCI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00007073, 0x0000707F, .ZICSR, {} }, + { .CSRRCI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00007073, 0x0000707F, .ZICSR, {explicit_count=3} }, // .MUL - { .MUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000033, 0xFE00707F, .M, {} }, + { .MUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000033, 0xFE00707F, .M, {explicit_count=3} }, // .MULH - { .MULH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02001033, 0xFE00707F, .M, {} }, + { .MULH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02001033, 0xFE00707F, .M, {explicit_count=3} }, // .MULHSU - { .MULHSU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02002033, 0xFE00707F, .M, {} }, + { .MULHSU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02002033, 0xFE00707F, .M, {explicit_count=3} }, // .MULHU - { .MULHU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02003033, 0xFE00707F, .M, {} }, + { .MULHU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02003033, 0xFE00707F, .M, {explicit_count=3} }, // .DIV - { .DIV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02004033, 0xFE00707F, .M, {} }, + { .DIV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02004033, 0xFE00707F, .M, {explicit_count=3} }, // .DIVU - { .DIVU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02005033, 0xFE00707F, .M, {} }, + { .DIVU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02005033, 0xFE00707F, .M, {explicit_count=3} }, // .REM - { .REM, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02006033, 0xFE00707F, .M, {} }, + { .REM, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02006033, 0xFE00707F, .M, {explicit_count=3} }, // .REMU - { .REMU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02007033, 0xFE00707F, .M, {} }, + { .REMU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02007033, 0xFE00707F, .M, {explicit_count=3} }, // .MULW - { .MULW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200003B, 0xFE00707F, .M, {rv64_only=true} }, + { .MULW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200003B, 0xFE00707F, .M, {rv64_only=true, explicit_count=3} }, // .DIVW - { .DIVW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200403B, 0xFE00707F, .M, {rv64_only=true} }, + { .DIVW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200403B, 0xFE00707F, .M, {rv64_only=true, explicit_count=3} }, // .DIVUW - { .DIVUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200503B, 0xFE00707F, .M, {rv64_only=true} }, + { .DIVUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200503B, 0xFE00707F, .M, {rv64_only=true, explicit_count=3} }, // .REMW - { .REMW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200603B, 0xFE00707F, .M, {rv64_only=true} }, + { .REMW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200603B, 0xFE00707F, .M, {rv64_only=true, explicit_count=3} }, // .REMUW - { .REMUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200703B, 0xFE00707F, .M, {rv64_only=true} }, + { .REMUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200703B, 0xFE00707F, .M, {rv64_only=true, explicit_count=3} }, // .LR_W - { .LR_W, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000202F, 0xF9F0707F, .A, {} }, + { .LR_W, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000202F, 0xF9F0707F, .A, {explicit_count=2} }, // .SC_W - { .SC_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800202F, 0xF800707F, .A, {} }, + { .SC_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800202F, 0xF800707F, .A, {explicit_count=3} }, // .AMOSWAP_W - { .AMOSWAP_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800202F, 0xF800707F, .A, {} }, + { .AMOSWAP_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800202F, 0xF800707F, .A, {explicit_count=3} }, // .AMOADD_W - { .AMOADD_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000202F, 0xF800707F, .A, {} }, + { .AMOADD_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000202F, 0xF800707F, .A, {explicit_count=3} }, // .AMOXOR_W - { .AMOXOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000202F, 0xF800707F, .A, {} }, + { .AMOXOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000202F, 0xF800707F, .A, {explicit_count=3} }, // .AMOAND_W - { .AMOAND_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000202F, 0xF800707F, .A, {} }, + { .AMOAND_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000202F, 0xF800707F, .A, {explicit_count=3} }, // .AMOOR_W - { .AMOOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000202F, 0xF800707F, .A, {} }, + { .AMOOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000202F, 0xF800707F, .A, {explicit_count=3} }, // .AMOMIN_W - { .AMOMIN_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000202F, 0xF800707F, .A, {} }, + { .AMOMIN_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000202F, 0xF800707F, .A, {explicit_count=3} }, // .AMOMAX_W - { .AMOMAX_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000202F, 0xF800707F, .A, {} }, + { .AMOMAX_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000202F, 0xF800707F, .A, {explicit_count=3} }, // .AMOMINU_W - { .AMOMINU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000202F, 0xF800707F, .A, {} }, + { .AMOMINU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000202F, 0xF800707F, .A, {explicit_count=3} }, // .AMOMAXU_W - { .AMOMAXU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000202F, 0xF800707F, .A, {} }, + { .AMOMAXU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000202F, 0xF800707F, .A, {explicit_count=3} }, // .LR_D - { .LR_D, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000302F, 0xF9F0707F, .A, {rv64_only=true} }, + { .LR_D, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000302F, 0xF9F0707F, .A, {rv64_only=true, explicit_count=2} }, // .SC_D - { .SC_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800302F, 0xF800707F, .A, {rv64_only=true} }, + { .SC_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .AMOSWAP_D - { .AMOSWAP_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800302F, 0xF800707F, .A, {rv64_only=true} }, + { .AMOSWAP_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .AMOADD_D - { .AMOADD_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000302F, 0xF800707F, .A, {rv64_only=true} }, + { .AMOADD_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .AMOXOR_D - { .AMOXOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000302F, 0xF800707F, .A, {rv64_only=true} }, + { .AMOXOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .AMOAND_D - { .AMOAND_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000302F, 0xF800707F, .A, {rv64_only=true} }, + { .AMOAND_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .AMOOR_D - { .AMOOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000302F, 0xF800707F, .A, {rv64_only=true} }, + { .AMOOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .AMOMIN_D - { .AMOMIN_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000302F, 0xF800707F, .A, {rv64_only=true} }, + { .AMOMIN_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .AMOMAX_D - { .AMOMAX_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000302F, 0xF800707F, .A, {rv64_only=true} }, + { .AMOMAX_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .AMOMINU_D - { .AMOMINU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000302F, 0xF800707F, .A, {rv64_only=true} }, + { .AMOMINU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .AMOMAXU_D - { .AMOMAXU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000302F, 0xF800707F, .A, {rv64_only=true} }, + { .AMOMAXU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000302F, 0xF800707F, .A, {rv64_only=true, explicit_count=3} }, // .FLW - { .FLW, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002007, 0x0000707F, .F, {} }, + { .FLW, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002007, 0x0000707F, .F, {explicit_count=2} }, // .FSW - { .FSW, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002027, 0x0000707F, .F, {} }, + { .FSW, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002027, 0x0000707F, .F, {explicit_count=2} }, // .FMADD_S - { .FMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000043, 0x0600007F, .F, {fp_round=true} }, + { .FMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000043, 0x0600007F, .F, {fp_round=true, explicit_count=4} }, // .FMSUB_S - { .FMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000047, 0x0600007F, .F, {fp_round=true} }, + { .FMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000047, 0x0600007F, .F, {fp_round=true, explicit_count=4} }, // .FNMSUB_S - { .FNMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004B, 0x0600007F, .F, {fp_round=true} }, + { .FNMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004B, 0x0600007F, .F, {fp_round=true, explicit_count=4} }, // .FNMADD_S - { .FNMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004F, 0x0600007F, .F, {fp_round=true} }, + { .FNMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004F, 0x0600007F, .F, {fp_round=true, explicit_count=4} }, // .FADD_S - { .FADD_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000053, 0xFE00007F, .F, {fp_round=true} }, + { .FADD_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000053, 0xFE00007F, .F, {fp_round=true, explicit_count=3} }, // .FSUB_S - { .FSUB_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x08000053, 0xFE00007F, .F, {fp_round=true} }, + { .FSUB_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x08000053, 0xFE00007F, .F, {fp_round=true, explicit_count=3} }, // .FMUL_S - { .FMUL_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x10000053, 0xFE00007F, .F, {fp_round=true} }, + { .FMUL_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x10000053, 0xFE00007F, .F, {fp_round=true, explicit_count=3} }, // .FDIV_S - { .FDIV_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x18000053, 0xFE00007F, .F, {fp_round=true} }, + { .FDIV_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x18000053, 0xFE00007F, .F, {fp_round=true, explicit_count=3} }, // .FSQRT_S - { .FSQRT_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x58000053, 0xFFF0007F, .F, {fp_round=true} }, + { .FSQRT_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x58000053, 0xFFF0007F, .F, {fp_round=true, explicit_count=2} }, // .FSGNJ_S - { .FSGNJ_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20000053, 0xFE00707F, .F, {} }, + { .FSGNJ_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20000053, 0xFE00707F, .F, {explicit_count=3} }, // .FSGNJN_S - { .FSGNJN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20001053, 0xFE00707F, .F, {} }, + { .FSGNJN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20001053, 0xFE00707F, .F, {explicit_count=3} }, // .FSGNJX_S - { .FSGNJX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002053, 0xFE00707F, .F, {} }, + { .FSGNJX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002053, 0xFE00707F, .F, {explicit_count=3} }, // .FMIN_S - { .FMIN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28000053, 0xFE00707F, .F, {} }, + { .FMIN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28000053, 0xFE00707F, .F, {explicit_count=3} }, // .FMAX_S - { .FMAX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001053, 0xFE00707F, .F, {} }, + { .FMAX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001053, 0xFE00707F, .F, {explicit_count=3} }, // .FCVT_W_S - { .FCVT_W_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0000053, 0xFFF0007F, .F, {fp_round=true} }, + { .FCVT_W_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0000053, 0xFFF0007F, .F, {fp_round=true, explicit_count=2} }, // .FCVT_WU_S - { .FCVT_WU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0100053, 0xFFF0007F, .F, {fp_round=true} }, + { .FCVT_WU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0100053, 0xFFF0007F, .F, {fp_round=true, explicit_count=2} }, // .FMV_X_W - { .FMV_X_W, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0000053, 0xFFF0707F, .F, {} }, + { .FMV_X_W, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0000053, 0xFFF0707F, .F, {explicit_count=2} }, // .FEQ_S - { .FEQ_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0002053, 0xFE00707F, .F, {} }, + { .FEQ_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0002053, 0xFE00707F, .F, {explicit_count=3} }, // .FLT_S - { .FLT_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0001053, 0xFE00707F, .F, {} }, + { .FLT_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0001053, 0xFE00707F, .F, {explicit_count=3} }, // .FLE_S - { .FLE_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0000053, 0xFE00707F, .F, {} }, + { .FLE_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0000053, 0xFE00707F, .F, {explicit_count=3} }, // .FCLASS_S - { .FCLASS_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0001053, 0xFFF0707F, .F, {} }, + { .FCLASS_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0001053, 0xFFF0707F, .F, {explicit_count=2} }, // .FCVT_S_W - { .FCVT_S_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0000053, 0xFFF0007F, .F, {fp_round=true} }, + { .FCVT_S_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0000053, 0xFFF0007F, .F, {fp_round=true, explicit_count=2} }, // .FCVT_S_WU - { .FCVT_S_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0100053, 0xFFF0007F, .F, {fp_round=true} }, + { .FCVT_S_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0100053, 0xFFF0007F, .F, {fp_round=true, explicit_count=2} }, // .FMV_W_X - { .FMV_W_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF0000053, 0xFFF0707F, .F, {} }, + { .FMV_W_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF0000053, 0xFFF0707F, .F, {explicit_count=2} }, // .FCVT_L_S - { .FCVT_L_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0200053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true} }, + { .FCVT_L_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0200053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true, explicit_count=2} }, // .FCVT_LU_S - { .FCVT_LU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0300053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true} }, + { .FCVT_LU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0300053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true, explicit_count=2} }, // .FCVT_S_L - { .FCVT_S_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0200053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true} }, + { .FCVT_S_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0200053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true, explicit_count=2} }, // .FCVT_S_LU - { .FCVT_S_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0300053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true} }, + { .FCVT_S_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0300053, 0xFFF0007F, .F, {rv64_only=true, fp_round=true, explicit_count=2} }, // .FLD - { .FLD, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003007, 0x0000707F, .D, {} }, + { .FLD, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003007, 0x0000707F, .D, {explicit_count=2} }, // .FSD - { .FSD, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003027, 0x0000707F, .D, {} }, + { .FSD, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003027, 0x0000707F, .D, {explicit_count=2} }, // .FMADD_D - { .FMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000043, 0x0600007F, .D, {fp_round=true} }, + { .FMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000043, 0x0600007F, .D, {fp_round=true, explicit_count=4} }, // .FMSUB_D - { .FMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000047, 0x0600007F, .D, {fp_round=true} }, + { .FMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000047, 0x0600007F, .D, {fp_round=true, explicit_count=4} }, // .FNMSUB_D - { .FNMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004B, 0x0600007F, .D, {fp_round=true} }, + { .FNMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004B, 0x0600007F, .D, {fp_round=true, explicit_count=4} }, // .FNMADD_D - { .FNMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004F, 0x0600007F, .D, {fp_round=true} }, + { .FNMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004F, 0x0600007F, .D, {fp_round=true, explicit_count=4} }, // .FADD_D - { .FADD_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000053, 0xFE00007F, .D, {fp_round=true} }, + { .FADD_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000053, 0xFE00007F, .D, {fp_round=true, explicit_count=3} }, // .FSUB_D - { .FSUB_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A000053, 0xFE00007F, .D, {fp_round=true} }, + { .FSUB_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A000053, 0xFE00007F, .D, {fp_round=true, explicit_count=3} }, // .FMUL_D - { .FMUL_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x12000053, 0xFE00007F, .D, {fp_round=true} }, + { .FMUL_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x12000053, 0xFE00007F, .D, {fp_round=true, explicit_count=3} }, // .FDIV_D - { .FDIV_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1A000053, 0xFE00007F, .D, {fp_round=true} }, + { .FDIV_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1A000053, 0xFE00007F, .D, {fp_round=true, explicit_count=3} }, // .FSQRT_D - { .FSQRT_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5A000053, 0xFFF0007F, .D, {fp_round=true} }, + { .FSQRT_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5A000053, 0xFFF0007F, .D, {fp_round=true, explicit_count=2} }, // .FSGNJ_D - { .FSGNJ_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22000053, 0xFE00707F, .D, {} }, + { .FSGNJ_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22000053, 0xFE00707F, .D, {explicit_count=3} }, // .FSGNJN_D - { .FSGNJN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22001053, 0xFE00707F, .D, {} }, + { .FSGNJN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22001053, 0xFE00707F, .D, {explicit_count=3} }, // .FSGNJX_D - { .FSGNJX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22002053, 0xFE00707F, .D, {} }, + { .FSGNJX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22002053, 0xFE00707F, .D, {explicit_count=3} }, // .FMIN_D - { .FMIN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A000053, 0xFE00707F, .D, {} }, + { .FMIN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A000053, 0xFE00707F, .D, {explicit_count=3} }, // .FMAX_D - { .FMAX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A001053, 0xFE00707F, .D, {} }, + { .FMAX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A001053, 0xFE00707F, .D, {explicit_count=3} }, // .FCVT_S_D - { .FCVT_S_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40100053, 0xFFF0007F, .D, {fp_round=true} }, + { .FCVT_S_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40100053, 0xFFF0007F, .D, {fp_round=true, explicit_count=2} }, // .FCVT_D_S - { .FCVT_D_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42000053, 0xFFF0007F, .D, {fp_round=true} }, + { .FCVT_D_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42000053, 0xFFF0007F, .D, {fp_round=true, explicit_count=2} }, // .FEQ_D - { .FEQ_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2002053, 0xFE00707F, .D, {} }, + { .FEQ_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2002053, 0xFE00707F, .D, {explicit_count=3} }, // .FLT_D - { .FLT_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2001053, 0xFE00707F, .D, {} }, + { .FLT_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2001053, 0xFE00707F, .D, {explicit_count=3} }, // .FLE_D - { .FLE_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2000053, 0xFE00707F, .D, {} }, + { .FLE_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2000053, 0xFE00707F, .D, {explicit_count=3} }, // .FCLASS_D - { .FCLASS_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2001053, 0xFFF0707F, .D, {} }, + { .FCLASS_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2001053, 0xFFF0707F, .D, {explicit_count=2} }, // .FCVT_W_D - { .FCVT_W_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2000053, 0xFFF0007F, .D, {fp_round=true} }, + { .FCVT_W_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2000053, 0xFFF0007F, .D, {fp_round=true, explicit_count=2} }, // .FCVT_WU_D - { .FCVT_WU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2100053, 0xFFF0007F, .D, {fp_round=true} }, + { .FCVT_WU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2100053, 0xFFF0007F, .D, {fp_round=true, explicit_count=2} }, // .FCVT_D_W - { .FCVT_D_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2000053, 0xFFF0007F, .D, {fp_round=true} }, + { .FCVT_D_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2000053, 0xFFF0007F, .D, {fp_round=true, explicit_count=2} }, // .FCVT_D_WU - { .FCVT_D_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2100053, 0xFFF0007F, .D, {fp_round=true} }, + { .FCVT_D_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2100053, 0xFFF0007F, .D, {fp_round=true, explicit_count=2} }, // .FCVT_L_D - { .FCVT_L_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2200053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true} }, + { .FCVT_L_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2200053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true, explicit_count=2} }, // .FCVT_LU_D - { .FCVT_LU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2300053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true} }, + { .FCVT_LU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2300053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true, explicit_count=2} }, // .FCVT_D_L - { .FCVT_D_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2200053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true} }, + { .FCVT_D_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2200053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true, explicit_count=2} }, // .FCVT_D_LU - { .FCVT_D_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2300053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true} }, + { .FCVT_D_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2300053, 0xFFF0007F, .D, {rv64_only=true, fp_round=true, explicit_count=2} }, // .FMV_X_D - { .FMV_X_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2000053, 0xFFF0707F, .D, {rv64_only=true} }, + { .FMV_X_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2000053, 0xFFF0707F, .D, {rv64_only=true, explicit_count=2} }, // .FMV_D_X - { .FMV_D_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF2000053, 0xFFF0707F, .D, {rv64_only=true} }, + { .FMV_D_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF2000053, 0xFFF0707F, .D, {rv64_only=true, explicit_count=2} }, // .C_NOP { .C_NOP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00000001, 0x0000FFFF, .C, {} }, // .C_EBREAK { .C_EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00009002, 0x0000FFFF, .C, {} }, // .C_ADDI4SPN - { .C_ADDI4SPN, {.GPR_C,.GPR_SP,.IMM_C8U,.NONE}, {.C_RD_PRIMED,.NONE,.C_IMM_CIW,.NONE}, 0x00000000, 0x0000E003, .C, {} }, + { .C_ADDI4SPN, {.GPR_C,.GPR_SP,.IMM_C8U,.NONE}, {.C_RD_PRIMED,.NONE,.C_IMM_CIW,.NONE}, 0x00000000, 0x0000E003, .C, {explicit_count=2, has_implicit=true} }, // .C_LW - { .C_LW, {.GPR_C,.MEM_C_W,.NONE,.NONE}, {.C_RD_PRIMED,.C_OFFSET_BASE_W,.NONE,.NONE}, 0x00004000, 0x0000E003, .C, {} }, + { .C_LW, {.GPR_C,.MEM_C_W,.NONE,.NONE}, {.C_RD_PRIMED,.C_OFFSET_BASE_W,.NONE,.NONE}, 0x00004000, 0x0000E003, .C, {explicit_count=2} }, // .C_LD - { .C_LD, {.GPR_C,.MEM_C_D,.NONE,.NONE}, {.C_RD_PRIMED,.C_OFFSET_BASE_D,.NONE,.NONE}, 0x00006000, 0x0000E003, .C, {rv64_only=true} }, + { .C_LD, {.GPR_C,.MEM_C_D,.NONE,.NONE}, {.C_RD_PRIMED,.C_OFFSET_BASE_D,.NONE,.NONE}, 0x00006000, 0x0000E003, .C, {rv64_only=true, explicit_count=2} }, // .C_SW - { .C_SW, {.GPR_C,.MEM_C_W,.NONE,.NONE}, {.C_RS2_PRIMED,.C_OFFSET_BASE_W,.NONE,.NONE}, 0x0000C000, 0x0000E003, .C, {} }, + { .C_SW, {.GPR_C,.MEM_C_W,.NONE,.NONE}, {.C_RS2_PRIMED,.C_OFFSET_BASE_W,.NONE,.NONE}, 0x0000C000, 0x0000E003, .C, {explicit_count=2} }, // .C_SD - { .C_SD, {.GPR_C,.MEM_C_D,.NONE,.NONE}, {.C_RS2_PRIMED,.C_OFFSET_BASE_D,.NONE,.NONE}, 0x0000E000, 0x0000E003, .C, {rv64_only=true} }, + { .C_SD, {.GPR_C,.MEM_C_D,.NONE,.NONE}, {.C_RS2_PRIMED,.C_OFFSET_BASE_D,.NONE,.NONE}, 0x0000E000, 0x0000E003, .C, {rv64_only=true, explicit_count=2} }, // .C_FLW - { .C_FLW, {.FPR_C,.MEM_C_W,.NONE,.NONE}, {.C_RD_PRIMED,.C_OFFSET_BASE_W,.NONE,.NONE}, 0x00006000, 0x0000E003, .F, {rv32_only=true} }, + { .C_FLW, {.FPR_C,.MEM_C_W,.NONE,.NONE}, {.C_RD_PRIMED,.C_OFFSET_BASE_W,.NONE,.NONE}, 0x00006000, 0x0000E003, .F, {rv32_only=true, explicit_count=2} }, // .C_FSW - { .C_FSW, {.FPR_C,.MEM_C_W,.NONE,.NONE}, {.C_RS2_PRIMED,.C_OFFSET_BASE_W,.NONE,.NONE}, 0x0000E000, 0x0000E003, .F, {rv32_only=true} }, + { .C_FSW, {.FPR_C,.MEM_C_W,.NONE,.NONE}, {.C_RS2_PRIMED,.C_OFFSET_BASE_W,.NONE,.NONE}, 0x0000E000, 0x0000E003, .F, {rv32_only=true, explicit_count=2} }, // .C_FLD - { .C_FLD, {.FPR_C,.MEM_C_D,.NONE,.NONE}, {.C_RD_PRIMED,.C_OFFSET_BASE_D,.NONE,.NONE}, 0x00002000, 0x0000E003, .D, {} }, + { .C_FLD, {.FPR_C,.MEM_C_D,.NONE,.NONE}, {.C_RD_PRIMED,.C_OFFSET_BASE_D,.NONE,.NONE}, 0x00002000, 0x0000E003, .D, {explicit_count=2} }, // .C_FSD - { .C_FSD, {.FPR_C,.MEM_C_D,.NONE,.NONE}, {.C_RS2_PRIMED,.C_OFFSET_BASE_D,.NONE,.NONE}, 0x0000A000, 0x0000E003, .D, {} }, + { .C_FSD, {.FPR_C,.MEM_C_D,.NONE,.NONE}, {.C_RS2_PRIMED,.C_OFFSET_BASE_D,.NONE,.NONE}, 0x0000A000, 0x0000E003, .D, {explicit_count=2} }, // .C_ADDI - { .C_ADDI, {.GPR_NONZERO,.IMM_C6S,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_CI_S,.NONE,.NONE}, 0x00000001, 0x0000E003, .C, {} }, + { .C_ADDI, {.GPR_NONZERO,.IMM_C6S,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_CI_S,.NONE,.NONE}, 0x00000001, 0x0000E003, .C, {explicit_count=2} }, // .C_ADDIW - { .C_ADDIW, {.GPR_NONZERO,.IMM_C6S,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_CI_S,.NONE,.NONE}, 0x00002001, 0x0000E003, .C, {rv64_only=true} }, + { .C_ADDIW, {.GPR_NONZERO,.IMM_C6S,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_CI_S,.NONE,.NONE}, 0x00002001, 0x0000E003, .C, {rv64_only=true, explicit_count=2} }, // .C_LI - { .C_LI, {.GPR_NONZERO,.IMM_C6S,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_CI_S,.NONE,.NONE}, 0x00004001, 0x0000E003, .C, {} }, + { .C_LI, {.GPR_NONZERO,.IMM_C6S,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_CI_S,.NONE,.NONE}, 0x00004001, 0x0000E003, .C, {explicit_count=2} }, // .C_LUI - { .C_LUI, {.GPR_NONZERO,.IMM_C18S,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_LUI,.NONE,.NONE}, 0x00006001, 0x0000E003, .C, {} }, + { .C_LUI, {.GPR_NONZERO,.IMM_C18S,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_LUI,.NONE,.NONE}, 0x00006001, 0x0000E003, .C, {explicit_count=2} }, // .C_ADDI16SP - { .C_ADDI16SP, {.GPR_SP,.IMM_C10S,.NONE,.NONE}, {.NONE,.C_IMM_ADDI16SP,.NONE,.NONE}, 0x00006101, 0x0000EF83, .C, {} }, + { .C_ADDI16SP, {.GPR_SP,.IMM_C10S,.NONE,.NONE}, {.NONE,.C_IMM_ADDI16SP,.NONE,.NONE}, 0x00006101, 0x0000EF83, .C, {explicit_count=1, has_implicit=true} }, // .C_SRLI - { .C_SRLI, {.GPR_C,.IMM_C6U,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_IMM_CI_U,.NONE,.NONE}, 0x00008001, 0x0000EC03, .C, {} }, + { .C_SRLI, {.GPR_C,.IMM_C6U,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_IMM_CI_U,.NONE,.NONE}, 0x00008001, 0x0000EC03, .C, {explicit_count=2} }, // .C_SRAI - { .C_SRAI, {.GPR_C,.IMM_C6U,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_IMM_CI_U,.NONE,.NONE}, 0x00008401, 0x0000EC03, .C, {} }, + { .C_SRAI, {.GPR_C,.IMM_C6U,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_IMM_CI_U,.NONE,.NONE}, 0x00008401, 0x0000EC03, .C, {explicit_count=2} }, // .C_ANDI - { .C_ANDI, {.GPR_C,.IMM_C6S,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_IMM_CI_S,.NONE,.NONE}, 0x00008801, 0x0000EC03, .C, {} }, + { .C_ANDI, {.GPR_C,.IMM_C6S,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_IMM_CI_S,.NONE,.NONE}, 0x00008801, 0x0000EC03, .C, {explicit_count=2} }, // .C_SUB - { .C_SUB, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00008C01, 0x0000FC63, .C, {} }, + { .C_SUB, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00008C01, 0x0000FC63, .C, {explicit_count=2} }, // .C_XOR - { .C_XOR, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00008C21, 0x0000FC63, .C, {} }, + { .C_XOR, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00008C21, 0x0000FC63, .C, {explicit_count=2} }, // .C_OR - { .C_OR, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00008C41, 0x0000FC63, .C, {} }, + { .C_OR, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00008C41, 0x0000FC63, .C, {explicit_count=2} }, // .C_AND - { .C_AND, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00008C61, 0x0000FC63, .C, {} }, + { .C_AND, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00008C61, 0x0000FC63, .C, {explicit_count=2} }, // .C_SUBW - { .C_SUBW, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00009C01, 0x0000FC63, .C, {rv64_only=true} }, + { .C_SUBW, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00009C01, 0x0000FC63, .C, {rv64_only=true, explicit_count=2} }, // .C_ADDW - { .C_ADDW, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00009C21, 0x0000FC63, .C, {rv64_only=true} }, + { .C_ADDW, {.GPR_C,.GPR_C,.NONE,.NONE}, {.C_RD_RS1_PRIMED,.C_RS2_PRIMED,.NONE,.NONE}, 0x00009C21, 0x0000FC63, .C, {rv64_only=true, explicit_count=2} }, // .C_J - { .C_J, {.REL12,.NONE,.NONE,.NONE}, {.C_BRANCH12,.NONE,.NONE,.NONE}, 0x0000A001, 0x0000E003, .C, {branch=true} }, + { .C_J, {.REL12,.NONE,.NONE,.NONE}, {.C_BRANCH12,.NONE,.NONE,.NONE}, 0x0000A001, 0x0000E003, .C, {branch=true, explicit_count=1} }, // .C_JAL - { .C_JAL, {.REL12,.NONE,.NONE,.NONE}, {.C_BRANCH12,.NONE,.NONE,.NONE}, 0x00002001, 0x0000E003, .C, {rv32_only=true, branch=true} }, + { .C_JAL, {.REL12,.NONE,.NONE,.NONE}, {.C_BRANCH12,.NONE,.NONE,.NONE}, 0x00002001, 0x0000E003, .C, {rv32_only=true, branch=true, explicit_count=1} }, // .C_BEQZ - { .C_BEQZ, {.GPR_C,.REL9,.NONE,.NONE}, {.C_RS1_PRIMED,.C_BRANCH9,.NONE,.NONE}, 0x0000C001, 0x0000E003, .C, {branch=true} }, + { .C_BEQZ, {.GPR_C,.REL9,.NONE,.NONE}, {.C_RS1_PRIMED,.C_BRANCH9,.NONE,.NONE}, 0x0000C001, 0x0000E003, .C, {branch=true, explicit_count=2} }, // .C_BNEZ - { .C_BNEZ, {.GPR_C,.REL9,.NONE,.NONE}, {.C_RS1_PRIMED,.C_BRANCH9,.NONE,.NONE}, 0x0000E001, 0x0000E003, .C, {branch=true} }, + { .C_BNEZ, {.GPR_C,.REL9,.NONE,.NONE}, {.C_RS1_PRIMED,.C_BRANCH9,.NONE,.NONE}, 0x0000E001, 0x0000E003, .C, {branch=true, explicit_count=2} }, // .C_SLLI - { .C_SLLI, {.GPR_NONZERO,.IMM_C6U,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_CI_U,.NONE,.NONE}, 0x00000002, 0x0000E003, .C, {} }, + { .C_SLLI, {.GPR_NONZERO,.IMM_C6U,.NONE,.NONE}, {.C_RD_RS1,.C_IMM_CI_U,.NONE,.NONE}, 0x00000002, 0x0000E003, .C, {explicit_count=2} }, // .C_LWSP - { .C_LWSP, {.GPR_NONZERO,.MEM_C_SP_W,.NONE,.NONE}, {.C_RD_RS1,.C_SP_OFFSET_W,.NONE,.NONE}, 0x00004002, 0x0000E003, .C, {} }, + { .C_LWSP, {.GPR_NONZERO,.MEM_C_SP_W,.NONE,.NONE}, {.C_RD_RS1,.C_SP_OFFSET_W,.NONE,.NONE}, 0x00004002, 0x0000E003, .C, {explicit_count=2} }, // .C_LDSP - { .C_LDSP, {.GPR_NONZERO,.MEM_C_SP_D,.NONE,.NONE}, {.C_RD_RS1,.C_SP_OFFSET_D,.NONE,.NONE}, 0x00006002, 0x0000E003, .C, {rv64_only=true} }, + { .C_LDSP, {.GPR_NONZERO,.MEM_C_SP_D,.NONE,.NONE}, {.C_RD_RS1,.C_SP_OFFSET_D,.NONE,.NONE}, 0x00006002, 0x0000E003, .C, {rv64_only=true, explicit_count=2} }, // .C_SWSP - { .C_SWSP, {.GPR,.MEM_C_SP_W,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_W,.NONE,.NONE}, 0x0000C002, 0x0000E003, .C, {} }, + { .C_SWSP, {.GPR,.MEM_C_SP_W,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_W,.NONE,.NONE}, 0x0000C002, 0x0000E003, .C, {explicit_count=2} }, // .C_SDSP - { .C_SDSP, {.GPR,.MEM_C_SP_D,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_D,.NONE,.NONE}, 0x0000E002, 0x0000E003, .C, {rv64_only=true} }, + { .C_SDSP, {.GPR,.MEM_C_SP_D,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_D,.NONE,.NONE}, 0x0000E002, 0x0000E003, .C, {rv64_only=true, explicit_count=2} }, // .C_FLDSP - { .C_FLDSP, {.FPR,.MEM_C_SP_D,.NONE,.NONE}, {.C_RD_RS1,.C_SP_OFFSET_D,.NONE,.NONE}, 0x00002002, 0x0000E003, .D, {} }, + { .C_FLDSP, {.FPR,.MEM_C_SP_D,.NONE,.NONE}, {.C_RD_RS1,.C_SP_OFFSET_D,.NONE,.NONE}, 0x00002002, 0x0000E003, .D, {explicit_count=2} }, // .C_FSDSP - { .C_FSDSP, {.FPR,.MEM_C_SP_D,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_D,.NONE,.NONE}, 0x0000A002, 0x0000E003, .D, {} }, + { .C_FSDSP, {.FPR,.MEM_C_SP_D,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_D,.NONE,.NONE}, 0x0000A002, 0x0000E003, .D, {explicit_count=2} }, // .C_JR - { .C_JR, {.GPR_NONZERO,.NONE,.NONE,.NONE}, {.C_RD_RS1,.NONE,.NONE,.NONE}, 0x00008002, 0x0000F07F, .C, {branch=true} }, + { .C_JR, {.GPR_NONZERO,.NONE,.NONE,.NONE}, {.C_RD_RS1,.NONE,.NONE,.NONE}, 0x00008002, 0x0000F07F, .C, {branch=true, explicit_count=1} }, // .C_JALR - { .C_JALR, {.GPR_NONZERO,.NONE,.NONE,.NONE}, {.C_RD_RS1,.NONE,.NONE,.NONE}, 0x00009002, 0x0000F07F, .C, {branch=true} }, + { .C_JALR, {.GPR_NONZERO,.NONE,.NONE,.NONE}, {.C_RD_RS1,.NONE,.NONE,.NONE}, 0x00009002, 0x0000F07F, .C, {branch=true, explicit_count=1} }, // .C_MV - { .C_MV, {.GPR_NONZERO,.GPR_NONZERO,.NONE,.NONE}, {.C_RD_RS1,.C_RS2,.NONE,.NONE}, 0x00008002, 0x0000F003, .C, {} }, + { .C_MV, {.GPR_NONZERO,.GPR_NONZERO,.NONE,.NONE}, {.C_RD_RS1,.C_RS2,.NONE,.NONE}, 0x00008002, 0x0000F003, .C, {explicit_count=2} }, // .C_ADD - { .C_ADD, {.GPR_NONZERO,.GPR_NONZERO,.NONE,.NONE}, {.C_RD_RS1,.C_RS2,.NONE,.NONE}, 0x00009002, 0x0000F003, .C, {} }, + { .C_ADD, {.GPR_NONZERO,.GPR_NONZERO,.NONE,.NONE}, {.C_RD_RS1,.C_RS2,.NONE,.NONE}, 0x00009002, 0x0000F003, .C, {explicit_count=2} }, // .C_FLWSP - { .C_FLWSP, {.FPR,.MEM_C_SP_W,.NONE,.NONE}, {.C_RD_RS1,.C_SP_OFFSET_W,.NONE,.NONE}, 0x00006002, 0x0000E003, .F, {rv32_only=true} }, + { .C_FLWSP, {.FPR,.MEM_C_SP_W,.NONE,.NONE}, {.C_RD_RS1,.C_SP_OFFSET_W,.NONE,.NONE}, 0x00006002, 0x0000E003, .F, {rv32_only=true, explicit_count=2} }, // .C_FSWSP - { .C_FSWSP, {.FPR,.MEM_C_SP_W,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_W,.NONE,.NONE}, 0x0000E002, 0x0000E003, .F, {rv32_only=true} }, + { .C_FSWSP, {.FPR,.MEM_C_SP_W,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_W,.NONE,.NONE}, 0x0000E002, 0x0000E003, .F, {rv32_only=true, explicit_count=2} }, + // .SH1ADD + { .SH1ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002033, 0xFE00707F, .ZBA, {explicit_count=3} }, + // .SH2ADD + { .SH2ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20004033, 0xFE00707F, .ZBA, {explicit_count=3} }, + // .SH3ADD + { .SH3ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20006033, 0xFE00707F, .ZBA, {explicit_count=3} }, + // .ADD_UW + { .ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0800003B, 0xFE00707F, .ZBA, {rv64_only=true, explicit_count=3} }, + // .SH1ADD_UW + { .SH1ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2000203B, 0xFE00707F, .ZBA, {rv64_only=true, explicit_count=3} }, + // .SH2ADD_UW + { .SH2ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2000403B, 0xFE00707F, .ZBA, {rv64_only=true, explicit_count=3} }, + // .SH3ADD_UW + { .SH3ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2000603B, 0xFE00707F, .ZBA, {rv64_only=true, explicit_count=3} }, + // .SLLI_UW + { .SLLI_UW, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x0800101B, 0xFC00707F, .ZBA, {rv64_only=true, explicit_count=3} }, + // .ANDN + { .ANDN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40007033, 0xFE00707F, .ZBB, {explicit_count=3} }, + // .ORN + { .ORN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40006033, 0xFE00707F, .ZBB, {explicit_count=3} }, + // .XNOR + { .XNOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40004033, 0xFE00707F, .ZBB, {explicit_count=3} }, + // .CLZ + { .CLZ, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60001013, 0xFFF0707F, .ZBB, {explicit_count=2} }, + // .CTZ + { .CTZ, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60101013, 0xFFF0707F, .ZBB, {explicit_count=2} }, + // .CPOP + { .CPOP, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60201013, 0xFFF0707F, .ZBB, {explicit_count=2} }, + // .SEXT_B + { .SEXT_B, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60401013, 0xFFF0707F, .ZBB, {explicit_count=2} }, + // .SEXT_H + { .SEXT_H, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60501013, 0xFFF0707F, .ZBB, {explicit_count=2} }, + // .ZEXT_H + { .ZEXT_H, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x08004033, 0xFFF0707F, .ZBB, {rv32_only=true, explicit_count=2} }, + { .ZEXT_H, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x0800403B, 0xFFF0707F, .ZBB, {rv64_only=true, explicit_count=2} }, + // .MIN + { .MIN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A004033, 0xFE00707F, .ZBB, {explicit_count=3} }, + // .MINU + { .MINU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A005033, 0xFE00707F, .ZBB, {explicit_count=3} }, + // .MAX + { .MAX, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A006033, 0xFE00707F, .ZBB, {explicit_count=3} }, + // .MAXU + { .MAXU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A007033, 0xFE00707F, .ZBB, {explicit_count=3} }, + // .ROL + { .ROL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x60001033, 0xFE00707F, .ZBB, {explicit_count=3} }, + // .ROR + { .ROR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x60005033, 0xFE00707F, .ZBB, {explicit_count=3} }, + // .RORI + { .RORI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x60005013, 0xFC00707F, .ZBB, {explicit_count=3} }, + // .ORC_B + { .ORC_B, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x28705013, 0xFFF0707F, .ZBB, {explicit_count=2} }, + // .REV8 + { .REV8, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x69805013, 0xFFF0707F, .ZBB, {rv32_only=true, explicit_count=2} }, + { .REV8, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6B805013, 0xFFF0707F, .ZBB, {rv64_only=true, explicit_count=2} }, + // .CLZW + { .CLZW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6000101B, 0xFFF0707F, .ZBB, {rv64_only=true, explicit_count=2} }, + // .CTZW + { .CTZW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6010101B, 0xFFF0707F, .ZBB, {rv64_only=true, explicit_count=2} }, + // .CPOPW + { .CPOPW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6020101B, 0xFFF0707F, .ZBB, {rv64_only=true, explicit_count=2} }, + // .ROLW + { .ROLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x6000103B, 0xFE00707F, .ZBB, {rv64_only=true, explicit_count=3} }, + // .RORW + { .RORW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x6000503B, 0xFE00707F, .ZBB, {rv64_only=true, explicit_count=3} }, + // .RORIW + { .RORIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x6000501B, 0xFE00707F, .ZBB, {rv64_only=true, explicit_count=3} }, + // .CLMUL + { .CLMUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A001033, 0xFE00707F, .ZBC, {explicit_count=3} }, + // .CLMULH + { .CLMULH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A003033, 0xFE00707F, .ZBC, {explicit_count=3} }, + // .CLMULR + { .CLMULR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A002033, 0xFE00707F, .ZBC, {explicit_count=3} }, + // .BCLR + { .BCLR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x48001033, 0xFE00707F, .ZBS, {explicit_count=3} }, + // .BCLRI + { .BCLRI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x48001013, 0xFC00707F, .ZBS, {explicit_count=3} }, + // .BEXT + { .BEXT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x48005033, 0xFE00707F, .ZBS, {explicit_count=3} }, + // .BEXTI + { .BEXTI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x48005013, 0xFC00707F, .ZBS, {explicit_count=3} }, + // .BINV + { .BINV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x68001033, 0xFE00707F, .ZBS, {explicit_count=3} }, + // .BINVI + { .BINVI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x68001013, 0xFC00707F, .ZBS, {explicit_count=3} }, + // .BSET + { .BSET, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001033, 0xFE00707F, .ZBS, {explicit_count=3} }, + // .BSETI + { .BSETI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x28001013, 0xFC00707F, .ZBS, {explicit_count=3} }, + // .CZERO_EQZ + { .CZERO_EQZ, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0E005033, 0xFE00707F, .ZICOND, {explicit_count=3} }, + // .CZERO_NEZ + { .CZERO_NEZ, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0E007033, 0xFE00707F, .ZICOND, {explicit_count=3} }, + // .FLH + { .FLH, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001007, 0x0000707F, .ZFH, {explicit_count=2} }, + // .FSH + { .FSH, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001027, 0x0000707F, .ZFH, {explicit_count=2} }, + // .FMADD_H + { .FMADD_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x04000043, 0x0600007F, .ZFH, {fp_round=true, explicit_count=4} }, + // .FMSUB_H + { .FMSUB_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x04000047, 0x0600007F, .ZFH, {fp_round=true, explicit_count=4} }, + // .FNMSUB_H + { .FNMSUB_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0400004B, 0x0600007F, .ZFH, {fp_round=true, explicit_count=4} }, + // .FNMADD_H + { .FNMADD_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0400004F, 0x0600007F, .ZFH, {fp_round=true, explicit_count=4} }, + // .FADD_H + { .FADD_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x04000053, 0xFE00007F, .ZFH, {fp_round=true, explicit_count=3} }, + // .FSUB_H + { .FSUB_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0C000053, 0xFE00007F, .ZFH, {fp_round=true, explicit_count=3} }, + // .FMUL_H + { .FMUL_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x14000053, 0xFE00007F, .ZFH, {fp_round=true, explicit_count=3} }, + // .FDIV_H + { .FDIV_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1C000053, 0xFE00007F, .ZFH, {fp_round=true, explicit_count=3} }, + // .FSQRT_H + { .FSQRT_H, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5C000053, 0xFFF0007F, .ZFH, {fp_round=true, explicit_count=2} }, + // .FSGNJ_H + { .FSGNJ_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x24000053, 0xFE00707F, .ZFH, {explicit_count=3} }, + // .FSGNJN_H + { .FSGNJN_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x24001053, 0xFE00707F, .ZFH, {explicit_count=3} }, + // .FSGNJX_H + { .FSGNJX_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x24002053, 0xFE00707F, .ZFH, {explicit_count=3} }, + // .FMIN_H + { .FMIN_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2C000053, 0xFE00707F, .ZFH, {explicit_count=3} }, + // .FMAX_H + { .FMAX_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2C001053, 0xFE00707F, .ZFH, {explicit_count=3} }, + // .FCVT_W_H + { .FCVT_W_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4000053, 0xFFF0007F, .ZFH, {fp_round=true, explicit_count=2} }, + // .FCVT_WU_H + { .FCVT_WU_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4100053, 0xFFF0007F, .ZFH, {fp_round=true, explicit_count=2} }, + // .FCVT_L_H + { .FCVT_L_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4200053, 0xFFF0007F, .ZFH, {rv64_only=true, fp_round=true, explicit_count=2} }, + // .FCVT_LU_H + { .FCVT_LU_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4300053, 0xFFF0007F, .ZFH, {rv64_only=true, fp_round=true, explicit_count=2} }, + // .FCVT_H_W + { .FCVT_H_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4000053, 0xFFF0007F, .ZFH, {fp_round=true, explicit_count=2} }, + // .FCVT_H_WU + { .FCVT_H_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4100053, 0xFFF0007F, .ZFH, {fp_round=true, explicit_count=2} }, + // .FCVT_H_L + { .FCVT_H_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4200053, 0xFFF0007F, .ZFH, {rv64_only=true, fp_round=true, explicit_count=2} }, + // .FCVT_H_LU + { .FCVT_H_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4300053, 0xFFF0007F, .ZFH, {rv64_only=true, fp_round=true, explicit_count=2} }, + // .FCVT_S_H + { .FCVT_S_H, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40200053, 0xFFF0007F, .ZFH, {fp_round=true, explicit_count=2} }, + // .FCVT_H_S + { .FCVT_H_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x44000053, 0xFFF0007F, .ZFH, {fp_round=true, explicit_count=2} }, + // .FCVT_D_H + { .FCVT_D_H, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42200053, 0xFFF0007F, .ZFH, {fp_round=true, explicit_count=2} }, + // .FCVT_H_D + { .FCVT_H_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x44100053, 0xFFF0007F, .ZFH, {fp_round=true, explicit_count=2} }, + // .FMV_X_H + { .FMV_X_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE4000053, 0xFFF0707F, .ZFH, {explicit_count=2} }, + // .FMV_H_X + { .FMV_H_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF4000053, 0xFFF0707F, .ZFH, {explicit_count=2} }, + // .FCLASS_H + { .FCLASS_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE4001053, 0xFFF0707F, .ZFH, {explicit_count=2} }, + // .FEQ_H + { .FEQ_H, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA4002053, 0xFE00707F, .ZFH, {explicit_count=3} }, + // .FLT_H + { .FLT_H, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA4001053, 0xFE00707F, .ZFH, {explicit_count=3} }, + // .FLE_H + { .FLE_H, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA4000053, 0xFE00707F, .ZFH, {explicit_count=3} }, + // .MRET + { .MRET, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x30200073, 0xFFFFFFFF, .PRIV, {branch=true} }, + // .SRET + { .SRET, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x10200073, 0xFFFFFFFF, .PRIV, {branch=true} }, + // .WFI + { .WFI, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x10500073, 0xFFFFFFFF, .PRIV, {} }, + // .SFENCE_VMA + { .SFENCE_VMA, {.GPR,.GPR,.NONE,.NONE}, {.RS1,.RS2,.NONE,.NONE}, 0x12000073, 0xFE007FFF, .PRIV, {explicit_count=2} }, } @(rodata) -CLOBBER_FORMS := [198]lib.Clobber{ +CLOBBER_FORMS := [283]lib.Clobber{ // .LUI {written={0}}, // .AUIPC @@ -805,6 +973,174 @@ CLOBBER_FORMS := [198]lib.Clobber{ {written={0}, implicit_rd={.SP}, reads_mem=true}, // .C_FSWSP {read={0}, implicit_rd={.SP}, writes_mem=true}, + // .SH1ADD + {written={0}, read={1, 2}}, + // .SH2ADD + {written={0}, read={1, 2}}, + // .SH3ADD + {written={0}, read={1, 2}}, + // .ADD_UW + {written={0}, read={1, 2}}, + // .SH1ADD_UW + {written={0}, read={1, 2}}, + // .SH2ADD_UW + {written={0}, read={1, 2}}, + // .SH3ADD_UW + {written={0}, read={1, 2}}, + // .SLLI_UW + {written={0}, read={1}}, + // .ANDN + {written={0}, read={1, 2}}, + // .ORN + {written={0}, read={1, 2}}, + // .XNOR + {written={0}, read={1, 2}}, + // .CLZ + {written={0}, read={1}}, + // .CTZ + {written={0}, read={1}}, + // .CPOP + {written={0}, read={1}}, + // .SEXT_B + {written={0}, read={1}}, + // .SEXT_H + {written={0}, read={1}}, + // .ZEXT_H + {written={0}, read={1}}, + {written={0}, read={1}}, + // .MIN + {written={0}, read={1, 2}}, + // .MINU + {written={0}, read={1, 2}}, + // .MAX + {written={0}, read={1, 2}}, + // .MAXU + {written={0}, read={1, 2}}, + // .ROL + {written={0}, read={1, 2}}, + // .ROR + {written={0}, read={1, 2}}, + // .RORI + {written={0}, read={1}}, + // .ORC_B + {written={0}, read={1}}, + // .REV8 + {written={0}, read={1}}, + {written={0}, read={1}}, + // .CLZW + {written={0}, read={1}}, + // .CTZW + {written={0}, read={1}}, + // .CPOPW + {written={0}, read={1}}, + // .ROLW + {written={0}, read={1, 2}}, + // .RORW + {written={0}, read={1, 2}}, + // .RORIW + {written={0}, read={1}}, + // .CLMUL + {written={0}, read={1, 2}}, + // .CLMULH + {written={0}, read={1, 2}}, + // .CLMULR + {written={0}, read={1, 2}}, + // .BCLR + {written={0}, read={1, 2}}, + // .BCLRI + {written={0}, read={1}}, + // .BEXT + {written={0}, read={1, 2}}, + // .BEXTI + {written={0}, read={1}}, + // .BINV + {written={0}, read={1, 2}}, + // .BINVI + {written={0}, read={1}}, + // .BSET + {written={0}, read={1, 2}}, + // .BSETI + {written={0}, read={1}}, + // .CZERO_EQZ + {written={0}, read={1, 2}}, + // .CZERO_NEZ + {written={0}, read={1, 2}}, + // .FLH + {written={0}, read={1}, reads_mem=true}, + // .FSH + {read={0, 1}, writes_mem=true}, + // .FMADD_H + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FMSUB_H + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FNMSUB_H + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FNMADD_H + {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FADD_H + {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FSUB_H + {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FMUL_H + {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FDIV_H + {written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true}, + // .FSQRT_H + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FSGNJ_H + {written={0}, read={1, 2}}, + // .FSGNJN_H + {written={0}, read={1, 2}}, + // .FSGNJX_H + {written={0}, read={1, 2}}, + // .FMIN_H + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FMAX_H + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FCVT_W_H + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_WU_H + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_L_H + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_LU_H + {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}, + // .FCVT_H_W + {written={0}, read={1}, fflags_wr={.OF, .NX}, reads_frm=true}, + // .FCVT_H_WU + {written={0}, read={1}, fflags_wr={.OF, .NX}, reads_frm=true}, + // .FCVT_H_L + {written={0}, read={1}, fflags_wr={.OF, .NX}, reads_frm=true}, + // .FCVT_H_LU + {written={0}, read={1}, fflags_wr={.OF, .NX}, reads_frm=true}, + // .FCVT_S_H + {written={0}, read={1}, fflags_wr={.NV}, reads_frm=true}, + // .FCVT_H_S + {written={0}, read={1}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FCVT_D_H + {written={0}, read={1}, fflags_wr={.NV}, reads_frm=true}, + // .FCVT_H_D + {written={0}, read={1}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}, + // .FMV_X_H + {written={0}, read={1}}, + // .FMV_H_X + {written={0}, read={1}}, + // .FCLASS_H + {written={0}, read={1}}, + // .FEQ_H + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FLT_H + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .FLE_H + {written={0}, read={1, 2}, fflags_wr={.NV}}, + // .MRET + {side_effects={.CONTROL}}, + // .SRET + {side_effects={.CONTROL}}, + // .WFI + {}, + // .SFENCE_VMA + {read={0, 1}, side_effects={.FENCE}}, } @(rodata) @@ -1008,4 +1344,87 @@ ENCODE_RUNS := [lib.Mnemonic]lib.Encode_Run{ .C_ADD = { 195, 1}, .C_FLWSP = { 196, 1}, .C_FSWSP = { 197, 1}, + .SH1ADD = { 198, 1}, + .SH2ADD = { 199, 1}, + .SH3ADD = { 200, 1}, + .ADD_UW = { 201, 1}, + .SH1ADD_UW = { 202, 1}, + .SH2ADD_UW = { 203, 1}, + .SH3ADD_UW = { 204, 1}, + .SLLI_UW = { 205, 1}, + .ANDN = { 206, 1}, + .ORN = { 207, 1}, + .XNOR = { 208, 1}, + .CLZ = { 209, 1}, + .CTZ = { 210, 1}, + .CPOP = { 211, 1}, + .SEXT_B = { 212, 1}, + .SEXT_H = { 213, 1}, + .ZEXT_H = { 214, 2}, + .MIN = { 216, 1}, + .MINU = { 217, 1}, + .MAX = { 218, 1}, + .MAXU = { 219, 1}, + .ROL = { 220, 1}, + .ROR = { 221, 1}, + .RORI = { 222, 1}, + .ORC_B = { 223, 1}, + .REV8 = { 224, 2}, + .CLZW = { 226, 1}, + .CTZW = { 227, 1}, + .CPOPW = { 228, 1}, + .ROLW = { 229, 1}, + .RORW = { 230, 1}, + .RORIW = { 231, 1}, + .CLMUL = { 232, 1}, + .CLMULH = { 233, 1}, + .CLMULR = { 234, 1}, + .BCLR = { 235, 1}, + .BCLRI = { 236, 1}, + .BEXT = { 237, 1}, + .BEXTI = { 238, 1}, + .BINV = { 239, 1}, + .BINVI = { 240, 1}, + .BSET = { 241, 1}, + .BSETI = { 242, 1}, + .CZERO_EQZ = { 243, 1}, + .CZERO_NEZ = { 244, 1}, + .FLH = { 245, 1}, + .FSH = { 246, 1}, + .FMADD_H = { 247, 1}, + .FMSUB_H = { 248, 1}, + .FNMSUB_H = { 249, 1}, + .FNMADD_H = { 250, 1}, + .FADD_H = { 251, 1}, + .FSUB_H = { 252, 1}, + .FMUL_H = { 253, 1}, + .FDIV_H = { 254, 1}, + .FSQRT_H = { 255, 1}, + .FSGNJ_H = { 256, 1}, + .FSGNJN_H = { 257, 1}, + .FSGNJX_H = { 258, 1}, + .FMIN_H = { 259, 1}, + .FMAX_H = { 260, 1}, + .FCVT_W_H = { 261, 1}, + .FCVT_WU_H = { 262, 1}, + .FCVT_L_H = { 263, 1}, + .FCVT_LU_H = { 264, 1}, + .FCVT_H_W = { 265, 1}, + .FCVT_H_WU = { 266, 1}, + .FCVT_H_L = { 267, 1}, + .FCVT_H_LU = { 268, 1}, + .FCVT_S_H = { 269, 1}, + .FCVT_H_S = { 270, 1}, + .FCVT_D_H = { 271, 1}, + .FCVT_H_D = { 272, 1}, + .FMV_X_H = { 273, 1}, + .FMV_H_X = { 274, 1}, + .FCLASS_H = { 275, 1}, + .FEQ_H = { 276, 1}, + .FLT_H = { 277, 1}, + .FLE_H = { 278, 1}, + .MRET = { 279, 1}, + .SRET = { 280, 1}, + .WFI = { 281, 1}, + .SFENCE_VMA = { 282, 1}, } diff --git a/core/rexcode/isa/riscv/tablegen/instruction_table.odin b/core/rexcode/isa/riscv/tablegen/instruction_table.odin index ca076d516..2bfc7bb02 100644 --- a/core/rexcode/isa/riscv/tablegen/instruction_table.odin +++ b/core/rexcode/isa/riscv/tablegen/instruction_table.odin @@ -687,4 +687,326 @@ INSTRUCTION_TABLE := [Mnemonic][]Form{ .C_FSWSP = { {{.C_FSWSP, {.FPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_W, .NONE, .NONE}, 0xE002, 0xE003, .F, {rv32_only=true}}, {read={0}, implicit_rd={.SP}, writes_mem=true}}, }, + + // ========================================================================= + // §7 Zba — address generation. Pure dataflow, no flags, no traps. + // ========================================================================= + .SH1ADD = { + {{.SH1ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002033, MASK_R, .ZBA, {}}, {written={0}, read={1, 2}}}, + }, + .SH2ADD = { + {{.SH2ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20004033, MASK_R, .ZBA, {}}, {written={0}, read={1, 2}}}, + }, + .SH3ADD = { + {{.SH3ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20006033, MASK_R, .ZBA, {}}, {written={0}, read={1, 2}}}, + }, + + // *.UW forms zero-extend rs1's low word; RV64-only by construction. + .ADD_UW = { + {{.ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0800003B, MASK_R, .ZBA, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .SH1ADD_UW = { + {{.SH1ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2000203B, MASK_R, .ZBA, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .SH2ADD_UW = { + {{.SH2ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2000403B, MASK_R, .ZBA, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .SH3ADD_UW = { + {{.SH3ADD_UW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2000603B, MASK_R, .ZBA, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + + // SLLI.UW: OP-IMM-32 opcode but a 6-bit shamt (funct6 @31-26 = 000010). + .SLLI_UW = { + {{.SLLI_UW, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x0800101B, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .ZBA, {rv64_only=true}}, {written={0}, read={1}}}, + }, + + // ========================================================================= + // §8 Zbb — basic bit-manipulation. All pure dataflow, no flags, no traps. + // ========================================================================= + + // Logic with negated operand (R-type) + .ANDN = { + {{.ANDN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40007033, MASK_R, .ZBB, {}}, {written={0}, read={1, 2}}}, + }, + .ORN = { + {{.ORN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40006033, MASK_R, .ZBB, {}}, {written={0}, read={1, 2}}}, + }, + .XNOR = { + {{.XNOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40004033, MASK_R, .ZBB, {}}, {written={0}, read={1, 2}}}, + }, + + // Count leading/trailing zeros, popcount (unary; rs2 is a selector) + .CLZ = { + {{.CLZ, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60001013, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {}}, {written={0}, read={1}}}, + }, + .CTZ = { + {{.CTZ, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60101013, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {}}, {written={0}, read={1}}}, + }, + .CPOP = { + {{.CPOP, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60201013, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {}}, {written={0}, read={1}}}, + }, + + // Sign/zero extend (unary) + .SEXT_B = { + {{.SEXT_B, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60401013, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {}}, {written={0}, read={1}}}, + }, + .SEXT_H = { + {{.SEXT_H, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x60501013, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {}}, {written={0}, read={1}}}, + }, + // ZEXT.H differs by base: OP (0x33) on RV32, OP-32 (0x3B) on RV64. + // Two forms in one slice keeps the same mnemonic valid on both. + .ZEXT_H = { + {{.ZEXT_H, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x08004033, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {rv32_only=true}}, {written={0}, read={1}}}, + {{.ZEXT_H, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x0800403B, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {rv64_only=true}}, {written={0}, read={1}}}, + }, + + // Min / max (R-type) + .MIN = { + {{.MIN, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A004033, MASK_R, .ZBB, {}}, {written={0}, read={1, 2}}}, + }, + .MINU = { + {{.MINU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A005033, MASK_R, .ZBB, {}}, {written={0}, read={1, 2}}}, + }, + .MAX = { + {{.MAX, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A006033, MASK_R, .ZBB, {}}, {written={0}, read={1, 2}}}, + }, + .MAXU = { + {{.MAXU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A007033, MASK_R, .ZBB, {}}, {written={0}, read={1, 2}}}, + }, + + // Rotate (R-type) + rotate-immediate (6-bit funct6 shift-imm) + .ROL = { + {{.ROL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x60001033, MASK_R, .ZBB, {}}, {written={0}, read={1, 2}}}, + }, + .ROR = { + {{.ROR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x60005033, MASK_R, .ZBB, {}}, {written={0}, read={1, 2}}}, + }, + .RORI = { + {{.RORI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x60005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .ZBB, {}}, {written={0}, read={1}}}, + }, + + // Byte-granule ops (unary) + .ORC_B = { + {{.ORC_B, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x28705013, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {}}, {written={0}, read={1}}}, + }, + // REV8 byte-reverse: RV32 uses funct7=0110100, RV64 uses 0110101 (imm[11:0] + // widens with XLEN). Two forms cover both bases. + .REV8 = { + {{.REV8, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x69805013, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {rv32_only=true}}, {written={0}, read={1}}}, + {{.REV8, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6B805013, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {rv64_only=true}}, {written={0}, read={1}}}, + }, + + // Word variants — RV64 only + .CLZW = { + {{.CLZW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6000101B, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {rv64_only=true}}, {written={0}, read={1}}}, + }, + .CTZW = { + {{.CTZW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6010101B, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {rv64_only=true}}, {written={0}, read={1}}}, + }, + .CPOPW = { + {{.CPOPW, {.GPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x6020101B, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RS2, .ZBB, {rv64_only=true}}, {written={0}, read={1}}}, + }, + .ROLW = { + {{.ROLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x6000103B, MASK_R, .ZBB, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + .RORW = { + {{.RORW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x6000503B, MASK_R, .ZBB, {rv64_only=true}}, {written={0}, read={1, 2}}}, + }, + // RORIW: OP-IMM-32 with a 5-bit shamt, so funct7 is fully fixed (MASK_R). + .RORIW = { + {{.RORIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x6000501B, MASK_R, .ZBB, {rv64_only=true}}, {written={0}, read={1}}}, + }, + + // ========================================================================= + // §9 Zbc — carry-less multiply. Pure dataflow. + // ========================================================================= + .CLMUL = { + {{.CLMUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A001033, MASK_R, .ZBC, {}}, {written={0}, read={1, 2}}}, + }, + .CLMULH = { + {{.CLMULH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A003033, MASK_R, .ZBC, {}}, {written={0}, read={1, 2}}}, + }, + .CLMULR = { + {{.CLMULR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A002033, MASK_R, .ZBC, {}}, {written={0}, read={1, 2}}}, + }, + + // ========================================================================= + // §10 Zbs — single-bit ops. Register and 6-bit-immediate forms. + // ========================================================================= + .BCLR = { + {{.BCLR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x48001033, MASK_R, .ZBS, {}}, {written={0}, read={1, 2}}}, + }, + .BCLRI = { + {{.BCLRI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x48001013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .ZBS, {}}, {written={0}, read={1}}}, + }, + .BEXT = { + {{.BEXT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x48005033, MASK_R, .ZBS, {}}, {written={0}, read={1, 2}}}, + }, + .BEXTI = { + {{.BEXTI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x48005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .ZBS, {}}, {written={0}, read={1}}}, + }, + .BINV = { + {{.BINV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x68001033, MASK_R, .ZBS, {}}, {written={0}, read={1, 2}}}, + }, + .BINVI = { + {{.BINVI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x68001013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .ZBS, {}}, {written={0}, read={1}}}, + }, + .BSET = { + {{.BSET, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001033, MASK_R, .ZBS, {}}, {written={0}, read={1, 2}}}, + }, + .BSETI = { + {{.BSETI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x28001013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .ZBS, {}}, {written={0}, read={1}}}, + }, + + // ========================================================================= + // §11 Zicond — conditional zero. rd = (cond on rs2) ? 0 : rs1. + // ========================================================================= + .CZERO_EQZ = { + {{.CZERO_EQZ, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0E005033, MASK_R, .ZICOND, {}}, {written={0}, read={1, 2}}}, + }, + .CZERO_NEZ = { + {{.CZERO_NEZ, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0E007033, MASK_R, .ZICOND, {}}, {written={0}, read={1, 2}}}, + }, + + // ========================================================================= + // §12 Zfh (half-precision, binary16) — mirrors §5 with fmt=10 (bits 26-25). + // reads_frm == encoding fp_round, exactly as in the F/D sections. + // ========================================================================= + .FLH = { + {{.FLH, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001007, MASK_I, .ZFH, {}}, {written={0}, read={1}, reads_mem=true}}, + }, + .FSH = { + {{.FSH, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001027, MASK_S, .ZFH, {}}, {read={0, 1}, writes_mem=true}}, + }, + + .FMADD_H = { + {{.FMADD_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x04000043, 0x0600007F, .ZFH, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FMSUB_H = { + {{.FMSUB_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x04000047, 0x0600007F, .ZFH, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FNMSUB_H = { + {{.FNMSUB_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0400004B, 0x0600007F, .ZFH, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FNMADD_H = { + {{.FNMADD_H, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0400004F, 0x0600007F, .ZFH, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + + .FADD_H = { + {{.FADD_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x04000053, MASK_OPCODE | MASK_FUNCT7, .ZFH, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FSUB_H = { + {{.FSUB_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0C000053, MASK_OPCODE | MASK_FUNCT7, .ZFH, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FMUL_H = { + {{.FMUL_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x14000053, MASK_OPCODE | MASK_FUNCT7, .ZFH, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FDIV_H = { + {{.FDIV_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1C000053, MASK_OPCODE | MASK_FUNCT7, .ZFH, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FSQRT_H = { + {{.FSQRT_H, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5C000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + + .FSGNJ_H = { + {{.FSGNJ_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x24000053, MASK_R, .ZFH, {}}, {written={0}, read={1, 2}}}, + }, + .FSGNJN_H = { + {{.FSGNJN_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x24001053, MASK_R, .ZFH, {}}, {written={0}, read={1, 2}}}, + }, + .FSGNJX_H = { + {{.FSGNJX_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x24002053, MASK_R, .ZFH, {}}, {written={0}, read={1, 2}}}, + }, + + .FMIN_H = { + {{.FMIN_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2C000053, MASK_R, .ZFH, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + .FMAX_H = { + {{.FMAX_H, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2C001053, MASK_R, .ZFH, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + + // Half <-> integer conversions. Int->half can overflow the narrow range, + // so those carry OF alongside NX. + .FCVT_W_H = { + {{.FCVT_W_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_WU_H = { + {{.FCVT_WU_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_L_H = { + {{.FCVT_L_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_LU_H = { + {{.FCVT_LU_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC4300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}}, + }, + .FCVT_H_W = { + {{.FCVT_H_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.OF, .NX}, reads_frm=true}}, + }, + .FCVT_H_WU = { + {{.FCVT_H_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.OF, .NX}, reads_frm=true}}, + }, + .FCVT_H_L = { + {{.FCVT_H_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.OF, .NX}, reads_frm=true}}, + }, + .FCVT_H_LU = { + {{.FCVT_H_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD4300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.OF, .NX}, reads_frm=true}}, + }, + + // Half <-> single/double. Widening (H->S, H->D) is value-exact -> {.NV} + // only; narrowing (S->H, D->H) can round -> full flag set. Requires F/D. + .FCVT_S_H = { + {{.FCVT_S_H, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV}, reads_frm=true}}, + }, + .FCVT_H_S = { + {{.FCVT_H_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x44000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + .FCVT_D_H = { + {{.FCVT_D_H, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV}, reads_frm=true}}, + }, + .FCVT_H_D = { + {{.FCVT_H_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x44100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .ZFH, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}}, + }, + + // Bit-pattern move / classify (no rounding, no flags) + .FMV_X_H = { + {{.FMV_X_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE4000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .ZFH, {}}, {written={0}, read={1}}}, + }, + .FMV_H_X = { + {{.FMV_H_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF4000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .ZFH, {}}, {written={0}, read={1}}}, + }, + .FCLASS_H = { + {{.FCLASS_H, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE4001053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .ZFH, {}}, {written={0}, read={1}}}, + }, + + // Comparisons -> GPR result; only NV possible. + .FEQ_H = { + {{.FEQ_H, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA4002053, MASK_R, .ZFH, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + .FLT_H = { + {{.FLT_H, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA4001053, MASK_R, .ZFH, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + .FLE_H = { + {{.FLE_H, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA4000053, MASK_R, .ZFH, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}}, + }, + + // ========================================================================= + // §13 Privileged — trap-return + TLB maintenance (SYSTEM opcode, 0x73). + // MRET/SRET/WFI are fully fixed 32-bit words (mask 0xFFFFFFFF, no operands). + // ========================================================================= + .MRET = { + {{.MRET, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x30200073, 0xFFFFFFFF, .PRIV, {branch=true}}, {side_effects={.CONTROL}}}, + }, + .SRET = { + {{.SRET, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x10200073, 0xFFFFFFFF, .PRIV, {branch=true}}, {side_effects={.CONTROL}}}, + }, + // WFI: wait-for-interrupt hint. No PC redirect and no register effects in the + // architectural sense; execution resumes after the wakeup event. + .WFI = { + {{.WFI, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x10500073, 0xFFFFFFFF, .PRIV, {}}, {}}, + }, + // SFENCE.VMA rs1(vaddr), rs2(asid): both operands optional (x0 = "all"). + // Reads rs1/rs2; acts as an address-translation ordering fence. + .SFENCE_VMA = { + {{.SFENCE_VMA, {.GPR,.GPR,.NONE,.NONE}, {.RS1,.RS2,.NONE,.NONE}, 0x12000073, MASK_OPCODE | MASK_FUNCT3 | MASK_FUNCT7 | MASK_RD, .PRIV, {}}, {read={0, 1}, side_effects={.FENCE}}}, + }, } diff --git a/core/rexcode/isa/riscv/tables.odin b/core/rexcode/isa/riscv/tables.odin index 4d708c3d3..627f0a2ab 100644 --- a/core/rexcode/isa/riscv/tables.odin +++ b/core/rexcode/isa/riscv/tables.odin @@ -30,9 +30,9 @@ Decode_Entry :: struct #packed { bits: u32, // 4 mask: u32, // 4 feature: Feature, // 1 - flags: Encoding_Flags, // 1 + flags: Encoding_Flags, // 2 } -#assert(size_of(Decode_Entry) == 20) +#assert(size_of(Decode_Entry) == 21) Decode_Index :: struct #packed { start: u16, diff --git a/core/rexcode/isa/riscv/tables/riscv.clobber_forms.bin b/core/rexcode/isa/riscv/tables/riscv.clobber_forms.bin index 047a2b041c0c42c712945ad31938704bf71dd435..7da4138f7dba2eb403d6d554871255730030a2f6 100644 GIT binary patch delta 197 zcmeyy`&oFyH@3;bOb(1plM@-0C*HK5oXKbgp@hIMhLPY1O*rv>LDuG5rPhIK@Nmq09=q0A(#Lcg4wJ4rzREXd5uz@UtS5QIC)$Pif&rrn5vhlhbdP>6wnA7T*$1A_u6 z6hYaUfq`Fuf#LuE|Nq$-7)&4{3=9m#3=lyE1{PB!K>@Hz1_l;021ag121b4+hGK}5 z7+4t$%n^c+Kn4j~AOsYgajQ(&>A5K2|AFV4cwc? z3=B;51q}Zf84PR@f&y?sJA|MDT+kjNXaE;10E02g$D z3tGe7Y2=C!gj;0fh7g2XWaN$zgj;0ffe?gSWaJ4hLm2rO81xkw1nLVu{A6NK@M2(O zg93qF7fh9JCY0Q06&C_<$H1Js*FVaS3|ZyJRo3qrkV6oD)V z^`=oIvLMu(Mp4LuP;VMVBMU;kX%vGj2=%5>EV3Zfn?`ZSf>3W7#WOH*F))DY4t8ih zVrEcC01JYu33Y^EA_Ef>6B8p7GmA4QYcnvgF*A51!3EtBg2`|}Z-ih9T+kmOm?^>2C|?8R4|i)iHU)Mk%@sJn1Lapp5eoPW(JKc zWR;+h|HsT=kc|)&V1NncAOscQg1HDm1_ljKA;8RFkcSWyfD7h>ZHC%@0BU;ylAr)g zunjYfgkUpB5E94`!GA0a z7A?qvT%feX!eG&gEGPsOY(o~5f(o`Hr@AOmAhR%NbRer#0wo(327^w7pa26*unQrm z02k~=2r@8eLACcF1O?!Ny-2nTI6!UhLlR_gf(rH{l8pkxBB+@Y5P|}5!HEb#2DsoP zM7#?yJOZT<76ygM2tfvhLr{yRAPEY<1g9b;28K&emD7*}1z>{Hk+ds7wQJ2l5;TAb z&P39#0M)KF3rWxbCO8{OJIwJ)bC6Ure1iB$X)e4S!U%4hFfgz)FwBDsGED%rSipkw z8TbW68N?Z6!II1mK!OVvFz`z;Fo>%$FfceUFhB$q7BcWlGcbs&GcYhDzyy^RfmKR^ zR33l{Dl7)8lmw}K025SN!XN}Q6RMq=L2)Tq5Ud@ll9@qq8G{haA_a(c76ygoU_r2% z3*dq)7zBkG7(}HR7(m{Hx^pE$5UQP>L1`625aFZM41(ee45D%j42)1Gu`?*FVGs~w zU|^7EU|>vSU}%013XlnF8TdsQ7^Gwv7#JHE7?|IH1QpgH1Y6*O>lyfk85pEMPU?UQ zZeZZ&XJC+$WME+IVPHu91J=F~E~tnQ+yobNLgbU@$t35QLj)bOs>^H`C}W zLJ)4I(K&d3Q(6FQ<{u6Qqw{c;#sv(ZhS@((27?O-!34PAMTDROT<{VDBO|0P78YPg z0F^eJ3<{T#1O;G%SC9l1V1ieX1RY?4*N_AQV1n1-g2oOY$A9?G$)Jc3w1x{R-9UCH z7pO+yWH7ji5DZ{|3En~oCcp)6BLoZJf_D&tU~e*jLg_9-FaYFtu;4v-APYkT|8O!G z+=n|}IG{iS8cGk41RF9Tf{G}D*$_dchj5kBVB0}{S9*jb2n%GT$4G*(KvsGJcc(R2 zJII|zPZ5F;cmCsKFnWeOdH`y=g9M+$RT>LG0)&gf-~~d^0513vA*cWse1#AcVDJD% z2RDPkYeXnP1pja|7`#EK41lYAi%1gU(7P$|HW0X6eILM22Hr1Ar@N^nD$o5A2C zvPzI3NaZJl$^ZsFkeNIT2A>gv1#rPH;C3Cju?OwH^D-!W1q*^3dkDdAptcRHvBy%+ zz`(}K;PD+U=+3|Z6Z`=e^hOB&gbVs31b=}9VU0bI_J6z#7Qc}Nc|c7#UIvRl$buqJ z!N16YGEl*P$StcFP&0;?LE}HNN)=Fm@G=;H+ECE;yZ{4CkdcuI(a47hG9d&R7<8c8 znGu2la6uMEQ1=3agBci(Ky7D55)^<5vLOj7Kn1nfkpvB3f*g!UeS|AeGdYn21z>_) zNP-GbK`m}1K?9f|52z~xZgK@PD1aNKybKz=NP-M5P>cAG1Qoz7RbB=Sek4Hwm`VX8 z$1^+u<#%2N1wka+8NNUTg%BzQ;3|bdK@Uj`3Jgo2fh>X$6o3ngA_N)Wf?}X%61bsP s%%ETZ8pz^fU=c?a6o3j!APELQ1sNnk!-@<{%-|s}q5t&^|M(ab0P3o3-v9sr literal 3960 zcmZQ%U}R@tVB}(8FlS(3sAm8HCb*b5T#T84k&}Uek(+@bA121a!obML%)rRR&X5ig zD_~$?U}0roWaMCAV&-H>hKsQw!~_@^>cQ&R5n>K7F%E=S08ES%A(j9W<3flPz{I%0 zeqiKbU|@#X%fN#WgW1c#ix5+Q>Sf?Vh{4>#z>g4vxrIRhEXK^sz@QAbLl7Ybw?haa z2Dd{PECzNT%pXi52r&bwTbM+_VqiPqVq)-c7KYm^ju3;}A%PHs>1B{ah{63Pg%E?e zg+Ur21`AUL83sm1HU>r}HU?pc-~KQ#$Rflb;qr%pK@M5Wp}v6O4+Dcd+&pQRo0$|C z7#Ud^7@1fZq#@@0V_;H5h(XNz$H1h7ECw>~9|Myz10y3N10xeNgE7Rse+&#N$YKz6 z45|n*m>mpi2r)=l{bOKIM~Fef>K_Ax20{!HR{t0nG!bGj_c3T8i$U$xMu6!TiBwfDnVZg~BryT7ItCUq21ag121b4+hGK|Y z7+4w15n_-qWng8nK!`!Yl!2AOl7W$%kAab2fT0-TW(HOUD})#%tQc4stPx_6uwr0k zuz~x{n1O+*zJTE$BZDnMOaLZkhY(YMiP3}9jo2r&nkm?J_g04C;y5KDlGIU~dh zU}7$CF>9Fnm|PKJFguvs5MnSpnA{O!Fgut$5MnSpm^{Jd0V5v+gT4ZTKz+f7pG*v1 z42+Ci42;ZtATf#h0)`(<4Bp6M91t-dWHC^=`-6$W7gCzNSq$PgrYK}Fh~Jo^k;Nc>V~Rl*gZPap7Fi79H>NmbF^J!o;u)B@7#Kk1 zJv%giFf$~8#Xx1dI$SJ~fr*KUiIIt!#Tk@W85r1@Ig;RF?r^bWxR^IwECnv+4;M=X ziGj<>V2Id1W{xyuF^+l$hJVZ)>BwRN5U~toF$suRCIb@_0|O%y14A$aLqt8phyTnR zS;*=@;rx%8AsZnkzyKA?L5L~9#Bvd03=A5eJk89IhY%BhiRFXsgxY%mVs8PGm;h9) z5J`;TL4Co8|I7?U42(=nkT6hS0L9xsW`<&fm;g+y1R=%%6DviSCjc|AjDd*}9tIa6 zZYf6+6M%|UAc--2fVia+VIG45#LZk)NMZ(1v1%l}3J~+SYLLVXpklS)Gz3mp&@z^V zp$;qtPFHZTdQh0c(iKxZ0|OfiM+02U9aLU{#Twya-f*!dxR^g&tQjN*2~&vJKNgM_ zWHByKdST&cMHUl+h_xY$NkPQgk<(QaC`?&6I*`>Vfzk#GLnlH^fB`Djg%DGKiFG5y z7#Or5dV3IJ0x+>&BzpxMAolhli7_}q#QG6wLxEut#JmXzF#(v^M1&XvOl%S&egzmF zfzkmB!(@aQ1H&PR9aE6R1fXJ5k>Z@;5=7lJBryS~*mNYl3J|?qGmyj#pkgzT^eRB~ za?L^#Gk}WCM$!v)Gt(R-bqt@t{$QF5Zyzv%+YAg0>_pL;TLG`jTtwM;w{jr)sP@I85RE~jx5$YCphBXWVVho_BFau*E14HwBP#COb z;1^+Fkdk3wU~FJuV15G|ziUVPFuIVPIflfP_6e!)^va83qPX4F(1# zc$n^C5R_$L5Y=R0V1k7y(_RKf83qP11qKEtm>mrJ7#L+47{nAA7?@yoFzshxg6W02 zkA>j?SPZNV>JJu%gA9TU3=EAhfF@w}G g96^XpU|@iV9c5sG`2*@^X2xS+F|eDV?qg;I0EizFKL7v# diff --git a/core/rexcode/isa/riscv/tables/riscv.encode_runs.bin b/core/rexcode/isa/riscv/tables/riscv.encode_runs.bin index 48103309bd3a581f7dc1adb43958e67c7d22d588..ade3757644fc689db418a64777ed02d5a44c9326 100644 GIT binary patch delta 677 zcmdnNb3t%}1zY_w1_lO31_p-XQ2GRvJ_)5yLFv;_`V5pl3#HFN>GM$f0+hZ8r7uD0 z%TW3Xl)eg~>lv;wFfcGNFfiPJ2r%4)(zl@WZ76*QO5cUj_n`EBDE$Cx&Lb%QF_eA+ zrJq9SXHfb%n677FcmZZGFua7)ub}j6DE$UXzlGB8p!9nv{Q*jUgwmg&^k*pj1xkN~ z(%+!;cMx6Az`*bW#9&}x_z9(dLFwO6`VW-;3#I=->Hkm~6n~&7WMqUyB@>iphSDrh zniWd3L1}hI28Mc&Mh>U|CzR%b(%ev*2TJooX+9{;52Xd5v>=ogg3`iJS_DdqLTNE5 UEzZaw3vxVz1XMs0N=rd$0F{I|lmGw# delta 7 Ocmca0xPxbd1sebiYXX!2 diff --git a/core/rexcode/isa/riscv/tables/riscv.entries.bin b/core/rexcode/isa/riscv/tables/riscv.entries.bin index 5e57948aa9d0081a4f9299335f6556db1b4d4836..744f4e7d8dc3123ac2f334b145ced49ad0386cc6 100644 GIT binary patch literal 5943 zcmd;PVB}(8VB}$7U}j)os4rju0Um^)09=q4A*cWsjAvkiI*A=>5iFfy_-Ffy?+NJA3XKL!RSMT8(E)DN$d*@Pmng!5di+5nW33VD!V0J2~MRC^$@-~y;%5VGI_s9-R%-~*^&C_>PH0qP^B zFl0ffkC?)d1))A-ia-{G`iLnKSrF&Y6f(k%JWd=q@Mg~SEW^hSbU%>E>fq_81sv`s;2@E8tfe?h`caWeaLJ*$07_^WDVYX`{1R*5@NV^U~5K=OL1Z@z43=B*l zA2Bj8*dhc4;DUAtK?S&=Jwng`F6e*|bbt#wA_N2Af=&p*1h}9xLa+cXcpM?9zyL}i z|2P;JP9Ovw;DRR+f(dZJ^9aEL25=~GGB8{~2qwS#L2*L6CoJD z029205KMpz-bM%(zywVqkcI5Hx@bzC;Kr zzy)6+1R>SgKW+wwHwZyUbp{fAhY*BRXCT23$bz8i3?%poAsE2G2MQ1#28PcF!2-A- zBfRP{2Nl$y5}APkk-4nlnTtsmuH71>5}di1^pFL?5y!y5q>m7UXD%iKgdjY3Fc~5X z!nC^}1mS6($rT|8Pqa*K2tjzFWpYOd!V@i%2SN~@XqiqS1Q|eO2*W=P2By;pL3m1L zI)e~|r(~wH2tjyCW_p4UgeM!OrwBoKvSCVOU}9ooVq{`waR!Aa0|Of~14liwAX7a9 z0~-qi$2Vj_7LXt>14j~E&>f+@0a*~H{X4QCOnWk1&>Nw>5m^wX{RgrjOnVAk&>x|_ z30V-P{U@>@OnWLw5L{3PL$v>6X5eT>76fVk$HKtz3t14P{U0v_M;fvqM?C`rNP7#i zAQwoGg@NNYvLFvgke7iY9a&HSB*@Ib(TXf61QKLn;P`_qC;}4XW#Gs_7L))9GBa?r zAqz@@1X&n3{vr#?fCPCNII@rh!9^uA14A}KPykXYGBYsbAOxXFk(q&^10l%3paja= zEDQ{t2tfh3U>8DA0WSC-A;`d>0@BXQ0P09EF+rk304~VL$OIEqfD7g#YX_G$%nS^9 z2tfe`m|!2qYp_XgA-IGAF@iYATI+4FOndG3rHm|0|!5npa4uT6WPoN zkV<9-j&@|hD3Blv1IIsP!5EMrF9Syr1ISQN<0M#t0o366$IQS`j1Uxn3zi@R8Q_Bb z2tfsgMW9e(VPKem5EOt5PDBVYzy*at(FuuS1%@Rc?Ys;OA_zeNxS%LPkO3~35AJJ% z`kTQF3!B&Yxt z_RkpvZ>f?TtZ1Px$< z9E?cryaFEOfE36KPe3Yp85o2Rf&y^C3M6kbd;qCrW?-0uEcgi|$il!Rh~#*N zFCal)1_o9JMn(<>CT32CWKb;w?wPW%Ap{|f69xtb7IuUnq&*K3K1dMU++r~SQy`+40W$2vz`$Y(;)8K9 zg8+Ceh=GAcj1ert04g{X3_t@!d<-n&$bte;K?x+m0H`2?B&d7DzyvOL7=-@UGyLOY zU@&7~6jSz%}5-S74dh7yti*1y?W#3NtW> zN;5Ek1feQ-F$jt%&Ffb@U1X&muRwA@R1=$&xwlhdF zFfgcsYCyOk>wX3%Sq27CO$G)gs2~di!vY3=DFy~{H3kL-2Z)*M3=FFfW+DW4GYHBs zFo zh{`cAFhW(bGcfF75QMoCF35D0feB_iRFIj0aRUQCKLdl5Bm)Cu4+BH;AF!Dl;ev_? z!A)>MM}**JxL_hea0^_JaSqH(rmb*6MTFp527VC+1}PZ^2F3;k2IeNcoAX>Ffl%am;+3VA0ZY16B9;=B|ycP zL=a*IFtK{Ac)FQ;7>R1?zL5>7tegOuC|NsC0XJas8;Nf9l5ENoy;D`G| zhJlfhje(JgjX@aVk3S3yvIsGV`~EO6$RUe4)E6-PVPFtrU}R)wU}R!v5Qdv4ju3;o zkAXn~AqI6H1A`<&3?4302r*a~Fi0cB3ZP-Yz{J4F&HxS@age=WUn(##GO{u-GO;p9 zL;UfNfk_b|2Jy!~1|}tBF_1t0F)+!)?T`kU2Z~=N0kHYZybKJ=Ffj%}gc!sQ1_lNp zgc#hvq6jgVf0+`%aRf3?9jcC*p$;JiRmZ~M3D(QV$H1Vkz#vdx@Zl#DLkL3504m1h z#lXnO#lXnS2T~_dU%>E#iNPCLi~}O(gDeJ0yFZv1e38WzAnN>(#S$Q5{>WmWu=>Ho z5P&S!08tl+EVck57KAKz03sHQEcO5*7K#uvV1W38DGXT*;t!^9WHE?8m?DtHApT&A zL>7bigDDDG4B`)_Xk;;nKbT^W#UTD*ibWQK_=719Sq$P2CS?XjMn(okCT4KXt1n>q z$H1V1EC#ao9|MCbLJX3I{xLA9A;chQ;~xWqIzkMRHvTa%XduKOdFCGjgC;@@mc|*h zkj0?(Y9quTdFvkogAPIrlDGabFxVi(7#Ns9{$OOVMTiN&#Ox4a3NSHygqQ(L%mE?h z026aWhy}pJoDgCOFfnI@SOH9o5uW$WLHQD#_jTdwtU+R+uxHXk7K4NVlRiQW7WPaA z2r*drF&QF@LG`*I#9-mVB*wy#jw~hs5@Y6QMHUkRiLr2G zAd5+W#F#nSkj11xVk{h4$YP-K;2$$XHbP8*0Vq3Yrz{GM9Vhju#Aic~Cc?dB9m{>PLjDbN5q>hE52O%Z^6YFJQVq#!mWMW_lW)N_w zXZY}+g`*EijKK*amWeDD0TN^8Xh#-{0*SG36frO|F+t)@fdN#m{bOb*Mu-W(#7Yoi z3^1{NgqQ-uB8ZzOAjAYj$YPH`>R1?NBg7aOAYx1vNOmxM0I6eUn1d|#2_(kC#LB?P$icwG%*l`p%IBc= z5DObZ3{rM7FtD&A#31z%0|N^OLJU%#GBB`kBE%qd4+8@W7eWkD_b@Q9u)y14>2Q0Q z85lVk7#O)381g}4pz@x@1Vn;yF$1J+%fMm^=7Wf01_5w;mx0BMfsvb$fsvnyp&06B zRt9r~7^JRcU}dmCh(YRF237`321af^21b4XhGM8cSQ)GkVo-muGFT(Tp#ETGn9sm3 zAj%-lAPaI11M>q026l$IU^a+g1iKj|wt_)Wn1Ml5nt=f%22r<*K~RK&K~#o;fr)_u zs&^TKkTe5>xH#5>1Qlap zSirz9#lRr0#=yYf05Ol9VHLtWxY%w6K^X=HQ4IzLCb-x_27Z`Z5}2RY6d}Z1_n_%1_nl`I(CLV41zHC!Ni!3GBCmHg^DpV zZeZZ&XJC+$WME+IVPHu912S(TTuc!zwh1og2p8K77fXbTZGnq1&Vic8v=uI<2p3z+ zz%RnUASJ`Vz}UdR!2AYe?>dB73ruW11HUi>gA^z(J78k-K+z4xOcOxq6r}ecgCGL~ zgD3+715*P7L;VK^26mQ12(bw;vBM04f(#6zVi0xAAax8!5MmP;7$9QH!D&Mhlr|PX z;)8`@8zLP*#n@R6fYX7PA_D^xRE&jT5jY)4g3`eOh+cMv9Sr;u3=9$~3=E7gF_ygy zj4})iVhRilOfWHq#o%-Rw)X*4FVj+RIslso6=P=Hi7*c;#?G>jfl-!$0qho-7}GIu MoP+IviZL?+0LyX`KL7v# diff --git a/core/rexcode/isa/riscv/tables/riscv.idx_op_fp.bin b/core/rexcode/isa/riscv/tables/riscv.idx_op_fp.bin index 73a24dc9e65f98690c6837a3b2725fc54a944851..f116ccc8b43b4f27e44c20c63aff726d37bbf446 100644 GIT binary patch literal 512 zcmeBYU}TuUz{oI>fsp|OCNVHFOlDwYm;&WbWng5O#=yuh9m=1E=5vhIy10%ym21bTWQ2Pm) zPiy(j49pDM7?>G$Lj6yweR~*K7!EM7FdSiE!K(EH0}I0$1{Q`3IOMM|Ffm+XU}Cs| SBm8bLFf!a`U}U(1BfJ3rryBtP literal 512 zcma!IU}T79U}S)S7zRd$SR{TN10zE`5|pFyNiL5p&L(l0RX*d3uFKQ diff --git a/core/rexcode/isa/riscv/tables/riscv.idx_opcode.bin b/core/rexcode/isa/riscv/tables/riscv.idx_opcode.bin index ed0bf4dd258af91bcfa4f25d746f8d57cd17fd27..588873e336285d66c2c4987bb0232729aada2ec8 100644 GIT binary patch literal 512 zcmZQT0qkfzW)wa;hl_y;MTmz%427@6z=*bZ7gAfYe z9nF3Z1}+qNbWRYOeIaQ4Ff@Jy8b6A`2;E4M_&p44DC#GnxgSN6fq`K%n*0<74s<01 F`2dF01?>O; diff --git a/core/rexcode/isa/riscv/tables/riscv.idx_rvc.bin b/core/rexcode/isa/riscv/tables/riscv.idx_rvc.bin index 9a3625db5a6f3621e6f377a9792c5a745bbde6c6..e80f1e9373ba85412d8070a05c1c485936dbd0a8 100644 GIT binary patch literal 128 zcmey!z{v24fr;S@10w?nd}Ux{_{PA*@B_;K$-v0)i-D2hH Date: Thu, 20 Aug 2026 19:12:44 +0100 Subject: [PATCH 06/20] Begin work on pseudo mnemonics in the checker --- .../riscv/tablegen/cpp-compiler/cpp-gen.odin | 4 +- .../x86/tablegen/cpp-compiler/cpp-gen.odin | 17 +- src/asm_tables.cpp | 6 +- src/asm_tables_amd64.cpp | 26 ++ src/asm_tables_riscv.cpp | 303 +++++++++++++----- src/check_asm.cpp | 36 ++- src/llvm_backend_asm.cpp | 12 +- src/parser.cpp | 7 +- 8 files changed, 315 insertions(+), 96 deletions(-) diff --git a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin index 7f3362a9b..3aba6c12b 100644 --- a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin @@ -294,7 +294,7 @@ main :: proc() { return found ? *found : PM_INVALID; } - PseudoAlias pseudo_alias(PseudoMnemonic pm) { + PseudoAlias pseudo_alias(u16 pm) { PseudoAlias *pa = (PseudoAlias *)raw_pseudo_aliases; return pa[pm]; } @@ -409,7 +409,7 @@ main :: proc() { strings.write_string(&sb, "\n") strings.write_string(&sb, "\tStringMap mnemonic_map;\n") strings.write_string(&sb, "\tStringMap register_map;\n") - strings.write_string(&sb, "\tStringMap pseudo_register_map;\n") + strings.write_string(&sb, "\tStringMap pseudo_mnemonic_map;\n") strings.write_string(&sb, """ diff --git a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin index 45f07ed9b..56f505d4b 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -340,8 +340,16 @@ main :: proc() { strings.write_string(&sb, "\n"); strings.write_string(&sb, "\n"); strings.write_string(&sb, """ + enum AliasSrc : u8 { + AliasSrc_NONE, // slot unused + }; + struct PseudoAlias { - Mnemonic target; + Mnemonic target; // real instruction emitted + AliasSrc src[4]; // how to fill target's four operand slots + i16 lit; // immediate when a src slot is AliasSrc_LIT + u16 csr; // CSR address when a src slot is AliasSrc_CSR_LIT + u8 nargs; // operands the user supplies (ARG0..>4u)&((1u<<3)-1)); } }; #pragma pack(pop) - GB_STATIC_ASSERT(gb_size_of(Encoding) == 20); + GB_STATIC_ASSERT(gb_size_of(Encoding) == 21); // Companion run index: ENCODE_RUNS[mnemonic] -> contiguous run in ENCODE_FORMS. @@ -313,12 +374,14 @@ struct Asm_riscv { }; - static EncodeRun const raw_encode_runs [199]; - static u8 const raw_encode_forms [3960]; - static u8 const raw_clobber_forms[1782]; + static EncodeRun const raw_encode_runs [282]; + static u8 const raw_encode_forms [5943]; + static u8 const raw_clobber_forms [2547]; + static u8 const raw_pseudo_aliases[696]; StringMap mnemonic_map; StringMap register_map; + StringMap pseudo_mnemonic_map; u16 XLEN; u16 FLEN; @@ -331,6 +394,12 @@ struct Asm_riscv { for (u16 m = M_INVALID+1; m < MNEMONIC_COUNT; m++) { string_map_set(&mnemonic_map, mnemonic_strings[m], cast(Mnemonic)m); } + + string_map_init(&mnemonic_map, PSEUDO_MNEMONIC_COUNT*2); + for (u16 m = PM_INVALID+1; m < PSEUDO_MNEMONIC_COUNT; m++) { + string_map_set(&pseudo_mnemonic_map, pseudo_mnemonic_strings[m], cast(PseudoMnemonic)m); + } + string_map_init(®ister_map, REG_COUNT*2); for (u16 r = REG_INVALID+1; r < REG_COUNT; r++) { string_map_set(®ister_map, register_strings[r], cast(Register)r); @@ -495,8 +564,8 @@ struct Asm_riscv { case OP_FPR_C: return FLEN; - // Memory -> access size (like OP_M*). Base OP_MEM's size comes from the - // opcode, so it's sizeless like x86 OP_M. Compressed forms name the size. + // Memory -> access size (like OP_M*). Base OP_MEM's size comes from the opcode. + // Compressed forms name the size. case OP_MEM: return 0; case OP_MEM_C_W: @@ -506,7 +575,7 @@ struct Asm_riscv { case OP_MEM_C_SP_D: return 64; - // Immediates -> value width (unchanged; matches x86 OP_IMM*). + // Immediates -> value width case OP_IMM12: case OP_IMM12U: case OP_CSR: @@ -532,7 +601,7 @@ struct Asm_riscv { case OP_IMM_C18S: return 18; - // Rels -> displacement value width (unchanged; matches x86 OP_REL*). + // Rels -> displacement value width case OP_REL13: return 13; case OP_REL21: @@ -589,7 +658,12 @@ String const Asm_riscv::mnemonic_strings[Asm_riscv::MNEMONIC_COUNT] { str_lit("flt_d"), str_lit("fle_d"), str_lit("fclass_d"), str_lit("fcvt_w_d"), str_lit("fcvt_wu_d"), str_lit("fcvt_d_w"), str_lit("fcvt_d_wu"), str_lit("fcvt_l_d"), str_lit("fcvt_lu_d"), str_lit("fcvt_d_l"), str_lit("fcvt_d_lu"), str_lit("fmv_x_d"), str_lit("fmv_d_x"), str_lit("c_nop"), str_lit("c_ebreak"), str_lit("c_addi4spn"), str_lit("c_lw"), str_lit("c_ld"), str_lit("c_sw"), str_lit("c_sd"), str_lit("c_flw"), str_lit("c_fsw"), str_lit("c_fld"), str_lit("c_fsd"), str_lit("c_addi"), str_lit("c_addiw"), str_lit("c_li"), str_lit("c_lui"), str_lit("c_addi16sp"), str_lit("c_srli"), str_lit("c_srai"), str_lit("c_andi"), str_lit("c_sub"), str_lit("c_xor"), str_lit("c_or"), str_lit("c_and"), str_lit("c_subw"), str_lit("c_addw"), str_lit("c_j"), str_lit("c_jal"), str_lit("c_beqz"), str_lit("c_bnez"), str_lit("c_slli"), str_lit("c_lwsp"), str_lit("c_ldsp"), str_lit("c_swsp"), str_lit("c_sdsp"), str_lit("c_fldsp"), - str_lit("c_fsdsp"), str_lit("c_jr"), str_lit("c_jalr"), str_lit("c_mv"), str_lit("c_add"), str_lit("c_flwsp"), str_lit("c_fswsp"), + str_lit("c_fsdsp"), str_lit("c_jr"), str_lit("c_jalr"), str_lit("c_mv"), str_lit("c_add"), str_lit("c_flwsp"), str_lit("c_fswsp"), str_lit("sh1add"), str_lit("sh2add"), str_lit("sh3add"), str_lit("add_uw"), str_lit("sh1add_uw"), str_lit("sh2add_uw"), str_lit("sh3add_uw"), str_lit("slli_uw"), str_lit("andn"), + str_lit("orn"), str_lit("xnor"), str_lit("clz"), str_lit("ctz"), str_lit("cpop"), str_lit("sext_b"), str_lit("sext_h"), str_lit("zext_h"), str_lit("min"), str_lit("minu"), str_lit("max"), str_lit("maxu"), str_lit("rol"), str_lit("ror"), str_lit("rori"), str_lit("orc_b"), + str_lit("rev8"), str_lit("clzw"), str_lit("ctzw"), str_lit("cpopw"), str_lit("rolw"), str_lit("rorw"), str_lit("roriw"), str_lit("clmul"), str_lit("clmulh"), str_lit("clmulr"), str_lit("bclr"), str_lit("bclri"), str_lit("bext"), str_lit("bexti"), str_lit("binv"), str_lit("binvi"), + str_lit("bset"), str_lit("bseti"), str_lit("czero_eqz"), str_lit("czero_nez"), str_lit("flh"), str_lit("fsh"), str_lit("fmadd_h"), str_lit("fmsub_h"), str_lit("fnmsub_h"), str_lit("fnmadd_h"), str_lit("fadd_h"), str_lit("fsub_h"), str_lit("fmul_h"), str_lit("fdiv_h"), str_lit("fsqrt_h"), str_lit("fsgnj_h"), + str_lit("fsgnjn_h"), str_lit("fsgnjx_h"), str_lit("fmin_h"), str_lit("fmax_h"), str_lit("fcvt_w_h"), str_lit("fcvt_wu_h"), str_lit("fcvt_l_h"), str_lit("fcvt_lu_h"), str_lit("fcvt_h_w"), str_lit("fcvt_h_wu"), str_lit("fcvt_h_l"), str_lit("fcvt_h_lu"), str_lit("fcvt_s_h"), str_lit("fcvt_h_s"), str_lit("fcvt_d_h"), str_lit("fcvt_h_d"), + str_lit("fmv_x_h"), str_lit("fmv_h_x"), str_lit("fclass_h"), str_lit("feq_h"), str_lit("flt_h"), str_lit("fle_h"), str_lit("mret"), str_lit("sret"), str_lit("wfi"), str_lit("sfence_vma"), }; u16 const Asm_riscv::register_codes[Asm_riscv::REG_COUNT] { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, @@ -605,7 +679,17 @@ String const Asm_riscv::register_strings[Asm_riscv::REG_COUNT] { str_lit("fa5"), str_lit("fa6"), str_lit("fa7"), str_lit("fs2"), str_lit("fs3"), str_lit("fs4"), str_lit("fs5"), str_lit("fs6"), str_lit("fs7"), str_lit("fs8"), str_lit("fs9"), str_lit("fs10"), str_lit("fs11"), str_lit("ft8"), str_lit("ft9"), str_lit("ft10"), str_lit("ft11"), }; -Asm_riscv::EncodeRun const Asm_riscv::raw_encode_runs[199] = { +String const Asm_riscv::pseudo_mnemonic_strings[Asm_riscv::PSEUDO_MNEMONIC_COUNT] { + str_lit(""), str_lit("nop"), str_lit("mv"), str_lit("not"), str_lit("neg"), str_lit("negw"), str_lit("sext_w"), str_lit("zext_b"), + str_lit("seqz"), str_lit("snez"), str_lit("sltz"), str_lit("sgtz"), str_lit("beqz"), str_lit("bnez"), str_lit("blez"), str_lit("bgez"), + str_lit("bltz"), str_lit("bgtz"), str_lit("bgt"), str_lit("ble"), str_lit("bgtu"), str_lit("bleu"), str_lit("j"), str_lit("jal_ra"), + str_lit("jr"), str_lit("jalr_ra"), str_lit("ret"), str_lit("csrr"), str_lit("csrw"), str_lit("csrs"), str_lit("csrc"), str_lit("csrwi"), + str_lit("csrsi"), str_lit("csrci"), str_lit("rdcycle"), str_lit("rdtime"), str_lit("rdinstret"), str_lit("rdcycleh"), str_lit("rdtimeh"), str_lit("rdinstreth"), + str_lit("frcsr"), str_lit("fscsr"), str_lit("frrm"), str_lit("fsrm"), str_lit("frflags"), str_lit("fsflags"), str_lit("fsrmi"), str_lit("fsflagsi"), + str_lit("fmv_s"), str_lit("fabs_s"), str_lit("fneg_s"), str_lit("fmv_d"), str_lit("fabs_d"), str_lit("fneg_d"), str_lit("fmv_h"), str_lit("fabs_h"), + str_lit("fneg_h"), str_lit("fence_all"), +}; +Asm_riscv::EncodeRun const Asm_riscv::raw_encode_runs[282] = { { 0, 0}, { 0, 1}, { 1, 1}, { 2, 1}, { 3, 1}, { 4, 1}, { 5, 1}, { 6, 1}, { 7, 1}, { 8, 1}, { 9, 1}, { 10, 1}, { 11, 1}, { 12, 1}, { 13, 1}, { 14, 1}, { 15, 1}, { 16, 1}, { 17, 1}, { 18, 1}, { 19, 1}, { 20, 1}, { 21, 1}, { 22, 1}, { 23, 1}, { 24, 1}, { 25, 1}, { 26, 1}, { 27, 1}, { 28, 1}, { 29, 1}, { 30, 1}, { 31, 1}, { 32, 1}, { 33, 1}, { 34, 1}, { 35, 1}, { 36, 1}, { 37, 1}, { 38, 1}, { 39, 1}, { 40, 1}, { 41, 1}, { 42, 1}, { 43, 1}, { 44, 1}, { 45, 1}, { 46, 1}, @@ -618,73 +702,109 @@ Asm_riscv::EncodeRun const Asm_riscv::raw_encode_runs[199] = { { 143, 1}, { 144, 1}, { 145, 1}, { 146, 1}, { 147, 1}, { 148, 1}, { 149, 1}, { 150, 1}, { 151, 1}, { 152, 1}, { 153, 1}, { 154, 1}, { 155, 1}, { 156, 1}, { 157, 1}, { 158, 1}, { 159, 1}, { 160, 1}, { 161, 1}, { 162, 1}, { 163, 1}, { 164, 1}, { 165, 1}, { 166, 1}, { 167, 1}, { 168, 1}, { 169, 1}, { 170, 1}, { 171, 1}, { 172, 1}, { 173, 1}, { 174, 1}, { 175, 1}, { 176, 1}, { 177, 1}, { 178, 1}, { 179, 1}, { 180, 1}, { 181, 1}, { 182, 1}, { 183, 1}, { 184, 1}, { 185, 1}, { 186, 1}, { 187, 1}, { 188, 1}, { 189, 1}, { 190, 1}, - { 191, 1}, { 192, 1}, { 193, 1}, { 194, 1}, { 195, 1}, { 196, 1}, { 197, 1}, + { 191, 1}, { 192, 1}, { 193, 1}, { 194, 1}, { 195, 1}, { 196, 1}, { 197, 1}, { 198, 1}, { 199, 1}, { 200, 1}, { 201, 1}, { 202, 1}, { 203, 1}, { 204, 1}, { 205, 1}, { 206, 1}, + { 207, 1}, { 208, 1}, { 209, 1}, { 210, 1}, { 211, 1}, { 212, 1}, { 213, 1}, { 214, 2}, { 216, 1}, { 217, 1}, { 218, 1}, { 219, 1}, { 220, 1}, { 221, 1}, { 222, 1}, { 223, 1}, + { 224, 2}, { 226, 1}, { 227, 1}, { 228, 1}, { 229, 1}, { 230, 1}, { 231, 1}, { 232, 1}, { 233, 1}, { 234, 1}, { 235, 1}, { 236, 1}, { 237, 1}, { 238, 1}, { 239, 1}, { 240, 1}, + { 241, 1}, { 242, 1}, { 243, 1}, { 244, 1}, { 245, 1}, { 246, 1}, { 247, 1}, { 248, 1}, { 249, 1}, { 250, 1}, { 251, 1}, { 252, 1}, { 253, 1}, { 254, 1}, { 255, 1}, { 256, 1}, + { 257, 1}, { 258, 1}, { 259, 1}, { 260, 1}, { 261, 1}, { 262, 1}, { 263, 1}, { 264, 1}, { 265, 1}, { 266, 1}, { 267, 1}, { 268, 1}, { 269, 1}, { 270, 1}, { 271, 1}, { 272, 1}, + { 273, 1}, { 274, 1}, { 275, 1}, { 276, 1}, { 277, 1}, { 278, 1}, { 279, 1}, { 280, 1}, { 281, 1}, { 282, 1}, }; -u8 const Asm_riscv::raw_encode_forms[3960] = { - 0x01, 0x00, 0x01, 0x07, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x07, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x09, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x01, 0x01, - 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x67, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x06, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, - 0x09, 0x00, 0x63, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x09, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x0a, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x70, - 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x04, 0x0b, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x7f, 0x70, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, - 0x11, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x01, 0x0a, - 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x02, 0x15, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x02, 0x16, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, - 0x07, 0x00, 0x13, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x60, - 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfc, 0x00, 0x00, 0x1d, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x50, 0x00, 0x00, 0x7f, 0x70, - 0x00, 0xfc, 0x00, 0x00, 0x1e, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x50, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfc, 0x00, 0x00, 0x1f, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, - 0x21, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x22, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, 0x50, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x23, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x24, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x00, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x25, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x26, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x27, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, - 0x03, 0x00, 0x33, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x28, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x29, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x2a, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, - 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x2b, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x2c, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x2d, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x7f, 0x70, - 0x00, 0xfe, 0x00, 0x02, 0x2e, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x2f, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x30, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, - 0x31, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x02, 0x32, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x11, 0x12, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x06, 0x00, 0x34, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x04, 0x36, 0x00, 0x01, 0x0b, 0x01, 0x00, 0x01, 0x0f, 0x02, 0x00, 0x73, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x37, 0x00, 0x01, 0x0b, 0x01, 0x00, 0x01, 0x0f, - 0x02, 0x00, 0x73, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x38, 0x00, 0x01, 0x0b, 0x01, 0x00, 0x01, 0x0f, 0x02, 0x00, 0x73, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x39, 0x00, 0x01, 0x0b, 0x0e, 0x00, 0x01, 0x0f, 0x10, 0x00, 0x73, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x3a, 0x00, 0x01, 0x0b, 0x0e, 0x00, 0x01, 0x0f, 0x10, 0x00, 0x73, 0x60, - 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x3b, 0x00, 0x01, 0x0b, 0x0e, 0x00, 0x01, 0x0f, 0x10, 0x00, 0x73, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x3c, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x00, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x3d, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x02, 0x7f, 0x70, - 0x00, 0xfe, 0x01, 0x00, 0x3e, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x20, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x3f, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x30, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x40, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x40, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, - 0x41, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x42, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x60, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x43, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x70, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x44, 0x00, 0x01, 0x01, - 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x45, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x40, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x47, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, - 0x03, 0x00, 0x3b, 0x60, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x48, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x70, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x02, 0x49, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x2f, 0x20, 0x00, 0x10, 0x7f, 0x70, 0xf0, 0xf9, 0x02, 0x00, 0x4a, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, - 0x00, 0x18, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x4b, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x08, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x4c, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x4d, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x20, 0x7f, 0x70, - 0x00, 0xf8, 0x02, 0x00, 0x4e, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x4f, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x50, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x80, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, - 0x51, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x52, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0xc0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x53, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0xe0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x54, 0x00, 0x01, 0x0a, - 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x2f, 0x30, 0x00, 0x10, 0x7f, 0x70, 0xf0, 0xf9, 0x02, 0x02, 0x55, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x18, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x56, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x08, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x57, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, - 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x58, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x59, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5a, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, - 0x00, 0x40, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5b, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x80, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5c, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5d, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0xc0, 0x7f, 0x70, - 0x00, 0xf8, 0x02, 0x02, 0x5e, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0xe0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x02, 0x5f, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x03, 0x00, 0x60, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x27, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x03, 0x00, - 0x61, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x43, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x08, 0x62, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x47, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x08, 0x63, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4b, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x08, 0x64, 0x00, 0x02, 0x02, - 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x08, 0x65, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x08, 0x66, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x08, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x08, 0x67, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, - 0x03, 0x00, 0x53, 0x00, 0x00, 0x10, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x08, 0x68, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x18, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x08, 0x69, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0x58, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, 0x6a, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, - 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x6b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x6c, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x6d, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x28, 0x7f, 0x70, - 0x00, 0xfe, 0x03, 0x00, 0x6e, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x28, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x6f, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, 0x70, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, - 0x71, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xe0, 0x7f, 0x70, 0xf0, 0xff, 0x03, 0x00, 0x72, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x73, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x74, 0x00, 0x01, 0x02, - 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x75, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x10, 0x00, 0xe0, 0x7f, 0x70, 0xf0, 0xff, 0x03, 0x00, 0x76, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, 0x77, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, - 0x00, 0x00, 0x53, 0x00, 0x10, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x08, 0x78, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xf0, 0x7f, 0x70, 0xf0, 0xff, 0x03, 0x00, 0x79, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x0a, 0x7a, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, - 0x30, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x0a, 0x7b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x0a, 0x7c, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x0a, 0x7d, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x7f, 0x70, - 0x00, 0x00, 0x04, 0x00, 0x7e, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x27, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x04, 0x00, 0x7f, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x43, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x08, 0x80, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x47, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x08, - 0x81, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4b, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x08, 0x82, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4f, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x08, 0x83, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x08, 0x84, 0x00, 0x02, 0x02, - 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x0a, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x08, 0x85, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x12, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x08, 0x86, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x1a, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x08, 0x87, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, - 0x00, 0x00, 0x53, 0x00, 0x00, 0x5a, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x88, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x22, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x89, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x22, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x8a, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, - 0x00, 0x22, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x8b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x2a, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x8c, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x2a, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x8d, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0x40, 0x7f, 0x00, - 0xf0, 0xff, 0x04, 0x08, 0x8e, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0x42, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x8f, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0xa2, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x90, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0xa2, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, - 0x91, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0xa2, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x92, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x10, 0x00, 0xe2, 0x7f, 0x70, 0xf0, 0xff, 0x04, 0x00, 0x93, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x94, 0x00, 0x01, 0x02, - 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x95, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x96, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x08, 0x97, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, - 0x00, 0x00, 0x53, 0x00, 0x20, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x0a, 0x98, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x0a, 0x99, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x0a, 0x9a, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, - 0x30, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x0a, 0x9b, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xe2, 0x7f, 0x70, 0xf0, 0xff, 0x04, 0x02, 0x9c, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xf2, 0x7f, 0x70, 0xf0, 0xff, 0x04, 0x02, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x00, 0x00, 0x07, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x90, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x07, 0x00, 0x9f, 0x00, 0x0f, 0x10, 0x15, 0x00, 0x17, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xa0, 0x00, 0x0f, 0x1a, 0x00, 0x00, 0x17, 0x26, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, - 0xa1, 0x00, 0x0f, 0x1b, 0x00, 0x00, 0x17, 0x27, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xa2, 0x00, 0x0f, 0x1a, 0x00, 0x00, 0x19, 0x26, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xa3, 0x00, 0x0f, 0x1b, 0x00, 0x00, 0x19, 0x27, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xa4, 0x00, 0x12, 0x1a, - 0x00, 0x00, 0x17, 0x26, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x01, 0xa5, 0x00, 0x12, 0x1a, 0x00, 0x00, 0x19, 0x26, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x01, 0xa6, 0x00, 0x12, 0x1b, 0x00, 0x00, 0x17, 0x27, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0xa7, 0x00, 0x12, 0x1b, 0x00, 0x00, 0x19, 0x27, - 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0xa8, 0x00, 0x11, 0x13, 0x00, 0x00, 0x15, 0x1b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xa9, 0x00, 0x11, 0x13, 0x00, 0x00, 0x15, 0x1b, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xaa, 0x00, 0x11, 0x13, 0x00, 0x00, 0x15, 0x1b, 0x00, 0x00, 0x01, 0x40, - 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xab, 0x00, 0x11, 0x17, 0x00, 0x00, 0x15, 0x1e, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xac, 0x00, 0x10, 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x61, 0x00, 0x00, 0x83, 0xef, 0x00, 0x00, 0x07, 0x00, 0xad, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x1a, 0x1c, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0xec, - 0x00, 0x00, 0x07, 0x00, 0xae, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x1a, 0x1c, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x07, 0x00, 0xaf, 0x00, 0x0f, 0x13, 0x00, 0x00, 0x1a, 0x1b, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x07, 0x00, 0xb0, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, - 0xb1, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x21, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0xb2, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x41, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0xb3, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x61, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0xb4, 0x00, 0x0f, 0x0f, - 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x01, 0x9c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x02, 0xb5, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x21, 0x9c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x02, 0xb6, 0x00, 0x19, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x04, 0xb7, 0x00, 0x19, 0x00, 0x00, 0x00, 0x25, 0x00, - 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x05, 0xb8, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x04, 0xb9, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x04, 0xba, 0x00, 0x11, 0x14, 0x00, 0x00, 0x15, 0x1c, 0x00, 0x00, 0x02, 0x00, - 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xbb, 0x00, 0x11, 0x1c, 0x00, 0x00, 0x15, 0x28, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xbc, 0x00, 0x11, 0x1d, 0x00, 0x00, 0x15, 0x29, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xbd, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x16, 0x20, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0x03, 0xe0, - 0x00, 0x00, 0x07, 0x00, 0xbe, 0x00, 0x01, 0x1d, 0x00, 0x00, 0x16, 0x21, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x02, 0xbf, 0x00, 0x02, 0x1d, 0x00, 0x00, 0x15, 0x29, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0xc0, 0x00, 0x02, 0x1d, 0x00, 0x00, 0x16, 0x21, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, - 0xc1, 0x00, 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x07, 0x04, 0xc2, 0x00, 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x90, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x07, 0x04, 0xc3, 0x00, 0x11, 0x11, 0x00, 0x00, 0x15, 0x16, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0x00, 0xc4, 0x00, 0x11, 0x11, - 0x00, 0x00, 0x15, 0x16, 0x00, 0x00, 0x02, 0x90, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0x00, 0xc5, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x15, 0x28, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x01, 0xc6, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x16, 0x20, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x01, +u8 const Asm_riscv::raw_encode_forms[5943] = { + 0x01, 0x00, 0x01, 0x07, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x02, 0x00, 0x01, 0x07, 0x00, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x03, 0x00, 0x01, 0x09, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x00, 0x6f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x04, + 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x67, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x34, 0x05, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x34, 0x06, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x34, 0x07, 0x00, + 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x34, 0x08, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x34, 0x09, 0x00, 0x01, 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x34, 0x0a, 0x00, 0x01, + 0x01, 0x08, 0x00, 0x02, 0x03, 0x09, 0x00, 0x63, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x34, 0x0b, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0c, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0d, 0x00, 0x01, 0x0a, + 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0e, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0f, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x01, 0x0a, 0x00, + 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x20, 0x12, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x20, 0x13, 0x00, 0x01, 0x0a, 0x00, 0x00, + 0x01, 0x0c, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x22, 0x14, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x22, 0x15, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x23, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x22, 0x16, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, + 0x02, 0x07, 0x00, 0x13, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, 0x17, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, 0x19, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, + 0x07, 0x00, 0x13, 0x40, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, 0x1a, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, 0x1b, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, 0x13, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x30, 0x1c, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, + 0x00, 0x13, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfc, 0x00, 0x00, 0x30, 0x1d, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfc, 0x00, 0x00, 0x30, 0x1e, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x50, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfc, 0x00, 0x00, 0x30, 0x1f, 0x00, 0x01, 0x01, 0x03, 0x00, 0x01, 0x02, 0x07, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x32, 0x20, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x32, 0x21, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x32, 0x22, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, + 0x50, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x32, 0x23, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x24, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x00, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x25, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, + 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x26, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x27, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x28, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x40, 0x00, + 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x29, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x2a, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x2b, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x60, 0x00, 0x00, + 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x2c, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x30, 0x2d, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x32, 0x2e, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x40, 0x7f, + 0x70, 0x00, 0xfe, 0x00, 0x00, 0x32, 0x2f, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x32, 0x30, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xfe, 0x00, 0x00, 0x32, 0x31, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x40, 0x7f, 0x70, + 0x00, 0xfe, 0x00, 0x00, 0x32, 0x32, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x11, 0x12, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x00, 0x00, 0x20, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x10, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x06, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x04, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x10, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x04, 0x36, 0x00, 0x01, 0x0b, 0x01, 0x00, 0x01, 0x0f, 0x02, 0x00, 0x73, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x30, 0x37, 0x00, 0x01, 0x0b, 0x01, 0x00, 0x01, 0x0f, 0x02, 0x00, 0x73, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, + 0x05, 0x00, 0x30, 0x38, 0x00, 0x01, 0x0b, 0x01, 0x00, 0x01, 0x0f, 0x02, 0x00, 0x73, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x30, 0x39, 0x00, 0x01, 0x0b, 0x0e, 0x00, 0x01, 0x0f, 0x10, 0x00, 0x73, 0x50, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x30, 0x3a, 0x00, 0x01, 0x0b, 0x0e, 0x00, 0x01, 0x0f, 0x10, 0x00, 0x73, 0x60, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, + 0x00, 0x30, 0x3b, 0x00, 0x01, 0x0b, 0x0e, 0x00, 0x01, 0x0f, 0x10, 0x00, 0x73, 0x70, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x05, 0x00, 0x30, 0x3c, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x00, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x30, 0x3d, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, + 0x30, 0x3e, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x20, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x30, 0x3f, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x30, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x30, 0x40, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x40, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x30, + 0x41, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x30, 0x42, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x60, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x30, 0x43, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x70, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x30, 0x44, + 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x32, 0x45, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x40, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x32, 0x46, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x32, 0x47, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x60, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x32, 0x48, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x70, 0x00, 0x02, 0x7f, 0x70, 0x00, 0xfe, 0x01, 0x00, 0x32, 0x49, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x2f, 0x20, 0x00, 0x10, 0x7f, 0x70, 0xf0, 0xf9, 0x02, 0x00, 0x20, 0x4a, 0x00, 0x01, + 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x18, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x4b, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x08, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x4c, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x4d, 0x00, 0x01, 0x01, + 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x4e, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x4f, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x50, 0x00, 0x01, 0x01, 0x0a, + 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0x80, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x51, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x52, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0xc0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x53, 0x00, 0x01, 0x01, 0x0a, 0x00, + 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x20, 0x00, 0xe0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x30, 0x54, 0x00, 0x01, 0x0a, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x2f, 0x30, 0x00, 0x10, 0x7f, 0x70, 0xf0, 0xf9, 0x02, 0x00, 0x22, 0x55, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x18, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x56, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, + 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x08, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x57, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x58, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x59, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, + 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x5a, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x5b, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0x80, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x5c, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, + 0x00, 0x2f, 0x30, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x5d, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0xc0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x5e, 0x00, 0x01, 0x01, 0x0a, 0x00, 0x01, 0x03, 0x0e, 0x00, 0x2f, 0x30, 0x00, 0xe0, 0x7f, 0x70, 0x00, 0xf8, 0x02, 0x00, 0x32, 0x5f, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, + 0x07, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x03, 0x00, 0x20, 0x60, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x27, 0x20, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x03, 0x00, 0x20, 0x61, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x43, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x00, 0x48, 0x62, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x47, + 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x00, 0x48, 0x63, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4b, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x00, 0x48, 0x64, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4f, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x06, 0x03, 0x00, 0x48, 0x65, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, + 0x00, 0x00, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x38, 0x66, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x08, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x38, 0x67, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x10, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x38, 0x68, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, + 0x18, 0x7f, 0x00, 0x00, 0xfe, 0x03, 0x00, 0x38, 0x69, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0x58, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x28, 0x6a, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x30, 0x6b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x20, + 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x30, 0x6c, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x30, 0x6d, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x28, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x30, 0x6e, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x28, 0x7f, + 0x70, 0x00, 0xfe, 0x03, 0x00, 0x30, 0x6f, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x28, 0x70, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x28, 0x71, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xe0, 0x7f, 0x70, + 0xf0, 0xff, 0x03, 0x00, 0x20, 0x72, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x30, 0x73, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0xa0, 0x7f, 0x70, 0x00, 0xfe, 0x03, 0x00, 0x30, 0x74, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0xa0, 0x7f, 0x70, 0x00, + 0xfe, 0x03, 0x00, 0x30, 0x75, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x10, 0x00, 0xe0, 0x7f, 0x70, 0xf0, 0xff, 0x03, 0x00, 0x20, 0x76, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x28, 0x77, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xd0, 0x7f, 0x00, 0xf0, 0xff, + 0x03, 0x00, 0x28, 0x78, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xf0, 0x7f, 0x70, 0xf0, 0xff, 0x03, 0x00, 0x20, 0x79, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x2a, 0x7a, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xc0, 0x7f, 0x00, 0xf0, 0xff, 0x03, + 0x00, 0x2a, 0x7b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x2a, 0x7c, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xd0, 0x7f, 0x00, 0xf0, 0xff, 0x03, 0x00, 0x2a, 0x7d, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x04, 0x00, + 0x20, 0x7e, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x27, 0x30, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x04, 0x00, 0x20, 0x7f, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x43, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x00, 0x48, 0x80, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x47, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x00, 0x48, + 0x81, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4b, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x00, 0x48, 0x82, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4f, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x06, 0x04, 0x00, 0x48, 0x83, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x00, 0x38, 0x84, + 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x0a, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x00, 0x38, 0x85, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x12, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x00, 0x38, 0x86, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x1a, 0x7f, 0x00, 0x00, 0xfe, 0x04, 0x00, 0x38, 0x87, 0x00, + 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0x5a, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x28, 0x88, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x22, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x30, 0x89, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x22, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x30, 0x8a, 0x00, 0x02, + 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0x22, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x30, 0x8b, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x2a, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x30, 0x8c, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x2a, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x30, 0x8d, 0x00, 0x02, 0x02, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0x40, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x28, 0x8e, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0x42, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x28, 0x8f, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0xa2, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x30, 0x90, 0x00, 0x01, 0x02, 0x02, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0xa2, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x30, 0x91, 0x00, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0xa2, 0x7f, 0x70, 0x00, 0xfe, 0x04, 0x00, 0x30, 0x92, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x10, 0x00, 0xe2, 0x7f, 0x70, 0xf0, 0xff, 0x04, 0x00, 0x20, 0x93, 0x00, 0x01, 0x02, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x28, 0x94, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x28, 0x95, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x28, 0x96, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x28, 0x97, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x2a, 0x98, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xc2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x2a, 0x99, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x53, 0x00, 0x20, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x2a, 0x9a, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xd2, 0x7f, 0x00, 0xf0, 0xff, 0x04, 0x00, 0x2a, 0x9b, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xe2, 0x7f, 0x70, 0xf0, 0xff, 0x04, 0x00, 0x22, 0x9c, 0x00, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x53, 0x00, 0x00, 0xf2, 0x7f, 0x70, 0xf0, 0xff, 0x04, 0x00, 0x22, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x07, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x90, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x07, 0x00, 0x00, 0x9f, 0x00, 0x0f, 0x10, 0x15, 0x00, 0x17, 0x00, 0x1d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0xa0, 0xa0, 0x00, 0x0f, 0x1a, 0x00, 0x00, 0x17, 0x26, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x20, 0xa1, 0x00, 0x0f, 0x1b, 0x00, 0x00, 0x17, 0x27, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x22, 0xa2, 0x00, 0x0f, 0x1a, 0x00, 0x00, 0x19, 0x26, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x20, 0xa3, 0x00, 0x0f, 0x1b, 0x00, 0x00, 0x19, 0x27, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x22, 0xa4, 0x00, 0x12, 0x1a, 0x00, 0x00, 0x17, 0x26, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x00, 0x21, 0xa5, 0x00, 0x12, 0x1a, 0x00, 0x00, 0x19, 0x26, 0x00, 0x00, 0x00, 0xe0, + 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x00, 0x21, 0xa6, 0x00, 0x12, 0x1b, 0x00, 0x00, 0x17, 0x27, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0x20, 0xa7, 0x00, 0x12, 0x1b, 0x00, 0x00, 0x19, 0x27, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0x20, 0xa8, 0x00, 0x11, 0x13, 0x00, 0x00, 0x15, 0x1b, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x20, 0xa9, 0x00, 0x11, 0x13, 0x00, 0x00, 0x15, 0x1b, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x22, 0xaa, 0x00, 0x11, 0x13, 0x00, 0x00, 0x15, 0x1b, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x20, 0xab, 0x00, 0x11, 0x17, 0x00, 0x00, 0x15, 0x1e, 0x00, 0x00, 0x01, 0x60, 0x00, 0x00, + 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x20, 0xac, 0x00, 0x10, 0x16, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x01, 0x61, 0x00, 0x00, 0x83, 0xef, 0x00, 0x00, 0x07, 0x00, 0x90, 0xad, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x1a, 0x1c, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x07, 0x00, 0x20, 0xae, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x1a, 0x1c, 0x00, 0x00, 0x01, 0x84, 0x00, 0x00, 0x03, + 0xec, 0x00, 0x00, 0x07, 0x00, 0x20, 0xaf, 0x00, 0x0f, 0x13, 0x00, 0x00, 0x1a, 0x1b, 0x00, 0x00, 0x01, 0x88, 0x00, 0x00, 0x03, 0xec, 0x00, 0x00, 0x07, 0x00, 0x20, 0xb0, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0x20, 0xb1, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x21, 0x8c, 0x00, 0x00, 0x63, 0xfc, + 0x00, 0x00, 0x07, 0x00, 0x20, 0xb2, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x41, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0x20, 0xb3, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x61, 0x8c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0x20, 0xb4, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x01, 0x9c, 0x00, 0x00, 0x63, 0xfc, 0x00, + 0x00, 0x07, 0x00, 0x22, 0xb5, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x1a, 0x19, 0x00, 0x00, 0x21, 0x9c, 0x00, 0x00, 0x63, 0xfc, 0x00, 0x00, 0x07, 0x00, 0x22, 0xb6, 0x00, 0x19, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0xa0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x14, 0xb7, 0x00, 0x19, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, + 0x07, 0x00, 0x15, 0xb8, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x01, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x24, 0xb9, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x18, 0x24, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x24, 0xba, 0x00, 0x11, 0x14, 0x00, 0x00, 0x15, 0x1c, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, + 0x00, 0x20, 0xbb, 0x00, 0x11, 0x1c, 0x00, 0x00, 0x15, 0x28, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x20, 0xbc, 0x00, 0x11, 0x1d, 0x00, 0x00, 0x15, 0x29, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x22, 0xbd, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x16, 0x20, 0x00, 0x00, 0x02, 0xc0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, + 0x20, 0xbe, 0x00, 0x01, 0x1d, 0x00, 0x00, 0x16, 0x21, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x07, 0x00, 0x22, 0xbf, 0x00, 0x02, 0x1d, 0x00, 0x00, 0x15, 0x29, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0x20, 0xc0, 0x00, 0x02, 0x1d, 0x00, 0x00, 0x16, 0x21, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x04, 0x00, 0x20, + 0xc1, 0x00, 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x07, 0x00, 0x14, 0xc2, 0x00, 0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x02, 0x90, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x07, 0x00, 0x14, 0xc3, 0x00, 0x11, 0x11, 0x00, 0x00, 0x15, 0x16, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0x00, 0x20, 0xc4, + 0x00, 0x11, 0x11, 0x00, 0x00, 0x15, 0x16, 0x00, 0x00, 0x02, 0x90, 0x00, 0x00, 0x03, 0xf0, 0x00, 0x00, 0x07, 0x00, 0x20, 0xc5, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x15, 0x28, 0x00, 0x00, 0x02, 0x60, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x00, 0x21, 0xc6, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x16, 0x20, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x03, 0x00, 0x21, 0xc7, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x20, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x08, 0x00, 0x30, 0xc8, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x40, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x08, 0x00, 0x30, 0xc9, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x60, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x08, 0x00, 0x30, 0xca, 0x00, 0x01, + 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x00, 0x00, 0x08, 0x7f, 0x70, 0x00, 0xfe, 0x08, 0x00, 0x32, 0xcb, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x20, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x08, 0x00, 0x32, 0xcc, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x40, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x08, 0x00, 0x32, 0xcd, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x60, 0x00, 0x20, 0x7f, 0x70, 0x00, 0xfe, 0x08, 0x00, 0x32, 0xce, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x1b, 0x10, 0x00, 0x08, 0x7f, 0x70, 0x00, 0xfc, 0x08, 0x00, 0x32, 0xcf, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x70, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x30, 0xd0, 0x00, 0x01, 0x01, 0x01, + 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x60, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x30, 0xd1, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x40, 0x00, 0x40, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x30, 0xd2, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x13, 0x10, 0x00, 0x60, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x20, 0xd3, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x00, 0x13, 0x10, 0x10, 0x60, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x20, 0xd4, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x13, 0x10, 0x20, 0x60, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x20, 0xd5, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x13, 0x10, 0x40, 0x60, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x20, 0xd6, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x00, 0x13, 0x10, 0x50, 0x60, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x20, 0xd7, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x33, 0x40, 0x00, 0x08, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x21, 0xd7, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x3b, 0x40, 0x00, 0x08, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x22, 0xd8, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, + 0x03, 0x00, 0x33, 0x40, 0x00, 0x0a, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x30, 0xd9, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x0a, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x30, 0xda, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x60, 0x00, 0x0a, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x30, 0xdb, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, + 0x00, 0x33, 0x70, 0x00, 0x0a, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x30, 0xdc, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x30, 0xdd, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x30, 0xde, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, + 0x13, 0x50, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xfc, 0x09, 0x00, 0x30, 0xdf, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x13, 0x50, 0x70, 0x28, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x20, 0xe0, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x13, 0x50, 0x80, 0x69, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x21, 0xe0, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x13, + 0x50, 0x80, 0x6b, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x22, 0xe1, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x1b, 0x10, 0x00, 0x60, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x22, 0xe2, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x1b, 0x10, 0x10, 0x60, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x22, 0xe3, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x1b, 0x10, + 0x20, 0x60, 0x7f, 0x70, 0xf0, 0xff, 0x09, 0x00, 0x22, 0xe4, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x10, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x32, 0xe5, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x3b, 0x50, 0x00, 0x60, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x32, 0xe6, 0x00, 0x01, 0x01, 0x05, 0x00, 0x01, 0x02, 0x05, 0x00, 0x1b, 0x50, 0x00, + 0x60, 0x7f, 0x70, 0x00, 0xfe, 0x09, 0x00, 0x32, 0xe7, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x0a, 0x7f, 0x70, 0x00, 0xfe, 0x0a, 0x00, 0x30, 0xe8, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x30, 0x00, 0x0a, 0x7f, 0x70, 0x00, 0xfe, 0x0a, 0x00, 0x30, 0xe9, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x20, 0x00, 0x0a, + 0x7f, 0x70, 0x00, 0xfe, 0x0a, 0x00, 0x30, 0xea, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x48, 0x7f, 0x70, 0x00, 0xfe, 0x0b, 0x00, 0x30, 0xeb, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x10, 0x00, 0x48, 0x7f, 0x70, 0x00, 0xfc, 0x0b, 0x00, 0x30, 0xec, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x48, 0x7f, + 0x70, 0x00, 0xfe, 0x0b, 0x00, 0x30, 0xed, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x50, 0x00, 0x48, 0x7f, 0x70, 0x00, 0xfc, 0x0b, 0x00, 0x30, 0xee, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x68, 0x7f, 0x70, 0x00, 0xfe, 0x0b, 0x00, 0x30, 0xef, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x10, 0x00, 0x68, 0x7f, 0x70, + 0x00, 0xfc, 0x0b, 0x00, 0x30, 0xf0, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x10, 0x00, 0x28, 0x7f, 0x70, 0x00, 0xfe, 0x0b, 0x00, 0x30, 0xf1, 0x00, 0x01, 0x01, 0x06, 0x00, 0x01, 0x02, 0x06, 0x00, 0x13, 0x10, 0x00, 0x28, 0x7f, 0x70, 0x00, 0xfc, 0x0b, 0x00, 0x30, 0xf2, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x50, 0x00, 0x0e, 0x7f, 0x70, 0x00, + 0xfe, 0x0c, 0x00, 0x30, 0xf3, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x02, 0x03, 0x00, 0x33, 0x70, 0x00, 0x0e, 0x7f, 0x70, 0x00, 0xfe, 0x0c, 0x00, 0x30, 0xf4, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x01, 0x0c, 0x00, 0x00, 0x07, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, 0x0d, 0x00, 0x20, 0xf5, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x03, 0x0d, 0x00, 0x00, 0x27, 0x10, 0x00, 0x00, 0x7f, 0x70, 0x00, 0x00, + 0x0d, 0x00, 0x20, 0xf6, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x43, 0x00, 0x00, 0x04, 0x7f, 0x00, 0x00, 0x06, 0x0d, 0x00, 0x48, 0xf7, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x47, 0x00, 0x00, 0x04, 0x7f, 0x00, 0x00, 0x06, 0x0d, 0x00, 0x48, 0xf8, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4b, 0x00, 0x00, 0x04, 0x7f, 0x00, 0x00, 0x06, 0x0d, + 0x00, 0x48, 0xf9, 0x00, 0x02, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x04, 0x4f, 0x00, 0x00, 0x04, 0x7f, 0x00, 0x00, 0x06, 0x0d, 0x00, 0x48, 0xfa, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x04, 0x7f, 0x00, 0x00, 0xfe, 0x0d, 0x00, 0x38, 0xfb, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x0c, 0x7f, 0x00, 0x00, 0xfe, 0x0d, 0x00, + 0x38, 0xfc, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x14, 0x7f, 0x00, 0x00, 0xfe, 0x0d, 0x00, 0x38, 0xfd, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x1c, 0x7f, 0x00, 0x00, 0xfe, 0x0d, 0x00, 0x38, 0xfe, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0x5c, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x28, + 0xff, 0x00, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x24, 0x7f, 0x70, 0x00, 0xfe, 0x0d, 0x00, 0x30, 0x00, 0x01, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x24, 0x7f, 0x70, 0x00, 0xfe, 0x0d, 0x00, 0x30, 0x01, 0x01, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0x24, 0x7f, 0x70, 0x00, 0xfe, 0x0d, 0x00, 0x30, 0x02, + 0x01, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0x2c, 0x7f, 0x70, 0x00, 0xfe, 0x0d, 0x00, 0x30, 0x03, 0x01, 0x02, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0x2c, 0x7f, 0x70, 0x00, 0xfe, 0x0d, 0x00, 0x30, 0x04, 0x01, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xc4, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x28, 0x05, 0x01, + 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xc4, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x28, 0x06, 0x01, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xc4, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x2a, 0x07, 0x01, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xc4, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x2a, 0x08, 0x01, 0x02, + 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xd4, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x28, 0x09, 0x01, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0xd4, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x28, 0x0a, 0x01, 0x02, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0xd4, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x2a, 0x0b, 0x01, 0x02, 0x01, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x30, 0xd4, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x2a, 0x0c, 0x01, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0x40, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x28, 0x0d, 0x01, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0x44, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x28, 0x0e, 0x01, 0x02, 0x02, 0x00, + 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x20, 0x42, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x28, 0x0f, 0x01, 0x02, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x10, 0x44, 0x7f, 0x00, 0xf0, 0xff, 0x0d, 0x00, 0x28, 0x10, 0x01, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xe4, 0x7f, 0x70, 0xf0, 0xff, 0x0d, 0x00, 0x20, 0x11, 0x01, 0x02, 0x01, 0x00, 0x00, + 0x01, 0x02, 0x00, 0x00, 0x53, 0x00, 0x00, 0xf4, 0x7f, 0x70, 0xf0, 0xff, 0x0d, 0x00, 0x20, 0x12, 0x01, 0x01, 0x02, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x53, 0x10, 0x00, 0xe4, 0x7f, 0x70, 0xf0, 0xff, 0x0d, 0x00, 0x20, 0x13, 0x01, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x20, 0x00, 0xa4, 0x7f, 0x70, 0x00, 0xfe, 0x0d, 0x00, 0x30, 0x14, 0x01, 0x01, 0x02, 0x02, 0x00, 0x01, + 0x02, 0x03, 0x00, 0x53, 0x10, 0x00, 0xa4, 0x7f, 0x70, 0x00, 0xfe, 0x0d, 0x00, 0x30, 0x15, 0x01, 0x01, 0x02, 0x02, 0x00, 0x01, 0x02, 0x03, 0x00, 0x53, 0x00, 0x00, 0xa4, 0x7f, 0x70, 0x00, 0xfe, 0x0d, 0x00, 0x30, 0x16, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x20, 0x30, 0xff, 0xff, 0xff, 0xff, 0x0e, 0x00, 0x04, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x73, 0x00, 0x20, 0x10, 0xff, 0xff, 0xff, 0xff, 0x0e, 0x00, 0x04, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x50, 0x10, 0xff, 0xff, 0xff, 0xff, 0x0e, 0x00, 0x00, 0x19, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x03, 0x00, 0x00, 0x73, 0x00, 0x00, 0x12, 0xff, 0x7f, 0x00, 0xfe, 0x0e, 0x00, 0x20, }; -u8 const Asm_riscv::raw_clobber_forms[1782] = { +u8 const Asm_riscv::raw_clobber_forms[2547] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, @@ -712,5 +832,30 @@ u8 const Asm_riscv::raw_clobber_forms[1782] = { 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x1d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, +}; +u8 const Asm_riscv::raw_pseudo_aliases[696] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x04, 0x04, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x19, 0x00, 0x01, 0x02, 0x06, 0x00, 0xff, 0xff, 0x00, 0x00, 0x02, 0x00, 0x24, 0x00, 0x01, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x2e, 0x00, 0x01, 0x04, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x01, 0x02, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x01, 0x02, 0x06, 0x00, 0xff, 0x00, 0x00, 0x00, 0x02, 0x00, 0x18, 0x00, 0x01, 0x02, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x27, 0x00, 0x01, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x26, 0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x26, 0x00, 0x01, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x01, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x00, 0x01, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x08, 0x00, 0x01, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x07, 0x00, 0x01, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x09, 0x00, 0x02, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x02, 0x01, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x04, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x05, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x04, 0x05, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x36, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x38, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x39, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, + 0x3a, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3b, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x37, 0x00, 0x01, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x37, 0x00, 0x01, 0x07, 0x04, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x01, 0x00, 0x37, 0x00, 0x01, 0x07, 0x04, 0x00, 0x00, 0x00, 0x02, 0x0c, 0x01, 0x00, 0x37, 0x00, 0x01, 0x07, + 0x04, 0x00, 0x00, 0x00, 0x80, 0x0c, 0x01, 0x01, 0x37, 0x00, 0x01, 0x07, 0x04, 0x00, 0x00, 0x00, 0x81, 0x0c, 0x01, 0x01, 0x37, 0x00, 0x01, 0x07, 0x04, 0x00, 0x00, 0x00, 0x82, 0x0c, 0x01, 0x01, 0x37, 0x00, 0x01, 0x07, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x36, 0x00, 0x01, 0x07, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x37, 0x00, 0x01, 0x07, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x36, 0x00, 0x01, 0x07, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x37, 0x00, 0x01, 0x07, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x36, 0x00, 0x01, 0x07, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x39, 0x00, 0x01, 0x07, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x39, 0x00, 0x01, 0x07, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, + 0x6a, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x6c, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x6b, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x88, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x8a, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x89, 0x00, 0x01, 0x02, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xff, 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x32, 0x00, 0x06, 0x06, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, }; diff --git a/src/check_asm.cpp b/src/check_asm.cpp index e7f4b6e75..27cc5a34f 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -844,6 +844,7 @@ gb_internal bool check_register(AsmCtx *asm_ctx, Operand *operand, AstAsmRegiste enum CheckMnemomicResult { CheckMnemomic_Invalid, CheckMnemomic_Mnemonic, + CheckMnemomic_PseudoMnemonic, CheckMnemomic_Prefix, }; @@ -862,6 +863,12 @@ gb_internal CheckMnemomicResult check_mnemonic_name(AsmCtx *asm_ctx, AstAsmInstr if (mnemonic_) *mnemonic_ = cast(u16)m; return CheckMnemomic_Mnemonic; } + auto pm = asm_ctx->pseudo_mnemonic_lookup(name); + if (pm) { + if (mnemonic_) *mnemonic_ = pm; + return CheckMnemomic_PseudoMnemonic; + } + ERROR_BLOCK(); if (instr->operands.count == 0) { @@ -913,13 +920,18 @@ struct AsmMnemonicAccumulator { template gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tmpl_entity, AstAsmInstruction *instr, - u16 mnemonic, Slice const &operands, + u16 mnemonic, u16 pseudo_mnemonic, Slice const &operands, u8 previous_prefix, Ast *previous_prefix_instr, AsmMnemonicAccumulator *asm_acc) { GB_ASSERT(mnemonic > 0); auto forms = asm_ctx->encoding_forms(mnemonic); String name = asm_ctx->mnemonic_strings[mnemonic]; + auto alias = asm_ctx->pseudo_alias(cast(u16)pseudo_mnemonic); + if (pseudo_mnemonic) { + name = asm_ctx->pseudo_mnemonic_strings[pseudo_mnemonic]; + } + int min_count = I32_MAX; int max_count = -1; @@ -931,6 +943,14 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm min_count = gb_max(min_count, 0); max_count = gb_max(max_count, 0); + if (pseudo_mnemonic) { + int alias_count = alias.nargs; + GB_ASSERT_MSG(alias_count <= min_count, "%d <= %d", alias_count, min_count); + GB_ASSERT_MSG(alias_count <= max_count, "%d <= %d", alias_count, max_count); + min_count = gb_min(min_count, alias_count); + max_count = gb_min(max_count, alias_count); + } + // A prefix that none of this mnemonic's forms can take is unconditionally wrong, // independent of whether the operands match — catch it even on a match failure. if (previous_prefix > 0) { @@ -1862,7 +1882,19 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity previous_prefix = cast(u8)mnemonic; previous_prefix_instr = instruction_; } else if (res == CheckMnemomic_Mnemonic) { - check_mnemonic(asm_ctx, ctx, entity, instr, mnemonic, slice_from_array(operands), + check_mnemonic(asm_ctx, ctx, entity, instr, mnemonic, 0, slice_from_array(operands), + previous_prefix, previous_prefix_instr, + &asm_acc); + + asm_acc.saw_any_instructions = true; + + previous_prefix = 0; + previous_prefix_instr = nullptr; + } else if (res == CheckMnemomic_PseudoMnemonic) { + u16 pseudo_mnemonic = cast(u16)mnemonic; + auto alias = asm_ctx->pseudo_alias(cast(u16)pseudo_mnemonic); + u16 target_mnemonic = cast(u16)alias.target; + check_mnemonic(asm_ctx, ctx, entity, instr, target_mnemonic, pseudo_mnemonic, slice_from_array(operands), previous_prefix, previous_prefix_instr, &asm_acc); diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index 83f98f28f..cb58b3cfd 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -185,10 +185,6 @@ struct lbAsmGenerate { } virtual char instruction_size_suffix(AstAsmInstruction *instr) = 0; - // Some AT&T mnemonics encode BOTH operand widths and so cannot be spelled as a name plus one - // suffix: `movsx` from i8 to i32 is `movsbl`. Returns the complete mnemonic, or {} when the - // name-plus-suffix spelling is the right one - virtual String instruction_att_mnemonic(AstAsmInstruction *instr) = 0; virtual char size_suffix_for_operand(Ast *op) = 0; virtual gbString write_memory_operand(gbString asm_string, Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) = 0; virtual lbValue emit_call(lbProcedure *p, Array const &args) = 0; @@ -225,10 +221,14 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } + // Some AT&T mnemonics encode BOTH operand widths and so cannot be spelled as a name plus one + // suffix: `movsx` from i8 to i32 is `movsbl`. Returns the complete mnemonic, or {} when the + // name-plus-suffix spelling is the right one + // // The sign/zero-extend family is the only one whose two operands differ in width. Its AT&T // mnemonic names both: `movsx` i8 -> i32 is `movsbl`, never `movsx` plus a suffix. `movsxd` is // the same rule, movs + l + q - String instruction_att_mnemonic(AstAsmInstruction *instr) override { + String instruction_att_mnemonic(AstAsmInstruction *instr) { bool sign_extend; switch (instr->mnemonic) { case Asm_amd64::M_MOVSX: @@ -826,7 +826,7 @@ gb_internal lbValue lb_emit_asm_template_call(lbProcedure *p, Entity *entity, Ar if (build_context.metrics.arch == TargetArch_amd64) { generator = &generator_amd64; } else { - compiler_error("Architecture does not support asm templates"); + compiler_error("Architecture does not support asm templates, yet"); } GB_ASSERT(generator != nullptr); generator->init(entity); diff --git a/src/parser.cpp b/src/parser.cpp index f9605cd47..572c638a2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2805,8 +2805,11 @@ gb_internal Ast *parse_asm_template(AstFile *f) { asm_instructions = slice_from_array(instructions); } - if (build_context.metrics.arch != TargetArch_amd64) { - syntax_error(token, "asm templates are currently only supported on -target:amd64"); + if (build_context.metrics.arch == TargetArch_amd64 || + build_context.metrics.arch == TargetArch_riscv64) { + // okay + } else { + syntax_error(token, "asm templates are currently only supported on -target:*_amd64 or -target:*_riscv64"); } Ast *asm_template = alloc_ast_node(f, Ast_AsmTemplate); From 09204e8982e736ba111a26456a2a063f8ba2ab90 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 20 Aug 2026 19:48:30 +0100 Subject: [PATCH 07/20] Correct risc-v aliases --- src/asm_tables_amd64.cpp | 8 ++++- src/asm_tables_riscv.cpp | 6 ++-- src/check_asm.cpp | 68 +++++++++++++++++++++++++++++++++------- 3 files changed, 67 insertions(+), 15 deletions(-) diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index c83679dd5..609d87723 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -341,7 +341,13 @@ struct Asm_amd64 { } enum AliasSrc : u8 { - AliasSrc_NONE, // slot unused + AliasSrc_NONE, // slot unused + AliasSrc_ARG0, // user's 1st operand + AliasSrc_ARG1, // user's 2nd operand + AliasSrc_ARG2, // user's 3rd operand + AliasSrc_ZERO, // hardwired zero + AliasSrc_LINK, // link register + AliasSrc_LIT, }; struct PseudoAlias { diff --git a/src/asm_tables_riscv.cpp b/src/asm_tables_riscv.cpp index 323faca90..550429635 100644 --- a/src/asm_tables_riscv.cpp +++ b/src/asm_tables_riscv.cpp @@ -203,8 +203,8 @@ struct Asm_riscv { AliasSrc_ARG0, // user's 1st operand AliasSrc_ARG1, // user's 2nd operand AliasSrc_ARG2, // user's 3rd operand - AliasSrc_X0, // hardwired zero (x0) - AliasSrc_X1, // link register (ra / x1) + AliasSrc_ZERO, // hardwired zero (x0) + AliasSrc_LINK, // link register (ra / x1) AliasSrc_LIT, // the `lit` field below (immediate literal) AliasSrc_CSR_LIT, // the `csr` field below (fixed 12-bit CSR address) }; @@ -395,7 +395,7 @@ struct Asm_riscv { string_map_set(&mnemonic_map, mnemonic_strings[m], cast(Mnemonic)m); } - string_map_init(&mnemonic_map, PSEUDO_MNEMONIC_COUNT*2); + string_map_init(&pseudo_mnemonic_map, PSEUDO_MNEMONIC_COUNT*2); for (u16 m = PM_INVALID+1; m < PSEUDO_MNEMONIC_COUNT; m++) { string_map_set(&pseudo_mnemonic_map, pseudo_mnemonic_strings[m], cast(PseudoMnemonic)m); } diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 27cc5a34f..584429b9c 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -932,6 +932,30 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm name = asm_ctx->pseudo_mnemonic_strings[pseudo_mnemonic]; } + bool is_pseudo = pseudo_mnemonic != 0; + int target_explicit_count = is_pseudo ? alias.nargs : -1; + + + auto pseudo_alias_arg_operand_index = [](AsmCtx *asm_ctx, auto a, int arg_index) -> int { + if (arg_index < 0 || arg_index > 2) { + return -1; + } + auto want = cast(AsmCtx::AliasSrc)(asm_ctx->AliasSrc_ARG0 + arg_index); + for (int i = 0; i < gb_count_of(a.src); i++) { + if (a.src[i] == want) { + return i; + } + } + return -1; + }; + + auto user_operand_target_index = [&](int user_i) -> int { + if (!is_pseudo) { + return user_i; + } + return pseudo_alias_arg_operand_index(asm_ctx, alias, user_i); + }; + int min_count = I32_MAX; int max_count = -1; @@ -943,12 +967,9 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm min_count = gb_max(min_count, 0); max_count = gb_max(max_count, 0); - if (pseudo_mnemonic) { - int alias_count = alias.nargs; - GB_ASSERT_MSG(alias_count <= min_count, "%d <= %d", alias_count, min_count); - GB_ASSERT_MSG(alias_count <= max_count, "%d <= %d", alias_count, max_count); - min_count = gb_min(min_count, alias_count); - max_count = gb_min(max_count, alias_count); + if (is_pseudo) { + min_count = gb_min(min_count, target_explicit_count); + max_count = gb_min(max_count, target_explicit_count); } // A prefix that none of this mnemonic's forms can take is unconditionally wrong, @@ -988,8 +1009,15 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm for_array(form_index, forms) { auto &form = forms[form_index]; - if (operands.count != cast(int)form.explicit_count()) { - continue; + + if (is_pseudo) { + if (cast(int)form.explicit_count() < target_explicit_count) { + continue; + } + } else { + if (operands.count != cast(int)form.explicit_count()) { + continue; + } } int score = 0; @@ -1141,7 +1169,8 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm // don't tell us which physical register was written. u16 written_ops = cast(u16)clobber.written; for_array(i, operands) { - if (i >= 4 || (written_ops & (1u << i)) == 0) { + int tslot = user_operand_target_index(cast(int)i); + if (tslot < 0 || tslot >= 4 || (written_ops & (1u << tslot)) == 0) { continue; } Ast *e = operands[i].expr; @@ -1151,6 +1180,22 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm explicit_writes |= b; } } + if (is_pseudo) { + // Synthesized register sources (e.g. ra in `jal off` -> `jal ra, off`) also + // write a physical register; record them so ra is treated as produced/clobbered. + u16 synth = 0; + for (int i = 0; i < gb_count_of(alias.src); i++) { + if ((written_ops & (1u << i)) == 0) { + continue; + } + if (alias.src[i] == asm_ctx->AliasSrc_LINK) { + GB_ASSERT(build_context.metrics.arch == TargetArch_riscv64); + synth |= 1<<0; // ClobberReg_RA + } + } + produced |= synth; + explicit_writes |= synth; + } asm_acc->defined_regs |= produced; // Registers this form clobbers implicitly (RDTSC->RAX:RDX, etc.), for the @@ -1203,7 +1248,8 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm if (best_form >= 0) { auto &form = forms[best_form]; for_array(i, operands) { - int slot = asm_ctx->form_explicit_slot(form, cast(int)i); + int tei = user_operand_target_index(cast(int)i); + int slot = (tei >= 0) ? asm_ctx->form_explicit_slot(form, tei) : -1; auto type = (slot >= 0) ? form.ops[slot] : asm_ctx->OP_NONE; AsmOperandKind dst = asm_ctx->kind_from_operand_type(type); AsmOperandKind src = determine_asm_operand_kind(&operands[i]); @@ -1274,7 +1320,7 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm } else if (dst == AsmOperand_Immediate) { error(operands[i].expr, "'%.*s' operand-%td must be an assemble-time constant or a $ immediate parameter, got a %.*s", LIT(name), i, LIT(asm_operand_kind_strings[src])); - }else if (dst) { + } else if (dst) { error(operands[i].expr, "'%.*s' operand-%td has an invalid kind, expected %.*s operand", LIT(name), i, LIT(asm_operand_kind_expected_strings[dst])); } else { From de8c0dc4fe58b82ac9606cf70f28301d89cf0e4e Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 00:38:34 +0100 Subject: [PATCH 08/20] Fix register width test for risc-v, and improve operand slot type inference for risc-v --- .../riscv/tablegen/cpp-compiler/cpp-gen.odin | 10 +++-- .../x86/tablegen/cpp-compiler/cpp-gen.odin | 12 +++++- src/asm_tables_amd64.cpp | 4 ++ src/asm_tables_riscv.cpp | 4 ++ src/check_asm.cpp | 38 ++++++++++++++----- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin index 3aba6c12b..8bc1026b3 100644 --- a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin @@ -260,8 +260,8 @@ main :: proc() { AliasSrc_ARG0, // user's 1st operand AliasSrc_ARG1, // user's 2nd operand AliasSrc_ARG2, // user's 3rd operand - AliasSrc_X0, // hardwired zero (x0) - AliasSrc_X1, // link register (ra / x1) + AliasSrc_ZERO, // hardwired zero (x0) + AliasSrc_LINK, // link register (ra / x1) AliasSrc_LIT, // the `lit` field below (immediate literal) AliasSrc_CSR_LIT, // the `csr` field below (fixed 12-bit CSR address) }; @@ -425,7 +425,7 @@ main :: proc() { string_map_set(&mnemonic_map, mnemonic_strings[m], cast(Mnemonic)m); } - string_map_init(&mnemonic_map, PSEUDO_MNEMONIC_COUNT*2); + string_map_init(&pseudo_mnemonic_map, PSEUDO_MNEMONIC_COUNT*2); for (u16 m = PM_INVALID+1; m < PSEUDO_MNEMONIC_COUNT; m++) { string_map_set(&pseudo_mnemonic_map, pseudo_mnemonic_strings[m], cast(PseudoMnemonic)m); } @@ -484,6 +484,10 @@ main :: proc() { } return 0; } + + bool integer_reg_width_is_exact() const { + return false; + } """) strings.write_string(&sb, "\n\n") diff --git a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin index 56f505d4b..b665d97dd 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -341,7 +341,13 @@ main :: proc() { strings.write_string(&sb, "\n"); strings.write_string(&sb, """ enum AliasSrc : u8 { - AliasSrc_NONE, // slot unused + AliasSrc_NONE, // slot unused + AliasSrc_ARG0, // user's 1st operand + AliasSrc_ARG1, // user's 2nd operand + AliasSrc_ARG2, // user's 3rd operand + AliasSrc_ZERO, // hardwired zero + AliasSrc_LINK, // link register + AliasSrc_LIT, }; struct PseudoAlias { @@ -520,6 +526,10 @@ main :: proc() { } return 0; } + + bool integer_reg_width_is_exact() const { + return true; + } """) strings.write_string(&sb, "\n\n") diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index 609d87723..c2f013049 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -555,6 +555,10 @@ struct Asm_amd64 { return 0; } + bool integer_reg_width_is_exact() const { + return true; + } + AsmOperandKind kind_from_operand_type(OperandType type) const { switch (type) { case OP_R8: case OP_R16: case OP_R32: case OP_R64: diff --git a/src/asm_tables_riscv.cpp b/src/asm_tables_riscv.cpp index 550429635..e5045f622 100644 --- a/src/asm_tables_riscv.cpp +++ b/src/asm_tables_riscv.cpp @@ -455,6 +455,10 @@ struct Asm_riscv { return 0; } + bool integer_reg_width_is_exact() const { + return false; + } + AsmOperandKind kind_from_operand_type(OperandType type) const { switch (type) { case OP_NONE: diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 584429b9c..74c4b07bb 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -312,15 +312,21 @@ gb_internal bool check_asm_operand_size_class(AsmCtx *asm_ctx, typename AsmCtx:: // Width check. if (want_w != 0 && got_w != 0) { if (want_class == AsmRegClass_Vector && !is_memory) { - // A scalar float uses only the low lane, so it is valid in any vector - // register slot as long as it fits; a #simd vector must match exactly. bool width_ok = (got_class == AsmRegClass_Float) ? (got_w <= want_w) : (got_w == want_w); if (!width_ok) { if (mismatch_) *mismatch_ = AsmMismatch_Size; return false; } + } else if (want_class == AsmRegClass_Integer && !is_memory && + !asm_ctx->integer_reg_width_is_exact()) { + // NOTE(bill): architectures such as RISC-V have registers which are + // always the architecture width + if (got_w > want_w) { + if (mismatch_) *mismatch_ = AsmMismatch_Size; + return false; + } } else { - // Integer/mask registers, and all memory operands: exact width. + // Integer/mask registers on exact-width targets, and all memory operands. if (want_w != got_w) { if (mismatch_) *mismatch_ = AsmMismatch_Size; return false; @@ -912,8 +918,9 @@ struct AsmMnemonicAccumulator { u16 explicitly_produced_regs; u16 stale_outputs; - // #align_stack relevance: any call/branch (CONTROL) or memory effect that could - // require the stack to be realigned. If none occurred, #align_stack is redundant. + // Related to #align_stack + // any call/branch (CONTROL) or memory effect that could require the stack + // to be realigned. If none occurred, #align_stack is redundant. bool saw_call_or_mem; }; @@ -990,6 +997,20 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm } + auto operand_slot_type = [&](typename AsmCtx::Encoding const &form, int user_index) -> typename AsmCtx::OperandType { + int raw_slot = -1; + if (is_pseudo) { + raw_slot = user_operand_target_index(user_index); + } else { + raw_slot = asm_ctx->form_explicit_slot(form, user_index); + } + if (0 <= raw_slot && raw_slot < cast(int)gb_count_of(form.ops)) { + return form.ops[raw_slot]; + } + return asm_ctx->OP_NONE; + }; + + auto valid_spots = slice_make(heap_allocator(), max_count); defer (slice_free(&valid_spots, heap_allocator())); @@ -1025,8 +1046,7 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm int width_pref = 0; for_array(i, operands) { - int slot = asm_ctx->form_explicit_slot(form, cast(int)i); - auto type = (slot >= 0) ? form.ops[slot] : asm_ctx->OP_NONE; + auto type = operand_slot_type(form, cast(int)i); Operand const *operand = &operands[i]; AsmOperandKind dst = asm_ctx->kind_from_operand_type(type); AsmOperandKind src = determine_asm_operand_kind(operand); @@ -1248,9 +1268,7 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm if (best_form >= 0) { auto &form = forms[best_form]; for_array(i, operands) { - int tei = user_operand_target_index(cast(int)i); - int slot = (tei >= 0) ? asm_ctx->form_explicit_slot(form, tei) : -1; - auto type = (slot >= 0) ? form.ops[slot] : asm_ctx->OP_NONE; + auto type = operand_slot_type(form, cast(int)i); AsmOperandKind dst = asm_ctx->kind_from_operand_type(type); AsmOperandKind src = determine_asm_operand_kind(&operands[i]); possible_kinds[i] = dst; From acb6c1408f19c4ead3de07bc263a2bac6a6ca978 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 00:39:26 +0100 Subject: [PATCH 09/20] Remove unneeded `typename` usage --- src/check_asm.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 74c4b07bb..a05eeb17a 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -963,6 +963,19 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm return pseudo_alias_arg_operand_index(asm_ctx, alias, user_i); }; + auto operand_slot_type = [&](AsmCtx::Encoding const &form, int user_index) -> AsmCtx::OperandType { + int raw_slot = -1; + if (is_pseudo) { + raw_slot = user_operand_target_index(user_index); + } else { + raw_slot = asm_ctx->form_explicit_slot(form, user_index); + } + if (0 <= raw_slot && raw_slot < cast(int)gb_count_of(form.ops)) { + return form.ops[raw_slot]; + } + return asm_ctx->OP_NONE; + }; + int min_count = I32_MAX; int max_count = -1; @@ -996,21 +1009,6 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm } } - - auto operand_slot_type = [&](typename AsmCtx::Encoding const &form, int user_index) -> typename AsmCtx::OperandType { - int raw_slot = -1; - if (is_pseudo) { - raw_slot = user_operand_target_index(user_index); - } else { - raw_slot = asm_ctx->form_explicit_slot(form, user_index); - } - if (0 <= raw_slot && raw_slot < cast(int)gb_count_of(form.ops)) { - return form.ops[raw_slot]; - } - return asm_ctx->OP_NONE; - }; - - auto valid_spots = slice_make(heap_allocator(), max_count); defer (slice_free(&valid_spots, heap_allocator())); From d0fb380c2087b0d2aaa0554ed54f0c461ca92958 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 01:05:47 +0100 Subject: [PATCH 10/20] Support riscv `_aq` `_rl` `_aqrl` suffixes for mnemonics --- .../riscv/tablegen/cpp-compiler/cpp-gen.odin | 48 +++++++++++++++++++ .../x86/tablegen/cpp-compiler/cpp-gen.odin | 15 ++++++ src/asm_tables_amd64.cpp | 15 ++++++ src/asm_tables_riscv.cpp | 48 +++++++++++++++++++ src/check_asm.cpp | 18 +++++-- src/parser.hpp | 1 + 6 files changed, 142 insertions(+), 3 deletions(-) diff --git a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin index 8bc1026b3..f357e6700 100644 --- a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin @@ -437,6 +437,54 @@ main :: proc() { return true; } + + enum MnemonicSuffix : u8 { + MnemonicSuffix_None = 0, + MnemonicSuffix_AQ = 1<<0, // Acquire + MnemonicSuffix_RL = 1<<1, // Release + }; + + bool mnemonic_accepts_suffix(u16 m) const { + auto forms = encoding_forms(m); + for (auto const &form : forms) { + for (auto const &enc : form.enc) { + if (enc == ENC_AQRL) { + return true; + } + } + } + auto clobbers = clobber_forms(m); + for (auto const &c : clobbers) { + if ((cast(u16)c.side_effects & (SideEffectFlag_ATOMIC | SideEffectFlag_RESERVATION)) != 0) { + return true; + } + } + return false; + } + + Mnemonic mnemonic_lookup_ordered(String const &name, u8 *suffixes_) { + u8 suffixes = 0; + String base = {}; + if (string_ends_with(name, str_lit(\"_aqrl\"))) { + suffixes = MnemonicSuffix_AQ | MnemonicSuffix_RL; + base = substring(name, 0, name.len - 5); + } else if (string_ends_with(name, str_lit(\"_aq\"))) { + suffixes = MnemonicSuffix_AQ; + base = substring(name, 0, name.len - 3); + } else if (string_ends_with(name, str_lit(\"_rl\"))) { + suffixes = MnemonicSuffix_RL; + base = substring(name, 0, name.len - 3); + } else { + return M_INVALID; + } + Mnemonic m = mnemonic_lookup(base); + if (m == M_INVALID || !mnemonic_accepts_suffix(cast(u16)m)) { + return M_INVALID; + } + if (suffixes_) *suffixes_ = suffixes; + return m; + } + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin index b665d97dd..a6052c650 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -480,6 +480,21 @@ main :: proc() { return true; } + + enum MnemonicSuffix : u8 { + MnemonicSuffix_None = 0, + }; + + bool mnemonic_accepts_suffix(u16 m) const { + return false; + } + + Mnemonic mnemonic_lookup_ordered(String const &name, u8 *suffixes_) { + // NOTE(bill): Do any instructions need a suffix idea? + return M_INVALID; + } + + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index c2f013049..d175ec0f5 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -508,6 +508,21 @@ struct Asm_amd64 { return true; } + + enum MnemonicSuffix : u8 { + MnemonicSuffix_None = 0, + }; + + bool mnemonic_accepts_suffix(u16 m) const { + return false; + } + + Mnemonic mnemonic_lookup_ordered(String const &name, u8 *suffixes_) { + // NOTE(bill): Do any instructions need a suffix idea? + return M_INVALID; + } + + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/src/asm_tables_riscv.cpp b/src/asm_tables_riscv.cpp index e5045f622..fbafea854 100644 --- a/src/asm_tables_riscv.cpp +++ b/src/asm_tables_riscv.cpp @@ -407,6 +407,54 @@ struct Asm_riscv { return true; } + + enum MnemonicSuffix : u8 { + MnemonicSuffix_None = 0, + MnemonicSuffix_AQ = 1<<0, // Acquire + MnemonicSuffix_RL = 1<<1, // Release + }; + + bool mnemonic_accepts_suffix(u16 m) const { + auto forms = encoding_forms(m); + for (auto const &form : forms) { + for (auto const &enc : form.enc) { + if (enc == ENC_AQRL) { + return true; + } + } + } + auto clobbers = clobber_forms(m); + for (auto const &c : clobbers) { + if ((cast(u16)c.side_effects & (SideEffectFlag_ATOMIC | SideEffectFlag_RESERVATION)) != 0) { + return true; + } + } + return false; + } + + Mnemonic mnemonic_lookup_ordered(String const &name, u8 *suffixes_) { + u8 suffixes = 0; + String base = {}; + if (string_ends_with(name, str_lit("_aqrl"))) { + suffixes = MnemonicSuffix_AQ | MnemonicSuffix_RL; + base = substring(name, 0, name.len - 5); + } else if (string_ends_with(name, str_lit("_aq"))) { + suffixes = MnemonicSuffix_AQ; + base = substring(name, 0, name.len - 3); + } else if (string_ends_with(name, str_lit("_rl"))) { + suffixes = MnemonicSuffix_RL; + base = substring(name, 0, name.len - 3); + } else { + return M_INVALID; + } + Mnemonic m = mnemonic_lookup(base); + if (m == M_INVALID || !mnemonic_accepts_suffix(cast(u16)m)) { + return M_INVALID; + } + if (suffixes_) *suffixes_ = suffixes; + return m; + } + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/src/check_asm.cpp b/src/check_asm.cpp index a05eeb17a..899565876 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -855,7 +855,7 @@ enum CheckMnemomicResult { }; template -gb_internal CheckMnemomicResult check_mnemonic_name(AsmCtx *asm_ctx, AstAsmInstruction *instr, u16 *mnemonic_) { +gb_internal CheckMnemomicResult check_mnemonic_name(AsmCtx *asm_ctx, AstAsmInstruction *instr, u16 *mnemonic_, u8 *suffix_flags_) { Token token = instr->name->Ident.token; GB_ASSERT_MSG(token.kind == Token_Ident || token_is_keyword(token.kind), "got %.*s of kind %.*s", LIT(token.string), LIT(token_strings[token.kind])); String name = token.string; @@ -875,6 +875,14 @@ gb_internal CheckMnemomicResult check_mnemonic_name(AsmCtx *asm_ctx, AstAsmInstr return CheckMnemomic_PseudoMnemonic; } + u8 suffix_flags = 0; + auto om = asm_ctx->mnemonic_lookup_ordered(name, &suffix_flags); + if (om) { + if (mnemonic_) *mnemonic_ = cast(u16)om; + if (suffix_flags_) *suffix_flags_ = suffix_flags; + return CheckMnemomic_Mnemonic; + } + ERROR_BLOCK(); if (instr->operands.count == 0) { @@ -1924,8 +1932,9 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity case_ast_node(instr, AsmInstruction, instruction_); GB_ASSERT(instr->name->kind == Ast_Ident); - u16 mnemonic = 0; - CheckMnemomicResult res = check_mnemonic_name(asm_ctx, instr, &mnemonic); + u16 mnemonic = 0; + u8 suffix_flags = 0; + CheckMnemomicResult res = check_mnemonic_name(asm_ctx, instr, &mnemonic, &suffix_flags); array_clear(&operands); for (Ast *expr : instr->operands) { @@ -1944,6 +1953,7 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity previous_prefix = cast(u8)mnemonic; previous_prefix_instr = instruction_; } else if (res == CheckMnemomic_Mnemonic) { + instr->suffix_flags = suffix_flags; check_mnemonic(asm_ctx, ctx, entity, instr, mnemonic, 0, slice_from_array(operands), previous_prefix, previous_prefix_instr, &asm_acc); @@ -1953,6 +1963,8 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity previous_prefix = 0; previous_prefix_instr = nullptr; } else if (res == CheckMnemomic_PseudoMnemonic) { + instr->suffix_flags = suffix_flags; + u16 pseudo_mnemonic = cast(u16)mnemonic; auto alias = asm_ctx->pseudo_alias(cast(u16)pseudo_mnemonic); u16 target_mnemonic = cast(u16)alias.target; diff --git a/src/parser.hpp b/src/parser.hpp index 4779e09a8..efc8be219 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -507,6 +507,7 @@ struct AstSplitArgs { Ast * name; \ Slice operands; \ u16 mnemonic; \ + u8 suffix_flags; \ i32 valid_form_index; \ }) \ AST_KIND(AsmMemoryOperand, "asm memory operand", struct { \ From a604ddceb105a15cba4fbfb972b4919bee6a3848 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 11:47:41 +0100 Subject: [PATCH 11/20] Support pseudo macro mnemonics (for RISC-V) in the frontend --- .../riscv/tablegen/cpp-compiler/cpp-gen.odin | 15 +++ .../x86/tablegen/cpp-compiler/cpp-gen.odin | 8 ++ src/asm_tables_amd64.cpp | 8 ++ src/asm_tables_riscv.cpp | 15 +++ src/check_asm.cpp | 93 +++++++++++++++++++ 5 files changed, 139 insertions(+) diff --git a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin index f357e6700..73c8d6874 100644 --- a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin @@ -485,6 +485,21 @@ main :: proc() { return m; } + enum PseudoMacroMnemonic : u8 { + PseudoMacroMnemonic_INVALID, + PseudoMacroMnemonic_LI, + PseudoMacroMnemonic_LA, + PseudoMacroMnemonic_LLA, + PseudoMacroMnemonic_COUNT + }; + + PseudoMacroMnemonic pseudo_macro_mnemonic_lookup(String const &name) { + if (name == \"li\") { return PseudoMacroMnemonic_LI; } + if (name == \"la\") { return PseudoMacroMnemonic_LA; } + if (name == \"lla\") { return PseudoMacroMnemonic_LLA; } + return PseudoMacroMnemonic_INVALID; + } + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin index a6052c650..edc0ba60d 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -494,6 +494,14 @@ main :: proc() { return M_INVALID; } + enum PseudoMacroMnemonic : u8 { + PseudoMacroMnemonic_INVALID, + PseudoMacroMnemonic_COUNT + }; + + PseudoMacroMnemonic pseudo_macro_mnemonic_lookup(String const &name) { + return PseudoMacroMnemonic_INVALID; + } Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index d175ec0f5..2485a7bfc 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -522,6 +522,14 @@ struct Asm_amd64 { return M_INVALID; } + enum PseudoMacroMnemonic : u8 { + PseudoMacroMnemonic_INVALID, + PseudoMacroMnemonic_COUNT + }; + + PseudoMacroMnemonic pseudo_macro_mnemonic_lookup(String const &name) { + return PseudoMacroMnemonic_INVALID; + } Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); diff --git a/src/asm_tables_riscv.cpp b/src/asm_tables_riscv.cpp index fbafea854..b861d1389 100644 --- a/src/asm_tables_riscv.cpp +++ b/src/asm_tables_riscv.cpp @@ -455,6 +455,21 @@ struct Asm_riscv { return m; } + enum PseudoMacroMnemonic : u8 { + PseudoMacroMnemonic_INVALID, + PseudoMacroMnemonic_LI, + PseudoMacroMnemonic_LA, + PseudoMacroMnemonic_LLA, + PseudoMacroMnemonic_COUNT + }; + + PseudoMacroMnemonic pseudo_macro_mnemonic_lookup(String const &name) { + if (name == "li") { return PseudoMacroMnemonic_LI; } + if (name == "la") { return PseudoMacroMnemonic_LA; } + if (name == "lla") { return PseudoMacroMnemonic_LLA; } + return PseudoMacroMnemonic_INVALID; + } + Mnemonic mnemonic_lookup(String const &name) { Mnemonic *found = string_map_get(&mnemonic_map, name); return found ? *found : M_INVALID; diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 899565876..6aed94084 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -495,6 +495,14 @@ gb_internal AsmTemplateEntityDeclKind check_asm_find_kind(Entity *entity, Array< return AsmTemplateEntityDecl_Invalid; }; +gb_internal bool check_asm_is_immediate_param(Entity *tmpl_entity, Operand const *o) { + Entity *pe = entity_of_node(o->expr); + if (pe != nullptr && pe->kind == Entity_Variable) { + return check_asm_find_kind(pe, tmpl_entity->AsmTemplate.decls) == AsmTemplateEntityDecl_Immediate; + } + return false; +} + template gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *scope, Slice const &specs, Array *asm_template_entity_decls) { @@ -851,9 +859,81 @@ enum CheckMnemomicResult { CheckMnemomic_Invalid, CheckMnemomic_Mnemonic, CheckMnemomic_PseudoMnemonic, + CheckMnemomic_PseudoMacroMnemonic, CheckMnemomic_Prefix, }; +template +gb_internal bool check_pseudo_macro_mnemonic(AsmCtx *asm_ctx, Entity *tmpl_entity, + AstAsmInstruction *instr, Slice const &operands) { + if (build_context.metrics.arch != TargetArch_riscv64) { + return false; + } + + /* + NOTE(bill): this is probably not even a complete list when it comes to + of the pseudo macro mnemonics, but this currently covers most of them. + It just handles those edge cases directly as the LLVM assembler will + handle them directly any way. + */ + + int const XLEN = cast(int)(build_context.metrics.ptr_size*8); + + String name = instr->name->Ident.token.string; + + auto want_int_reg = [&](Operand const *o, char const *role) { + if (determine_asm_operand_kind(o) != AsmOperand_Register || + check_asm_reg_class_from_type(o->type) != AsmRegClass_Integer) { + error(o->expr, "'%.*s' %s must be an integer register", LIT(name), role); + return false; + } + int width = check_asm_operand_bit_width(o->type); + if (width > XLEN) { + error(o->expr, "'%.*s' %s is wider than the %d-bit register width, got %d-bits", LIT(name), role, XLEN, width); + return false; + } + return true; + }; + + if (name == "li") { // li rd, imm — dest reg + assemble-time integer that fits XLEN (or a $-immediate) + if (operands.count != 2) { + error(instr->name, "'%.*s' expects 2 operands, got %td", LIT(name), operands.count); + return true; // it exists but incorrectly handled + } + want_int_reg(&operands[0], "destination"); + Operand const *imm = &operands[1]; + if (imm->mode == Addressing_Constant) { + ExactValue ev = exact_value_to_integer(imm->value); + if (ev.kind != ExactValue_Integer) { + error(imm->expr, "'%.*s' immediate must be an integer constant", LIT(name)); + return true; + } + AsmMismatch m = AsmMismatch_None; i32 needed = 0; + if (!check_asm_immediate_value_fits(ev, XLEN, &needed, &m)) { + gbString vs = exact_value_to_string(ev); + error(imm->expr, "'%.*s' immediate %s does not fit in a %d-bit register (needs %d bits)", LIT(name), vs, XLEN, needed); + gb_string_free(vs); + } + } else if (!check_asm_is_immediate_param(tmpl_entity, imm)) { + error(imm->expr, "'li' source must be a constant integer or a $ immediate parameter"); + } + return true; + } else if (name == "la" || name == "lla") { // la / lla rd, symbol — dest reg + a label (or symbol, once representable) + if (operands.count != 2) { + error(instr->name, "'%.*s' expects 2 operands, got %td", LIT(name), operands.count); + // NOTE(bill): it exists but incorrectly handled + return true; + } + want_int_reg(&operands[0], "destination"); + if (determine_asm_operand_kind(&operands[1]) != AsmOperand_Label) { + error(operands[1].expr, "'%.*s' source must be a label", LIT(name)); + } + return true; + } + + return false; +} + template gb_internal CheckMnemomicResult check_mnemonic_name(AsmCtx *asm_ctx, AstAsmInstruction *instr, u16 *mnemonic_, u8 *suffix_flags_) { Token token = instr->name->Ident.token; @@ -883,6 +963,11 @@ gb_internal CheckMnemomicResult check_mnemonic_name(AsmCtx *asm_ctx, AstAsmInstr return CheckMnemomic_Mnemonic; } + auto pmm = asm_ctx->pseudo_macro_mnemonic_lookup(name); + if (pmm) { + if (mnemonic_) *mnemonic_ = cast(u16)pmm; + return CheckMnemomic_PseudoMacroMnemonic; + } ERROR_BLOCK(); if (instr->operands.count == 0) { @@ -1974,6 +2059,14 @@ gb_internal void check_asm_template(AsmCtx *asm_ctx, CheckerContext *ctx, Entity asm_acc.saw_any_instructions = true; + previous_prefix = 0; + previous_prefix_instr = nullptr; + } else if (res == CheckMnemomic_PseudoMacroMnemonic) { + instr->suffix_flags = suffix_flags; + check_pseudo_macro_mnemonic(asm_ctx, entity, instr, slice_from_array(operands)); + + asm_acc.saw_any_instructions = true; + previous_prefix = 0; previous_prefix_instr = nullptr; } else { From 4a4a5045f8d620c4fd477a2c6a0b8d39455fc7dd Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 12:19:02 +0100 Subject: [PATCH 12/20] Check for float register width exactly for risc-v frontend --- .../riscv/tablegen/cpp-compiler/cpp-gen.odin | 3 +++ .../isa/x86/tablegen/cpp-compiler/cpp-gen.odin | 3 +++ src/asm_tables_amd64.cpp | 3 +++ src/asm_tables_riscv.cpp | 3 +++ src/check_asm.cpp | 17 +++++++++++++++-- 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin index 73c8d6874..928455eba 100644 --- a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin @@ -551,6 +551,9 @@ main :: proc() { bool integer_reg_width_is_exact() const { return false; } + bool float_reg_width_is_exact() const { + return false; + } """) strings.write_string(&sb, "\n\n") diff --git a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin index edc0ba60d..002c2d1b5 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -553,6 +553,9 @@ main :: proc() { bool integer_reg_width_is_exact() const { return true; } + bool float_reg_width_is_exact() const { + return true; + } """) strings.write_string(&sb, "\n\n") diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index 2485a7bfc..ce8ce4f6c 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -581,6 +581,9 @@ struct Asm_amd64 { bool integer_reg_width_is_exact() const { return true; } + bool float_reg_width_is_exact() const { + return true; + } AsmOperandKind kind_from_operand_type(OperandType type) const { switch (type) { diff --git a/src/asm_tables_riscv.cpp b/src/asm_tables_riscv.cpp index b861d1389..3a4305d29 100644 --- a/src/asm_tables_riscv.cpp +++ b/src/asm_tables_riscv.cpp @@ -521,6 +521,9 @@ struct Asm_riscv { bool integer_reg_width_is_exact() const { return false; } + bool float_reg_width_is_exact() const { + return false; + } AsmOperandKind kind_from_operand_type(OperandType type) const { switch (type) { diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 6aed94084..a2263b6f6 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -312,11 +312,22 @@ gb_internal bool check_asm_operand_size_class(AsmCtx *asm_ctx, typename AsmCtx:: // Width check. if (want_w != 0 && got_w != 0) { if (want_class == AsmRegClass_Vector && !is_memory) { + // A scalar float uses only the low lane, so it may be narrower than the + // slot; a #simd vector must match the vector width exactly. bool width_ok = (got_class == AsmRegClass_Float) ? (got_w <= want_w) : (got_w == want_w); if (!width_ok) { if (mismatch_) *mismatch_ = AsmMismatch_Size; return false; } + } else if (want_class == AsmRegClass_Float && + got_class == AsmRegClass_Float && !is_memory && + !asm_ctx->float_reg_width_is_exact()) { + // NOTE(bill): architectures such as RISC-V have registers which are + // always the architecture width + if (got_w > want_w) { + if (mismatch_) *mismatch_ = AsmMismatch_Size; + return false; + } } else if (want_class == AsmRegClass_Integer && !is_memory && !asm_ctx->integer_reg_width_is_exact()) { // NOTE(bill): architectures such as RISC-V have registers which are @@ -1419,8 +1430,10 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm error(operands[i].expr, "'%.*s' operand-%td: a floating-point constant cannot be used as an immediate", LIT(name), i); } else if (m == AsmMismatch_Size && want_bits[i] && got_bits[i]) { - error(operands[i].expr, "'%.*s' operand-%td has the wrong size: expected a %u-bit operand, got %u-bit", - LIT(name), i, cast(unsigned)want_bits[i], cast(unsigned)got_bits[i]); + error(operands[i].expr, "'%.*s' operand-%td has the wrong size: expected a %u-bit %.*s operand, got %u-bit", + LIT(name), i, + cast(unsigned)want_bits[i], LIT(asm_reg_class_strings[dst_reg_class]), + cast(unsigned)got_bits[i]); } else if (m == AsmMismatch_Class) { error(operands[i].expr, "'%.*s' operand-%td is in the wrong register class, expected %d-bit %.*s %.*s, got %d-bit %.*s %.*s", LIT(name), i, From 648c418fc463362f2178b67eda3de1f8b7f863b4 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 14:31:58 +0100 Subject: [PATCH 13/20] Restrict riscv to only allow `[base + disp]` (i.e. disallow `index*scale` style things) --- .../riscv/tablegen/cpp-compiler/cpp-gen.odin | 3 + .../x86/tablegen/cpp-compiler/cpp-gen.odin | 3 + src/asm_tables_amd64.cpp | 3 + src/asm_tables_riscv.cpp | 3 + src/check_asm.cpp | 11 + src/llvm_backend_asm.cpp | 484 +++++++++++++++++- 6 files changed, 505 insertions(+), 2 deletions(-) diff --git a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin index 928455eba..dfe6caca3 100644 --- a/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/riscv/tablegen/cpp-compiler/cpp-gen.odin @@ -554,6 +554,9 @@ main :: proc() { bool float_reg_width_is_exact() const { return false; } + bool supports_memory_index_not_just_disp() const { + return false; + } """) strings.write_string(&sb, "\n\n") diff --git a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin index 002c2d1b5..554b9b6bb 100644 --- a/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin +++ b/core/rexcode/isa/x86/tablegen/cpp-compiler/cpp-gen.odin @@ -556,6 +556,9 @@ main :: proc() { bool float_reg_width_is_exact() const { return true; } + bool supports_memory_index_not_just_disp() const { + return true; + } """) strings.write_string(&sb, "\n\n") diff --git a/src/asm_tables_amd64.cpp b/src/asm_tables_amd64.cpp index ce8ce4f6c..dab07eec7 100644 --- a/src/asm_tables_amd64.cpp +++ b/src/asm_tables_amd64.cpp @@ -584,6 +584,9 @@ struct Asm_amd64 { bool float_reg_width_is_exact() const { return true; } + bool supports_memory_index_not_just_disp() const { + return true; + } AsmOperandKind kind_from_operand_type(OperandType type) const { switch (type) { diff --git a/src/asm_tables_riscv.cpp b/src/asm_tables_riscv.cpp index 3a4305d29..02deec215 100644 --- a/src/asm_tables_riscv.cpp +++ b/src/asm_tables_riscv.cpp @@ -524,6 +524,9 @@ struct Asm_riscv { bool float_reg_width_is_exact() const { return false; } + bool supports_memory_index_not_just_disp() const { + return false; + } AsmOperandKind kind_from_operand_type(OperandType type) const { switch (type) { diff --git a/src/check_asm.cpp b/src/check_asm.cpp index a2263b6f6..0429ed80d 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -1786,6 +1786,17 @@ gb_internal void check_asm_instruction_operand(AsmCtx *asm_ctx, CheckerContext * gb_string_free(s); } + if (index.expr != nullptr) { + if (!asm_ctx->supports_memory_index_not_just_disp()) { + error(index.expr, "The target platform does not support memory indexing within memory operands, only displacements"); + } + } + if (scale.expr != nullptr) { + if (!asm_ctx->supports_memory_index_not_just_disp()) { + error(scale.expr, "The target platform does not support memory index scaling within memory operands"); + } + } + if (mem_op->type) { Type *t = check_type(ctx, mem_op->type); if (t != nullptr && t != t_invalid) { diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index cb58b3cfd..e23e0530e 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -819,16 +819,496 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } }; +struct lbAsmGenerate_riscv64 : lbAsmGenerate { + // RISC-V has no AT&T-style operand-size suffixes; precision lives in the mnemonic + // (flw vs fld, .s vs .d), so nothing here ever contributes a b/w/l/q suffix. + char size_suffix_for_operand(Ast *op) override { + return 0; + } + char instruction_size_suffix(AstAsmInstruction *instr) override { + return 0; + } + + // RISC-V has no architectural condition-flags register, so no output can be pinned + // to a flag / lowered to `=@cc`. + String flag_output_cc_suffix(String const &pin_flag) override { + return {}; + } + + // LLVM inline-asm constraint class letters for RISC-V. + char const *class_letter(AsmRegClass rc) { + switch (rc) { + case AsmRegClass_Integer: return "r"; // GPR (x-registers) + case AsmRegClass_Float: return "f"; // FPR (single/double share the FLEN file) + case AsmRegClass_Vector: return "vr"; // RVV vector register (V extension) + case AsmRegClass_Mask: return "vm"; // RVV mask register (v0) + default: + GB_PANIC("asm: unknown reg class"); + return "r"; + } + } + + // RISC-V immediates are bare integers (no '$' prefix). + gbString write_constant_operand(gbString asm_string, Ast *op, u32 flags) { + GB_ASSERT(op->tav.mode == Addressing_Constant); + op->tav.value = exact_value_to_integer(op->tav.value); + ExactValue ev = op->tav.value; + GB_ASSERT(ev.kind != ExactValue_Invalid); + switch (ev.kind) { + case ExactValue_Integer: { + GB_ASSERT((flags & (WriteOperandFlag_IsScale|WriteOperandFlag_IsScaleLog2)) == 0); + i64 val = exact_value_to_i64(ev); + if (flags & WriteOperandFlag_Negate) { + val = -val; + } + asm_string = gb_string_append_fmt(asm_string, "%lld", cast(long long)val); + break; + } + case ExactValue_Float: + error(op, "Floating-point literals that cannot be represented as an integer are not supported within asm operands"); + break; + default: + GB_PANIC("Unsupported asm immediate literal %s", expr_to_string(op)); + break; + } + return asm_string; + } + + // RISC-V operand syntax: bare registers (no '%'), bare immediates (no '$$'), and + // no x86 sub-register width modifiers. + gbString write_operand(gbString asm_string, Slice const &op_number, Ast *op, u32 flags) { + if (op->tav.mode == Addressing_Constant) { + return this->write_constant_operand(asm_string, op, flags); + } + + if (flags & WriteOperandFlag_Negate) { + flags &= ~WriteOperandFlag_Negate; + asm_string = gb_string_appendc(asm_string, "-"); + } + + switch (op->kind) { + case_ast_node(i, Ident, op); + Entity *e = entity_of_node(op); + auto *ed = entity_op(e); + // A width-view resolves to its source's operand. RISC-V x-registers are + // always XLEN-wide with no named sub-registers, so a view is simply the + // same register: emit the source operand number, no width modifier. + i32 idx = (ed->view_of >= 0) ? op_number[ed->view_of] : op_number[ed->total_index]; + GB_ASSERT(idx >= 0); + asm_string = gb_string_append_fmt(asm_string, "$%d", idx); + case_end; + case_ast_node(mem_op, AsmMemoryOperand, op); + asm_string = this->write_memory_operand(asm_string, op_number, mem_op, flags&~WriteOperandFlag_PrintPrefixes); + case_end; + case_ast_node(bl, BasicLit, op); + GB_PANIC("NOTE(bill): this should have been handled above"); + case_end; + case_ast_node(label, AsmLabelDecl, op); + asm_string = write_label(asm_string, &label->name->Ident); + case_end; + case_ast_node(reg, AsmRegister, op); + // RISC-V names registers bare (zero, a0, fa0); no '%' prefix. + asm_string = gb_string_append_length(asm_string, reg->name.string.text, reg->name.string.len); + case_end; + default: + GB_PANIC("TODO(bill): write_operand for '%s'", expr_to_string(op)); + break; + } + return asm_string; + } + + // RISC-V addressing is `offset(base)`: a signed 12-bit displacement plus one base + // register. No index register, scale factor, or segment override exists. + gbString write_memory_operand(gbString asm_string, Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) override { + GB_ASSERT_MSG(mem_op->segment_override == nullptr, "asm: RISC-V has no segment overrides"); + GB_ASSERT_MSG(mem_op->index == nullptr && mem_op->scale == nullptr, "asm: RISC-V memory operands have no index/scale"); + + if (mem_op->disp) { + u32 disp_flags = flags & ~WriteOperandFlag_PrintPrefixes; + if (mem_op->disp_op.kind == Token_Sub) { + disp_flags |= WriteOperandFlag_Negate; + } + asm_string = this->write_operand(asm_string, op_number, mem_op->disp, disp_flags); + } + asm_string = gb_string_appendc(asm_string, "("); + if (mem_op->base != nullptr) { + asm_string = this->write_operand(asm_string, op_number, mem_op->base, flags&~WriteOperandFlag_PrintPrefixes); + } + asm_string = gb_string_appendc(asm_string, ")"); + return asm_string; + } + + // RISC-V mnemonics are spelled with '.' (fmadd.s, fmv.w.x, lr.w). Odin identifiers + // cannot contain '.', so they are written with '_' and translated back here. No + // real RISC-V mnemonic contains an underscore, so this mapping is unambiguous. + gbString append_riscv_mnemonic(gbString s, String name) { + for (isize i = 0; i < name.len; i++) { + char c = cast(char)name.text[i]; + if (c == '_') { + c = '.'; + } + s = gb_string_append_length(s, &c, 1); + } + return s; + } + + lbValue emit_call(lbProcedure *p, Array const &args) override { + lbModule *m = p->module; + LLVMContextRef ctx = m->ctx; + + gbString asm_string = gb_string_make_reserve(heap_allocator(), 256); + gbString constraints = gb_string_make_reserve(heap_allocator(), 64); + defer ({ + gb_string_free(constraints); + gb_string_free(asm_string); + }); + + TEMPORARY_ALLOCATOR_GUARD(); + + auto param_types = array_make (temporary_allocator(), 0, ops->count); + auto call_args = array_make(temporary_allocator(), 0, ops->count); + auto ret_types = array_make (temporary_allocator(), 0, ops->count); + + auto op_number = slice_make(temporary_allocator(), ops->count); // $N, or -1 for clobbers/views + auto ret_slot = slice_make(temporary_allocator(), ops->count); // return-struct index, or -1 + for_array(i, *ops) { + op_number[i] = -1; + ret_slot [i] = -1; + } + + struct ElemAttr { + unsigned arg_pos; + LLVMTypeRef elem; + }; + auto elem_attrs = array_make(temporary_allocator(), 0, ops->count); + + auto sep = [&]() { + if (gb_string_length(constraints) != 0) { + constraints = gb_string_appendc(constraints, ","); + } + }; + auto raw = [&](char const *s) { + constraints = gb_string_appendc(constraints, s); + }; + auto clobber = [&](char const *start, String mid, char const *end) { + constraints = gb_string_appendc(constraints, start); + constraints = gb_string_append_length(constraints, mid.text, mid.len); + constraints = gb_string_appendc(constraints, end); + }; + + auto add_input_value = [](Array *param_types, Array *call_args, LLVMValueRef v) { + array_add(param_types, LLVMTypeOf(v)); + array_add(call_args, v); + }; + + i32 next_op = 0; // running $N counter (outputs first, then inputs) + + // Pass 1: outputs (real outputs + unpinned register scratch modeled as + // discarded early-clobber outputs). + for_array(i, *ops) { + AsmTemplateEntityDecl const &e = (*ops)[i]; + + if (e.view_of >= 0) { + continue; // width-view: resolved to its source's operand, owns no slot + } + + // A flag output cannot occur on RISC-V (no condition-flags register), but + // keep the branch for structural parity; flag_output_cc_suffix returns {} + // so it is never actually taken. + if (e.param_group == AsmTemplateEntityDeclParamGroup_Output && e.pin_flag.len != 0) { + GB_ASSERT_MSG(false, "asm: RISC-V has no flag outputs"); + } + + bool is_output = e.param_group == AsmTemplateEntityDeclParamGroup_Output; + bool is_alloc_scratch = e.param_group == AsmTemplateEntityDeclParamGroup_Scratch + && e.kind == AsmTemplateEntityDecl_Register; + if (!is_output && !is_alloc_scratch) { + continue; + } + + sep(); + + raw("="); + if (is_alloc_scratch || tmpl_node->instructions.count > 1) { + raw("&"); + } + if (e.pin.len != 0) { + clobber("{", e.pin, "}"); + } else { + raw(this->class_letter(e.reg_class)); + } + + LLVMTypeRef ty = is_alloc_scratch ? lb_type(m, e.entity->type) : this->output_llvm_type(m, e); + + ret_slot[i] = cast(i32)ret_types.count; + array_add(&ret_types, ty); + op_number[i] = next_op++; + } + + // Pass 2: inputs + for_array(i, *ops) { + AsmTemplateEntityDecl const &e = (*ops)[i]; + + if (e.view_of >= 0) { + continue; // width-view: not its own input + } + if (e.param_group != AsmTemplateEntityDeclParamGroup_Input) { + continue; + } + + sep(); + lbValue v = args[e.param_index]; + + if (e.tie >= 0) { + i32 n = op_number[e.tie]; + GB_ASSERT(n >= 0); + constraints = gb_string_append_fmt(constraints, "%d", n); + add_input_value(¶m_types, &call_args, v.value); + } else { + switch (e.kind) { + case AsmTemplateEntityDecl_Register: + case AsmTemplateEntityDecl_Memory: + if (e.pin.len != 0) { + clobber("{", e.pin, "}"); + } else { + raw(this->class_letter(e.reg_class)); + } + add_input_value(¶m_types, &call_args, v.value); + break; + case AsmTemplateEntityDecl_Immediate: + raw("i"); + add_input_value(¶m_types, &call_args, v.value); + break; + default: + GB_PANIC("asm: invalid input operand kind"); + } + } + op_number[i] = next_op++; + } + + // Build the template text + for_array(i, tmpl_node->instructions) { + if (i > 0) { + asm_string = gb_string_appendc(asm_string, "\n"); + } + Ast *instr_ = tmpl_node->instructions[i]; + switch (instr_->kind) { + case_ast_node(instr, AsmInstruction, instr_); + asm_string = gb_string_appendc(asm_string, "\t"); + String name = instr->name->Ident.token.string; + asm_string = this->append_riscv_mnemonic(asm_string, name); + + asm_string = gb_string_appendc(asm_string, " "); + // RISC-V is destination-first natively; emit operands in written order. + for (isize j = 0; j < instr->operands.count; j += 1) { + Ast *op = instr->operands[j]; + if (j > 0) { + asm_string = gb_string_appendc(asm_string, ", "); + } + asm_string = this->write_operand(asm_string, op_number, op, WriteOperandFlag_NONE); + } + case_end; + case_ast_node(label, AsmLabelDecl, instr_); + asm_string = this->write_label(asm_string, &label->name->Ident); + asm_string = gb_string_appendc(asm_string, ":"); + case_end; + case_ast_node(dir, AsmDirective, instr_); + String name = dir->name.string; + if (name == "byte") { + asm_string = gb_string_appendc(asm_string, ".byte "); + isize op_index = 0; + for (auto const &op : dir->operands) { + if (op_index > 0) { + asm_string = gb_string_appendc(asm_string, ", "); + } + ExactValue ev = exact_value_to_integer(op->tav.value); + GB_ASSERT(ev.kind == ExactValue_Integer); + i64 v = exact_value_to_i64(ev); + asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)v); + op_index += 1; + } + } else if (name == "align") { + GB_ASSERT(dir->operands.count == 1); + auto const &op = dir->operands[0]; + ExactValue ev = exact_value_to_integer(op->tav.value); + GB_ASSERT(ev.kind == ExactValue_Integer); + u64 v = exact_value_to_u64(ev); + u64 v_log2 = floor_log2(v); + asm_string = gb_string_append_fmt(asm_string, ".p2align %llu", cast(unsigned long long)v_log2); + } else if (name == "skip") { + GB_ASSERT(dir->operands.count == 1); + auto const &op = dir->operands[0]; + ExactValue ev = exact_value_to_integer(op->tav.value); + GB_ASSERT(ev.kind == ExactValue_Integer); + u64 v = exact_value_to_u64(ev); + asm_string = gb_string_append_fmt(asm_string, ".skip %llu", cast(unsigned long long)v); + } else if (name == "nop") { + GB_ASSERT(dir->operands.count == 1); + auto const &op = dir->operands[0]; + ExactValue ev = exact_value_to_integer(op->tav.value); + GB_ASSERT(ev.kind == ExactValue_Integer); + u64 v = exact_value_to_u64(ev); + asm_string = gb_string_append_fmt(asm_string, ".nops %llu", cast(unsigned long long)v); + } else { + GB_PANIC("Invalid asm directive: %.*s", LIT(name)); + } + case_end; + default: + GB_PANIC("Invalid asm instruction"); + break; + } + } + + bool memory_clobbered_already = false; + // Pass 3: clobbers (Scratch group only; unpinned register scratch already + // emitted as an output in Pass 1). + StringSet emitted_reg_clobbers = {}; + string_set_init(&emitted_reg_clobbers); + defer (string_set_destroy(&emitted_reg_clobbers)); + + for_array(i, *ops) { + AsmTemplateEntityDecl const &e = (*ops)[i]; + + if (e.view_of >= 0) { + continue; // width-view carries no clobber; its source owns the register + } + if (e.param_group != AsmTemplateEntityDeclParamGroup_Scratch) { + continue; + } + if (e.kind == AsmTemplateEntityDecl_Register && e.pin.len == 0) { + continue; + } + + sep(); + switch (e.kind) { + case AsmTemplateEntityDecl_Register: + GB_ASSERT(e.pin.len != 0); + clobber("~{", e.pin, "}"); + string_set_update(&emitted_reg_clobbers, e.pin); + break; + case AsmTemplateEntityDecl_Memory: + raw("~{memory}"); + memory_clobbered_already = true; + break; + default: + GB_PANIC("asm: invalid scratch operand kind"); + } + } + + for (String const ® : tmpl_entity->AsmTemplate.clobber_registers_set) { + if (string_set_exists(&emitted_reg_clobbers, reg)) { + continue; + } + sep(); + clobber("~{", reg, "}"); + string_set_update(&emitted_reg_clobbers, reg); + } + + // RISC-V has no condition-flags/cc register, so #clobber flags maps to nothing. + // (clobber_flags being set here is effectively a no-op.) + + if (tmpl_entity->AsmTemplate.clobber_memory && !memory_clobbered_already) { + sep(); + raw("~{memory}"); + } + + // Build the callee type + LLVMTypeRef ret_ty = nullptr; + if (ret_types.count == 0) { + ret_ty = LLVMVoidTypeInContext(ctx); + } else if (ret_types.count == 1) { + ret_ty = ret_types[0]; + } else { + ret_ty = LLVMStructTypeInContext(ctx, ret_types.data, cast(unsigned)ret_types.count, /*packed*/false); + } + + LLVMTypeRef fn_ty = LLVMFunctionType(ret_ty, param_types.data, cast(unsigned)param_types.count, /*vararg*/false); + + LLVMValueRef ia = LLVMGetInlineAsm( + fn_ty, + asm_string, cast(size_t)gb_string_length(asm_string), + constraints, cast(size_t)gb_string_length(constraints), + /*HasSideEffects*/ tmpl_entity->AsmTemplate.is_volatile, + /*IsAlignStack*/ tmpl_entity->AsmTemplate.is_align_stack, + LLVMInlineAsmDialectATT, + /*CanThrow*/ false); + + LLVMValueRef call = LLVMBuildCall2(p->builder, fn_ty, ia, call_args.data, cast(unsigned)call_args.count, ""); + + if (LLVM_ASM_DEBUG_PRINT) { + gb_printf_err("%s\n", asm_string); + char *ir = LLVMPrintValueToString(call); + gb_printf_err("%s\n\n", ir); + LLVMDisposeMessage(ir); + } + + unsigned et_kind = LLVMGetEnumAttributeKindForName("elementtype", 11); + for (auto const &elem_attr : elem_attrs) { + LLVMAttributeRef attr = LLVMCreateTypeAttribute(ctx, et_kind, elem_attr.elem); + LLVMAddCallSiteAttribute(call, cast(LLVMAttributeIndex)(elem_attr.arg_pos + 1), attr); + } + + // Repackage results in Odin result order + Type *pt = base_type(tmpl_entity->type); + isize result_count = 0; + if (pt->Proc.results != nullptr) { + result_count = pt->Proc.results->Tuple.variables.count; + } + if (result_count == 0) { + return lbValue{}; + } + + auto result_vals = slice_make(temporary_allocator(), result_count); + + for_array(i, *ops) { + AsmTemplateEntityDecl const &e = (*ops)[i]; + if (e.view_of >= 0) { + continue; + } + if (e.param_group != AsmTemplateEntityDeclParamGroup_Output) { + continue; + } + if (e.result_index < 0) { + continue; // memory output: not a returned value + } + GB_ASSERT(ret_slot[i] >= 0); + + LLVMValueRef v = call; + if (ret_types.count != 1) { + v = LLVMBuildExtractValue(p->builder, call, cast(unsigned)ret_slot[i], ""); + } + result_vals[e.result_index] = v; + } + + if (result_count == 1) { + Type *rt = pt->Proc.results->Tuple.variables[0]->type; + return lbValue{result_vals[0], rt}; + } + + Type *results_type = pt->Proc.results; + LLVMValueRef agg = LLVMGetUndef(lb_type(m, results_type)); + for_array(i, result_vals) { + GB_ASSERT(result_vals[i] != nullptr); + agg = LLVMBuildInsertValue(p->builder, agg, result_vals[i], cast(unsigned)i, ""); + } + + return lbValue{agg, results_type}; + } +}; + gb_internal lbValue lb_emit_asm_template_call(lbProcedure *p, Entity *entity, Array const &args) { - lbAsmGenerate_amd64 generator_amd64 = {}; + lbAsmGenerate_amd64 generator_amd64 = {}; + lbAsmGenerate_riscv64 generator_riscv64 = {}; lbAsmGenerate *generator = nullptr; if (build_context.metrics.arch == TargetArch_amd64) { generator = &generator_amd64; + } else if (build_context.metrics.arch == TargetArch_riscv64) { + generator = &generator_riscv64; } else { compiler_error("Architecture does not support asm templates, yet"); } GB_ASSERT(generator != nullptr); generator->init(entity); return generator->emit_call(p, args); -} +} \ No newline at end of file From 0e101db3a4b2262d82a195181b59c2ee279ce243 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 15:00:21 +0100 Subject: [PATCH 14/20] Clean up llvm_backend_asm.cpp to reuse some of the same printing code --- src/llvm_backend_asm.cpp | 312 +++++++++++++++++++-------------------- 1 file changed, 152 insertions(+), 160 deletions(-) diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index e23e0530e..fafd84d1c 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -5,6 +5,14 @@ struct lbAsmGenerate { AstAsmTemplate * tmpl_node; Array *ops; + gbString asm_string; + gbString constraints; + + struct ElemAttr { + unsigned arg_pos; + LLVMTypeRef elem; + }; + enum WriteOperandFlags : u32 { WriteOperandFlag_PrintPrefixes = 1<<0, WriteOperandFlag_IsScale = 1<<1, @@ -24,18 +32,45 @@ struct lbAsmGenerate { this->ops = &this->tmpl_entity->AsmTemplate.decls; GB_ASSERT(this->tmpl_entity->AsmTemplate.node->kind == Ast_AsmTemplate); this->tmpl_node = &this->tmpl_entity->AsmTemplate.node->AsmTemplate; + + this->asm_string = gb_string_make_reserve(heap_allocator(), 256); + this->constraints = gb_string_make_reserve(heap_allocator(), 64); } - gbString write_label(gbString asm_string, AstIdent *label_ident) { + void destroy() { + gb_string_free(this->asm_string); + gb_string_free(this->constraints); + } + + void write_cstr(char const *cstr) { + asm_string = gb_string_appendc(asm_string, cstr); + } + void write_char(char c) { + asm_string = gb_string_append_length(asm_string, &c, 1); + } + void write_string(String str) { + asm_string = gb_string_append_length(asm_string, str.text, str.len); + } + void write_int(int val) { + asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)val); + } + void write_u64(u64 val) { + asm_string = gb_string_append_fmt(asm_string, "%llu", cast(unsigned long long)val); + } + void write_i64(i64 val) { + asm_string = gb_string_append_fmt(asm_string, "%lld", cast(long long)val); + } + + + void write_label(AstIdent *label_ident) { String name = label_ident->token.string; - asm_string = gb_string_appendc(asm_string, ".L_"); - asm_string = gb_string_append_length(asm_string, tmpl_entity->token.string.text, tmpl_entity->token.string.len); - asm_string = gb_string_appendc(asm_string, "_"); - asm_string = gb_string_append_length(asm_string, name.text, name.len); + write_cstr(".L_"); + write_string(tmpl_entity->token.string); + write_cstr("_"); + write_string(name); // ${:uid} expands to a per-instantiation unique integer, so repeated // inlining of the same template can't collide on the label symbol. - asm_string = gb_string_appendc(asm_string, "${:uid}"); - return asm_string; + write_cstr("${:uid}"); } AsmTemplateEntityDecl *entity_op(Entity *parameter) { @@ -48,7 +83,7 @@ struct lbAsmGenerate { return nullptr; } - gbString write_constant_operand(gbString asm_string, Ast *op, u32 flags) { + void write_constant_operand(Ast *op, u32 flags) { GB_ASSERT(op->tav.mode == Addressing_Constant); op->tav.value = exact_value_to_integer(op->tav.value); @@ -79,14 +114,14 @@ struct lbAsmGenerate { } if (flags & WriteOperandFlag_PrintPrefixes) { - asm_string = gb_string_appendc(asm_string, "$$"); + write_cstr("$$"); } if (flags & WriteOperandFlag_Negate) { val = -val; } - asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)val); + write_int(cast(int)val); break; } case ExactValue_Float: @@ -96,19 +131,18 @@ struct lbAsmGenerate { GB_PANIC("Unsupported asm immediate literal %s", expr_to_string(op)); break; } - - return asm_string; } - gbString write_operand(gbString asm_string, Slice const &op_number, Ast *op, u32 flags) { + void write_operand(Slice const &op_number, Ast *op, u32 flags) { if (op->tav.mode == Addressing_Constant) { - return write_constant_operand(asm_string, op, flags); + this->write_constant_operand(op, flags); + return; } if (flags & WriteOperandFlag_Negate) { flags &= ~WriteOperandFlag_Negate; - asm_string = gb_string_appendc(asm_string, "-"); + write_cstr("-"); } switch (op->kind) { @@ -138,7 +172,7 @@ struct lbAsmGenerate { } case_end; case_ast_node(mem_op, AsmMemoryOperand, op); - asm_string = this->write_memory_operand(asm_string, op_number, mem_op, flags&~WriteOperandFlag_PrintPrefixes); + this->write_memory_operand(op_number, mem_op, flags&~WriteOperandFlag_PrintPrefixes); case_end; case_ast_node(bl, BasicLit, op); @@ -146,18 +180,18 @@ struct lbAsmGenerate { case_end; case_ast_node(label, AsmLabelDecl, op); - asm_string = write_label(asm_string, &label->name->Ident); + this->write_label(&label->name->Ident); case_end; case_ast_node(reg, AsmRegister, op); - asm_string = gb_string_appendc(asm_string, "%"); - asm_string = gb_string_append_length(asm_string, reg->name.string.text, reg->name.string.len); + write_cstr("%"); + write_string(reg->name.string); case_end; default: GB_PANIC("TODO(bill): write_operand for '%s'", expr_to_string(op)); break; } - return asm_string; + return; } char const *class_letter(AsmRegClass rc) { @@ -184,11 +218,29 @@ struct lbAsmGenerate { return pt->Proc.results->Tuple.variables[e.result_index]->type; } - virtual char instruction_size_suffix(AstAsmInstruction *instr) = 0; - virtual char size_suffix_for_operand(Ast *op) = 0; - virtual gbString write_memory_operand(gbString asm_string, Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) = 0; - virtual lbValue emit_call(lbProcedure *p, Array const &args) = 0; - virtual String flag_output_cc_suffix(String const &pin_flag) = 0; + void sep() { + if (gb_string_length(this->constraints) != 0) { + this->constraints = gb_string_appendc(this->constraints, ","); + } + } + void raw(char const *s) { + this->constraints = gb_string_appendc(this->constraints, s); + } + void clobber(char const *start, String mid, char const *end) { + this->constraints = gb_string_appendc (this->constraints, start); + this->constraints = gb_string_append_length(this->constraints, mid.text, mid.len); + this->constraints = gb_string_appendc (this->constraints, end); + } + void add_input_value(Array *param_types, Array *call_args, LLVMValueRef v) { + array_add(param_types, LLVMTypeOf(v)); + array_add(call_args, v); + } + + virtual char instruction_size_suffix(AstAsmInstruction *instr) = 0; + virtual char size_suffix_for_operand(Ast *op) = 0; + virtual void write_memory_operand(Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) = 0; + virtual lbValue emit_call(lbProcedure *p, Array const &args) = 0; + virtual String flag_output_cc_suffix(String const &pin_flag) = 0; }; @@ -341,10 +393,10 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } - gbString write_memory_operand(gbString asm_string, Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) override { + void write_memory_operand(Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) override { if (mem_op->segment_override != nullptr) { - asm_string = this->write_operand(asm_string, op_number, mem_op->segment_override, flags); - asm_string = gb_string_appendc(asm_string, ":"); + this->write_operand(op_number, mem_op->segment_override, flags); + write_cstr(":"); } if (mem_op->disp) { @@ -354,51 +406,47 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { disp_flags |= WriteOperandFlag_Negate; } - asm_string = this->write_operand(asm_string, op_number, mem_op->disp, disp_flags); + this->write_operand(op_number, mem_op->disp, disp_flags); } if (mem_op->base == nullptr && mem_op->index == nullptr) { GB_ASSERT(mem_op->scale == nullptr); - return asm_string; + return; } - asm_string = gb_string_appendc(asm_string, "("); + write_cstr("("); if (mem_op->base != nullptr) { - asm_string = this->write_operand(asm_string, op_number, mem_op->base, flags); + this->write_operand(op_number, mem_op->base, flags); } if (mem_op->index) { u32 index_flags = flags; if (mem_op->index_op.kind == Token_Sub) { index_flags |= WriteOperandFlag_Negate; } - asm_string = gb_string_appendc(asm_string, ","); - asm_string = this->write_operand(asm_string, op_number, mem_op->index, index_flags); + write_cstr(","); + this->write_operand(op_number, mem_op->index, index_flags); if (mem_op->scale) { - asm_string = gb_string_appendc(asm_string, ","); + write_cstr(","); switch (mem_op->scale_op.kind) { case Token_Mul: - asm_string = this->write_operand(asm_string, op_number, mem_op->scale, (flags|WriteOperandFlag_IsScale)&~WriteOperandFlag_PrintPrefixes); + this->write_operand(op_number, mem_op->scale, (flags|WriteOperandFlag_IsScale)&~WriteOperandFlag_PrintPrefixes); break; case Token_Shl: case Token_Shr: - asm_string = this->write_operand(asm_string, op_number, mem_op->scale, (flags|WriteOperandFlag_IsScaleLog2)&~WriteOperandFlag_PrintPrefixes); + this->write_operand(op_number, mem_op->scale, (flags|WriteOperandFlag_IsScaleLog2)&~WriteOperandFlag_PrintPrefixes); break; } } } - asm_string = gb_string_appendc(asm_string, ")"); - return asm_string; + write_cstr(")"); + return; } lbValue emit_call(lbProcedure *p, Array const &args) override { lbModule *m = p->module; LLVMContextRef ctx = m->ctx; - gbString asm_string = gb_string_make_reserve(heap_allocator(), 256); - gbString constraints = gb_string_make_reserve(heap_allocator(), 64); - defer ({ - gb_string_free(constraints); - gb_string_free(asm_string); - }); + gb_string_clear(this->asm_string); + gb_string_clear(this->constraints); TEMPORARY_ALLOCATOR_GUARD(); @@ -415,33 +463,8 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } // elementtype() attrs to attach after the call is built (indirect/memory operands). - struct ElemAttr { - unsigned arg_pos; - LLVMTypeRef elem; - }; auto elem_attrs = array_make(temporary_allocator(), 0, ops->count); - - auto sep = [&]() { - if (gb_string_length(constraints) != 0) { - constraints = gb_string_appendc(constraints, ","); - } - }; - auto raw = [&](char const *s) { - constraints = gb_string_appendc(constraints, s); - }; - auto clobber = [&](char const *start, String mid, char const *end) { - constraints = gb_string_appendc(constraints, start); - constraints = gb_string_append_length(constraints, mid.text, mid.len); - constraints = gb_string_appendc(constraints, end); - }; - - auto add_input_value = [](Array *param_types, Array *call_args, LLVMValueRef v) { - array_add(param_types, LLVMTypeOf(v)); - array_add(call_args, v); - }; - - i32 next_op = 0; // running $N counter (outputs first, then inputs) // Pass 1: outputs @@ -551,18 +574,18 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { // Build the template text for_array(i, tmpl_node->instructions) { if (i > 0) { - asm_string = gb_string_appendc(asm_string, "\n"); + write_cstr("\n"); } Ast *instr_ = tmpl_node->instructions[i]; switch (instr_->kind) { case_ast_node(instr, AsmInstruction, instr_); - asm_string = gb_string_appendc(asm_string, "\t"); + write_cstr("\t"); String name = instr->name->Ident.token.string; String att = this->instruction_att_mnemonic(instr); if (att.len != 0) { name = att; } - asm_string = gb_string_append_length(asm_string, name.text, name.len); + write_string(name); // If a memory operand carries an explicit size annotation ([p]:u8) and // no register operand pins the width, the AT&T assembler needs the size @@ -571,37 +594,37 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { // suffix can never conflict with a register operand's implied width. if (att.len == 0) { if (char suffix = this->instruction_size_suffix(instr)) { - asm_string = gb_string_append_length(asm_string, &suffix, 1); + write_char(suffix); } } - asm_string = gb_string_appendc(asm_string, " "); + write_cstr(" "); // Intel-source operand order reversed to AT&T (src, ..., dst). for (isize j = instr->operands.count-1; j >= 0; j -= 1) { Ast *op = instr->operands[j]; if (j < instr->operands.count-1) { - asm_string = gb_string_appendc(asm_string, ", "); + write_cstr(", "); } - asm_string = this->write_operand(asm_string, op_number, op, WriteOperandFlag_DEFAULT); + this->write_operand(op_number, op, WriteOperandFlag_DEFAULT); } case_end; case_ast_node(label, AsmLabelDecl, instr_); - asm_string = this->write_label(asm_string, &label->name->Ident); - asm_string = gb_string_appendc(asm_string, ":"); + this->write_label(&label->name->Ident); + write_cstr(":"); case_end; case_ast_node(dir, AsmDirective, instr_); String name = dir->name.string; if (name == "byte") { - asm_string = gb_string_appendc(asm_string, ".byte "); + write_cstr(".byte "); isize op_index = 0; for (auto const &op : dir->operands) { if (op_index > 0) { - asm_string = gb_string_appendc(asm_string, ", "); + write_cstr(", "); } ExactValue ev = exact_value_to_integer(op->tav.value); GB_ASSERT(ev.kind == ExactValue_Integer); i64 i = exact_value_to_i64(ev); - asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)i); + write_int(cast(int)i); op_index += 1; } } else if (name == "align") { @@ -611,24 +634,24 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { GB_ASSERT(ev.kind == ExactValue_Integer); u64 i = exact_value_to_u64(ev); u64 i_log2 = floor_log2(i); - asm_string = gb_string_appendc(asm_string, ".p2align "); - asm_string = gb_string_append_fmt(asm_string, "%llu", cast(unsigned long long)i_log2); + write_cstr(".p2align "); + write_u64(i_log2); } else if (name == "skip") { GB_ASSERT(dir->operands.count == 1); auto const &op = dir->operands[0]; ExactValue ev = exact_value_to_integer(op->tav.value); GB_ASSERT(ev.kind == ExactValue_Integer); u64 i = exact_value_to_u64(ev); - asm_string = gb_string_appendc(asm_string, ".skip "); - asm_string = gb_string_append_fmt(asm_string, "%llu", cast(unsigned long long)i); + write_cstr(".skip "); + write_u64(i); } else if (name == "nop") { GB_ASSERT(dir->operands.count == 1); auto const &op = dir->operands[0]; ExactValue ev = exact_value_to_integer(op->tav.value); GB_ASSERT(ev.kind == ExactValue_Integer); u64 i = exact_value_to_u64(ev); - asm_string = gb_string_appendc(asm_string, ".nops "); - asm_string = gb_string_append_fmt(asm_string, "%llu", cast(unsigned long long)i); + write_cstr(".nops "); + write_u64(i); } else { GB_PANIC("Invalid asm directive: %.*s", LIT(name)); } @@ -849,7 +872,7 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { } // RISC-V immediates are bare integers (no '$' prefix). - gbString write_constant_operand(gbString asm_string, Ast *op, u32 flags) { + void write_constant_operand(Ast *op, u32 flags) { GB_ASSERT(op->tav.mode == Addressing_Constant); op->tav.value = exact_value_to_integer(op->tav.value); ExactValue ev = op->tav.value; @@ -861,7 +884,7 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { if (flags & WriteOperandFlag_Negate) { val = -val; } - asm_string = gb_string_append_fmt(asm_string, "%lld", cast(long long)val); + this->write_i64(val); break; } case ExactValue_Float: @@ -871,19 +894,19 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { GB_PANIC("Unsupported asm immediate literal %s", expr_to_string(op)); break; } - return asm_string; } // RISC-V operand syntax: bare registers (no '%'), bare immediates (no '$$'), and // no x86 sub-register width modifiers. - gbString write_operand(gbString asm_string, Slice const &op_number, Ast *op, u32 flags) { + void write_operand(Slice const &op_number, Ast *op, u32 flags) { if (op->tav.mode == Addressing_Constant) { - return this->write_constant_operand(asm_string, op, flags); + this->write_constant_operand(op, flags); + return; } if (flags & WriteOperandFlag_Negate) { flags &= ~WriteOperandFlag_Negate; - asm_string = gb_string_appendc(asm_string, "-"); + write_cstr("-"); } switch (op->kind) { @@ -898,28 +921,27 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { asm_string = gb_string_append_fmt(asm_string, "$%d", idx); case_end; case_ast_node(mem_op, AsmMemoryOperand, op); - asm_string = this->write_memory_operand(asm_string, op_number, mem_op, flags&~WriteOperandFlag_PrintPrefixes); + this->write_memory_operand(op_number, mem_op, flags&~WriteOperandFlag_PrintPrefixes); case_end; case_ast_node(bl, BasicLit, op); GB_PANIC("NOTE(bill): this should have been handled above"); case_end; case_ast_node(label, AsmLabelDecl, op); - asm_string = write_label(asm_string, &label->name->Ident); + this->write_label(&label->name->Ident); case_end; case_ast_node(reg, AsmRegister, op); // RISC-V names registers bare (zero, a0, fa0); no '%' prefix. - asm_string = gb_string_append_length(asm_string, reg->name.string.text, reg->name.string.len); + this->write_string(reg->name.string); case_end; default: GB_PANIC("TODO(bill): write_operand for '%s'", expr_to_string(op)); break; } - return asm_string; } // RISC-V addressing is `offset(base)`: a signed 12-bit displacement plus one base // register. No index register, scale factor, or segment override exists. - gbString write_memory_operand(gbString asm_string, Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) override { + void write_memory_operand(Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) override { GB_ASSERT_MSG(mem_op->segment_override == nullptr, "asm: RISC-V has no segment overrides"); GB_ASSERT_MSG(mem_op->index == nullptr && mem_op->scale == nullptr, "asm: RISC-V memory operands have no index/scale"); @@ -928,40 +950,35 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { if (mem_op->disp_op.kind == Token_Sub) { disp_flags |= WriteOperandFlag_Negate; } - asm_string = this->write_operand(asm_string, op_number, mem_op->disp, disp_flags); + this->write_operand(op_number, mem_op->disp, disp_flags); } - asm_string = gb_string_appendc(asm_string, "("); + write_cstr("("); if (mem_op->base != nullptr) { - asm_string = this->write_operand(asm_string, op_number, mem_op->base, flags&~WriteOperandFlag_PrintPrefixes); + this->write_operand(op_number, mem_op->base, flags&~WriteOperandFlag_PrintPrefixes); } - asm_string = gb_string_appendc(asm_string, ")"); - return asm_string; + write_cstr(")"); + return; } // RISC-V mnemonics are spelled with '.' (fmadd.s, fmv.w.x, lr.w). Odin identifiers // cannot contain '.', so they are written with '_' and translated back here. No // real RISC-V mnemonic contains an underscore, so this mapping is unambiguous. - gbString append_riscv_mnemonic(gbString s, String name) { + void append_riscv_mnemonic(String name) { for (isize i = 0; i < name.len; i++) { char c = cast(char)name.text[i]; if (c == '_') { c = '.'; } - s = gb_string_append_length(s, &c, 1); + write_char(c); } - return s; } lbValue emit_call(lbProcedure *p, Array const &args) override { lbModule *m = p->module; LLVMContextRef ctx = m->ctx; - gbString asm_string = gb_string_make_reserve(heap_allocator(), 256); - gbString constraints = gb_string_make_reserve(heap_allocator(), 64); - defer ({ - gb_string_free(constraints); - gb_string_free(asm_string); - }); + gb_string_clear(this->asm_string); + gb_string_clear(this->constraints); TEMPORARY_ALLOCATOR_GUARD(); @@ -976,31 +993,7 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { ret_slot [i] = -1; } - struct ElemAttr { - unsigned arg_pos; - LLVMTypeRef elem; - }; auto elem_attrs = array_make(temporary_allocator(), 0, ops->count); - - auto sep = [&]() { - if (gb_string_length(constraints) != 0) { - constraints = gb_string_appendc(constraints, ","); - } - }; - auto raw = [&](char const *s) { - constraints = gb_string_appendc(constraints, s); - }; - auto clobber = [&](char const *start, String mid, char const *end) { - constraints = gb_string_appendc(constraints, start); - constraints = gb_string_append_length(constraints, mid.text, mid.len); - constraints = gb_string_appendc(constraints, end); - }; - - auto add_input_value = [](Array *param_types, Array *call_args, LLVMValueRef v) { - array_add(param_types, LLVMTypeOf(v)); - array_add(call_args, v); - }; - i32 next_op = 0; // running $N counter (outputs first, then inputs) // Pass 1: outputs (real outputs + unpinned register scratch modeled as @@ -1012,11 +1005,10 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { continue; // width-view: resolved to its source's operand, owns no slot } - // A flag output cannot occur on RISC-V (no condition-flags register), but - // keep the branch for structural parity; flag_output_cc_suffix returns {} - // so it is never actually taken. + // NOTE(bill): A flag output cannot occur on RISC-V (no condition-flags register), + // but keep the branch for structural parity. if (e.param_group == AsmTemplateEntityDeclParamGroup_Output && e.pin_flag.len != 0) { - GB_ASSERT_MSG(false, "asm: RISC-V has no flag outputs"); + GB_PANIC("llvm_backend_asm.cpp: RISC-V has no flag outputs"); } bool is_output = e.param_group == AsmTemplateEntityDeclParamGroup_Output; @@ -1089,42 +1081,41 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { // Build the template text for_array(i, tmpl_node->instructions) { if (i > 0) { - asm_string = gb_string_appendc(asm_string, "\n"); + write_cstr("\n"); } Ast *instr_ = tmpl_node->instructions[i]; switch (instr_->kind) { case_ast_node(instr, AsmInstruction, instr_); - asm_string = gb_string_appendc(asm_string, "\t"); + write_cstr("\t"); String name = instr->name->Ident.token.string; - asm_string = this->append_riscv_mnemonic(asm_string, name); + this->append_riscv_mnemonic(name); - asm_string = gb_string_appendc(asm_string, " "); - // RISC-V is destination-first natively; emit operands in written order. - for (isize j = 0; j < instr->operands.count; j += 1) { + write_cstr(" "); + for_array(j, instr->operands) { Ast *op = instr->operands[j]; if (j > 0) { - asm_string = gb_string_appendc(asm_string, ", "); + write_cstr(", "); } - asm_string = this->write_operand(asm_string, op_number, op, WriteOperandFlag_NONE); + this->write_operand(op_number, op, WriteOperandFlag_NONE); } case_end; case_ast_node(label, AsmLabelDecl, instr_); - asm_string = this->write_label(asm_string, &label->name->Ident); - asm_string = gb_string_appendc(asm_string, ":"); + this->write_label(&label->name->Ident); + write_cstr(":"); case_end; case_ast_node(dir, AsmDirective, instr_); String name = dir->name.string; if (name == "byte") { - asm_string = gb_string_appendc(asm_string, ".byte "); + write_cstr(".byte "); isize op_index = 0; for (auto const &op : dir->operands) { if (op_index > 0) { - asm_string = gb_string_appendc(asm_string, ", "); + write_cstr(", "); } ExactValue ev = exact_value_to_integer(op->tav.value); GB_ASSERT(ev.kind == ExactValue_Integer); i64 v = exact_value_to_i64(ev); - asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)v); + write_int(cast(int)v); op_index += 1; } } else if (name == "align") { @@ -1204,15 +1195,12 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { string_set_update(&emitted_reg_clobbers, reg); } - // RISC-V has no condition-flags/cc register, so #clobber flags maps to nothing. - // (clobber_flags being set here is effectively a no-op.) - + // NOTE(bill): RISC-V has no condition-flags/cc register, so #clobber flags maps to nothing. if (tmpl_entity->AsmTemplate.clobber_memory && !memory_clobbered_already) { sep(); raw("~{memory}"); } - // Build the callee type LLVMTypeRef ret_ty = nullptr; if (ret_types.count == 0) { ret_ty = LLVMVoidTypeInContext(ctx); @@ -1236,6 +1224,9 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { LLVMValueRef call = LLVMBuildCall2(p->builder, fn_ty, ia, call_args.data, cast(unsigned)call_args.count, ""); if (LLVM_ASM_DEBUG_PRINT) { + // DEBUG PRINT!!! + // DEBUG PRINT!!! + // DEBUG PRINT!!! gb_printf_err("%s\n", asm_string); char *ir = LLVMPrintValueToString(call); gb_printf_err("%s\n\n", ir); @@ -1248,7 +1239,6 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { LLVMAddCallSiteAttribute(call, cast(LLVMAttributeIndex)(elem_attr.arg_pos + 1), attr); } - // Repackage results in Odin result order Type *pt = base_type(tmpl_entity->type); isize result_count = 0; if (pt->Proc.results != nullptr) { @@ -1269,7 +1259,8 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { continue; } if (e.result_index < 0) { - continue; // memory output: not a returned value + // NOTE(bill): memory output is not a returned value + continue; } GB_ASSERT(ret_slot[i] >= 0); @@ -1310,5 +1301,6 @@ gb_internal lbValue lb_emit_asm_template_call(lbProcedure *p, Entity *entity, Ar } GB_ASSERT(generator != nullptr); generator->init(entity); + defer (generator->destroy()); return generator->emit_call(p, args); } \ No newline at end of file From 51467b41ba46801c1154e066413825011b7a1d0b Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 15:28:06 +0100 Subject: [PATCH 15/20] Unify even more logic in llvm_backend_asm.cpp --- src/llvm_backend_asm.cpp | 1151 +++++++++++++------------------------- 1 file changed, 393 insertions(+), 758 deletions(-) diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index fafd84d1c..0e7fdc919 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -20,7 +20,6 @@ struct lbAsmGenerate { WriteOperandFlag_Negate = 1<<3, - WriteOperandFlag_NONE = 0, WriteOperandFlag_DEFAULT = WriteOperandFlag_PrintPrefixes, }; @@ -30,6 +29,7 @@ struct lbAsmGenerate { GB_ASSERT(this->tmpl_entity != nullptr); GB_ASSERT(this->tmpl_entity->kind == Entity_AsmTemplate); this->ops = &this->tmpl_entity->AsmTemplate.decls; + GB_ASSERT(this->tmpl_entity->AsmTemplate.node->kind == Ast_AsmTemplate); this->tmpl_node = &this->tmpl_entity->AsmTemplate.node->AsmTemplate; @@ -42,25 +42,12 @@ struct lbAsmGenerate { gb_string_free(this->constraints); } - void write_cstr(char const *cstr) { - asm_string = gb_string_appendc(asm_string, cstr); - } - void write_char(char c) { - asm_string = gb_string_append_length(asm_string, &c, 1); - } - void write_string(String str) { - asm_string = gb_string_append_length(asm_string, str.text, str.len); - } - void write_int(int val) { - asm_string = gb_string_append_fmt(asm_string, "%d", cast(int)val); - } - void write_u64(u64 val) { - asm_string = gb_string_append_fmt(asm_string, "%llu", cast(unsigned long long)val); - } - void write_i64(i64 val) { - asm_string = gb_string_append_fmt(asm_string, "%lld", cast(long long)val); - } - + void write_cstr(char const *cstr) { asm_string = gb_string_appendc (asm_string, cstr); } + void write_char(char c) { asm_string = gb_string_append_length(asm_string, &c, 1); } + void write_string(String str) { asm_string = gb_string_append_length(asm_string, str.text, str.len); } + void write_int(int val) { asm_string = gb_string_append_fmt (asm_string, "%d", cast(int)val); } + void write_u64(u64 val) { asm_string = gb_string_append_fmt (asm_string, "%llu", cast(unsigned long long)val); } + void write_i64(i64 val) { asm_string = gb_string_append_fmt (asm_string, "%lld", cast(long long)val); } void write_label(AstIdent *label_ident) { String name = label_ident->token.string; @@ -83,126 +70,6 @@ struct lbAsmGenerate { return nullptr; } - void write_constant_operand(Ast *op, u32 flags) { - GB_ASSERT(op->tav.mode == Addressing_Constant); - - op->tav.value = exact_value_to_integer(op->tav.value); - ExactValue ev = op->tav.value; - GB_ASSERT(ev.kind != ExactValue_Invalid); - switch (ev.kind) { - case ExactValue_Integer: { - i64 val = exact_value_to_i64(ev); - if (flags & WriteOperandFlag_IsScale) { - switch (val) { - case 1: case 2: case 4: case 8: - // okay - break; - default: - error(op, "A scale must be a constant integer or an immediate with the value 1, 2, 4, or 8, got %lld", cast(long long)val); - break; - } - } else if (flags & WriteOperandFlag_IsScaleLog2) { - switch (val) { - case 0: case 1: case 2: case 3: - // NOTE(bill): AMD64 only supports full scales - val = (cast(i64)1)< const &op_number, Ast *op, u32 flags) { - if (op->tav.mode == Addressing_Constant) { - this->write_constant_operand(op, flags); - return; - } - - if (flags & WriteOperandFlag_Negate) { - flags &= ~WriteOperandFlag_Negate; - write_cstr("-"); - } - - switch (op->kind) { - case_ast_node(i, Ident, op); - Entity *e = entity_of_node(op); - auto *ed = entity_op(e); - - if (ed->view_of >= 0) { - // Width-view of another operand (e.g. `p0b: u8 = p0`): emit the SOURCE - // operand's number with an LLVM width modifier, so both names share the - // one register the allocator chose, viewed at the requested width. - i32 idx = op_number[ed->view_of]; - GB_ASSERT(idx >= 0); - char mod = 0; - switch (ed->view_bits) { - case 8: mod = 'b'; break; // low 8-bit (al/r11b/...) - case 16: mod = 'w'; break; // 16-bit (ax/r11w/...) - case 32: mod = 'k'; break; // 32-bit (eax/r11d/...) - case 64: mod = 'q'; break; // 64-bit (rax/r11/...) - default: GB_PANIC("asm: invalid width-view size %d", ed->view_bits); break; - } - asm_string = gb_string_append_fmt(asm_string, "${%d:%c}", idx, mod); - } else { - i32 idx = op_number[ed->total_index]; - GB_ASSERT(idx >= 0); - asm_string = gb_string_append_fmt(asm_string, "$%d", idx); - } - case_end; - case_ast_node(mem_op, AsmMemoryOperand, op); - this->write_memory_operand(op_number, mem_op, flags&~WriteOperandFlag_PrintPrefixes); - case_end; - - case_ast_node(bl, BasicLit, op); - GB_PANIC("NOTE(bill): this should have been handled above"); - case_end; - - case_ast_node(label, AsmLabelDecl, op); - this->write_label(&label->name->Ident); - case_end; - - case_ast_node(reg, AsmRegister, op); - write_cstr("%"); - write_string(reg->name.string); - case_end; - default: - GB_PANIC("TODO(bill): write_operand for '%s'", expr_to_string(op)); - break; - } - return; - } - - char const *class_letter(AsmRegClass rc) { - switch (rc) { - case AsmRegClass_Integer: return "r"; - case AsmRegClass_Float: return "x"; // TODO(bill): target-dependent - case AsmRegClass_Vector: return "x"; // TODO(bill): target-dependent - case AsmRegClass_Mask: return "^Yk"; // AVX-512 k-regs - default: GB_PANIC("asm: unknown reg class"); return "r"; - } - }; // LLVM type of a returned register output, taken from the proc signature's results. @@ -210,7 +77,7 @@ struct lbAsmGenerate { Type *pt = base_type(tmpl_entity->type); Type *rt = pt->Proc.results->Tuple.variables[e.result_index]->type; return lb_type(m, rt); - }; + } // The declared Odin result type for an output entity. Type *result_type_of(AsmTemplateEntityDecl const &e) { @@ -236,212 +103,7 @@ struct lbAsmGenerate { array_add(call_args, v); } - virtual char instruction_size_suffix(AstAsmInstruction *instr) = 0; - virtual char size_suffix_for_operand(Ast *op) = 0; - virtual void write_memory_operand(Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) = 0; - virtual lbValue emit_call(lbProcedure *p, Array const &args) = 0; - virtual String flag_output_cc_suffix(String const &pin_flag) = 0; - -}; - -struct lbAsmGenerate_amd64 : lbAsmGenerate { - // AT&T operand-size suffix ('b','w','l','q') for an annotated memory operand, - // or 0 if there is no size annotation to apply. Vector/other widths return 0, - // since those forms take no b/w/l/q suffix (the register operand fixes the size). - char size_suffix_for_operand(Ast *op) override { - if (op->kind != Ast_AsmMemoryOperand) { - return 0; - } - AstAsmMemoryOperand *mem_op = &op->AsmMemoryOperand; - if (mem_op->type == nullptr) { - return 0; // unsized: rely on a register operand to fix the width - } - // The frontend stored the access type as a pointer on the node's tav: [p]:u8 -> ^u8. - Type *ptr = mem_op->type->tav.type; - if (ptr == nullptr) { - return 0; - } - Type *access = type_deref(ptr); // ^u8 -> u8 - i64 sz = type_size_of(base_type(access)); - switch (sz) { - case 1: return 'b'; - case 2: return 'w'; - case 4: return 'l'; - case 8: return 'q'; - } - return 0; - } - - - // Some AT&T mnemonics encode BOTH operand widths and so cannot be spelled as a name plus one - // suffix: `movsx` from i8 to i32 is `movsbl`. Returns the complete mnemonic, or {} when the - // name-plus-suffix spelling is the right one - // - // The sign/zero-extend family is the only one whose two operands differ in width. Its AT&T - // mnemonic names both: `movsx` i8 -> i32 is `movsbl`, never `movsx` plus a suffix. `movsxd` is - // the same rule, movs + l + q - String instruction_att_mnemonic(AstAsmInstruction *instr) { - bool sign_extend; - switch (instr->mnemonic) { - case Asm_amd64::M_MOVSX: - case Asm_amd64::M_MOVSXD: - sign_extend = true; - break; - case Asm_amd64::M_MOVZX: - sign_extend = false; - break; - default: - return {}; - } - - auto forms = g_asm_amd64.encoding_forms(instr->mnemonic); - if (instr->valid_form_index < 0 || instr->valid_form_index >= forms.count) { - return {}; - } - auto const &form = forms[instr->valid_form_index]; - - // Intel operand order: dst first - i32 dst = g_asm_amd64.operand_type_bit_width(form.ops[0]); - i32 src = g_asm_amd64.operand_type_bit_width(form.ops[1]); - - if (sign_extend) { - if (src == 8 && dst == 16) { return str_lit("movsbw"); } - if (src == 8 && dst == 32) { return str_lit("movsbl"); } - if (src == 8 && dst == 64) { return str_lit("movsbq"); } - if (src == 16 && dst == 32) { return str_lit("movswl"); } - if (src == 16 && dst == 64) { return str_lit("movswq"); } - if (src == 32 && dst == 64) { return str_lit("movslq"); } - } else { - if (src == 8 && dst == 16) { return str_lit("movzbw"); } - if (src == 8 && dst == 32) { return str_lit("movzbl"); } - if (src == 8 && dst == 64) { return str_lit("movzbq"); } - if (src == 16 && dst == 32) { return str_lit("movzwl"); } - if (src == 16 && dst == 64) { return str_lit("movzwq"); } - } - return {}; - } - - // Scan an instruction's operands for an annotated memory operand and return its - // size suffix, or 0 if none. The checker has already verified the annotation - // agrees with the matched encoding form, so a suffix here can never conflict. - char instruction_size_suffix(AstAsmInstruction *instr) override { - for (Ast *operand : instr->operands) { - char s = this->size_suffix_for_operand(operand); - if (s != 0) { - return s; - } - } - GB_ASSERT(instr->mnemonic != 0); - GB_ASSERT(instr->valid_form_index >= 0); - - auto forms = g_asm_amd64.encoding_forms(instr->mnemonic); - if (forms.count <= 1) { - return 0; - } - auto const &form = forms[instr->valid_form_index]; - - i32 width = 0; - for (auto ot : form.ops) { - if (ot == g_asm_amd64.OP_NONE) { - break; - } - if (g_asm_amd64.operand_type_is_implicit(ot)) { - continue; - } - AsmRegClass cls = g_asm_amd64.operand_type_reg_class(ot); - if (cls == AsmRegClass_Vector || cls == AsmRegClass_Mask) { - // xmm/ymm/zmm/k forms take no b/w/l/q suffix - return 0; - } - - // Only register and memory operands contribute an operand-size suffix. - // Relative branch targets (OP_REL8/REL32), immediates (OP_IMM*), and - // labels are NOT operand sizes -- jl/jmp/call/setcc must never get a - // b/w/l/q suffix from their displacement/immediate. - AsmOperandKind kind = g_asm_amd64.kind_from_operand_type(ot); - if (kind != AsmOperand_Register && - kind != AsmOperand_Memory && - kind != AsmOperand_Register_Or_Memory) { - continue; - } - - i32 w = g_asm_amd64.operand_type_bit_width(ot); - if (w == 8 || w == 16 || w == 32 || w == 64) { - width = gb_max(width, w); // GP/memory width - } - } - - switch (width) { - case 8: return 'b'; - case 16: return 'w'; - case 32: return 'l'; - case 64: return 'q'; - } - // vector op, or nothing that needs a GP-width suffix - return 0; - } - - // Map an EFLAGS flag name to its LLVM `=@cc` setcc condition, or {} if - // the flag has no single-flag setcc form (af/df/if/... can't be a flag output). - String flag_output_cc_suffix(String const &pin_flag) override { - if (pin_flag == "c") return str_lit("c"); // carry - if (pin_flag == "p") return str_lit("p"); // parity (even) - if (pin_flag == "z") return str_lit("z"); // zero - if (pin_flag == "s") return str_lit("s"); // sign - if (pin_flag == "o") return str_lit("o"); // overflow - return {}; - } - - - void write_memory_operand(Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) override { - if (mem_op->segment_override != nullptr) { - this->write_operand(op_number, mem_op->segment_override, flags); - write_cstr(":"); - } - - if (mem_op->disp) { - u32 disp_flags = flags; - disp_flags &= ~WriteOperandFlag_PrintPrefixes; - if (mem_op->disp_op.kind == Token_Sub) { - disp_flags |= WriteOperandFlag_Negate; - } - - this->write_operand(op_number, mem_op->disp, disp_flags); - } - if (mem_op->base == nullptr && mem_op->index == nullptr) { - GB_ASSERT(mem_op->scale == nullptr); - return; - } - write_cstr("("); - if (mem_op->base != nullptr) { - this->write_operand(op_number, mem_op->base, flags); - } - if (mem_op->index) { - u32 index_flags = flags; - if (mem_op->index_op.kind == Token_Sub) { - index_flags |= WriteOperandFlag_Negate; - } - write_cstr(","); - this->write_operand(op_number, mem_op->index, index_flags); - - if (mem_op->scale) { - write_cstr(","); - switch (mem_op->scale_op.kind) { - case Token_Mul: - this->write_operand(op_number, mem_op->scale, (flags|WriteOperandFlag_IsScale)&~WriteOperandFlag_PrintPrefixes); - break; - case Token_Shl: - case Token_Shr: - this->write_operand(op_number, mem_op->scale, (flags|WriteOperandFlag_IsScaleLog2)&~WriteOperandFlag_PrintPrefixes); - break; - } - } - } - write_cstr(")"); - return; - } - - lbValue emit_call(lbProcedure *p, Array const &args) override { + lbValue emit_call(lbProcedure *p, Array const &args) { lbModule *m = p->module; LLVMContextRef ctx = m->ctx; @@ -478,9 +140,10 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } // Flag output: an output pinned to a condition flag (e.g. `= %flags.zf`). - // Lowers to LLVM's `=@cc`, which yields an i1 (0/1). It takes a - // return-struct slot but is NEVER referenced in the body (the instruction - // sets the flag as a side effect), so it gets no $N operand number. + // Lowers to LLVM's `=@cc` (i1). Takes a return-struct slot but is + // never referenced in the body. On targets with no flags register, + // flag_output_cc_suffix returns {} and the assert below fires (unreachable + // in practice: the frontend cannot form a valid flag pin there). if (e.param_group == AsmTemplateEntityDeclParamGroup_Output && e.pin_flag.len != 0) { GB_ASSERT(e.pin == "flags"); String suffix = this->flag_output_cc_suffix(e.pin_flag); @@ -492,7 +155,6 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { ret_slot[i] = cast(i32)ret_types.count; array_add(&ret_types, LLVMInt8TypeInContext(ctx)); - // Counted in $N even though never referenced in the body. op_number[i] = next_op++; continue; } @@ -509,7 +171,7 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { // Register output: '=' ['&'] ( '{pin}' | class-letter ) raw("="); // early-clobber: keep scratch, and any output a later instruction could read past, - // off an input's register. One instruction reads before it writes, so it is safe + // off an input's register. One instruction reads before it writes, so it is safe. if (is_alloc_scratch || tmpl_node->instructions.count > 1) { raw("&"); } @@ -519,8 +181,6 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { raw(this->class_letter(e.reg_class)); } - // Use the entity's real declared type so the return-struct slot matches - // the constraint's width/class (e.g. <4 x float> for a #simd[4]f32 scratch). LLVMTypeRef ty = is_alloc_scratch ? lb_type(m, e.entity->type) : this->output_llvm_type(m, e); ret_slot[i] = cast(i32)ret_types.count; @@ -572,6 +232,8 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } // Build the template text + u32 op_flags = this->default_operand_write_flags(); + bool reverse = this->reverse_operand_order(); for_array(i, tmpl_node->instructions) { if (i > 0) { write_cstr("\n"); @@ -580,32 +242,16 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { switch (instr_->kind) { case_ast_node(instr, AsmInstruction, instr_); write_cstr("\t"); - String name = instr->name->Ident.token.string; - String att = this->instruction_att_mnemonic(instr); - if (att.len != 0) { - name = att; - } - write_string(name); - - // If a memory operand carries an explicit size annotation ([p]:u8) and - // no register operand pins the width, the AT&T assembler needs the size - // encoded as a mnemonic suffix (crc32 -> crc32b). The checker has already - // verified the annotation agrees with the matched form, so an emitted - // suffix can never conflict with a register operand's implied width. - if (att.len == 0) { - if (char suffix = this->instruction_size_suffix(instr)) { - write_char(suffix); - } - } - + this->write_instruction_mnemonic(instr); write_cstr(" "); - // Intel-source operand order reversed to AT&T (src, ..., dst). - for (isize j = instr->operands.count-1; j >= 0; j -= 1) { - Ast *op = instr->operands[j]; - if (j < instr->operands.count-1) { + + isize n = instr->operands.count; + for (isize k = 0; k < n; k += 1) { + isize j = reverse ? (n-1-k) : k; + if (k > 0) { write_cstr(", "); } - this->write_operand(op_number, op, WriteOperandFlag_DEFAULT); + this->write_operand(op_number, instr->operands[j], op_flags); } case_end; case_ast_node(label, AsmLabelDecl, instr_); @@ -623,8 +269,8 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } ExactValue ev = exact_value_to_integer(op->tav.value); GB_ASSERT(ev.kind == ExactValue_Integer); - i64 i = exact_value_to_i64(ev); - write_int(cast(int)i); + i64 v = exact_value_to_i64(ev); + write_int(cast(int)v); op_index += 1; } } else if (name == "align") { @@ -632,26 +278,23 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { auto const &op = dir->operands[0]; ExactValue ev = exact_value_to_integer(op->tav.value); GB_ASSERT(ev.kind == ExactValue_Integer); - u64 i = exact_value_to_u64(ev); - u64 i_log2 = floor_log2(i); + u64 v = exact_value_to_u64(ev); write_cstr(".p2align "); - write_u64(i_log2); + write_u64(floor_log2(v)); } else if (name == "skip") { GB_ASSERT(dir->operands.count == 1); auto const &op = dir->operands[0]; ExactValue ev = exact_value_to_integer(op->tav.value); GB_ASSERT(ev.kind == ExactValue_Integer); - u64 i = exact_value_to_u64(ev); write_cstr(".skip "); - write_u64(i); + write_u64(exact_value_to_u64(ev)); } else if (name == "nop") { GB_ASSERT(dir->operands.count == 1); auto const &op = dir->operands[0]; ExactValue ev = exact_value_to_integer(op->tav.value); GB_ASSERT(ev.kind == ExactValue_Integer); - u64 i = exact_value_to_u64(ev); write_cstr(".nops "); - write_u64(i); + write_u64(exact_value_to_u64(ev)); } else { GB_PANIC("Invalid asm directive: %.*s", LIT(name)); } @@ -663,9 +306,8 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } bool memory_clobbered_already = false; - // Pass 3: clobbers - // Only the Scratch group. Unpinned register scratch was already emitted as an - // output in Pass 1, so it is skipped here. + // Pass 3: clobbers (Scratch group only; unpinned register scratch already + // emitted as an output in Pass 1). StringSet emitted_reg_clobbers = {}; string_set_init(&emitted_reg_clobbers); defer (string_set_destroy(&emitted_reg_clobbers)); @@ -703,7 +345,7 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { // scratch clobbers already emitted above. for (String const ® : tmpl_entity->AsmTemplate.clobber_registers_set) { if (string_set_exists(&emitted_reg_clobbers, reg)) { - continue; // already clobbered as a pinned scratch; don't double-emit + continue; } sep(); clobber("~{", reg, "}"); @@ -712,15 +354,7 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { // Template-level clobbers derived from #clobber flags / #clobber memory. if (tmpl_entity->AsmTemplate.clobber_flags) { - sep(); - if (build_context.metrics.arch == TargetArch_amd64) { - // clang's canonical x86 flags clobber - raw("~{dirflag}"); sep(); - raw("~{fpsr}"); sep(); - raw("~{flags}"); - } else { - raw("~{cc}"); // AArch64 uses ~{cc} - } + this->emit_flags_clobber(); } if (tmpl_entity->AsmTemplate.clobber_memory && !memory_clobbered_already) { sep(); @@ -754,9 +388,6 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { LLVMValueRef call = LLVMBuildCall2(p->builder, fn_ty, ia, call_args.data, cast(unsigned)call_args.count, ""); if (LLVM_ASM_DEBUG_PRINT) { - // DEBUG PRINT!!! - // DEBUG PRINT!!! - // DEBUG PRINT!!! gb_printf_err("%s\n", asm_string); char *ir = LLVMPrintValueToString(call); gb_printf_err("%s\n\n", ir); @@ -799,12 +430,10 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { LLVMValueRef v = call; if (ret_types.count != 1) { - // Not a single-element return but a struct v = LLVMBuildExtractValue(p->builder, call, cast(unsigned)ret_slot[i], ""); } - // A flag output is delivered as i8; coerce it to the declared result type - // (e.g. i1, or a wider bool). zext when widening, trunc when narrowing. + // A flag output is delivered as i8; coerce it to the declared result type. // zext (not sext) is correct: a flag output is 0 or 1. if (e.pin_flag.len != 0) { Type *rt = this->result_type_of(e); @@ -818,7 +447,6 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } else if (want_w > got_w) { v = LLVMBuildZExt(p->builder, v, want, ""); } - // want_w == got_w with differing type identity: same width, no-op. } } @@ -830,7 +458,6 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { return lbValue{result_vals[0], rt}; } - // Multiple results -> assemble Odin's result aggregate in result order. Type *results_type = pt->Proc.results; LLVMValueRef agg = LLVMGetUndef(lb_type(m, results_type)); for_array(i, result_vals) { @@ -840,30 +467,358 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { return lbValue{agg, results_type}; } + + + // Operand-write flags for the template body. amd64 wants prefixes ('$$', '%'); + // riscv64 wants none. Kept explicit rather than relying on the riscv overrides + // happening to ignore the prefix bit. + virtual u32 default_operand_write_flags() { + return WriteOperandFlag_DEFAULT; + } + + // #clobber flags -> target constraint fragment. Default: nothing (RISC-V has no + // architectural condition-code register). amd64 overrides with the x86 triple. + virtual void emit_flags_clobber() { + // empty + } + + + virtual char const *class_letter (AsmRegClass rc) = 0; + virtual void write_constant_operand (Ast *op, u32 flags) = 0; + virtual void write_operand (Slice const &op_number, Ast *op, u32 flags) = 0; + virtual bool reverse_operand_order () = 0; // Intel dst-first -> AT&T src-first? + virtual void write_instruction_mnemonic(AstAsmInstruction *instr) = 0; // name (+ any suffix / spelling fixup) + virtual void write_memory_operand (Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) = 0; + virtual String flag_output_cc_suffix (String const &pin_flag) = 0; + }; -struct lbAsmGenerate_riscv64 : lbAsmGenerate { - // RISC-V has no AT&T-style operand-size suffixes; precision lives in the mnemonic - // (flw vs fld, .s vs .d), so nothing here ever contributes a b/w/l/q suffix. - char size_suffix_for_operand(Ast *op) override { - return 0; - } - char instruction_size_suffix(AstAsmInstruction *instr) override { - return 0; +struct lbAsmGenerate_amd64 : lbAsmGenerate { + bool reverse_operand_order() override { + return true; + } + + u32 default_operand_write_flags() override { + return WriteOperandFlag_DEFAULT; + } + + void emit_flags_clobber() override { + // NOTE(bill): clang's canonical x86 flags clobber + sep(); raw("~{dirflag}"); + sep(); raw("~{fpsr}"); + sep(); raw("~{flags}"); + } + + + char const *class_letter(AsmRegClass rc) override { + switch (rc) { + case AsmRegClass_Integer: return "r"; + case AsmRegClass_Float: return "x"; // x86 XMM + case AsmRegClass_Vector: return "x"; + case AsmRegClass_Mask: return "^Yk"; // AVX-512 k-regs + default: + GB_PANIC("asm: unknown reg class"); + return "r"; + } + } + + void write_instruction_mnemonic(AstAsmInstruction *instr) override { + String name = instr->name->Ident.token.string; + String att = this->instruction_att_mnemonic(instr); + if (att.len != 0) { + write_string(att); + return; + } + write_string(name); + if (char suffix = this->instruction_size_suffix(instr)) { + write_char(suffix); + } + } + + void write_constant_operand(Ast *op, u32 flags) override { + GB_ASSERT(op->tav.mode == Addressing_Constant); + + op->tav.value = exact_value_to_integer(op->tav.value); + ExactValue ev = op->tav.value; + GB_ASSERT(ev.kind != ExactValue_Invalid); + switch (ev.kind) { + case ExactValue_Integer: { + i64 val = exact_value_to_i64(ev); + if (flags & WriteOperandFlag_IsScale) { + switch (val) { + case 1: case 2: case 4: case 8: + break; + default: + error(op, "A scale must be a constant integer or an immediate with the value 1, 2, 4, or 8, got %lld", cast(long long)val); + break; + } + } else if (flags & WriteOperandFlag_IsScaleLog2) { + switch (val) { + case 0: case 1: case 2: case 3: + // NOTE(bill): AMD64 only supports full scales + val = (cast(i64)1)< const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) override { + if (mem_op->segment_override != nullptr) { + this->write_operand(op_number, mem_op->segment_override, flags); + write_cstr(":"); + } + + if (mem_op->disp) { + u32 disp_flags = flags & ~WriteOperandFlag_PrintPrefixes; + if (mem_op->disp_op.kind == Token_Sub) { + disp_flags |= WriteOperandFlag_Negate; + } + this->write_operand(op_number, mem_op->disp, disp_flags); + } + if (mem_op->base == nullptr && mem_op->index == nullptr) { + GB_ASSERT(mem_op->scale == nullptr); + return; + } + write_cstr("("); + if (mem_op->base != nullptr) { + this->write_operand(op_number, mem_op->base, flags); + } + if (mem_op->index) { + u32 index_flags = flags; + if (mem_op->index_op.kind == Token_Sub) { + index_flags |= WriteOperandFlag_Negate; + } + write_cstr(","); + this->write_operand(op_number, mem_op->index, index_flags); + + if (mem_op->scale) { + write_cstr(","); + switch (mem_op->scale_op.kind) { + case Token_Mul: + this->write_operand(op_number, mem_op->scale, (flags|WriteOperandFlag_IsScale)&~WriteOperandFlag_PrintPrefixes); + break; + case Token_Shl: + case Token_Shr: + this->write_operand(op_number, mem_op->scale, (flags|WriteOperandFlag_IsScaleLog2)&~WriteOperandFlag_PrintPrefixes); + break; + } + } + } + write_cstr(")"); + } + + void write_operand(Slice const &op_number, Ast *op, u32 flags) override { + if (op->tav.mode == Addressing_Constant) { + this->write_constant_operand(op, flags); + return; + } + + if (flags & WriteOperandFlag_Negate) { + flags &= ~WriteOperandFlag_Negate; + write_cstr("-"); + } + + switch (op->kind) { + case_ast_node(i, Ident, op); + Entity *e = entity_of_node(op); + auto *ed = entity_op(e); + + if (ed->view_of >= 0) { + // Width-view of another operand (e.g. `p0b: u8 = p0`): emit the SOURCE + // operand's number with an LLVM width modifier, so both names share the + // one register the allocator chose, viewed at the requested width. + i32 idx = op_number[ed->view_of]; + GB_ASSERT(idx >= 0); + char mod = 0; + switch (ed->view_bits) { + case 8: mod = 'b'; break; + case 16: mod = 'w'; break; + case 32: mod = 'k'; break; + case 64: mod = 'q'; break; + default: GB_PANIC("asm: invalid width-view size %d", ed->view_bits); break; + } + asm_string = gb_string_append_fmt(asm_string, "${%d:%c}", idx, mod); + } else { + i32 idx = op_number[ed->total_index]; + GB_ASSERT(idx >= 0); + asm_string = gb_string_append_fmt(asm_string, "$%d", idx); + } + case_end; + case_ast_node(mem_op, AsmMemoryOperand, op); + this->write_memory_operand(op_number, mem_op, flags&~WriteOperandFlag_PrintPrefixes); + case_end; + case_ast_node(bl, BasicLit, op); + GB_PANIC("NOTE(bill): this should have been handled above"); + case_end; + case_ast_node(label, AsmLabelDecl, op); + this->write_label(&label->name->Ident); + case_end; + case_ast_node(reg, AsmRegister, op); + write_cstr("%"); + write_string(reg->name.string); + case_end; + default: + GB_PANIC("TODO(bill): write_operand for '%s'", expr_to_string(op)); + break; + } } - // RISC-V has no architectural condition-flags register, so no output can be pinned - // to a flag / lowered to `=@cc`. String flag_output_cc_suffix(String const &pin_flag) override { + if (pin_flag == "c") return str_lit("c"); + if (pin_flag == "p") return str_lit("p"); + if (pin_flag == "z") return str_lit("z"); + if (pin_flag == "s") return str_lit("s"); + if (pin_flag == "o") return str_lit("o"); return {}; } + char size_suffix_for_operand(Ast *op) { + if (op->kind != Ast_AsmMemoryOperand) { + return 0; + } + AstAsmMemoryOperand *mem_op = &op->AsmMemoryOperand; + if (mem_op->type == nullptr) { + return 0; + } + Type *ptr = mem_op->type->tav.type; + if (ptr == nullptr) { + return 0; + } + Type *access = type_deref(ptr); + i64 sz = type_size_of(base_type(access)); + switch (sz) { + case 1: return 'b'; + case 2: return 'w'; + case 4: return 'l'; + case 8: return 'q'; + } + return 0; + } + + String instruction_att_mnemonic(AstAsmInstruction *instr) { + bool sign_extend; + switch (instr->mnemonic) { + case Asm_amd64::M_MOVSX: + case Asm_amd64::M_MOVSXD: + sign_extend = true; + break; + case Asm_amd64::M_MOVZX: + sign_extend = false; + break; + default: + return {}; + } + + auto forms = g_asm_amd64.encoding_forms(instr->mnemonic); + if (0 <= instr->valid_form_index && instr->valid_form_index < forms.count) { + auto const &form = forms[instr->valid_form_index]; + + i32 dst = g_asm_amd64.operand_type_bit_width(form.ops[0]); + i32 src = g_asm_amd64.operand_type_bit_width(form.ops[1]); + + if (sign_extend) { + if (src == 8 && dst == 16) { return str_lit("movsbw"); } + if (src == 8 && dst == 32) { return str_lit("movsbl"); } + if (src == 8 && dst == 64) { return str_lit("movsbq"); } + if (src == 16 && dst == 32) { return str_lit("movswl"); } + if (src == 16 && dst == 64) { return str_lit("movswq"); } + if (src == 32 && dst == 64) { return str_lit("movslq"); } + } else { + if (src == 8 && dst == 16) { return str_lit("movzbw"); } + if (src == 8 && dst == 32) { return str_lit("movzbl"); } + if (src == 8 && dst == 64) { return str_lit("movzbq"); } + if (src == 16 && dst == 32) { return str_lit("movzwl"); } + if (src == 16 && dst == 64) { return str_lit("movzwq"); } + } + } + return {}; + } + + char instruction_size_suffix(AstAsmInstruction *instr) { + for (Ast *operand : instr->operands) { + char s = this->size_suffix_for_operand(operand); + if (s != 0) { + return s; + } + } + GB_ASSERT(instr->mnemonic != 0); + GB_ASSERT(instr->valid_form_index >= 0); + + auto forms = g_asm_amd64.encoding_forms(instr->mnemonic); + if (forms.count <= 1) { + return 0; + } + auto const &form = forms[instr->valid_form_index]; + + i32 width = 0; + for (auto ot : form.ops) { + if (ot == g_asm_amd64.OP_NONE) { + break; + } + if (g_asm_amd64.operand_type_is_implicit(ot)) { + continue; + } + AsmRegClass cls = g_asm_amd64.operand_type_reg_class(ot); + if (cls == AsmRegClass_Vector || cls == AsmRegClass_Mask) { + return 0; + } + AsmOperandKind kind = g_asm_amd64.kind_from_operand_type(ot); + if (kind != AsmOperand_Register && + kind != AsmOperand_Memory && + kind != AsmOperand_Register_Or_Memory) { + continue; + } + i32 w = g_asm_amd64.operand_type_bit_width(ot); + if (w == 8 || w == 16 || w == 32 || w == 64) { + width = gb_max(width, w); + } + } + + switch (width) { + case 8: return 'b'; + case 16: return 'w'; + case 32: return 'l'; + case 64: return 'q'; + } + return 0; + } +}; + +struct lbAsmGenerate_riscv64 : lbAsmGenerate { + bool reverse_operand_order() override { + return false; + } + + u32 default_operand_write_flags() override { + return WriteOperandFlag_NONE; + } + // LLVM inline-asm constraint class letters for RISC-V. - char const *class_letter(AsmRegClass rc) { + char const *class_letter(AsmRegClass rc) override { switch (rc) { - case AsmRegClass_Integer: return "r"; // GPR (x-registers) - case AsmRegClass_Float: return "f"; // FPR (single/double share the FLEN file) - case AsmRegClass_Vector: return "vr"; // RVV vector register (V extension) + case AsmRegClass_Integer: return "r"; // GPR + case AsmRegClass_Float: return "f"; // FPR (single/double share the FLEN file) + case AsmRegClass_Vector: return "vr"; // RVV vector register case AsmRegClass_Mask: return "vm"; // RVV mask register (v0) default: GB_PANIC("asm: unknown reg class"); @@ -871,8 +826,8 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { } } - // RISC-V immediates are bare integers (no '$' prefix). - void write_constant_operand(Ast *op, u32 flags) { + // RISC-V immediates are bare integers (no '$' prefix); no scale/log2 forms exist. + void write_constant_operand(Ast *op, u32 flags) override { GB_ASSERT(op->tav.mode == Addressing_Constant); op->tav.value = exact_value_to_integer(op->tav.value); ExactValue ev = op->tav.value; @@ -896,26 +851,22 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { } } - // RISC-V operand syntax: bare registers (no '%'), bare immediates (no '$$'), and - // no x86 sub-register width modifiers. - void write_operand(Slice const &op_number, Ast *op, u32 flags) { + // Bare registers, bare immediates, no sub-register width modifiers. + void write_operand(Slice const &op_number, Ast *op, u32 flags) override { if (op->tav.mode == Addressing_Constant) { this->write_constant_operand(op, flags); return; } - if (flags & WriteOperandFlag_Negate) { flags &= ~WriteOperandFlag_Negate; write_cstr("-"); } - switch (op->kind) { case_ast_node(i, Ident, op); Entity *e = entity_of_node(op); auto *ed = entity_op(e); - // A width-view resolves to its source's operand. RISC-V x-registers are - // always XLEN-wide with no named sub-registers, so a view is simply the - // same register: emit the source operand number, no width modifier. + // x-registers are always XLEN-wide with no named sub-registers, so a + // width-view is just the same register: emit the source operand number. i32 idx = (ed->view_of >= 0) ? op_number[ed->view_of] : op_number[ed->total_index]; GB_ASSERT(idx >= 0); asm_string = gb_string_append_fmt(asm_string, "$%d", idx); @@ -930,8 +881,7 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { this->write_label(&label->name->Ident); case_end; case_ast_node(reg, AsmRegister, op); - // RISC-V names registers bare (zero, a0, fa0); no '%' prefix. - this->write_string(reg->name.string); + this->write_string(reg->name.string); // bare (zero, a0, fa0) case_end; default: GB_PANIC("TODO(bill): write_operand for '%s'", expr_to_string(op)); @@ -939,8 +889,7 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { } } - // RISC-V addressing is `offset(base)`: a signed 12-bit displacement plus one base - // register. No index register, scale factor, or segment override exists. + // RISC-V addressing is `offset(base)`: signed 12-bit displacement + one base reg. void write_memory_operand(Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) override { GB_ASSERT_MSG(mem_op->segment_override == nullptr, "asm: RISC-V has no segment overrides"); GB_ASSERT_MSG(mem_op->index == nullptr && mem_op->scale == nullptr, "asm: RISC-V memory operands have no index/scale"); @@ -957,337 +906,23 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { this->write_operand(op_number, mem_op->base, flags&~WriteOperandFlag_PrintPrefixes); } write_cstr(")"); - return; } - // RISC-V mnemonics are spelled with '.' (fmadd.s, fmv.w.x, lr.w). Odin identifiers - // cannot contain '.', so they are written with '_' and translated back here. No - // real RISC-V mnemonic contains an underscore, so this mapping is unambiguous. - void append_riscv_mnemonic(String name) { + // No condition-flags register, so no flag output can exist. + String flag_output_cc_suffix(String const &pin_flag) override { + return {}; + } + + // Mnemonics are spelled with '.' (fmadd.s, fmv.w.x); Odin identifiers use '_'. + void write_instruction_mnemonic(AstAsmInstruction *instr) override { + String name = instr->name->Ident.token.string; for (isize i = 0; i < name.len; i++) { char c = cast(char)name.text[i]; - if (c == '_') { - c = '.'; - } - write_char(c); + write_char(c == '_' ? '.' : c); } } - - lbValue emit_call(lbProcedure *p, Array const &args) override { - lbModule *m = p->module; - LLVMContextRef ctx = m->ctx; - - gb_string_clear(this->asm_string); - gb_string_clear(this->constraints); - - TEMPORARY_ALLOCATOR_GUARD(); - - auto param_types = array_make (temporary_allocator(), 0, ops->count); - auto call_args = array_make(temporary_allocator(), 0, ops->count); - auto ret_types = array_make (temporary_allocator(), 0, ops->count); - - auto op_number = slice_make(temporary_allocator(), ops->count); // $N, or -1 for clobbers/views - auto ret_slot = slice_make(temporary_allocator(), ops->count); // return-struct index, or -1 - for_array(i, *ops) { - op_number[i] = -1; - ret_slot [i] = -1; - } - - auto elem_attrs = array_make(temporary_allocator(), 0, ops->count); - i32 next_op = 0; // running $N counter (outputs first, then inputs) - - // Pass 1: outputs (real outputs + unpinned register scratch modeled as - // discarded early-clobber outputs). - for_array(i, *ops) { - AsmTemplateEntityDecl const &e = (*ops)[i]; - - if (e.view_of >= 0) { - continue; // width-view: resolved to its source's operand, owns no slot - } - - // NOTE(bill): A flag output cannot occur on RISC-V (no condition-flags register), - // but keep the branch for structural parity. - if (e.param_group == AsmTemplateEntityDeclParamGroup_Output && e.pin_flag.len != 0) { - GB_PANIC("llvm_backend_asm.cpp: RISC-V has no flag outputs"); - } - - bool is_output = e.param_group == AsmTemplateEntityDeclParamGroup_Output; - bool is_alloc_scratch = e.param_group == AsmTemplateEntityDeclParamGroup_Scratch - && e.kind == AsmTemplateEntityDecl_Register; - if (!is_output && !is_alloc_scratch) { - continue; - } - - sep(); - - raw("="); - if (is_alloc_scratch || tmpl_node->instructions.count > 1) { - raw("&"); - } - if (e.pin.len != 0) { - clobber("{", e.pin, "}"); - } else { - raw(this->class_letter(e.reg_class)); - } - - LLVMTypeRef ty = is_alloc_scratch ? lb_type(m, e.entity->type) : this->output_llvm_type(m, e); - - ret_slot[i] = cast(i32)ret_types.count; - array_add(&ret_types, ty); - op_number[i] = next_op++; - } - - // Pass 2: inputs - for_array(i, *ops) { - AsmTemplateEntityDecl const &e = (*ops)[i]; - - if (e.view_of >= 0) { - continue; // width-view: not its own input - } - if (e.param_group != AsmTemplateEntityDeclParamGroup_Input) { - continue; - } - - sep(); - lbValue v = args[e.param_index]; - - if (e.tie >= 0) { - i32 n = op_number[e.tie]; - GB_ASSERT(n >= 0); - constraints = gb_string_append_fmt(constraints, "%d", n); - add_input_value(¶m_types, &call_args, v.value); - } else { - switch (e.kind) { - case AsmTemplateEntityDecl_Register: - case AsmTemplateEntityDecl_Memory: - if (e.pin.len != 0) { - clobber("{", e.pin, "}"); - } else { - raw(this->class_letter(e.reg_class)); - } - add_input_value(¶m_types, &call_args, v.value); - break; - case AsmTemplateEntityDecl_Immediate: - raw("i"); - add_input_value(¶m_types, &call_args, v.value); - break; - default: - GB_PANIC("asm: invalid input operand kind"); - } - } - op_number[i] = next_op++; - } - - // Build the template text - for_array(i, tmpl_node->instructions) { - if (i > 0) { - write_cstr("\n"); - } - Ast *instr_ = tmpl_node->instructions[i]; - switch (instr_->kind) { - case_ast_node(instr, AsmInstruction, instr_); - write_cstr("\t"); - String name = instr->name->Ident.token.string; - this->append_riscv_mnemonic(name); - - write_cstr(" "); - for_array(j, instr->operands) { - Ast *op = instr->operands[j]; - if (j > 0) { - write_cstr(", "); - } - this->write_operand(op_number, op, WriteOperandFlag_NONE); - } - case_end; - case_ast_node(label, AsmLabelDecl, instr_); - this->write_label(&label->name->Ident); - write_cstr(":"); - case_end; - case_ast_node(dir, AsmDirective, instr_); - String name = dir->name.string; - if (name == "byte") { - write_cstr(".byte "); - isize op_index = 0; - for (auto const &op : dir->operands) { - if (op_index > 0) { - write_cstr(", "); - } - ExactValue ev = exact_value_to_integer(op->tav.value); - GB_ASSERT(ev.kind == ExactValue_Integer); - i64 v = exact_value_to_i64(ev); - write_int(cast(int)v); - op_index += 1; - } - } else if (name == "align") { - GB_ASSERT(dir->operands.count == 1); - auto const &op = dir->operands[0]; - ExactValue ev = exact_value_to_integer(op->tav.value); - GB_ASSERT(ev.kind == ExactValue_Integer); - u64 v = exact_value_to_u64(ev); - u64 v_log2 = floor_log2(v); - asm_string = gb_string_append_fmt(asm_string, ".p2align %llu", cast(unsigned long long)v_log2); - } else if (name == "skip") { - GB_ASSERT(dir->operands.count == 1); - auto const &op = dir->operands[0]; - ExactValue ev = exact_value_to_integer(op->tav.value); - GB_ASSERT(ev.kind == ExactValue_Integer); - u64 v = exact_value_to_u64(ev); - asm_string = gb_string_append_fmt(asm_string, ".skip %llu", cast(unsigned long long)v); - } else if (name == "nop") { - GB_ASSERT(dir->operands.count == 1); - auto const &op = dir->operands[0]; - ExactValue ev = exact_value_to_integer(op->tav.value); - GB_ASSERT(ev.kind == ExactValue_Integer); - u64 v = exact_value_to_u64(ev); - asm_string = gb_string_append_fmt(asm_string, ".nops %llu", cast(unsigned long long)v); - } else { - GB_PANIC("Invalid asm directive: %.*s", LIT(name)); - } - case_end; - default: - GB_PANIC("Invalid asm instruction"); - break; - } - } - - bool memory_clobbered_already = false; - // Pass 3: clobbers (Scratch group only; unpinned register scratch already - // emitted as an output in Pass 1). - StringSet emitted_reg_clobbers = {}; - string_set_init(&emitted_reg_clobbers); - defer (string_set_destroy(&emitted_reg_clobbers)); - - for_array(i, *ops) { - AsmTemplateEntityDecl const &e = (*ops)[i]; - - if (e.view_of >= 0) { - continue; // width-view carries no clobber; its source owns the register - } - if (e.param_group != AsmTemplateEntityDeclParamGroup_Scratch) { - continue; - } - if (e.kind == AsmTemplateEntityDecl_Register && e.pin.len == 0) { - continue; - } - - sep(); - switch (e.kind) { - case AsmTemplateEntityDecl_Register: - GB_ASSERT(e.pin.len != 0); - clobber("~{", e.pin, "}"); - string_set_update(&emitted_reg_clobbers, e.pin); - break; - case AsmTemplateEntityDecl_Memory: - raw("~{memory}"); - memory_clobbered_already = true; - break; - default: - GB_PANIC("asm: invalid scratch operand kind"); - } - } - - for (String const ® : tmpl_entity->AsmTemplate.clobber_registers_set) { - if (string_set_exists(&emitted_reg_clobbers, reg)) { - continue; - } - sep(); - clobber("~{", reg, "}"); - string_set_update(&emitted_reg_clobbers, reg); - } - - // NOTE(bill): RISC-V has no condition-flags/cc register, so #clobber flags maps to nothing. - if (tmpl_entity->AsmTemplate.clobber_memory && !memory_clobbered_already) { - sep(); - raw("~{memory}"); - } - - LLVMTypeRef ret_ty = nullptr; - if (ret_types.count == 0) { - ret_ty = LLVMVoidTypeInContext(ctx); - } else if (ret_types.count == 1) { - ret_ty = ret_types[0]; - } else { - ret_ty = LLVMStructTypeInContext(ctx, ret_types.data, cast(unsigned)ret_types.count, /*packed*/false); - } - - LLVMTypeRef fn_ty = LLVMFunctionType(ret_ty, param_types.data, cast(unsigned)param_types.count, /*vararg*/false); - - LLVMValueRef ia = LLVMGetInlineAsm( - fn_ty, - asm_string, cast(size_t)gb_string_length(asm_string), - constraints, cast(size_t)gb_string_length(constraints), - /*HasSideEffects*/ tmpl_entity->AsmTemplate.is_volatile, - /*IsAlignStack*/ tmpl_entity->AsmTemplate.is_align_stack, - LLVMInlineAsmDialectATT, - /*CanThrow*/ false); - - LLVMValueRef call = LLVMBuildCall2(p->builder, fn_ty, ia, call_args.data, cast(unsigned)call_args.count, ""); - - if (LLVM_ASM_DEBUG_PRINT) { - // DEBUG PRINT!!! - // DEBUG PRINT!!! - // DEBUG PRINT!!! - gb_printf_err("%s\n", asm_string); - char *ir = LLVMPrintValueToString(call); - gb_printf_err("%s\n\n", ir); - LLVMDisposeMessage(ir); - } - - unsigned et_kind = LLVMGetEnumAttributeKindForName("elementtype", 11); - for (auto const &elem_attr : elem_attrs) { - LLVMAttributeRef attr = LLVMCreateTypeAttribute(ctx, et_kind, elem_attr.elem); - LLVMAddCallSiteAttribute(call, cast(LLVMAttributeIndex)(elem_attr.arg_pos + 1), attr); - } - - Type *pt = base_type(tmpl_entity->type); - isize result_count = 0; - if (pt->Proc.results != nullptr) { - result_count = pt->Proc.results->Tuple.variables.count; - } - if (result_count == 0) { - return lbValue{}; - } - - auto result_vals = slice_make(temporary_allocator(), result_count); - - for_array(i, *ops) { - AsmTemplateEntityDecl const &e = (*ops)[i]; - if (e.view_of >= 0) { - continue; - } - if (e.param_group != AsmTemplateEntityDeclParamGroup_Output) { - continue; - } - if (e.result_index < 0) { - // NOTE(bill): memory output is not a returned value - continue; - } - GB_ASSERT(ret_slot[i] >= 0); - - LLVMValueRef v = call; - if (ret_types.count != 1) { - v = LLVMBuildExtractValue(p->builder, call, cast(unsigned)ret_slot[i], ""); - } - result_vals[e.result_index] = v; - } - - if (result_count == 1) { - Type *rt = pt->Proc.results->Tuple.variables[0]->type; - return lbValue{result_vals[0], rt}; - } - - Type *results_type = pt->Proc.results; - LLVMValueRef agg = LLVMGetUndef(lb_type(m, results_type)); - for_array(i, result_vals) { - GB_ASSERT(result_vals[i] != nullptr); - agg = LLVMBuildInsertValue(p->builder, agg, result_vals[i], cast(unsigned)i, ""); - } - - return lbValue{agg, results_type}; - } }; - gb_internal lbValue lb_emit_asm_template_call(lbProcedure *p, Entity *entity, Array const &args) { lbAsmGenerate_amd64 generator_amd64 = {}; lbAsmGenerate_riscv64 generator_riscv64 = {}; From 2ba79e2f17fba53963f3ad7f785715e4d0379149 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 15:34:27 +0100 Subject: [PATCH 16/20] Remove dead code --- src/llvm_backend_asm.cpp | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index 0e7fdc919..eae2b6fc5 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -8,11 +8,6 @@ struct lbAsmGenerate { gbString asm_string; gbString constraints; - struct ElemAttr { - unsigned arg_pos; - LLVMTypeRef elem; - }; - enum WriteOperandFlags : u32 { WriteOperandFlag_PrintPrefixes = 1<<0, WriteOperandFlag_IsScale = 1<<1, @@ -124,9 +119,6 @@ struct lbAsmGenerate { ret_slot [i] = -1; } - // elementtype() attrs to attach after the call is built (indirect/memory operands). - auto elem_attrs = array_make(temporary_allocator(), 0, ops->count); - i32 next_op = 0; // running $N counter (outputs first, then inputs) // Pass 1: outputs @@ -394,13 +386,6 @@ struct lbAsmGenerate { LLVMDisposeMessage(ir); } - // Attach elementtype() to every indirect operand's pointer arg (opaque-pointer requirement). - unsigned et_kind = LLVMGetEnumAttributeKindForName("elementtype", 11); - for (auto const &elem_attr : elem_attrs) { - LLVMAttributeRef attr = LLVMCreateTypeAttribute(ctx, et_kind, elem_attr.elem); - LLVMAddCallSiteAttribute(call, cast(LLVMAttributeIndex)(elem_attr.arg_pos + 1), attr); - } - // Repackage results in Odin result order Type *pt = base_type(tmpl_entity->type); isize result_count = 0; From 83f5cd87676e7693f00d07954c0ff0d12de2dc06 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 15:45:23 +0100 Subject: [PATCH 17/20] Add extra check for scratch parameters with no other parameters --- src/check_asm.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 0429ed80d..3e48a0a9c 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -672,6 +672,10 @@ gb_internal void check_asm_specs(AsmCtx *asm_ctx, CheckerContext *ctx, Scope *sc } } + if (other_scratch == nullptr && check_asm_reg_class_from_type(type) != AsmRegClass_Unknown) { + ed.kind = AsmTemplateEntityDecl_Register; + } + array_add(asm_template_entity_decls, ed); } else { TokenPos pos = found->token.pos; From a848739cf2c1f0d2e54133025f9042fb940eb7f0 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 15:52:40 +0100 Subject: [PATCH 18/20] Fix indirect call printing for asm amd64 --- src/llvm_backend_asm.cpp | 67 +++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/src/llvm_backend_asm.cpp b/src/llvm_backend_asm.cpp index eae2b6fc5..496c08fc6 100644 --- a/src/llvm_backend_asm.cpp +++ b/src/llvm_backend_asm.cpp @@ -9,11 +9,13 @@ struct lbAsmGenerate { gbString constraints; enum WriteOperandFlags : u32 { - WriteOperandFlag_PrintPrefixes = 1<<0, - WriteOperandFlag_IsScale = 1<<1, - WriteOperandFlag_IsScaleLog2 = 1<<2, + WriteOperandFlag_PrintPrefixes = 1<<0, + WriteOperandFlag_IsScale = 1<<1, + WriteOperandFlag_IsScaleLog2 = 1<<2, - WriteOperandFlag_Negate = 1<<3, + WriteOperandFlag_Negate = 1<<3, + + WriteOperandFlag_IndirectBranch = 1<<4, WriteOperandFlag_NONE = 0, WriteOperandFlag_DEFAULT = WriteOperandFlag_PrintPrefixes, @@ -237,13 +239,15 @@ struct lbAsmGenerate { this->write_instruction_mnemonic(instr); write_cstr(" "); + bool indirect = this->is_indirect_control_transfer(instr); // call/jmp with reg|mem target slot + isize n = instr->operands.count; for (isize k = 0; k < n; k += 1) { isize j = reverse ? (n-1-k) : k; - if (k > 0) { - write_cstr(", "); - } - this->write_operand(op_number, instr->operands[j], op_flags); + if (k > 0) { write_cstr(", "); } + u32 f = op_flags; + if (indirect) f |= WriteOperandFlag_IndirectBranch; + this->write_operand(op_number, instr->operands[j], f); } case_end; case_ast_node(label, AsmLabelDecl, instr_); @@ -468,13 +472,14 @@ struct lbAsmGenerate { } - virtual char const *class_letter (AsmRegClass rc) = 0; - virtual void write_constant_operand (Ast *op, u32 flags) = 0; - virtual void write_operand (Slice const &op_number, Ast *op, u32 flags) = 0; - virtual bool reverse_operand_order () = 0; // Intel dst-first -> AT&T src-first? - virtual void write_instruction_mnemonic(AstAsmInstruction *instr) = 0; // name (+ any suffix / spelling fixup) - virtual void write_memory_operand (Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) = 0; - virtual String flag_output_cc_suffix (String const &pin_flag) = 0; + virtual bool is_indirect_control_transfer(AstAsmInstruction *instr) = 0; + virtual char const *class_letter (AsmRegClass rc) = 0; + virtual void write_constant_operand (Ast *op, u32 flags) = 0; + virtual void write_operand (Slice const &op_number, Ast *op, u32 flags) = 0; + virtual bool reverse_operand_order () = 0; // Intel dst-first -> AT&T src-first? + virtual void write_instruction_mnemonic (AstAsmInstruction *instr) = 0; // name (+ any suffix / spelling fixup) + virtual void write_memory_operand (Slice const &op_number, AstAsmMemoryOperand *mem_op, u32 flags) = 0; + virtual String flag_output_cc_suffix (String const &pin_flag) = 0; }; @@ -507,6 +512,29 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { } } + bool is_indirect_control_transfer(AstAsmInstruction *instr) override { + switch (instr->mnemonic) { + case Asm_amd64::M_CALL: + case Asm_amd64::M_JMP: + break; + default: + return false; + } + auto forms = g_asm_amd64.encoding_forms(instr->mnemonic); + if (0 <= instr->valid_form_index && instr->valid_form_index < forms.count) { + auto const &form = forms[instr->valid_form_index]; + // call/jmp take a single explicit target operand. + AsmOperandKind k = g_asm_amd64.kind_from_operand_type(form.ops[0]); + switch (k) { + case AsmOperand_Register: + case AsmOperand_Memory: + case AsmOperand_Register_Or_Memory: + return true; + } + } + return false; + } + void write_instruction_mnemonic(AstAsmInstruction *instr) override { String name = instr->name->Ident.token.string; String att = this->instruction_att_mnemonic(instr); @@ -618,6 +646,11 @@ struct lbAsmGenerate_amd64 : lbAsmGenerate { return; } + if (flags & WriteOperandFlag_IndirectBranch) { + flags &= ~WriteOperandFlag_IndirectBranch; + write_cstr("*"); + } + if (flags & WriteOperandFlag_Negate) { flags &= ~WriteOperandFlag_Negate; write_cstr("-"); @@ -811,6 +844,10 @@ struct lbAsmGenerate_riscv64 : lbAsmGenerate { } } + bool is_indirect_control_transfer(AstAsmInstruction *instr) override { + return false; + } + // RISC-V immediates are bare integers (no '$' prefix); no scale/log2 forms exist. void write_constant_operand(Ast *op, u32 flags) override { GB_ASSERT(op->tav.mode == Addressing_Constant); From c6a4dd08fc09538486b5e0839a8c80dd8f5bcdee Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 15:57:45 +0100 Subject: [PATCH 19/20] Add `typename` to keep clang happy --- src/check_asm.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 3e48a0a9c..4bad35ba8 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -1055,7 +1055,7 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm if (arg_index < 0 || arg_index > 2) { return -1; } - auto want = cast(AsmCtx::AliasSrc)(asm_ctx->AliasSrc_ARG0 + arg_index); + auto want = cast(typename AsmCtx::AliasSrc)(asm_ctx->AliasSrc_ARG0 + arg_index); for (int i = 0; i < gb_count_of(a.src); i++) { if (a.src[i] == want) { return i; @@ -1071,7 +1071,7 @@ gb_internal void check_mnemonic(AsmCtx *asm_ctx, CheckerContext *ctx, Entity *tm return pseudo_alias_arg_operand_index(asm_ctx, alias, user_i); }; - auto operand_slot_type = [&](AsmCtx::Encoding const &form, int user_index) -> AsmCtx::OperandType { + auto operand_slot_type = [&](typename AsmCtx::Encoding const &form, int user_index) -> typename AsmCtx::OperandType { int raw_slot = -1; if (is_pseudo) { raw_slot = user_operand_target_index(user_index); From c26aa48ca50c8d2a60c379187644b643e74876da Mon Sep 17 00:00:00 2001 From: gingerBill Date: Fri, 21 Aug 2026 16:01:49 +0100 Subject: [PATCH 20/20] Support `+` `-` and `~` unary operators for asm operands --- src/check_asm.cpp | 7 +++++++ src/parser.cpp | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/check_asm.cpp b/src/check_asm.cpp index 4bad35ba8..69912c339 100644 --- a/src/check_asm.cpp +++ b/src/check_asm.cpp @@ -1476,6 +1476,13 @@ gb_internal void check_asm_instruction_operand(AsmCtx *asm_ctx, CheckerContext * gb_unused(label_scope); switch (expr->kind) { + case_ast_node(ue, UnaryExpr, expr); + check_expr(ctx, operand, expr); + if (operand->mode != Addressing_Constant) { + error(expr, "Asm operands within unary operands (+ - ~) can only compile time constants"); + } + return; + case_end; case_ast_node(pe, ParenExpr, expr); check_expr(ctx, operand, expr); if (operand->mode != Addressing_Constant) { diff --git a/src/parser.cpp b/src/parser.cpp index 572c638a2..64f73e0ab 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2484,6 +2484,16 @@ gb_internal Ast *parse_asm_operand(AstFile *f, bool allow_memory_operand) { case Token_Float: case Token_Rune: return ast_basic_lit(f, advance_token(f)); + + case Token_Add: + case Token_Sub: + case Token_Xor: + { + Token token = advance_token(f); + Ast *op = parse_asm_operand(f, false); + return ast_unary_expr(f, token, op); + } + case Token_OpenParen: return parse_expr(f, false); case Token_OpenBracket: