156 lines
5.0 KiB
C
156 lines
5.0 KiB
C
#ifndef __SPL_EMIT_H__
|
|
#define __SPL_EMIT_H__
|
|
|
|
#include "../stage0/spl_ir.h"
|
|
#include "spl_type.h"
|
|
#include <stdint.h>
|
|
|
|
/* ============================================================
|
|
* Frame allocator
|
|
* ============================================================ */
|
|
|
|
typedef struct {
|
|
int current_bytes;
|
|
int peak_bytes;
|
|
} spl_frame_alloc_t;
|
|
|
|
static inline void fa_init(spl_frame_alloc_t *fa) {
|
|
fa->current_bytes = 0;
|
|
fa->peak_bytes = 0;
|
|
}
|
|
|
|
static inline int fa_alloc(spl_frame_alloc_t *fa, usize byte_size) {
|
|
usize aligned = (byte_size + sizeof(spl_val_t) - 1) & ~(sizeof(spl_val_t) - 1);
|
|
if (aligned < sizeof(spl_val_t))
|
|
aligned = sizeof(spl_val_t);
|
|
int offset = fa->current_bytes;
|
|
fa->current_bytes += (int)aligned;
|
|
if (fa->current_bytes > fa->peak_bytes)
|
|
fa->peak_bytes = fa->current_bytes;
|
|
return offset;
|
|
}
|
|
|
|
int fa_alloc_type(spl_frame_alloc_t *fa, spl_type_ctx_t *tctx, int type_idx);
|
|
|
|
static inline void fa_reset_to(spl_frame_alloc_t *fa, int mark) { fa->current_bytes = mark; }
|
|
|
|
static inline int fa_alloc_slots(spl_frame_alloc_t *fa, usize nslots) {
|
|
return fa_alloc(fa, nslots * sizeof(spl_val_t));
|
|
}
|
|
|
|
static inline int fa_alloc_temp(spl_frame_alloc_t *fa, usize nslots) {
|
|
return fa_alloc_slots(fa, nslots);
|
|
}
|
|
|
|
static inline void fa_free(spl_frame_alloc_t *fa, int mark) { fa->current_bytes = mark; }
|
|
|
|
/* ============================================================
|
|
* Emit context
|
|
* ============================================================ */
|
|
|
|
typedef struct {
|
|
spl_val_t insn_idx;
|
|
int func_idx;
|
|
} spl_fixup_entry_t;
|
|
|
|
typedef struct {
|
|
spl_prog_t *prog;
|
|
spl_frame_alloc_t frame;
|
|
VEC(spl_fixup_entry_t) fixups;
|
|
} spl_emit_t;
|
|
|
|
void spl_emit_init(spl_emit_t *e, spl_prog_t *prog);
|
|
void spl_emit_drop(spl_emit_t *e);
|
|
|
|
/* ============================================================
|
|
* Layer 1 — single-instruction semantic wrappers
|
|
* ============================================================ */
|
|
|
|
/* Stack ops */
|
|
void emit_drop(spl_emit_t *e);
|
|
void emit_dup(spl_emit_t *e);
|
|
void emit_swap(spl_emit_t *e);
|
|
void emit_rot(spl_emit_t *e);
|
|
void emit_pick(spl_emit_t *e, int n);
|
|
|
|
/* Push */
|
|
void emit_push_i32(spl_emit_t *e, int v);
|
|
void emit_push_usize(spl_emit_t *e, usize v);
|
|
void emit_push_u64(spl_emit_t *e, uint64_t v);
|
|
void emit_push_f64(spl_emit_t *e, uint64_t v);
|
|
void emit_push_ptr(spl_emit_t *e, spl_val_t v);
|
|
void emit_push_type(spl_emit_t *e, uint16_t bt, spl_val_t v);
|
|
|
|
/* Load */
|
|
void emit_load_ptr(spl_emit_t *e);
|
|
void emit_load_usize(spl_emit_t *e);
|
|
void emit_load_type(spl_emit_t *e, uint16_t bt);
|
|
|
|
/* Store */
|
|
void emit_store_i32(spl_emit_t *e);
|
|
void emit_store_ptr(spl_emit_t *e);
|
|
void emit_store_usize(spl_emit_t *e);
|
|
void emit_store_type(spl_emit_t *e, uint16_t bt);
|
|
|
|
/* Arithmetic */
|
|
void emit_add_usize(spl_emit_t *e);
|
|
void emit_add_u64(spl_emit_t *e);
|
|
void emit_mul_u64(spl_emit_t *e);
|
|
void emit_sub_usize(spl_emit_t *e);
|
|
|
|
/* Compare */
|
|
void emit_ult_usize(spl_emit_t *e);
|
|
|
|
/* Branch */
|
|
void emit_jmp(spl_emit_t *e, spl_val_t offset);
|
|
spl_val_t emit_jmp_here(spl_emit_t *e);
|
|
spl_val_t emit_bz_here(spl_emit_t *e);
|
|
spl_val_t emit_bnz_here(spl_emit_t *e);
|
|
void emit_patch(spl_emit_t *e, spl_val_t addr, spl_val_t target);
|
|
void emit_patch_here(spl_emit_t *e, spl_val_t addr);
|
|
|
|
/* Address */
|
|
void emit_laddr(spl_emit_t *e, int offset);
|
|
void emit_gaddr(spl_emit_t *e, int idx);
|
|
|
|
/* Call */
|
|
void emit_call(spl_emit_t *e, int nargs);
|
|
void emit_ncall(spl_emit_t *e, int nargs);
|
|
|
|
/* Misc */
|
|
void emit_alloc(spl_emit_t *e, int slots);
|
|
void emit_binop(spl_emit_t *e, uint16_t op, uint16_t bt);
|
|
void emit_dbg_void(spl_emit_t *e);
|
|
void emit_dbg_usize(spl_emit_t *e);
|
|
|
|
/* Low-level emit (raw opcode + type + imm) */
|
|
spl_val_t emit_raw(spl_emit_t *e, uint16_t opcode, uint16_t type, spl_val_t imm);
|
|
|
|
/* ============================================================
|
|
* Layer 2 — semantic-level helpers
|
|
* ============================================================ */
|
|
|
|
void emit_frame_copy(spl_emit_t *e, int dest_offset, usize nslots);
|
|
void emit_copy_addr_to_addr(spl_emit_t *e, usize nslots, int depth);
|
|
void emit_load_to_var(spl_emit_t *e, spl_type_ctx_t *tctx, int ptr_slot_offset, usize byte_offset,
|
|
int data_type_idx, int var_offset);
|
|
void emit_store_to_laddr(spl_emit_t *e, int offset, uint16_t type);
|
|
void emit_ptr_add(spl_emit_t *e, usize byte_off);
|
|
spl_val_t emit_call_with_fixup(spl_emit_t *e, int nargs, int func_idx);
|
|
void emit_return(spl_emit_t *e, spl_type_ctx_t *tctx, int ret_type_idx);
|
|
|
|
/* Patch all fixups */
|
|
void emit_patch_call_fixups(spl_emit_t *e, spl_prog_t *prog);
|
|
|
|
/* ============================================================
|
|
* Layer 3 — compiler-level helpers (need spl_comp_t for tctx)
|
|
* ============================================================ */
|
|
|
|
struct spl_comp;
|
|
void spl_emit_ret(struct spl_comp *ctx, int ret_type_idx);
|
|
void spl_emit_store_init(struct spl_comp *ctx, int var_offset, int var_type_idx);
|
|
void spl_emit_defer(struct spl_comp *ctx);
|
|
void spl_emit_defer_epilogue(struct spl_comp *ctx, int depth);
|
|
|
|
#endif /* __SPL_EMIT_H__ */
|