harec

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

emit.c (7652B)


      1 #include <assert.h>
      2 #include <ctype.h>
      3 #include <float.h>
      4 #include <inttypes.h>
      5 #include <stdlib.h>
      6 #include <stdio.h>
      7 #include "emit.h"
      8 #include "qbe.h"
      9 #include "typedef.h"
     10 #include "types.h"
     11 
     12 static void
     13 emit_qtype(const struct qbe_type *type, bool aggr, FILE *out)
     14 {
     15 	assert(type);
     16 	switch (type->stype) {
     17 	case Q_BYTE:
     18 	case Q_HALF:
     19 	case Q_WORD:
     20 	case Q_LONG:
     21 	case Q_SINGLE:
     22 	case Q_DOUBLE:
     23 		fprintf(out, "%c", (char)type->stype);
     24 		break;
     25 	case Q__AGGREGATE:
     26 		if (aggr) {
     27 			fprintf(out, ":%s", type->name);
     28 		} else {
     29 			fprintf(out, "l");
     30 		}
     31 		break;
     32 	case Q__VOID:
     33 		break; // no-op
     34 	}
     35 }
     36 
     37 static char *
     38 gen_typename(const struct type *type)
     39 {
     40 	size_t sz = 0;
     41 	char *ptr = NULL;
     42 	FILE *f = open_memstream(&ptr, &sz);
     43 	emit_type(type, f);
     44 	fclose(f);
     45 	return ptr;
     46 }
     47 
     48 static void
     49 qemit_type(const struct qbe_def *def, FILE *out)
     50 {
     51 	assert(def->kind == Q_TYPE);
     52 	const struct type *base = def->type.base;
     53 	if (base) {
     54 		char *tn = gen_typename(base);
     55 		fprintf(out, "# %s [id: %u; size: %zu]\n", tn, base->id, base->size);
     56 		free(tn);
     57 		fprintf(out, "type :%s =", def->name);
     58 		if (base->align != (size_t)-1) {
     59 			fprintf(out, " align %zu", base->align);
     60 		}
     61 	} else {
     62 		fprintf(out, "type :%s =", def->name);
     63 	}
     64 	fprintf(out, " {");
     65 
     66 	bool is_union = base == NULL || type_dealias(base)->storage == STORAGE_UNION;
     67 	const struct qbe_field *field = &def->type.fields;
     68 	while (field) {
     69 		if (is_union) {
     70 			fprintf(out, " {");
     71 		}
     72 		if (field->type) {
     73 			fprintf(out, " ");
     74 			emit_qtype(field->type, true, out);
     75 		}
     76 		if (field->count) {
     77 			fprintf(out, " %zu", field->count);
     78 		}
     79 		if (is_union) {
     80 			fprintf(out, " }");
     81 		} else if (field->next) {
     82 			fprintf(out, ",");
     83 		}
     84 		field = field->next;
     85 	}
     86 
     87 	fprintf(out, " }\n\n");
     88 }
     89 
     90 static void
     91 emit_const(struct qbe_value *val, FILE *out)
     92 {
     93 	switch (val->type->stype) {
     94 	case Q_BYTE:
     95 	case Q_HALF:
     96 	case Q_WORD:
     97 		fprintf(out, "%u", val->wval);
     98 		break;
     99 	case Q_LONG:
    100 		fprintf(out, "%" PRIu64, val->lval);
    101 		break;
    102 	case Q_SINGLE:
    103 		fprintf(out, "s_%.*g", DECIMAL_DIG, val->sval);
    104 		break;
    105 	case Q_DOUBLE:
    106 		fprintf(out, "d_%.*g", DECIMAL_DIG, val->dval);
    107 		break;
    108 	case Q__VOID:
    109 	case Q__AGGREGATE:
    110 		assert(0); // Invariant
    111 	}
    112 }
    113 
    114 static void
    115 emit_value(struct qbe_value *val, FILE *out)
    116 {
    117 	switch (val->kind) {
    118 	case QV_CONST:
    119 		emit_const(val, out);
    120 		break;
    121 	case QV_GLOBAL:
    122 		fprintf(out, "$%s", val->name);
    123 		break;
    124 	case QV_LABEL:
    125 		fprintf(out, "@%s", val->name);
    126 		break;
    127 	case QV_TEMPORARY:
    128 		fprintf(out, "%%%s", val->name);
    129 		break;
    130 	case QV_VARIADIC:
    131 		fprintf(out, "...");
    132 		break;
    133 	}
    134 }
    135 
    136 static void
    137 emit_call(struct qbe_statement *stmt, FILE *out)
    138 {
    139 	fprintf(out, "%s ", qbe_instr[stmt->instr]);
    140 
    141 	struct qbe_arguments *arg = stmt->args;
    142 	assert(arg);
    143 	emit_value(&arg->value, out);
    144 	fprintf(out, "(");
    145 	arg = arg->next;
    146 
    147 	bool comma = false;
    148 	while (arg) {
    149 		fprintf(out, "%s", comma ? ", " : "");
    150 		if (arg->value.kind != QV_VARIADIC) {
    151 			emit_qtype(arg->value.type, true, out);
    152 			fprintf(out, " ");
    153 		}
    154 		emit_value(&arg->value, out);
    155 		arg = arg->next;
    156 		comma = true;
    157 	}
    158 
    159 	fprintf(out, ")\n");
    160 }
    161 
    162 static void
    163 emit_stmt(struct qbe_statement *stmt, FILE *out)
    164 {
    165 	switch (stmt->type) {
    166 	case Q_COMMENT:
    167 		fprintf(out, "\t# %s\n", stmt->comment);
    168 		break;
    169 	case Q_INSTR:
    170 		fprintf(out, "\t");
    171 		if (stmt->instr == Q_CALL) {
    172 			if (stmt->out != NULL) {
    173 				emit_value(stmt->out, out);
    174 				fprintf(out, " =");
    175 				emit_qtype(stmt->out->type, true, out);
    176 				fprintf(out, " ");
    177 			}
    178 			emit_call(stmt, out);
    179 			break;
    180 		}
    181 		if (stmt->out != NULL) {
    182 			emit_value(stmt->out, out);
    183 			fprintf(out, " =");
    184 			emit_qtype(stmt->out->type, false, out);
    185 			fprintf(out, " ");
    186 		}
    187 		fprintf(out, "%s%s", qbe_instr[stmt->instr],
    188 				stmt->args ? " " : "");
    189 		struct qbe_arguments *arg = stmt->args;
    190 		while (arg) {
    191 			fprintf(out, "%s", arg == stmt->args ? "" : ", ");
    192 			emit_value(&arg->value, out);
    193 			arg = arg->next;
    194 		}
    195 		fprintf(out, "\n");
    196 		break;
    197 	case Q_LABEL:
    198 		fprintf(out, "@%s\n", stmt->label);
    199 		break;
    200 	}
    201 }
    202 
    203 static void
    204 emit_func(struct qbe_def *def, FILE *out)
    205 {
    206 	assert(def->kind == Q_FUNC);
    207 	fprintf(out, "section \".text.%s\" \"ax\"%s\nfunction",
    208 			def->name,
    209 			def->exported ? " export" : "");
    210 	if (def->func.returns->stype != Q__VOID) {
    211 		fprintf(out, " ");
    212 		emit_qtype(def->func.returns, true, out);
    213 	}
    214 	fprintf(out, " $%s(", def->name);
    215 	struct qbe_func_param *param = def->func.params;
    216 	while (param) {
    217 		emit_qtype(param->type, true, out);
    218 		fprintf(out, " %%%s", param->name);
    219 		if (param->next) {
    220 			fprintf(out, ", ");
    221 		}
    222 		param = param->next;
    223 	}
    224 	if (def->func.variadic) {
    225 		fprintf(out, ", ...");
    226 	}
    227 	fprintf(out, ") {\n");
    228 
    229 	for (size_t i = 0; i < def->func.prelude.ln; ++i) {
    230 		struct qbe_statement *stmt = &def->func.prelude.stmts[i];
    231 		emit_stmt(stmt, out);
    232 	}
    233 
    234 	for (size_t i = 0; i < def->func.body.ln; ++i) {
    235 		struct qbe_statement *stmt = &def->func.body.stmts[i];
    236 		emit_stmt(stmt, out);
    237 	}
    238 
    239 	fprintf(out, "}\n\n");
    240 }
    241 
    242 static void
    243 emit_data_string(const char *str, size_t sz, FILE *out)
    244 {
    245 	bool q = false;
    246 	for (size_t i = 0; i < sz; ++i) {
    247 		/* XXX: We could stand to emit less conservatively */
    248 		if (!isprint((unsigned char)(str[i])) || str[i] == '"'
    249 				|| str[i] == '\\') {
    250 			if (q) {
    251 				q = false;
    252 				fprintf(out, "\", ");
    253 			}
    254 			fprintf(out, "b %d%s", str[i], i + 1 < sz ? ", " : "");
    255 		} else {
    256 			if (!q) {
    257 				q = true;
    258 				fprintf(out, "b \"");
    259 			}
    260 			fprintf(out, "%c", str[i]);
    261 		}
    262 	}
    263 	if (q) {
    264 		fprintf(out, "\"");
    265 	}
    266 }
    267 
    268 static bool
    269 is_zeroes(struct qbe_data_item *data)
    270 {
    271 	for (struct qbe_data_item *cur = data; cur; cur = cur->next) {
    272 		switch (cur->type) {
    273 		case QD_ZEROED:
    274 			break;
    275 		case QD_VALUE:
    276 			switch (cur->value.kind) {
    277 			case QV_CONST:
    278 				if (cur->value.lval != 0) {
    279 					return false;
    280 				}
    281 				break;
    282 			case QV_GLOBAL:
    283 			case QV_LABEL:
    284 			case QV_TEMPORARY:
    285 				return false;
    286 			case QV_VARIADIC:
    287 				abort();
    288 			}
    289 			break;
    290 		case QD_STRING:
    291 			for (size_t i = 0; i < cur->sz; ++i) {
    292 				if (cur->str[i] != 0) {
    293 					return false;
    294 				}
    295 			}
    296 			break;
    297 		case QD_SYMOFFS:
    298 			return false;
    299 		}
    300 	}
    301 	return true;
    302 }
    303 
    304 static void
    305 emit_data(struct qbe_def *def, FILE *out)
    306 {
    307 	assert(def->kind == Q_DATA);
    308 	if (def->data.section && def->data.secflags) {
    309 		fprintf(out, "section \"%s\" \"%s\"",
    310 				def->data.section, def->data.secflags);
    311 	} else if (def->data.section) {
    312 		fprintf(out, "section \"%s\"", def->data.section);
    313 	} else if (is_zeroes(&def->data.items)) {
    314 		fprintf(out, "section \".bss.%s\"", def->name);
    315 	} else {
    316 		fprintf(out, "section \".data.%s\"", def->name);
    317 	}
    318 	fprintf(out, "%s\ndata $%s = ", def->exported ? " export" : "",
    319 			def->name);
    320 	if (def->data.align != ALIGN_UNDEFINED) {
    321 		fprintf(out, "align %lu ", def->data.align);
    322 	}
    323 	fprintf(out, "{ ");
    324 
    325 	struct qbe_data_item *item = &def->data.items;
    326 	while (item) {
    327 		switch (item->type) {
    328 		case QD_VALUE:
    329 			emit_qtype(item->value.type, true, out);
    330 			fprintf(out, " ");
    331 			emit_value(&item->value, out);
    332 			break;
    333 		case QD_ZEROED:
    334 			fprintf(out, "z %zu", item->zeroed);
    335 			break;
    336 		case QD_STRING:
    337 			emit_data_string(item->str, item->sz, out);
    338 			break;
    339 		case QD_SYMOFFS:
    340 			// XXX: ARCH
    341 			fprintf(out, "l $%s + %ld", item->sym, item->offset);
    342 			break;
    343 		}
    344 
    345 		fprintf(out, item->next ? ", " : " ");
    346 		item = item->next;
    347 	}
    348 
    349 	fprintf(out, "}\n\n");
    350 }
    351 
    352 static void
    353 emit_def(struct qbe_def *def, FILE *out)
    354 {
    355 	switch (def->kind) {
    356 	case Q_TYPE:
    357 		qemit_type(def, out);
    358 		break;
    359 	case Q_FUNC:
    360 		emit_func(def, out);
    361 		break;
    362 	case Q_DATA:
    363 		emit_data(def, out);
    364 		break;
    365 	}
    366 }
    367 
    368 void
    369 emit(struct qbe_program *program, FILE *out)
    370 {
    371 	struct qbe_def *def = program->defs;
    372 	while (def) {
    373 		emit_def(def, out);
    374 		def = def->next;
    375 	}
    376 }