From c294977b3e5bdde919c8b2cc88b384273eea73c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Sat, 25 Apr 2026 23:42:01 +0300 Subject: [PATCH 1/9] lifting the base (integer) extension of RISC-V and some compressed variants of the instructions in it for 32-bit arch variant only, and add some tests --- librz/arch/il/analysis_il.c | 1 + librz/arch/isa/riscv/riscv_il.c | 292 +++++++++++++++++++++ librz/arch/isa/riscv/riscv_il.h | 20 ++ librz/arch/meson.build | 1 + librz/arch/p/analysis/analysis_riscv_cs.c | 10 +- test/db/asm/riscv_32 | 296 ++++++++++++---------- 6 files changed, 479 insertions(+), 141 deletions(-) create mode 100644 librz/arch/isa/riscv/riscv_il.c create mode 100644 librz/arch/isa/riscv/riscv_il.h diff --git a/librz/arch/il/analysis_il.c b/librz/arch/il/analysis_il.c index baf6224db62..e9dc8bf6e3a 100644 --- a/librz/arch/il/analysis_il.c +++ b/librz/arch/il/analysis_il.c @@ -193,6 +193,7 @@ static bool setup_regs(RzAnalysis *a, RzAnalysisILVM *vm, RzAnalysisILConfig *cf goto new_real; } succ = rz_reg_set_profile_string(reg, profile); + free(profile); if (!succ) { goto new_real; diff --git a/librz/arch/isa/riscv/riscv_il.c b/librz/arch/isa/riscv/riscv_il.c new file mode 100644 index 00000000000..37a2b1601eb --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il.c @@ -0,0 +1,292 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause +#include "analysis_private.h" +#include "riscv.h" +#include "rz_il/rz_il_opcodes.h" +#include "rz_types.h" +#include "rz_util/rz_assert.h" +#include +#include "riscv_il.h" + +#include +static const char *riscv_register_names[] = { + [RISCV_REG_X1] = "ra", + [RISCV_REG_X2] = "sp", + [RISCV_REG_X3] = "gp", + [RISCV_REG_X4] = "tp", + [RISCV_REG_X5] = "t0", + [RISCV_REG_X6] = "t1", + [RISCV_REG_X7] = "t2", + [RISCV_REG_X8] = "s0", + [RISCV_REG_X9] = "s1", + [RISCV_REG_X10] = "a0", + [RISCV_REG_X11] = "a1", + [RISCV_REG_X12] = "a2", + [RISCV_REG_X13] = "a3", + [RISCV_REG_X14] = "a4", + [RISCV_REG_X15] = "a5", + [RISCV_REG_X16] = "a6", + [RISCV_REG_X17] = "a7", + [RISCV_REG_X18] = "s2", + [RISCV_REG_X19] = "s3", + [RISCV_REG_X20] = "s4", + [RISCV_REG_X21] = "s5", + [RISCV_REG_X22] = "s6", + [RISCV_REG_X23] = "s7", + [RISCV_REG_X24] = "s8", + [RISCV_REG_X25] = "s9", + [RISCV_REG_X26] = "s10", + [RISCV_REG_X27] = "s11", + [RISCV_REG_X28] = "t3", + [RISCV_REG_X29] = "t4", + [RISCV_REG_X30] = "t5", + [RISCV_REG_X31] = "t6", +}; + +#define RISCV_GET_REG(reg) (((reg) != RISCV_REG_X0) ? (VARG(riscv_register_names[reg])) : UN(analysis->bits, 0)) +#define RISCV_SET_REG(reg, r) (((reg) != RISCV_REG_X0) ? (SETG(riscv_register_names[reg], r)) : ((rz_il_op_pure_free(r), NOP()))) + +#define DEFINE_LIFTER(name, decoder, result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { \ + decoder(analysis, insn); \ + return RISCV_SET_REG(rd, result); \ + } + +// by default, a RISC-V jump both sets a destination and sets the PC (i.e., jumps) +#define DEFINE_LIFTER_FOR_JUMP(name, decoder, result, jmp_effect) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { \ + decoder(analysis, insn); \ + return SEQ2( \ + RISCV_SET_REG(rd, result), \ + jmp_effect); \ + } + +#define DEFINE_LIFTER_WITH_EFFECT(name, decoder, effect) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { \ + decoder(analysis, insn); \ + return effect; \ + } + +// oneway jumps are those that don't have a destination register +#define DEFINE_LIFTER_FOR_ONEWAY_JUMP DEFINE_LIFTER_WITH_EFFECT + +#define TWICE_FOR(name1, name2, lifter, ...) \ + lifter(name1, __VA_ARGS__) \ + lifter(name2, __VA_ARGS__) + +#define THRICE_FOR(name1, name2, name3, lifter, ...) \ + TWICE_FOR(name1, name2, lifter, __VA_ARGS__) \ + lifter(name3, __VA_ARGS__) + +#define FOR_4(name1, name2, name3, name4, lifter, ...) \ + TWICE_FOR(name1, name2, lifter, __VA_ARGS__) \ + TWICE_FOR(name3, name4, lifter, __VA_ARGS__) + +#define DECODE_RD_RS_IMM(analysis, insn) \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[2].imm); + +#define DECODE_RD_RS_RS(analysis, insn) \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[2].reg); + +#define DECODE_RS_IMM(analysis, insn) \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].imm); + +#define DECODE_RS_RS_IMM(analysis, insn) \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[2].imm); + +#define DECODE_RD_RS(analysis, insn) \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); + +#define DECODE_IMM(analysis, insn) \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[0].imm); + +#define DECODE_RD_IMM(analysis, insn) \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].imm); + +#define DECODE_RS_RS_IMM_MEM(analysis, insn) \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +#define DECODE_RD_RS_IMM_MEM(analysis, insn) \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +#define USE_LIFTER(name, uppername) [RISCV_INS_##uppername] = rz_riscv_lift_##name + +FOR_4(addi, c_addi, c_addi16sp, c_addi4spn, + DEFINE_LIFTER, DECODE_RD_RS_IMM, ADD(rs, imm)) +TWICE_FOR(slli, c_slli, + DEFINE_LIFTER, DECODE_RD_RS_IMM, SHIFTL0(rs, imm)) +TWICE_FOR(andi, c_andi, + DEFINE_LIFTER, DECODE_RD_RS_IMM, LOGAND(rs, imm)) +DEFINE_LIFTER(ori, DECODE_RD_RS_IMM, LOGOR(rs, imm)) +DEFINE_LIFTER(xori, DECODE_RD_RS_IMM, LOGXOR(rs, imm)) +DEFINE_LIFTER(slti, DECODE_RD_RS_IMM, BOOL_TO_BV(SLT(rs, imm), analysis->bits)) +DEFINE_LIFTER(sltiu, DECODE_RD_RS_IMM, BOOL_TO_BV(ULT(rs, imm), analysis->bits)) +TWICE_FOR(srli, c_srli, + DEFINE_LIFTER, DECODE_RD_RS_IMM, SHIFTR0(rs, imm)) +TWICE_FOR(srai, c_srai, + DEFINE_LIFTER, DECODE_RD_RS_IMM, SHIFTRA(rs, imm)) + +DEFINE_LIFTER(add, DECODE_RD_RS_RS, ADD(rs1, rs2)) +DEFINE_LIFTER(sub, DECODE_RD_RS_RS, SUB(rs1, rs2)) +DEFINE_LIFTER(and, DECODE_RD_RS_RS, LOGAND(rs1, rs2)) +DEFINE_LIFTER(or, DECODE_RD_RS_RS, LOGOR(rs1, rs2)) +DEFINE_LIFTER(xor, DECODE_RD_RS_RS, LOGXOR(rs1, rs2)) +DEFINE_LIFTER(slt, DECODE_RD_RS_RS, BOOL_TO_BV(SLT(rs1, rs2), analysis->bits)) +DEFINE_LIFTER(sltu, DECODE_RD_RS_RS, BOOL_TO_BV(ULT(rs1, rs2), analysis->bits)) +DEFINE_LIFTER(sll, DECODE_RD_RS_RS, SHIFTL0(rs1, rs2)) +DEFINE_LIFTER(srl, DECODE_RD_RS_RS, SHIFTR0(rs1, rs2)) +DEFINE_LIFTER(sra, DECODE_RD_RS_RS, SHIFTRA(rs1, rs2)) + +#define DEFINE_LIFTER_FOR_BRANCH(name, decoder, condition) \ + DEFINE_LIFTER_FOR_ONEWAY_JUMP(name, decoder, BRANCH(condition, JMP(imm), JMP(UN(analysis->bits, current_addr + size)))) + +DEFINE_LIFTER_FOR_BRANCH(beq, DECODE_RS_RS_IMM, EQ(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(bne, DECODE_RS_RS_IMM, NE(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(blt, DECODE_RS_RS_IMM, SLT(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(bge, DECODE_RS_RS_IMM, SGE(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(bltu, DECODE_RS_RS_IMM, ULT(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(bgeu, DECODE_RS_RS_IMM, UGE(rs1, rs2)) + +DEFINE_LIFTER_FOR_BRANCH(c_beqz, DECODE_RS_IMM, EQ(rs, UN(analysis->bits, 0))) +DEFINE_LIFTER_FOR_BRANCH(c_bnez, DECODE_RS_IMM, NE(rs, UN(analysis->bits, 0))) + +DEFINE_LIFTER(c_mv, DECODE_RD_RS, DUP(rs)) + +DEFINE_LIFTER_FOR_ONEWAY_JUMP(c_j, DECODE_IMM, JMP(imm)) + +DEFINE_LIFTER_FOR_JUMP(jal, DECODE_RD_IMM, + /*RETURN ADDR*/ UN(analysis->bits, current_addr + size), + /*GOTO ADDR*/ JMP(imm)) + +TWICE_FOR(jalr, c_jr, + DEFINE_LIFTER_FOR_JUMP, DECODE_RD_RS_IMM, + /*RETURN ADDR*/ UN(analysis->bits, current_addr + size), + /*GOTO ADDR*/ JMP(LOGAND(ADD(rs, imm), UN(analysis->bits, ~1ULL)))) + +TWICE_FOR(lui, c_lui, + DEFINE_LIFTER, DECODE_RD_IMM, SHIFTL0(imm, UN(analysis->bits, 12))) +DEFINE_LIFTER(c_li, DECODE_RD_IMM, DUP(imm)) +DEFINE_LIFTER(auipc, DECODE_RD_IMM, ADD(UN(analysis->bits, current_addr), SHIFTL0(imm, UN(analysis->bits, 12)))) + +DEFINE_LIFTER_WITH_EFFECT(sb, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), CAST(8, IL_FALSE, rs1))) +DEFINE_LIFTER_WITH_EFFECT(sh, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), CAST(16, IL_FALSE, rs1))) + +THRICE_FOR(sw, c_sw, c_swsp, + DEFINE_LIFTER_WITH_EFFECT, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), analysis->bits == 32 ? rs1 : CAST(64, IL_FALSE, rs1))) + +TWICE_FOR(sd, c_sd, + DEFINE_LIFTER_WITH_EFFECT, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), rs1)) + +THRICE_FOR(lw, c_lwsp, c_lw, + DEFINE_LIFTER, DECODE_RD_RS_IMM_MEM, analysis->bits == 32 ? LOADW(32, ADD(rs, imm)) : SIGNED(analysis->bits, LOADW(32, ADD(rs, imm)))) +DEFINE_LIFTER(lb, DECODE_RD_RS_IMM_MEM, SIGNED(analysis->bits, LOADW(8, ADD(rs, imm)))) +DEFINE_LIFTER(lh, DECODE_RD_RS_IMM_MEM, SIGNED(analysis->bits, LOADW(16, ADD(rs, imm)))) +DEFINE_LIFTER(lbu, DECODE_RD_RS_IMM_MEM, UNSIGNED(analysis->bits, LOADW(8, ADD(rs, imm)))) +DEFINE_LIFTER(lhu, DECODE_RD_RS_IMM_MEM, UNSIGNED(analysis->bits, LOADW(16, ADD(rs, imm)))) + +TWICE_FOR(ld, c_ld, + DEFINE_LIFTER, DECODE_RD_RS_IMM_MEM, LOADW(64, ADD(rs, imm))) + +#include + +static const RiscvInstructionLifter riscv_lifters[] = { + USE_LIFTER(addi, ADDI), + USE_LIFTER(c_addi, C_ADDI), + USE_LIFTER(c_addi16sp, C_ADDI16SP), + USE_LIFTER(c_addi4spn, C_ADDI4SPN), + USE_LIFTER(andi, ANDI), + USE_LIFTER(c_andi, C_ANDI), + USE_LIFTER(ori, ORI), + USE_LIFTER(xori, XORI), + USE_LIFTER(slti, SLTI), + USE_LIFTER(sltiu, SLTIU), + USE_LIFTER(slli, SLLI), + USE_LIFTER(srli, SRLI), + USE_LIFTER(srai, SRAI), + USE_LIFTER(c_slli, C_SLLI), + USE_LIFTER(c_srli, C_SRLI), + USE_LIFTER(c_srai, C_SRAI), + USE_LIFTER(jalr, JALR), + USE_LIFTER(c_jr, C_JR), + USE_LIFTER(lb, LB), + USE_LIFTER(lh, LH), + USE_LIFTER(lw, LW), + USE_LIFTER(lbu, LBU), + USE_LIFTER(lhu, LHU), + USE_LIFTER(c_lwsp, C_LWSP), + USE_LIFTER(c_lw, C_LW), + USE_LIFTER(ld, LD), + USE_LIFTER(c_ld, C_LD), + USE_LIFTER(lui, LUI), + USE_LIFTER(c_lui, C_LUI), + USE_LIFTER(c_li, C_LI), + USE_LIFTER(auipc, AUIPC), + USE_LIFTER(beq, BEQ), + USE_LIFTER(bne, BNE), + USE_LIFTER(blt, BLT), + USE_LIFTER(bge, BGE), + USE_LIFTER(bltu, BLTU), + USE_LIFTER(bgeu, BGEU), + USE_LIFTER(c_beqz, C_BEQZ), + USE_LIFTER(c_bnez, C_BNEZ), + USE_LIFTER(sb, SB), + USE_LIFTER(sh, SH), + USE_LIFTER(sw, SW), + USE_LIFTER(c_sw, C_SW), + USE_LIFTER(c_swsp, C_SWSP), + USE_LIFTER(sd, SD), + USE_LIFTER(c_sd, C_SD), + USE_LIFTER(add, ADD), + USE_LIFTER(sub, SUB), + USE_LIFTER(and, AND), + USE_LIFTER(or, OR), + USE_LIFTER(xor, XOR), + USE_LIFTER(slt, SLT), + USE_LIFTER(sltu, SLTU), + USE_LIFTER(sll, SLL), + USE_LIFTER(srl, SRL), + USE_LIFTER(sra, SRA), + USE_LIFTER(jal, JAL), + USE_LIFTER(c_mv, C_MV), + USE_LIFTER(c_j, C_J), +}; + +RZ_OWN RZ_IPI RzILOpEffect * +rz_riscv_lift_instr(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { + rz_return_val_if_fail(analysis && op && insn, NULL); + + if (insn->id > 0 && insn->id < RZ_ARRAY_SIZE(riscv_lifters)) { + RiscvInstructionLifter lifter = riscv_lifters[insn->id]; + if (lifter) { + return lifter(analysis, op, insn, current_addr, size); + } else { + RZ_LOG_ERROR("No lifter found for instruction %s (id: %d) (0x%08x)", insn->mnemonic, insn->id, rz_read_le32(insn->bytes)); + } + } + rz_warn_if_reached(); + return NULL; +} + +RZ_IPI RzAnalysisILConfig *rz_riscv_il_config(RZ_NONNULL RzAnalysis *analysis) { + rz_return_val_if_fail(analysis, NULL); + + RzAnalysisILConfig *conf = rz_analysis_il_config_new(analysis->bits, analysis->big_endian, analysis->bits); + + return conf; +} \ No newline at end of file diff --git a/librz/arch/isa/riscv/riscv_il.h b/librz/arch/isa/riscv/riscv_il.h new file mode 100644 index 00000000000..eb398ed9042 --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RZ_ARCH_ISA_RISCV_IL_H +#define RZ_ARCH_ISA_RISCV_IL_H + +#include +#include + +#include +#include +typedef RzILOpEffect *(*RiscvInstructionLifter)(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size); + +RZ_OWN RZ_IPI RzILOpEffect * +rz_riscv_lift_instr(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size); + +RZ_IPI RzAnalysisILConfig *rz_riscv_il_config(RZ_NONNULL RzAnalysis *analysis); + +#endif \ No newline at end of file diff --git a/librz/arch/meson.build b/librz/arch/meson.build index 5366e3b45b3..d5c0be1ab8f 100644 --- a/librz/arch/meson.build +++ b/librz/arch/meson.build @@ -302,6 +302,7 @@ arch_isa_sources = [ 'isa/pyc/opcode_analysis.c', 'isa/pyc/opcode_arg_fmt.c', 'isa/pyc/pyc_dis.c', + 'isa/riscv/riscv_il.c', 'isa/rl78/rl78.c', 'isa/rl78/rl78_instr.c', 'isa/rl78/rl78_maps.c', diff --git a/librz/arch/p/analysis/analysis_riscv_cs.c b/librz/arch/p/analysis/analysis_riscv_cs.c index aa6725346b9..545378548b4 100644 --- a/librz/arch/p/analysis/analysis_riscv_cs.c +++ b/librz/arch/p/analysis/analysis_riscv_cs.c @@ -14,6 +14,8 @@ #include "analysis_riscv_utils.h" #include +#include + #define OPERAND(x) insn->detail->riscv.operands[x] #define REGID(x) insn->detail->riscv.operands[x].reg #define REG(x) cs_reg_name(*handle, insn->detail->riscv.operands[x].reg) @@ -1922,6 +1924,11 @@ int analyze_op(RzAnalysis *analysis, RzAnalysisOp *op, ut64 addr, const ut8 *buf set_op_family(op, insn); set_op_extra_metadata(analysis, op, ctx->hndl, insn); set_stack_effect(op, insn); + + if (mask & RZ_ANALYSIS_OP_MASK_IL) { + RzILOpEffect *il_op = rz_riscv_lift_instr(analysis, op, insn, addr, op->size); + op->il_op = il_op; + } } set_opdir(op); if (insn && mask & RZ_ANALYSIS_OP_MASK_OPEX) { @@ -2148,7 +2155,7 @@ static char *get_reg_profile(RzAnalysis *analysis) { "gpr ft9 .64 488 0\n" // =f29 "gpr ft10 .64 496 0\n" // =f30 "gpr ft11 .64 504 0\n" // =f31 - "gpr fcsr .32 512 0\n" + "gpr fcsr .64 512 0\n" // vector registers // assume each register is 512 bits (64 bytes) for maximum compatibility // TODO: make the width accurately reflect the exact width defined in the binary @@ -2276,6 +2283,7 @@ RzAnalysisPlugin rz_analysis_plugin_riscv_cs = { .archinfo = archinfo, .bits = 32 | 64, .op = &analyze_op, + .il_config = rz_riscv_il_config, .init = riscv_init, .fini = riscv_fini, }; diff --git a/test/db/asm/riscv_32 b/test/db/asm/riscv_32 index 29165a9578d..269ff99bf7a 100644 --- a/test/db/asm/riscv_32 +++ b/test/db/asm/riscv_32 @@ -1,138 +1,145 @@ -d "addi sp, sp, -0x90" 7571 -d "lui a5, 0x10" c167 -d "sw a5, 0x1c(sp)" 3ece -d "lui a5, 0x30" b7070300 -d "sw a5, 0x24(sp)" 3ed2 -d "lui a5, 0xc" b167 -d "sw a5, 0x3c(sp)" 3ede -d "lui a5, 0xffff8" e177 -d "sw s1, 0x84(sp)" 26c3 -d "sw ra, 0x8c(sp)" 06c7 -d "sw s0, 0x88(sp)" 22c5 -d "sw s2, 0x80(sp)" 4ac1 -d "sw s3, 0x7c(sp)" cede -d "sw s4, 0x78(sp)" d2dc -d "sw s5, 0x74(sp)" d6da -d "sw s6, 0x70(sp)" dad8 -d "sw s7, 0x6c(sp)" ded6 -d "sw s8, 0x68(sp)" e2d4 -d "sw s9, 0x64(sp)" e6d2 -d "sw s10, 0x60(sp)" ead0 -d "sw s11, 0x5c(sp)" eece -d "sw zero, 0x28(sp)" 02d4 -d "sw zero, 0x20(sp)" 02d0 -d "sw zero, 0x38(sp)" 02dc -d "sw zero, 0x30(sp)" 02d8 -d "sw a5, 0x34(sp)" 3eda -d "sw zero, 0x18(sp)" 02cc -d "lui s1, 0x40" b7040400 0x38 -d "lui a5, 0x10013" b7370110 -d "lw a5, 4(a5)" dc43 0x40 -d "blez a5, 0x64" 6351f002 0x42 -d "lw ra, 0x8c(sp)" ba40 0x40 -d "lw s0, 0x88(sp)" 2a44 0x40 -d "lw s1, 0x84(sp)" 9a44 0x40 -d "lw s2, 0x80(sp)" 0a49 0x40 -d "lw s3, 0x7c(sp)" f659 0x40 -d "lw s4, 0x78(sp)" 665a 0x44 -d "lw s5, 0x74(sp)" d65a 0x48 -d "lw s6, 0x70(sp)" 465b 0x40 -d "lw s7, 0x6c(sp)" b65b 0x40 -d "lw s8, 0x68(sp)" 265c 0x40 -d "lw s9, 0x64(sp)" 965c 0x40 -d "lw s10, 0x60(sp)" 065d 0x40 -d "lw s11, 0x5c(sp)" f64d 0x40 +# ----------------------------- C_ADDI16SP ----------------------------- +d "addi sp, sp, -0x90" 7571 0x0 (set sp (+ (var sp) (bv 32 0xffffff70))) +# ----------------------------- ADDI ----------------------------- +d "addi a1, a1, 0x700" 93850570 0x0 (set a1 (+ (var a1) (bv 32 0x700))) +# ----------------------------- C_ADDI4SPN ----------------------------- +d "addi s0, sp, 0x80" 0001 0x0 (set s0 (+ (var sp) (bv 32 0x80))) +# ----------------------------- C_ADDI --------------------------------- +d "addi sp, sp, -0x20" 0111 0x0 (set sp (+ (var sp) (bv 32 0xffffffe0))) +d "lui a5, 0x10" c167 0x0 (set a5 (<< (bv 32 0x10) (bv 32 0xc) false)) +d "sw a5, 0x1c(sp)" 3ece 0x0 (storew 0 (+ (var sp) (bv 32 0x1c)) (var a5)) +d "lui a5, 0x30" b7070300 0x0 (set a5 (<< (bv 32 0x30) (bv 32 0xc) false)) +d "sw a5, 0x24(sp)" 3ed2 0x0 (storew 0 (+ (var sp) (bv 32 0x24)) (var a5)) +d "lui a5, 0xc" b167 0x0 (set a5 (<< (bv 32 0xc) (bv 32 0xc) false)) +d "sw a5, 0x3c(sp)" 3ede 0x0 (storew 0 (+ (var sp) (bv 32 0x3c)) (var a5)) +d "lui a5, 0xffff8" e177 0x0 (set a5 (<< (bv 32 0xffff8) (bv 32 0xc) false)) +d "sw s1, 0x84(sp)" 26c3 0x0 (storew 0 (+ (var sp) (bv 32 0x84)) (var s1)) +d "sw ra, 0x8c(sp)" 06c7 0x0 (storew 0 (+ (var sp) (bv 32 0x8c)) (var ra)) +d "sw s0, 0x88(sp)" 22c5 0x0 (storew 0 (+ (var sp) (bv 32 0x88)) (var s0)) +d "sw s2, 0x80(sp)" 4ac1 0x0 (storew 0 (+ (var sp) (bv 32 0x80)) (var s2)) +d "sw s3, 0x7c(sp)" cede 0x0 (storew 0 (+ (var sp) (bv 32 0x7c)) (var s3)) +d "sw s4, 0x78(sp)" d2dc 0x0 (storew 0 (+ (var sp) (bv 32 0x78)) (var s4)) +d "sw s5, 0x74(sp)" d6da 0x0 (storew 0 (+ (var sp) (bv 32 0x74)) (var s5)) +d "sw s6, 0x70(sp)" dad8 0x0 (storew 0 (+ (var sp) (bv 32 0x70)) (var s6)) +d "sw s7, 0x6c(sp)" ded6 0x0 (storew 0 (+ (var sp) (bv 32 0x6c)) (var s7)) +d "sw s8, 0x68(sp)" e2d4 0x0 (storew 0 (+ (var sp) (bv 32 0x68)) (var s8)) +d "sw s9, 0x64(sp)" e6d2 0x0 (storew 0 (+ (var sp) (bv 32 0x64)) (var s9)) +d "sw s10, 0x60(sp)" ead0 0x0 (storew 0 (+ (var sp) (bv 32 0x60)) (var s10)) +d "sw s11, 0x5c(sp)" eece 0x0 (storew 0 (+ (var sp) (bv 32 0x5c)) (var s11)) +d "sw zero, 0x28(sp)" 02d4 0x0 (storew 0 (+ (var sp) (bv 32 0x28)) (bv 32 0x0)) +d "sw zero, 0x20(sp)" 02d0 0x0 (storew 0 (+ (var sp) (bv 32 0x20)) (bv 32 0x0)) +d "sw zero, 0x38(sp)" 02dc 0x0 (storew 0 (+ (var sp) (bv 32 0x38)) (bv 32 0x0)) +d "sw zero, 0x30(sp)" 02d8 0x0 (storew 0 (+ (var sp) (bv 32 0x30)) (bv 32 0x0)) +d "sw a5, 0x34(sp)" 3eda 0x0 (storew 0 (+ (var sp) (bv 32 0x34)) (var a5)) +d "sw zero, 0x18(sp)" 02cc 0x0 (storew 0 (+ (var sp) (bv 32 0x18)) (bv 32 0x0)) +d "lui s1, 0x40" b7040400 0x38 (set s1 (<< (bv 32 0x40) (bv 32 0xc) false)) +d "lui a5, 0x10013" b7370110 0x0 (set a5 (<< (bv 32 0x10013) (bv 32 0xc) false)) +d "lw a5, 4(a5)" dc43 0x40 (set a5 (loadw 0 32 (+ (var a5) (bv 32 0x4)))) +d "blez a5, 0x64" 6351f002 0x42 (branch (|| (! (sle (bv 32 0x0) (var a5))) (== (bv 32 0x0) (var a5))) (jmp (bv 32 0x64)) (jmp (bv 32 0x46))) +d "lw ra, 0x8c(sp)" ba40 0x40 (set ra (loadw 0 32 (+ (var sp) (bv 32 0x8c)))) +d "lw s0, 0x88(sp)" 2a44 0x40 (set s0 (loadw 0 32 (+ (var sp) (bv 32 0x88)))) +d "lw s1, 0x84(sp)" 9a44 0x40 (set s1 (loadw 0 32 (+ (var sp) (bv 32 0x84)))) +d "lw s2, 0x80(sp)" 0a49 0x40 (set s2 (loadw 0 32 (+ (var sp) (bv 32 0x80)))) +d "lw s3, 0x7c(sp)" f659 0x40 (set s3 (loadw 0 32 (+ (var sp) (bv 32 0x7c)))) +d "lw s4, 0x78(sp)" 665a 0x44 (set s4 (loadw 0 32 (+ (var sp) (bv 32 0x78)))) +d "lw s5, 0x74(sp)" d65a 0x48 (set s5 (loadw 0 32 (+ (var sp) (bv 32 0x74)))) +d "lw s6, 0x70(sp)" 465b 0x40 (set s6 (loadw 0 32 (+ (var sp) (bv 32 0x70)))) +d "lw s7, 0x6c(sp)" b65b 0x40 (set s7 (loadw 0 32 (+ (var sp) (bv 32 0x6c)))) +d "lw s8, 0x68(sp)" 265c 0x40 (set s8 (loadw 0 32 (+ (var sp) (bv 32 0x68)))) +d "lw s9, 0x64(sp)" 965c 0x40 (set s9 (loadw 0 32 (+ (var sp) (bv 32 0x64)))) +d "lw s10, 0x60(sp)" 065d 0x40 (set s10 (loadw 0 32 (+ (var sp) (bv 32 0x60)))) +d "lw s11, 0x5c(sp)" f64d 0x40 (set s11 (loadw 0 32 (+ (var sp) (bv 32 0x5c)))) d "addi sp, sp, 0x90" 4961 0x40 -d "ret" 8280 0x40 -d "lw a5, 0x18(sp)" e247 0x40 +d "ret" 8280 0x40 NONE +d "lw a5, 0x18(sp)" e247 0x40 (set a5 (loadw 0 32 (+ (var sp) (bv 32 0x18)))) d "beqz a5, 0x2d8" 63890726 0x66 -d "lw s0, 0x1c(sp)" 7244 0x40 -d "lw a0, 0x24(sp)" 1255 0x40 -d "lw a6, 0x28(sp)" 2258 0x40 -d "lw t3, 0x38(sp)" 625e 0x40 +d "lw s0, 0x1c(sp)" 7244 0x40 (set s0 (loadw 0 32 (+ (var sp) (bv 32 0x1c)))) +d "lw a0, 0x24(sp)" 1255 0x40 (set a0 (loadw 0 32 (+ (var sp) (bv 32 0x24)))) +d "lw a6, 0x28(sp)" 2258 0x40 (set a6 (loadw 0 32 (+ (var sp) (bv 32 0x28)))) +d "lw t3, 0x38(sp)" 625e 0x40 (set t3 (loadw 0 32 (+ (var sp) (bv 32 0x38)))) d "srai a5, s0, 0x1f" 9357f441 0x40 -d "lw a2, 0x20(sp)" 0256 0x40 -d "andi a5, a5, 0xf" bd8b 0x40 +d "lw a2, 0x20(sp)" 0256 0x40 (set a2 (loadw 0 32 (+ (var sp) (bv 32 0x20)))) +d "andi a5, a5, 0xf" bd8b 0x40 (set a5 (& (var a5) (bv 32 0xf))) d "srai a4, a0, 0x1f" 1357f541 0x40 -d "lw a7, 0x30(sp)" c258 0x40 -d "add a3, a5, a6" b3860701 0x80 -d "sub s2, t3, a6" 33090e41 0x80 -d "andi a4, a4, 0x3f" 1377f703 0x80 -d "lw a6, 0x34(sp)" 5258 0x80 -d "add a1, a4, a2" b305c700 0x80 -d "sltu a4, a1, a4" 33b7e500 0x80 -d "sub a2, a7, a2" 3386c840 0x80 -d "sltu s7, a3, a5" b3bbf600 0x80 -d "sltu a7, a7, a2" b3b8c800 0x80 -d "add a5, a4, a0" b307a700 0x80 -d "mv a4, a2" 3287 0x80 -d "sub a2, a6, a0" 3306a840 0x80 -d "sltu a6, t3, s2" 33382e01 0x80 -d "lw t3, 0x3c(sp)" 725e 0x80 -d "mv t1, a0" 2a83 0x80 -d "srli a1, a1, 6" 9981 0x80 -d "slli a0, a5, 0x1a" 1395a701 0x80 -d "sw a4, 0x40(sp)" bac0 0x80 -d "sub a4, a2, a7" 33071641 0x80 -d "add s7, s7, s0" a29b 0xc0 -d "sw a4, 0x44(sp)" bac2 0xc0 -d "srai a5, a5, 6" 9987 0xc0 -d "or a4, a0, a1" 3367b500 0xc0 -d "slli s8, s7, 0x1c" 139ccb01 0xc0 -d "sub s0, t3, s0" 33048e40 0xc0 -d "srli a3, a3, 4" 9182 0xc0 -d "sw a4, 0x10(sp)" 3ac8 0xc0 -d "sw a5, 0x14(sp)" 3eca 0xc0 -d "lui a4, 1" 0567 0xc0 -d "sub s0, s0, a6" 33040441 0xc0 -d "or s8, s8, a3" 336cdc00 0xc0 -d "srai s7, s7, 4" 93db4b40 0xc0 -d "blt t1, a4, 0x2d4" 6347e31e 0xe6 -d "lw a5, 0x1c(sp)" f247 0xc0 -d "lui a4, 1" 0567 0xc0 -d "blt a5, a4, 0x2d4" 63c3e71e 0xee -d "srli a5, s8, 0x1d" 9357dc01 0xc0 -d "slli a4, s7, 3" 13973b00 0xc0 -d "or a5, a5, a4" d98f 0xc0 -d "sw a5, 0x4c(sp)" bec6 0xc0 -d "slli a5, s8, 3" 93173c00 0xc0 -d "addi a5, sp, 8" 3c00 0x100 -d "li s11, 0xff" 930df00f 0x100 -d "sw a5, 0x48(sp)" bec4 0x100 -d "sw s2, 0xc(sp)" 4ac6 0x100 -d "li a5, 4" 9147 0x100 -d "li s2, 0" 0149 0x100 -d "mv s3, s11" ee89 0x100 -d "sw a5, 0x2c(sp)" 3ed6 0x100 -d "li s6, 0x10" 414b 0x100 -d "li s9, 8" a14c 0x100 -d "mv s11, s2" ca8d 0x100 -d "lw s10, 0x40(sp)" 064d 0x100 -d "lw s5, 0x44(sp)" 964a 0x100 -d "li s2, 0x80" 13090008 0x100 -d "mv s4, s3" 4e8a 0x100 -d "mv s3, s2" ca89 0x100 -d "lw t2, 0xc(sp)" b243 0x100 -d "mv t6, s0" a28f 0x100 -d "li ra, 0" 8140 0x100 -d "li s2, 0" 0149 0x100 -d "li a1, 0" 8145 0x100 -d "li a4, 0" 0147 0x100 -d "li t3, 0" 014e 0x100 -d "li a6, 0" 0148 0x100 -d "li a5, 0" 8147 0x100 -d "li a3, 0" 8146 0x100 -d "li t1, 0" 0143 0x100 -d "li a2, 0" 0146 0x100 -d "li a0, 0" 0145 0x100 -d "j 0x176" 25a8 0x13e +d "lw a7, 0x30(sp)" c258 0x40 (set a7 (loadw 0 32 (+ (var sp) (bv 32 0x30)))) +d "add a3, a5, a6" b3860701 0x80 (set a3 (+ (var a5) (var a6))) +d "sub s2, t3, a6" 33090e41 0x80 (set s2 (- (var t3) (var a6))) +d "andi a4, a4, 0x3f" 1377f703 0x80 (set a4 (& (var a4) (bv 32 0x3f))) +d "lw a6, 0x34(sp)" 5258 0x80 (set a6 (loadw 0 32 (+ (var sp) (bv 32 0x34)))) +d "add a1, a4, a2" b305c700 0x80 (set a1 (+ (var a4) (var a2))) +d "sltu a4, a1, a4" 33b7e500 0x80 (set a4 (ite (&& (ule (var a1) (var a4)) (! (== (var a1) (var a4)))) (bv 32 0x1) (bv 32 0x0))) +d "sub a2, a7, a2" 3386c840 0x80 (set a2 (- (var a7) (var a2))) +d "sltu s7, a3, a5" b3bbf600 0x80 (set s7 (ite (&& (ule (var a3) (var a5)) (! (== (var a3) (var a5)))) (bv 32 0x1) (bv 32 0x0))) +d "sltu a7, a7, a2" b3b8c800 0x80 (set a7 (ite (&& (ule (var a7) (var a2)) (! (== (var a7) (var a2)))) (bv 32 0x1) (bv 32 0x0))) +d "add a5, a4, a0" b307a700 0x80 (set a5 (+ (var a4) (var a0))) +d "mv a4, a2" 3287 0x80 (set a4 (var a2)) +d "sub a2, a6, a0" 3306a840 0x80 (set a2 (- (var a6) (var a0))) +d "sltu a6, t3, s2" 33382e01 0x80 (set a6 (ite (&& (ule (var t3) (var s2)) (! (== (var t3) (var s2)))) (bv 32 0x1) (bv 32 0x0))) +d "lw t3, 0x3c(sp)" 725e 0x80 (set t3 (loadw 0 32 (+ (var sp) (bv 32 0x3c)))) +d "mv t1, a0" 2a83 0x80 (set t1 (var a0)) +d "srli a1, a1, 6" 9981 0x80 (set a1 (>> (var a1) (bv 32 0x6) false)) +d "slli a0, a5, 0x1a" 1395a701 0x80 (set a0 (<< (var a5) (bv 32 0x1a) false)) +d "sw a4, 0x40(sp)" bac0 0x80 (storew 0 (+ (var sp) (bv 32 0x40)) (var a4)) +d "sub a4, a2, a7" 33071641 0x80 (set a4 (- (var a2) (var a7))) +d "add s7, s7, s0" a29b 0xc0 NONE +d "sw a4, 0x44(sp)" bac2 0xc0 (storew 0 (+ (var sp) (bv 32 0x44)) (var a4)) +d "srai a5, a5, 6" 9987 0xc0 (set a5 (>> (var a5) (bv 32 0x6) (msb (var a5)))) +d "or a4, a0, a1" 3367b500 0xc0 (set a4 (| (var a0) (var a1))) +d "slli s8, s7, 0x1c" 139ccb01 0xc0 (set s8 (<< (var s7) (bv 32 0x1c) false)) +d "sub s0, t3, s0" 33048e40 0xc0 (set s0 (- (var t3) (var s0))) +d "srli a3, a3, 4" 9182 0xc0 (set a3 (>> (var a3) (bv 32 0x4) false)) +d "sw a4, 0x10(sp)" 3ac8 0xc0 (storew 0 (+ (var sp) (bv 32 0x10)) (var a4)) +d "sw a5, 0x14(sp)" 3eca 0xc0 (storew 0 (+ (var sp) (bv 32 0x14)) (var a5)) +d "lui a4, 1" 0567 0xc0 (set a4 (<< (bv 32 0x1) (bv 32 0xc) false)) +d "sub s0, s0, a6" 33040441 0xc0 (set s0 (- (var s0) (var a6))) +d "or s8, s8, a3" 336cdc00 0xc0 (set s8 (| (var s8) (var a3))) +d "srai s7, s7, 4" 93db4b40 0xc0 (set s7 (>> (var s7) (bv 32 0x4) (msb (var s7)))) +d "blt t1, a4, 0x2d4" 6347e31e 0xe6 (branch (&& (sle (var t1) (var a4)) (! (== (var t1) (var a4)))) (jmp (bv 32 0x2d4)) (jmp (bv 32 0xea))) +d "lw a5, 0x1c(sp)" f247 0xc0 (set a5 (loadw 0 32 (+ (var sp) (bv 32 0x1c)))) +d "lui a4, 1" 0567 0xc0 (set a4 (<< (bv 32 0x1) (bv 32 0xc) false)) +d "blt a5, a4, 0x2d4" 63c3e71e 0xee (branch (&& (sle (var a5) (var a4)) (! (== (var a5) (var a4)))) (jmp (bv 32 0x2d4)) (jmp (bv 32 0xf2))) +d "srli a5, s8, 0x1d" 9357dc01 0xc0 (set a5 (>> (var s8) (bv 32 0x1d) false)) +d "slli a4, s7, 3" 13973b00 0xc0 (set a4 (<< (var s7) (bv 32 0x3) false)) +d "or a5, a5, a4" d98f 0xc0 NONE +d "sw a5, 0x4c(sp)" bec6 0xc0 (storew 0 (+ (var sp) (bv 32 0x4c)) (var a5)) +d "slli a5, s8, 3" 93173c00 0xc0 (set a5 (<< (var s8) (bv 32 0x3) false)) +d "addi a5, sp, 8" 3c00 0x100 (set a5 (+ (var sp) (bv 32 0x8))) +d "li s11, 0xff" 930df00f 0x100 (set s11 (+ (bv 32 0x0) (bv 32 0xff))) +d "sw a5, 0x48(sp)" bec4 0x100 (storew 0 (+ (var sp) (bv 32 0x48)) (var a5)) +d "sw s2, 0xc(sp)" 4ac6 0x100 (storew 0 (+ (var sp) (bv 32 0xc)) (var s2)) +d "li a5, 4" 9147 0x100 (set a5 (bv 32 0x4)) +d "li s2, 0" 0149 0x100 (set s2 (bv 32 0x0)) +d "mv s3, s11" ee89 0x100 (set s3 (var s11)) +d "sw a5, 0x2c(sp)" 3ed6 0x100 (storew 0 (+ (var sp) (bv 32 0x2c)) (var a5)) +d "li s6, 0x10" 414b 0x100 (set s6 (bv 32 0x10)) +d "li s9, 8" a14c 0x100 (set s9 (bv 32 0x8)) +d "mv s11, s2" ca8d 0x100 (set s11 (var s2)) +d "lw s10, 0x40(sp)" 064d 0x100 (set s10 (loadw 0 32 (+ (var sp) (bv 32 0x40)))) +d "lw s5, 0x44(sp)" 964a 0x100 (set s5 (loadw 0 32 (+ (var sp) (bv 32 0x44)))) +d "li s2, 0x80" 13090008 0x100 (set s2 (+ (bv 32 0x0) (bv 32 0x80))) +d "mv s4, s3" 4e8a 0x100 (set s4 (var s3)) +d "mv s3, s2" ca89 0x100 (set s3 (var s2)) +d "lw t2, 0xc(sp)" b243 0x100 (set t2 (loadw 0 32 (+ (var sp) (bv 32 0xc)))) +d "mv t6, s0" a28f 0x100 (set t6 (var s0)) +d "li ra, 0" 8140 0x100 (set ra (bv 32 0x0)) +d "li s2, 0" 0149 0x100 (set s2 (bv 32 0x0)) +d "li a1, 0" 8145 0x100 (set a1 (bv 32 0x0)) +d "li a4, 0" 0147 0x100 (set a4 (bv 32 0x0)) +d "li t3, 0" 014e 0x100 (set t3 (bv 32 0x0)) +d "li a6, 0" 0148 0x100 (set a6 (bv 32 0x0)) +d "li a5, 0" 8147 0x100 (set a5 (bv 32 0x0)) +d "li a3, 0" 8146 0x100 (set a3 (bv 32 0x0)) +d "li t1, 0" 0143 0x100 (set t1 (bv 32 0x0)) +d "li a2, 0" 0146 0x100 (set a2 (bv 32 0x0)) +d "li a0, 0" 0145 0x100 (set a0 (bv 32 0x0)) +d "j 0x176" 25a8 0x13e (jmp (bv 32 0x176)) d "mul a4, a0, a2" 3307c502 0x140 d "mulhu t1, a2, a2" 3333c602 0x140 -d "slli a4, a4, 1" 0607 0x140 +d "slli a4, a4, 1" 0607 0x140 (set a4 (<< (var a4) (bv 32 0x1) false)) d "mul a7, a5, a6" b3880703 0x140 d "add t1, t1, a4" 3a93 0x140 d "mul a3, a2, a2" b306c602 0x140 -d "slli a7, a7, 1" 8608 0x140 +d "slli a7, a7, 1" 8608 0x140 (set a7 (<< (var a7) (bv 32 0x1) false)) d "mulhu t3, a6, a6" 333e0803 0x140 d "mul a4, a6, a6" 33070803 0x140 d "add t3, t3, a7" 469e 0x140 @@ -140,8 +147,8 @@ d "add t5, t1, t3" 330fc301 0x140 d "add t4, a3, a4" b38ee600 0x140 d "sltu a7, t4, a3" b3b8de00 0x140 d "add a7, a7, t5" fa98 0x140 -d "blt s1, a7, 0x2c6" 63cc1415 0x16e -d "beq a7, s1, 0x2c2" 63889814 0x172 +d "blt s1, a7, 0x2c6" 63cc1415 0x16e (branch (&& (sle (var s1) (var a7)) (! (== (var s1) (var a7)))) (jmp (bv 32 0x2c6)) (jmp (bv 32 0x172))) +d "beq a7, s1, 0x2c2" 63889814 0x172 (branch (== (var a7) (var s1)) (jmp (bv 32 0x2c2)) (jmp (bv 32 0x176))) d "sub a4, a3, a4" 3387e640 0x140 d "sub t3, t1, t3" 330ec341 0x140 d "sltu a3, ra, zero" b3b60000 0x140 @@ -151,35 +158,44 @@ d "sltu a4, a7, a4" 33b7e800 0x180 d "add a3, a3, s5" d696 0x180 d "add a3, a3, a4" ba96 0x180 d "mul a5, a5, a2" b387c702 0x180 -d "slli t1, a3, 8" 13938600 0x180 -d "addi a1, a1, 1" 8505 0x180 +d "slli t1, a3, 8" 13938600 0x180 (set t1 (<< (var a3) (bv 32 0x8) false)) +d "addi a1, a1, 1" 8505 0x180 (set a1 (+ (var a1) (bv 32 0x1))) d "mul a4, a0, a6" 33070503 0x180 -d "srai a0, a3, 0x18" 13d58641 0x180 +d "srai a0, a3, 0x18" 13d58641 0x180 (set a0 (>> (var a3) (bv 32 0x18) (msb (var a3)))) d "mulhu a3, a6, a2" b336c802 0x180 d "add a4, a4, a5" 3e97 0x180 d "mul a6, a6, a2" 3308c802 0x180 d "add a4, a4, a3" 3697 0x180 -d "srli a2, a7, 0x18" 13d68801 0x180 -d "slli a4, a4, 1" 0607 0x180 +d "srli a2, a7, 0x18" 13d68801 0x180 (set a2 (>> (var a7) (bv 32 0x18) false)) +d "slli a4, a4, 1" 0607 0x180 (set a4 (<< (var a4) (bv 32 0x1) false)) d "or a2, t1, a2" 3366c300 0x180 -d "slli a7, a6, 1" 93181800 0x180 -d "srli a3, a6, 0x1f" 9356f801 0x180 +d "slli a7, a6, 1" 93181800 0x180 (set a7 (<< (var a6) (bv 32 0x1) false)) +d "srli a3, a6, 0x1f" 9356f801 0x180 (set a3 (>> (var a6) (bv 32 0x1f) false)) d "add a5, a7, t2" b3877800 0x1c0 d "or a4, a4, a3" 558f 0x1c0 -d "srli a6, a5, 0x18" 13d88701 0x1c0 +d "srli a6, a5, 0x18" 13d88701 0x1c0 (set a6 (>> (var a5) (bv 32 0x18) false)) d "add a4, a4, t6" 7e97 0x1c0 d "sltu a5, a5, a7" b3b71701 0x1c0 d "add a4, a4, a5" 3e97 0x1c0 -d "slli a5, a4, 8" 93178700 0x1c0 +d "slli a5, a4, 8" 93178700 0x1c0 (set a5 (<< (var a4) (bv 32 0x8) false)) d "or a6, a5, a6" 33e80701 0x1c0 d "srai a5, a4, 0x18" 93578741 0x1c0 -d "bne a1, s6, 0x140" e39065f7 0x1e0 +d "bne a1, s6, 0x140" e39065f7 0x1e0 (branch (! (== (var a1) (var s6))) (jmp (bv 32 0x140)) (jmp (bv 32 0x1e4))) d "li a5, 0" 8147 0x1c0 d "add a4, t2, s8" 33878301 0x1c0 d "sltu a3, a4, t2" b3367700 0x1c0 d "or s2, a5, s2" 33e92701 0x1c0 d "add t6, t6, s7" de9f 0x1c0 -d "addi ra, ra, 1" 8500 0x1c0 -d "andi s2, s2, 0xff" 1379f90f 0x1c0 +d "addi ra, ra, 1" 8500 0x1c0 (set ra (+ (var ra) (bv 32 0x1))) +d "andi s2, s2, 0xff" 1379f90f 0x1c0 (set s2 (& (var s2) (bv 32 0xff))) d "mv t2, a4" ba83 0x1c0 d "add t6, t6, a3" b69f 0x1c0 +d "ori a5, a5, 0x89" 93e79708 0x0 (set a5 (| (var a5) (bv 32 0x89))) +d "xori a5, a5, 0x431" 93c71743 0x0 (set a5 (^ (var a5) (bv 32 0x431))) +d "jalr ra" e7800000 0x30 (seq (set ra (bv 32 0x34)) (jmp (& (+ (var ra) (bv 32 0x0)) (bv 32 0xfffffffe)))) +d "slti zero, ra, 0xc" 13a0c000 0x0 nop +d "sltiu zero, ra, 0xc" 13b0c000 0x0 nop +d "slti t0, ra, 0xc" 93a2c000 0x0 (set t0 (ite (&& (sle (var ra) (bv 32 0xc)) (! (== (var ra) (bv 32 0xc)))) (bv 32 0x1) (bv 32 0x0))) +d "sltiu t1, sp, 0x14" 13334101 0x0 (set t1 (ite (&& (ule (var sp) (bv 32 0x14)) (! (== (var sp) (bv 32 0x14)))) (bv 32 0x1) (bv 32 0x0))) +d "jal t0, 0x14" ef024001 0x0 (seq (set t0 (bv 32 0x4)) (jmp (bv 32 0x14))) +d "jal t0, 0x4a" ef024001 0x36 (seq (set t0 (bv 32 0x3a)) (jmp (bv 32 0x4a))) From 80f7c8579b048770f98e37f86d2fadbbc463d6b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Thu, 14 May 2026 22:02:17 +0300 Subject: [PATCH 2/9] refactor implementation to more declarative style --- librz/arch/isa/riscv/riscv_il.c | 318 +++++------------- librz/arch/isa/riscv/riscv_il.h | 4 +- librz/arch/isa/riscv/riscv_il_base.h | 199 +++++++++++ librz/arch/isa/riscv/riscv_il_compressed.h | 71 ++++ librz/arch/isa/riscv/riscv_il_integer.h | 99 ++++++ .../isa/riscv/riscv_il_integer_reg_names.h | 53 +++ librz/arch/isa/riscv/riscv_il_m.h | 21 ++ test/db/asm/riscv_32 | 96 +++--- 8 files changed, 577 insertions(+), 284 deletions(-) create mode 100644 librz/arch/isa/riscv/riscv_il_base.h create mode 100644 librz/arch/isa/riscv/riscv_il_compressed.h create mode 100644 librz/arch/isa/riscv/riscv_il_integer.h create mode 100644 librz/arch/isa/riscv/riscv_il_integer_reg_names.h create mode 100644 librz/arch/isa/riscv/riscv_il_m.h diff --git a/librz/arch/isa/riscv/riscv_il.c b/librz/arch/isa/riscv/riscv_il.c index 37a2b1601eb..61f99b2fb14 100644 --- a/librz/arch/isa/riscv/riscv_il.c +++ b/librz/arch/isa/riscv/riscv_il.c @@ -1,217 +1,20 @@ // SPDX-FileCopyrightText: 2026 Mostafa Mahmoud // SPDX-License-Identifier: BSD-3-Clause -#include "analysis_private.h" -#include "riscv.h" -#include "rz_il/rz_il_opcodes.h" -#include "rz_types.h" -#include "rz_util/rz_assert.h" -#include -#include "riscv_il.h" - -#include -static const char *riscv_register_names[] = { - [RISCV_REG_X1] = "ra", - [RISCV_REG_X2] = "sp", - [RISCV_REG_X3] = "gp", - [RISCV_REG_X4] = "tp", - [RISCV_REG_X5] = "t0", - [RISCV_REG_X6] = "t1", - [RISCV_REG_X7] = "t2", - [RISCV_REG_X8] = "s0", - [RISCV_REG_X9] = "s1", - [RISCV_REG_X10] = "a0", - [RISCV_REG_X11] = "a1", - [RISCV_REG_X12] = "a2", - [RISCV_REG_X13] = "a3", - [RISCV_REG_X14] = "a4", - [RISCV_REG_X15] = "a5", - [RISCV_REG_X16] = "a6", - [RISCV_REG_X17] = "a7", - [RISCV_REG_X18] = "s2", - [RISCV_REG_X19] = "s3", - [RISCV_REG_X20] = "s4", - [RISCV_REG_X21] = "s5", - [RISCV_REG_X22] = "s6", - [RISCV_REG_X23] = "s7", - [RISCV_REG_X24] = "s8", - [RISCV_REG_X25] = "s9", - [RISCV_REG_X26] = "s10", - [RISCV_REG_X27] = "s11", - [RISCV_REG_X28] = "t3", - [RISCV_REG_X29] = "t4", - [RISCV_REG_X30] = "t5", - [RISCV_REG_X31] = "t6", -}; - -#define RISCV_GET_REG(reg) (((reg) != RISCV_REG_X0) ? (VARG(riscv_register_names[reg])) : UN(analysis->bits, 0)) -#define RISCV_SET_REG(reg, r) (((reg) != RISCV_REG_X0) ? (SETG(riscv_register_names[reg], r)) : ((rz_il_op_pure_free(r), NOP()))) - -#define DEFINE_LIFTER(name, decoder, result) \ - static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { \ - decoder(analysis, insn); \ - return RISCV_SET_REG(rd, result); \ - } - -// by default, a RISC-V jump both sets a destination and sets the PC (i.e., jumps) -#define DEFINE_LIFTER_FOR_JUMP(name, decoder, result, jmp_effect) \ - static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { \ - decoder(analysis, insn); \ - return SEQ2( \ - RISCV_SET_REG(rd, result), \ - jmp_effect); \ - } - -#define DEFINE_LIFTER_WITH_EFFECT(name, decoder, effect) \ - static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { \ - decoder(analysis, insn); \ - return effect; \ - } - -// oneway jumps are those that don't have a destination register -#define DEFINE_LIFTER_FOR_ONEWAY_JUMP DEFINE_LIFTER_WITH_EFFECT - -#define TWICE_FOR(name1, name2, lifter, ...) \ - lifter(name1, __VA_ARGS__) \ - lifter(name2, __VA_ARGS__) - -#define THRICE_FOR(name1, name2, name3, lifter, ...) \ - TWICE_FOR(name1, name2, lifter, __VA_ARGS__) \ - lifter(name3, __VA_ARGS__) - -#define FOR_4(name1, name2, name3, name4, lifter, ...) \ - TWICE_FOR(name1, name2, lifter, __VA_ARGS__) \ - TWICE_FOR(name3, name4, lifter, __VA_ARGS__) - -#define DECODE_RD_RS_IMM(analysis, insn) \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[2].imm); - -#define DECODE_RD_RS_RS(analysis, insn) \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ - RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[2].reg); - -#define DECODE_RS_IMM(analysis, insn) \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].imm); - -#define DECODE_RS_RS_IMM(analysis, insn) \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ - RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[2].imm); - -#define DECODE_RD_RS(analysis, insn) \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); - -#define DECODE_IMM(analysis, insn) \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[0].imm); - -#define DECODE_RD_IMM(analysis, insn) \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].imm); - -#define DECODE_RS_RS_IMM_MEM(analysis, insn) \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ - RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); - -#define DECODE_RD_RS_IMM_MEM(analysis, insn) \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); - -#define USE_LIFTER(name, uppername) [RISCV_INS_##uppername] = rz_riscv_lift_##name - -FOR_4(addi, c_addi, c_addi16sp, c_addi4spn, - DEFINE_LIFTER, DECODE_RD_RS_IMM, ADD(rs, imm)) -TWICE_FOR(slli, c_slli, - DEFINE_LIFTER, DECODE_RD_RS_IMM, SHIFTL0(rs, imm)) -TWICE_FOR(andi, c_andi, - DEFINE_LIFTER, DECODE_RD_RS_IMM, LOGAND(rs, imm)) -DEFINE_LIFTER(ori, DECODE_RD_RS_IMM, LOGOR(rs, imm)) -DEFINE_LIFTER(xori, DECODE_RD_RS_IMM, LOGXOR(rs, imm)) -DEFINE_LIFTER(slti, DECODE_RD_RS_IMM, BOOL_TO_BV(SLT(rs, imm), analysis->bits)) -DEFINE_LIFTER(sltiu, DECODE_RD_RS_IMM, BOOL_TO_BV(ULT(rs, imm), analysis->bits)) -TWICE_FOR(srli, c_srli, - DEFINE_LIFTER, DECODE_RD_RS_IMM, SHIFTR0(rs, imm)) -TWICE_FOR(srai, c_srai, - DEFINE_LIFTER, DECODE_RD_RS_IMM, SHIFTRA(rs, imm)) - -DEFINE_LIFTER(add, DECODE_RD_RS_RS, ADD(rs1, rs2)) -DEFINE_LIFTER(sub, DECODE_RD_RS_RS, SUB(rs1, rs2)) -DEFINE_LIFTER(and, DECODE_RD_RS_RS, LOGAND(rs1, rs2)) -DEFINE_LIFTER(or, DECODE_RD_RS_RS, LOGOR(rs1, rs2)) -DEFINE_LIFTER(xor, DECODE_RD_RS_RS, LOGXOR(rs1, rs2)) -DEFINE_LIFTER(slt, DECODE_RD_RS_RS, BOOL_TO_BV(SLT(rs1, rs2), analysis->bits)) -DEFINE_LIFTER(sltu, DECODE_RD_RS_RS, BOOL_TO_BV(ULT(rs1, rs2), analysis->bits)) -DEFINE_LIFTER(sll, DECODE_RD_RS_RS, SHIFTL0(rs1, rs2)) -DEFINE_LIFTER(srl, DECODE_RD_RS_RS, SHIFTR0(rs1, rs2)) -DEFINE_LIFTER(sra, DECODE_RD_RS_RS, SHIFTRA(rs1, rs2)) -#define DEFINE_LIFTER_FOR_BRANCH(name, decoder, condition) \ - DEFINE_LIFTER_FOR_ONEWAY_JUMP(name, decoder, BRANCH(condition, JMP(imm), JMP(UN(analysis->bits, current_addr + size)))) - -DEFINE_LIFTER_FOR_BRANCH(beq, DECODE_RS_RS_IMM, EQ(rs1, rs2)) -DEFINE_LIFTER_FOR_BRANCH(bne, DECODE_RS_RS_IMM, NE(rs1, rs2)) -DEFINE_LIFTER_FOR_BRANCH(blt, DECODE_RS_RS_IMM, SLT(rs1, rs2)) -DEFINE_LIFTER_FOR_BRANCH(bge, DECODE_RS_RS_IMM, SGE(rs1, rs2)) -DEFINE_LIFTER_FOR_BRANCH(bltu, DECODE_RS_RS_IMM, ULT(rs1, rs2)) -DEFINE_LIFTER_FOR_BRANCH(bgeu, DECODE_RS_RS_IMM, UGE(rs1, rs2)) - -DEFINE_LIFTER_FOR_BRANCH(c_beqz, DECODE_RS_IMM, EQ(rs, UN(analysis->bits, 0))) -DEFINE_LIFTER_FOR_BRANCH(c_bnez, DECODE_RS_IMM, NE(rs, UN(analysis->bits, 0))) - -DEFINE_LIFTER(c_mv, DECODE_RD_RS, DUP(rs)) - -DEFINE_LIFTER_FOR_ONEWAY_JUMP(c_j, DECODE_IMM, JMP(imm)) - -DEFINE_LIFTER_FOR_JUMP(jal, DECODE_RD_IMM, - /*RETURN ADDR*/ UN(analysis->bits, current_addr + size), - /*GOTO ADDR*/ JMP(imm)) - -TWICE_FOR(jalr, c_jr, - DEFINE_LIFTER_FOR_JUMP, DECODE_RD_RS_IMM, - /*RETURN ADDR*/ UN(analysis->bits, current_addr + size), - /*GOTO ADDR*/ JMP(LOGAND(ADD(rs, imm), UN(analysis->bits, ~1ULL)))) - -TWICE_FOR(lui, c_lui, - DEFINE_LIFTER, DECODE_RD_IMM, SHIFTL0(imm, UN(analysis->bits, 12))) -DEFINE_LIFTER(c_li, DECODE_RD_IMM, DUP(imm)) -DEFINE_LIFTER(auipc, DECODE_RD_IMM, ADD(UN(analysis->bits, current_addr), SHIFTL0(imm, UN(analysis->bits, 12)))) - -DEFINE_LIFTER_WITH_EFFECT(sb, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), CAST(8, IL_FALSE, rs1))) -DEFINE_LIFTER_WITH_EFFECT(sh, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), CAST(16, IL_FALSE, rs1))) - -THRICE_FOR(sw, c_sw, c_swsp, - DEFINE_LIFTER_WITH_EFFECT, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), analysis->bits == 32 ? rs1 : CAST(64, IL_FALSE, rs1))) - -TWICE_FOR(sd, c_sd, - DEFINE_LIFTER_WITH_EFFECT, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), rs1)) - -THRICE_FOR(lw, c_lwsp, c_lw, - DEFINE_LIFTER, DECODE_RD_RS_IMM_MEM, analysis->bits == 32 ? LOADW(32, ADD(rs, imm)) : SIGNED(analysis->bits, LOADW(32, ADD(rs, imm)))) -DEFINE_LIFTER(lb, DECODE_RD_RS_IMM_MEM, SIGNED(analysis->bits, LOADW(8, ADD(rs, imm)))) -DEFINE_LIFTER(lh, DECODE_RD_RS_IMM_MEM, SIGNED(analysis->bits, LOADW(16, ADD(rs, imm)))) -DEFINE_LIFTER(lbu, DECODE_RD_RS_IMM_MEM, UNSIGNED(analysis->bits, LOADW(8, ADD(rs, imm)))) -DEFINE_LIFTER(lhu, DECODE_RD_RS_IMM_MEM, UNSIGNED(analysis->bits, LOADW(16, ADD(rs, imm)))) - -TWICE_FOR(ld, c_ld, - DEFINE_LIFTER, DECODE_RD_RS_IMM_MEM, LOADW(64, ADD(rs, imm))) +#include "riscv_il.h" +#include "riscv_il_integer.h" +#include "riscv_il_m.h" +#include "riscv_il_compressed.h" -#include +static void label_ecall(RzILVM *vm, RzILOpEffect *op) { + // stub: ecall is handled at the analysis layer +} static const RiscvInstructionLifter riscv_lifters[] = { + /* ---------------------------------- Integer ---------------------------------*/ + // arithmetic, immediate USE_LIFTER(addi, ADDI), - USE_LIFTER(c_addi, C_ADDI), - USE_LIFTER(c_addi16sp, C_ADDI16SP), - USE_LIFTER(c_addi4spn, C_ADDI4SPN), USE_LIFTER(andi, ANDI), - USE_LIFTER(c_andi, C_ANDI), USE_LIFTER(ori, ORI), USE_LIFTER(xori, XORI), USE_LIFTER(slti, SLTI), @@ -219,56 +22,99 @@ static const RiscvInstructionLifter riscv_lifters[] = { USE_LIFTER(slli, SLLI), USE_LIFTER(srli, SRLI), USE_LIFTER(srai, SRAI), - USE_LIFTER(c_slli, C_SLLI), - USE_LIFTER(c_srli, C_SRLI), - USE_LIFTER(c_srai, C_SRAI), - USE_LIFTER(jalr, JALR), - USE_LIFTER(c_jr, C_JR), + // immediate constants + USE_LIFTER(lui, LUI), + USE_LIFTER(auipc, AUIPC), + // arithmetic + USE_LIFTER(add, ADD), + USE_LIFTER(sub, SUB), + USE_LIFTER(and, AND), + USE_LIFTER(or, OR), + USE_LIFTER(xor, XOR), + USE_LIFTER(slt, SLT), + USE_LIFTER(sltu, SLTU), + USE_LIFTER(sll, SLL), + USE_LIFTER(srl, SRL), + USE_LIFTER(sra, SRA), + // arithmetic, 32-bit operations in 64-bit mode + USE_LIFTER(addw, ADDW), + USE_LIFTER(subw, SUBW), + USE_LIFTER(sllw, SLLW), + USE_LIFTER(srlw, SRLW), + USE_LIFTER(sraw, SRAW), + USE_LIFTER(addiw, ADDIW), + USE_LIFTER(slliw, SLLIW), + USE_LIFTER(srliw, SRLIW), + USE_LIFTER(sraiw, SRAIW), + // memory USE_LIFTER(lb, LB), USE_LIFTER(lh, LH), USE_LIFTER(lw, LW), USE_LIFTER(lbu, LBU), USE_LIFTER(lhu, LHU), - USE_LIFTER(c_lwsp, C_LWSP), - USE_LIFTER(c_lw, C_LW), USE_LIFTER(ld, LD), - USE_LIFTER(c_ld, C_LD), - USE_LIFTER(lui, LUI), - USE_LIFTER(c_lui, C_LUI), - USE_LIFTER(c_li, C_LI), - USE_LIFTER(auipc, AUIPC), + USE_LIFTER(sb, SB), + USE_LIFTER(sh, SH), + USE_LIFTER(sw, SW), + USE_LIFTER(sd, SD), + // branches USE_LIFTER(beq, BEQ), USE_LIFTER(bne, BNE), USE_LIFTER(blt, BLT), USE_LIFTER(bge, BGE), USE_LIFTER(bltu, BLTU), USE_LIFTER(bgeu, BGEU), + USE_LIFTER(jalr, JALR), + USE_LIFTER(jal, JAL), + // concurrency, no-ops in RzIL + USE_LIFTER(fence, FENCE), + USE_LIFTER(fence_i, FENCE_I), + // system + USE_LIFTER(ecall, ECALL), + // RV64I extra loads + USE_LIFTER(lwu, LWU), + // M extension + USE_LIFTER(mul, MUL), + USE_LIFTER(mulhu, MULHU), + USE_LIFTER(divu, DIVU), + USE_LIFTER(remu, REMU), + USE_LIFTER(remuw, REMUW), + /* ---------------------------------- Compressed ---------------------------------*/ + USE_LIFTER(c_addi, C_ADDI), + USE_LIFTER(c_addi16sp, C_ADDI16SP), + USE_LIFTER(c_addi4spn, C_ADDI4SPN), + USE_LIFTER(c_add, C_ADD), + USE_LIFTER(c_andi, C_ANDI), + USE_LIFTER(c_slli, C_SLLI), + USE_LIFTER(c_srli, C_SRLI), + USE_LIFTER(c_srai, C_SRAI), + USE_LIFTER(c_jr, C_JR), + USE_LIFTER(c_jalr, C_JALR), + USE_LIFTER(c_lwsp, C_LWSP), + USE_LIFTER(c_lw, C_LW), + USE_LIFTER(c_ld, C_LD), + USE_LIFTER(c_lui, C_LUI), + USE_LIFTER(c_li, C_LI), USE_LIFTER(c_beqz, C_BEQZ), USE_LIFTER(c_bnez, C_BNEZ), - USE_LIFTER(sb, SB), - USE_LIFTER(sh, SH), - USE_LIFTER(sw, SW), USE_LIFTER(c_sw, C_SW), USE_LIFTER(c_swsp, C_SWSP), - USE_LIFTER(sd, SD), USE_LIFTER(c_sd, C_SD), - USE_LIFTER(add, ADD), - USE_LIFTER(sub, SUB), - USE_LIFTER(and, AND), - USE_LIFTER(or, OR), - USE_LIFTER(xor, XOR), - USE_LIFTER(slt, SLT), - USE_LIFTER(sltu, SLTU), - USE_LIFTER(sll, SLL), - USE_LIFTER(srl, SRL), - USE_LIFTER(sra, SRA), - USE_LIFTER(jal, JAL), USE_LIFTER(c_mv, C_MV), USE_LIFTER(c_j, C_J), + USE_LIFTER(c_or, C_OR), + USE_LIFTER(c_ldsp, C_LDSP), + USE_LIFTER(c_sdsp, C_SDSP), + USE_LIFTER(c_sub, C_SUB), + USE_LIFTER(c_and, C_AND), + USE_LIFTER(c_xor, C_XOR), + USE_LIFTER(c_addw, C_ADDW), + USE_LIFTER(c_addiw, C_ADDIW), + USE_LIFTER(c_subw, C_SUBW), }; RZ_OWN RZ_IPI RzILOpEffect * -rz_riscv_lift_instr(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size) { +rz_riscv_lift_instr(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { rz_return_val_if_fail(analysis && op && insn, NULL); if (insn->id > 0 && insn->id < RZ_ARRAY_SIZE(riscv_lifters)) { @@ -288,5 +134,9 @@ RZ_IPI RzAnalysisILConfig *rz_riscv_il_config(RZ_NONNULL RzAnalysis *analysis) { RzAnalysisILConfig *conf = rz_analysis_il_config_new(analysis->bits, analysis->big_endian, analysis->bits); + RzILEffectLabel *ecall_label = rz_il_effect_label_new("ecall", EFFECT_LABEL_SYSCALL); + ecall_label->hook = label_ecall; + rz_analysis_il_config_add_label(conf, ecall_label); + return conf; } \ No newline at end of file diff --git a/librz/arch/isa/riscv/riscv_il.h b/librz/arch/isa/riscv/riscv_il.h index eb398ed9042..03c42770f59 100644 --- a/librz/arch/isa/riscv/riscv_il.h +++ b/librz/arch/isa/riscv/riscv_il.h @@ -9,11 +9,11 @@ #include #include -typedef RzILOpEffect *(*RiscvInstructionLifter)(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size); +typedef RzILOpEffect *(*RiscvInstructionLifter)(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size); RZ_OWN RZ_IPI RzILOpEffect * rz_riscv_lift_instr(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, int size); + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size); RZ_IPI RzAnalysisILConfig *rz_riscv_il_config(RZ_NONNULL RzAnalysis *analysis); diff --git a/librz/arch/isa/riscv/riscv_il_base.h b/librz/arch/isa/riscv/riscv_il_base.h new file mode 100644 index 00000000000..c52516ed77e --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_base.h @@ -0,0 +1,199 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_BASE_H +#define RISCV_IL_BASE_H + +#include "riscv.h" +#include "rz_types.h" +#include + +#include "riscv_il.h" +#include "riscv_il_integer_reg_names.h" + +#include + +#define RISCV_GET_REG(reg) (((reg) != RISCV_REG_X0) ? (VARG(riscv_integer_reg_name(reg))) : UN(analysis->bits, 0)) +#define RISCV_SET_REG(reg, r) (((reg) != RISCV_REG_X0) ? (SETG(riscv_integer_reg_name(reg), r)) : ((rz_il_op_pure_free(r), NOP()))) + +#define DEFINE_LIFTER(name, decoder, result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return RISCV_SET_REG(rd, result); \ + } + +// by default, a RISC-V jump both sets a destination and sets the PC (i.e., jumps) +#define DEFINE_LIFTER_FOR_JUMP(name, decoder, result, jmp_effect) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return SEQ2( \ + RISCV_SET_REG(rd, result), \ + jmp_effect); \ + } + +#define DEFINE_LIFTER_WITH_EFFECT(name, decoder, effect) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return effect; \ + } + +// oneway jumps are those that don't have a destination register +#define DEFINE_LIFTER_FOR_ONEWAY_JUMP DEFINE_LIFTER_WITH_EFFECT + +// A more intuitive definition would be: +// static const RiscvInstructionLifter rz_riscv_lift_##alias = ...; +// but C (unlike C++) does not treat const-qualified variables as constant expressions +// (C11 §6.6), so they cannot appear in a static array initializer. Most compilers +// accept it tolerantly, but TCC enforces the standard strictly and rejects it. +// A forced-inline wrapper is an alternative for 0-indirection aliasing. +#define DEFINE_ALIAS_LIFTER(alias, name) \ + static inline FUNC_ATTR_ALWAYS_INLINE RzILOpEffect *rz_riscv_lift_##alias(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + return rz_riscv_lift_##name(analysis, op, insn, current_addr, size); \ + } + +#define TWICE_FOR(name1, name2, def_lifter, ...) \ + def_lifter(name1, __VA_ARGS__) \ + def_lifter(name2, __VA_ARGS__) + +#define THRICE_FOR(name1, name2, name3, def_lifter, ...) \ + TWICE_FOR(name1, name2, def_lifter, __VA_ARGS__) \ + def_lifter(name3, __VA_ARGS__) + +#define FOR_4(name1, name2, name3, name4, def_lifter, ...) \ + TWICE_FOR(name1, name2, def_lifter, __VA_ARGS__) \ + TWICE_FOR(name3, name4, def_lifter, __VA_ARGS__) + +#if RZ_CHECKS_LEVEL > 0 +#define REQUIRE_OP(idx, t) \ + if (insn->detail->riscv.operands[idx].type != (t) || insn->detail->riscv.operands[idx].type == RISCV_OP_INVALID) { \ + RZ_LOG_ERROR("[%s (%d) @ 0x%08" PFMT64x "] Expected type %d (%s) at index %d, found type %d instead\n", insn->mnemonic, insn->id, current_addr, t, #t, idx, insn->detail->riscv.operands[idx].type); \ + RZ_LOG_ERROR("op_str: %s\n", insn->op_str); \ + RZ_LOG_ERROR("need_effective_addr: %d\n", insn->detail->riscv.need_effective_addr); \ + RZ_LOG_ERROR("op_count: %u\n", insn->detail->riscv.op_count); \ + for (int _i = 0; _i < insn->detail->riscv.op_count; _i++) { \ + RZ_LOG_ERROR("operands[%d].type: %d\n", _i, insn->detail->riscv.operands[_i].type); \ + if (insn->detail->riscv.operands[_i].type == RISCV_OP_REG) { \ + RZ_LOG_ERROR(" REG = %d\n", insn->detail->riscv.operands[_i].reg); \ + } else if (insn->detail->riscv.operands[_i].type == RISCV_OP_IMM) { \ + RZ_LOG_ERROR(" IMM = 0x%" PFMT64x "\n", (ut64)insn->detail->riscv.operands[_i].imm); \ + } else if (insn->detail->riscv.operands[_i].type == RISCV_OP_MEM) { \ + RZ_LOG_ERROR(" MEM base = %d, disp = 0x%" PFMT64x "\n", insn->detail->riscv.operands[_i].mem.base, (ut64)insn->detail->riscv.operands[_i].mem.disp); \ + } \ + } \ + return NULL; \ + } + +#define REQUIRE_64_BIT(analysis) \ + if (analysis->bits != 64) { \ + RZ_LOG_ERROR("[%s (%d)] Expected 64-bit analysis, found %d bits\n", insn->mnemonic, insn->id, analysis->bits); \ + return NULL; \ + } +#else +#define REQUIRE_OP(idx, t) \ + do { \ + } while (0) +#define REQUIRE_64_BIT(analysis) \ + do { \ + } while (0) +#endif + +// Decoders, every instruction defines how its own transformation of capstone operands to IL operands + +#define DECODE_RD_RS_IMM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_IMM); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[2].imm); + +#define DECODE_RD_RS_RS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[2].reg); + +#define DECODE_RS_IMM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_IMM); \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].imm); + +#define DECODE_RS_RS_IMM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_IMM); \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[2].imm); + +#define DECODE_RD_RS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); + +#define DECODE_IMM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_IMM); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[0].imm); + +#define DECODE_RD_IMM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_IMM); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].imm); + +#define DECODE_RS_RS_IMM_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +#define DECODE_RD_RS_IMM_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +// used for *w instructions in RV64 that truncate the operands to 32 bits then does the operation +#define DECODE_RD_RS_RS_TRUNCATE32(analysis, insn) \ + REQUIRE_64_BIT(analysis); \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs1 = CAST(32, IL_FALSE, RISCV_GET_REG(insn->detail->riscv.operands[1].reg)); \ + RzILOpBitVector *rs2 = CAST(32, IL_FALSE, RISCV_GET_REG(insn->detail->riscv.operands[2].reg)); + +#define DECODE_RD_RS_IMM_TRUNCATE32(analysis, insn) \ + REQUIRE_64_BIT(analysis); \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_IMM); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = CAST(32, IL_FALSE, RISCV_GET_REG(insn->detail->riscv.operands[1].reg)); \ + RzILOpBitVector *imm = SN(32, insn->detail->riscv.operands[2].imm); + +#define DECODE_RD_IMM_TRUNCATE32(analysis, insn) \ + REQUIRE_64_BIT(analysis); \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_IMM); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *imm = SN(32, insn->detail->riscv.operands[1].imm); + +#define DECODE_NONE(analysis, insn) \ + (void)analysis; \ + (void)insn; + +#define USE_LIFTER(name, uppername) [RISCV_INS_##uppername] = rz_riscv_lift_##name + +#include + +#endif // RISCV_IL_BASE_H \ No newline at end of file diff --git a/librz/arch/isa/riscv/riscv_il_compressed.h b/librz/arch/isa/riscv/riscv_il_compressed.h new file mode 100644 index 00000000000..955a112a31f --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_compressed.h @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_COMPRESSED_H +#define RISCV_IL_COMPRESSED_H + +#include "riscv/riscv_il_base.h" +#include "riscv_il_integer.h" +#include "rz_util/rz_buf.h" + +#include + +// Compressed instruction decoder variants that suppress operands not consumed by the lifter +#define DECODE_RD_RS_IMM_NO_RS(analysis, insn) \ + DECODE_RD_RS_IMM(analysis, insn) \ + (void)(rs); + +#define DECODE_RD_IMM_NO_RD(analysis, insn) \ + DECODE_RD_IMM(analysis, insn) \ + (void)(rd); + +#define DECODE_RS_RS_IMM_NO_RS2(analysis, insn) \ + DECODE_RS_RS_IMM(analysis, insn) \ + (void)(rs2); + +DEFINE_ALIAS_LIFTER(c_addi, addi) +DEFINE_ALIAS_LIFTER(c_addi16sp, addi) +DEFINE_ALIAS_LIFTER(c_addi4spn, addi) +DEFINE_ALIAS_LIFTER(c_add, add) +DEFINE_ALIAS_LIFTER(c_slli, slli) +DEFINE_ALIAS_LIFTER(c_andi, andi) +DEFINE_ALIAS_LIFTER(c_srli, srli) +DEFINE_ALIAS_LIFTER(c_srai, srai) +DEFINE_ALIAS_LIFTER(c_or, or) +DEFINE_ALIAS_LIFTER(c_sub, sub) +DEFINE_ALIAS_LIFTER(c_and, and) +DEFINE_ALIAS_LIFTER(c_xor, xor) +DEFINE_ALIAS_LIFTER(c_addw, addw) + +DEFINE_ALIAS_LIFTER(c_addiw, addiw) + +DEFINE_ALIAS_LIFTER(c_subw, subw) + +DEFINE_LIFTER(c_mv, DECODE_RD_RS, DUP(rs)) +DEFINE_LIFTER(c_li, DECODE_RD_RS_IMM_NO_RS, DUP(imm)) + +DEFINE_LIFTER_FOR_ONEWAY_JUMP(c_j, DECODE_RD_IMM_NO_RD, JMP(imm)) +DEFINE_ALIAS_LIFTER(c_jr, jalr) + +DEFINE_ALIAS_LIFTER(c_jalr, jalr) + +DEFINE_ALIAS_LIFTER(c_lui, lui) + +DEFINE_ALIAS_LIFTER(c_sw, sw) +DEFINE_ALIAS_LIFTER(c_swsp, sw) + +DEFINE_ALIAS_LIFTER(c_sd, sd) +DEFINE_ALIAS_LIFTER(c_sdsp, sd) + +DEFINE_ALIAS_LIFTER(c_lwsp, lw) +DEFINE_ALIAS_LIFTER(c_lw, lw) + +DEFINE_ALIAS_LIFTER(c_ld, ld) +DEFINE_ALIAS_LIFTER(c_ldsp, ld) + +DEFINE_LIFTER_FOR_BRANCH(c_beqz, DECODE_RS_RS_IMM_NO_RS2, EQ(rs1, UN(analysis->bits, 0))) +DEFINE_LIFTER_FOR_BRANCH(c_bnez, DECODE_RS_RS_IMM_NO_RS2, NE(rs1, UN(analysis->bits, 0))) + +#include + +#endif // RISCV_IL_COMPRESSED_H diff --git a/librz/arch/isa/riscv/riscv_il_integer.h b/librz/arch/isa/riscv/riscv_il_integer.h new file mode 100644 index 00000000000..6159636594f --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_integer.h @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_INTEGER_H +#define RISCV_IL_INTEGER_H + +#include "analysis_private.h" +#include "capstone.h" +#include "riscv_il_base.h" + +#include + +DEFINE_LIFTER(addi, DECODE_RD_RS_IMM, ADD(rs, imm)) +DEFINE_LIFTER(slli, DECODE_RD_RS_IMM, SHIFTL0(rs, imm)) +DEFINE_LIFTER(andi, DECODE_RD_RS_IMM, LOGAND(rs, imm)) +DEFINE_LIFTER(ori, DECODE_RD_RS_IMM, LOGOR(rs, imm)) +DEFINE_LIFTER(xori, DECODE_RD_RS_IMM, LOGXOR(rs, imm)) +DEFINE_LIFTER(slti, DECODE_RD_RS_IMM, BOOL_TO_BV(SLT(rs, imm), analysis->bits)) +DEFINE_LIFTER(sltiu, DECODE_RD_RS_IMM, BOOL_TO_BV(ULT(rs, imm), analysis->bits)) +DEFINE_LIFTER(srli, DECODE_RD_RS_IMM, SHIFTR0(rs, imm)) +DEFINE_LIFTER(srai, DECODE_RD_RS_IMM, SHIFTRA(rs, imm)) + +DEFINE_LIFTER(add, DECODE_RD_RS_RS, ADD(rs1, rs2)) +DEFINE_LIFTER(sub, DECODE_RD_RS_RS, SUB(rs1, rs2)) +DEFINE_LIFTER(and, DECODE_RD_RS_RS, LOGAND(rs1, rs2)) +DEFINE_LIFTER(or, DECODE_RD_RS_RS, LOGOR(rs1, rs2)) +DEFINE_LIFTER(xor, DECODE_RD_RS_RS, LOGXOR(rs1, rs2)) +DEFINE_LIFTER(slt, DECODE_RD_RS_RS, BOOL_TO_BV(SLT(rs1, rs2), analysis->bits)) +DEFINE_LIFTER(sltu, DECODE_RD_RS_RS, BOOL_TO_BV(ULT(rs1, rs2), analysis->bits)) +DEFINE_LIFTER(sll, DECODE_RD_RS_RS, SHIFTL0(rs1, LOGAND(rs2, UN(analysis->bits, analysis->bits - 1)))) +DEFINE_LIFTER(srl, DECODE_RD_RS_RS, SHIFTR0(rs1, LOGAND(rs2, UN(analysis->bits, analysis->bits - 1)))) +DEFINE_LIFTER(sra, DECODE_RD_RS_RS, SHIFTRA(rs1, LOGAND(rs2, UN(analysis->bits, analysis->bits - 1)))) + +#define DEFINE_LIFTER_FOR_BRANCH(name, decoder, condition) \ + DEFINE_LIFTER_FOR_ONEWAY_JUMP(name, decoder, BRANCH(condition, JMP(imm), JMP(UN(analysis->bits, current_addr + size)))) + +DEFINE_LIFTER_FOR_BRANCH(beq, DECODE_RS_RS_IMM, EQ(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(bne, DECODE_RS_RS_IMM, NE(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(blt, DECODE_RS_RS_IMM, SLT(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(bge, DECODE_RS_RS_IMM, SGE(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(bltu, DECODE_RS_RS_IMM, ULT(rs1, rs2)) +DEFINE_LIFTER_FOR_BRANCH(bgeu, DECODE_RS_RS_IMM, UGE(rs1, rs2)) + +DEFINE_LIFTER_FOR_JUMP(jal, DECODE_RD_IMM, + /*RETURN ADDR*/ UN(analysis->bits, current_addr + size), + /*GOTO ADDR*/ JMP(imm)) + +DEFINE_LIFTER_FOR_JUMP(jalr, DECODE_RD_RS_IMM, + /*RETURN ADDR*/ UN(analysis->bits, current_addr + size), + /*GOTO ADDR*/ JMP(LOGAND(ADD(rs, imm), UN(analysis->bits, ~1ULL)))) + +// Intentional: on RV32 imm is already 32-bit and the result needs no sign-extension, +// so CAST(32) and SIGNED(32) would both be no-ops; on RV64 CAST(32) truncates imm and SIGNED(64) +// sign-extends the shifted 32-bit result to XLEN. +DEFINE_LIFTER(lui, DECODE_RD_IMM, + analysis->bits == 32 + ? SHIFTL0(imm, UN(32, 12)) + : SIGNED(analysis->bits, SHIFTL0(CAST(32, IL_FALSE, imm), UN(32, 12)))) +DEFINE_LIFTER(auipc, DECODE_RD_IMM, ADD(UN(analysis->bits, current_addr), SIGNED(analysis->bits, SHIFTL0(CAST(32, IL_FALSE, imm), UN(32, 12))))) + +DEFINE_LIFTER_WITH_EFFECT(sb, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), CAST(8, IL_FALSE, rs1))) +DEFINE_LIFTER_WITH_EFFECT(sh, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), CAST(16, IL_FALSE, rs1))) +// Intentional: on RV32 rs1 is already 32-bit so CAST(32) would be a redundant no-op; +// on RV64 it is needed to truncate the 64-bit register value to 32 bits before storing. +DEFINE_LIFTER_WITH_EFFECT(sw, DECODE_RS_RS_IMM_MEM, + analysis->bits == 32 + ? STOREW(ADD(rs2, imm), rs1) + : STOREW(ADD(rs2, imm), CAST(32, IL_FALSE, rs1))) +DEFINE_LIFTER_WITH_EFFECT(sd, DECODE_RS_RS_IMM_MEM, STOREW(ADD(rs2, imm), rs1)) + +DEFINE_LIFTER(lw, DECODE_RD_RS_IMM_MEM, analysis->bits == 32 ? LOADW(32, ADD(rs, imm)) : SIGNED(analysis->bits, LOADW(32, ADD(rs, imm)))) +DEFINE_LIFTER(lb, DECODE_RD_RS_IMM_MEM, SIGNED(analysis->bits, LOADW(8, ADD(rs, imm)))) +DEFINE_LIFTER(lh, DECODE_RD_RS_IMM_MEM, SIGNED(analysis->bits, LOADW(16, ADD(rs, imm)))) +DEFINE_LIFTER(lbu, DECODE_RD_RS_IMM_MEM, UNSIGNED(analysis->bits, LOADW(8, ADD(rs, imm)))) +DEFINE_LIFTER(lhu, DECODE_RD_RS_IMM_MEM, UNSIGNED(analysis->bits, LOADW(16, ADD(rs, imm)))) +DEFINE_LIFTER(ld, DECODE_RD_RS_IMM_MEM, LOADW(64, ADD(rs, imm))) + +TWICE_FOR(fence, fence_i, + DEFINE_LIFTER_WITH_EFFECT, DECODE_NONE, NOP()) + +DEFINE_LIFTER(addw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, ADD(rs1, rs2))) +DEFINE_LIFTER(subw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, SUB(rs1, rs2))) +DEFINE_LIFTER(sllw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, SHIFTL0(rs1, LOGAND(rs2, UN(32, 31))))) +DEFINE_LIFTER(srlw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, SHIFTR0(rs1, LOGAND(rs2, UN(32, 31))))) +DEFINE_LIFTER(sraw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, SHIFTRA(rs1, LOGAND(rs2, UN(32, 31))))) +DEFINE_LIFTER(addiw, DECODE_RD_RS_IMM_TRUNCATE32, SIGNED(analysis->bits, ADD(rs, imm))) +DEFINE_LIFTER(slliw, DECODE_RD_RS_IMM_TRUNCATE32, SIGNED(analysis->bits, SHIFTL0(rs, imm))) +DEFINE_LIFTER(srliw, DECODE_RD_RS_IMM_TRUNCATE32, SIGNED(analysis->bits, SHIFTR0(rs, imm))) +DEFINE_LIFTER(sraiw, DECODE_RD_RS_IMM_TRUNCATE32, SIGNED(analysis->bits, SHIFTRA(rs, imm))) + +// RV64I: load word unsigned (zero-extend 32-bit load to XLEN) +DEFINE_LIFTER(lwu, DECODE_RD_RS_IMM_MEM, UNSIGNED(analysis->bits, LOADW(32, ADD(rs, imm)))) + +// System: environment call (trap to OS / hypervisor) +DEFINE_LIFTER_WITH_EFFECT(ecall, DECODE_NONE, GOTO("ecall")) + +#include + +#endif // RISCV_IL_INTEGER_H \ No newline at end of file diff --git a/librz/arch/isa/riscv/riscv_il_integer_reg_names.h b/librz/arch/isa/riscv/riscv_il_integer_reg_names.h new file mode 100644 index 00000000000..80cadb58790 --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_integer_reg_names.h @@ -0,0 +1,53 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_INTEGER_REG_NAMES_H +#define RISCV_IL_INTEGER_REG_NAMES_H + +#include +#include + +static const char *riscv_integer_reg_names[] = { + /* x0 */ "zero", + /* x1 */ "ra", + /* x2 */ "sp", + /* x3 */ "gp", + /* x4 */ "tp", + /* x5 */ "t0", + /* x6 */ "t1", + /* x7 */ "t2", + /* x8 */ "s0", + /* x9 */ "s1", + /* x10 */ "a0", + /* x11 */ "a1", + /* x12 */ "a2", + /* x13 */ "a3", + /* x14 */ "a4", + /* x15 */ "a5", + /* x16 */ "a6", + /* x17 */ "a7", + /* x18 */ "s2", + /* x19 */ "s3", + /* x20 */ "s4", + /* x21 */ "s5", + /* x22 */ "s6", + /* x23 */ "s7", + /* x24 */ "s8", + /* x25 */ "s9", + /* x26 */ "s10", + /* x27 */ "s11", + /* x28 */ "t3", + /* x29 */ "t4", + /* x30 */ "t5", + /* x31 */ "t6", +}; + +static inline const char *riscv_integer_reg_name(uint32_t reg) { + int idx = (int)reg - RISCV_REG_X0; + if (idx < 0 || idx >= 32) { + return ""; + } + return riscv_integer_reg_names[idx]; +} + +#endif // RISCV_IL_INTEGER_REG_NAMES_H diff --git a/librz/arch/isa/riscv/riscv_il_m.h b/librz/arch/isa/riscv/riscv_il_m.h new file mode 100644 index 00000000000..e3f666f6a44 --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_m.h @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_M_H +#define RISCV_IL_M_H + +#include "riscv_il_base.h" + +#include + +// M extension: multiply/divide/remainder (RV32M / RV64M) +DEFINE_LIFTER(mul, DECODE_RD_RS_RS, MUL(rs1, rs2)) +DEFINE_LIFTER(mulhu, DECODE_RD_RS_RS, CAST(analysis->bits, IL_FALSE, SHIFTR0(MUL(UNSIGNED(analysis->bits * 2, rs1), UNSIGNED(analysis->bits * 2, rs2)), UN(8, analysis->bits)))) +DEFINE_LIFTER(divu, DECODE_RD_RS_RS, DIV(rs1, rs2)) +DEFINE_LIFTER(remu, DECODE_RD_RS_RS, MOD(rs1, rs2)) +// RV64M: unsigned remainder of 32-bit operands, result sign-extended to 64 bits +DEFINE_LIFTER(remuw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, MOD(rs1, rs2))) + +#include + +#endif // RISCV_IL_M_H diff --git a/test/db/asm/riscv_32 b/test/db/asm/riscv_32 index 269ff99bf7a..87831e4ba54 100644 --- a/test/db/asm/riscv_32 +++ b/test/db/asm/riscv_32 @@ -49,18 +49,18 @@ d "lw s8, 0x68(sp)" 265c 0x40 (set s8 (loadw 0 32 (+ (var sp) (bv 32 0x68)))) d "lw s9, 0x64(sp)" 965c 0x40 (set s9 (loadw 0 32 (+ (var sp) (bv 32 0x64)))) d "lw s10, 0x60(sp)" 065d 0x40 (set s10 (loadw 0 32 (+ (var sp) (bv 32 0x60)))) d "lw s11, 0x5c(sp)" f64d 0x40 (set s11 (loadw 0 32 (+ (var sp) (bv 32 0x5c)))) -d "addi sp, sp, 0x90" 4961 0x40 -d "ret" 8280 0x40 NONE +d "addi sp, sp, 0x90" 4961 0x40 (set sp (+ (var sp) (bv 32 0x90))) +d "ret" 8280 0x40 (seq nop (jmp (& (+ (var ra) (bv 32 0x0)) (bv 32 0xfffffffe)))) d "lw a5, 0x18(sp)" e247 0x40 (set a5 (loadw 0 32 (+ (var sp) (bv 32 0x18)))) -d "beqz a5, 0x2d8" 63890726 0x66 +d "beqz a5, 0x2d8" 63890726 0x66 (branch (== (var a5) (bv 32 0x0)) (jmp (bv 32 0x2d8)) (jmp (bv 32 0x6a))) d "lw s0, 0x1c(sp)" 7244 0x40 (set s0 (loadw 0 32 (+ (var sp) (bv 32 0x1c)))) d "lw a0, 0x24(sp)" 1255 0x40 (set a0 (loadw 0 32 (+ (var sp) (bv 32 0x24)))) d "lw a6, 0x28(sp)" 2258 0x40 (set a6 (loadw 0 32 (+ (var sp) (bv 32 0x28)))) d "lw t3, 0x38(sp)" 625e 0x40 (set t3 (loadw 0 32 (+ (var sp) (bv 32 0x38)))) -d "srai a5, s0, 0x1f" 9357f441 0x40 +d "srai a5, s0, 0x1f" 9357f441 0x40 (set a5 (>> (var s0) (bv 32 0x1f) (msb (var s0)))) d "lw a2, 0x20(sp)" 0256 0x40 (set a2 (loadw 0 32 (+ (var sp) (bv 32 0x20)))) d "andi a5, a5, 0xf" bd8b 0x40 (set a5 (& (var a5) (bv 32 0xf))) -d "srai a4, a0, 0x1f" 1357f541 0x40 +d "srai a4, a0, 0x1f" 1357f541 0x40 (set a4 (>> (var a0) (bv 32 0x1f) (msb (var a0)))) d "lw a7, 0x30(sp)" c258 0x40 (set a7 (loadw 0 32 (+ (var sp) (bv 32 0x30)))) d "add a3, a5, a6" b3860701 0x80 (set a3 (+ (var a5) (var a6))) d "sub s2, t3, a6" 33090e41 0x80 (set s2 (- (var t3) (var a6))) @@ -81,7 +81,7 @@ d "srli a1, a1, 6" 9981 0x80 (set a1 (>> (var a1) (bv 32 0x6) false)) d "slli a0, a5, 0x1a" 1395a701 0x80 (set a0 (<< (var a5) (bv 32 0x1a) false)) d "sw a4, 0x40(sp)" bac0 0x80 (storew 0 (+ (var sp) (bv 32 0x40)) (var a4)) d "sub a4, a2, a7" 33071641 0x80 (set a4 (- (var a2) (var a7))) -d "add s7, s7, s0" a29b 0xc0 NONE +d "add s7, s7, s0" a29b 0xc0 (set s7 (+ (var s7) (var s0))) d "sw a4, 0x44(sp)" bac2 0xc0 (storew 0 (+ (var sp) (bv 32 0x44)) (var a4)) d "srai a5, a5, 6" 9987 0xc0 (set a5 (>> (var a5) (bv 32 0x6) (msb (var a5)))) d "or a4, a0, a1" 3367b500 0xc0 (set a4 (| (var a0) (var a1))) @@ -100,7 +100,7 @@ d "lui a4, 1" 0567 0xc0 (set a4 (<< (bv 32 0x1) (bv 32 0xc) false)) d "blt a5, a4, 0x2d4" 63c3e71e 0xee (branch (&& (sle (var a5) (var a4)) (! (== (var a5) (var a4)))) (jmp (bv 32 0x2d4)) (jmp (bv 32 0xf2))) d "srli a5, s8, 0x1d" 9357dc01 0xc0 (set a5 (>> (var s8) (bv 32 0x1d) false)) d "slli a4, s7, 3" 13973b00 0xc0 (set a4 (<< (var s7) (bv 32 0x3) false)) -d "or a5, a5, a4" d98f 0xc0 NONE +d "or a5, a5, a4" d98f 0xc0 (set a5 (| (var a5) (var a4))) d "sw a5, 0x4c(sp)" bec6 0xc0 (storew 0 (+ (var sp) (bv 32 0x4c)) (var a5)) d "slli a5, s8, 3" 93173c00 0xc0 (set a5 (<< (var s8) (bv 32 0x3) false)) d "addi a5, sp, 8" 3c00 0x100 (set a5 (+ (var sp) (bv 32 0x8))) @@ -133,63 +133,63 @@ d "li t1, 0" 0143 0x100 (set t1 (bv 32 0x0)) d "li a2, 0" 0146 0x100 (set a2 (bv 32 0x0)) d "li a0, 0" 0145 0x100 (set a0 (bv 32 0x0)) d "j 0x176" 25a8 0x13e (jmp (bv 32 0x176)) -d "mul a4, a0, a2" 3307c502 0x140 -d "mulhu t1, a2, a2" 3333c602 0x140 +d "mul a4, a0, a2" 3307c502 0x140 (set a4 (* (var a0) (var a2))) +d "mulhu t1, a2, a2" 3333c602 0x140 (set t1 (cast 32 false (>> (* (cast 64 false (var a2)) (cast 64 false (var a2))) (bv 8 0x20) false))) d "slli a4, a4, 1" 0607 0x140 (set a4 (<< (var a4) (bv 32 0x1) false)) -d "mul a7, a5, a6" b3880703 0x140 -d "add t1, t1, a4" 3a93 0x140 -d "mul a3, a2, a2" b306c602 0x140 +d "mul a7, a5, a6" b3880703 0x140 (set a7 (* (var a5) (var a6))) +d "add t1, t1, a4" 3a93 0x140 (set t1 (+ (var t1) (var a4))) +d "mul a3, a2, a2" b306c602 0x140 (set a3 (* (var a2) (var a2))) d "slli a7, a7, 1" 8608 0x140 (set a7 (<< (var a7) (bv 32 0x1) false)) -d "mulhu t3, a6, a6" 333e0803 0x140 -d "mul a4, a6, a6" 33070803 0x140 -d "add t3, t3, a7" 469e 0x140 -d "add t5, t1, t3" 330fc301 0x140 -d "add t4, a3, a4" b38ee600 0x140 -d "sltu a7, t4, a3" b3b8de00 0x140 -d "add a7, a7, t5" fa98 0x140 +d "mulhu t3, a6, a6" 333e0803 0x140 (set t3 (cast 32 false (>> (* (cast 64 false (var a6)) (cast 64 false (var a6))) (bv 8 0x20) false))) +d "mul a4, a6, a6" 33070803 0x140 (set a4 (* (var a6) (var a6))) +d "add t3, t3, a7" 469e 0x140 (set t3 (+ (var t3) (var a7))) +d "add t5, t1, t3" 330fc301 0x140 (set t5 (+ (var t1) (var t3))) +d "add t4, a3, a4" b38ee600 0x140 (set t4 (+ (var a3) (var a4))) +d "sltu a7, t4, a3" b3b8de00 0x140 (set a7 (ite (&& (ule (var t4) (var a3)) (! (== (var t4) (var a3)))) (bv 32 0x1) (bv 32 0x0))) +d "add a7, a7, t5" fa98 0x140 (set a7 (+ (var a7) (var t5))) d "blt s1, a7, 0x2c6" 63cc1415 0x16e (branch (&& (sle (var s1) (var a7)) (! (== (var s1) (var a7)))) (jmp (bv 32 0x2c6)) (jmp (bv 32 0x172))) d "beq a7, s1, 0x2c2" 63889814 0x172 (branch (== (var a7) (var s1)) (jmp (bv 32 0x2c2)) (jmp (bv 32 0x176))) -d "sub a4, a3, a4" 3387e640 0x140 -d "sub t3, t1, t3" 330ec341 0x140 -d "sltu a3, ra, zero" b3b60000 0x140 -d "add a7, a4, s10" b308a701 0x180 -d "sub a3, t3, a3" b306de40 0x180 -d "sltu a4, a7, a4" 33b7e800 0x180 -d "add a3, a3, s5" d696 0x180 -d "add a3, a3, a4" ba96 0x180 -d "mul a5, a5, a2" b387c702 0x180 +d "sub a4, a3, a4" 3387e640 0x140 (set a4 (- (var a3) (var a4))) +d "sub t3, t1, t3" 330ec341 0x140 (set t3 (- (var t1) (var t3))) +d "sltu a3, ra, zero" b3b60000 0x140 (set a3 (ite (&& (ule (var ra) (bv 32 0x0)) (! (== (var ra) (bv 32 0x0)))) (bv 32 0x1) (bv 32 0x0))) +d "add a7, a4, s10" b308a701 0x180 (set a7 (+ (var a4) (var s10))) +d "sub a3, t3, a3" b306de40 0x180 (set a3 (- (var t3) (var a3))) +d "sltu a4, a7, a4" 33b7e800 0x180 (set a4 (ite (&& (ule (var a7) (var a4)) (! (== (var a7) (var a4)))) (bv 32 0x1) (bv 32 0x0))) +d "add a3, a3, s5" d696 0x180 (set a3 (+ (var a3) (var s5))) +d "add a3, a3, a4" ba96 0x180 (set a3 (+ (var a3) (var a4))) +d "mul a5, a5, a2" b387c702 0x180 (set a5 (* (var a5) (var a2))) d "slli t1, a3, 8" 13938600 0x180 (set t1 (<< (var a3) (bv 32 0x8) false)) d "addi a1, a1, 1" 8505 0x180 (set a1 (+ (var a1) (bv 32 0x1))) -d "mul a4, a0, a6" 33070503 0x180 +d "mul a4, a0, a6" 33070503 0x180 (set a4 (* (var a0) (var a6))) d "srai a0, a3, 0x18" 13d58641 0x180 (set a0 (>> (var a3) (bv 32 0x18) (msb (var a3)))) -d "mulhu a3, a6, a2" b336c802 0x180 -d "add a4, a4, a5" 3e97 0x180 -d "mul a6, a6, a2" 3308c802 0x180 -d "add a4, a4, a3" 3697 0x180 +d "mulhu a3, a6, a2" b336c802 0x180 (set a3 (cast 32 false (>> (* (cast 64 false (var a6)) (cast 64 false (var a2))) (bv 8 0x20) false))) +d "add a4, a4, a5" 3e97 0x180 (set a4 (+ (var a4) (var a5))) +d "mul a6, a6, a2" 3308c802 0x180 (set a6 (* (var a6) (var a2))) +d "add a4, a4, a3" 3697 0x180 (set a4 (+ (var a4) (var a3))) d "srli a2, a7, 0x18" 13d68801 0x180 (set a2 (>> (var a7) (bv 32 0x18) false)) d "slli a4, a4, 1" 0607 0x180 (set a4 (<< (var a4) (bv 32 0x1) false)) -d "or a2, t1, a2" 3366c300 0x180 +d "or a2, t1, a2" 3366c300 0x180 (set a2 (| (var t1) (var a2))) d "slli a7, a6, 1" 93181800 0x180 (set a7 (<< (var a6) (bv 32 0x1) false)) d "srli a3, a6, 0x1f" 9356f801 0x180 (set a3 (>> (var a6) (bv 32 0x1f) false)) -d "add a5, a7, t2" b3877800 0x1c0 -d "or a4, a4, a3" 558f 0x1c0 +d "add a5, a7, t2" b3877800 0x1c0 (set a5 (+ (var a7) (var t2))) +d "or a4, a4, a3" 558f 0x1c0 (set a4 (| (var a4) (var a3))) d "srli a6, a5, 0x18" 13d88701 0x1c0 (set a6 (>> (var a5) (bv 32 0x18) false)) -d "add a4, a4, t6" 7e97 0x1c0 -d "sltu a5, a5, a7" b3b71701 0x1c0 -d "add a4, a4, a5" 3e97 0x1c0 +d "add a4, a4, t6" 7e97 0x1c0 (set a4 (+ (var a4) (var t6))) +d "sltu a5, a5, a7" b3b71701 0x1c0 (set a5 (ite (&& (ule (var a5) (var a7)) (! (== (var a5) (var a7)))) (bv 32 0x1) (bv 32 0x0))) +d "add a4, a4, a5" 3e97 0x1c0 (set a4 (+ (var a4) (var a5))) d "slli a5, a4, 8" 93178700 0x1c0 (set a5 (<< (var a4) (bv 32 0x8) false)) -d "or a6, a5, a6" 33e80701 0x1c0 -d "srai a5, a4, 0x18" 93578741 0x1c0 +d "or a6, a5, a6" 33e80701 0x1c0 (set a6 (| (var a5) (var a6))) +d "srai a5, a4, 0x18" 93578741 0x1c0 (set a5 (>> (var a4) (bv 32 0x18) (msb (var a4)))) d "bne a1, s6, 0x140" e39065f7 0x1e0 (branch (! (== (var a1) (var s6))) (jmp (bv 32 0x140)) (jmp (bv 32 0x1e4))) -d "li a5, 0" 8147 0x1c0 -d "add a4, t2, s8" 33878301 0x1c0 -d "sltu a3, a4, t2" b3367700 0x1c0 -d "or s2, a5, s2" 33e92701 0x1c0 -d "add t6, t6, s7" de9f 0x1c0 +d "li a5, 0" 8147 0x1c0 (set a5 (bv 32 0x0)) +d "add a4, t2, s8" 33878301 0x1c0 (set a4 (+ (var t2) (var s8))) +d "sltu a3, a4, t2" b3367700 0x1c0 (set a3 (ite (&& (ule (var a4) (var t2)) (! (== (var a4) (var t2)))) (bv 32 0x1) (bv 32 0x0))) +d "or s2, a5, s2" 33e92701 0x1c0 (set s2 (| (var a5) (var s2))) +d "add t6, t6, s7" de9f 0x1c0 (set t6 (+ (var t6) (var s7))) d "addi ra, ra, 1" 8500 0x1c0 (set ra (+ (var ra) (bv 32 0x1))) d "andi s2, s2, 0xff" 1379f90f 0x1c0 (set s2 (& (var s2) (bv 32 0xff))) -d "mv t2, a4" ba83 0x1c0 -d "add t6, t6, a3" b69f 0x1c0 +d "mv t2, a4" ba83 0x1c0 (set t2 (var a4)) +d "add t6, t6, a3" b69f 0x1c0 (set t6 (+ (var t6) (var a3))) d "ori a5, a5, 0x89" 93e79708 0x0 (set a5 (| (var a5) (bv 32 0x89))) d "xori a5, a5, 0x431" 93c71743 0x0 (set a5 (^ (var a5) (bv 32 0x431))) d "jalr ra" e7800000 0x30 (seq (set ra (bv 32 0x34)) (jmp (& (+ (var ra) (bv 32 0x0)) (bv 32 0xfffffffe)))) From c6f4465eddd0ee863841b5a2e03a40aff957ea36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Wed, 17 Jun 2026 00:55:02 +0300 Subject: [PATCH 3/9] cut down on macro usage --- librz/arch/isa/riscv/riscv_il_base.h | 149 ++++++++++++++++----------- 1 file changed, 88 insertions(+), 61 deletions(-) diff --git a/librz/arch/isa/riscv/riscv_il_base.h b/librz/arch/isa/riscv/riscv_il_base.h index c52516ed77e..5c31ce4ce80 100644 --- a/librz/arch/isa/riscv/riscv_il_base.h +++ b/librz/arch/isa/riscv/riscv_il_base.h @@ -13,14 +13,19 @@ #include -#define RISCV_GET_REG(reg) (((reg) != RISCV_REG_X0) ? (VARG(riscv_integer_reg_name(reg))) : UN(analysis->bits, 0)) -#define RISCV_SET_REG(reg, r) (((reg) != RISCV_REG_X0) ? (SETG(riscv_integer_reg_name(reg), r)) : ((rz_il_op_pure_free(r), NOP()))) +static inline RzILOpBitVector *riscv_il_get_reg(ut32 bits, uint32_t reg) { + return reg != RISCV_REG_X0 ? VARG(riscv_integer_reg_name(reg)) : UN(bits, 0); +} + +static inline RzILOpEffect *riscv_il_set_reg(uint32_t reg, RZ_OWN RZ_NONNULL RzILOpBitVector *value) { + return reg != RISCV_REG_X0 ? SETG(riscv_integer_reg_name(reg), value) : ((rz_il_op_pure_free(value), NOP())); +} #define DEFINE_LIFTER(name, decoder, result) \ static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ decoder(analysis, insn); \ - return RISCV_SET_REG(rd, result); \ + return riscv_il_set_reg(rd, result); \ } // by default, a RISC-V jump both sets a destination and sets the PC (i.e., jumps) @@ -29,7 +34,7 @@ RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ decoder(analysis, insn); \ return SEQ2( \ - RISCV_SET_REG(rd, result), \ + riscv_il_set_reg(rd, result), \ jmp_effect); \ } @@ -67,30 +72,62 @@ TWICE_FOR(name3, name4, def_lifter, __VA_ARGS__) #if RZ_CHECKS_LEVEL > 0 +static inline void riscv_il_dump_operands(RZ_NONNULL cs_insn *insn) { + RZ_LOG_ERROR("op_str: %s\n", insn->op_str); + RZ_LOG_ERROR("need_effective_addr: %d\n", insn->detail->riscv.need_effective_addr); + RZ_LOG_ERROR("op_count: %u\n", insn->detail->riscv.op_count); + for (int i = 0; i < insn->detail->riscv.op_count; i++) { + RZ_LOG_ERROR("operands[%d].type: %d\n", i, insn->detail->riscv.operands[i].type); + if (insn->detail->riscv.operands[i].type == RISCV_OP_REG) { + RZ_LOG_ERROR(" REG = %d\n", insn->detail->riscv.operands[i].reg); + } else if (insn->detail->riscv.operands[i].type == RISCV_OP_IMM) { + RZ_LOG_ERROR(" IMM = 0x%" PFMT64x "\n", (ut64)insn->detail->riscv.operands[i].imm); + } else if (insn->detail->riscv.operands[i].type == RISCV_OP_MEM) { + RZ_LOG_ERROR(" MEM base = %d, disp = 0x%" PFMT64x "\n", insn->detail->riscv.operands[i].mem.base, (ut64)insn->detail->riscv.operands[i].mem.disp); + } + } +} + +static inline void riscv_il_log_operand_mismatch(RZ_NONNULL cs_insn *insn, ut64 current_addr, int idx, int type, const char *type_name) { + RZ_LOG_ERROR("[%s (%d) @ 0x%08" PFMT64x "] Expected type %d (%s) at index %d, found type %d instead\n", + insn->mnemonic, insn->id, current_addr, type, type_name, idx, insn->detail->riscv.operands[idx].type); + riscv_il_dump_operands(insn); +} + +static inline bool riscv_il_require_op(RZ_NONNULL cs_insn *insn, ut64 current_addr, int idx, int type, const char *type_name) { + if (insn->detail->riscv.operands[idx].type == type && insn->detail->riscv.operands[idx].type != RISCV_OP_INVALID) { + return true; + } + riscv_il_log_operand_mismatch(insn, current_addr, idx, type, type_name); + return false; +} + +static inline bool riscv_il_require_64_bit(RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL cs_insn *insn) { + if (analysis->bits == 64) { + return true; + } + RZ_LOG_ERROR("[%s (%d)] Expected 64-bit analysis, found %d bits\n", insn->mnemonic, insn->id, analysis->bits); + return false; +} + #define REQUIRE_OP(idx, t) \ - if (insn->detail->riscv.operands[idx].type != (t) || insn->detail->riscv.operands[idx].type == RISCV_OP_INVALID) { \ - RZ_LOG_ERROR("[%s (%d) @ 0x%08" PFMT64x "] Expected type %d (%s) at index %d, found type %d instead\n", insn->mnemonic, insn->id, current_addr, t, #t, idx, insn->detail->riscv.operands[idx].type); \ - RZ_LOG_ERROR("op_str: %s\n", insn->op_str); \ - RZ_LOG_ERROR("need_effective_addr: %d\n", insn->detail->riscv.need_effective_addr); \ - RZ_LOG_ERROR("op_count: %u\n", insn->detail->riscv.op_count); \ - for (int _i = 0; _i < insn->detail->riscv.op_count; _i++) { \ - RZ_LOG_ERROR("operands[%d].type: %d\n", _i, insn->detail->riscv.operands[_i].type); \ - if (insn->detail->riscv.operands[_i].type == RISCV_OP_REG) { \ - RZ_LOG_ERROR(" REG = %d\n", insn->detail->riscv.operands[_i].reg); \ - } else if (insn->detail->riscv.operands[_i].type == RISCV_OP_IMM) { \ - RZ_LOG_ERROR(" IMM = 0x%" PFMT64x "\n", (ut64)insn->detail->riscv.operands[_i].imm); \ - } else if (insn->detail->riscv.operands[_i].type == RISCV_OP_MEM) { \ - RZ_LOG_ERROR(" MEM base = %d, disp = 0x%" PFMT64x "\n", insn->detail->riscv.operands[_i].mem.base, (ut64)insn->detail->riscv.operands[_i].mem.disp); \ - } \ - } \ + if (!riscv_il_require_op(insn, current_addr, idx, t, #t)) { \ return NULL; \ } #define REQUIRE_64_BIT(analysis) \ - if (analysis->bits != 64) { \ - RZ_LOG_ERROR("[%s (%d)] Expected 64-bit analysis, found %d bits\n", insn->mnemonic, insn->id, analysis->bits); \ + if (!riscv_il_require_64_bit(analysis, insn)) { \ return NULL; \ } + +#define REQUIRE_2OPS(t0, t1) \ + REQUIRE_OP(0, t0); \ + REQUIRE_OP(1, t1) + +#define REQUIRE_3OPS(t0, t1, t2) \ + REQUIRE_OP(0, t0); \ + REQUIRE_OP(1, t1); \ + REQUIRE_OP(2, t2) #else #define REQUIRE_OP(idx, t) \ do { \ @@ -98,93 +135,83 @@ #define REQUIRE_64_BIT(analysis) \ do { \ } while (0) +#define REQUIRE_2OPS(t0, t1) \ + do { \ + } while (0) +#define REQUIRE_3OPS(t0, t1, t2) \ + do { \ + } while (0) #endif // Decoders, every instruction defines how its own transformation of capstone operands to IL operands #define DECODE_RD_RS_IMM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_IMM); \ + REQUIRE_3OPS(RISCV_OP_REG, RISCV_OP_REG, RISCV_OP_IMM); \ uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *rs = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].reg); \ RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[2].imm); #define DECODE_RD_RS_RS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ + REQUIRE_3OPS(RISCV_OP_REG, RISCV_OP_REG, RISCV_OP_REG); \ uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ - RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[2].reg); + RzILOpBitVector *rs1 = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *rs2 = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[2].reg); #define DECODE_RS_IMM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_IMM); \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ + REQUIRE_2OPS(RISCV_OP_REG, RISCV_OP_IMM); \ + RzILOpBitVector *rs = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[0].reg); \ RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].imm); #define DECODE_RS_RS_IMM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_IMM); \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ - RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); \ + REQUIRE_3OPS(RISCV_OP_REG, RISCV_OP_REG, RISCV_OP_IMM); \ + RzILOpBitVector *rs1 = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *rs2 = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].reg); \ RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[2].imm); #define DECODE_RD_RS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_2OPS(RISCV_OP_REG, RISCV_OP_REG); \ uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); + RzILOpBitVector *rs = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].reg); #define DECODE_IMM(analysis, insn) \ REQUIRE_OP(0, RISCV_OP_IMM); \ RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[0].imm); #define DECODE_RD_IMM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_IMM); \ + REQUIRE_2OPS(RISCV_OP_REG, RISCV_OP_IMM); \ uint32_t rd = insn->detail->riscv.operands[0].reg; \ RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].imm); #define DECODE_RS_RS_IMM_MEM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_MEM); \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[0].reg); \ - RzILOpBitVector *rs2 = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + REQUIRE_2OPS(RISCV_OP_REG, RISCV_OP_MEM); \ + RzILOpBitVector *rs1 = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *rs2 = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].mem.base); \ RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); #define DECODE_RD_RS_IMM_MEM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_MEM); \ + REQUIRE_2OPS(RISCV_OP_REG, RISCV_OP_MEM); \ uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *rs = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].mem.base); \ RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); // used for *w instructions in RV64 that truncate the operands to 32 bits then does the operation #define DECODE_RD_RS_RS_TRUNCATE32(analysis, insn) \ REQUIRE_64_BIT(analysis); \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ + REQUIRE_3OPS(RISCV_OP_REG, RISCV_OP_REG, RISCV_OP_REG); \ uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs1 = CAST(32, IL_FALSE, RISCV_GET_REG(insn->detail->riscv.operands[1].reg)); \ - RzILOpBitVector *rs2 = CAST(32, IL_FALSE, RISCV_GET_REG(insn->detail->riscv.operands[2].reg)); + RzILOpBitVector *rs1 = CAST(32, IL_FALSE, riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].reg)); \ + RzILOpBitVector *rs2 = CAST(32, IL_FALSE, riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[2].reg)); #define DECODE_RD_RS_IMM_TRUNCATE32(analysis, insn) \ REQUIRE_64_BIT(analysis); \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_IMM); \ + REQUIRE_3OPS(RISCV_OP_REG, RISCV_OP_REG, RISCV_OP_IMM); \ uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = CAST(32, IL_FALSE, RISCV_GET_REG(insn->detail->riscv.operands[1].reg)); \ + RzILOpBitVector *rs = CAST(32, IL_FALSE, riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].reg)); \ RzILOpBitVector *imm = SN(32, insn->detail->riscv.operands[2].imm); #define DECODE_RD_IMM_TRUNCATE32(analysis, insn) \ REQUIRE_64_BIT(analysis); \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_IMM); \ + REQUIRE_2OPS(RISCV_OP_REG, RISCV_OP_IMM); \ uint32_t rd = insn->detail->riscv.operands[0].reg; \ RzILOpBitVector *imm = SN(32, insn->detail->riscv.operands[1].imm); From 47ff84a4228d844ca9a122d242b9d6e0fae60403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Sat, 16 May 2026 19:22:41 +0300 Subject: [PATCH 4/9] implement the rest of the multiplication extension --- librz/arch/isa/riscv/riscv_il.c | 8 ++++++++ librz/arch/isa/riscv/riscv_il_m.h | 21 ++++++++++++++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/librz/arch/isa/riscv/riscv_il.c b/librz/arch/isa/riscv/riscv_il.c index 61f99b2fb14..5a43a4352d6 100644 --- a/librz/arch/isa/riscv/riscv_il.c +++ b/librz/arch/isa/riscv/riscv_il.c @@ -75,9 +75,17 @@ static const RiscvInstructionLifter riscv_lifters[] = { USE_LIFTER(lwu, LWU), // M extension USE_LIFTER(mul, MUL), + USE_LIFTER(mulh, MULH), + USE_LIFTER(mulhsu, MULHSU), USE_LIFTER(mulhu, MULHU), + USE_LIFTER(div, DIV), USE_LIFTER(divu, DIVU), + USE_LIFTER(rem, REM), USE_LIFTER(remu, REMU), + USE_LIFTER(mulw, MULW), + USE_LIFTER(divw, DIVW), + USE_LIFTER(divuw, DIVUW), + USE_LIFTER(remw, REMW), USE_LIFTER(remuw, REMUW), /* ---------------------------------- Compressed ---------------------------------*/ USE_LIFTER(c_addi, C_ADDI), diff --git a/librz/arch/isa/riscv/riscv_il_m.h b/librz/arch/isa/riscv/riscv_il_m.h index e3f666f6a44..96f77d45961 100644 --- a/librz/arch/isa/riscv/riscv_il_m.h +++ b/librz/arch/isa/riscv/riscv_il_m.h @@ -9,11 +9,22 @@ #include // M extension: multiply/divide/remainder (RV32M / RV64M) -DEFINE_LIFTER(mul, DECODE_RD_RS_RS, MUL(rs1, rs2)) -DEFINE_LIFTER(mulhu, DECODE_RD_RS_RS, CAST(analysis->bits, IL_FALSE, SHIFTR0(MUL(UNSIGNED(analysis->bits * 2, rs1), UNSIGNED(analysis->bits * 2, rs2)), UN(8, analysis->bits)))) -DEFINE_LIFTER(divu, DECODE_RD_RS_RS, DIV(rs1, rs2)) -DEFINE_LIFTER(remu, DECODE_RD_RS_RS, MOD(rs1, rs2)) -// RV64M: unsigned remainder of 32-bit operands, result sign-extended to 64 bits + +// RV32M +DEFINE_LIFTER(mul, DECODE_RD_RS_RS, MUL(rs1, rs2)) +DEFINE_LIFTER(mulh, DECODE_RD_RS_RS, CAST(analysis->bits, IL_FALSE, SHIFTR0(MUL(SIGNED(analysis->bits * 2, rs1), SIGNED(analysis->bits * 2, rs2)), UN(8, analysis->bits)))) +DEFINE_LIFTER(mulhsu, DECODE_RD_RS_RS, CAST(analysis->bits, IL_FALSE, SHIFTR0(MUL(SIGNED(analysis->bits * 2, rs1), UNSIGNED(analysis->bits * 2, rs2)), UN(8, analysis->bits)))) +DEFINE_LIFTER(mulhu, DECODE_RD_RS_RS, CAST(analysis->bits, IL_FALSE, SHIFTR0(MUL(UNSIGNED(analysis->bits * 2, rs1), UNSIGNED(analysis->bits * 2, rs2)), UN(8, analysis->bits)))) +DEFINE_LIFTER(div, DECODE_RD_RS_RS, SDIV(rs1, rs2)) +DEFINE_LIFTER(divu, DECODE_RD_RS_RS, DIV(rs1, rs2)) +DEFINE_LIFTER(rem, DECODE_RD_RS_RS, SMOD(rs1, rs2)) +DEFINE_LIFTER(remu, DECODE_RD_RS_RS, MOD(rs1, rs2)) + +// RV64M: *w instructions operate on lower 32 bits, result sign-extended to 64 bits +DEFINE_LIFTER(mulw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, MUL(rs1, rs2))) +DEFINE_LIFTER(divw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, SDIV(rs1, rs2))) +DEFINE_LIFTER(divuw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, DIV(rs1, rs2))) +DEFINE_LIFTER(remw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, SMOD(rs1, rs2))) DEFINE_LIFTER(remuw, DECODE_RD_RS_RS_TRUNCATE32, SIGNED(analysis->bits, MOD(rs1, rs2))) #include From 3e55eceaa3c2b8e7da33d0448e86403e9bae09f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Thu, 14 May 2026 22:02:17 +0300 Subject: [PATCH 5/9] implement the atomic extension trivially by ignoring concurrency guards --- librz/arch/isa/riscv/riscv_il.c | 100 ++++++++++++ librz/arch/isa/riscv/riscv_il_a.h | 226 +++++++++++++++++++++++++++ librz/arch/isa/riscv/riscv_il_base.h | 20 ++- 3 files changed, 342 insertions(+), 4 deletions(-) create mode 100644 librz/arch/isa/riscv/riscv_il_a.h diff --git a/librz/arch/isa/riscv/riscv_il.c b/librz/arch/isa/riscv/riscv_il.c index 5a43a4352d6..0200f4575a7 100644 --- a/librz/arch/isa/riscv/riscv_il.c +++ b/librz/arch/isa/riscv/riscv_il.c @@ -4,6 +4,7 @@ #include "riscv_il.h" #include "riscv_il_integer.h" #include "riscv_il_m.h" +#include "riscv_il_a.h" #include "riscv_il_compressed.h" static void label_ecall(RzILVM *vm, RzILOpEffect *op) { @@ -87,6 +88,105 @@ static const RiscvInstructionLifter riscv_lifters[] = { USE_LIFTER(divuw, DIVUW), USE_LIFTER(remw, REMW), USE_LIFTER(remuw, REMUW), + /* ---------------------------------- A extension ---------------------------------*/ + // Load-Reserved / Store-Conditional + USE_LIFTER(lr_w, LR_W), + USE_LIFTER(lr_w_aq, LR_W_AQ), + USE_LIFTER(lr_w_rl, LR_W_RL), + USE_LIFTER(lr_w_aqrl, LR_W_AQRL), + USE_LIFTER(lr_d, LR_D), + USE_LIFTER(lr_d_aq, LR_D_AQ), + USE_LIFTER(lr_d_rl, LR_D_RL), + USE_LIFTER(lr_d_aqrl, LR_D_AQRL), + USE_LIFTER(sc_w, SC_W), + USE_LIFTER(sc_w_aq, SC_W_AQ), + USE_LIFTER(sc_w_rl, SC_W_RL), + USE_LIFTER(sc_w_aqrl, SC_W_AQRL), + USE_LIFTER(sc_d, SC_D), + USE_LIFTER(sc_d_aq, SC_D_AQ), + USE_LIFTER(sc_d_rl, SC_D_RL), + USE_LIFTER(sc_d_aqrl, SC_D_AQRL), + // AMO swap + USE_LIFTER(amoswap_w, AMOSWAP_W), + USE_LIFTER(amoswap_w_aq, AMOSWAP_W_AQ), + USE_LIFTER(amoswap_w_rl, AMOSWAP_W_RL), + USE_LIFTER(amoswap_w_aqrl, AMOSWAP_W_AQRL), + USE_LIFTER(amoswap_d, AMOSWAP_D), + USE_LIFTER(amoswap_d_aq, AMOSWAP_D_AQ), + USE_LIFTER(amoswap_d_rl, AMOSWAP_D_RL), + USE_LIFTER(amoswap_d_aqrl, AMOSWAP_D_AQRL), + // AMO add + USE_LIFTER(amoadd_w, AMOADD_W), + USE_LIFTER(amoadd_w_aq, AMOADD_W_AQ), + USE_LIFTER(amoadd_w_rl, AMOADD_W_RL), + USE_LIFTER(amoadd_w_aqrl, AMOADD_W_AQRL), + USE_LIFTER(amoadd_d, AMOADD_D), + USE_LIFTER(amoadd_d_aq, AMOADD_D_AQ), + USE_LIFTER(amoadd_d_rl, AMOADD_D_RL), + USE_LIFTER(amoadd_d_aqrl, AMOADD_D_AQRL), + // AMO xor + USE_LIFTER(amoxor_w, AMOXOR_W), + USE_LIFTER(amoxor_w_aq, AMOXOR_W_AQ), + USE_LIFTER(amoxor_w_rl, AMOXOR_W_RL), + USE_LIFTER(amoxor_w_aqrl, AMOXOR_W_AQRL), + USE_LIFTER(amoxor_d, AMOXOR_D), + USE_LIFTER(amoxor_d_aq, AMOXOR_D_AQ), + USE_LIFTER(amoxor_d_rl, AMOXOR_D_RL), + USE_LIFTER(amoxor_d_aqrl, AMOXOR_D_AQRL), + // AMO and + USE_LIFTER(amoand_w, AMOAND_W), + USE_LIFTER(amoand_w_aq, AMOAND_W_AQ), + USE_LIFTER(amoand_w_rl, AMOAND_W_RL), + USE_LIFTER(amoand_w_aqrl, AMOAND_W_AQRL), + USE_LIFTER(amoand_d, AMOAND_D), + USE_LIFTER(amoand_d_aq, AMOAND_D_AQ), + USE_LIFTER(amoand_d_rl, AMOAND_D_RL), + USE_LIFTER(amoand_d_aqrl, AMOAND_D_AQRL), + // AMO or + USE_LIFTER(amoor_w, AMOOR_W), + USE_LIFTER(amoor_w_aq, AMOOR_W_AQ), + USE_LIFTER(amoor_w_rl, AMOOR_W_RL), + USE_LIFTER(amoor_w_aqrl, AMOOR_W_AQRL), + USE_LIFTER(amoor_d, AMOOR_D), + USE_LIFTER(amoor_d_aq, AMOOR_D_AQ), + USE_LIFTER(amoor_d_rl, AMOOR_D_RL), + USE_LIFTER(amoor_d_aqrl, AMOOR_D_AQRL), + // AMO signed min + USE_LIFTER(amomin_w, AMOMIN_W), + USE_LIFTER(amomin_w_aq, AMOMIN_W_AQ), + USE_LIFTER(amomin_w_rl, AMOMIN_W_RL), + USE_LIFTER(amomin_w_aqrl, AMOMIN_W_AQRL), + USE_LIFTER(amomin_d, AMOMIN_D), + USE_LIFTER(amomin_d_aq, AMOMIN_D_AQ), + USE_LIFTER(amomin_d_rl, AMOMIN_D_RL), + USE_LIFTER(amomin_d_aqrl, AMOMIN_D_AQRL), + // AMO signed max + USE_LIFTER(amomax_w, AMOMAX_W), + USE_LIFTER(amomax_w_aq, AMOMAX_W_AQ), + USE_LIFTER(amomax_w_rl, AMOMAX_W_RL), + USE_LIFTER(amomax_w_aqrl, AMOMAX_W_AQRL), + USE_LIFTER(amomax_d, AMOMAX_D), + USE_LIFTER(amomax_d_aq, AMOMAX_D_AQ), + USE_LIFTER(amomax_d_rl, AMOMAX_D_RL), + USE_LIFTER(amomax_d_aqrl, AMOMAX_D_AQRL), + // AMO unsigned min + USE_LIFTER(amominu_w, AMOMINU_W), + USE_LIFTER(amominu_w_aq, AMOMINU_W_AQ), + USE_LIFTER(amominu_w_rl, AMOMINU_W_RL), + USE_LIFTER(amominu_w_aqrl, AMOMINU_W_AQRL), + USE_LIFTER(amominu_d, AMOMINU_D), + USE_LIFTER(amominu_d_aq, AMOMINU_D_AQ), + USE_LIFTER(amominu_d_rl, AMOMINU_D_RL), + USE_LIFTER(amominu_d_aqrl, AMOMINU_D_AQRL), + // AMO unsigned max + USE_LIFTER(amomaxu_w, AMOMAXU_W), + USE_LIFTER(amomaxu_w_aq, AMOMAXU_W_AQ), + USE_LIFTER(amomaxu_w_rl, AMOMAXU_W_RL), + USE_LIFTER(amomaxu_w_aqrl, AMOMAXU_W_AQRL), + USE_LIFTER(amomaxu_d, AMOMAXU_D), + USE_LIFTER(amomaxu_d_aq, AMOMAXU_D_AQ), + USE_LIFTER(amomaxu_d_rl, AMOMAXU_D_RL), + USE_LIFTER(amomaxu_d_aqrl, AMOMAXU_D_AQRL), /* ---------------------------------- Compressed ---------------------------------*/ USE_LIFTER(c_addi, C_ADDI), USE_LIFTER(c_addi16sp, C_ADDI16SP), diff --git a/librz/arch/isa/riscv/riscv_il_a.h b/librz/arch/isa/riscv/riscv_il_a.h new file mode 100644 index 00000000000..692ad2781a2 --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_a.h @@ -0,0 +1,226 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_A_H +#define RISCV_IL_A_H + +#include "riscv_il_base.h" + +#include + +// Decoder: rd=REG[0], addr=MEM[1].base (lr.w / lr.d) +#define DECODE_RD_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *addr = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].mem.base); + +// Decoder: rd=REG[0], addr=MEM[1].base, rs2=REG[2] (sc.* / amo*.*) +#define DECODE_RD_MEM_RS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *addr = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *rs2 = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[2].reg); + +// 64-bit-only variants (RV64A .d instructions) +#define DECODE_RD_MEM_64(analysis, insn) \ + REQUIRE_64_BIT(analysis); \ + DECODE_RD_MEM(analysis, insn) + +#define DECODE_RD_MEM_RS_64(analysis, insn) \ + REQUIRE_64_BIT(analysis); \ + DECODE_RD_MEM_RS(analysis, insn) + +// A extension: atomic instructions (RV32A / RV64A) +// +// Sequential-execution assumption +// -------------------------------- +// This entire file assumes the RzIL VM is completely sequential with no parallelism or +// asynchrony of any kind. Under that assumption every "atomic" concern reduces as follows: +// +// Acquire/release ordering (.aq / .rl / .aqrl variants) +// Collapse to no-ops. Ordering constraints only matter when multiple execution flows +// share memory concurrently. All ordering variants are therefore aliased to the base +// instruction with no extra fence or barrier logic. +// +// Load-Reserved / Store-Conditional reservations +// Are trivially always valid. The only execution flow that could invalidate a reservation +// between lr and sc are external ones — another hart, a DMA engine, an interrupt +// handler that writes to the same address, memory-mapped I/O side-effects, etc. — +// none of which exist in this model. lr.* is therefore a plain load and sc.* +// is an unconditional store that always reports success (rd = 0). +// +// AMO read-modify-write atomicity +// Is trivially preserved. There is no window in which another execution flow could observe +// or modify memory between the internal load and store, so the straightforward +// SEQ-based implementation is fully correct and complete. +// +// If the VM ever gains any form of parallelism or asynchrony — including but not limited +// to hardware threads (harts), DMA engines, memory-mapped I/O with side-effects, interrupt +// delivery modelled between individual instructions, or speculative / out-of-order execution +// — this file MUST be revisited. + +// Load-Reserved: plain load as in riscv_il_integer.h; reservation is not modelled +DEFINE_LIFTER(lr_w, DECODE_RD_MEM, + analysis->bits == 32 ? LOADW(32, addr) : SIGNED(analysis->bits, LOADW(32, addr))) +DEFINE_ALIAS_LIFTER(lr_w_aq, lr_w) +DEFINE_ALIAS_LIFTER(lr_w_rl, lr_w) +DEFINE_ALIAS_LIFTER(lr_w_aqrl, lr_w) + +DEFINE_LIFTER(lr_d, DECODE_RD_MEM_64, LOADW(64, addr)) +DEFINE_ALIAS_LIFTER(lr_d_aq, lr_d) +DEFINE_ALIAS_LIFTER(lr_d_rl, lr_d) +DEFINE_ALIAS_LIFTER(lr_d_aqrl, lr_d) + +// Store-Conditional: unconditional store as in riscv_il_integer.h, rd = 0 (always succeeds; see sequential assumption above) +DEFINE_LIFTER_WITH_PRE_EFFECT(sc_w, DECODE_RD_MEM_RS, + STOREW(addr, CAST(32, IL_FALSE, rs2)), + UN(analysis->bits, 0)) +DEFINE_ALIAS_LIFTER(sc_w_aq, sc_w) +DEFINE_ALIAS_LIFTER(sc_w_rl, sc_w) +DEFINE_ALIAS_LIFTER(sc_w_aqrl, sc_w) + +DEFINE_LIFTER_WITH_PRE_EFFECT(sc_d, DECODE_RD_MEM_RS_64, + STOREW(addr, rs2), + UN(analysis->bits, 0)) +DEFINE_ALIAS_LIFTER(sc_d_aq, sc_d) +DEFINE_ALIAS_LIFTER(sc_d_rl, sc_d) +DEFINE_ALIAS_LIFTER(sc_d_aqrl, sc_d) + +// AMO .w helper: atomically read-modify-write 32-bit memory, return old value sign-extended to XLEN. +// new32 may reference VARL("_v32") (old 32-bit mem val) and VARL("_r32") (rs2 lower 32 bits). +#define AMO_W(rd, addr, rs2, new32) \ + SEQ5( \ + SETL("_a", (addr)), \ + SETL("_v32", LOADW(32, VARL("_a"))), \ + SETL("_r32", CAST(32, IL_FALSE, (rs2))), \ + STOREW(VARL("_a"), (new32)), \ + riscv_il_set_reg((rd), SIGNED(analysis->bits, VARL("_v32")))) + +// AMO .d helper: atomically read-modify-write 64-bit memory, return old value in rd. +// new64 may reference VARL("_v") (old 64-bit mem val) and VARL("_r") (rs2). +#define AMO_D(rd, addr, rs2, new64) \ + SEQ5( \ + SETL("_a", (addr)), \ + SETL("_v", LOADW(64, VARL("_a"))), \ + SETL("_r", (rs2)), \ + STOREW(VARL("_a"), (new64)), \ + riscv_il_set_reg((rd), VARL("_v"))) + +// AMO swap: mem = rs2, rd = old_mem +DEFINE_LIFTER_WITH_EFFECT(amoswap_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, VARL("_r32"))) +DEFINE_ALIAS_LIFTER(amoswap_w_aq, amoswap_w) +DEFINE_ALIAS_LIFTER(amoswap_w_rl, amoswap_w) +DEFINE_ALIAS_LIFTER(amoswap_w_aqrl, amoswap_w) + +DEFINE_LIFTER_WITH_EFFECT(amoswap_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, VARL("_r"))) +DEFINE_ALIAS_LIFTER(amoswap_d_aq, amoswap_d) +DEFINE_ALIAS_LIFTER(amoswap_d_rl, amoswap_d) +DEFINE_ALIAS_LIFTER(amoswap_d_aqrl, amoswap_d) + +// AMO add +DEFINE_LIFTER_WITH_EFFECT(amoadd_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, ADD(VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amoadd_w_aq, amoadd_w) +DEFINE_ALIAS_LIFTER(amoadd_w_rl, amoadd_w) +DEFINE_ALIAS_LIFTER(amoadd_w_aqrl, amoadd_w) + +DEFINE_LIFTER_WITH_EFFECT(amoadd_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, ADD(VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amoadd_d_aq, amoadd_d) +DEFINE_ALIAS_LIFTER(amoadd_d_rl, amoadd_d) +DEFINE_ALIAS_LIFTER(amoadd_d_aqrl, amoadd_d) + +// AMO xor +DEFINE_LIFTER_WITH_EFFECT(amoxor_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, LOGXOR(VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amoxor_w_aq, amoxor_w) +DEFINE_ALIAS_LIFTER(amoxor_w_rl, amoxor_w) +DEFINE_ALIAS_LIFTER(amoxor_w_aqrl, amoxor_w) + +DEFINE_LIFTER_WITH_EFFECT(amoxor_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, LOGXOR(VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amoxor_d_aq, amoxor_d) +DEFINE_ALIAS_LIFTER(amoxor_d_rl, amoxor_d) +DEFINE_ALIAS_LIFTER(amoxor_d_aqrl, amoxor_d) + +// AMO and +DEFINE_LIFTER_WITH_EFFECT(amoand_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, LOGAND(VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amoand_w_aq, amoand_w) +DEFINE_ALIAS_LIFTER(amoand_w_rl, amoand_w) +DEFINE_ALIAS_LIFTER(amoand_w_aqrl, amoand_w) + +DEFINE_LIFTER_WITH_EFFECT(amoand_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, LOGAND(VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amoand_d_aq, amoand_d) +DEFINE_ALIAS_LIFTER(amoand_d_rl, amoand_d) +DEFINE_ALIAS_LIFTER(amoand_d_aqrl, amoand_d) + +// AMO or +DEFINE_LIFTER_WITH_EFFECT(amoor_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, LOGOR(VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amoor_w_aq, amoor_w) +DEFINE_ALIAS_LIFTER(amoor_w_rl, amoor_w) +DEFINE_ALIAS_LIFTER(amoor_w_aqrl, amoor_w) + +DEFINE_LIFTER_WITH_EFFECT(amoor_d, DECODE_RD_MEM_RS_64, AMO_D(rd, addr, rs2, LOGOR(VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amoor_d_aq, amoor_d) +DEFINE_ALIAS_LIFTER(amoor_d_rl, amoor_d) +DEFINE_ALIAS_LIFTER(amoor_d_aqrl, amoor_d) + +// AMO signed min/max: operands are 32-bit bitvectors (_v32, _r32), so SLT/SGT is 32-bit signed +DEFINE_LIFTER_WITH_EFFECT(amomin_w, DECODE_RD_MEM_RS, + AMO_W(rd, addr, rs2, ITE(SLT(VARL("_v32"), VARL("_r32")), VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amomin_w_aq, amomin_w) +DEFINE_ALIAS_LIFTER(amomin_w_rl, amomin_w) +DEFINE_ALIAS_LIFTER(amomin_w_aqrl, amomin_w) + +DEFINE_LIFTER_WITH_EFFECT(amomin_d, DECODE_RD_MEM_RS_64, + AMO_D(rd, addr, rs2, ITE(SLT(VARL("_v"), VARL("_r")), VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amomin_d_aq, amomin_d) +DEFINE_ALIAS_LIFTER(amomin_d_rl, amomin_d) +DEFINE_ALIAS_LIFTER(amomin_d_aqrl, amomin_d) + +DEFINE_LIFTER_WITH_EFFECT(amomax_w, DECODE_RD_MEM_RS, + AMO_W(rd, addr, rs2, ITE(SGT(VARL("_v32"), VARL("_r32")), VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amomax_w_aq, amomax_w) +DEFINE_ALIAS_LIFTER(amomax_w_rl, amomax_w) +DEFINE_ALIAS_LIFTER(amomax_w_aqrl, amomax_w) + +DEFINE_LIFTER_WITH_EFFECT(amomax_d, DECODE_RD_MEM_RS_64, + AMO_D(rd, addr, rs2, ITE(SGT(VARL("_v"), VARL("_r")), VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amomax_d_aq, amomax_d) +DEFINE_ALIAS_LIFTER(amomax_d_rl, amomax_d) +DEFINE_ALIAS_LIFTER(amomax_d_aqrl, amomax_d) + +// AMO unsigned min/max: _v32/_r32 are 32-bit bitvectors, so ULT/UGT is 32-bit unsigned +DEFINE_LIFTER_WITH_EFFECT(amominu_w, DECODE_RD_MEM_RS, + AMO_W(rd, addr, rs2, ITE(ULT(VARL("_v32"), VARL("_r32")), VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amominu_w_aq, amominu_w) +DEFINE_ALIAS_LIFTER(amominu_w_rl, amominu_w) +DEFINE_ALIAS_LIFTER(amominu_w_aqrl, amominu_w) + +DEFINE_LIFTER_WITH_EFFECT(amominu_d, DECODE_RD_MEM_RS_64, + AMO_D(rd, addr, rs2, ITE(ULT(VARL("_v"), VARL("_r")), VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amominu_d_aq, amominu_d) +DEFINE_ALIAS_LIFTER(amominu_d_rl, amominu_d) +DEFINE_ALIAS_LIFTER(amominu_d_aqrl, amominu_d) + +DEFINE_LIFTER_WITH_EFFECT(amomaxu_w, DECODE_RD_MEM_RS, + AMO_W(rd, addr, rs2, ITE(UGT(VARL("_v32"), VARL("_r32")), VARL("_v32"), VARL("_r32")))) +DEFINE_ALIAS_LIFTER(amomaxu_w_aq, amomaxu_w) +DEFINE_ALIAS_LIFTER(amomaxu_w_rl, amomaxu_w) +DEFINE_ALIAS_LIFTER(amomaxu_w_aqrl, amomaxu_w) + +DEFINE_LIFTER_WITH_EFFECT(amomaxu_d, DECODE_RD_MEM_RS_64, + AMO_D(rd, addr, rs2, ITE(UGT(VARL("_v"), VARL("_r")), VARL("_v"), VARL("_r")))) +DEFINE_ALIAS_LIFTER(amomaxu_d_aq, amomaxu_d) +DEFINE_ALIAS_LIFTER(amomaxu_d_rl, amomaxu_d) +DEFINE_ALIAS_LIFTER(amomaxu_d_aqrl, amomaxu_d) + +#undef DECODE_RD_MEM +#undef DECODE_RD_MEM_RS +#undef DECODE_RD_MEM_64 +#undef DECODE_RD_MEM_RS_64 +#undef AMO_W +#undef AMO_D + +#include + +#endif // RISCV_IL_A_H diff --git a/librz/arch/isa/riscv/riscv_il_base.h b/librz/arch/isa/riscv/riscv_il_base.h index 5c31ce4ce80..abde8bb3c17 100644 --- a/librz/arch/isa/riscv/riscv_il_base.h +++ b/librz/arch/isa/riscv/riscv_il_base.h @@ -28,14 +28,24 @@ static inline RzILOpEffect *riscv_il_set_reg(uint32_t reg, RZ_OWN RZ_NONNULL RzI return riscv_il_set_reg(rd, result); \ } -// by default, a RISC-V jump both sets a destination and sets the PC (i.e., jumps) -#define DEFINE_LIFTER_FOR_JUMP(name, decoder, result, jmp_effect) \ +// rd = result, then post_effect (e.g. jump: set return address, then redirect PC) +#define DEFINE_LIFTER_WITH_POST_EFFECT(name, decoder, result, post_effect) \ static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ decoder(analysis, insn); \ return SEQ2( \ riscv_il_set_reg(rd, result), \ - jmp_effect); \ + post_effect); \ + } + +// pre_effect, then rd = result (e.g. store-conditional: store first, then write success flag) +#define DEFINE_LIFTER_WITH_PRE_EFFECT(name, decoder, pre_effect, result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return SEQ2( \ + pre_effect, \ + riscv_il_set_reg(rd, result)); \ } #define DEFINE_LIFTER_WITH_EFFECT(name, decoder, effect) \ @@ -45,8 +55,10 @@ static inline RzILOpEffect *riscv_il_set_reg(uint32_t reg, RZ_OWN RZ_NONNULL RzI return effect; \ } +// by default, a RISC-V jump both sets a destination and sets the PC (i.e., jumps) +#define DEFINE_LIFTER_FOR_JUMP DEFINE_LIFTER_WITH_POST_EFFECT // oneway jumps are those that don't have a destination register -#define DEFINE_LIFTER_FOR_ONEWAY_JUMP DEFINE_LIFTER_WITH_EFFECT +#define DEFINE_LIFTER_FOR_ONEWAY_JUMP DEFINE_LIFTER_WITH_EFFECT // A more intuitive definition would be: // static const RiscvInstructionLifter rz_riscv_lift_##alias = ...; From 1d30abda9ecdac3e1f8aaada2b223acc237b6e6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Thu, 14 May 2026 22:02:17 +0300 Subject: [PATCH 6/9] implement the atomic extension trivially by ignoring concurrency guards --- librz/arch/isa/riscv/riscv_il_a.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/librz/arch/isa/riscv/riscv_il_a.h b/librz/arch/isa/riscv/riscv_il_a.h index 692ad2781a2..38ccde5336a 100644 --- a/librz/arch/isa/riscv/riscv_il_a.h +++ b/librz/arch/isa/riscv/riscv_il_a.h @@ -97,7 +97,11 @@ DEFINE_ALIAS_LIFTER(sc_d_aqrl, sc_d) SETL("_v32", LOADW(32, VARL("_a"))), \ SETL("_r32", CAST(32, IL_FALSE, (rs2))), \ STOREW(VARL("_a"), (new32)), \ +<<<<<<< HEAD riscv_il_set_reg((rd), SIGNED(analysis->bits, VARL("_v32")))) +======= + RISCV_SET_REG((rd), SIGNED(analysis->bits, VARL("_v32")))) +>>>>>>> 9323674ce4 (implement the atomic extension trivially by ignoring concurrency guards) // AMO .d helper: atomically read-modify-write 64-bit memory, return old value in rd. // new64 may reference VARL("_v") (old 64-bit mem val) and VARL("_r") (rs2). @@ -107,7 +111,11 @@ DEFINE_ALIAS_LIFTER(sc_d_aqrl, sc_d) SETL("_v", LOADW(64, VARL("_a"))), \ SETL("_r", (rs2)), \ STOREW(VARL("_a"), (new64)), \ +<<<<<<< HEAD riscv_il_set_reg((rd), VARL("_v"))) +======= + RISCV_SET_REG((rd), VARL("_v"))) +>>>>>>> 9323674ce4 (implement the atomic extension trivially by ignoring concurrency guards) // AMO swap: mem = rs2, rd = old_mem DEFINE_LIFTER_WITH_EFFECT(amoswap_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, VARL("_r32"))) From 60c433a6389e9a6de7db8bb192488c1d0074329a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Thu, 14 May 2026 22:02:17 +0300 Subject: [PATCH 7/9] add floating and double instructions, and add privlieged ISA instructions like reading CSRs to implement fflags reading and writing --- librz/arch/isa/riscv/riscv_il.c | 101 +++++ librz/arch/isa/riscv/riscv_il_d.h | 421 +++++++++++++++++ librz/arch/isa/riscv/riscv_il_f.h | 422 ++++++++++++++++++ librz/arch/isa/riscv/riscv_il_fd_compressed.h | 14 + .../arch/isa/riscv/riscv_il_float_reg_names.h | 55 +++ librz/arch/isa/riscv/riscv_il_priv.h | 180 ++++++++ subprojects/capstone-next.wrap | 4 +- 7 files changed, 1195 insertions(+), 2 deletions(-) create mode 100644 librz/arch/isa/riscv/riscv_il_d.h create mode 100644 librz/arch/isa/riscv/riscv_il_f.h create mode 100644 librz/arch/isa/riscv/riscv_il_fd_compressed.h create mode 100644 librz/arch/isa/riscv/riscv_il_float_reg_names.h create mode 100644 librz/arch/isa/riscv/riscv_il_priv.h diff --git a/librz/arch/isa/riscv/riscv_il.c b/librz/arch/isa/riscv/riscv_il.c index 0200f4575a7..9d9f8a978bb 100644 --- a/librz/arch/isa/riscv/riscv_il.c +++ b/librz/arch/isa/riscv/riscv_il.c @@ -5,7 +5,11 @@ #include "riscv_il_integer.h" #include "riscv_il_m.h" #include "riscv_il_a.h" +#include "riscv_il_f.h" +#include "riscv_il_d.h" #include "riscv_il_compressed.h" +#include "riscv_il_fd_compressed.h" +#include "riscv_il_priv.h" static void label_ecall(RzILVM *vm, RzILOpEffect *op) { // stub: ecall is handled at the analysis layer @@ -187,6 +191,96 @@ static const RiscvInstructionLifter riscv_lifters[] = { USE_LIFTER(amomaxu_d_aq, AMOMAXU_D_AQ), USE_LIFTER(amomaxu_d_rl, AMOMAXU_D_RL), USE_LIFTER(amomaxu_d_aqrl, AMOMAXU_D_AQRL), + /* ---------------------------------- F extension ---------------------------------*/ + // Memory + USE_LIFTER(flw, FLW), + USE_LIFTER(fsw, FSW), + // Arithmetic + USE_LIFTER(fadd_s, FADD_S), + USE_LIFTER(fsub_s, FSUB_S), + USE_LIFTER(fmul_s, FMUL_S), + USE_LIFTER(fdiv_s, FDIV_S), + USE_LIFTER(fsqrt_s, FSQRT_S), + // Fused multiply-add + USE_LIFTER(fmadd_s, FMADD_S), + USE_LIFTER(fmsub_s, FMSUB_S), + USE_LIFTER(fnmadd_s, FNMADD_S), + USE_LIFTER(fnmsub_s, FNMSUB_S), + // Sign injection + USE_LIFTER(fsgnj_s, FSGNJ_S), + USE_LIFTER(fsgnjn_s, FSGNJN_S), + USE_LIFTER(fsgnjx_s, FSGNJX_S), + // Min / max + USE_LIFTER(fmin_s, FMIN_S), + USE_LIFTER(fmax_s, FMAX_S), + // Comparison + USE_LIFTER(feq_s, FEQ_S), + USE_LIFTER(flt_s, FLT_S), + USE_LIFTER(fle_s, FLE_S), + // Classification + USE_LIFTER(fclass_s, FCLASS_S), + // Conversions float32 → int + USE_LIFTER(fcvt_w_s, FCVT_W_S), + USE_LIFTER(fcvt_wu_s, FCVT_WU_S), + USE_LIFTER(fcvt_l_s, FCVT_L_S), + USE_LIFTER(fcvt_lu_s, FCVT_LU_S), + // Conversions int → float32 + USE_LIFTER(fcvt_s_w, FCVT_S_W), + USE_LIFTER(fcvt_s_wu, FCVT_S_WU), + USE_LIFTER(fcvt_s_l, FCVT_S_L), + USE_LIFTER(fcvt_s_lu, FCVT_S_LU), + // Bit-level move + USE_LIFTER(fmv_x_w, FMV_X_W), + USE_LIFTER(fmv_w_x, FMV_W_X), + /* ---------------------------------- D extension ---------------------------------*/ + // Memory + USE_LIFTER(fld, FLD), + USE_LIFTER(fsd, FSD), + // Arithmetic + USE_LIFTER(fadd_d, FADD_D), + USE_LIFTER(fsub_d, FSUB_D), + USE_LIFTER(fmul_d, FMUL_D), + USE_LIFTER(fdiv_d, FDIV_D), + USE_LIFTER(fsqrt_d, FSQRT_D), + // Fused multiply-add + USE_LIFTER(fmadd_d, FMADD_D), + USE_LIFTER(fmsub_d, FMSUB_D), + USE_LIFTER(fnmadd_d, FNMADD_D), + USE_LIFTER(fnmsub_d, FNMSUB_D), + // Sign injection + USE_LIFTER(fsgnj_d, FSGNJ_D), + USE_LIFTER(fsgnjn_d, FSGNJN_D), + USE_LIFTER(fsgnjx_d, FSGNJX_D), + // Min / max + USE_LIFTER(fmin_d, FMIN_D), + USE_LIFTER(fmax_d, FMAX_D), + // Comparison + USE_LIFTER(feq_d, FEQ_D), + USE_LIFTER(flt_d, FLT_D), + USE_LIFTER(fle_d, FLE_D), + // Classification + USE_LIFTER(fclass_d, FCLASS_D), + // Conversions float64 → int + USE_LIFTER(fcvt_w_d, FCVT_W_D), + USE_LIFTER(fcvt_wu_d, FCVT_WU_D), + USE_LIFTER(fcvt_l_d, FCVT_L_D), + USE_LIFTER(fcvt_lu_d, FCVT_LU_D), + // Conversions int → float64 + USE_LIFTER(fcvt_d_w, FCVT_D_W), + USE_LIFTER(fcvt_d_wu, FCVT_D_WU), + USE_LIFTER(fcvt_d_l, FCVT_D_L), + USE_LIFTER(fcvt_d_lu, FCVT_D_LU), + // Precision conversions + USE_LIFTER(fcvt_d_s, FCVT_D_S), + USE_LIFTER(fcvt_s_d, FCVT_S_D), + // Bit-level move (RV64D only) + USE_LIFTER(fmv_x_d, FMV_X_D), + USE_LIFTER(fmv_d_x, FMV_D_X), + // ---------------------------------- Compressed F/D --------------------------------- + USE_LIFTER(c_fld, C_FLD), + USE_LIFTER(c_fsd, C_FSD), + USE_LIFTER(c_fldsp, C_FLDSP), + USE_LIFTER(c_fsdsp, C_FSDSP), /* ---------------------------------- Compressed ---------------------------------*/ USE_LIFTER(c_addi, C_ADDI), USE_LIFTER(c_addi16sp, C_ADDI16SP), @@ -219,6 +313,13 @@ static const RiscvInstructionLifter riscv_lifters[] = { USE_LIFTER(c_addw, C_ADDW), USE_LIFTER(c_addiw, C_ADDIW), USE_LIFTER(c_subw, C_SUBW), + // ---------------------------------- Privileged instructions --------------------------------- + USE_LIFTER(csrrw, CSRRW), + USE_LIFTER(csrrs, CSRRS), + USE_LIFTER(csrrc, CSRRC), + USE_LIFTER(csrrwi, CSRRWI), + USE_LIFTER(csrrsi, CSRRSI), + USE_LIFTER(csrrci, CSRRCI), }; RZ_OWN RZ_IPI RzILOpEffect * diff --git a/librz/arch/isa/riscv/riscv_il_d.h b/librz/arch/isa/riscv/riscv_il_d.h new file mode 100644 index 00000000000..263281250c1 --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_d.h @@ -0,0 +1,421 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_D_H +#define RISCV_IL_D_H + +#include "riscv_il_base.h" + +#include "riscv_il_f.h" + +#include + +// ----------------------------------------------------------------------- +// D extension: register access (RISCV_REG_F0_D = 74, _D suffix) +// +// When the D extension is present the FP register file is 64 bits wide. +// The IL global variables for ft0-ft11 / fs0-fs11 / fa0-fa7 must be +// declared with width 64 in the IL config (rz_riscv_il_config). +// +// Single-precision values written by F instructions are NaN-boxed: +// the upper 32 bits are all 1s so that D instructions treating the +// register as float64 see a canonical quiet NaN for any narrower value. +// ----------------------------------------------------------------------- +#define RISCV_FREG_D_NAME(reg) riscv_freg_name(reg) +// Read a D register as a float64 IL value. +#define RISCV_GET_FREG_D(reg) FLOATV64(VARG(RISCV_FREG_D_NAME(reg))) +// Read a D register as a raw 64-bit bitvector (sign-injection, fmv, store). +#define RISCV_GET_FREG_D_BV(reg) VARG(RISCV_FREG_D_NAME(reg)) +// Read a D register's lower 32 bits as a float32 IL value (fcvt.d.s source). +#define RISCV_GET_FREG_D_AS_F32(reg) FLOATV32(CAST(32, IL_FALSE, VARG(RISCV_FREG_D_NAME(reg)))) +// Write a float64 IL value into a D register. +#define RISCV_SET_FREG_D(reg, fl) SETG(RISCV_FREG_D_NAME(reg), F2BV(fl)) +// Write a raw 64-bit bitvector into a D register. +#define RISCV_SET_FREG_D_BV(reg, bv) SETG(RISCV_FREG_D_NAME(reg), bv) +// Write a float32 IL value into a D register, NaN-boxed to 64 bits. +// Upper 32 bits are set to 0xFFFFFFFF per the RISC-V NaN-boxing rule. +#define RISCV_SET_FREG_D_F32(reg, fl32) SETG(RISCV_FREG_D_NAME(reg), APPEND(UN(32, 0xFFFFFFFF), F2BV(fl32))) + +// riscv_rm_to_rz is defined in riscv_il_f.h (included above). +#define D_RM riscv_rm_to_rz(insn->detail->riscv.rounding_mode) + +// ----------------------------------------------------------------------- +// Lifter templates +// ----------------------------------------------------------------------- + +// float64 result → D register, with fflags/fcsr update +#define DEFINE_D_LIFTER(name, decoder, fl_result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return SEQ3( \ + SETL("_r", fl_result), \ + RISCV_SET_FREG_D(frd, VARL("_r")), \ + RISCV_ACCUMULATE_FFLAGS()); \ + } + +// raw 64-bit bitvector → D register (sign injection, fmv.d.x) +#define DEFINE_D_LIFTER_BV_TO_FREG(name, decoder, bv_result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return RISCV_SET_FREG_D_BV(frd, bv_result); \ + } + +// float32 NaN-boxed result → D register (fcvt.s.d) +#define DEFINE_D_LIFTER_F32_TO_FREG(name, decoder, fl32_result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return RISCV_SET_FREG_D_F32(frd, fl32_result); \ + } + +// ----------------------------------------------------------------------- +// Decoders +// ----------------------------------------------------------------------- + +// frd=DReg[0], frs1=float64(DReg[1]), frs2=float64(DReg[2]) +#define DECODE_D_FD_FS_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); \ + RzILOpFloat *frs2 = RISCV_GET_FREG_D(insn->detail->riscv.operands[2].reg); + +// frd=DReg[0], raw 64-bit bitvectors (sign injection) +#define DECODE_D_FD_BV_BV(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *bvrs1 = RISCV_GET_FREG_D_BV(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *bvrs2 = RISCV_GET_FREG_D_BV(insn->detail->riscv.operands[2].reg); + +// frd=DReg[0], frs1=float64(DReg[1]) +#define DECODE_D_FD_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); + +// rd=IntReg[0], frs1=float64(DReg[1]), frs2=float64(DReg[2]) (feq/flt/fle) +#define DECODE_D_RD_FS_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); \ + RzILOpFloat *frs2 = RISCV_GET_FREG_D(insn->detail->riscv.operands[2].reg); + +// rd=IntReg[0], frs1=float64(DReg[1]) (fcvt.w.d, fclass.d) +#define DECODE_D_RD_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); + +// rd=IntReg[0], bvrs1=raw64(DReg[1]) (fmv.x.d, fclass.d bit path) +#define DECODE_D_RD_FS_BV(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *bvrs1 = RISCV_GET_FREG_D_BV(insn->detail->riscv.operands[1].reg); + +// frd=DReg[0], rs1=IntReg[1] (fcvt.d.w, fmv.d.x) +#define DECODE_D_FD_RS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); + +// frd=DReg[0], MEM base+offset (fld) +#define DECODE_D_FD_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +// DReg[0] source, MEM base+offset (fsd) +#define DECODE_D_FS_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + RzILOpBitVector *bvrs1 = RISCV_GET_FREG_D_BV(insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +// frd=DReg[0], frs1=float64, frs2=float64, frs3=float64 +#define DECODE_D_FD_FS_FS_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + REQUIRE_OP(3, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); \ + RzILOpFloat *frs2 = RISCV_GET_FREG_D(insn->detail->riscv.operands[2].reg); \ + RzILOpFloat *frs3 = RISCV_GET_FREG_D(insn->detail->riscv.operands[3].reg); + +// frd=DReg[0], frs1=float32 from lower 32 bits of FReg[1] (fcvt.d.s) +// capstone encodes the source with the _F suffix; riscv_freg_name() handles both. +#define DECODE_D_FD_FS_F32(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = FLOATV32(CAST(32, IL_FALSE, VARG(riscv_freg_name(insn->detail->riscv.operands[1].reg)))); + +// frd=DReg[0], frs1=float64 from DReg[1] (fcvt.s.d — dest also a D register) +#define DECODE_D_FD_FS_F64(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); + +// ----------------------------------------------------------------------- +// D Extension: Memory +// ----------------------------------------------------------------------- + +// fld fd, offset(rs1) — load 64-bit double from memory +DEFINE_D_LIFTER_BV_TO_FREG(fld, DECODE_D_FD_MEM, LOADW(64, ADD(rs, imm))) + +// fsd fs2, offset(rs1) — store 64-bit double to memory +DEFINE_LIFTER_WITH_EFFECT(fsd, DECODE_D_FS_MEM, STOREW(ADD(rs, imm), bvrs1)) + +// ----------------------------------------------------------------------- +// Arithmetic +// ----------------------------------------------------------------------- +DEFINE_D_LIFTER(fadd_d, DECODE_D_FD_FS_FS, FADD(D_RM, frs1, frs2)) +DEFINE_D_LIFTER(fsub_d, DECODE_D_FD_FS_FS, FSUB(D_RM, frs1, frs2)) +DEFINE_D_LIFTER(fmul_d, DECODE_D_FD_FS_FS, FMUL(D_RM, frs1, frs2)) +DEFINE_D_LIFTER(fdiv_d, DECODE_D_FD_FS_FS, FDIV(D_RM, frs1, frs2)) +DEFINE_D_LIFTER(fsqrt_d, DECODE_D_FD_FS, FSQRT(D_RM, frs1)) + +// ----------------------------------------------------------------------- +// Fused Multiply-Add +// ----------------------------------------------------------------------- +DEFINE_D_LIFTER(fmadd_d, DECODE_D_FD_FS_FS_FS, FMAD(D_RM, frs1, frs2, frs3)) +DEFINE_D_LIFTER(fmsub_d, DECODE_D_FD_FS_FS_FS, FMAD(D_RM, frs1, frs2, FNEG(frs3))) +DEFINE_D_LIFTER(fnmadd_d, DECODE_D_FD_FS_FS_FS, FNEG(FMAD(D_RM, frs1, frs2, frs3))) +DEFINE_D_LIFTER(fnmsub_d, DECODE_D_FD_FS_FS_FS, FMAD(D_RM, FNEG(frs1), frs2, frs3)) + +// ----------------------------------------------------------------------- +// Sign Injection (bit-level) +// Bit 63 of float64 is the sign bit. +// ----------------------------------------------------------------------- +DEFINE_D_LIFTER_BV_TO_FREG(fsgnj_d, DECODE_D_FD_BV_BV, + LOGOR(LOGAND(bvrs1, UN(64, 0x7FFFFFFFFFFFFFFF)), + LOGAND(bvrs2, UN(64, 0x8000000000000000)))) + +DEFINE_D_LIFTER_BV_TO_FREG(fsgnjn_d, DECODE_D_FD_BV_BV, + LOGOR(LOGAND(bvrs1, UN(64, 0x7FFFFFFFFFFFFFFF)), + LOGAND(LOGNOT(bvrs2), UN(64, 0x8000000000000000)))) + +DEFINE_D_LIFTER_BV_TO_FREG(fsgnjx_d, DECODE_D_FD_BV_BV, + LOGOR(LOGAND(DUP(bvrs1), UN(64, 0x7FFFFFFFFFFFFFFF)), + LOGAND(LOGXOR(bvrs1, bvrs2), UN(64, 0x8000000000000000)))) + +// ----------------------------------------------------------------------- +// D Extension: Min / Max +// +// IEEE 754-201x minimumNumber / maximumNumber (RISC-V D spec >= 2.2): +// - signaling NaN operand → raise NV, return canonical qNaN +// - exactly one quiet NaN → return the non-NaN operand +// - both quiet NaN → return canonical qNaN +// - otherwise → normal min / max +// +// Float64 layout: sign[63], exponent[62:52] (11 bits), mantissa[51:0] (52 bits), +// quiet bit[51]. +// A value is sNaN iff exponent==0x7FF && mantissa!=0 && quiet_bit==0. +// cond(a, b): FLE for fmin_d, FGE for fmax_d. +// ----------------------------------------------------------------------- +#define DEFINE_LIFTER_MINMAX(name, cond) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + uint32_t frs1_reg = insn->detail->riscv.operands[1].reg; \ + uint32_t frs2_reg = insn->detail->riscv.operands[2].reg; \ + return SEQN(10, \ + /* _bva: raw 64-bit bitvector of frs1, needed for bit-level sNaN inspection */ \ + SETL("_bva", RISCV_GET_FREG_D_BV(frs1_reg)), \ + /* _bvb: raw 64-bit bitvector of frs2, needed for bit-level sNaN inspection */ \ + SETL("_bvb", RISCV_GET_FREG_D_BV(frs2_reg)), \ + /* _a: frs1 reinterpreted as float64 for IL float comparisons */ \ + SETL("_a", FLOATV64(VARL("_bva"))), \ + /* _b: frs2 reinterpreted as float64 for IL float comparisons */ \ + SETL("_b", FLOATV64(VARL("_bvb"))), \ + /* _na: true if frs1 is any NaN (exponent==0x7FF and mantissa!=0) */ \ + SETL("_na", AND(EQ(EXTRACT64(VARL("_bva"), UN(64, 52), UN(64, 11)), UN(11, 0x7FF)), \ + NON_ZERO(EXTRACT64(VARL("_bva"), UN(64, 0), UN(64, 52))))), \ + /* _nb: true if frs2 is any NaN */ \ + SETL("_nb", AND(EQ(EXTRACT64(VARL("_bvb"), UN(64, 52), UN(64, 11)), UN(11, 0x7FF)), \ + NON_ZERO(EXTRACT64(VARL("_bvb"), UN(64, 0), UN(64, 52))))), \ + /* _sa: true if frs1 is a signaling NaN (NaN with quiet bit[51]==0) */ \ + SETL("_sa", AND(VARL("_na"), INV(NON_ZERO(EXTRACT64(VARL("_bva"), UN(64, 51), UN(64, 1)))))), \ + /* _sb: true if frs2 is a signaling NaN */ \ + SETL("_sb", AND(VARL("_nb"), INV(NON_ZERO(EXTRACT64(VARL("_bvb"), UN(64, 51), UN(64, 1)))))), \ + /* raise NV (invalid operation, bit 4) in fcsr when either operand is sNaN */ \ + SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_sa"), VARL("_sb")), UN(64, 0x10), UN(64, 0)))), \ + RISCV_SET_FREG_D(frd, \ + ITE(OR(VARL("_sa"), VARL("_sb")), IL_FQNAN(RZ_FLOAT_IEEE754_BIN_64), \ + ITE(VARL("_na"), VARL("_b"), \ + ITE(VARL("_nb"), VARL("_a"), \ + ITE(cond(VARL("_a"), VARL("_b")), VARL("_a"), VARL("_b"))))))); \ + } + +DEFINE_LIFTER_MINMAX(fmin_d, FLE) +DEFINE_LIFTER_MINMAX(fmax_d, FGE) + +// ----------------------------------------------------------------------- +// D Extension: Comparison (result in integer register) +// ----------------------------------------------------------------------- +DEFINE_LIFTER(feq_d, DECODE_D_RD_FS_FS, BOOL_TO_BV(FEQ(frs1, frs2), analysis->bits)) +DEFINE_LIFTER(flt_d, DECODE_D_RD_FS_FS, BOOL_TO_BV(FLT(frs1, frs2), analysis->bits)) +DEFINE_LIFTER(fle_d, DECODE_D_RD_FS_FS, BOOL_TO_BV(FLE(frs1, frs2), analysis->bits)) + +// ----------------------------------------------------------------------- +// D Extension: fclass.d +// +// Same 10-bit one-hot classification as fclass.s, applied to float64. +// +// Float64 layout: sign[63], exponent[62:52] (11 bits), mantissa[51:0] (52 bits), +// quiet bit[51]. +// Exponent 0x7FF indicates NaN or infinity. +// ----------------------------------------------------------------------- +static RzILOpEffect *rz_riscv_lift_fclass_d(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_D_RD_FS_BV(analysis, insn); + int xlen = analysis->bits; +#define FBIT_D(n, cond) SHIFTL0(BOOL_TO_BV(cond, xlen), UN(xlen, (n))) + return SEQN(14, + SETL("_b", bvrs1), + SETL("_ex", EXTRACT64(VARL("_b"), UN(64, 52), UN(64, 11))), + SETL("_mn", EXTRACT64(VARL("_b"), UN(64, 0), UN(64, 52))), + SETL("_sg", NON_ZERO(EXTRACT64(VARL("_b"), UN(64, 63), UN(64, 1)))), + SETL("_qt", NON_ZERO(EXTRACT64(VARL("_b"), UN(64, 51), UN(64, 1)))), + SETL("_xff", EQ(VARL("_ex"), UN(11, 0x7FF))), + SETL("_xz", IS_ZERO(VARL("_ex"))), + SETL("_mz", IS_ZERO(VARL("_mn"))), + SETL("_na", AND(VARL("_xff"), INV(VARL("_mz")))), + SETL("_in", AND(VARL("_xff"), VARL("_mz"))), + SETL("_su", AND(VARL("_xz"), INV(VARL("_mz")))), + SETL("_ze", AND(VARL("_xz"), VARL("_mz"))), + SETL("_no", AND(INV(VARL("_xz")), INV(VARL("_xff")))), + RISCV_SET_REG(rd, + LOGOR(FBIT_D(0, AND(VARL("_sg"), VARL("_in"))), + LOGOR(FBIT_D(1, AND(VARL("_sg"), VARL("_no"))), + LOGOR(FBIT_D(2, AND(VARL("_sg"), VARL("_su"))), + LOGOR(FBIT_D(3, AND(VARL("_sg"), VARL("_ze"))), + LOGOR(FBIT_D(4, AND(INV(VARL("_sg")), VARL("_ze"))), + LOGOR(FBIT_D(5, AND(INV(VARL("_sg")), VARL("_su"))), + LOGOR(FBIT_D(6, AND(INV(VARL("_sg")), VARL("_no"))), + LOGOR(FBIT_D(7, AND(INV(VARL("_sg")), VARL("_in"))), + LOGOR(FBIT_D(8, AND(VARL("_na"), INV(VARL("_qt")))), + FBIT_D(9, AND(VARL("_na"), VARL("_qt")))))))))))))); +#undef FBIT_D +} + +// ----------------------------------------------------------------------- +// D Extension: Conversions float64 → integer +// ----------------------------------------------------------------------- + +// fcvt.w.d rd, fs1 — float64 → signed int32, sign-extended to XLEN +DEFINE_LIFTER(fcvt_w_d, DECODE_D_RD_FS, + SIGNED(analysis->bits, F2SINT(32, D_RM, frs1))) + +// fcvt.wu.d rd, fs1 — float64 → unsigned int32, sign-extended to XLEN +DEFINE_LIFTER(fcvt_wu_d, DECODE_D_RD_FS, + SIGNED(analysis->bits, F2INT(32, D_RM, frs1))) + +// fcvt.l.d rd, fs1 — float64 → signed int64 (RV64D only) +static RzILOpEffect *rz_riscv_lift_fcvt_l_d(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_D_RD_FS(analysis, insn); + return RISCV_SET_REG(rd, F2SINT(64, D_RM, frs1)); +} + +// fcvt.lu.d rd, fs1 — float64 → unsigned int64 (RV64D only) +static RzILOpEffect *rz_riscv_lift_fcvt_lu_d(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_D_RD_FS(analysis, insn); + return RISCV_SET_REG(rd, F2INT(64, D_RM, frs1)); +} + +// ----------------------------------------------------------------------- +// D Extension: Conversions integer → float64 +// ----------------------------------------------------------------------- + +// fcvt.d.w fd, rs1 — signed int32 → float64 +DEFINE_D_LIFTER(fcvt_d_w, DECODE_D_FD_RS, + SINT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, CAST(32, IL_FALSE, rs1))) + +// fcvt.d.wu fd, rs1 — unsigned int32 → float64 +DEFINE_D_LIFTER(fcvt_d_wu, DECODE_D_FD_RS, + INT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, CAST(32, IL_FALSE, rs1))) + +// fcvt.d.l fd, rs1 — signed int64 → float64 (RV64D only) +static RzILOpEffect *rz_riscv_lift_fcvt_d_l(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_D_FD_RS(analysis, insn); + return RISCV_SET_FREG_D(frd, SINT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, rs1)); +} + +// fcvt.d.lu fd, rs1 — unsigned int64 → float64 (RV64D only) +static RzILOpEffect *rz_riscv_lift_fcvt_d_lu(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_D_FD_RS(analysis, insn); + return RISCV_SET_FREG_D(frd, INT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, rs1)); +} + +// ----------------------------------------------------------------------- +// D Extension: Precision conversions +// +// NaN-boxing note +// --------------- +// When the D extension is present the FP register file is 64 bits wide. +// A float32 result stored into an FP register must be NaN-boxed: the upper +// 32 bits are forced to 0xFFFFFFFF. RISCV_SET_FREG_D_F32 handles this. +// +// When reading a float32 source from a D register the lower 32 bits +// are used; the upper NaN-box bits are discarded by CAST(32, IL_FALSE, ...). +// ----------------------------------------------------------------------- + +// fcvt.d.s fd, fs1 — float32 (NaN-boxed in D reg) → float64 +// capstone encodes fs1 with the _F suffix; DECODE_D_FD_FS_F32 reads the +// lower 32 bits of the 64-bit register and reinterprets as float32. +DEFINE_D_LIFTER(fcvt_d_s, DECODE_D_FD_FS_F32, + FCONVERT(RZ_FLOAT_IEEE754_BIN_64, D_RM, frs1)) + +// fcvt.s.d fd, fs1 — float64 → float32, NaN-boxed into D register +DEFINE_D_LIFTER_F32_TO_FREG(fcvt_s_d, DECODE_D_FD_FS_F64, + FCONVERT(RZ_FLOAT_IEEE754_BIN_32, D_RM, frs1)) + +// ----------------------------------------------------------------------- +// D Extension: Bit-level Move (RV64D only) +// ----------------------------------------------------------------------- + +// fmv.x.d rd, fs1 — copy float64 bits to integer register (RV64D) +static RzILOpEffect *rz_riscv_lift_fmv_x_d(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_D_RD_FS_BV(analysis, insn); + return RISCV_SET_REG(rd, bvrs1); +} + +// fmv.d.x fd, rs1 — copy integer register bits to float64 register (RV64D) +static RzILOpEffect *rz_riscv_lift_fmv_d_x(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_D_FD_RS(analysis, insn); + return RISCV_SET_FREG_D_BV(frd, rs1); +} + +#include + +#endif // RISCV_IL_D_H diff --git a/librz/arch/isa/riscv/riscv_il_f.h b/librz/arch/isa/riscv/riscv_il_f.h new file mode 100644 index 00000000000..e117d54f28b --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_f.h @@ -0,0 +1,422 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_F_H +#define RISCV_IL_F_H + +#include "riscv_il_base.h" + +#include +#include + +#include "riscv_il_float_reg_names.h" + +// ----------------------------------------------------------------------- +// F extension: register access (RISCV_REG_F0_F = 106, _F suffix) +// +// In an F-only implementation the FP registers are 32-bit IL global +// variables whose raw bits hold the IEEE 754 binary32 value. +// ----------------------------------------------------------------------- +#define RISCV_FREG_F_NAME(reg) riscv_freg_names[(reg) - RISCV_REG_F0_F] + +// The register is 64-bit (NaN-boxed); hence extracting the lower 32 bits. +#define RISCV_GET_FREG_RAW(reg) CAST(32, IL_FALSE, VARG(RISCV_FREG_F_NAME(reg))) +// Write a raw 32-bit bitvector into a float register, NaN-boxing to 64 bits. +#define RISCV_SET_FREG_RAW(reg, val) SETG(RISCV_FREG_F_NAME(reg), APPEND(UN(32, 0xFFFFFFFF), val)) + +// Read a float register as a float32 IL value +#define RISCV_GET_FREG_F(reg) FLOATV32(RISCV_GET_FREG_RAW(reg)) +// Read a float register as a raw 32-bit bitvector +#define RISCV_GET_FREG_F_BV(reg) RISCV_GET_FREG_RAW(reg) +// Write a float32 IL value into a float register +#define RISCV_SET_FREG_F(reg, fl) RISCV_SET_FREG_RAW(reg, F2BV(fl)) +// Write a raw 32-bit bitvector into a float register +#define RISCV_SET_FREG_F_BV(reg, bv) RISCV_SET_FREG_RAW(reg, bv) + +// Map Capstone's RISC-V rounding mode to RzFloat's rounding mode. + +// RzIL float operations (FADD, FMUL, F2SINT, ...) accept a RzFloatRMode enum +// value that is baked into the IL expression at lift time — it is a +// compile-time constant in the IL tree, not a runtime value. There is +// currently no RzIL mechanism to pass a variable (e.g. VARG("fcsr")) as the +// rounding mode of a float operation, so RISCV_RM_DYN cannot be faithfully +// represented. Instructions that use dynamic rounding are lifted with RNE as +// a fallback, which is architecturally incorrect whenever frm != RNE at +// runtime but is the best approximation available without changes to the RzIL +// float layer. +static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { + switch (rm) { + case RISCV_RM_RNE: return RZ_FLOAT_RMODE_RNE; + case RISCV_RM_RTZ: return RZ_FLOAT_RMODE_RTZ; + case RISCV_RM_RDN: return RZ_FLOAT_RMODE_RTN; + case RISCV_RM_RUP: return RZ_FLOAT_RMODE_RTP; + case RISCV_RM_RMM: return RZ_FLOAT_RMODE_RNA; + default: return RZ_FLOAT_RMODE_RNE; // RISCV_RM_DYN / RISCV_RM_INVALID: see above + } +} + +#define F_RM riscv_rm_to_rz(insn->detail->riscv.rounding_mode) + +// fflags / fcsr helpers +// RISC-V fflags layout (bits 4:0 of fcsr): +// bit 0 NX inexact RZ_FLOAT_E_INEXACT +// bit 1 UF underflow RZ_FLOAT_E_UNDERFLOW +// bit 2 OF overflow RZ_FLOAT_E_OVERFLOW +// bit 3 DZ divide-by-zero RZ_FLOAT_E_DIV_ZERO +// bit 4 NV invalid RZ_FLOAT_E_INVALID_OP +// +// Usage: set local float variable "_r" to the result, then call +// RISCV_ACCUMULATE_FFLAGS() to sticky-OR exceptions into "fflags" +// and keep "fcsr" in sync. +#define RISCV_F_EXC(riscv_bit, rz_exc) \ + ITE(FEXCEPT(rz_exc, VARL("_r")), UN(64, riscv_bit), UN(64, 0)) + +#define RISCV_ACCUMULATE_FFLAGS() \ + SETG("fcsr", LOGOR(VARG("fcsr"), \ + LOGOR(RISCV_F_EXC(0x01, RZ_FLOAT_E_INEXACT), \ + LOGOR(RISCV_F_EXC(0x02, RZ_FLOAT_E_UNDERFLOW), \ + LOGOR(RISCV_F_EXC(0x04, RZ_FLOAT_E_OVERFLOW), \ + LOGOR(RISCV_F_EXC(0x08, RZ_FLOAT_E_DIV_ZERO), \ + RISCV_F_EXC(0x10, RZ_FLOAT_E_INVALID_OP))))))) + +// ----------------------------------------------------------------------- +// Lifter templates +// ----------------------------------------------------------------------- + +// float32 result → float destination register, with fflags/fcsr update +#define DEFINE_F_LIFTER(name, decoder, fl_result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return SEQ3( \ + SETL("_r", fl_result), \ + RISCV_SET_FREG_F(frd, VARL("_r")), \ + RISCV_ACCUMULATE_FFLAGS()); \ + } + +// raw 32-bit bitvector → float destination register +#define DEFINE_F_LIFTER_BV_TO_FREG(name, decoder, bv_result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return RISCV_SET_FREG_F_BV(frd, bv_result); \ + } + +// ----------------------------------------------------------------------- +// Decoders +// ----------------------------------------------------------------------- + +#define DECODE_F_FD_FS_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); \ + RzILOpFloat *frs2 = RISCV_GET_FREG_F(insn->detail->riscv.operands[2].reg); + +#define DECODE_F_FD_BV_BV(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *bvrs1 = RISCV_GET_FREG_F_BV(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *bvrs2 = RISCV_GET_FREG_F_BV(insn->detail->riscv.operands[2].reg); + +#define DECODE_F_FD_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); + +#define DECODE_F_RD_FS_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); \ + RzILOpFloat *frs2 = RISCV_GET_FREG_F(insn->detail->riscv.operands[2].reg); + +#define DECODE_F_RD_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); + +#define DECODE_F_RD_FS_BV(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *bvrs1 = RISCV_GET_FREG_F_BV(insn->detail->riscv.operands[1].reg); + +#define DECODE_F_FD_RS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); + +#define DECODE_F_FD_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +#define DECODE_F_FS_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + RzILOpBitVector *bvrs1 = RISCV_GET_FREG_F_BV(insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +#define DECODE_F_FD_FS_FS_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + REQUIRE_OP(3, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); \ + RzILOpFloat *frs2 = RISCV_GET_FREG_F(insn->detail->riscv.operands[2].reg); \ + RzILOpFloat *frs3 = RISCV_GET_FREG_F(insn->detail->riscv.operands[3].reg); + +// ----------------------------------------------------------------------- +// F Extension: Memory +// ----------------------------------------------------------------------- + +// flw fd, offset(rs1) — load 32-bit float from memory +DEFINE_F_LIFTER_BV_TO_FREG(flw, DECODE_F_FD_MEM, LOADW(32, ADD(rs, imm))) + +// fsw fs2, offset(rs1) — store 32-bit float to memory +DEFINE_LIFTER_WITH_EFFECT(fsw, DECODE_F_FS_MEM, STOREW(ADD(rs, imm), bvrs1)) + +// ----------------------------------------------------------------------- +// Arithmetic +// ----------------------------------------------------------------------- +DEFINE_F_LIFTER(fadd_s, DECODE_F_FD_FS_FS, FADD(F_RM, frs1, frs2)) +DEFINE_F_LIFTER(fsub_s, DECODE_F_FD_FS_FS, FSUB(F_RM, frs1, frs2)) +DEFINE_F_LIFTER(fmul_s, DECODE_F_FD_FS_FS, FMUL(F_RM, frs1, frs2)) +DEFINE_F_LIFTER(fdiv_s, DECODE_F_FD_FS_FS, FDIV(F_RM, frs1, frs2)) +DEFINE_F_LIFTER(fsqrt_s, DECODE_F_FD_FS, FSQRT(F_RM, frs1)) + +// ----------------------------------------------------------------------- +// Fused Multiply-Add +// +// fmadd.s: fd = (rs1 × rs2) + rs3 +// fmsub.s: fd = (rs1 × rs2) - rs3 +// fnmadd.s: fd = -(rs1 × rs2) - rs3 +// fnmsub.s: fd = -(rs1 × rs2) + rs3 +// ----------------------------------------------------------------------- +DEFINE_F_LIFTER(fmadd_s, DECODE_F_FD_FS_FS_FS, FMAD(F_RM, frs1, frs2, frs3)) +DEFINE_F_LIFTER(fmsub_s, DECODE_F_FD_FS_FS_FS, FMAD(F_RM, frs1, frs2, FNEG(frs3))) +DEFINE_F_LIFTER(fnmadd_s, DECODE_F_FD_FS_FS_FS, FNEG(FMAD(F_RM, frs1, frs2, frs3))) +DEFINE_F_LIFTER(fnmsub_s, DECODE_F_FD_FS_FS_FS, FMAD(F_RM, FNEG(frs1), frs2, frs3)) + +// ----------------------------------------------------------------------- +// Sign Injection (bit-level, no rounding) +// +// fsgnj.s: fd = |rs1| with sign of rs2 +// fsgnjn.s: fd = |rs1| with negated sign of rs2 +// fsgnjx.s: fd = |rs1| with sign = sign(rs1) XOR sign(rs2) +// +// Bit 31 of float32 is the sign bit. +// ----------------------------------------------------------------------- +DEFINE_F_LIFTER_BV_TO_FREG(fsgnj_s, DECODE_F_FD_BV_BV, + LOGOR(LOGAND(bvrs1, UN(32, 0x7FFFFFFF)), + LOGAND(bvrs2, UN(32, 0x80000000)))) + +DEFINE_F_LIFTER_BV_TO_FREG(fsgnjn_s, DECODE_F_FD_BV_BV, + LOGOR(LOGAND(bvrs1, UN(32, 0x7FFFFFFF)), + LOGAND(LOGNOT(bvrs2), UN(32, 0x80000000)))) + +// DUP bvrs1 to avoid shared AST nodes. +DEFINE_F_LIFTER_BV_TO_FREG(fsgnjx_s, DECODE_F_FD_BV_BV, + LOGOR(LOGAND(DUP(bvrs1), UN(32, 0x7FFFFFFF)), + LOGAND(LOGXOR(bvrs1, bvrs2), UN(32, 0x80000000)))) + +// ----------------------------------------------------------------------- +// Min / Max +// +// IEEE 754-201x minimumNumber / maximumNumber (RISC-V F spec >= 2.2): +// - signaling NaN operand → raise NV, return canonical qNaN +// - exactly one quiet NaN → return the non-NaN operand +// - both quiet NaN → return canonical qNaN +// - otherwise → normal min / max +// +// Float32 layout: sign[31], exponent[30:23], mantissa[22:0], quiet[22]. +// A value is sNaN iff exponent==0xFF && mantissa!=0 && quiet_bit==0. +// cond(a, b): FLE for fmin_s, FGE for fmax_s. +// ----------------------------------------------------------------------- +#define DEFINE_LIFTER_MINMAX(name, cond) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + uint32_t frs1_reg = insn->detail->riscv.operands[1].reg; \ + uint32_t frs2_reg = insn->detail->riscv.operands[2].reg; \ + return SEQN(10, \ + /* raw 32-bit bitvector of frs1, needed for bit-level sNaN inspection */ \ + SETL("_bva", RISCV_GET_FREG_F_BV(frs1_reg)), \ + /* raw 32-bit bitvector of frs2, needed for bit-level sNaN inspection */ \ + SETL("_bvb", RISCV_GET_FREG_F_BV(frs2_reg)), \ + /* ordinary float32 interpetation of operand 1 for IL float comparisons */ \ + SETL("_a", FLOATV32(VARL("_bva"))), \ + /* ordinary float32 interpetation of operand 2 for IL float comparisons */ \ + SETL("_b", FLOATV32(VARL("_bvb"))), \ + /* true if operand 1 is any NaN (exponent==0xFF and mantissa!=0) */ \ + SETL("_na", AND(EQ(EXTRACT32(VARL("_bva"), UN(32, 23), UN(32, 8)), UN(8, 0xFF)), \ + NON_ZERO(EXTRACT32(VARL("_bva"), UN(32, 0), UN(32, 23))))), \ + /* true if operand 2 is any NaN */ \ + SETL("_nb", AND(EQ(EXTRACT32(VARL("_bvb"), UN(32, 23), UN(32, 8)), UN(8, 0xFF)), \ + NON_ZERO(EXTRACT32(VARL("_bvb"), UN(32, 0), UN(32, 23))))), \ + /* true if operand 1 is a signaling NaN (NaN with quiet bit[22]==0) */ \ + SETL("_sa", AND(VARL("_na"), INV(NON_ZERO(EXTRACT32(VARL("_bva"), UN(32, 22), UN(32, 1)))))), \ + /* true if operand 2 is a signaling NaN */ \ + SETL("_sb", AND(VARL("_nb"), INV(NON_ZERO(EXTRACT32(VARL("_bvb"), UN(32, 22), UN(32, 1)))))), \ + /* raise NV (invalid operation, bit 4) in fcsr when either operand is sNaN */ \ + SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_sa"), VARL("_sb")), UN(64, 0x10), UN(64, 0)))), \ + RISCV_SET_FREG_F(frd, \ + ITE(OR(VARL("_sa"), VARL("_sb")), IL_FQNAN(RZ_FLOAT_IEEE754_BIN_32), \ + ITE(VARL("_na"), VARL("_b"), \ + ITE(VARL("_nb"), VARL("_a"), \ + ITE(cond(VARL("_a"), VARL("_b")), VARL("_a"), VARL("_b"))))))); \ + } + +DEFINE_LIFTER_MINMAX(fmin_s, FLE) +DEFINE_LIFTER_MINMAX(fmax_s, FGE) + +// ----------------------------------------------------------------------- +// Comparison (result in integer register) +// ----------------------------------------------------------------------- +DEFINE_LIFTER(feq_s, DECODE_F_RD_FS_FS, BOOL_TO_BV(FEQ(frs1, frs2), analysis->bits)) +DEFINE_LIFTER(flt_s, DECODE_F_RD_FS_FS, BOOL_TO_BV(FLT(frs1, frs2), analysis->bits)) +DEFINE_LIFTER(fle_s, DECODE_F_RD_FS_FS, BOOL_TO_BV(FLE(frs1, frs2), analysis->bits)) + +// ----------------------------------------------------------------------- +// F Extension: fclass.s +// +// Classifies the float32 value in fs1 into one of 10 categories, placing +// a one-hot 10-bit mask into rd (zero-extended to XLEN). +// +// bit 0 -infinity +// bit 1 negative normal +// bit 2 negative subnormal +// bit 3 -0 +// bit 4 +0 +// bit 5 positive subnormal +// bit 6 positive normal +// bit 7 +infinity +// bit 8 signaling NaN +// bit 9 quiet NaN +// +// Float32 layout: sign[31], exponent[30:23], mantissa[22:0], quiet[22]. +// ----------------------------------------------------------------------- +#define FBIT_S(n, cond) SHIFTL0(BOOL_TO_BV(cond, xlen), UN(xlen, (n))) + +static RzILOpEffect *rz_riscv_lift_fclass_s(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_F_RD_FS_BV(analysis, insn); + int xlen = analysis->bits; + return SEQN(14, + SETL("_b", bvrs1), + SETL("_ex", EXTRACT32(VARL("_b"), UN(32, 23), UN(32, 8))), + SETL("_mn", EXTRACT32(VARL("_b"), UN(32, 0), UN(32, 23))), + SETL("_sg", NON_ZERO(EXTRACT32(VARL("_b"), UN(32, 31), UN(32, 1)))), + SETL("_qt", NON_ZERO(EXTRACT32(VARL("_b"), UN(32, 22), UN(32, 1)))), + SETL("_xff", EQ(VARL("_ex"), UN(8, 0xFF))), + SETL("_xz", IS_ZERO(VARL("_ex"))), + SETL("_mz", IS_ZERO(VARL("_mn"))), + SETL("_na", AND(VARL("_xff"), INV(VARL("_mz")))), + SETL("_in", AND(VARL("_xff"), VARL("_mz"))), + SETL("_su", AND(VARL("_xz"), INV(VARL("_mz")))), + SETL("_ze", AND(VARL("_xz"), VARL("_mz"))), + SETL("_no", AND(INV(VARL("_xz")), INV(VARL("_xff")))), + RISCV_SET_REG(rd, + LOGOR(FBIT_S(0, AND(VARL("_sg"), VARL("_in"))), + LOGOR(FBIT_S(1, AND(VARL("_sg"), VARL("_no"))), + LOGOR(FBIT_S(2, AND(VARL("_sg"), VARL("_su"))), + LOGOR(FBIT_S(3, AND(VARL("_sg"), VARL("_ze"))), + LOGOR(FBIT_S(4, AND(INV(VARL("_sg")), VARL("_ze"))), + LOGOR(FBIT_S(5, AND(INV(VARL("_sg")), VARL("_su"))), + LOGOR(FBIT_S(6, AND(INV(VARL("_sg")), VARL("_no"))), + LOGOR(FBIT_S(7, AND(INV(VARL("_sg")), VARL("_in"))), + LOGOR(FBIT_S(8, AND(VARL("_na"), INV(VARL("_qt")))), + FBIT_S(9, AND(VARL("_na"), VARL("_qt")))))))))))))); +} +#undef FBIT_S + +// ----------------------------------------------------------------------- +// F Extension: Conversions float32 → integer +// +// RISC-V: in RV64 the 32-bit integer results of fcvt.w.s / fcvt.wu.s are +// sign-extended to 64 bits regardless of signedness (per spec §11.4). +// ----------------------------------------------------------------------- + +// fcvt.w.s rd, fs1 — float32 → signed int32, sign-extended to XLEN +DEFINE_LIFTER(fcvt_w_s, DECODE_F_RD_FS, + SIGNED(analysis->bits, F2SINT(32, F_RM, frs1))) + +// fcvt.wu.s rd, fs1 — float32 → unsigned int32, sign-extended to XLEN +DEFINE_LIFTER(fcvt_wu_s, DECODE_F_RD_FS, + SIGNED(analysis->bits, F2INT(32, F_RM, frs1))) + +// fcvt.l.s rd, fs1 — float32 → signed int64 (RV64F only) +static RzILOpEffect *rz_riscv_lift_fcvt_l_s(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_F_RD_FS(analysis, insn); + return RISCV_SET_REG(rd, F2SINT(64, F_RM, frs1)); +} + +// fcvt.lu.s rd, fs1 — float32 → unsigned int64 (RV64F only) +static RzILOpEffect *rz_riscv_lift_fcvt_lu_s(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_F_RD_FS(analysis, insn); + return RISCV_SET_REG(rd, F2INT(64, F_RM, frs1)); +} + +// ----------------------------------------------------------------------- +// F Extension: Conversions integer → float32 +// ----------------------------------------------------------------------- + +// fcvt.s.w fd, rs1 — signed int32 to float32 +// CAST(32, IL_FALSE, rs1) truncates XLEN-bit rs1 to 32 bits for the conversion. +DEFINE_F_LIFTER(fcvt_s_w, DECODE_F_FD_RS, + SINT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, CAST(32, IL_FALSE, rs1))) + +// fcvt.s.wu fd, rs1 — unsigned int32 to float32 +DEFINE_F_LIFTER(fcvt_s_wu, DECODE_F_FD_RS, + INT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, CAST(32, IL_FALSE, rs1))) + +// fcvt.s.l fd, rs1 — signed int64 to float32 (RV64F only) +static RzILOpEffect *rz_riscv_lift_fcvt_s_l(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_F_FD_RS(analysis, insn); + return RISCV_SET_FREG_F(frd, SINT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, rs1)); +} + +// fcvt.s.lu fd, rs1 — unsigned int64 to float32 (RV64F only) +static RzILOpEffect *rz_riscv_lift_fcvt_s_lu(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + REQUIRE_64_BIT(analysis); + DECODE_F_FD_RS(analysis, insn); + return RISCV_SET_FREG_F(frd, INT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, rs1)); +} + +// ----------------------------------------------------------------------- +// F Extension: Bit-level Move (no float conversion, no rounding) +// ----------------------------------------------------------------------- + +// fmv.x.w rd, fs1 — copy float32 bits to integer register, sign-extended to XLEN +DEFINE_LIFTER(fmv_x_w, DECODE_F_RD_FS_BV, + SIGNED(analysis->bits, bvrs1)) + +// fmv.w.x fd, rs1 — copy integer register bits (lower 32) to float register +DEFINE_F_LIFTER_BV_TO_FREG(fmv_w_x, DECODE_F_FD_RS, + CAST(32, IL_FALSE, rs1)) + +#include + +#endif // RISCV_IL_F_H diff --git a/librz/arch/isa/riscv/riscv_il_fd_compressed.h b/librz/arch/isa/riscv/riscv_il_fd_compressed.h new file mode 100644 index 00000000000..968e9cfe603 --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_fd_compressed.h @@ -0,0 +1,14 @@ +#ifndef RISCV_IL_FD_COMPRESSED_H +#define RISCV_IL_FD_COMPRESSED_H + +#include "riscv/riscv_il_base.h" +#include "riscv_il_f.h" +#include "riscv_il_d.h" + +DEFINE_ALIAS_LIFTER(c_fld, fld) +DEFINE_ALIAS_LIFTER(c_fldsp, fld) +DEFINE_ALIAS_LIFTER(c_fsd, fsd) +DEFINE_ALIAS_LIFTER(c_fsdsp, fsd) +#include + +#endif // RISCV_IL_FD_COMPRESSED_H \ No newline at end of file diff --git a/librz/arch/isa/riscv/riscv_il_float_reg_names.h b/librz/arch/isa/riscv/riscv_il_float_reg_names.h new file mode 100644 index 00000000000..2a3d5b485ee --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_float_reg_names.h @@ -0,0 +1,55 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_FLOAT_REG_NAMES_H +#define RISCV_IL_FLOAT_REG_NAMES_H + +#include +#include + +static const char *riscv_freg_names[] = { + /* f0 */ "ft0", + /* f1 */ "ft1", + /* f2 */ "ft2", + /* f3 */ "ft3", + /* f4 */ "ft4", + /* f5 */ "ft5", + /* f6 */ "ft6", + /* f7 */ "ft7", + /* f8 */ "fs0", + /* f9 */ "fs1", + /* f10 */ "fa0", + /* f11 */ "fa1", + /* f12 */ "fa2", + /* f13 */ "fa3", + /* f14 */ "fa4", + /* f15 */ "fa5", + /* f16 */ "fa6", + /* f17 */ "fa7", + /* f18 */ "fs2", + /* f19 */ "fs3", + /* f20 */ "fs4", + /* f21 */ "fs5", + /* f22 */ "fs6", + /* f23 */ "fs7", + /* f24 */ "fs8", + /* f25 */ "fs9", + /* f26 */ "fs10", + /* f27 */ "fs11", + /* f28 */ "ft8", + /* f29 */ "ft9", + /* f30 */ "ft10", + /* f31 */ "ft11", +}; + +// Resolve any RISC-V FP register enum value (F or D variant) to its ABI name. +// RISCV_REG_F0_D = 74, RISCV_REG_F0_F = 106. Both ranges are 32 wide and +// map physical register index n to riscv_freg_names[n]. +static inline const char *riscv_freg_name(uint32_t reg) { + if (reg >= RISCV_REG_F0_D && reg <= RISCV_REG_F31_D) { + return riscv_freg_names[reg - RISCV_REG_F0_D]; + } + return riscv_freg_names[reg - RISCV_REG_F0_F]; +} + +#endif // RISCV_IL_FLOAT_REG_NAMES_H diff --git a/librz/arch/isa/riscv/riscv_il_priv.h b/librz/arch/isa/riscv/riscv_il_priv.h new file mode 100644 index 00000000000..b8eac96d1d7 --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_priv.h @@ -0,0 +1,180 @@ +// SPDX-FileCopyrightText: 2026 Mostafa Mahmoud +// SPDX-License-Identifier: BSD-3-Clause + +#ifndef RISCV_IL_PRIV_H +#define RISCV_IL_PRIV_H + +#include "riscv_il_base.h" + +#include + +// ----------------------------------------------------------------------- +// CSR (Control and Status Register) instructions — Zicsr extension +// +// We currently support only the floating-point CSRs because they are the +// only ones that affect program-visible IL state in our model: +// fflags (0x001) — FP accrued exceptions, bits [4:0] of "fcsr" +// frm (0x002) — FP rounding mode, bits [7:5] of "fcsr" +// fcsr (0x003) — combined FP control/status register +// +// NOTE: The spec distinguishes "shall not read" (rd=x0) and "shall not +// write" (rs1=x0 / uimm=0) semantics to avoid triggering side effects on +// CSRs that have architectural read/write side effects. Since every CSR +// we model today is pure data (fflags, frm, fcsr), reading or writing them +// redundantly is harmless. We therefore always perform both the read and +// the write unconditionally. Revisit this when side-effectual CSRs +// (e.g., mstatus, sstatus, cycle) are added. +// ----------------------------------------------------------------------- + +// Read a CSR value as an XLEN-bit bitvector from the "fcsr" IL global. +static RzILOpBitVector *riscv_csr_read(uint16_t csr, int xlen) { + switch (csr) { + case RISCV_SYSREG_FFLAGS: + // bits [4:0] of "fcsr", zero-extended to XLEN + return CAST(xlen, IL_FALSE, LOGAND(VARG("fcsr"), UN(64, 0x1F))); + case RISCV_SYSREG_FRM: + // bits [7:5] of "fcsr" shifted right by 5, zero-extended to XLEN + return CAST(xlen, IL_FALSE, SHIFTR0(LOGAND(VARG("fcsr"), UN(64, 0xE0)), UN(64, 5))); + case RISCV_SYSREG_FCSR: + // full "fcsr" (only bits [7:0] are meaningful), zero-extended to XLEN + return CAST(xlen, IL_FALSE, VARG("fcsr")); + default: + return UN(xlen, 0); + } +} + +// Write an XLEN-bit value into the appropriate field of the "fcsr" IL global. +// val is consumed (ownership transferred to the returned effect or freed on unknown CSR). +static RzILOpEffect *riscv_csr_write(uint16_t csr, RzILOpBitVector *val, int xlen) { + switch (csr) { + case RISCV_SYSREG_FFLAGS: + // update bits [4:0] of "fcsr", preserve the rest + return SETG("fcsr", LOGOR( + LOGAND(VARG("fcsr"), UN(64, ~0x1FULL)), + LOGAND(CAST(64, IL_FALSE, val), UN(64, 0x1F)))); + case RISCV_SYSREG_FRM: + // update bits [7:5] of "fcsr", preserve the rest + return SETG("fcsr", LOGOR( + LOGAND(VARG("fcsr"), UN(64, ~0xE0ULL)), + LOGAND(SHIFTL0(CAST(64, IL_FALSE, val), UN(64, 5)), UN(64, 0xE0)))); + case RISCV_SYSREG_FCSR: + // update "fcsr" directly, masking to the 8 meaningful bits + return SETG("fcsr", LOGAND(CAST(64, IL_FALSE, val), UN(64, 0xFF))); + default: + rz_il_op_pure_free(val); + return NOP(); + } +} + +// ----------------------------------------------------------------------- +// Decoders +// ----------------------------------------------------------------------- + +// rd=IntReg[0], csr=CSR[1], rs=IntReg[2] (csrrw, csrrs, csrrc) +#define DECODE_CSR_RD_CSR_RS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_CSR); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + uint16_t csr = insn->detail->riscv.operands[1].csr; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[2].reg); + +// rd=IntReg[0], csr=CSR[1], uimm=5-bit unsigned IMM[2] (csrrwi, csrrsi, csrrci) +#define DECODE_CSR_RD_CSR_IMM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_CSR); \ + REQUIRE_OP(2, RISCV_OP_IMM); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + uint16_t csr = insn->detail->riscv.operands[1].csr; \ + RzILOpBitVector *uimm = UN(analysis->bits, (ut64)(insn->detail->riscv.operands[2].imm) & 0x1F); + +// ----------------------------------------------------------------------- +// csrrw rd, csr, rs1 +// rd ← old CSR value (zero-extended to XLEN) +// CSR ← rs1 +// ----------------------------------------------------------------------- +static RzILOpEffect *rz_riscv_lift_csrrw(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_CSR_RD_CSR_RS(analysis, insn); + return SEQ3( + SETL("_old", riscv_csr_read(csr, analysis->bits)), + riscv_csr_write(csr, rs, analysis->bits), + RISCV_SET_REG(rd, VARL("_old"))); +} + +// ----------------------------------------------------------------------- +// csrrs rd, csr, rs1 +// rd ← old CSR value (zero-extended to XLEN) +// CSR ← old CSR | rs1 (set bits where rs1 has 1s) +// ----------------------------------------------------------------------- +static RzILOpEffect *rz_riscv_lift_csrrs(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_CSR_RD_CSR_RS(analysis, insn); + return SEQ3( + SETL("_old", riscv_csr_read(csr, analysis->bits)), + riscv_csr_write(csr, LOGOR(VARL("_old"), rs), analysis->bits), + RISCV_SET_REG(rd, VARL("_old"))); +} + +// ----------------------------------------------------------------------- +// csrrc rd, csr, rs1 +// rd ← old CSR value (zero-extended to XLEN) +// CSR ← old CSR & ~rs1 (clear bits where rs1 has 1s) +// ----------------------------------------------------------------------- +static RzILOpEffect *rz_riscv_lift_csrrc(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_CSR_RD_CSR_RS(analysis, insn); + return SEQ3( + SETL("_old", riscv_csr_read(csr, analysis->bits)), + riscv_csr_write(csr, LOGAND(VARL("_old"), LOGNOT(rs)), analysis->bits), + RISCV_SET_REG(rd, VARL("_old"))); +} + +// ----------------------------------------------------------------------- +// csrrwi rd, csr, uimm +// rd ← old CSR value (zero-extended to XLEN) +// CSR ← zero-extend(uimm[4:0]) +// ----------------------------------------------------------------------- +static RzILOpEffect *rz_riscv_lift_csrrwi(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_CSR_RD_CSR_IMM(analysis, insn); + return SEQ3( + SETL("_old", riscv_csr_read(csr, analysis->bits)), + riscv_csr_write(csr, uimm, analysis->bits), + RISCV_SET_REG(rd, VARL("_old"))); +} + +// ----------------------------------------------------------------------- +// csrrsi rd, csr, uimm +// rd ← old CSR value (zero-extended to XLEN) +// CSR ← old CSR | zero-extend(uimm[4:0]) +// ----------------------------------------------------------------------- +static RzILOpEffect *rz_riscv_lift_csrrsi(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_CSR_RD_CSR_IMM(analysis, insn); + return SEQ3( + SETL("_old", riscv_csr_read(csr, analysis->bits)), + riscv_csr_write(csr, LOGOR(VARL("_old"), uimm), analysis->bits), + RISCV_SET_REG(rd, VARL("_old"))); +} + +// ----------------------------------------------------------------------- +// csrrci rd, csr, uimm +// rd ← old CSR value (zero-extended to XLEN) +// CSR ← old CSR & ~zero-extend(uimm[4:0]) +// ----------------------------------------------------------------------- +static RzILOpEffect *rz_riscv_lift_csrrci(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_CSR_RD_CSR_IMM(analysis, insn); + return SEQ3( + SETL("_old", riscv_csr_read(csr, analysis->bits)), + riscv_csr_write(csr, LOGAND(VARL("_old"), LOGNOT(uimm)), analysis->bits), + RISCV_SET_REG(rd, VARL("_old"))); +} + +#undef DECODE_CSR_RD_CSR_RS +#undef DECODE_CSR_RD_CSR_IMM + +#include + +#endif // RISCV_IL_PRIV_H diff --git a/subprojects/capstone-next.wrap b/subprojects/capstone-next.wrap index 9bf2c73fbeb..f36ec97f5c5 100644 --- a/subprojects/capstone-next.wrap +++ b/subprojects/capstone-next.wrap @@ -1,6 +1,6 @@ [wrap-git] -url = https://github.com/capstone-engine/capstone.git -revision = 3df6ff015fb6afd81307e325fdd9c82dbf184b28 +url = https://github.com/moste00/capstone.git +revision = 86c8301074c35e86079408783956ada84c6f1d69 directory = capstone-next patch_directory = capstone-next depth = 1 From b29d63103edccc95a9617fe9f4de76080b335e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Sun, 31 May 2026 20:32:38 +0300 Subject: [PATCH 8/9] refactor to common file for both F and D extensions --- librz/arch/isa/riscv/riscv_il_d.h | 449 ++++--------- librz/arch/isa/riscv/riscv_il_f.h | 427 +++--------- librz/arch/isa/riscv/riscv_il_fd_common.h | 634 ++++++++++++++++++ .../arch/isa/riscv/riscv_il_float_reg_names.h | 5 +- 4 files changed, 883 insertions(+), 632 deletions(-) create mode 100644 librz/arch/isa/riscv/riscv_il_fd_common.h diff --git a/librz/arch/isa/riscv/riscv_il_d.h b/librz/arch/isa/riscv/riscv_il_d.h index 263281250c1..c93624f1aa6 100644 --- a/librz/arch/isa/riscv/riscv_il_d.h +++ b/librz/arch/isa/riscv/riscv_il_d.h @@ -5,156 +5,106 @@ #define RISCV_IL_D_H #include "riscv_il_base.h" - #include "riscv_il_f.h" -#include - // ----------------------------------------------------------------------- // D extension: register access (RISCV_REG_F0_D = 74, _D suffix) // // When the D extension is present the FP register file is 64 bits wide. -// The IL global variables for ft0-ft11 / fs0-fs11 / fa0-fa7 must be -// declared with width 64 in the IL config (rz_riscv_il_config). -// // Single-precision values written by F instructions are NaN-boxed: // the upper 32 bits are all 1s so that D instructions treating the // register as float64 see a canonical quiet NaN for any narrower value. // ----------------------------------------------------------------------- #define RISCV_FREG_D_NAME(reg) riscv_freg_name(reg) -// Read a D register as a float64 IL value. #define RISCV_GET_FREG_D(reg) FLOATV64(VARG(RISCV_FREG_D_NAME(reg))) -// Read a D register as a raw 64-bit bitvector (sign-injection, fmv, store). #define RISCV_GET_FREG_D_BV(reg) VARG(RISCV_FREG_D_NAME(reg)) -// Read a D register's lower 32 bits as a float32 IL value (fcvt.d.s source). #define RISCV_GET_FREG_D_AS_F32(reg) FLOATV32(CAST(32, IL_FALSE, VARG(RISCV_FREG_D_NAME(reg)))) -// Write a float64 IL value into a D register. #define RISCV_SET_FREG_D(reg, fl) SETG(RISCV_FREG_D_NAME(reg), F2BV(fl)) -// Write a raw 64-bit bitvector into a D register. #define RISCV_SET_FREG_D_BV(reg, bv) SETG(RISCV_FREG_D_NAME(reg), bv) -// Write a float32 IL value into a D register, NaN-boxed to 64 bits. -// Upper 32 bits are set to 0xFFFFFFFF per the RISC-V NaN-boxing rule. #define RISCV_SET_FREG_D_F32(reg, fl32) SETG(RISCV_FREG_D_NAME(reg), APPEND(UN(32, 0xFFFFFFFF), F2BV(fl32))) -// riscv_rm_to_rz is defined in riscv_il_f.h (included above). #define D_RM riscv_rm_to_rz(insn->detail->riscv.rounding_mode) // ----------------------------------------------------------------------- -// Lifter templates -// ----------------------------------------------------------------------- +// D extension: specialization of the riscv_il_fd_common.h interface +// Float64 IEEE 754: sign[63], exponent[62:52] (11 bits), mantissa[51:0] (52 bits) +// ----------------------------------------------------------------------- +#define RISCV_FD_REG_GETTER(reg) RISCV_GET_FREG_D(reg) +#define RISCV_FD_REG_SETTER(reg, fl) RISCV_SET_FREG_D(reg, fl) +#define RISCV_FD_REG_GETTER_BV(reg) RISCV_GET_FREG_D_BV(reg) +#define RISCV_FD_REG_SETTER_BV(reg, bv) RISCV_SET_FREG_D_BV(reg, bv) +#define RISCV_FD_GET_MANTISSA(bv) EXTRACT64(bv, UN(64, 0), UN(32, 52)) +#define RISCV_FD_GET_EXPONENT(bv) EXTRACT64(bv, UN(64, 52), UN(32, 11)) +#define RISCV_FD_GET_SIGN(bv) EXTRACT64(bv, UN(64, 63), UN(32, 1)) +#define RISCV_FD_IS_NAN(bv) AND(EQ(RISCV_FD_GET_EXPONENT(bv), UN(64, 0x7FF)), NON_ZERO(RISCV_FD_GET_MANTISSA(bv))) +#define RISCV_FD_IS_S_NAN(bv) AND(RISCV_FD_IS_NAN(bv), EQ(EXTRACT64(bv, UN(64, 51), UN(32, 1)), UN(64, 0))) +#define RISCV_FD_IS_MAX_EXP(bv) EQ(bv, UN(64, 0x7FF)) +#define RISCV_FD_IS_EXP_OVERFLOW_INT(bv) UGE(bv, UN(64, 1054)) +#define RISCV_FD_IS_EXP_OVERFLOW_UINT(bv) UGE(bv, UN(64, 1055)) +#define RISCV_FD_IS_EXP_OVERFLOW_LONG(bv) UGE(bv, UN(64, 1086)) +#define RISCV_FD_IS_EXP_OVERFLOW_ULONG(bv) UGE(bv, UN(64, 1087)) -// float64 result → D register, with fflags/fcsr update -#define DEFINE_D_LIFTER(name, decoder, fl_result) \ - static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ - decoder(analysis, insn); \ - return SEQ3( \ - SETL("_r", fl_result), \ - RISCV_SET_FREG_D(frd, VARL("_r")), \ - RISCV_ACCUMULATE_FFLAGS()); \ - } - -// raw 64-bit bitvector → D register (sign injection, fmv.d.x) -#define DEFINE_D_LIFTER_BV_TO_FREG(name, decoder, bv_result) \ - static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ - decoder(analysis, insn); \ - return RISCV_SET_FREG_D_BV(frd, bv_result); \ - } - -// float32 NaN-boxed result → D register (fcvt.s.d) -#define DEFINE_D_LIFTER_F32_TO_FREG(name, decoder, fl32_result) \ - static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ - decoder(analysis, insn); \ - return RISCV_SET_FREG_D_F32(frd, fl32_result); \ - } +#include // ----------------------------------------------------------------------- -// Decoders +// Memory // ----------------------------------------------------------------------- +DEF_LOAD(fld, 64) +DEF_STORE(fsd) -// frd=DReg[0], frs1=float64(DReg[1]), frs2=float64(DReg[2]) -#define DECODE_D_FD_FS_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); \ - RzILOpFloat *frs2 = RISCV_GET_FREG_D(insn->detail->riscv.operands[2].reg); - -// frd=DReg[0], raw 64-bit bitvectors (sign injection) -#define DECODE_D_FD_BV_BV(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *bvrs1 = RISCV_GET_FREG_D_BV(insn->detail->riscv.operands[1].reg); \ - RzILOpBitVector *bvrs2 = RISCV_GET_FREG_D_BV(insn->detail->riscv.operands[2].reg); - -// frd=DReg[0], frs1=float64(DReg[1]) -#define DECODE_D_FD_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); +// ----------------------------------------------------------------------- +// Arithmetic +// ----------------------------------------------------------------------- +DEF_ADD(fadd_d) +DEF_SUB(fsub_d) +DEF_MUL(fmul_d) +DEF_DIV(fdiv_d) +DEF_SQRT(fsqrt_d) -// rd=IntReg[0], frs1=float64(DReg[1]), frs2=float64(DReg[2]) (feq/flt/fle) -#define DECODE_D_RD_FS_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); \ - RzILOpFloat *frs2 = RISCV_GET_FREG_D(insn->detail->riscv.operands[2].reg); +// ----------------------------------------------------------------------- +// Fused Multiply-Add +// ----------------------------------------------------------------------- +DEF_FMADD(fmadd_d) +DEF_FMSUB(fmsub_d) +DEF_FNMADD(fnmadd_d) +DEF_FNMSUB(fnmsub_d) -// rd=IntReg[0], frs1=float64(DReg[1]) (fcvt.w.d, fclass.d) -#define DECODE_D_RD_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); +// ----------------------------------------------------------------------- +// Sign Injection (bit-level, no rounding) +// ----------------------------------------------------------------------- +DEF_FSGNJ(fsgnj_d, 64) +DEF_FSGNJN(fsgnjn_d, 64) +DEF_FSGNJX(fsgnjx_d, 64) -// rd=IntReg[0], bvrs1=raw64(DReg[1]) (fmv.x.d, fclass.d bit path) -#define DECODE_D_RD_FS_BV(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *bvrs1 = RISCV_GET_FREG_D_BV(insn->detail->riscv.operands[1].reg); +// ----------------------------------------------------------------------- +// Min/Max +// ----------------------------------------------------------------------- +DEF_FMIN(fmin_d, 64) +DEF_FMAX(fmax_d, 64) -// frd=DReg[0], rs1=IntReg[1] (fcvt.d.w, fmv.d.x) -#define DECODE_D_FD_RS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); +// ----------------------------------------------------------------------- +// Comparison (result in integer register) +// ----------------------------------------------------------------------- +DEF_FEQ(feq_d, 64) +DEF_FLT(flt_d, 64) +DEF_FLE(fle_d, 64) -// frd=DReg[0], MEM base+offset (fld) -#define DECODE_D_FD_MEM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_MEM); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); +// ----------------------------------------------------------------------- +// Classification +// ----------------------------------------------------------------------- +DEF_FCLASS(fclass_d) -// DReg[0] source, MEM base+offset (fsd) -#define DECODE_D_FS_MEM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_MEM); \ - RzILOpBitVector *bvrs1 = RISCV_GET_FREG_D_BV(insn->detail->riscv.operands[0].reg); \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); +// ----------------------------------------------------------------------- +// Conversions float64 → integer +// ----------------------------------------------------------------------- +DEF_FCVT_W(fcvt_w_d, 64) +DEF_FCVT_WU(fcvt_wu_d, 64) +DEF_FCVT_L(fcvt_l_d, 64) +DEF_FCVT_LU(fcvt_lu_d, 64) -// frd=DReg[0], frs1=float64, frs2=float64, frs3=float64 -#define DECODE_D_FD_FS_FS_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - REQUIRE_OP(3, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); \ - RzILOpFloat *frs2 = RISCV_GET_FREG_D(insn->detail->riscv.operands[2].reg); \ - RzILOpFloat *frs3 = RISCV_GET_FREG_D(insn->detail->riscv.operands[3].reg); +// ----------------------------------------------------------------------- +// D-exclusive decoders (cross-precision and bit-move instructions) +// ----------------------------------------------------------------------- // frd=DReg[0], frs1=float32 from lower 32 bits of FReg[1] (fcvt.d.s) // capstone encodes the source with the _F suffix; riscv_freg_name() handles both. @@ -164,185 +114,49 @@ uint32_t frd = insn->detail->riscv.operands[0].reg; \ RzILOpFloat *frs1 = FLOATV32(CAST(32, IL_FALSE, VARG(riscv_freg_name(insn->detail->riscv.operands[1].reg)))); -// frd=DReg[0], frs1=float64 from DReg[1] (fcvt.s.d — dest also a D register) +// frd=DReg[0], frs1=float64 from DReg[1] (fcvt.s.d) #define DECODE_D_FD_FS_F64(analysis, insn) \ REQUIRE_OP(0, RISCV_OP_REG); \ REQUIRE_OP(1, RISCV_OP_REG); \ uint32_t frd = insn->detail->riscv.operands[0].reg; \ RzILOpFloat *frs1 = RISCV_GET_FREG_D(insn->detail->riscv.operands[1].reg); -// ----------------------------------------------------------------------- -// D Extension: Memory -// ----------------------------------------------------------------------- - -// fld fd, offset(rs1) — load 64-bit double from memory -DEFINE_D_LIFTER_BV_TO_FREG(fld, DECODE_D_FD_MEM, LOADW(64, ADD(rs, imm))) - -// fsd fs2, offset(rs1) — store 64-bit double to memory -DEFINE_LIFTER_WITH_EFFECT(fsd, DECODE_D_FS_MEM, STOREW(ADD(rs, imm), bvrs1)) - -// ----------------------------------------------------------------------- -// Arithmetic -// ----------------------------------------------------------------------- -DEFINE_D_LIFTER(fadd_d, DECODE_D_FD_FS_FS, FADD(D_RM, frs1, frs2)) -DEFINE_D_LIFTER(fsub_d, DECODE_D_FD_FS_FS, FSUB(D_RM, frs1, frs2)) -DEFINE_D_LIFTER(fmul_d, DECODE_D_FD_FS_FS, FMUL(D_RM, frs1, frs2)) -DEFINE_D_LIFTER(fdiv_d, DECODE_D_FD_FS_FS, FDIV(D_RM, frs1, frs2)) -DEFINE_D_LIFTER(fsqrt_d, DECODE_D_FD_FS, FSQRT(D_RM, frs1)) - -// ----------------------------------------------------------------------- -// Fused Multiply-Add -// ----------------------------------------------------------------------- -DEFINE_D_LIFTER(fmadd_d, DECODE_D_FD_FS_FS_FS, FMAD(D_RM, frs1, frs2, frs3)) -DEFINE_D_LIFTER(fmsub_d, DECODE_D_FD_FS_FS_FS, FMAD(D_RM, frs1, frs2, FNEG(frs3))) -DEFINE_D_LIFTER(fnmadd_d, DECODE_D_FD_FS_FS_FS, FNEG(FMAD(D_RM, frs1, frs2, frs3))) -DEFINE_D_LIFTER(fnmsub_d, DECODE_D_FD_FS_FS_FS, FMAD(D_RM, FNEG(frs1), frs2, frs3)) - -// ----------------------------------------------------------------------- -// Sign Injection (bit-level) -// Bit 63 of float64 is the sign bit. -// ----------------------------------------------------------------------- -DEFINE_D_LIFTER_BV_TO_FREG(fsgnj_d, DECODE_D_FD_BV_BV, - LOGOR(LOGAND(bvrs1, UN(64, 0x7FFFFFFFFFFFFFFF)), - LOGAND(bvrs2, UN(64, 0x8000000000000000)))) - -DEFINE_D_LIFTER_BV_TO_FREG(fsgnjn_d, DECODE_D_FD_BV_BV, - LOGOR(LOGAND(bvrs1, UN(64, 0x7FFFFFFFFFFFFFFF)), - LOGAND(LOGNOT(bvrs2), UN(64, 0x8000000000000000)))) - -DEFINE_D_LIFTER_BV_TO_FREG(fsgnjx_d, DECODE_D_FD_BV_BV, - LOGOR(LOGAND(DUP(bvrs1), UN(64, 0x7FFFFFFFFFFFFFFF)), - LOGAND(LOGXOR(bvrs1, bvrs2), UN(64, 0x8000000000000000)))) - -// ----------------------------------------------------------------------- -// D Extension: Min / Max -// -// IEEE 754-201x minimumNumber / maximumNumber (RISC-V D spec >= 2.2): -// - signaling NaN operand → raise NV, return canonical qNaN -// - exactly one quiet NaN → return the non-NaN operand -// - both quiet NaN → return canonical qNaN -// - otherwise → normal min / max -// -// Float64 layout: sign[63], exponent[62:52] (11 bits), mantissa[51:0] (52 bits), -// quiet bit[51]. -// A value is sNaN iff exponent==0x7FF && mantissa!=0 && quiet_bit==0. -// cond(a, b): FLE for fmin_d, FGE for fmax_d. -// ----------------------------------------------------------------------- -#define DEFINE_LIFTER_MINMAX(name, cond) \ - static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - uint32_t frs1_reg = insn->detail->riscv.operands[1].reg; \ - uint32_t frs2_reg = insn->detail->riscv.operands[2].reg; \ - return SEQN(10, \ - /* _bva: raw 64-bit bitvector of frs1, needed for bit-level sNaN inspection */ \ - SETL("_bva", RISCV_GET_FREG_D_BV(frs1_reg)), \ - /* _bvb: raw 64-bit bitvector of frs2, needed for bit-level sNaN inspection */ \ - SETL("_bvb", RISCV_GET_FREG_D_BV(frs2_reg)), \ - /* _a: frs1 reinterpreted as float64 for IL float comparisons */ \ - SETL("_a", FLOATV64(VARL("_bva"))), \ - /* _b: frs2 reinterpreted as float64 for IL float comparisons */ \ - SETL("_b", FLOATV64(VARL("_bvb"))), \ - /* _na: true if frs1 is any NaN (exponent==0x7FF and mantissa!=0) */ \ - SETL("_na", AND(EQ(EXTRACT64(VARL("_bva"), UN(64, 52), UN(64, 11)), UN(11, 0x7FF)), \ - NON_ZERO(EXTRACT64(VARL("_bva"), UN(64, 0), UN(64, 52))))), \ - /* _nb: true if frs2 is any NaN */ \ - SETL("_nb", AND(EQ(EXTRACT64(VARL("_bvb"), UN(64, 52), UN(64, 11)), UN(11, 0x7FF)), \ - NON_ZERO(EXTRACT64(VARL("_bvb"), UN(64, 0), UN(64, 52))))), \ - /* _sa: true if frs1 is a signaling NaN (NaN with quiet bit[51]==0) */ \ - SETL("_sa", AND(VARL("_na"), INV(NON_ZERO(EXTRACT64(VARL("_bva"), UN(64, 51), UN(64, 1)))))), \ - /* _sb: true if frs2 is a signaling NaN */ \ - SETL("_sb", AND(VARL("_nb"), INV(NON_ZERO(EXTRACT64(VARL("_bvb"), UN(64, 51), UN(64, 1)))))), \ - /* raise NV (invalid operation, bit 4) in fcsr when either operand is sNaN */ \ - SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_sa"), VARL("_sb")), UN(64, 0x10), UN(64, 0)))), \ - RISCV_SET_FREG_D(frd, \ - ITE(OR(VARL("_sa"), VARL("_sb")), IL_FQNAN(RZ_FLOAT_IEEE754_BIN_64), \ - ITE(VARL("_na"), VARL("_b"), \ - ITE(VARL("_nb"), VARL("_a"), \ - ITE(cond(VARL("_a"), VARL("_b")), VARL("_a"), VARL("_b"))))))); \ - } - -DEFINE_LIFTER_MINMAX(fmin_d, FLE) -DEFINE_LIFTER_MINMAX(fmax_d, FGE) - -// ----------------------------------------------------------------------- -// D Extension: Comparison (result in integer register) -// ----------------------------------------------------------------------- -DEFINE_LIFTER(feq_d, DECODE_D_RD_FS_FS, BOOL_TO_BV(FEQ(frs1, frs2), analysis->bits)) -DEFINE_LIFTER(flt_d, DECODE_D_RD_FS_FS, BOOL_TO_BV(FLT(frs1, frs2), analysis->bits)) -DEFINE_LIFTER(fle_d, DECODE_D_RD_FS_FS, BOOL_TO_BV(FLE(frs1, frs2), analysis->bits)) +// frd=DReg[0], rs1=IntReg[1] (fcvt.d.w, fcvt.d.l, fmv.d.x) +#define DECODE_D_FD_RS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); -// ----------------------------------------------------------------------- -// D Extension: fclass.d -// -// Same 10-bit one-hot classification as fclass.s, applied to float64. -// -// Float64 layout: sign[63], exponent[62:52] (11 bits), mantissa[51:0] (52 bits), -// quiet bit[51]. -// Exponent 0x7FF indicates NaN or infinity. -// ----------------------------------------------------------------------- -static RzILOpEffect *rz_riscv_lift_fclass_d(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { - DECODE_D_RD_FS_BV(analysis, insn); - int xlen = analysis->bits; -#define FBIT_D(n, cond) SHIFTL0(BOOL_TO_BV(cond, xlen), UN(xlen, (n))) - return SEQN(14, - SETL("_b", bvrs1), - SETL("_ex", EXTRACT64(VARL("_b"), UN(64, 52), UN(64, 11))), - SETL("_mn", EXTRACT64(VARL("_b"), UN(64, 0), UN(64, 52))), - SETL("_sg", NON_ZERO(EXTRACT64(VARL("_b"), UN(64, 63), UN(64, 1)))), - SETL("_qt", NON_ZERO(EXTRACT64(VARL("_b"), UN(64, 51), UN(64, 1)))), - SETL("_xff", EQ(VARL("_ex"), UN(11, 0x7FF))), - SETL("_xz", IS_ZERO(VARL("_ex"))), - SETL("_mz", IS_ZERO(VARL("_mn"))), - SETL("_na", AND(VARL("_xff"), INV(VARL("_mz")))), - SETL("_in", AND(VARL("_xff"), VARL("_mz"))), - SETL("_su", AND(VARL("_xz"), INV(VARL("_mz")))), - SETL("_ze", AND(VARL("_xz"), VARL("_mz"))), - SETL("_no", AND(INV(VARL("_xz")), INV(VARL("_xff")))), - RISCV_SET_REG(rd, - LOGOR(FBIT_D(0, AND(VARL("_sg"), VARL("_in"))), - LOGOR(FBIT_D(1, AND(VARL("_sg"), VARL("_no"))), - LOGOR(FBIT_D(2, AND(VARL("_sg"), VARL("_su"))), - LOGOR(FBIT_D(3, AND(VARL("_sg"), VARL("_ze"))), - LOGOR(FBIT_D(4, AND(INV(VARL("_sg")), VARL("_ze"))), - LOGOR(FBIT_D(5, AND(INV(VARL("_sg")), VARL("_su"))), - LOGOR(FBIT_D(6, AND(INV(VARL("_sg")), VARL("_no"))), - LOGOR(FBIT_D(7, AND(INV(VARL("_sg")), VARL("_in"))), - LOGOR(FBIT_D(8, AND(VARL("_na"), INV(VARL("_qt")))), - FBIT_D(9, AND(VARL("_na"), VARL("_qt")))))))))))))); -#undef FBIT_D -} +// rd=IntReg[0], bvrs1=raw64(DReg[1]) (fmv.x.d) +#define DECODE_D_RD_FS_BV(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *bvrs1 = RISCV_GET_FREG_D_BV(insn->detail->riscv.operands[1].reg); // ----------------------------------------------------------------------- -// D Extension: Conversions float64 → integer +// D Extension: Precision conversions // ----------------------------------------------------------------------- -// fcvt.w.d rd, fs1 — float64 → signed int32, sign-extended to XLEN -DEFINE_LIFTER(fcvt_w_d, DECODE_D_RD_FS, - SIGNED(analysis->bits, F2SINT(32, D_RM, frs1))) - -// fcvt.wu.d rd, fs1 — float64 → unsigned int32, sign-extended to XLEN -DEFINE_LIFTER(fcvt_wu_d, DECODE_D_RD_FS, - SIGNED(analysis->bits, F2INT(32, D_RM, frs1))) - -// fcvt.l.d rd, fs1 — float64 → signed int64 (RV64D only) -static RzILOpEffect *rz_riscv_lift_fcvt_l_d(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, +// fcvt.d.s fd, fs1 — float32 (NaN-boxed in D reg) → float64 +static RzILOpEffect *rz_riscv_lift_fcvt_d_s(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { - REQUIRE_64_BIT(analysis); - DECODE_D_RD_FS(analysis, insn); - return RISCV_SET_REG(rd, F2SINT(64, D_RM, frs1)); + DECODE_D_FD_FS_F32(analysis, insn); + return SEQ3( + SETL("_r", FCONVERT(RZ_FLOAT_IEEE754_BIN_64, D_RM, frs1)), + RISCV_SET_FREG_D(frd, VARL("_r")), + RISCV_FD_UPDATE_FFLAGS()); } -// fcvt.lu.d rd, fs1 — float64 → unsigned int64 (RV64D only) -static RzILOpEffect *rz_riscv_lift_fcvt_lu_d(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, +// fcvt.s.d fd, fs1 — float64 → float32, NaN-boxed into D register +static RzILOpEffect *rz_riscv_lift_fcvt_s_d(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { - REQUIRE_64_BIT(analysis); - DECODE_D_RD_FS(analysis, insn); - return RISCV_SET_REG(rd, F2INT(64, D_RM, frs1)); + DECODE_D_FD_FS_F64(analysis, insn); + return SEQ3( + SETL("_r", FCONVERT(RZ_FLOAT_IEEE754_BIN_32, D_RM, frs1)), + RISCV_SET_FREG_D_F32(frd, VARL("_r")), + RISCV_FD_UPDATE_FFLAGS()); } // ----------------------------------------------------------------------- @@ -350,19 +164,36 @@ static RzILOpEffect *rz_riscv_lift_fcvt_lu_d(RZ_BORROW RZ_NONNULL RzAnalysis *an // ----------------------------------------------------------------------- // fcvt.d.w fd, rs1 — signed int32 → float64 -DEFINE_D_LIFTER(fcvt_d_w, DECODE_D_FD_RS, - SINT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, CAST(32, IL_FALSE, rs1))) +static RzILOpEffect *rz_riscv_lift_fcvt_d_w(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_D_FD_RS(analysis, insn); + return SEQ3( + SETL("_r", SINT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, SIGNED(64, CAST(32, IL_FALSE, rs1)))), + RISCV_SET_FREG_D(frd, VARL("_r")), + RISCV_FD_UPDATE_FFLAGS()); +} // fcvt.d.wu fd, rs1 — unsigned int32 → float64 -DEFINE_D_LIFTER(fcvt_d_wu, DECODE_D_FD_RS, - INT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, CAST(32, IL_FALSE, rs1))) +static RzILOpEffect *rz_riscv_lift_fcvt_d_wu(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { + DECODE_D_FD_RS(analysis, insn); + return SEQ3( + SETL("_r", INT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, CAST(64, IL_FALSE, CAST(32, IL_FALSE, rs1)))), + RISCV_SET_FREG_D(frd, VARL("_r")), + RISCV_FD_UPDATE_FFLAGS()); +} // fcvt.d.l fd, rs1 — signed int64 → float64 (RV64D only) +// NX is raised when the integer cannot be represented exactly in float64 (more than +// 53 significant bits). Saving to _r lets RISCV_FD_UPDATE_FFLAGS query the result. static RzILOpEffect *rz_riscv_lift_fcvt_d_l(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { REQUIRE_64_BIT(analysis); DECODE_D_FD_RS(analysis, insn); - return RISCV_SET_FREG_D(frd, SINT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, rs1)); + return SEQ3( + SETL("_r", SINT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, rs1)), + RISCV_SET_FREG_D(frd, VARL("_r")), + RISCV_FD_UPDATE_FFLAGS()); } // fcvt.d.lu fd, rs1 — unsigned int64 → float64 (RV64D only) @@ -370,32 +201,12 @@ static RzILOpEffect *rz_riscv_lift_fcvt_d_lu(RZ_BORROW RZ_NONNULL RzAnalysis *an RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { REQUIRE_64_BIT(analysis); DECODE_D_FD_RS(analysis, insn); - return RISCV_SET_FREG_D(frd, INT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, rs1)); + return SEQ3( + SETL("_r", INT2F(RZ_FLOAT_IEEE754_BIN_64, D_RM, rs1)), + RISCV_SET_FREG_D(frd, VARL("_r")), + RISCV_FD_UPDATE_FFLAGS()); } -// ----------------------------------------------------------------------- -// D Extension: Precision conversions -// -// NaN-boxing note -// --------------- -// When the D extension is present the FP register file is 64 bits wide. -// A float32 result stored into an FP register must be NaN-boxed: the upper -// 32 bits are forced to 0xFFFFFFFF. RISCV_SET_FREG_D_F32 handles this. -// -// When reading a float32 source from a D register the lower 32 bits -// are used; the upper NaN-box bits are discarded by CAST(32, IL_FALSE, ...). -// ----------------------------------------------------------------------- - -// fcvt.d.s fd, fs1 — float32 (NaN-boxed in D reg) → float64 -// capstone encodes fs1 with the _F suffix; DECODE_D_FD_FS_F32 reads the -// lower 32 bits of the 64-bit register and reinterprets as float32. -DEFINE_D_LIFTER(fcvt_d_s, DECODE_D_FD_FS_F32, - FCONVERT(RZ_FLOAT_IEEE754_BIN_64, D_RM, frs1)) - -// fcvt.s.d fd, fs1 — float64 → float32, NaN-boxed into D register -DEFINE_D_LIFTER_F32_TO_FREG(fcvt_s_d, DECODE_D_FD_FS_F64, - FCONVERT(RZ_FLOAT_IEEE754_BIN_32, D_RM, frs1)) - // ----------------------------------------------------------------------- // D Extension: Bit-level Move (RV64D only) // ----------------------------------------------------------------------- @@ -418,4 +229,22 @@ static RzILOpEffect *rz_riscv_lift_fmv_d_x(RZ_BORROW RZ_NONNULL RzAnalysis *anal #include +// ----------------------------------------------------------------------- +// Clean up D interface macros +// ----------------------------------------------------------------------- +#undef RISCV_FD_REG_GETTER +#undef RISCV_FD_REG_SETTER +#undef RISCV_FD_REG_GETTER_BV +#undef RISCV_FD_REG_SETTER_BV +#undef RISCV_FD_GET_MANTISSA +#undef RISCV_FD_GET_EXPONENT +#undef RISCV_FD_GET_SIGN +#undef RISCV_FD_IS_NAN +#undef RISCV_FD_IS_S_NAN +#undef RISCV_FD_IS_MAX_EXP +#undef RISCV_FD_IS_EXP_OVERFLOW_INT +#undef RISCV_FD_IS_EXP_OVERFLOW_UINT +#undef RISCV_FD_IS_EXP_OVERFLOW_LONG +#undef RISCV_FD_IS_EXP_OVERFLOW_ULONG + #endif // RISCV_IL_D_H diff --git a/librz/arch/isa/riscv/riscv_il_f.h b/librz/arch/isa/riscv/riscv_il_f.h index e117d54f28b..b025c5cdbb5 100644 --- a/librz/arch/isa/riscv/riscv_il_f.h +++ b/librz/arch/isa/riscv/riscv_il_f.h @@ -4,20 +4,7 @@ #ifndef RISCV_IL_F_H #define RISCV_IL_F_H -#include "riscv_il_base.h" - -#include -#include - -#include "riscv_il_float_reg_names.h" - -// ----------------------------------------------------------------------- -// F extension: register access (RISCV_REG_F0_F = 106, _F suffix) -// -// In an F-only implementation the FP registers are 32-bit IL global -// variables whose raw bits hold the IEEE 754 binary32 value. -// ----------------------------------------------------------------------- -#define RISCV_FREG_F_NAME(reg) riscv_freg_names[(reg) - RISCV_REG_F0_F] +#define RISCV_FREG_F_NAME(reg) riscv_freg_name(reg) // The register is 64-bit (NaN-boxed); hence extracting the lower 32 bits. #define RISCV_GET_FREG_RAW(reg) CAST(32, IL_FALSE, VARG(RISCV_FREG_F_NAME(reg))) @@ -25,356 +12,124 @@ #define RISCV_SET_FREG_RAW(reg, val) SETG(RISCV_FREG_F_NAME(reg), APPEND(UN(32, 0xFFFFFFFF), val)) // Read a float register as a float32 IL value -#define RISCV_GET_FREG_F(reg) FLOATV32(RISCV_GET_FREG_RAW(reg)) +#define RISCV_FD_REG_GETTER(reg) FLOATV32(RISCV_GET_FREG_RAW(reg)) // Read a float register as a raw 32-bit bitvector -#define RISCV_GET_FREG_F_BV(reg) RISCV_GET_FREG_RAW(reg) +#define RISCV_FD_REG_GETTER_BV(reg) RISCV_GET_FREG_RAW(reg) // Write a float32 IL value into a float register -#define RISCV_SET_FREG_F(reg, fl) RISCV_SET_FREG_RAW(reg, F2BV(fl)) +#define RISCV_FD_REG_SETTER(reg, fl) RISCV_SET_FREG_RAW(reg, F2BV(fl)) // Write a raw 32-bit bitvector into a float register -#define RISCV_SET_FREG_F_BV(reg, bv) RISCV_SET_FREG_RAW(reg, bv) - -// Map Capstone's RISC-V rounding mode to RzFloat's rounding mode. - -// RzIL float operations (FADD, FMUL, F2SINT, ...) accept a RzFloatRMode enum -// value that is baked into the IL expression at lift time — it is a -// compile-time constant in the IL tree, not a runtime value. There is -// currently no RzIL mechanism to pass a variable (e.g. VARG("fcsr")) as the -// rounding mode of a float operation, so RISCV_RM_DYN cannot be faithfully -// represented. Instructions that use dynamic rounding are lifted with RNE as -// a fallback, which is architecturally incorrect whenever frm != RNE at -// runtime but is the best approximation available without changes to the RzIL -// float layer. -static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { - switch (rm) { - case RISCV_RM_RNE: return RZ_FLOAT_RMODE_RNE; - case RISCV_RM_RTZ: return RZ_FLOAT_RMODE_RTZ; - case RISCV_RM_RDN: return RZ_FLOAT_RMODE_RTN; - case RISCV_RM_RUP: return RZ_FLOAT_RMODE_RTP; - case RISCV_RM_RMM: return RZ_FLOAT_RMODE_RNA; - default: return RZ_FLOAT_RMODE_RNE; // RISCV_RM_DYN / RISCV_RM_INVALID: see above - } -} - +#define RISCV_FD_REG_SETTER_BV(reg, bv) RISCV_SET_FREG_RAW(reg, bv) +// destructure a float into its 3 IEEE 754 fields +#define RISCV_FD_GET_EXPONENT(bv) EXTRACT32(bv, UN(32, 23), UN(32, 8)) +#define RISCV_FD_GET_MANTISSA(bv) EXTRACT32(bv, UN(32, 0), UN(32, 23)) +#define RISCV_FD_GET_SIGN(bv) EXTRACT32(bv, UN(32, 31), UN(32, 1)) +// NAN API +#define RISCV_FD_IS_NAN(bv) AND(EQ(RISCV_FD_GET_EXPONENT(bv), UN(32, 0xFF)), NON_ZERO(RISCV_FD_GET_MANTISSA(bv))) +#define RISCV_FD_IS_S_NAN(bv) AND(RISCV_FD_IS_NAN(bv), EQ(EXTRACT32(bv, UN(32, 22), UN(32, 1)), UN(32, 0))) +// Exponent API +#define RISCV_FD_IS_MAX_EXP(bv) EQ(bv, UN(32, 0xFF)) +#define RISCV_FD_IS_EXP_OVERFLOW_INT(bv) UGE(bv, UN(32, 158)) +#define RISCV_FD_IS_EXP_OVERFLOW_UINT(bv) UGE(bv, UN(32, 159)) +#define RISCV_FD_IS_EXP_OVERFLOW_LONG(bv) UGE(bv, UN(32, 190)) +#define RISCV_FD_IS_EXP_OVERFLOW_ULONG(bv) UGE(bv, UN(32, 191)) + +// ----------------------------------------------------------------------- +// F Extension: rounding mode, decoders, and lifter templates +// ----------------------------------------------------------------------- #define F_RM riscv_rm_to_rz(insn->detail->riscv.rounding_mode) -// fflags / fcsr helpers -// RISC-V fflags layout (bits 4:0 of fcsr): -// bit 0 NX inexact RZ_FLOAT_E_INEXACT -// bit 1 UF underflow RZ_FLOAT_E_UNDERFLOW -// bit 2 OF overflow RZ_FLOAT_E_OVERFLOW -// bit 3 DZ divide-by-zero RZ_FLOAT_E_DIV_ZERO -// bit 4 NV invalid RZ_FLOAT_E_INVALID_OP -// -// Usage: set local float variable "_r" to the result, then call -// RISCV_ACCUMULATE_FFLAGS() to sticky-OR exceptions into "fflags" -// and keep "fcsr" in sync. -#define RISCV_F_EXC(riscv_bit, rz_exc) \ - ITE(FEXCEPT(rz_exc, VARL("_r")), UN(64, riscv_bit), UN(64, 0)) +#define RISCV_SET_FREG_F(reg, fl) RISCV_FD_REG_SETTER(reg, fl) +#define RISCV_ACCUMULATE_FFLAGS() RISCV_FD_UPDATE_FFLAGS() -#define RISCV_ACCUMULATE_FFLAGS() \ - SETG("fcsr", LOGOR(VARG("fcsr"), \ - LOGOR(RISCV_F_EXC(0x01, RZ_FLOAT_E_INEXACT), \ - LOGOR(RISCV_F_EXC(0x02, RZ_FLOAT_E_UNDERFLOW), \ - LOGOR(RISCV_F_EXC(0x04, RZ_FLOAT_E_OVERFLOW), \ - LOGOR(RISCV_F_EXC(0x08, RZ_FLOAT_E_DIV_ZERO), \ - RISCV_F_EXC(0x10, RZ_FLOAT_E_INVALID_OP))))))) +// frd=FReg[0], rs1=IntReg[1] (fcvt.s.w, fcvt.s.wu, fcvt.s.l, fcvt.s.lu, fmv.w.x) +#define DECODE_F_FD_RS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); -// ----------------------------------------------------------------------- -// Lifter templates -// ----------------------------------------------------------------------- +// rd=IntReg[0], bvrs1=raw32(FReg[1]) (fmv.x.w) +#define DECODE_F_RD_FS_BV(analysis, insn) DECODE_FD_RD_FS_BV(analysis, insn) -// float32 result → float destination register, with fflags/fcsr update -#define DEFINE_F_LIFTER(name, decoder, fl_result) \ +// integer→float32 lifter: compute expr, store to freg, update fflags +#define DEFINE_F_LIFTER(name, decoder, expr) \ static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ decoder(analysis, insn); \ return SEQ3( \ - SETL("_r", fl_result), \ - RISCV_SET_FREG_F(frd, VARL("_r")), \ - RISCV_ACCUMULATE_FFLAGS()); \ + SETL("_r", expr), \ + RISCV_FD_REG_SETTER(frd, VARL("_r")), \ + RISCV_FD_UPDATE_FFLAGS()); \ } -// raw 32-bit bitvector → float destination register -#define DEFINE_F_LIFTER_BV_TO_FREG(name, decoder, bv_result) \ +// bitvector→float register lifter (no rounding, no fflags update) +#define DEFINE_F_LIFTER_BV_TO_FREG(name, decoder, bv_expr) \ static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ decoder(analysis, insn); \ - return RISCV_SET_FREG_F_BV(frd, bv_result); \ + return RISCV_FD_REG_SETTER_BV(frd, bv_expr); \ } -// ----------------------------------------------------------------------- -// Decoders -// ----------------------------------------------------------------------- +// ---------------------------- Instantiate FP definition generators ---------------------------- +#include "riscv_il_fd_common.h" -#define DECODE_F_FD_FS_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); \ - RzILOpFloat *frs2 = RISCV_GET_FREG_F(insn->detail->riscv.operands[2].reg); - -#define DECODE_F_FD_BV_BV(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *bvrs1 = RISCV_GET_FREG_F_BV(insn->detail->riscv.operands[1].reg); \ - RzILOpBitVector *bvrs2 = RISCV_GET_FREG_F_BV(insn->detail->riscv.operands[2].reg); - -#define DECODE_F_FD_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); - -#define DECODE_F_RD_FS_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); \ - RzILOpFloat *frs2 = RISCV_GET_FREG_F(insn->detail->riscv.operands[2].reg); - -#define DECODE_F_RD_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); - -#define DECODE_F_RD_FS_BV(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - uint32_t rd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *bvrs1 = RISCV_GET_FREG_F_BV(insn->detail->riscv.operands[1].reg); - -#define DECODE_F_FD_RS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); - -#define DECODE_F_FD_MEM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_MEM); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); - -#define DECODE_F_FS_MEM(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_MEM); \ - RzILOpBitVector *bvrs1 = RISCV_GET_FREG_F_BV(insn->detail->riscv.operands[0].reg); \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ - RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); - -#define DECODE_F_FD_FS_FS_FS(analysis, insn) \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - REQUIRE_OP(3, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpFloat *frs1 = RISCV_GET_FREG_F(insn->detail->riscv.operands[1].reg); \ - RzILOpFloat *frs2 = RISCV_GET_FREG_F(insn->detail->riscv.operands[2].reg); \ - RzILOpFloat *frs3 = RISCV_GET_FREG_F(insn->detail->riscv.operands[3].reg); +#include // ----------------------------------------------------------------------- -// F Extension: Memory +// Memory // ----------------------------------------------------------------------- -// flw fd, offset(rs1) — load 32-bit float from memory -DEFINE_F_LIFTER_BV_TO_FREG(flw, DECODE_F_FD_MEM, LOADW(32, ADD(rs, imm))) - -// fsw fs2, offset(rs1) — store 32-bit float to memory -DEFINE_LIFTER_WITH_EFFECT(fsw, DECODE_F_FS_MEM, STOREW(ADD(rs, imm), bvrs1)) +// flw fd, offset(rs1) — load 32-bit float from memory +DEF_LOAD(flw, 32) +// fsw fs2, offset(rs1) — store 32-bit float to memory +DEF_STORE(fsw) // ----------------------------------------------------------------------- // Arithmetic // ----------------------------------------------------------------------- -DEFINE_F_LIFTER(fadd_s, DECODE_F_FD_FS_FS, FADD(F_RM, frs1, frs2)) -DEFINE_F_LIFTER(fsub_s, DECODE_F_FD_FS_FS, FSUB(F_RM, frs1, frs2)) -DEFINE_F_LIFTER(fmul_s, DECODE_F_FD_FS_FS, FMUL(F_RM, frs1, frs2)) -DEFINE_F_LIFTER(fdiv_s, DECODE_F_FD_FS_FS, FDIV(F_RM, frs1, frs2)) -DEFINE_F_LIFTER(fsqrt_s, DECODE_F_FD_FS, FSQRT(F_RM, frs1)) +DEF_ADD(fadd_s) +DEF_SUB(fsub_s) +DEF_MUL(fmul_s) +DEF_DIV(fdiv_s) +DEF_SQRT(fsqrt_s) // ----------------------------------------------------------------------- // Fused Multiply-Add -// -// fmadd.s: fd = (rs1 × rs2) + rs3 -// fmsub.s: fd = (rs1 × rs2) - rs3 -// fnmadd.s: fd = -(rs1 × rs2) - rs3 -// fnmsub.s: fd = -(rs1 × rs2) + rs3 // ----------------------------------------------------------------------- -DEFINE_F_LIFTER(fmadd_s, DECODE_F_FD_FS_FS_FS, FMAD(F_RM, frs1, frs2, frs3)) -DEFINE_F_LIFTER(fmsub_s, DECODE_F_FD_FS_FS_FS, FMAD(F_RM, frs1, frs2, FNEG(frs3))) -DEFINE_F_LIFTER(fnmadd_s, DECODE_F_FD_FS_FS_FS, FNEG(FMAD(F_RM, frs1, frs2, frs3))) -DEFINE_F_LIFTER(fnmsub_s, DECODE_F_FD_FS_FS_FS, FMAD(F_RM, FNEG(frs1), frs2, frs3)) +DEF_FMADD(fmadd_s) +DEF_FMSUB(fmsub_s) +DEF_FNMADD(fnmadd_s) +DEF_FNMSUB(fnmsub_s) // ----------------------------------------------------------------------- // Sign Injection (bit-level, no rounding) -// -// fsgnj.s: fd = |rs1| with sign of rs2 -// fsgnjn.s: fd = |rs1| with negated sign of rs2 -// fsgnjx.s: fd = |rs1| with sign = sign(rs1) XOR sign(rs2) -// -// Bit 31 of float32 is the sign bit. -// ----------------------------------------------------------------------- -DEFINE_F_LIFTER_BV_TO_FREG(fsgnj_s, DECODE_F_FD_BV_BV, - LOGOR(LOGAND(bvrs1, UN(32, 0x7FFFFFFF)), - LOGAND(bvrs2, UN(32, 0x80000000)))) - -DEFINE_F_LIFTER_BV_TO_FREG(fsgnjn_s, DECODE_F_FD_BV_BV, - LOGOR(LOGAND(bvrs1, UN(32, 0x7FFFFFFF)), - LOGAND(LOGNOT(bvrs2), UN(32, 0x80000000)))) - -// DUP bvrs1 to avoid shared AST nodes. -DEFINE_F_LIFTER_BV_TO_FREG(fsgnjx_s, DECODE_F_FD_BV_BV, - LOGOR(LOGAND(DUP(bvrs1), UN(32, 0x7FFFFFFF)), - LOGAND(LOGXOR(bvrs1, bvrs2), UN(32, 0x80000000)))) - -// ----------------------------------------------------------------------- -// Min / Max -// -// IEEE 754-201x minimumNumber / maximumNumber (RISC-V F spec >= 2.2): -// - signaling NaN operand → raise NV, return canonical qNaN -// - exactly one quiet NaN → return the non-NaN operand -// - both quiet NaN → return canonical qNaN -// - otherwise → normal min / max -// -// Float32 layout: sign[31], exponent[30:23], mantissa[22:0], quiet[22]. -// A value is sNaN iff exponent==0xFF && mantissa!=0 && quiet_bit==0. -// cond(a, b): FLE for fmin_s, FGE for fmax_s. // ----------------------------------------------------------------------- -#define DEFINE_LIFTER_MINMAX(name, cond) \ - static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ - REQUIRE_OP(0, RISCV_OP_REG); \ - REQUIRE_OP(1, RISCV_OP_REG); \ - REQUIRE_OP(2, RISCV_OP_REG); \ - uint32_t frd = insn->detail->riscv.operands[0].reg; \ - uint32_t frs1_reg = insn->detail->riscv.operands[1].reg; \ - uint32_t frs2_reg = insn->detail->riscv.operands[2].reg; \ - return SEQN(10, \ - /* raw 32-bit bitvector of frs1, needed for bit-level sNaN inspection */ \ - SETL("_bva", RISCV_GET_FREG_F_BV(frs1_reg)), \ - /* raw 32-bit bitvector of frs2, needed for bit-level sNaN inspection */ \ - SETL("_bvb", RISCV_GET_FREG_F_BV(frs2_reg)), \ - /* ordinary float32 interpetation of operand 1 for IL float comparisons */ \ - SETL("_a", FLOATV32(VARL("_bva"))), \ - /* ordinary float32 interpetation of operand 2 for IL float comparisons */ \ - SETL("_b", FLOATV32(VARL("_bvb"))), \ - /* true if operand 1 is any NaN (exponent==0xFF and mantissa!=0) */ \ - SETL("_na", AND(EQ(EXTRACT32(VARL("_bva"), UN(32, 23), UN(32, 8)), UN(8, 0xFF)), \ - NON_ZERO(EXTRACT32(VARL("_bva"), UN(32, 0), UN(32, 23))))), \ - /* true if operand 2 is any NaN */ \ - SETL("_nb", AND(EQ(EXTRACT32(VARL("_bvb"), UN(32, 23), UN(32, 8)), UN(8, 0xFF)), \ - NON_ZERO(EXTRACT32(VARL("_bvb"), UN(32, 0), UN(32, 23))))), \ - /* true if operand 1 is a signaling NaN (NaN with quiet bit[22]==0) */ \ - SETL("_sa", AND(VARL("_na"), INV(NON_ZERO(EXTRACT32(VARL("_bva"), UN(32, 22), UN(32, 1)))))), \ - /* true if operand 2 is a signaling NaN */ \ - SETL("_sb", AND(VARL("_nb"), INV(NON_ZERO(EXTRACT32(VARL("_bvb"), UN(32, 22), UN(32, 1)))))), \ - /* raise NV (invalid operation, bit 4) in fcsr when either operand is sNaN */ \ - SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_sa"), VARL("_sb")), UN(64, 0x10), UN(64, 0)))), \ - RISCV_SET_FREG_F(frd, \ - ITE(OR(VARL("_sa"), VARL("_sb")), IL_FQNAN(RZ_FLOAT_IEEE754_BIN_32), \ - ITE(VARL("_na"), VARL("_b"), \ - ITE(VARL("_nb"), VARL("_a"), \ - ITE(cond(VARL("_a"), VARL("_b")), VARL("_a"), VARL("_b"))))))); \ - } - -DEFINE_LIFTER_MINMAX(fmin_s, FLE) -DEFINE_LIFTER_MINMAX(fmax_s, FGE) +DEF_FSGNJ(fsgnj_s, 32) +DEF_FSGNJN(fsgnjn_s, 32) +DEF_FSGNJX(fsgnjx_s, 32) // ----------------------------------------------------------------------- -// Comparison (result in integer register) +// Min/Max // ----------------------------------------------------------------------- -DEFINE_LIFTER(feq_s, DECODE_F_RD_FS_FS, BOOL_TO_BV(FEQ(frs1, frs2), analysis->bits)) -DEFINE_LIFTER(flt_s, DECODE_F_RD_FS_FS, BOOL_TO_BV(FLT(frs1, frs2), analysis->bits)) -DEFINE_LIFTER(fle_s, DECODE_F_RD_FS_FS, BOOL_TO_BV(FLE(frs1, frs2), analysis->bits)) - +DEF_FMIN(fmin_s, 32) +DEF_FMAX(fmax_s, 32) // ----------------------------------------------------------------------- -// F Extension: fclass.s -// -// Classifies the float32 value in fs1 into one of 10 categories, placing -// a one-hot 10-bit mask into rd (zero-extended to XLEN). -// -// bit 0 -infinity -// bit 1 negative normal -// bit 2 negative subnormal -// bit 3 -0 -// bit 4 +0 -// bit 5 positive subnormal -// bit 6 positive normal -// bit 7 +infinity -// bit 8 signaling NaN -// bit 9 quiet NaN -// -// Float32 layout: sign[31], exponent[30:23], mantissa[22:0], quiet[22]. +// Comparison and equality // ----------------------------------------------------------------------- -#define FBIT_S(n, cond) SHIFTL0(BOOL_TO_BV(cond, xlen), UN(xlen, (n))) +DEF_FEQ(feq_s, 32) +DEF_FLT(flt_s, 32) +DEF_FLE(fle_s, 32) -static RzILOpEffect *rz_riscv_lift_fclass_s(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { - DECODE_F_RD_FS_BV(analysis, insn); - int xlen = analysis->bits; - return SEQN(14, - SETL("_b", bvrs1), - SETL("_ex", EXTRACT32(VARL("_b"), UN(32, 23), UN(32, 8))), - SETL("_mn", EXTRACT32(VARL("_b"), UN(32, 0), UN(32, 23))), - SETL("_sg", NON_ZERO(EXTRACT32(VARL("_b"), UN(32, 31), UN(32, 1)))), - SETL("_qt", NON_ZERO(EXTRACT32(VARL("_b"), UN(32, 22), UN(32, 1)))), - SETL("_xff", EQ(VARL("_ex"), UN(8, 0xFF))), - SETL("_xz", IS_ZERO(VARL("_ex"))), - SETL("_mz", IS_ZERO(VARL("_mn"))), - SETL("_na", AND(VARL("_xff"), INV(VARL("_mz")))), - SETL("_in", AND(VARL("_xff"), VARL("_mz"))), - SETL("_su", AND(VARL("_xz"), INV(VARL("_mz")))), - SETL("_ze", AND(VARL("_xz"), VARL("_mz"))), - SETL("_no", AND(INV(VARL("_xz")), INV(VARL("_xff")))), - RISCV_SET_REG(rd, - LOGOR(FBIT_S(0, AND(VARL("_sg"), VARL("_in"))), - LOGOR(FBIT_S(1, AND(VARL("_sg"), VARL("_no"))), - LOGOR(FBIT_S(2, AND(VARL("_sg"), VARL("_su"))), - LOGOR(FBIT_S(3, AND(VARL("_sg"), VARL("_ze"))), - LOGOR(FBIT_S(4, AND(INV(VARL("_sg")), VARL("_ze"))), - LOGOR(FBIT_S(5, AND(INV(VARL("_sg")), VARL("_su"))), - LOGOR(FBIT_S(6, AND(INV(VARL("_sg")), VARL("_no"))), - LOGOR(FBIT_S(7, AND(INV(VARL("_sg")), VARL("_in"))), - LOGOR(FBIT_S(8, AND(VARL("_na"), INV(VARL("_qt")))), - FBIT_S(9, AND(VARL("_na"), VARL("_qt")))))))))))))); -} -#undef FBIT_S +DEF_FCLASS(fclass_s) // ----------------------------------------------------------------------- -// F Extension: Conversions float32 → integer -// -// RISC-V: in RV64 the 32-bit integer results of fcvt.w.s / fcvt.wu.s are -// sign-extended to 64 bits regardless of signedness (per spec §11.4). +// Conversions float32 → integer // ----------------------------------------------------------------------- - -// fcvt.w.s rd, fs1 — float32 → signed int32, sign-extended to XLEN -DEFINE_LIFTER(fcvt_w_s, DECODE_F_RD_FS, - SIGNED(analysis->bits, F2SINT(32, F_RM, frs1))) - -// fcvt.wu.s rd, fs1 — float32 → unsigned int32, sign-extended to XLEN -DEFINE_LIFTER(fcvt_wu_s, DECODE_F_RD_FS, - SIGNED(analysis->bits, F2INT(32, F_RM, frs1))) - -// fcvt.l.s rd, fs1 — float32 → signed int64 (RV64F only) -static RzILOpEffect *rz_riscv_lift_fcvt_l_s(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { - REQUIRE_64_BIT(analysis); - DECODE_F_RD_FS(analysis, insn); - return RISCV_SET_REG(rd, F2SINT(64, F_RM, frs1)); -} - -// fcvt.lu.s rd, fs1 — float32 → unsigned int64 (RV64F only) -static RzILOpEffect *rz_riscv_lift_fcvt_lu_s(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, - RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { - REQUIRE_64_BIT(analysis); - DECODE_F_RD_FS(analysis, insn); - return RISCV_SET_REG(rd, F2INT(64, F_RM, frs1)); -} +// +DEF_FCVT_W(fcvt_w_s, 32) +DEF_FCVT_WU(fcvt_wu_s, 32) +DEF_FCVT_L(fcvt_l_s, 32) +DEF_FCVT_LU(fcvt_lu_s, 32) // ----------------------------------------------------------------------- // F Extension: Conversions integer → float32 @@ -390,11 +145,16 @@ DEFINE_F_LIFTER(fcvt_s_wu, DECODE_F_FD_RS, INT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, CAST(32, IL_FALSE, rs1))) // fcvt.s.l fd, rs1 — signed int64 to float32 (RV64F only) +// NX is raised when the integer cannot be represented exactly in float32 (more than +// 24 significant bits). Saving to _r lets RISCV_ACCUMULATE_FFLAGS query the result. static RzILOpEffect *rz_riscv_lift_fcvt_s_l(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { REQUIRE_64_BIT(analysis); DECODE_F_FD_RS(analysis, insn); - return RISCV_SET_FREG_F(frd, SINT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, rs1)); + return SEQ3( + SETL("_r", SINT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, rs1)), + RISCV_SET_FREG_F(frd, VARL("_r")), + RISCV_ACCUMULATE_FFLAGS()); } // fcvt.s.lu fd, rs1 — unsigned int64 to float32 (RV64F only) @@ -402,7 +162,10 @@ static RzILOpEffect *rz_riscv_lift_fcvt_s_lu(RZ_BORROW RZ_NONNULL RzAnalysis *an RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { REQUIRE_64_BIT(analysis); DECODE_F_FD_RS(analysis, insn); - return RISCV_SET_FREG_F(frd, INT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, rs1)); + return SEQ3( + SETL("_r", INT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, rs1)), + RISCV_SET_FREG_F(frd, VARL("_r")), + RISCV_ACCUMULATE_FFLAGS()); } // ----------------------------------------------------------------------- @@ -419,4 +182,26 @@ DEFINE_F_LIFTER_BV_TO_FREG(fmv_w_x, DECODE_F_FD_RS, #include +#undef RISCV_FD_REG_GETTER +#undef RISCV_FD_REG_SETTER +#undef RISCV_FD_REG_GETTER_BV +#undef RISCV_FD_REG_SETTER_BV +#undef RISCV_FD_GET_MANTISSA +#undef RISCV_FD_GET_EXPONENT +#undef RISCV_FD_GET_SIGN +#undef RISCV_FD_IS_NAN +#undef RISCV_FD_IS_S_NAN +#undef RISCV_FD_IS_MAX_EXP +#undef RISCV_FD_IS_EXP_OVERFLOW_INT +#undef RISCV_FD_IS_EXP_OVERFLOW_UINT +#undef RISCV_FD_IS_EXP_OVERFLOW_LONG +#undef RISCV_FD_IS_EXP_OVERFLOW_ULONG +#undef F_RM +#undef RISCV_SET_FREG_F +#undef RISCV_ACCUMULATE_FFLAGS +#undef DECODE_F_FD_RS +#undef DECODE_F_RD_FS_BV +#undef DEFINE_F_LIFTER +#undef DEFINE_F_LIFTER_BV_TO_FREG + #endif // RISCV_IL_F_H diff --git a/librz/arch/isa/riscv/riscv_il_fd_common.h b/librz/arch/isa/riscv/riscv_il_fd_common.h new file mode 100644 index 00000000000..1ba6406ef07 --- /dev/null +++ b/librz/arch/isa/riscv/riscv_il_fd_common.h @@ -0,0 +1,634 @@ +#ifndef RISCV_IL_FD_COMMON_H +#define RISCV_IL_FD_COMMON_H + +/** + * This file provides width-agnostic common definitions for floating-point instructions in RISC-V. + * + * The file MUST be specialized by defining ALL the following macros BEFORE including it: + * - RISCV_FD_REG_SETTER: set a floating-point register. + * - RISCV_FD_REG_GETTER: get a floating-point register. + * - RISCV_FD_REG_SETTER_BV: set a floating-point register to a raw bitvector. + * - RISCV_FD_REG_GETTER_BV: get a floating-point register as a raw bitvector. + * - RISCV_FD_GET_MANTISSA: get the mantissa of a floating-point number. + * - RISCV_FD_GET_EXPONENT: get the exponent of a floating-point number. + * - RISCV_FD_GET_SIGN: get the sign bit of a floating-point number. + * - RISCV_FD_IS_NAN: check if a floating-point number is NaN. + * - RISCV_FD_IS_S_NAN: check if a floating-point number is a signaling NaN. + * - RISCV_FD_IS_MAX_EXP: check if a floating-point number has the maximum exponent. + * - RISCV_FD_IS_EXP_OVERFLOW_INT: check if a floating-point number has an exponent that would overflow an integer. + * - RISCV_FD_IS_EXP_OVERFLOW_UINT: check if a floating-point number has an exponent that would overflow an unsigned integer. + * - RISCV_FD_IS_EXP_OVERFLOW_LONG: check if a floating-point number has an exponent that would overflow a long integer. + * - RISCV_FD_IS_EXP_OVERFLOW_ULONG: check if a floating-point number has an exponent that would overflow an unsigned long integer. + + * Once this low-level API is fixed, the instruction definitions are generic on FP width. + + * After inclusion, all the DEF_* macros defined by this file must be called with a concrete name and sometimes + * also with a bit width in order to instantiate the actual instruction definition. +*/ + +#include "riscv_il_base.h" + +#include + +#include "riscv_il_float_reg_names.h" + +#include +// ------------------------------------------- API ------------------------------------------- +// -------------------------------------- Register API -------------------------------------- +#ifndef RISCV_FD_REG_SETTER +#error "RISCV_FD_REG_SETTER must be defined before including this file" +#endif // RISCV_FD_REG_SETTER + +#ifndef RISCV_FD_REG_GETTER +#error "RISCV_FD_REG_GETTER must be defined before including this file" +#endif // RISCV_FD_REG_GETTER + +#ifndef RISCV_FD_REG_SETTER_BV +#error "RISCV_FD_REG_SETTER_BV must be defined before including this file" +#endif // RISCV_FD_REG_SETTER_BV + +#ifndef RISCV_FD_REG_GETTER_BV +#error "RISCV_FD_REG_GETTER_BV must be defined before including this file" +#endif // RISCV_FD_REG_GETTER_BV + +// -------------------------------------- Destructuring API ----------------------------------- +#ifndef RISCV_FD_GET_MANTISSA +#error "RISCV_FD_GET_MANTISSA must be defined before including this file" +#endif // RISCV_FD_GET_MANTISSA + +#ifndef RISCV_FD_GET_EXPONENT +#error "RISCV_FD_GET_EXPONENT must be defined before including this file" +#endif // RISCV_FD_GET_EXPONENT + +#ifndef RISCV_FD_GET_SIGN +#error "RISCV_FD_GET_SIGN must be defined before including this file" +#endif // RISCV_FD_GET_SIGN + +// -------------------------------------- NAN Query API -------------------------------------- +#ifndef RISCV_FD_IS_NAN +#error "RISCV_FD_IS_NAN must be defined before including this file" +#endif // RISCV_FD_IS_NAN + +#ifndef RISCV_FD_IS_S_NAN +#error "RISCV_FD_IS_S_NAN must be defined before including this file" +#endif // RISCV_FD_IS_S_NAN + +// -------------------------------------- Exponent Query API -------------------------------------- +#ifndef RISCV_FD_IS_MAX_EXP +#error "RISCV_FD_IS_MAX_EXP must be defined before including this file" +#endif // RISCV_FD_IS_MAX_EXP + +#ifndef RISCV_FD_IS_EXP_OVERFLOW_INT +#error "RISCV_FD_IS_EXP_OVERFLOW_INT must be defined before including this file" +#endif // RISCV_FD_IS_EXP_OVERFLOW_INT + +#ifndef RISCV_FD_IS_EXP_OVERFLOW_UINT +#error "RISCV_FD_IS_EXP_OVERFLOW_UINT must be defined before including this file" +#endif // RISCV_FD_IS_EXP_OVERFLOW_UINT + +#ifndef RISCV_FD_IS_EXP_OVERFLOW_LONG +#error "RISCV_FD_IS_EXP_OVERFLOW_LONG must be defined before including this file" +#endif // RISCV_FD_IS_EXP_OVERFLOW_LONG + +#ifndef RISCV_FD_IS_EXP_OVERFLOW_ULONG +#error "RISCV_FD_IS_EXP_OVERFLOW_ULONG must be defined before including this file" +#endif // RISCV_FD_IS_EXP_OVERFLOW_ULONG + +// -------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------- + +// Map Capstone's RISC-V static rounding mode to RzFloat's rounding mode. +// RISCV_RM_DYN must never be passed here; use RISCV_FD_FRM_DISPATCH instead. +static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { + switch (rm) { + case RISCV_RM_RNE: return RZ_FLOAT_RMODE_RNE; + case RISCV_RM_RTZ: return RZ_FLOAT_RMODE_RTZ; + case RISCV_RM_RDN: return RZ_FLOAT_RMODE_RTN; + case RISCV_RM_RUP: return RZ_FLOAT_RMODE_RTP; + case RISCV_RM_RMM: return RZ_FLOAT_RMODE_RNA; + default: return RZ_FLOAT_RMODE_RNE; + } +} + +// FD_ROUNDING_MODE: static rounding mode for the current instruction (never DYN). +#define FD_ROUNDING_MODE riscv_rm_to_rz(insn->detail->riscv.rounding_mode) + +#define RISCV_FD_EXC(riscv_bit, rz_exc) \ + ITE(FEXCEPT(rz_exc, VARL("_r")), UN(64, riscv_bit), UN(64, 0)) // CSR is always 64-bit wide in QEMU + +#define RISCV_FD_UPDATE_FFLAGS() \ + SETG("fcsr", LOGOR(VARG("fcsr"), \ + LOGOR(RISCV_FD_EXC(0x01, RZ_FLOAT_E_INEXACT), \ + LOGOR(RISCV_FD_EXC(0x02, RZ_FLOAT_E_UNDERFLOW), \ + LOGOR(RISCV_FD_EXC(0x04, RZ_FLOAT_E_OVERFLOW), \ + LOGOR(RISCV_FD_EXC(0x08, RZ_FLOAT_E_DIV_ZERO), \ + RISCV_FD_EXC(0x10, RZ_FLOAT_E_INVALID_OP))))))) + +#define RISCV_SET_FRM() \ + SETL("_frm", EXTRACT64(VARG("fcsr"), UN(64, 5), UN(32, 3))) + +// ----------------------------------------------------------------------- +// Dynamic rounding mode dispatch +// +// When an instruction encodes rm=111 (DYN), the actual rounding mode is +// read at runtime from fcsr.frm (bits [7:5]). Because RzIL float ops +// take a compile-time RzFloatRMode enum, we enumerate all five valid frm +// values in an ITE tree so the right mode is chosen at emulation time. +#define RISCV_FD_FRM_DISPATCH(fn, ...) \ + ITE(EQ(VARL("_frm"), UN(64, 0)), fn(RZ_FLOAT_RMODE_RNE, __VA_ARGS__), \ + ITE(EQ(VARL("_frm"), UN(64, 1)), fn(RZ_FLOAT_RMODE_RTZ, __VA_ARGS__), \ + ITE(EQ(VARL("_frm"), UN(64, 2)), fn(RZ_FLOAT_RMODE_RTN, __VA_ARGS__), \ + ITE(EQ(VARL("_frm"), UN(64, 3)), fn(RZ_FLOAT_RMODE_RTP, __VA_ARGS__), \ + fn(RZ_FLOAT_RMODE_RNA, __VA_ARGS__))))) + +#define DEFINE_FD_LIFTER(name, decoder, fl_result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return SEQ3( \ + SETL("_r", fl_result), \ + RISCV_FD_REG_SETTER(frd, VARL("_r")), \ + RISCV_FD_UPDATE_FFLAGS()); \ + } + +#define DEFINE_FD_LIFTER_BV_TO_FREG(name, decoder, bv_result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + return RISCV_FD_REG_SETTER_BV(frd, bv_result); \ + } + +#define DEFINE_FD_LIFTER_UNARY(name, decoder, fn) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + if (insn->detail->riscv.rounding_mode == RISCV_RM_DYN) { \ + return SEQN(5, \ + RISCV_SET_FRM(), \ + SETL("_x", frs1), \ + SETL("_r", RISCV_FD_FRM_DISPATCH(fn, VARL("_x"))), \ + RISCV_FD_REG_SETTER(frd, VARL("_r")), \ + RISCV_FD_UPDATE_FFLAGS()); \ + } \ + return SEQ3( \ + SETL("_r", fn(FD_ROUNDING_MODE, frs1)), \ + RISCV_FD_REG_SETTER(frd, VARL("_r")), \ + RISCV_FD_UPDATE_FFLAGS()); \ + } + +// Binary float op (fadd.s, fsub.s, fmul.s, fdiv.s) with DYN support. +#define DEFINE_FD_LIFTER_BINARY(name, decoder, fn) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + if (insn->detail->riscv.rounding_mode == RISCV_RM_DYN) { \ + return SEQN(6, \ + RISCV_SET_FRM(), \ + SETL("_x", frs1), \ + SETL("_y", frs2), \ + SETL("_r", RISCV_FD_FRM_DISPATCH(fn, VARL("_x"), VARL("_y"))), \ + RISCV_FD_REG_SETTER(frd, VARL("_r")), \ + RISCV_FD_UPDATE_FFLAGS()); \ + } \ + return SEQ3( \ + SETL("_r", fn(FD_ROUNDING_MODE, frs1, frs2)), \ + RISCV_FD_REG_SETTER(frd, VARL("_r")), \ + RISCV_FD_UPDATE_FFLAGS()); \ + } + +// Fused multiply-add variants with DYN support. +// a, b, c are the three float operand IL expressions (may include FNEG). +// negate_result: pass true for fnmadd (result = -(a*b+c)). +// Exception flags are always checked on the un-negated FMAD result. +#define DEFINE_FD_LIFTER_MAD(name, decoder, a, b, c, negate_result) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + decoder(analysis, insn); \ + if (insn->detail->riscv.rounding_mode == RISCV_RM_DYN) { \ + return SEQN(7, \ + RISCV_SET_FRM(), \ + SETL("_x", a), \ + SETL("_y", b), \ + SETL("_z", c), \ + SETL("_r", RISCV_FD_FRM_DISPATCH(FMAD, VARL("_x"), VARL("_y"), VARL("_z"))), \ + RISCV_FD_REG_SETTER(frd, (negate_result) ? FNEG(VARL("_r")) : VARL("_r")), \ + RISCV_FD_UPDATE_FFLAGS()); \ + } \ + return SEQ3( \ + SETL("_r", FMAD(FD_ROUNDING_MODE, a, b, c)), \ + RISCV_FD_REG_SETTER(frd, (negate_result) ? FNEG(VARL("_r")) : VARL("_r")), \ + RISCV_FD_UPDATE_FFLAGS()); \ + } + +#define DECODE_FD_FD_FS_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_FD_REG_GETTER(insn->detail->riscv.operands[1].reg); \ + RzILOpFloat *frs2 = RISCV_FD_REG_GETTER(insn->detail->riscv.operands[2].reg); + +#define DECODE_FD_FD_BV_BV(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *bvrs1 = RISCV_FD_REG_GETTER_BV(insn->detail->riscv.operands[1].reg); \ + RzILOpBitVector *bvrs2 = RISCV_FD_REG_GETTER_BV(insn->detail->riscv.operands[2].reg); + +#define DECODE_FD_FD_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_FD_REG_GETTER(insn->detail->riscv.operands[1].reg); + +#define DECODE_FD_RD_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_FD_REG_GETTER(insn->detail->riscv.operands[1].reg); + +#define DECODE_FD_RD_FS_BV(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *bvrs1 = RISCV_FD_REG_GETTER_BV(insn->detail->riscv.operands[1].reg); + +#define DECODE_FD_FD_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +#define DECODE_FD_FS_MEM(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_MEM); \ + RzILOpBitVector *bvrs1 = RISCV_FD_REG_GETTER_BV(insn->detail->riscv.operands[0].reg); \ + RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); + +#define DECODE_FD_FD_FS_FS_FS(analysis, insn) \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + REQUIRE_OP(3, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + RzILOpFloat *frs1 = RISCV_FD_REG_GETTER(insn->detail->riscv.operands[1].reg); \ + RzILOpFloat *frs2 = RISCV_FD_REG_GETTER(insn->detail->riscv.operands[2].reg); \ + RzILOpFloat *frs3 = RISCV_FD_REG_GETTER(insn->detail->riscv.operands[3].reg); + +// ----------------------------------------------------------------------- +// Memory +// ----------------------------------------------------------------------- +// load size-bit float from memory +#define DEF_LOAD(name, size) DEFINE_FD_LIFTER_BV_TO_FREG(name, DECODE_FD_FD_MEM, LOADW(size, ADD(rs, imm))) + +// store float to memory +#define DEF_STORE(name) DEFINE_LIFTER_WITH_EFFECT(name, DECODE_FD_FS_MEM, STOREW(ADD(rs, imm), bvrs1)) + +// ----------------------------------------------------------------------- +// Arithmetic +// ----------------------------------------------------------------------- +#define DEF_ADD(name) DEFINE_FD_LIFTER_BINARY(name, DECODE_FD_FD_FS_FS, FADD) +#define DEF_SUB(name) DEFINE_FD_LIFTER_BINARY(name, DECODE_FD_FD_FS_FS, FSUB) +#define DEF_MUL(name) DEFINE_FD_LIFTER_BINARY(name, DECODE_FD_FD_FS_FS, FMUL) +#define DEF_DIV(name) DEFINE_FD_LIFTER_BINARY(name, DECODE_FD_FD_FS_FS, FDIV) +#define DEF_SQRT(name) DEFINE_FD_LIFTER_UNARY(name, DECODE_FD_FD_FS, FSQRT) + +// ----------------------------------------------------------------------- +// Fused Multiply-Add +// +// fmadd.s: fd = (rs1 × rs2) + rs3 +// fmsub.s: fd = (rs1 × rs2) - rs3 +// fnmadd.s: fd = -(rs1 × rs2) - rs3 +// fnmsub.s: fd = -(rs1 × rs2) + rs3 +// ----------------------------------------------------------------------- +#define DEF_FMADD(name) DEFINE_FD_LIFTER_MAD(name, DECODE_FD_FD_FS_FS_FS, frs1, frs2, frs3, false) +#define DEF_FMSUB(name) DEFINE_FD_LIFTER_MAD(name, DECODE_FD_FD_FS_FS_FS, frs1, frs2, FNEG(frs3), false) +#define DEF_FNMADD(name) DEFINE_FD_LIFTER_MAD(name, DECODE_FD_FD_FS_FS_FS, frs1, frs2, frs3, true) +#define DEF_FNMSUB(name) DEFINE_FD_LIFTER_MAD(name, DECODE_FD_FD_FS_FS_FS, FNEG(frs1), frs2, frs3, false) + +// ----------------------------------------------------------------------- +// Sign Injection (bit-level, no rounding) +// +// fsgnj.s: fd = |rs1| with sign of rs2 +// fsgnjn.s: fd = |rs1| with negated sign of rs2 +// fsgnjx.s: fd = |rs1| with sign = sign(rs1) XOR sign(rs2) +// +// Bit 31 of float32 is the sign bit. +// IMPLEMENTATION NOTE: The result is simply the OR combination of +// (1) All bits but the sign from rs1 (i.e. AND with 0x7FFFFFFF....) +// (2) The sign-bit from rs2 (i.e.AND with 0x80000000....) +// ----------------------------------------------------------------------- +#define SIGN_MASK(size) UN(size, (1ULL << (size - 1))) +#define MAGNITUDE_MASK(size) UN(size, ~(1ULL << (size - 1))) +#define DEF_FSGNJ(name, size) DEFINE_FD_LIFTER_BV_TO_FREG(name, DECODE_FD_FD_BV_BV, \ + LOGOR( \ + LOGAND(bvrs1, MAGNITUDE_MASK(size)), \ + LOGAND(bvrs2, SIGN_MASK(size)) \ + )) + +#define DEF_FSGNJN(name, size) DEFINE_FD_LIFTER_BV_TO_FREG(name, DECODE_FD_FD_BV_BV, \ + LOGOR( \ + LOGAND(bvrs1, MAGNITUDE_MASK(size)), \ + LOGAND(LOGNOT(bvrs2), SIGN_MASK(size)) \ + )) + +// DUP bvrs1 to avoid shared AST nodes. +#define DEF_FSGNJX(name, size) DEFINE_FD_LIFTER_BV_TO_FREG(name, DECODE_FD_FD_BV_BV, \ + LOGOR( \ + LOGAND(DUP(bvrs1), MAGNITUDE_MASK(size)), \ + LOGAND(LOGXOR(bvrs1, bvrs2), SIGN_MASK(size)) \ + )) + + +// ----------------------------------------------------------------------- +// Min / Max +// ----------------------------------------------------------------------- +// IEEE 754-201x minimumNumber / maximumNumber (RISC-V F spec >= 2.2): +// - signaling NaN operand → raise NV, return canonical qNaN +// - exactly one quiet NaN → return the non-NaN operand +// - both quiet NaN → return canonical qNaN +// - otherwise → normal min / max +// ----------------------------------------------------------------------- +#define DEFINE_LIFTER_MINMAX(name, cond, sz) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t frd = insn->detail->riscv.operands[0].reg; \ + uint32_t frs1_reg = insn->detail->riscv.operands[1].reg; \ + uint32_t frs2_reg = insn->detail->riscv.operands[2].reg; \ + return SEQN(10, \ + /* raw 32-bit bitvector of frs1, needed for bit-level sNaN inspection */ \ + SETL("_bva", RISCV_FD_REG_GETTER_BV(frs1_reg)), \ + /* raw 32-bit bitvector of frs2, needed for bit-level sNaN inspection */ \ + SETL("_bvb", RISCV_FD_REG_GETTER_BV(frs2_reg)), \ + /* ordinary float interpetation for IL float comparisons */ \ + SETL("_a", FLOATV##sz(VARL("_bva"))), \ + /* ordinary float interpetation for IL float comparisons */ \ + SETL("_b", FLOATV##sz(VARL("_bvb"))), \ + /* true if operand 1 is any NaN (exponent==0xFF and mantissa!=0) */ \ + SETL("_na", RISCV_FD_IS_NAN(VARL("_bva"))), \ + /* true if operand 2 is any NaN */ \ + SETL("_nb", RISCV_FD_IS_NAN(VARL("_bvb"))), \ + /* true if operand 1 is a signaling NaN (NaN with quiet bit[22]==0) */ \ + SETL("_sa", RISCV_FD_IS_S_NAN(VARL("_bva"))), \ + /* true if operand 2 is a signaling NaN */ \ + SETL("_sb", RISCV_FD_IS_S_NAN(VARL("_bvb"))), \ + /* raise NV (invalid operation, bit 4) in fcsr when either operand is sNaN */ \ + SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_sa"), VARL("_sb")), UN(64, 0x10), UN(64, 0)))), \ + RISCV_FD_REG_SETTER(frd, \ + ITE(OR(VARL("_sa"), VARL("_sb")), IL_FQNAN(RZ_FLOAT_IEEE754_BIN_##sz), \ + ITE(VARL("_na"), VARL("_b"), \ + ITE(VARL("_nb"), VARL("_a"), \ + ITE(cond(VARL("_a"), VARL("_b")), VARL("_a"), VARL("_b"))))))); \ + } + +#define DEF_FMIN(name, size) DEFINE_LIFTER_MINMAX(name, FLE, size) +#define DEF_FMAX(name, size) DEFINE_LIFTER_MINMAX(name, FGE, size) + +// ----------------------------------------------------------------------- +// Comparison (result in integer register) +// +// flt.s / fle.s raise NV (bit 4 of fflags) when either operand is NaN. +// Float32 NaN: exponent[30:23] == 0xFF AND mantissa[22:0] != 0. +// ----------------------------------------------------------------------- +#define DEFINE_FCMP_LIFTER(name, cmp_fn, sz) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + uint32_t frs1_reg = insn->detail->riscv.operands[1].reg; \ + uint32_t frs2_reg = insn->detail->riscv.operands[2].reg; \ + return SEQN(8, \ + SETL("_bva", RISCV_FD_REG_GETTER_BV(frs1_reg)), \ + SETL("_bvb", RISCV_FD_REG_GETTER_BV(frs2_reg)), \ + SETL("_a", FLOATV##sz(VARL("_bva"))), \ + SETL("_b", FLOATV##sz(VARL("_bvb"))), \ + SETL("_na", RISCV_FD_IS_NAN(VARL("_bva"))), \ + SETL("_nb", RISCV_FD_IS_NAN(VARL("_bvb"))), \ + SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_na"), VARL("_nb")), UN(64, 0x10), UN(64, 0)))), \ + RISCV_SET_REG(rd, BOOL_TO_BV(cmp_fn(VARL("_a"), VARL("_b")), analysis->bits))); \ + } + +#define DEF_FLT(name, size) DEFINE_FCMP_LIFTER(name, FLT, size) +#define DEF_FLE(name, size) DEFINE_FCMP_LIFTER(name, FLE, size) + +// feq*: quiet NaN gives 0 result with no exception; signaling NaN gives 0 and raises NV. +#define DEF_FEQ(name, sz) \ + static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + REQUIRE_OP(2, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + uint32_t frs1_reg = insn->detail->riscv.operands[1].reg; \ + uint32_t frs2_reg = insn->detail->riscv.operands[2].reg; \ + return SEQN(8, \ + SETL("_bva", RISCV_FD_REG_GETTER_BV(frs1_reg)), \ + SETL("_bvb", RISCV_FD_REG_GETTER_BV(frs2_reg)), \ + SETL("_a", FLOATV##sz(VARL("_bva"))), \ + SETL("_b", FLOATV##sz(VARL("_bvb"))), \ + SETL("_sa", RISCV_FD_IS_S_NAN(VARL("_bva"))), \ + SETL("_sb", RISCV_FD_IS_S_NAN(VARL("_bvb"))), \ + SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_sa"), VARL("_sb")), UN(64, 0x10), UN(64, 0)))), \ + RISCV_SET_REG(rd, BOOL_TO_BV(FEQ(VARL("_a"), VARL("_b")), analysis->bits))); \ +} + +// ----------------------------------------------------------------------- +// fclass* +// +// Classifies the float32 value in fs1 into one of 10 categories, placing +// a one-hot 10-bit mask into rd (zero-extended to XLEN). +// +// bit 0 -infinity +// bit 1 negative normal +// bit 2 negative subnormal +// bit 3 -0 +// bit 4 +0 +// bit 5 positive subnormal +// bit 6 positive normal +// bit 7 +infinity +// bit 8 signaling NaN +// bit 9 quiet NaN +// ----------------------------------------------------------------------- +#define CLASSIFICATION_BIT(n, cond) SHIFTL0(BOOL_TO_BV(cond, xlen), UN(xlen, (n))) + +#define DEF_FCLASS(name) static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + DECODE_FD_RD_FS_BV(analysis, insn); \ + uint32_t xlen = analysis->bits; \ + return SEQN(13, \ + SETL("_b", bvrs1), \ + SETL("_ex", RISCV_FD_GET_EXPONENT(VARL("_b"))), \ + SETL("_mn", RISCV_FD_GET_MANTISSA(VARL("_b"))), \ + SETL("_sg", NON_ZERO(RISCV_FD_GET_SIGN(VARL("_b")))), \ + SETL("_xff", RISCV_FD_IS_MAX_EXP(VARL("_ex"))), \ + SETL("_xz", IS_ZERO(VARL("_ex"))), \ + SETL("_mz", IS_ZERO(VARL("_mn"))), \ + SETL("_na", AND(VARL("_xff"), INV(VARL("_mz")))), \ + SETL("_in", AND(VARL("_xff"), VARL("_mz"))), \ + SETL("_su", AND(VARL("_xz"), INV(VARL("_mz")))), \ + SETL("_ze", AND(VARL("_xz"), VARL("_mz"))), \ + SETL("_no", AND(INV(VARL("_xz")), INV(VARL("_xff")))), \ + RISCV_SET_REG(rd, \ + LOGOR(CLASSIFICATION_BIT(0, AND(VARL("_sg"), VARL("_in"))), \ + LOGOR(CLASSIFICATION_BIT(1, AND(VARL("_sg"), VARL("_no"))), \ + LOGOR(CLASSIFICATION_BIT(2, AND(VARL("_sg"), VARL("_su"))), \ + LOGOR(CLASSIFICATION_BIT(3, AND(VARL("_sg"), VARL("_ze"))), \ + LOGOR(CLASSIFICATION_BIT(4, AND(INV(VARL("_sg")), VARL("_ze"))), \ + LOGOR(CLASSIFICATION_BIT(5, AND(INV(VARL("_sg")), VARL("_su"))), \ + LOGOR(CLASSIFICATION_BIT(6, AND(INV(VARL("_sg")), VARL("_no"))), \ + LOGOR(CLASSIFICATION_BIT(7, AND(INV(VARL("_sg")), VARL("_in"))), \ + LOGOR(CLASSIFICATION_BIT(8, RISCV_FD_IS_S_NAN(VARL("_b"))), \ + CLASSIFICATION_BIT(9, AND(VARL("_na"), INV(RISCV_FD_IS_S_NAN(VARL("_b")))))))))))))))); \ +} + +// ----------------------------------------------------------------------- +// F Extension: Conversions float32 → integer +// +// NORE: in RV64 the 32-bit integer results of fcvt.w.s / fcvt.wu.s are +// sign-extended to 64 bits regardless of signedness (per spec §11.4). +// ----------------------------------------------------------------------- + +// fcvt.w* rd, fs1 — float32 → signed int32, sign-extended to XLEN +// NV: biased exponent >= BIG THRESHOLD +// 32-bit F: 158 (covers NaN, ±∞, and |value| >= 2^31). +// 64-bit F: 1054 (covers NaN, ±∞, and |value| >= 2^31). +// NX: source has a fractional part (detected via FROUND); mutually exclusive with NV. +// Saturation (RISC-V spec §11.4): +// NaN (any) or positive overflow → INT32_MAX (0x7FFFFFFF) +// -Inf or negative overflow → INT32_MIN (0x80000000) +#define DEF_FCVT_W(name, sz) static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + DECODE_FD_RD_FS_BV(analysis, insn); \ + return SEQN(8, \ + SETL("_bv", bvrs1), \ + SETL("_ex", RISCV_FD_GET_EXPONENT(VARL("_bv"))), \ + SETL("_mn", RISCV_FD_GET_MANTISSA(VARL("_bv"))), \ + SETL("_sg", NON_ZERO(RISCV_FD_GET_SIGN(VARL("_bv")))), \ + SETL("_f", FLOATV##sz(VARL("_bv"))), \ + SETL("_nv", RISCV_FD_IS_EXP_OVERFLOW_INT(VARL("_ex"))), \ + RISCV_SET_REG(rd, SIGNED(analysis->bits, \ + ITE(VARL("_nv"), \ + ITE(AND(VARL("_sg"), INV(AND(RISCV_FD_IS_MAX_EXP(VARL("_ex")), NON_ZERO(VARL("_mn"))))), \ + UN(32, 0x80000000), \ + UN(32, 0x7FFFFFFF)), \ + F2SINT(32, FD_ROUNDING_MODE, VARL("_f"))))), \ + SETG("fcsr", LOGOR(VARG("fcsr"), \ + LOGOR( \ + ITE(VARL("_nv"), UN(64, 0x10), UN(64, 0)), \ + ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND(FD_ROUNDING_MODE, VARL("_f")))), \ + UN(64, 0x01), UN(64, 0)))))); \ +} + +// fcvt.wu.s rd, fs1 — float32 → unsigned int32, sign-extended to XLEN +// NV: biased exponent >= 159 (|value| >= 2^32) OR negative non-zero value. +// NX: source has a fractional part AND not NV. The NV guard prevents double-flagging +// negative fractional values such as -0.5. +// Saturation (RISC-V spec §11.4): +// NaN (any) or positive overflow → UINT32_MAX (0xFFFFFFFF) +// negative non-zero (incl. −Inf) → 0x00000000 +#define DEF_FCVT_WU(name, sz) static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + DECODE_FD_RD_FS_BV(analysis, insn); \ + return SEQN(8, \ + SETL("_bv", bvrs1), \ + SETL("_ex", RISCV_FD_GET_EXPONENT(VARL("_bv"))), \ + SETL("_mn", RISCV_FD_GET_MANTISSA(VARL("_bv"))), \ + SETL("_sg", NON_ZERO(RISCV_FD_GET_SIGN(VARL("_bv")))), \ + SETL("_f", FLOATV##sz(VARL("_bv"))), \ + SETL("_nv", \ + OR(RISCV_FD_IS_EXP_OVERFLOW_UINT(VARL("_ex")), \ + AND(VARL("_sg"), OR(NON_ZERO(VARL("_ex")), NON_ZERO(VARL("_mn")))))), \ + RISCV_SET_REG(rd, SIGNED(analysis->bits, \ + ITE(VARL("_nv"), \ + ITE(OR(AND(RISCV_FD_IS_MAX_EXP(VARL("_ex")), NON_ZERO(VARL("_mn"))), INV(VARL("_sg"))), \ + UN(32, 0xFFFFFFFF), \ + UN(32, 0x00000000)), \ + F2INT(32, FD_ROUNDING_MODE, VARL("_f"))))), \ + SETG("fcsr", LOGOR(VARG("fcsr"), \ + LOGOR( \ + ITE(VARL("_nv"), UN(64, 0x10), UN(64, 0)), \ + ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND(FD_ROUNDING_MODE, VARL("_f")))), \ + UN(64, 0x01), UN(64, 0)))))); \ +} + +// fcvt.l.s rd, fs1 — float32 → signed int64 (RV64F only) +// NV: biased exponent >= 190 (= 127+63; covers NaN, ±∞, and |value| >= 2^63). +// NX: source has a fractional part (detected via FROUND); mutually exclusive with NV +// since E >= 190 > 149 (no fractional bits in the float representation at that range). +// Saturation (RISC-V spec §11.4): +// NaN (any) or positive overflow → INT64_MAX (0x7FFFFFFFFFFFFFFF) +// -Inf or negative overflow → INT64_MIN (0x8000000000000000) +#define DEF_FCVT_L(name, sz) static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + REQUIRE_64_BIT(analysis); \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + uint32_t fsrc = insn->detail->riscv.operands[1].reg; \ + return SEQN(8, \ + SETL("_bv", RISCV_FD_REG_GETTER_BV(fsrc)), \ + SETL("_ex", RISCV_FD_GET_EXPONENT(VARL("_bv"))), \ + SETL("_mn", RISCV_FD_GET_MANTISSA(VARL("_bv"))), \ + SETL("_sg", NON_ZERO(RISCV_FD_GET_SIGN(VARL("_bv")))), \ + SETL("_f", FLOATV##sz(VARL("_bv"))), \ + SETL("_nv", RISCV_FD_IS_EXP_OVERFLOW_LONG(VARL("_ex"))), \ + RISCV_SET_REG(rd, \ + ITE(VARL("_nv"), \ + ITE(AND(VARL("_sg"), INV(AND(RISCV_FD_IS_MAX_EXP(VARL("_ex")), NON_ZERO(VARL("_mn"))))), \ + UN(64, 0x8000000000000000ULL), \ + UN(64, 0x7FFFFFFFFFFFFFFFULL)), \ + F2SINT(64, FD_ROUNDING_MODE, VARL("_f")))), \ + SETG("fcsr", LOGOR(VARG("fcsr"), \ + LOGOR( \ + ITE(VARL("_nv"), UN(64, 0x10), UN(64, 0)), \ + ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND(FD_ROUNDING_MODE, VARL("_f")))), \ + UN(64, 0x01), UN(64, 0)))))); \ +} + +// fcvt.lu.s rd, fs1 — float32 → unsigned int64 (RV64F only) +// NV: biased exponent >= 191 (= 127+64) OR negative non-zero value. +// NX: source has a fractional part AND not NV (guard prevents double-flagging +// negative fractional values such as -0.5). +// Saturation (RISC-V spec §11.4): +// NaN (any) or positive overflow → UINT64_MAX (0xFFFFFFFFFFFFFFFF) +// negative non-zero (incl. −Inf) → 0x0000000000000000 +#define DEF_FCVT_LU(name, sz) static RzILOpEffect *rz_riscv_lift_##name(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, \ + RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { \ + REQUIRE_64_BIT(analysis); \ + REQUIRE_OP(0, RISCV_OP_REG); \ + REQUIRE_OP(1, RISCV_OP_REG); \ + uint32_t rd = insn->detail->riscv.operands[0].reg; \ + uint32_t fsrc = insn->detail->riscv.operands[1].reg; \ + return SEQN(8, \ + SETL("_bv", RISCV_FD_REG_GETTER_BV(fsrc)), \ + SETL("_ex", RISCV_FD_GET_EXPONENT(VARL("_bv"))), \ + SETL("_mn", RISCV_FD_GET_MANTISSA(VARL("_bv"))), \ + SETL("_sg", NON_ZERO(RISCV_FD_GET_SIGN(VARL("_bv")))), \ + SETL("_f", FLOATV##sz(VARL("_bv"))), \ + SETL("_nv", \ + OR(RISCV_FD_IS_EXP_OVERFLOW_ULONG(VARL("_ex")), \ + AND(VARL("_sg"), OR(NON_ZERO(VARL("_ex")), NON_ZERO(VARL("_mn")))))), \ + RISCV_SET_REG(rd, \ + ITE(VARL("_nv"), \ + ITE(OR(AND(RISCV_FD_IS_MAX_EXP(VARL("_ex")), NON_ZERO(VARL("_mn"))), INV(VARL("_sg"))), \ + UN(64, 0xFFFFFFFFFFFFFFFFULL), \ + UN(64, 0x0000000000000000ULL)), \ + F2INT(64, FD_ROUNDING_MODE, VARL("_f")))), \ + SETG("fcsr", LOGOR(VARG("fcsr"), \ + LOGOR( \ + ITE(VARL("_nv"), UN(64, 0x10), UN(64, 0)), \ + ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND(FD_ROUNDING_MODE, VARL("_f")))), \ + UN(64, 0x01), UN(64, 0)))))); \ +} + +#include + +#endif // RISCV_IL_FD_COMMON_H \ No newline at end of file diff --git a/librz/arch/isa/riscv/riscv_il_float_reg_names.h b/librz/arch/isa/riscv/riscv_il_float_reg_names.h index 2a3d5b485ee..9b723d0a11d 100644 --- a/librz/arch/isa/riscv/riscv_il_float_reg_names.h +++ b/librz/arch/isa/riscv/riscv_il_float_reg_names.h @@ -49,7 +49,10 @@ static inline const char *riscv_freg_name(uint32_t reg) { if (reg >= RISCV_REG_F0_D && reg <= RISCV_REG_F31_D) { return riscv_freg_names[reg - RISCV_REG_F0_D]; } - return riscv_freg_names[reg - RISCV_REG_F0_F]; + if (reg >= RISCV_REG_F0_F && reg <= RISCV_REG_F31_F) { + return riscv_freg_names[reg - RISCV_REG_F0_F]; + } + return ""; } #endif // RISCV_IL_FLOAT_REG_NAMES_H From fedf48a9b5a64b3341c4f76f335acde40ddbab95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D9=85=D8=B5=D8=B7=D9=81=D9=8A=20=D9=85=D8=AD=D9=85=D9=88?= =?UTF-8?q?=D8=AF=20=D9=83=D9=85=D8=A7=D9=84=20=D8=A7=D9=84=D8=AF=D9=8A?= =?UTF-8?q?=D9=86?= <48567303+moste00@users.noreply.github.com> Date: Sun, 14 Jun 2026 01:41:34 +0300 Subject: [PATCH 9/9] fix more bugs in the lifters --- librz/arch/isa/riscv/riscv_il_a.h | 8 --- librz/arch/isa/riscv/riscv_il_d.h | 7 ++- librz/arch/isa/riscv/riscv_il_f.h | 20 +++---- librz/arch/isa/riscv/riscv_il_fd_common.h | 69 +++++++++++++++-------- librz/arch/isa/riscv/riscv_il_priv.h | 14 ++--- 5 files changed, 64 insertions(+), 54 deletions(-) diff --git a/librz/arch/isa/riscv/riscv_il_a.h b/librz/arch/isa/riscv/riscv_il_a.h index 38ccde5336a..692ad2781a2 100644 --- a/librz/arch/isa/riscv/riscv_il_a.h +++ b/librz/arch/isa/riscv/riscv_il_a.h @@ -97,11 +97,7 @@ DEFINE_ALIAS_LIFTER(sc_d_aqrl, sc_d) SETL("_v32", LOADW(32, VARL("_a"))), \ SETL("_r32", CAST(32, IL_FALSE, (rs2))), \ STOREW(VARL("_a"), (new32)), \ -<<<<<<< HEAD riscv_il_set_reg((rd), SIGNED(analysis->bits, VARL("_v32")))) -======= - RISCV_SET_REG((rd), SIGNED(analysis->bits, VARL("_v32")))) ->>>>>>> 9323674ce4 (implement the atomic extension trivially by ignoring concurrency guards) // AMO .d helper: atomically read-modify-write 64-bit memory, return old value in rd. // new64 may reference VARL("_v") (old 64-bit mem val) and VARL("_r") (rs2). @@ -111,11 +107,7 @@ DEFINE_ALIAS_LIFTER(sc_d_aqrl, sc_d) SETL("_v", LOADW(64, VARL("_a"))), \ SETL("_r", (rs2)), \ STOREW(VARL("_a"), (new64)), \ -<<<<<<< HEAD riscv_il_set_reg((rd), VARL("_v"))) -======= - RISCV_SET_REG((rd), VARL("_v"))) ->>>>>>> 9323674ce4 (implement the atomic extension trivially by ignoring concurrency guards) // AMO swap: mem = rs2, rd = old_mem DEFINE_LIFTER_WITH_EFFECT(amoswap_w, DECODE_RD_MEM_RS, AMO_W(rd, addr, rs2, VARL("_r32"))) diff --git a/librz/arch/isa/riscv/riscv_il_d.h b/librz/arch/isa/riscv/riscv_il_d.h index c93624f1aa6..911b6447557 100644 --- a/librz/arch/isa/riscv/riscv_il_d.h +++ b/librz/arch/isa/riscv/riscv_il_d.h @@ -5,7 +5,6 @@ #define RISCV_IL_D_H #include "riscv_il_base.h" -#include "riscv_il_f.h" // ----------------------------------------------------------------------- // D extension: register access (RISCV_REG_F0_D = 74, _D suffix) @@ -38,6 +37,7 @@ #define RISCV_FD_GET_SIGN(bv) EXTRACT64(bv, UN(64, 63), UN(32, 1)) #define RISCV_FD_IS_NAN(bv) AND(EQ(RISCV_FD_GET_EXPONENT(bv), UN(64, 0x7FF)), NON_ZERO(RISCV_FD_GET_MANTISSA(bv))) #define RISCV_FD_IS_S_NAN(bv) AND(RISCV_FD_IS_NAN(bv), EQ(EXTRACT64(bv, UN(64, 51), UN(32, 1)), UN(64, 0))) +#define RISCV_FD_CANONICAL_QNAN() UN(64, 0x7FF8000000000000) #define RISCV_FD_IS_MAX_EXP(bv) EQ(bv, UN(64, 0x7FF)) #define RISCV_FD_IS_EXP_OVERFLOW_INT(bv) UGE(bv, UN(64, 1054)) #define RISCV_FD_IS_EXP_OVERFLOW_UINT(bv) UGE(bv, UN(64, 1055)) @@ -45,6 +45,7 @@ #define RISCV_FD_IS_EXP_OVERFLOW_ULONG(bv) UGE(bv, UN(64, 1087)) #include +#include "riscv_il_fd_common.h" // ----------------------------------------------------------------------- // Memory @@ -126,7 +127,7 @@ DEF_FCVT_LU(fcvt_lu_d, 64) REQUIRE_OP(0, RISCV_OP_REG); \ REQUIRE_OP(1, RISCV_OP_REG); \ uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); + RzILOpBitVector *rs1 = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].reg); // rd=IntReg[0], bvrs1=raw64(DReg[1]) (fmv.x.d) #define DECODE_D_RD_FS_BV(analysis, insn) \ @@ -216,7 +217,7 @@ static RzILOpEffect *rz_riscv_lift_fmv_x_d(RZ_BORROW RZ_NONNULL RzAnalysis *anal RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { REQUIRE_64_BIT(analysis); DECODE_D_RD_FS_BV(analysis, insn); - return RISCV_SET_REG(rd, bvrs1); + return riscv_il_set_reg(rd, bvrs1); } // fmv.d.x fd, rs1 — copy integer register bits to float64 register (RV64D) diff --git a/librz/arch/isa/riscv/riscv_il_f.h b/librz/arch/isa/riscv/riscv_il_f.h index b025c5cdbb5..8c389a5c701 100644 --- a/librz/arch/isa/riscv/riscv_il_f.h +++ b/librz/arch/isa/riscv/riscv_il_f.h @@ -26,6 +26,7 @@ // NAN API #define RISCV_FD_IS_NAN(bv) AND(EQ(RISCV_FD_GET_EXPONENT(bv), UN(32, 0xFF)), NON_ZERO(RISCV_FD_GET_MANTISSA(bv))) #define RISCV_FD_IS_S_NAN(bv) AND(RISCV_FD_IS_NAN(bv), EQ(EXTRACT32(bv, UN(32, 22), UN(32, 1)), UN(32, 0))) +#define RISCV_FD_CANONICAL_QNAN() UN(32, 0x7FC00000) // Exponent API #define RISCV_FD_IS_MAX_EXP(bv) EQ(bv, UN(32, 0xFF)) #define RISCV_FD_IS_EXP_OVERFLOW_INT(bv) UGE(bv, UN(32, 158)) @@ -38,15 +39,12 @@ // ----------------------------------------------------------------------- #define F_RM riscv_rm_to_rz(insn->detail->riscv.rounding_mode) -#define RISCV_SET_FREG_F(reg, fl) RISCV_FD_REG_SETTER(reg, fl) -#define RISCV_ACCUMULATE_FFLAGS() RISCV_FD_UPDATE_FFLAGS() - // frd=FReg[0], rs1=IntReg[1] (fcvt.s.w, fcvt.s.wu, fcvt.s.l, fcvt.s.lu, fmv.w.x) #define DECODE_F_FD_RS(analysis, insn) \ REQUIRE_OP(0, RISCV_OP_REG); \ REQUIRE_OP(1, RISCV_OP_REG); \ uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs1 = RISCV_GET_REG(insn->detail->riscv.operands[1].reg); + RzILOpBitVector *rs1 = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].reg); // rd=IntReg[0], bvrs1=raw32(FReg[1]) (fmv.x.w) #define DECODE_F_RD_FS_BV(analysis, insn) DECODE_FD_RD_FS_BV(analysis, insn) @@ -146,15 +144,15 @@ DEFINE_F_LIFTER(fcvt_s_wu, DECODE_F_FD_RS, // fcvt.s.l fd, rs1 — signed int64 to float32 (RV64F only) // NX is raised when the integer cannot be represented exactly in float32 (more than -// 24 significant bits). Saving to _r lets RISCV_ACCUMULATE_FFLAGS query the result. +// 24 significant bits). Saving to _r lets RISCV_FD_UPDATE_FFLAGS query the result. static RzILOpEffect *rz_riscv_lift_fcvt_s_l(RZ_BORROW RZ_NONNULL RzAnalysis *analysis, RZ_NONNULL RzAnalysisOp *op, RZ_NONNULL cs_insn *insn, ut64 current_addr, size_t size) { REQUIRE_64_BIT(analysis); DECODE_F_FD_RS(analysis, insn); return SEQ3( SETL("_r", SINT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, rs1)), - RISCV_SET_FREG_F(frd, VARL("_r")), - RISCV_ACCUMULATE_FFLAGS()); + RISCV_FD_REG_SETTER(frd, VARL("_r")), + RISCV_FD_UPDATE_FFLAGS()); } // fcvt.s.lu fd, rs1 — unsigned int64 to float32 (RV64F only) @@ -164,8 +162,8 @@ static RzILOpEffect *rz_riscv_lift_fcvt_s_lu(RZ_BORROW RZ_NONNULL RzAnalysis *an DECODE_F_FD_RS(analysis, insn); return SEQ3( SETL("_r", INT2F(RZ_FLOAT_IEEE754_BIN_32, F_RM, rs1)), - RISCV_SET_FREG_F(frd, VARL("_r")), - RISCV_ACCUMULATE_FFLAGS()); + RISCV_FD_REG_SETTER(frd, VARL("_r")), + RISCV_FD_UPDATE_FFLAGS()); } // ----------------------------------------------------------------------- @@ -191,14 +189,14 @@ DEFINE_F_LIFTER_BV_TO_FREG(fmv_w_x, DECODE_F_FD_RS, #undef RISCV_FD_GET_SIGN #undef RISCV_FD_IS_NAN #undef RISCV_FD_IS_S_NAN +#undef RISCV_FD_CANONICAL_QNAN #undef RISCV_FD_IS_MAX_EXP #undef RISCV_FD_IS_EXP_OVERFLOW_INT #undef RISCV_FD_IS_EXP_OVERFLOW_UINT #undef RISCV_FD_IS_EXP_OVERFLOW_LONG #undef RISCV_FD_IS_EXP_OVERFLOW_ULONG #undef F_RM -#undef RISCV_SET_FREG_F -#undef RISCV_ACCUMULATE_FFLAGS +#undef RISCV_FD_REG_SETTER #undef DECODE_F_FD_RS #undef DECODE_F_RD_FS_BV #undef DEFINE_F_LIFTER diff --git a/librz/arch/isa/riscv/riscv_il_fd_common.h b/librz/arch/isa/riscv/riscv_il_fd_common.h index 1ba6406ef07..d083bbdda83 100644 --- a/librz/arch/isa/riscv/riscv_il_fd_common.h +++ b/librz/arch/isa/riscv/riscv_il_fd_common.h @@ -9,11 +9,15 @@ * - RISCV_FD_REG_GETTER: get a floating-point register. * - RISCV_FD_REG_SETTER_BV: set a floating-point register to a raw bitvector. * - RISCV_FD_REG_GETTER_BV: get a floating-point register as a raw bitvector. + * - RISCV_FD_GET_MANTISSA: get the mantissa of a floating-point number. * - RISCV_FD_GET_EXPONENT: get the exponent of a floating-point number. * - RISCV_FD_GET_SIGN: get the sign bit of a floating-point number. + * - RISCV_FD_IS_NAN: check if a floating-point number is NaN. * - RISCV_FD_IS_S_NAN: check if a floating-point number is a signaling NaN. + * - RISCV_FD_CANONICAL_QNAN: get a canonical quiet NaN. + * - RISCV_FD_IS_MAX_EXP: check if a floating-point number has the maximum exponent. * - RISCV_FD_IS_EXP_OVERFLOW_INT: check if a floating-point number has an exponent that would overflow an integer. * - RISCV_FD_IS_EXP_OVERFLOW_UINT: check if a floating-point number has an exponent that would overflow an unsigned integer. @@ -64,7 +68,7 @@ #error "RISCV_FD_GET_SIGN must be defined before including this file" #endif // RISCV_FD_GET_SIGN -// -------------------------------------- NAN Query API -------------------------------------- +// -------------------------------------- NAN API -------------------------------------- #ifndef RISCV_FD_IS_NAN #error "RISCV_FD_IS_NAN must be defined before including this file" #endif // RISCV_FD_IS_NAN @@ -73,7 +77,11 @@ #error "RISCV_FD_IS_S_NAN must be defined before including this file" #endif // RISCV_FD_IS_S_NAN -// -------------------------------------- Exponent Query API -------------------------------------- +#ifndef RISCV_FD_CANONICAL_QNAN +#error "RISCV_FD_CANONICAL_QNAN must be defined before including this file" +#endif // RISCV_FD_CANONICAL_QNAN + +// -------------------------------------- Exponent API -------------------------------------- #ifndef RISCV_FD_IS_MAX_EXP #error "RISCV_FD_IS_MAX_EXP must be defined before including this file" #endif // RISCV_FD_IS_MAX_EXP @@ -133,7 +141,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { // When an instruction encodes rm=111 (DYN), the actual rounding mode is // read at runtime from fcsr.frm (bits [7:5]). Because RzIL float ops // take a compile-time RzFloatRMode enum, we enumerate all five valid frm -// values in an ITE tree so the right mode is chosen at emulation time. +// values in an ITE decision tree so the right mode is chosen at emulation time. #define RISCV_FD_FRM_DISPATCH(fn, ...) \ ITE(EQ(VARL("_frm"), UN(64, 0)), fn(RZ_FLOAT_RMODE_RNE, __VA_ARGS__), \ ITE(EQ(VARL("_frm"), UN(64, 1)), fn(RZ_FLOAT_RMODE_RTZ, __VA_ARGS__), \ @@ -258,14 +266,14 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { REQUIRE_OP(0, RISCV_OP_REG); \ REQUIRE_OP(1, RISCV_OP_MEM); \ uint32_t frd = insn->detail->riscv.operands[0].reg; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *rs = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].mem.base); \ RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); #define DECODE_FD_FS_MEM(analysis, insn) \ REQUIRE_OP(0, RISCV_OP_REG); \ REQUIRE_OP(1, RISCV_OP_MEM); \ RzILOpBitVector *bvrs1 = RISCV_FD_REG_GETTER_BV(insn->detail->riscv.operands[0].reg); \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[1].mem.base); \ + RzILOpBitVector *rs = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[1].mem.base); \ RzILOpBitVector *imm = SN(analysis->bits, insn->detail->riscv.operands[1].mem.disp); #define DECODE_FD_FD_FS_FS_FS(analysis, insn) \ @@ -371,20 +379,31 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { /* ordinary float interpetation for IL float comparisons */ \ SETL("_b", FLOATV##sz(VARL("_bvb"))), \ /* true if operand 1 is any NaN (exponent==0xFF and mantissa!=0) */ \ - SETL("_na", RISCV_FD_IS_NAN(VARL("_bva"))), \ + SETL("_a_is_nan", RISCV_FD_IS_NAN(VARL("_bva"))), \ /* true if operand 2 is any NaN */ \ - SETL("_nb", RISCV_FD_IS_NAN(VARL("_bvb"))), \ + SETL("_b_is_nan", RISCV_FD_IS_NAN(VARL("_bvb"))), \ /* true if operand 1 is a signaling NaN (NaN with quiet bit[22]==0) */ \ - SETL("_sa", RISCV_FD_IS_S_NAN(VARL("_bva"))), \ + SETL("_a_is_snan", RISCV_FD_IS_S_NAN(VARL("_bva"))), \ /* true if operand 2 is a signaling NaN */ \ - SETL("_sb", RISCV_FD_IS_S_NAN(VARL("_bvb"))), \ + SETL("_b_is_snan", RISCV_FD_IS_S_NAN(VARL("_bvb"))), \ /* raise NV (invalid operation, bit 4) in fcsr when either operand is sNaN */ \ - SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_sa"), VARL("_sb")), UN(64, 0x10), UN(64, 0)))), \ + SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_a_is_snan"), VARL("_b_is_snan")), UN(64, 0x10), UN(64, 0)))), \ RISCV_FD_REG_SETTER(frd, \ - ITE(OR(VARL("_sa"), VARL("_sb")), IL_FQNAN(RZ_FLOAT_IEEE754_BIN_##sz), \ - ITE(VARL("_na"), VARL("_b"), \ - ITE(VARL("_nb"), VARL("_a"), \ - ITE(cond(VARL("_a"), VARL("_b")), VARL("_a"), VARL("_b"))))))); \ + /* are both non-NAN and a op b? (op is >= or <=) */ \ + ITE(cond(VARL("_a"), VARL("_b")), \ + VARL("_a"), /* return a */ \ + /* otherwise, check for NAN */ \ + ITE(VARL("_a_is_nan"), \ + ITE(VARL("_b_is_nan"), \ + FLOATV##sz(RISCV_FD_CANONICAL_QNAN()), \ + /* a is NaN, b is not */ \ + VARL("_b")), \ + /* a is not NaN, what about b ? */ \ + ITE(VARL("_b_is_nan"), \ + /* a is not NaN, b is NaN */ \ + VARL("_a"), \ + /* both non-NAN and b op a */ \ + VARL("_b")))))); \ } #define DEF_FMIN(name, size) DEFINE_LIFTER_MINMAX(name, FLE, size) @@ -413,7 +432,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETL("_na", RISCV_FD_IS_NAN(VARL("_bva"))), \ SETL("_nb", RISCV_FD_IS_NAN(VARL("_bvb"))), \ SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_na"), VARL("_nb")), UN(64, 0x10), UN(64, 0)))), \ - RISCV_SET_REG(rd, BOOL_TO_BV(cmp_fn(VARL("_a"), VARL("_b")), analysis->bits))); \ + riscv_il_set_reg(rd, BOOL_TO_BV(cmp_fn(VARL("_a"), VARL("_b")), analysis->bits))); \ } #define DEF_FLT(name, size) DEFINE_FCMP_LIFTER(name, FLT, size) @@ -437,7 +456,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETL("_sa", RISCV_FD_IS_S_NAN(VARL("_bva"))), \ SETL("_sb", RISCV_FD_IS_S_NAN(VARL("_bvb"))), \ SETG("fcsr", LOGOR(VARG("fcsr"), ITE(OR(VARL("_sa"), VARL("_sb")), UN(64, 0x10), UN(64, 0)))), \ - RISCV_SET_REG(rd, BOOL_TO_BV(FEQ(VARL("_a"), VARL("_b")), analysis->bits))); \ + riscv_il_set_reg(rd, BOOL_TO_BV(FEQ(VARL("_a"), VARL("_b")), analysis->bits))); \ } // ----------------------------------------------------------------------- @@ -476,7 +495,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETL("_su", AND(VARL("_xz"), INV(VARL("_mz")))), \ SETL("_ze", AND(VARL("_xz"), VARL("_mz"))), \ SETL("_no", AND(INV(VARL("_xz")), INV(VARL("_xff")))), \ - RISCV_SET_REG(rd, \ + riscv_il_set_reg(rd, \ LOGOR(CLASSIFICATION_BIT(0, AND(VARL("_sg"), VARL("_in"))), \ LOGOR(CLASSIFICATION_BIT(1, AND(VARL("_sg"), VARL("_no"))), \ LOGOR(CLASSIFICATION_BIT(2, AND(VARL("_sg"), VARL("_su"))), \ @@ -514,7 +533,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETL("_sg", NON_ZERO(RISCV_FD_GET_SIGN(VARL("_bv")))), \ SETL("_f", FLOATV##sz(VARL("_bv"))), \ SETL("_nv", RISCV_FD_IS_EXP_OVERFLOW_INT(VARL("_ex"))), \ - RISCV_SET_REG(rd, SIGNED(analysis->bits, \ + riscv_il_set_reg(rd, SIGNED(analysis->bits, \ ITE(VARL("_nv"), \ ITE(AND(VARL("_sg"), INV(AND(RISCV_FD_IS_MAX_EXP(VARL("_ex")), NON_ZERO(VARL("_mn"))))), \ UN(32, 0x80000000), \ @@ -523,7 +542,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETG("fcsr", LOGOR(VARG("fcsr"), \ LOGOR( \ ITE(VARL("_nv"), UN(64, 0x10), UN(64, 0)), \ - ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND(FD_ROUNDING_MODE, VARL("_f")))), \ + ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND_EXC(FD_ROUNDING_MODE, VARL("_f")))), \ UN(64, 0x01), UN(64, 0)))))); \ } @@ -546,7 +565,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETL("_nv", \ OR(RISCV_FD_IS_EXP_OVERFLOW_UINT(VARL("_ex")), \ AND(VARL("_sg"), OR(NON_ZERO(VARL("_ex")), NON_ZERO(VARL("_mn")))))), \ - RISCV_SET_REG(rd, SIGNED(analysis->bits, \ + riscv_il_set_reg(rd, SIGNED(analysis->bits, \ ITE(VARL("_nv"), \ ITE(OR(AND(RISCV_FD_IS_MAX_EXP(VARL("_ex")), NON_ZERO(VARL("_mn"))), INV(VARL("_sg"))), \ UN(32, 0xFFFFFFFF), \ @@ -555,7 +574,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETG("fcsr", LOGOR(VARG("fcsr"), \ LOGOR( \ ITE(VARL("_nv"), UN(64, 0x10), UN(64, 0)), \ - ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND(FD_ROUNDING_MODE, VARL("_f")))), \ + ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND_EXC(FD_ROUNDING_MODE, VARL("_f")))), \ UN(64, 0x01), UN(64, 0)))))); \ } @@ -580,7 +599,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETL("_sg", NON_ZERO(RISCV_FD_GET_SIGN(VARL("_bv")))), \ SETL("_f", FLOATV##sz(VARL("_bv"))), \ SETL("_nv", RISCV_FD_IS_EXP_OVERFLOW_LONG(VARL("_ex"))), \ - RISCV_SET_REG(rd, \ + riscv_il_set_reg(rd, \ ITE(VARL("_nv"), \ ITE(AND(VARL("_sg"), INV(AND(RISCV_FD_IS_MAX_EXP(VARL("_ex")), NON_ZERO(VARL("_mn"))))), \ UN(64, 0x8000000000000000ULL), \ @@ -589,7 +608,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETG("fcsr", LOGOR(VARG("fcsr"), \ LOGOR( \ ITE(VARL("_nv"), UN(64, 0x10), UN(64, 0)), \ - ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND(FD_ROUNDING_MODE, VARL("_f")))), \ + ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND_EXC(FD_ROUNDING_MODE, VARL("_f")))), \ UN(64, 0x01), UN(64, 0)))))); \ } @@ -616,7 +635,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETL("_nv", \ OR(RISCV_FD_IS_EXP_OVERFLOW_ULONG(VARL("_ex")), \ AND(VARL("_sg"), OR(NON_ZERO(VARL("_ex")), NON_ZERO(VARL("_mn")))))), \ - RISCV_SET_REG(rd, \ + riscv_il_set_reg(rd, \ ITE(VARL("_nv"), \ ITE(OR(AND(RISCV_FD_IS_MAX_EXP(VARL("_ex")), NON_ZERO(VARL("_mn"))), INV(VARL("_sg"))), \ UN(64, 0xFFFFFFFFFFFFFFFFULL), \ @@ -625,7 +644,7 @@ static inline RzFloatRMode riscv_rm_to_rz(riscv_rounding_mode rm) { SETG("fcsr", LOGOR(VARG("fcsr"), \ LOGOR( \ ITE(VARL("_nv"), UN(64, 0x10), UN(64, 0)), \ - ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND(FD_ROUNDING_MODE, VARL("_f")))), \ + ITE(AND(INV(VARL("_nv")), FEXCEPT(RZ_FLOAT_E_INEXACT, FROUND_EXC(FD_ROUNDING_MODE, VARL("_f")))), \ UN(64, 0x01), UN(64, 0)))))); \ } diff --git a/librz/arch/isa/riscv/riscv_il_priv.h b/librz/arch/isa/riscv/riscv_il_priv.h index b8eac96d1d7..a23772c2a89 100644 --- a/librz/arch/isa/riscv/riscv_il_priv.h +++ b/librz/arch/isa/riscv/riscv_il_priv.h @@ -77,7 +77,7 @@ static RzILOpEffect *riscv_csr_write(uint16_t csr, RzILOpBitVector *val, int xle REQUIRE_OP(2, RISCV_OP_REG); \ uint32_t rd = insn->detail->riscv.operands[0].reg; \ uint16_t csr = insn->detail->riscv.operands[1].csr; \ - RzILOpBitVector *rs = RISCV_GET_REG(insn->detail->riscv.operands[2].reg); + RzILOpBitVector *rs = riscv_il_get_reg(analysis->bits, insn->detail->riscv.operands[2].reg); // rd=IntReg[0], csr=CSR[1], uimm=5-bit unsigned IMM[2] (csrrwi, csrrsi, csrrci) #define DECODE_CSR_RD_CSR_IMM(analysis, insn) \ @@ -99,7 +99,7 @@ static RzILOpEffect *rz_riscv_lift_csrrw(RZ_BORROW RZ_NONNULL RzAnalysis *analys return SEQ3( SETL("_old", riscv_csr_read(csr, analysis->bits)), riscv_csr_write(csr, rs, analysis->bits), - RISCV_SET_REG(rd, VARL("_old"))); + riscv_il_set_reg(rd, VARL("_old"))); } // ----------------------------------------------------------------------- @@ -113,7 +113,7 @@ static RzILOpEffect *rz_riscv_lift_csrrs(RZ_BORROW RZ_NONNULL RzAnalysis *analys return SEQ3( SETL("_old", riscv_csr_read(csr, analysis->bits)), riscv_csr_write(csr, LOGOR(VARL("_old"), rs), analysis->bits), - RISCV_SET_REG(rd, VARL("_old"))); + riscv_il_set_reg(rd, VARL("_old"))); } // ----------------------------------------------------------------------- @@ -127,7 +127,7 @@ static RzILOpEffect *rz_riscv_lift_csrrc(RZ_BORROW RZ_NONNULL RzAnalysis *analys return SEQ3( SETL("_old", riscv_csr_read(csr, analysis->bits)), riscv_csr_write(csr, LOGAND(VARL("_old"), LOGNOT(rs)), analysis->bits), - RISCV_SET_REG(rd, VARL("_old"))); + riscv_il_set_reg(rd, VARL("_old"))); } // ----------------------------------------------------------------------- @@ -141,7 +141,7 @@ static RzILOpEffect *rz_riscv_lift_csrrwi(RZ_BORROW RZ_NONNULL RzAnalysis *analy return SEQ3( SETL("_old", riscv_csr_read(csr, analysis->bits)), riscv_csr_write(csr, uimm, analysis->bits), - RISCV_SET_REG(rd, VARL("_old"))); + riscv_il_set_reg(rd, VARL("_old"))); } // ----------------------------------------------------------------------- @@ -155,7 +155,7 @@ static RzILOpEffect *rz_riscv_lift_csrrsi(RZ_BORROW RZ_NONNULL RzAnalysis *analy return SEQ3( SETL("_old", riscv_csr_read(csr, analysis->bits)), riscv_csr_write(csr, LOGOR(VARL("_old"), uimm), analysis->bits), - RISCV_SET_REG(rd, VARL("_old"))); + riscv_il_set_reg(rd, VARL("_old"))); } // ----------------------------------------------------------------------- @@ -169,7 +169,7 @@ static RzILOpEffect *rz_riscv_lift_csrrci(RZ_BORROW RZ_NONNULL RzAnalysis *analy return SEQ3( SETL("_old", riscv_csr_read(csr, analysis->bits)), riscv_csr_write(csr, LOGAND(VARL("_old"), LOGNOT(uimm)), analysis->bits), - RISCV_SET_REG(rd, VARL("_old"))); + riscv_il_set_reg(rd, VARL("_old"))); } #undef DECODE_CSR_RD_CSR_RS