#ifndef EMIT_H #define EMIT_H #include #include #include "../ast.h" #include "../gen.h" #include "../io.h" #include "../scanner.h" #include "../types.h" /* Code emission. */ #define emit(g, ins) __emit(g, ins) /* Slice field offsets */ enum { SLICE_FIELD_PTR_OFFSET = 0, SLICE_FIELD_LEN_OFFSET = WORD_SIZE, }; /* Helper describing the possibly-adjusted base register for stack accesses. */ typedef struct { reg_t base; /* Register that should be used for the access. */ bool temp; /* Whether `base` was synthesized and must be freed. */ } addr_adj_t; /* Emit the given instruction. */ static inline usize __emit(gen_t *g, instr_t ins) { if (g->ninstrs >= MAX_INSTRS) { abort(); } g->instrs[g->ninstrs] = ins; g->ninstrs++; return g->ninstrs - 1; } /* Split a 32-bit immediate into upper 20 bits and lower 12 bits for RISC-V. */ void split_imm(i32 imm, i32 *hi, i32 *lo); /* Emit a load immediate (LI) instruction sequence. */ void emit_li(gen_t *g, reg_t rd, i32 imm); /* Helper function to copy register values if needed. */ void emit_mv(gen_t *g, reg_t dst, reg_t src); /* Emit relative jump to offset. */ usize emit_jump(gen_t *g, usize offset); /* Emit a function call. */ usize emit_call(gen_t *g, usize addr); /* Load a PC-relative address into a register. */ void emit_pc_rel_addr(gen_t *g, reg_t rd, usize addr); /* Emit code to index into an array */ value_t emit_array_index(gen_t *g, value_t array_val, value_t index, bool); /* Load a value into a specific register. */ reg_t emit_load_into(gen_t *g, reg_t dst, value_t src); /* Load a value from a value. */ reg_t emit_load(gen_t *g, value_t v); /* Load a word from a value. */ reg_t emit_load_dword(gen_t *g, value_t v); /* Load a value with an offset. */ reg_t emit_load_offset(gen_t *g, value_t v, i32 offset); /* Store a value on the stack. Returns a new value located on the stack. */ value_t emit_store(gen_t *g, value_t v, reg_t base, int offset); /* Push a value to the stack. */ value_t emit_push(gen_t *g, value_t v); /* Replace a value, eg. for assigning */ void emit_replace(gen_t *g, value_t old, value_t new); /* Compute dst = base + offset while respecting SIMM12 limits. */ void emit_addr_offset(gen_t *g, reg_t dst, reg_t base, i32 offset); /* Load a value at a stack offset into a register. */ usize emit_regload(gen_t *g, reg_t dst, reg_t base, i32 offset, type_t *ty); /* Push a register to the stack. */ int emit_regpush(gen_t *g, reg_t src, type_t *ty); /* Store a register value on the stack. */ usize emit_regstore(gen_t *g, reg_t src, reg_t base, i32 offset, type_t *ty); /* Store a tvalue tag. */ void emit_store_tag(gen_t *g, tval_t tv, reg_t tag_reg); /* Reserve stack space with explicit alignment. */ i32 reserve_aligned(gen_t *g, type_t *ty, i32 align); /* Copy memory between two locations */ void emit_memcopy(gen_t *g, offset_t src, offset_t dst, type_t *ty); /* Zero out a memory region */ void emit_memzero(gen_t *g, offset_t dst, i32 size); /* Compare two registers based on their type: * * - If references, compares the addresses (pointers) * - If values, compares the content * - For records and arrays, compares each element * - For slices, compares the pointer addresses * * Puts the result (0 or 1) in the result register. */ void emit_memequal(gen_t *g, reg_t left, reg_t right, type_t *ty, reg_t result); /* Compare raw bytes between two memory locations */ void emit_bytes_equal( gen_t *g, reg_t left, reg_t right, usize size, reg_t result ); /* Copy a record from one memory offset to another. */ void emit_record_copy(gen_t *g, offset_t src, offset_t dst, type_t *ty); /* Store a value directly to a record field. */ void emit_record_field_set( gen_t *g, value_t val, reg_t base, i32 record_offset, symbol_t *field ); /* Calculate record field value from a record value and field symbol. * Creates a stack-based value pointing to the field at the correct offset. */ value_t emit_record_field_get(value_t sval, symbol_t *field); /* Copy an array from one memory location to another. */ void emit_array_copy(gen_t *g, offset_t src, offset_t dst, type_t *ty); /* Copy a word between two locations. Copies addresses of * pass-by-reference types. */ void emit_copy_by_ref(gen_t *g, value_t src, value_t dst); /* Emit a slice literal */ value_t emit_slice_lit(gen_t *g, i32 offset, usize ptr, usize len, type_t *typ); /* Store a successful result value by clearing the tag and * writing the payload. */ void emit_result_store_success(gen_t *g, value_t dest, value_t value); /* Store an error result by writing the raw error tag and * zeroing the payload. */ void emit_result_store_error(gen_t *g, value_t dest, value_t err); #endif