harec

[hare] Hare compiler, written in C11 for POSIX OSs
Log | Files | Refs | README | LICENSE

qbe.c (5869B)


      1 #include <assert.h>
      2 #include <stdarg.h>
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include "qbe.h"
      7 #include "util.h"
      8 
      9 // Simple type singletons
     10 const struct qbe_type
     11 qbe_byte = {
     12 	.stype = Q_BYTE,
     13 	.size = 1,
     14 },
     15 qbe_half = {
     16 	.stype = Q_HALF,
     17 	.size = 2,
     18 },
     19 qbe_word = {
     20 	.stype = Q_WORD,
     21 	.size = 4,
     22 },
     23 qbe_long = {
     24 	.stype = Q_LONG,
     25 	.size = 8,
     26 },
     27 qbe_single = {
     28 	.stype = Q_SINGLE,
     29 	.size = 4,
     30 },
     31 qbe_double = {
     32 	.stype = Q_DOUBLE,
     33 	.size = 8,
     34 },
     35 qbe_void = {
     36 	.stype = Q__VOID,
     37 },
     38 qbe_aggregate = {
     39 	.stype = Q__AGGREGATE,
     40 };
     41 
     42 const struct qbe_value variadic_sigil = {0};
     43 
     44 const char *qbe_instr[Q_LAST_INSTR] = {
     45 	[Q_ADD] = "add",
     46 	[Q_ALLOC16] = "alloc16",
     47 	[Q_ALLOC4] = "alloc4",
     48 	[Q_ALLOC8] = "alloc8",
     49 	[Q_AND] = "and",
     50 	[Q_BLIT] = "blit",
     51 	[Q_CALL] = "call",
     52 	[Q_CAST] = "cast",
     53 	[Q_CEQD] = "ceqd",
     54 	[Q_CEQL] = "ceql",
     55 	[Q_CEQS] = "ceqs",
     56 	[Q_CEQW] = "ceqw",
     57 	[Q_CGED] = "cged",
     58 	[Q_CGES] = "cges",
     59 	[Q_CGTD] = "cgtd",
     60 	[Q_CGTS] = "cgts",
     61 	[Q_CLED] = "cled",
     62 	[Q_CLES] = "cles",
     63 	[Q_CLTD] = "cltd",
     64 	[Q_CLTS] = "clts",
     65 	[Q_CNED] = "cned",
     66 	[Q_CNEL] = "cnel",
     67 	[Q_CNES] = "cnes",
     68 	[Q_CNEW] = "cnew",
     69 	[Q_COD] = "cod",
     70 	[Q_COPY] = "copy",
     71 	[Q_COS] = "cos",
     72 	[Q_CSGEL] = "csgel",
     73 	[Q_CSGEW] = "csgew",
     74 	[Q_CSGTL] = "csgtl",
     75 	[Q_CSGTW] = "csgtw",
     76 	[Q_CSLEL] = "cslel",
     77 	[Q_CSLEW] = "cslew",
     78 	[Q_CSLTL] = "csltl",
     79 	[Q_CSLTW] = "csltw",
     80 	[Q_CUGEL] = "cugel",
     81 	[Q_CUGEW] = "cugew",
     82 	[Q_CUGTL] = "cugtl",
     83 	[Q_CUGTW] = "cugtw",
     84 	[Q_CULEL] = "culel",
     85 	[Q_CULEW] = "culew",
     86 	[Q_CULTL] = "cultl",
     87 	[Q_CULTW] = "cultw",
     88 	[Q_CUOD] = "cuod",
     89 	[Q_CUOS] = "cuos",
     90 	[Q_DIV] = "div",
     91 	[Q_DTOSI] = "dtosi",
     92 	[Q_DTOUI] = "dtoui",
     93 	[Q_EXTS] = "exts",
     94 	[Q_EXTSB] = "extsb",
     95 	[Q_EXTSH] = "extsh",
     96 	[Q_EXTSW] = "extsw",
     97 	[Q_EXTUB] = "extub",
     98 	[Q_EXTUH] = "extuh",
     99 	[Q_EXTUW] = "extuw",
    100 	[Q_JMP] = "jmp",
    101 	[Q_JNZ] = "jnz",
    102 	[Q_LOADD] = "loadd",
    103 	[Q_LOADL] = "loadl",
    104 	[Q_LOADS] = "loads",
    105 	[Q_LOADSB] = "loadsb",
    106 	[Q_LOADSH] = "loadsh",
    107 	[Q_LOADSW] = "loadsw",
    108 	[Q_LOADUB] = "loadub",
    109 	[Q_LOADUH] = "loaduh",
    110 	[Q_LOADUW] = "loaduw",
    111 	[Q_MUL] = "mul",
    112 	[Q_NEG] = "neg",
    113 	[Q_OR] = "or",
    114 	[Q_REM] = "rem",
    115 	[Q_RET] = "ret",
    116 	[Q_SAR] = "sar",
    117 	[Q_SHL] = "shl",
    118 	[Q_SHR] = "shr",
    119 	[Q_SLTOF] = "sltof",
    120 	[Q_STOREB] = "storeb",
    121 	[Q_STORED] = "stored",
    122 	[Q_STOREH] = "storeh",
    123 	[Q_STOREL] = "storel",
    124 	[Q_STORES] = "stores",
    125 	[Q_STOREW] = "storew",
    126 	[Q_STOSI] = "stosi",
    127 	[Q_STOUI] = "stoui",
    128 	[Q_SUB] = "sub",
    129 	[Q_SWTOF] = "swtof",
    130 	[Q_TRUNCD] = "truncd",
    131 	[Q_UDIV] = "udiv",
    132 	[Q_ULTOF] = "ultof",
    133 	[Q_UREM] = "urem",
    134 	[Q_UWTOF] = "uwtof",
    135 	[Q_VAARG] = "vaarg",
    136 	[Q_VASTART] = "vastart",
    137 	[Q_XOR] = "xor",
    138 };
    139 
    140 void
    141 qbe_append_def(struct qbe_program *prog, struct qbe_def *def)
    142 {
    143 	*prog->next = def;
    144 	prog->next = &def->next;
    145 }
    146 
    147 struct qbe_value *
    148 qval_dup(const struct qbe_value *val)
    149 {
    150 	struct qbe_value *new = xcalloc(1, sizeof(struct qbe_value));
    151 	*new = *val;
    152 	if (val->kind != QV_CONST) {
    153 		new->name = xstrdup(val->name);
    154 	}
    155 	return new;
    156 }
    157 
    158 static void
    159 va_geni(struct qbe_statement *stmt, enum qbe_instr instr,
    160 		const struct qbe_value *out, va_list ap)
    161 {
    162 	stmt->type = Q_INSTR;
    163 	stmt->instr = instr;
    164 
    165 	if (out) {
    166 		stmt->out = qval_dup(out);
    167 	}
    168 
    169 	struct qbe_arguments **next = &stmt->args;
    170 	struct qbe_value *val;
    171 	while ((val = va_arg(ap, struct qbe_value *))) {
    172 		struct qbe_arguments *arg = xcalloc(1, sizeof(struct qbe_arguments));
    173 		arg->value = *val;
    174 		*next = arg;
    175 		next = &arg->next;
    176 	}
    177 }
    178 
    179 void
    180 geni(struct qbe_statement *stmt, const struct qbe_value *out,
    181 		enum qbe_instr instr, ...)
    182 {
    183 	va_list ap;
    184 	va_start(ap, instr);
    185 	va_geni(stmt, instr, out, ap);
    186 	va_end(ap);
    187 }
    188 
    189 const char *
    190 genl(struct qbe_statement *stmt, int *id, const char *fmt)
    191 {
    192 	stmt->type = Q_LABEL;
    193 	int n = snprintf(NULL, 0, fmt, *id);
    194 	char *l = xcalloc(1, n + 1);
    195 	snprintf(l, n + 1, fmt, *id);
    196 	stmt->label = l;
    197 	*id = *id + 1;
    198 	return l;
    199 }
    200 
    201 void
    202 push(struct qbe_statements *stmts, struct qbe_statement *stmt)
    203 {
    204 	if (!stmts->stmts) {
    205 		stmts->sz = 256;
    206 		stmts->ln = 0;
    207 		stmts->stmts = xcalloc(1,
    208 			sizeof(struct qbe_statement) * stmts->sz);
    209 	}
    210 	if (stmts->ln + 1 >= stmts->sz) {
    211 		stmts->sz *= 2;
    212 		stmts->stmts = xrealloc(stmts->stmts,
    213 			sizeof(struct qbe_statement) * stmts->sz);
    214 	}
    215 	stmts->stmts[stmts->ln++] = *stmt;
    216 }
    217 
    218 void
    219 pushi(struct qbe_func *func, const struct qbe_value *out,
    220 		enum qbe_instr instr, ...)
    221 {
    222 	struct qbe_statement stmt = {0};
    223 	va_list ap;
    224 	va_start(ap, instr);
    225 
    226 	struct qbe_value hack;
    227 	if (out && (out->type->stype == Q_BYTE || out->type->stype == Q_HALF)) {
    228 		hack = *out;
    229 		hack.type = &qbe_word;
    230 		out = &hack;
    231 	}
    232 
    233 	va_geni(&stmt, instr, out, ap);
    234 	va_end(ap);
    235 	push(&func->body, &stmt);
    236 }
    237 
    238 void
    239 pushprei(struct qbe_func *func, const struct qbe_value *out,
    240 		enum qbe_instr instr, ...)
    241 {
    242 	struct qbe_statement stmt = {0};
    243 	va_list ap;
    244 	va_start(ap, instr);
    245 	va_geni(&stmt, instr, out, ap);
    246 	va_end(ap);
    247 	push(&func->prelude, &stmt);
    248 }
    249 
    250 const char *
    251 pushl(struct qbe_func *func, int *id, const char *fmt)
    252 {
    253 	struct qbe_statement stmt = {0};
    254 	const char *l = genl(&stmt, id, fmt);
    255 	push(&func->body, &stmt);
    256 	return l;
    257 }
    258 
    259 void
    260 pushc(struct qbe_func *func, const char *fmt, ...)
    261 {
    262 	struct qbe_statement stmt = {0};
    263 
    264 	va_list ap;
    265 	va_start(ap, fmt);
    266 	int n = vsnprintf(NULL, 0, fmt, ap);
    267 	va_end(ap);
    268 
    269 	char *str = xcalloc(1, n + 1);
    270 	va_start(ap, fmt);
    271 	vsnprintf(str, n + 1, fmt, ap);
    272 	va_end(ap);
    273 
    274 	stmt.comment = str;
    275 	push(&func->body, &stmt);
    276 }
    277 
    278 struct qbe_value
    279 constl(uint64_t l)
    280 {
    281 	return (struct qbe_value){
    282 		.kind = QV_CONST,
    283 		.type = &qbe_long,
    284 		.lval = l,
    285 	};
    286 }
    287 
    288 struct qbe_value
    289 constw(uint32_t w)
    290 {
    291 	return (struct qbe_value){
    292 		.kind = QV_CONST,
    293 		.type = &qbe_word,
    294 		.wval = w,
    295 	};
    296 }
    297 
    298 struct qbe_value
    299 consts(float s)
    300 {
    301 	return (struct qbe_value){
    302 		.kind = QV_CONST,
    303 		.type = &qbe_single,
    304 		.sval = s,
    305 	};
    306 }
    307 
    308 struct qbe_value
    309 constd(double d)
    310 {
    311 	return (struct qbe_value){
    312 		.kind = QV_CONST,
    313 		.type = &qbe_double,
    314 		.dval = d,
    315 	};
    316 }