gen/
.clang-format
570 B
.gitignore
30 B
.gitsigners
112 B
LICENSE
1.1 KiB
Makefile
911 B
README
1.8 KiB
ast.c
5.0 KiB
ast.h
15.1 KiB
desugar.c
23.1 KiB
desugar.h
286 B
gen.c
108.5 KiB
gen.h
4.9 KiB
io.c
1.1 KiB
io.h
444 B
limits.h
1.3 KiB
module.c
10.0 KiB
module.h
2.2 KiB
options.c
1.4 KiB
options.h
472 B
parser.c
68.3 KiB
parser.h
942 B
radiance.c
3.7 KiB
ralloc.c
2.0 KiB
ralloc.h
1.1 KiB
resolver.c
109.7 KiB
resolver.h
5.6 KiB
riscv.c
12.0 KiB
riscv.h
12.0 KiB
scanner.c
10.2 KiB
scanner.h
3.2 KiB
strings.c
2.6 KiB
strings.h
407 B
symtab.c
5.7 KiB
symtab.h
4.6 KiB
types.h
1.0 KiB
util.h
1.5 KiB
gen.h
raw
| 1 | #ifndef GEN_H |
| 2 | #define GEN_H |
| 3 | |
| 4 | #include "ast.h" |
| 5 | #include "limits.h" |
| 6 | #include "module.h" |
| 7 | #include "ralloc.h" |
| 8 | #include "resolver.h" |
| 9 | #include "riscv.h" |
| 10 | #include "scanner.h" |
| 11 | #include "symtab.h" |
| 12 | #include "types.h" |
| 13 | |
| 14 | #include "gen/data.h" |
| 15 | |
| 16 | /* Create an offset. */ |
| 17 | #define OFFSET(base, off) ((offset_t){ base, off }) |
| 18 | |
| 19 | /* Function call instruction patch, used to patch a jump location after |
| 20 | * function addresses are calculated. */ |
| 21 | typedef enum { |
| 22 | PATCH_CALL, /* Function call (JAL instruction) */ |
| 23 | PATCH_ADDRESS, /* Function address (load instruction) */ |
| 24 | } patch_type_t; |
| 25 | |
| 26 | /* Metadata for deferred branch patching that may expand to a trampoline. */ |
| 27 | typedef struct { |
| 28 | usize pc; /* Branch instruction index */ |
| 29 | usize tramp_pc; /* Trampoline instruction index */ |
| 30 | iname_t op; /* Branch operation */ |
| 31 | reg_t rs1; /* First operand register */ |
| 32 | reg_t rs2; /* Second operand register */ |
| 33 | bool valid; /* Whether this patch slot is in use */ |
| 34 | } branch_patch_t; |
| 35 | |
| 36 | typedef struct { |
| 37 | usize skip_body; /* Jump location when pattern (or guard) fails */ |
| 38 | branch_patch_t guard_branch; /* Guard failure branch placeholder */ |
| 39 | } match_case_ctrl_t; |
| 40 | |
| 41 | typedef struct { |
| 42 | const char *fn_name; |
| 43 | usize pc; /* Instruction index. */ |
| 44 | usize tramp_pc; /* Optional secondary slot for long jumps. */ |
| 45 | bool applied; /* Whether the patch was applied. */ |
| 46 | patch_type_t patch_type; /* Type of patch to apply. */ |
| 47 | reg_t target_reg; /* Target register for address patches. */ |
| 48 | reg_t scratch_reg; /* Scratch register for far calls. */ |
| 49 | } fnpatch_t; |
| 50 | |
| 51 | /* Return patch, used to jump to a function's epilogue from return statements */ |
| 52 | typedef struct { |
| 53 | usize pc; /* Instruction index of the jump placeholder */ |
| 54 | bool applied; /* Whether the patch was applied */ |
| 55 | } retpatch_t; |
| 56 | |
| 57 | /* Control flow patch, used to jump to a function's epilogue from |
| 58 | * return statements, or jump to a loop's end. */ |
| 59 | typedef struct { |
| 60 | usize pc; /* Instruction index of the jump placeholder */ |
| 61 | bool applied; /* Whether the patch was applied */ |
| 62 | node_t *loop; /* Parent loop of this patch, for breaks. */ |
| 63 | } ctpatch_t; |
| 64 | |
| 65 | /* Loop context for handling control flow statements. */ |
| 66 | typedef struct { |
| 67 | usize start; /* Start address of loop (for `continue`). */ |
| 68 | usize end; /* End address of loop (for `break`). */ |
| 69 | node_t *current; /* Current loop we're in. */ |
| 70 | } loop_t; |
| 71 | |
| 72 | /* Function context for handling return statements. */ |
| 73 | typedef struct { |
| 74 | /* Return and break patches for current function. */ |
| 75 | ctpatch_t retpatches[MAX_RET_PATCHES]; |
| 76 | usize nretpatches; |
| 77 | ctpatch_t brkpatches[MAX_BRK_PATCHES]; |
| 78 | usize nbrkpatches; |
| 79 | symbol_t *current; /* Current function. */ |
| 80 | } fn_t; |
| 81 | |
| 82 | /* Code generator context. */ |
| 83 | typedef struct gen_t { |
| 84 | instr_t instrs[MAX_INSTRS]; |
| 85 | usize ninstrs; |
| 86 | loop_t loop; /* Current loop. */ |
| 87 | fn_t fn; /* Current function. */ |
| 88 | fnpatch_t fnpatches[MAX_FN_PATCHES]; |
| 89 | usize nfnpatches; |
| 90 | |
| 91 | types_t *types; |
| 92 | ralloc_t regs; |
| 93 | module_manager_t *mm; |
| 94 | struct module_t *mod; /* Current module being compiled */ |
| 95 | data_section_t data; /* Static data section */ |
| 96 | u32 flags; |
| 97 | } gen_t; |
| 98 | |
| 99 | /* Represents a tagged value (eg. an optional or enum with payload) */ |
| 100 | typedef struct { |
| 101 | value_t tag; /* Location of the tag */ |
| 102 | value_t val; /* Location of the value */ |
| 103 | type_t *typ; /* The tagged type (eg. `?T` or `enum`) */ |
| 104 | } tval_t; |
| 105 | |
| 106 | value_t value_stack(offset_t off, type_t *ty); |
| 107 | value_t value_addr(usize addr, i32 off, type_t *ty); |
| 108 | value_t value_imm(imm_t imm, type_t *ty); |
| 109 | value_t value_reg(reg_t r, type_t *ty); |
| 110 | |
| 111 | static inline reg_t nextreg(gen_t *g) { |
| 112 | return ralloc_next(&g->regs); |
| 113 | } |
| 114 | |
| 115 | static inline reg_t nextreg_except(gen_t *g, reg_t r) { |
| 116 | return ralloc_next_except(&g->regs, r); |
| 117 | } |
| 118 | |
| 119 | static inline bool isreserved(gen_t *g, reg_t r) { |
| 120 | if (r == FP) |
| 121 | return true; |
| 122 | return !ralloc_is_free(&g->regs, r); |
| 123 | } |
| 124 | |
| 125 | static inline void freereg(gen_t *g, reg_t r) { |
| 126 | ralloc_free(&g->regs, r); |
| 127 | } |
| 128 | |
| 129 | static inline reg_t usereg(gen_t *g, reg_t r) { |
| 130 | ralloc_reserve(&g->regs, r); |
| 131 | return r; |
| 132 | } |
| 133 | |
| 134 | /* Calculate a jump offset. */ |
| 135 | i32 jump_offset(usize from, usize to); |
| 136 | /* Reserve stack space for the given type. */ |
| 137 | i32 reserve(gen_t *g, type_t *ty); |
| 138 | /* Like `align`, but rounds down. */ |
| 139 | i32 align_stack(i32 addr, i32 alignment); |
| 140 | |
| 141 | /* Optional and enum value helper functions */ |
| 142 | tval_t tval_from_val(gen_t *g, value_t val); |
| 143 | i32 tval_payload_zero_size(type_t *container); |
| 144 | void tval_store(gen_t *g, value_t dest, value_t value, i32 tag); |
| 145 | |
| 146 | /* Write instructions in binary format. */ |
| 147 | void gen_dump_bin(gen_t *g, FILE *text, FILE *data_ro, FILE *data_rw); |
| 148 | /* Generate code for the given module. */ |
| 149 | int gen_emit(gen_t *g, module_t *root); |
| 150 | /* Initialize a `codegen` object. */ |
| 151 | void gen_init(gen_t *g, types_t *t, module_manager_t *mm, u32 flags); |
| 152 | |
| 153 | #endif |