#ifndef GEN_H #define GEN_H #include "ast.h" #include "limits.h" #include "module.h" #include "ralloc.h" #include "resolver.h" #include "riscv.h" #include "scanner.h" #include "symtab.h" #include "types.h" #include "gen/data.h" /* Create an offset. */ #define OFFSET(base, off) ((offset_t){ base, off }) /* Function call instruction patch, used to patch a jump location after * function addresses are calculated. */ typedef enum { PATCH_CALL, /* Function call (JAL instruction) */ PATCH_ADDRESS, /* Function address (load instruction) */ } patch_type_t; /* Metadata for deferred branch patching that may expand to a trampoline. */ typedef struct { usize pc; /* Branch instruction index */ usize tramp_pc; /* Trampoline instruction index */ iname_t op; /* Branch operation */ reg_t rs1; /* First operand register */ reg_t rs2; /* Second operand register */ bool valid; /* Whether this patch slot is in use */ } branch_patch_t; typedef struct { usize skip_body; /* Jump location when pattern (or guard) fails */ branch_patch_t guard_branch; /* Guard failure branch placeholder */ } match_case_ctrl_t; typedef struct { const char *fn_name; usize pc; /* Instruction index. */ usize tramp_pc; /* Optional secondary slot for long jumps. */ bool applied; /* Whether the patch was applied. */ patch_type_t patch_type; /* Type of patch to apply. */ reg_t target_reg; /* Target register for address patches. */ reg_t scratch_reg; /* Scratch register for far calls. */ } fnpatch_t; /* Return patch, used to jump to a function's epilogue from return statements */ typedef struct { usize pc; /* Instruction index of the jump placeholder */ bool applied; /* Whether the patch was applied */ } retpatch_t; /* Control flow patch, used to jump to a function's epilogue from * return statements, or jump to a loop's end. */ typedef struct { usize pc; /* Instruction index of the jump placeholder */ bool applied; /* Whether the patch was applied */ node_t *loop; /* Parent loop of this patch, for breaks. */ } ctpatch_t; /* Loop context for handling control flow statements. */ typedef struct { usize start; /* Start address of loop (for `continue`). */ usize end; /* End address of loop (for `break`). */ node_t *current; /* Current loop we're in. */ } loop_t; /* Function context for handling return statements. */ typedef struct { /* Return and break patches for current function. */ ctpatch_t retpatches[MAX_RET_PATCHES]; usize nretpatches; ctpatch_t brkpatches[MAX_BRK_PATCHES]; usize nbrkpatches; symbol_t *current; /* Current function. */ } fn_t; /* Code generator context. */ typedef struct gen_t { instr_t instrs[MAX_INSTRS]; usize ninstrs; loop_t loop; /* Current loop. */ fn_t fn; /* Current function. */ fnpatch_t fnpatches[MAX_FN_PATCHES]; usize nfnpatches; types_t *types; ralloc_t regs; module_manager_t *mm; struct module_t *mod; /* Current module being compiled */ data_section_t data; /* Static data section */ u32 flags; } gen_t; /* Represents a tagged value (eg. an optional or enum with payload) */ typedef struct { value_t tag; /* Location of the tag */ value_t val; /* Location of the value */ type_t *typ; /* The tagged type (eg. `?T` or `enum`) */ } tval_t; value_t value_stack(offset_t off, type_t *ty); value_t value_addr(usize addr, i32 off, type_t *ty); value_t value_imm(imm_t imm, type_t *ty); value_t value_reg(reg_t r, type_t *ty); static inline reg_t nextreg(gen_t *g) { return ralloc_next(&g->regs); } static inline reg_t nextreg_except(gen_t *g, reg_t r) { return ralloc_next_except(&g->regs, r); } static inline bool isreserved(gen_t *g, reg_t r) { if (r == FP) return true; return !ralloc_is_free(&g->regs, r); } static inline void freereg(gen_t *g, reg_t r) { ralloc_free(&g->regs, r); } static inline reg_t usereg(gen_t *g, reg_t r) { ralloc_reserve(&g->regs, r); return r; } /* Calculate a jump offset. */ i32 jump_offset(usize from, usize to); /* Reserve stack space for the given type. */ i32 reserve(gen_t *g, type_t *ty); /* Like `align`, but rounds down. */ i32 align_stack(i32 addr, i32 alignment); /* Optional and enum value helper functions */ tval_t tval_from_val(gen_t *g, value_t val); i32 tval_payload_zero_size(type_t *container); void tval_store(gen_t *g, value_t dest, value_t value, i32 tag); /* Write instructions in binary format. */ void gen_dump_bin(gen_t *g, FILE *text, FILE *data_ro, FILE *data_rw); /* Generate code for the given module. */ int gen_emit(gen_t *g, module_t *root); /* Initialize a `codegen` object. */ void gen_init(gen_t *g, types_t *t, module_manager_t *mm, u32 flags); #endif