engine: intern constants

This does two things so I'll split them.

(1) Add function intern_constant() which adds a constant to the
constants array and returns the index.

The assembly for this function is beautiful. Only one load and store on
a successfull path.

Dump of assembler code for function intern_constant:
   0x0000000000010ee0 <+0>:     ldr     w8, [x4]
   0x0000000000010ee4 <+4>:     cbnz    w8, 0x10f08 <intern_constant+40>
   0x0000000000010ee8 <+8>:     ldrh    w8, [x2]
   0x0000000000010eec <+12>:    cmp     x3, x8
   0x0000000000010ef0 <+16>:    b.ls    0x10f10 <intern_constant+48>  // b.plast
   0x0000000000010ef4 <+20>:    str     w0, [x1, x8, lsl #2]
   0x0000000000010ef8 <+24>:    add     w9, w8, #0x1
   0x0000000000010efc <+28>:    orr     w0, w8, #0x10000
   0x0000000000010f00 <+32>:    strh    w9, [x2]
   0x0000000000010f04 <+36>:    ret
   0x0000000000010f08 <+40>:    mov     w0, #0x10000                    // #65536
   0x0000000000010f0c <+44>:    ret
   0x0000000000010f10 <+48>:    mov     w8, #0xffffff9c                 // #-100
   0x0000000000010f14 <+52>:    mov     w0, #0x10000                    // #65536
   0x0000000000010f18 <+56>:    str     w8, [x4]
   0x0000000000010f1c <+60>:    ret
End of assembler dump.

(2) I've decided that the entire translation code will fit in
bal_engine.c so the bal_ir_immiter and bal_translator files are not
needed anymore. I moved their preprocessor definitions into bal_engine.c

Signed-off-by: Ronald Caesar <github43132@proton.me>
This commit is contained in:
Ronald Caesar
2026-01-23 20:40:10 -04:00
parent 6a7db3db18
commit 2cc7f297c9
7 changed files with 39 additions and 147 deletions

View File

@@ -36,7 +36,6 @@ add_library(Ballistic STATIC
src/decoder.c
src/decoder_table_gen.c
src/bal_engine.c
src/bal_translator.c
src/bal_memory.c
)

View File

@@ -132,7 +132,6 @@ BAL_HOT bal_error_t bal_engine_reset(bal_engine_t *engine);
/// caller may have allocated it on the stack.
BAL_COLD void bal_engine_destroy(bal_allocator_t *allocator,
bal_engine_t *engine);
#endif /* BALLISTIC_ENGINE_H */
/*** end of file ***/

View File

@@ -9,8 +9,21 @@
//
#define MAX_GUEST_REGISTERS 128
// Helper macro to align `x` UP to the nearest memory alignment.
//
#define BAL_OPCODE_SHIFT_POSITION 51U
#define BAL_SOURCE1_SHIFT_POSITION 34U
#define BAL_SOURCE2_SHIFT_POSITION 17U
/// The maximum value for an Opcode.
#define BAL_OPCODE_SIZE (1U << 11U)
/// The maximum value for an Operand Index.
/// Bit 17 is reserved for the "Is Constant" flag.
#define BAL_SOURCE_SIZE (1U << 16U)
/// The bit position for the is constant flag in a bal_instruction_t.
#define BAL_IS_CONSTANT_BIT_POSITION (1U << 16U)
/// Helper macro to align `x` UP to the nearest memory alignment.
#define BAL_ALIGN_UP(x, memory_alignment) \
(((x) + ((memory_alignment) - 1)) & ~((memory_alignment) - 1))
@@ -94,8 +107,6 @@ bal_engine_translate (bal_engine_t *BAL_RESTRICT engine,
return BAL_ERROR_ENGINE_STATE_INVALID;
}
// Load state to registers.
//
bal_instruction_t *BAL_RESTRICT ir_instruction_cursor
= engine->instructions + engine->instruction_count;
@@ -168,3 +179,27 @@ extract_operand_value (bal_instruction_t instruction,
uint32_t bits = (instruction >> (uint32_t)operand->bit_position) & mask;
return bits;
}
BAL_HOT static uint32_t
intern_constant (bal_constant_t constant,
bal_constant_t *BAL_RESTRICT constants,
bal_constant_count_t *BAL_RESTRICT count,
size_t constants_max_size,
bal_error_t *BAL_RESTRICT status)
{
if (BAL_UNLIKELY(*status != BAL_SUCCESS))
{
return 0 | BAL_IS_CONSTANT_BIT_POSITION;
}
if (BAL_UNLIKELY(*count >= constants_max_size))
{
*status = BAL_ERROR_INSTRUCTION_OVERFLOW;
return 0 | BAL_IS_CONSTANT_BIT_POSITION;
}
constants[*count] = constant;
uint32_t index = *count | BAL_IS_CONSTANT_BIT_POSITION;
(*count)++;
return index;
}

View File

@@ -1,62 +0,0 @@
#include "bal_ir_emitter.h"
#include <stdbool.h>
#define BAL_OPCODE_SHIFT_POSITION 51U
#define BAL_SOURCE1_SHIFT_POSITION 34U
#define BAL_SOURCE2_SHIFT_POSITION 17U
#define BAL_IS_CONSTANT_BIT_POSITION (1U << 16U)
bal_error_t
emit_instruction (bal_engine_t *engine,
uint32_t opcode,
uint32_t source1,
uint32_t source2,
uint32_t source3,
bal_bit_width_t bit_width)
{
// This is a hot function, no argument error handling. Segfault if the user
// passes NULL.
if (BAL_UNLIKELY(engine->status != BAL_SUCCESS))
{
return BAL_ERROR_ENGINE_STATE_INVALID;
}
bool is_greater_than_instructions_array
= (engine->instruction_count >= engine->instructions_size);
bool is_greater_than_source_size
= (engine->instruction_count >= (BAL_SOURCE_SIZE - 1));
if (BAL_UNLIKELY((true == is_greater_than_instructions_array)
|| (true == is_greater_than_source_size)))
{
engine->status = BAL_ERROR_INSTRUCTION_OVERFLOW;
return engine->status;
}
bal_instruction_t opcode_bits = (BAL_OPCODE_SIZE - 1U) & opcode;
bal_instruction_t source1_bits
= ((BAL_SOURCE_SIZE - 1U) | BAL_IS_CONSTANT_BIT_POSITION) & source1;
bal_instruction_t source2_bits
= ((BAL_SOURCE_SIZE - 1U) | BAL_IS_CONSTANT_BIT_POSITION) & source2;
bal_instruction_t source3_bits
= ((BAL_SOURCE_SIZE - 1U) | BAL_IS_CONSTANT_BIT_POSITION) & source3;
bal_instruction_t instruction
= (opcode_bits << BAL_OPCODE_SHIFT_POSITION)
| (source1_bits << BAL_SOURCE1_SHIFT_POSITION)
| (source2_bits << BAL_SOURCE2_SHIFT_POSITION) | source3_bits;
engine->instructions[engine->instruction_count] = instruction;
engine->ssa_bit_widths[engine->instruction_count] = bit_width;
engine->status = BAL_SUCCESS;
++engine->instruction_count;
return engine->status;
}
/*** end of file ***/

View File

@@ -1,51 +0,0 @@
/** @file bal_ir_emitter.h
*
* @brief Responsible for encoding the IR into the memory arena.
*/
#ifndef BALLISTIC_IR_EMITTER_H
#define BALLISTIC_IR_EMITTER_H
#include "bal_attributes.h"
#include "bal_types.h"
#include "bal_errors.h"
#include "bal_engine.h"
/*!
* @brief The maximum value for an Opcode.
*/
#define BAL_OPCODE_SIZE (1U << 11U)
/*!
* @brief The maximum value for an Operand Index.
* @note Bit 17 is reserved for the "Is Constant" flag.
*/
#define BAL_SOURCE_SIZE (1U << 16U)
/*!
* @brief Appends a new instruction to the linear instruction stream.
*
* @param[in,out] engine The JIT engine containing the instruction buffer.
* @param[in] opcode The operation to perform (see @ref bal_opcode_t).
* @param[in] source1 SSA ID or Constant Pool Index for operand 1.
* @param[in] source2 SSA ID or Constant Pool Index for operand 2.
* @param[in] source3 SSA ID or Constant Pool Index for operand 3.
* @param[in] bit_width The bit width of the variable defined by this
* instruction.
*
* @note Increments engine->instruction_count when called.
*
* @return BAL_SUCCESS on success.
* @return BAL_ERROR_INSTRUCTION_OVERFLOW if the block limit is reached.
* @return BAL_ERROR_ENGINE_STATE_INVALID if engine->status != BAL_SUCCESS.
*/
BAL_HOT bal_error_t emit_instruction(bal_engine_t *engine,
uint32_t opcode,
uint32_t source1,
uint32_t source2,
uint32_t source3,
bal_bit_width_t bit_width);
#endif /* BALLISTIC_IR_EMITTER_H */
/*** end of file ***/

View File

@@ -1,3 +0,0 @@
#include "bal_translator.h"
/*** end of file ***/

View File

@@ -1,25 +0,0 @@
/** @file bal_translator.h
*
* @brief ARM to Ballistic IR Translation Interface.
*
* @details
*
* This module represents the frontend of Ballistic. It performas the following
* in a single pass:
*
* 1. Fetch
* 2. Decode
* 3. SSA Construction
*/
#ifndef BAL_TRANSLATOR_H
#define BAL_TRANSLATOR_H
#include "bal_engine.h"
#include "bal_types.h"
#include "bal_errors.h"
#endif /* BAL_TRANSLATOR_H */
/*** end of file ***/