harec

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

emit.c (7892B)


      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 		if (val->threadlocal) {
    123 			fprintf(out, "thread ");
    124 		}
    125 		fprintf(out, "$%s", val->name);
    126 		break;
    127 	case QV_LABEL:
    128 		fprintf(out, "@%s", val->name);
    129 		break;
    130 	case QV_TEMPORARY:
    131 		fprintf(out, "%%%s", val->name);
    132 		break;
    133 	case QV_VARIADIC:
    134 		fprintf(out, "...");
    135 		break;
    136 	}
    137 }
    138 
    139 static void
    140 emit_call(struct qbe_statement *stmt, FILE *out)
    141 {
    142 	fprintf(out, "%s ", qbe_instr[stmt->instr]);
    143 
    144 	struct qbe_arguments *arg = stmt->args;
    145 	assert(arg);
    146 	emit_value(&arg->value, out);
    147 	fprintf(out, "(");
    148 	arg = arg->next;
    149 
    150 	bool comma = false;
    151 	while (arg) {
    152 		fprintf(out, "%s", comma ? ", " : "");
    153 		if (arg->value.kind != QV_VARIADIC) {
    154 			emit_qtype(arg->value.type, true, out);
    155 			fprintf(out, " ");
    156 		}
    157 		emit_value(&arg->value, out);
    158 		arg = arg->next;
    159 		comma = true;
    160 	}
    161 
    162 	fprintf(out, ")\n");
    163 }
    164 
    165 static void
    166 emit_stmt(struct qbe_statement *stmt, FILE *out)
    167 {
    168 	switch (stmt->type) {
    169 	case Q_COMMENT:
    170 		fprintf(out, "\t# %s\n", stmt->comment);
    171 		break;
    172 	case Q_INSTR:
    173 		fprintf(out, "\t");
    174 		if (stmt->instr == Q_CALL) {
    175 			if (stmt->out != NULL) {
    176 				emit_value(stmt->out, out);
    177 				fprintf(out, " =");
    178 				emit_qtype(stmt->out->type, true, out);
    179 				fprintf(out, " ");
    180 			}
    181 			emit_call(stmt, out);
    182 			break;
    183 		}
    184 		if (stmt->out != NULL) {
    185 			emit_value(stmt->out, out);
    186 			fprintf(out, " =");
    187 			emit_qtype(stmt->out->type, false, out);
    188 			fprintf(out, " ");
    189 		}
    190 		fprintf(out, "%s%s", qbe_instr[stmt->instr],
    191 				stmt->args ? " " : "");
    192 		struct qbe_arguments *arg = stmt->args;
    193 		while (arg) {
    194 			fprintf(out, "%s", arg == stmt->args ? "" : ", ");
    195 			emit_value(&arg->value, out);
    196 			arg = arg->next;
    197 		}
    198 		fprintf(out, "\n");
    199 		break;
    200 	case Q_LABEL:
    201 		fprintf(out, "@%s\n", stmt->label);
    202 		break;
    203 	}
    204 }
    205 
    206 static void
    207 emit_func(struct qbe_def *def, FILE *out)
    208 {
    209 	assert(def->kind == Q_FUNC);
    210 	fprintf(out, "section \".text.%s\" \"ax\"%s\nfunction",
    211 			def->name,
    212 			def->exported ? " export" : "");
    213 	if (def->func.returns->stype != Q__VOID) {
    214 		fprintf(out, " ");
    215 		emit_qtype(def->func.returns, true, out);
    216 	}
    217 	fprintf(out, " $%s(", def->name);
    218 	struct qbe_func_param *param = def->func.params;
    219 	while (param) {
    220 		emit_qtype(param->type, true, out);
    221 		fprintf(out, " %%%s", param->name);
    222 		if (param->next) {
    223 			fprintf(out, ", ");
    224 		}
    225 		param = param->next;
    226 	}
    227 	if (def->func.variadic) {
    228 		fprintf(out, ", ...");
    229 	}
    230 	fprintf(out, ") {\n");
    231 
    232 	for (size_t i = 0; i < def->func.prelude.ln; ++i) {
    233 		struct qbe_statement *stmt = &def->func.prelude.stmts[i];
    234 		emit_stmt(stmt, out);
    235 	}
    236 
    237 	for (size_t i = 0; i < def->func.body.ln; ++i) {
    238 		struct qbe_statement *stmt = &def->func.body.stmts[i];
    239 		emit_stmt(stmt, out);
    240 	}
    241 
    242 	fprintf(out, "}\n\n");
    243 }
    244 
    245 static void
    246 emit_data_string(const char *str, size_t sz, FILE *out)
    247 {
    248 	bool q = false;
    249 	for (size_t i = 0; i < sz; ++i) {
    250 		/* XXX: We could stand to emit less conservatively */
    251 		if (!isprint((unsigned char)(str[i])) || str[i] == '"'
    252 				|| str[i] == '\\') {
    253 			if (q) {
    254 				q = false;
    255 				fprintf(out, "\", ");
    256 			}
    257 			fprintf(out, "b %d%s", str[i], i + 1 < sz ? ", " : "");
    258 		} else {
    259 			if (!q) {
    260 				q = true;
    261 				fprintf(out, "b \"");
    262 			}
    263 			fprintf(out, "%c", str[i]);
    264 		}
    265 	}
    266 	if (q) {
    267 		fprintf(out, "\"");
    268 	}
    269 }
    270 
    271 static bool
    272 is_zeroes(struct qbe_data_item *data)
    273 {
    274 	for (struct qbe_data_item *cur = data; cur; cur = cur->next) {
    275 		switch (cur->type) {
    276 		case QD_ZEROED:
    277 			break;
    278 		case QD_VALUE:
    279 			switch (cur->value.kind) {
    280 			case QV_CONST:
    281 				if (cur->value.lval != 0) {
    282 					return false;
    283 				}
    284 				break;
    285 			case QV_GLOBAL:
    286 			case QV_LABEL:
    287 			case QV_TEMPORARY:
    288 				return false;
    289 			case QV_VARIADIC:
    290 				abort();
    291 			}
    292 			break;
    293 		case QD_STRING:
    294 			for (size_t i = 0; i < cur->sz; ++i) {
    295 				if (cur->str[i] != 0) {
    296 					return false;
    297 				}
    298 			}
    299 			break;
    300 		case QD_SYMOFFS:
    301 			return false;
    302 		}
    303 	}
    304 	return true;
    305 }
    306 
    307 static void
    308 emit_data(struct qbe_def *def, FILE *out)
    309 {
    310 	assert(def->kind == Q_DATA);
    311 	if (def->data.section && def->data.secflags) {
    312 		fprintf(out, "section \"%s\" \"%s\"",
    313 				def->data.section, def->data.secflags);
    314 	} else if (def->data.section) {
    315 		fprintf(out, "section \"%s\"", def->data.section);
    316 	} else if (def->data.threadlocal) {
    317 		if (is_zeroes(&def->data.items)) {
    318 			fprintf(out, "section \".tbss\" \"awT\"");
    319 		} else {
    320 			fprintf(out, "section \".tdata\" \"awT\"");
    321 		}
    322 	} else if (is_zeroes(&def->data.items)) {
    323 		fprintf(out, "section \".bss.%s\"", def->name);
    324 	} else {
    325 		fprintf(out, "section \".data.%s\"", def->name);
    326 	}
    327 	fprintf(out, "%s\ndata $%s = ", def->exported ? " export" : "",
    328 			def->name);
    329 	if (def->data.align != ALIGN_UNDEFINED) {
    330 		fprintf(out, "align %zu ", def->data.align);
    331 	}
    332 	fprintf(out, "{ ");
    333 
    334 	struct qbe_data_item *item = &def->data.items;
    335 	while (item) {
    336 		switch (item->type) {
    337 		case QD_VALUE:
    338 			emit_qtype(item->value.type, true, out);
    339 			fprintf(out, " ");
    340 			emit_value(&item->value, out);
    341 			break;
    342 		case QD_ZEROED:
    343 			fprintf(out, "z %zu", item->zeroed);
    344 			break;
    345 		case QD_STRING:
    346 			emit_data_string(item->str, item->sz, out);
    347 			break;
    348 		case QD_SYMOFFS:
    349 			// XXX: ARCH
    350 			fprintf(out, "l $%s + %ld", item->sym, item->offset);
    351 			break;
    352 		}
    353 
    354 		fprintf(out, item->next ? ", " : " ");
    355 		item = item->next;
    356 	}
    357 
    358 	fprintf(out, "}\n\n");
    359 }
    360 
    361 static void
    362 emit_def(struct qbe_def *def, FILE *out)
    363 {
    364 	switch (def->kind) {
    365 	case Q_TYPE:
    366 		qemit_type(def, out);
    367 		break;
    368 	case Q_FUNC:
    369 		emit_func(def, out);
    370 		break;
    371 	case Q_DATA:
    372 		emit_data(def, out);
    373 		break;
    374 	}
    375 }
    376 
    377 void
    378 emit(struct qbe_program *program, FILE *out)
    379 {
    380 	struct qbe_def *def = program->defs;
    381 	while (def) {
    382 		emit_def(def, out);
    383 		def = def->next;
    384 	}
    385 }