aoc-2019-c

Advent of Code 2019 Solutions in C
git clone https://git.sinitax.com/sinitax/aoc-2019-c
Log | Files | Refs | README | sfeed.txt

iccmp.c (14328B)


      1#include "iccmp.h"
      2#include "allocator.h"
      3#include "aoc.h"
      4#include "hmap.h"
      5#include "maxint.h"
      6#include "util.h"
      7
      8#include <assert.h>
      9#include <stdbool.h>
     10#include <stdint.h>
     11
     12const char *icc_err[] = {
     13	[ICC_OK] = "ok",
     14	[ICC_INV_INST] = "invalid instruction",
     15	[ICC_OOB_WRITE] = "write addr oob",
     16	[ICC_OOB_READ] = "read addr oob",
     17};
     18
     19static struct maxint *
     20mi_tmp(int64_t val)
     21{
     22	static mi_ul data = 0;
     23	static struct maxint m = { &data, 1, 1, MI_POS };
     24
     25	data = (mi_ul) ABS(val);
     26	m.sign = val >= 0 ? MI_POS : MI_NEG;
     27
     28	return &m;
     29}
     30
     31static bool
     32icc_hmap_keycmp(struct hmap_key k1, struct hmap_key k2)
     33{
     34	return mi_cmp(k1.p, k2.p) == 0;
     35}
     36
     37static uint32_t
     38icc_hmap_hash(struct hmap_key key)
     39{
     40	return (uint32_t) mi_cast_ul(key.p);
     41}
     42
     43void
     44icc_init(struct icc *icc)
     45{
     46	int rc;
     47
     48	icc->state = ICC_RUN;
     49
     50	icc->debug = getenv("ICC_DEBUG") != NULL;
     51
     52	mi_init(&icc->rip);
     53	mi_setv(&icc->rip, 0, MI_POS);
     54
     55	mi_init(&icc->base);
     56	mi_setv(&icc->base, 0, MI_POS);
     57
     58	mi_init(&icc->in);
     59	mi_init(&icc->out);
     60	mi_init(&icc->read_addr);
     61	mi_init(&icc->write_addr);
     62
     63	mi_init(&icc->r1);
     64	mi_init(&icc->r2);
     65	mi_init(&icc->r3);
     66	mi_init(&icc->r4);
     67	mi_init(&icc->tmp);
     68
     69	icc->abort_on_err = true;
     70
     71	icc->line_terminated = true;
     72
     73	rc = hmap_init(&icc->instructions, 1024, icc_hmap_hash,
     74		icc_hmap_keycmp, &stdlib_strict_heap_allocator);
     75	assert(!rc);
     76}
     77
     78void
     79icc_deinit(struct icc *icc)
     80{
     81	struct hmap_iter iter;
     82
     83	mi_deinit(&icc->rip);
     84	mi_deinit(&icc->base);
     85	mi_deinit(&icc->in);
     86	mi_deinit(&icc->out);
     87	mi_deinit(&icc->read_addr);
     88	mi_deinit(&icc->write_addr);
     89	mi_deinit(&icc->r1);
     90	mi_deinit(&icc->r2);
     91	mi_deinit(&icc->r3);
     92	mi_deinit(&icc->r4);
     93	mi_deinit(&icc->tmp);
     94
     95	for (HMAP_ITER(&icc->instructions, iter)) {
     96		mi_deinit(iter.link->key._p);
     97		free(iter.link->key._p);
     98		mi_deinit(iter.link->value._p);
     99		free(iter.link->value._p);
    100	}
    101
    102	hmap_deinit(&icc->instructions);
    103}
    104
    105void
    106icc_copy(struct icc *dst, struct icc *src)
    107{
    108	struct hmap_iter hmap_iter;
    109	struct maxint *key, *value;
    110
    111	dst->state = src->state;
    112	mi_set(&dst->rip, &src->rip);
    113	mi_set(&dst->base, &src->base);
    114	mi_set(&dst->in, &src->in);
    115	mi_set(&dst->out, &src->out);
    116
    117	for (HMAP_ITER(&dst->instructions, hmap_iter)) {
    118		mi_deinit(hmap_iter.link->key._p);
    119		free(hmap_iter.link->key._p);
    120		mi_deinit(hmap_iter.link->value._p);
    121		free(hmap_iter.link->value._p);
    122	}
    123	hmap_clear(&dst->instructions);
    124
    125	for (HMAP_ITER(&src->instructions, hmap_iter)) {
    126		key = malloc(sizeof(struct maxint));
    127		mi_init(key);
    128		mi_set(key, hmap_iter.link->key.p);
    129		value = malloc(sizeof(struct maxint));
    130		mi_init(value);
    131		mi_set(value, hmap_iter.link->value.p);
    132		hmap_add(&dst->instructions, (struct hmap_key) {.p = key},
    133			(struct hmap_val) {.p = value});
    134	}
    135}
    136
    137void
    138icc_reset(struct icc *icc, struct hmap *inst)
    139{
    140	int rc;
    141
    142	icc->state = ICC_RUN;
    143	mi_setv(&icc->rip, 0, MI_POS);
    144	mi_setv(&icc->base, 0, MI_POS);
    145	if (inst) {
    146		rc = hmap_copy(&icc->instructions, inst);
    147		assert(!rc);
    148	}
    149}
    150
    151void
    152icc_parse_inst(struct icc *icc, const char *str, size_t len)
    153{
    154	struct maxint *key, *val;
    155	const char *pos, *end;
    156	char buf[256];
    157	int64_t v;
    158	int rc, rip;
    159
    160	pos = str;
    161	end = str + len;
    162	rip = 0;
    163	while (readtok(buf, sizeof(buf), ',', &pos, end)) {
    164		v = parsei64(buf);
    165
    166		key = malloc(sizeof(struct maxint));
    167		assert(key != NULL);
    168		mi_init(key);
    169		mi_setv(key, (mi_ul) rip, MI_POS);
    170
    171		val = malloc(sizeof(struct maxint));
    172		assert(val != NULL);
    173		mi_init(val);
    174		mi_setv(val, (mi_ul) ABS(v), v >= 0 ? MI_POS : MI_NEG);
    175
    176		rc = hmap_add(&icc->instructions, (struct hmap_key) {.p = key},
    177			(struct hmap_val) {.p = val});
    178		assert(!rc);
    179
    180		rip += 1;
    181	}
    182}
    183
    184const char *
    185icc_literal_str(struct icc *icc, struct maxint *addr, size_t zfill)
    186{
    187	static char buf[64];
    188
    189	mi_dec(addr, buf, sizeof(buf), zfill);
    190
    191	return buf;
    192}
    193
    194const char *
    195icc_value_str(struct icc *icc, struct maxint *addr, size_t zfill)
    196{
    197	static char buf[62];
    198	struct maxint *val;
    199	int rc;
    200
    201	rc = icc_read(icc, addr, &val);
    202	if (rc) {
    203		snprintf(buf, sizeof(buf), "???");
    204	} else {
    205		mi_dec(val, buf, sizeof(buf), zfill);
    206	}
    207
    208	return buf;
    209}
    210
    211static void
    212icc_debug_op_pre(struct icc *icc)
    213{
    214	if (!icc->debug) return;
    215
    216	fprintf(stderr, "%*s: ", 5, icc_literal_str(icc, &icc->rip, 0));
    217	fprintf(stderr, "(%*s) ", 5, icc_value_str(icc, &icc->rip, 5));
    218	icc->line_terminated = false;
    219}
    220
    221static void
    222icc_debug_op_main(struct icc *icc, struct maxint *tmp, const char *opstr, int n)
    223{
    224	struct maxint *inst, *val;
    225	int i, rc, instint;
    226
    227	if (!icc->debug) return;
    228
    229	rc = icc_read(icc, &icc->rip, &inst);
    230	assert(!rc);
    231
    232	fprintf(stderr, "%s ", opstr);
    233	icc->line_terminated = false;
    234
    235	mi_set(tmp, &icc->rip);
    236	instint = (int) mi_cast_ul(inst);
    237	for (i = 1; i <= n; i++) {
    238		if (i > 1) fprintf(stderr, ", ");
    239		mi_add(tmp, tmp, mi_tmp(1));
    240		rc = icc_read(icc, tmp, &val);
    241		if (rc) {
    242			fprintf(stderr, "???");
    243			continue;
    244		}
    245		switch (icc_param_mode(instint, i)) {
    246		case ICC_PARAM_IMM:
    247			fprintf(stderr, "%s", icc_literal_str(icc, val, 0));
    248			break;
    249		case ICC_PARAM_POS:
    250			fprintf(stderr, "[%s]=%s", icc_literal_str(icc, val, 0),
    251				icc_value_str(icc, val, 0));
    252			break;
    253		case ICC_PARAM_REL:
    254			mi_add(tmp, &icc->base, val);
    255			fprintf(stderr, "[%s+", icc_literal_str(icc, &icc->base, 0));
    256			fprintf(stderr, "%s", icc_literal_str(icc, val, 0));
    257			fprintf(stderr, "=%s]=%s", icc_literal_str(icc, tmp, 0),
    258				icc_value_str(icc, tmp, 0));
    259			break;
    260		default:
    261			assert(0);
    262		}
    263	}
    264}
    265
    266static void
    267icc_debug_op_post(struct icc *icc, struct maxint *addr)
    268{
    269	if (!icc->debug) return;
    270
    271	fprintf(stderr, " -> [%s]=%s\n", icc_literal_str(icc, addr, 0),
    272		icc_value_str(icc, addr, 0));
    273	icc->line_terminated = true;
    274}
    275
    276static void
    277icc_debug_op(struct icc *icc, struct maxint *tmp, const char *opstr, int n)
    278{
    279	if (!icc->debug) return;
    280
    281	icc_debug_op_main(icc, tmp, opstr, n);
    282	fprintf(stderr, "\n");
    283	icc->line_terminated = true;
    284}
    285
    286int
    287icc_inst_add(struct icc *icc)
    288{
    289	struct maxint *dst;
    290	int rc;
    291
    292	icc_debug_op_main(icc, &icc->tmp, "ADD", 3);
    293
    294	rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1);
    295	if (rc) return rc;
    296	rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2);
    297	if (rc) return rc;
    298	rc = icc_get_dest(icc, &icc->tmp, 3, &icc->r3);
    299	if (rc) return rc;
    300
    301	mi_add(&icc->tmp, &icc->r1, &icc->r2);
    302	rc = icc_write(icc, &icc->r3, &icc->tmp);
    303	if (rc) return rc;
    304
    305	icc_debug_op_post(icc, dst);
    306
    307	mi_add(&icc->rip, &icc->rip, mi_tmp(4));
    308	icc->state = ICC_RUN;
    309
    310	return 0;
    311}
    312
    313int
    314icc_inst_mul(struct icc *icc)
    315{
    316	int rc;
    317
    318	icc_debug_op_main(icc, &icc->tmp, "MUL", 3);
    319
    320	rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1);
    321	if (rc) return rc;
    322	rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2);
    323	if (rc) return rc;
    324	rc = icc_get_dest(icc, &icc->tmp, 3, &icc->r3);
    325	if (rc) return rc;
    326
    327	mi_mul(&icc->tmp, &icc->r1, &icc->r2);
    328	rc = icc_write(icc, &icc->r3, &icc->tmp);
    329	if (rc) return rc;
    330
    331	icc_debug_op_post(icc, &icc->r3);
    332
    333	mi_add(&icc->rip, &icc->rip, mi_tmp(4));
    334	icc->state = ICC_RUN;
    335
    336	return 0;
    337}
    338
    339int
    340icc_inst_store(struct icc *icc)
    341{
    342	int rc;
    343
    344	if (icc->state != ICC_INPUT || !icc->in.size) {
    345		icc_debug_op(icc, &icc->tmp, "INPUT", 0);
    346		icc->state = ICC_INPUT;
    347		icc->in.size = 0;
    348	} else {
    349		icc_debug_op_main(icc, &icc->tmp, "STORE", 1);
    350
    351		rc = icc_get_dest(icc, &icc->tmp, 1, &icc->r1);
    352		if (rc) return rc;
    353
    354		rc = icc_write(icc, &icc->r1, &icc->in);
    355		if (rc) return rc;
    356
    357		icc_debug_op_post(icc, &icc->r1);
    358
    359		mi_add(&icc->rip, &icc->rip, mi_tmp(2));
    360		icc->state = ICC_RUN;
    361	}
    362
    363	return 0;
    364}
    365
    366int
    367icc_inst_load(struct icc *icc)
    368{
    369	int rc;
    370
    371	if (icc->state != ICC_OUTPUT) {
    372		icc_debug_op(icc, &icc->tmp, "LOAD", 1);
    373
    374		rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1);
    375		if (rc) return rc;
    376
    377		mi_set(&icc->out, &icc->r1);
    378		icc->state = ICC_OUTPUT;
    379
    380		icc_debug_op(icc, &icc->tmp, "OUTPUT", 0);
    381	} else {
    382		mi_add(&icc->rip, &icc->rip, mi_tmp(2));
    383		icc->state = ICC_RUN;
    384	}
    385
    386	return 0;
    387}
    388
    389int
    390icc_inst_jmp_true(struct icc *icc)
    391{
    392	int rc;
    393
    394	icc_debug_op(icc, &icc->tmp, "JMPT", 2);
    395
    396	rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1);
    397	if (rc) return rc;
    398	rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2);
    399	if (rc) return rc;
    400
    401	if (!mi_zero(&icc->r1)) {
    402		mi_set(&icc->rip, &icc->r2);
    403	} else {
    404		mi_add(&icc->rip, &icc->rip, mi_tmp(3));
    405	}
    406
    407	icc->state = ICC_RUN;
    408
    409	return 0;
    410}
    411
    412int
    413icc_inst_jmp_false(struct icc *icc)
    414{
    415	int rc;
    416
    417	icc_debug_op(icc, &icc->tmp, "JMPF", 2);
    418
    419	rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1);
    420	if (rc) return rc;
    421	rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2);
    422	if (rc) return rc;
    423
    424	if (mi_zero(&icc->r1)) {
    425		mi_set(&icc->rip, &icc->r2);
    426	} else {
    427		mi_add(&icc->rip, &icc->rip, mi_tmp(3));
    428	}
    429
    430	icc->state = ICC_RUN;
    431
    432	return 0;
    433}
    434
    435int
    436icc_inst_test_lt(struct icc *icc)
    437{
    438	int rc;
    439
    440	icc_debug_op_main(icc, &icc->tmp, "TLT", 3);
    441
    442	rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1);
    443	if (rc) return rc;
    444	rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2);
    445	if (rc) return rc;
    446	rc = icc_get_dest(icc, &icc->tmp, 3, &icc->r3);
    447	if (rc) return rc;
    448
    449	mi_setv(&icc->tmp, mi_cmp(&icc->r1, &icc->r2) == -1, MI_POS);
    450	rc = icc_write(icc, &icc->r3, &icc->tmp);
    451	if (rc) return rc;
    452
    453	icc_debug_op_post(icc, &icc->r3);
    454
    455	mi_add(&icc->rip, &icc->rip, mi_tmp(4));
    456	icc->state = ICC_RUN;
    457
    458	return 0;
    459}
    460
    461int
    462icc_inst_test_eq(struct icc *icc)
    463{
    464	int rc;
    465
    466	icc_debug_op_main(icc, &icc->tmp, "TEQ", 3);
    467
    468	rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1);
    469	if (rc) return rc;
    470	rc = icc_get_param(icc, &icc->tmp, 2, &icc->r2);
    471	if (rc) return rc;
    472	rc = icc_get_dest(icc, &icc->tmp, 3, &icc->r3);
    473	if (rc) return rc;
    474
    475	mi_setv(&icc->tmp, mi_cmp(&icc->r1, &icc->r2) == 0, MI_POS);
    476	rc = icc_write(icc, &icc->r3, &icc->tmp);
    477	if (rc) return rc;
    478
    479	icc_debug_op_post(icc, &icc->r3);
    480
    481	mi_add(&icc->rip, &icc->rip, mi_tmp(4));
    482	icc->state = ICC_RUN;
    483
    484	return 0;
    485}
    486
    487int
    488icc_inst_base(struct icc *icc)
    489{
    490	int rc;
    491
    492	icc_debug_op_main(icc, &icc->tmp, "BASE", 1);
    493
    494	rc = icc_get_param(icc, &icc->tmp, 1, &icc->r1);
    495	if (rc) return rc;
    496
    497	mi_add(&icc->base, &icc->base, &icc->r1);
    498	mi_add(&icc->rip, &icc->rip, mi_tmp(2));
    499	icc->state = ICC_RUN;
    500
    501	if (icc->debug) {
    502		fprintf(stderr, " -> BASE:%s\n",
    503			icc_literal_str(icc, &icc->base, 0));
    504		icc->line_terminated = true;
    505	}
    506
    507	return 0;
    508}
    509
    510int
    511icc_inst_halt(struct icc *icc)
    512{
    513	icc_debug_op(icc, &icc->tmp, "HALT", 0);
    514
    515	icc->state = ICC_HALT;
    516
    517	return 0;
    518}
    519
    520int
    521icc_step_inst(struct icc *icc)
    522{
    523	struct maxint *inst;
    524	int rc;
    525
    526	icc_debug_op_pre(icc);
    527
    528	rc = icc_read(icc, &icc->rip, &inst);
    529	if (rc) return rc;
    530
    531	switch (mi_cast_ul(inst) % 100) {
    532	case ICC_INST_ADD:
    533		rc = icc_inst_add(icc);
    534		break;
    535	case ICC_INST_MULT:
    536		rc = icc_inst_mul(icc);
    537		break;
    538	case ICC_INST_STORE:
    539		rc = icc_inst_store(icc);
    540		break;
    541	case ICC_INST_LOAD:
    542		rc = icc_inst_load(icc);
    543		break;
    544	case ICC_INST_JMPT:
    545		rc = icc_inst_jmp_true(icc);
    546		break;
    547	case ICC_INST_JMPF:
    548		rc = icc_inst_jmp_false(icc);
    549		break;
    550	case ICC_INST_TLT:
    551		rc = icc_inst_test_lt(icc);
    552		break;
    553	case ICC_INST_TEQ:
    554		rc = icc_inst_test_eq(icc);
    555		break;
    556	case ICC_INST_BASE:
    557		rc = icc_inst_base(icc);
    558		break;
    559	case ICC_INST_HALT:
    560		rc = icc_inst_halt(icc);
    561		break;
    562	default:
    563		rc = ICC_INV_INST;
    564		break;
    565	}
    566
    567	if (icc->debug) {
    568		if (!icc->line_terminated) {
    569			fprintf(stderr, "\n");
    570			icc->line_terminated = true;
    571		}
    572		if (rc != ICC_OK)
    573			fprintf(stderr, " -- error: %s --\n", icc_err[rc]);
    574	}
    575
    576	return rc;
    577}
    578
    579struct hmap_link *
    580icc_write_any(struct icc *icc, struct maxint *addr, struct maxint *value)
    581{
    582	struct hmap_link **link;
    583	struct maxint *key, *val;
    584
    585	link = hmap_link_pos(&icc->instructions, (struct hmap_key) {.p = addr});
    586	if (*link) {
    587		mi_set((*link)->value._p, value);
    588	} else {
    589		key = malloc(sizeof(struct maxint));
    590		assert(key != NULL);
    591		mi_init(key);
    592		mi_set(key, addr);
    593
    594		val = malloc(sizeof(struct maxint));
    595		assert(val != NULL);
    596		mi_init(val);
    597		mi_set(val, value);
    598
    599		*link = hmap_link_alloc(&icc->instructions,
    600			(struct hmap_key) {.p = key},
    601			(struct hmap_val) {.p = val}, NULL);
    602	}
    603
    604	return *link;
    605}
    606
    607int
    608icc_write(struct icc *icc, struct maxint *addr, struct maxint *val)
    609{
    610	struct hmap_link *link;
    611
    612	link = hmap_get(&icc->instructions, (struct hmap_key) {.p = addr});
    613	if (!link) {
    614		if (addr->sign != MI_POS) {
    615			mi_set(&icc->read_addr, addr);
    616			assert(!icc->abort_on_err);
    617			return ICC_OOB_READ;
    618		}
    619
    620		icc_write_any(icc, addr, val);
    621	} else {
    622		mi_set(link->value._p, val);
    623	}
    624
    625	return 0;
    626}
    627
    628int
    629icc_read(struct icc *icc, struct maxint *addr, struct maxint **out)
    630{
    631	struct hmap_link *link;
    632
    633	link = hmap_get(&icc->instructions, (struct hmap_key) {.p = addr});
    634	if (!link) {
    635		if (addr->sign != MI_POS) {
    636			mi_set(&icc->read_addr, addr);
    637			assert(!icc->abort_on_err);
    638			return ICC_OOB_READ;
    639		}
    640
    641		link = icc_write_any(icc, addr, mi_tmp(0));
    642	}
    643	*out = link->value._p;
    644
    645	return 0;
    646}
    647
    648int
    649icc_param_mode(int inst, int param)
    650{
    651	int div, i;
    652
    653	div = 100;
    654	for (i = 1; i < param; i++) div *= 10;
    655
    656	return (inst / div) % 10;
    657}
    658
    659int
    660icc_get_param(struct icc *icc, struct maxint *tmp, int param, struct maxint *out)
    661{
    662	struct maxint *inst, *val, *val2;
    663	int rc;
    664
    665	/* TODO: make out double pointer and optimize out mi_set */
    666
    667	rc = icc_read(icc, &icc->rip, &inst);
    668	if (rc) return rc;
    669
    670	mi_setv(tmp, (mi_ul) ABS(param), param >= 0 ? MI_POS : MI_NEG);
    671	mi_add(tmp, tmp, &icc->rip);
    672	rc = icc_read(icc, tmp, &val);
    673	if (rc) return rc;
    674
    675	assert(mi_lastset(inst) == 0);
    676	switch (icc_param_mode((int) mi_cast_ul(inst), param)) {
    677	case ICC_PARAM_IMM:
    678		mi_set(out, val);
    679		break;
    680	case ICC_PARAM_POS:
    681		rc = icc_read(icc, val, &val2);
    682		if (rc) return rc;
    683		mi_set(out, val2);
    684		break;
    685	case ICC_PARAM_REL:
    686		mi_add(tmp, &icc->base, val);
    687		rc = icc_read(icc, tmp, &val2);
    688		mi_set(out, val2);
    689		break;
    690	default:
    691		assert(0);
    692	};
    693
    694	return 0;
    695}
    696
    697int
    698icc_get_dest(struct icc *icc, struct maxint *tmp, int param, struct maxint *out)
    699{
    700	struct maxint *inst, *val;
    701	int rc;
    702
    703	rc = icc_read(icc, &icc->rip, &inst);
    704	if (rc) return rc;
    705
    706	mi_setv(tmp, (mi_ul) ABS(param), param >= 0 ? MI_POS : MI_NEG);
    707	mi_add(tmp, tmp, &icc->rip);
    708	rc = icc_read(icc, tmp, &val);
    709	if (rc) return rc;
    710
    711	switch (icc_param_mode((int) mi_cast_ul(inst), param)) {
    712	case ICC_PARAM_POS:
    713		mi_set(out, val);
    714		break;
    715	case ICC_PARAM_REL:
    716		mi_add(out, &icc->base, val);
    717		break;
    718	default:
    719		assert(0);
    720	}
    721
    722	return 0;
    723}
    724
    725void
    726icc_debug_print(struct icc *icc, struct maxint *addr)
    727{
    728	if (!icc->debug) return;
    729
    730	fprintf(stderr, "[%s] = %s\n", icc_literal_str(icc, addr, 0),
    731		icc_value_str(icc, addr, 0));
    732}
    733