Affix
view release on metacpan or search on metacpan
infix/src/arch/riscv/abi_riscv64_emitters.c view on Meta::CPAN
/**
* Copyright (c) 2026 Sanko Robinson
*
* This source code is dual-licensed under the Artistic License 2.0 or the MIT License.
* You may choose to use this code under the terms of either license.
*
* SPDX-License-Identifier: (Artistic-2.0 OR MIT)
*
* The documentation blocks within this file are licensed under the
* Creative Commons Attribution 4.0 International License (CC BY 4.0).
*
* SPDX-License-Identifier: CC-BY-4.0
*/
/**
* @file abi_riscv64_emitters.c
* @brief Emits single RISC-V (RV64GC) instructions into a `code_buffer`.
* @ingroup internal_abi_riscv64
*
* @internal
* Each function in this file encodes exactly one RISC-V instruction and appends
* 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;
( run in 0.828 second using v1.01-cache-2.11-cpan-4ac696b4eb4 )