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 )