gen.h 4.9 KiB 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