Affix

 view release on metacpan or  search on metacpan

infix/src/arch/riscv/abi_riscv64_emitters.c  view on Meta::CPAN

 * it to a `code_buffer`. The emitters are intentionally low-level: they do not
 * know about the FFI marshalling logic and instead serve as the instruction-level
 * building blocks for `abi_riscv64.c`.
 *
 * The encoding helpers (`rv_enc_*`) implement the base RISC-V instruction
 * formats (R, I, S, B, U, J) as described in "The RISC-V Instruction Set
 * Manual, Volume I".
 * @endinternal
 */
#include "arch/riscv/abi_riscv64_emitters.h"
#include "arch/riscv/abi_riscv64_common.h"
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

// Instruction encoding helpers (RISC-V base formats)
/** @internal Mask a value to the signed 12-bit range `[-2048, 2047]`. */
static inline uint32_t rv_sx_imm12(int32_t imm) { return (uint32_t)(imm & 0xFFF); }
/** @internal Mask a value to the unsigned 20-bit range `[0, 0xFFFFF]`. */
static inline uint32_t rv_imm20(uint32_t imm) { return imm & 0xFFFFF; }

/** @internal R-type: `funct7 rs2 rs1 funct3 rd opcode`. */
static inline uint32_t rv_enc_r(
    uint32_t funct7, uint8_t rs2, uint8_t rs1, uint32_t funct3, uint8_t rd, uint32_t opcode) {
    return (funct7 << 25) | ((uint32_t)rs2 << RV_RS2_SHIFT) | ((uint32_t)rs1 << RV_RS1_SHIFT) |
        (funct3 << RV_FUNCT3_SHIFT) | ((uint32_t)rd << RV_RD_SHIFT) | opcode;
}
/** @internal I-type: `imm12 rs1 funct3 rd opcode`. */
static inline uint32_t rv_enc_i(uint32_t imm12, uint8_t rs1, uint32_t funct3, uint8_t rd, uint32_t opcode) {
    return (imm12 << 20) | ((uint32_t)rs1 << RV_RS1_SHIFT) | (funct3 << RV_FUNCT3_SHIFT) |
        ((uint32_t)rd << RV_RD_SHIFT) | opcode;
}
/** @internal S-type: `imm[11:5] rs2 rs1 funct3 imm[4:0] opcode`. */
static inline uint32_t rv_enc_s(uint32_t imm12, uint8_t rs2, uint8_t rs1, uint32_t funct3, uint32_t opcode) {
    return (((imm12 >> 5) & 0x7F) << 25) | ((uint32_t)rs2 << RV_RS2_SHIFT) | ((uint32_t)rs1 << RV_RS1_SHIFT) |
        (funct3 << RV_FUNCT3_SHIFT) | ((imm12 & 0x1F) << 7) | opcode;
}
/** @internal B-type: `imm[12|10:5] rs2 rs1 funct3 imm[4:1|11] opcode`. */
static inline uint32_t rv_enc_b(uint32_t imm13, uint8_t rs2, uint8_t rs1, uint32_t funct3, uint32_t opcode) {
    return (((imm13 >> 12) & 0x1) << 31) | (((imm13 >> 5) & 0x3F) << 25) | ((uint32_t)rs2 << RV_RS2_SHIFT) |
        ((uint32_t)rs1 << RV_RS1_SHIFT) | (funct3 << RV_FUNCT3_SHIFT) | (((imm13 >> 1) & 0xF) << 8) |
        (((imm13 >> 11) & 0x1) << 7) | opcode;
}
/** @internal U-type: `imm20 rd opcode`. */
static inline uint32_t rv_enc_u(uint32_t imm20, uint8_t rd, uint32_t opcode) {
    return (imm20 << 12) | ((uint32_t)rd << RV_RD_SHIFT) | opcode;
}
/** @internal J-type: `imm[20|10:1|11|19:12] rd opcode`. */
static inline uint32_t rv_enc_j(uint32_t imm21, uint8_t rd, uint32_t opcode) {
    return (((imm21 >> 20) & 0x1) << 31) | (((imm21 >> 1) & 0x3FF) << 21) | (((imm21 >> 11) & 0x1) << 20) |
        (((imm21 >> 12) & 0xFF) << 12) | ((uint32_t)rd << RV_RD_SHIFT) | opcode;
}
/** @internal Shift-immediate I-type (RV64): `funct6 shamt rs1 funct3 rd opcode`. */
static inline uint32_t rv_enc_shift(uint32_t funct6, uint8_t shamt, uint8_t rs1, uint32_t funct3, uint8_t rd) {
    return (funct6 << 26) | ((uint32_t)shamt << 20) | ((uint32_t)rs1 << RV_RS1_SHIFT) | (funct3 << RV_FUNCT3_SHIFT) |
        ((uint32_t)rd << RV_RD_SHIFT) | RV_OP_OP_IMM;
}
/** @internal Append a fully-encoded instruction word to a `code_buffer`. */
static inline void rv_emit(code_buffer * buf, uint32_t word) {
    if (buf->error)
        return;
    emit_int32(buf, (int32_t)word);
}

void infix_riscv64_emit_addi(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm), rs1, RV_F3_ADD_SUB, rd, RV_OP_OP_IMM));
}
void infix_riscv64_emit_addiw(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm), rs1, RV_F3_ADD_SUB, rd, RV_OP_OP_IMM_32));
}
void infix_riscv64_emit_add(code_buffer * buf, uint8_t rd, uint8_t rs1, uint8_t rs2) {
    rv_emit(buf, rv_enc_r(RV_F7_ADD, rs2, rs1, RV_F3_ADD_SUB, rd, RV_OP_OP));
}
void infix_riscv64_emit_sub(code_buffer * buf, uint8_t rd, uint8_t rs1, uint8_t rs2) {
    rv_emit(buf, rv_enc_r(RV_F7_SUB, rs2, rs1, RV_F3_ADD_SUB, rd, RV_OP_OP));
}
void infix_riscv64_emit_slli(code_buffer * buf, uint8_t rd, uint8_t rs1, uint8_t shamt) {
    rv_emit(buf, rv_enc_shift(RV_F6_SLLI, shamt & 0x3F, rs1, RV_F3_SLL, rd));
}
void infix_riscv64_emit_srli(code_buffer * buf, uint8_t rd, uint8_t rs1, uint8_t shamt) {
    rv_emit(buf, rv_enc_shift(RV_F6_SRLI, shamt & 0x3F, rs1, RV_F3_SR, rd));
}
void infix_riscv64_emit_lui(code_buffer * buf, uint8_t rd, uint32_t imm20) {
    rv_emit(buf, rv_enc_u(rv_imm20(imm20), rd, RV_OP_LUI));
}
void infix_riscv64_emit_auipc(code_buffer * buf, uint8_t rd, uint32_t imm20) {
    rv_emit(buf, rv_enc_u(rv_imm20(imm20), rd, RV_OP_AUIPC));
}
void infix_riscv64_emit_jal(code_buffer * buf, uint8_t rd, int32_t imm20) {
    rv_emit(buf, rv_enc_j((uint32_t)(imm20 & ~1), rd, RV_OP_JAL));
}
void infix_riscv64_emit_jalr(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm12) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm12), rs1, RV_F3_ADD_SUB, rd, RV_OP_JALR));
}
void infix_riscv64_emit_beq(code_buffer * buf, uint8_t rs1, uint8_t rs2, int32_t imm12) {
    rv_emit(buf, rv_enc_b((uint32_t)(imm12 & ~1), rs2, rs1, RV_F3_BEQ, RV_OP_BRANCH));
}
void infix_riscv64_emit_bne(code_buffer * buf, uint8_t rs1, uint8_t rs2, int32_t imm12) {
    rv_emit(buf, rv_enc_b((uint32_t)(imm12 & ~1), rs2, rs1, RV_F3_BNE, RV_OP_BRANCH));
}
void infix_riscv64_emit_ld(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm12) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm12), rs1, RV_F3_LD, rd, RV_OP_LOAD));
}
void infix_riscv64_emit_lw(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm12) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm12), rs1, RV_F3_LW, rd, RV_OP_LOAD));
}
void infix_riscv64_emit_lwu(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm12) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm12), rs1, RV_F3_LWU, rd, RV_OP_LOAD));
}
void infix_riscv64_emit_lb(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm12) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm12), rs1, RV_F3_LB, rd, RV_OP_LOAD));
}
void infix_riscv64_emit_lbu(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm12) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm12), rs1, RV_F3_LBU, rd, RV_OP_LOAD));
}
void infix_riscv64_emit_lh(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm12) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm12), rs1, RV_F3_LH, rd, RV_OP_LOAD));
}
void infix_riscv64_emit_lhu(code_buffer * buf, uint8_t rd, uint8_t rs1, int32_t imm12) {
    rv_emit(buf, rv_enc_i(rv_sx_imm12(imm12), rs1, RV_F3_LHU, rd, RV_OP_LOAD));



( run in 0.957 second using v1.01-cache-2.11-cpan-0fb53d1c279 )