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 )