icfp12/ovm/ovm.c
2009-06-26 23:13:17 +02:00

169 lines
4.5 KiB
C

#include "ovm.h"
#include <glib/gstdio.h>
void ovm_free(ovm_t *ovm) {
if (!ovm) return;
g_slice_free1(ovm->limit * sizeof(instruction_t), ovm->instructions);
g_slice_free1(ovm->limit * sizeof(gdouble), ovm->values);
g_slice_free(ovm_t, ovm);
}
ovm_t* ovm_load(const gchar *filename) {
GError *err = NULL;
gchar *buf = NULL, *cur;
gsize len = 0, i;
instruction_t *oi;
gdouble *vi;
ovm_t *ovm = g_slice_new(ovm_t);
ovm->limit = 0x4000;
ovm->instructions = g_slice_alloc0(ovm->limit * sizeof(instruction_t));
ovm->values = g_slice_alloc0(ovm->limit * sizeof(gdouble));
if (!g_file_get_contents(filename, &buf, &len, &err)) {
fprintf (stderr, "Unable to read file: %s\n", err->message);
g_error_free (err);
exit(1);
}
oi = ovm->instructions;
vi = ovm->values;
for (cur = buf, i = 0; i < len; i++) {
*vi++ = *(gdouble*)buf;
buf += sizeof(gdouble);
*oi++ = *(guint32*)buf;
buf += sizeof(guint32);
if (++i < len) {
*oi++ = *(guint32*)buf;
buf += sizeof(guint32);
*vi++ = *(gdouble*)buf;
buf += sizeof(gdouble);
} else {
break;
}
}
ovm->used = i;
return ovm;
}
static const gchar* cmp_op_strings[] = {
"<", "<=", "==", ">=", ">"
};
void ovm_print_c(ovm_t *ovm, const gchar *filename) {
guint i;
instruction_t *oi = ovm->instructions;
gdouble *vi = ovm->values;
guint64 *uvi = (guint64*) ovm->values;
guchar *usedv = g_slice_alloc0(ovm->used*sizeof(guchar));
GString *str = g_string_sized_new(0), *buf = g_string_sized_new(0);
int f = g_open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0644);
if (-1 == f) {
fprintf(stderr, "Couldn't open file %s: %s\n", filename, g_strerror(errno));
exit(2);
}
g_string_append_len(buf, CONST_STR_LEN(
"void ovm_step(gdouble scenario, gdouble *in, gdouble *out) {\n"
));
#define USED(i) (usedv[i] = TRUE, i)
for (i = 0; i < ovm->used; i++) {
g_string_printf(str, "\t/* Invalid command: 0x%X */\n", (guint) oi[i]);
switch (instr_dop(oi[i])) {
case OP_STYPE:
switch (instr_sop(oi[i])) {
case SOP_NOOP:
g_string_printf(str, "/* NOOP */\n");
g_string_truncate(str, 0);
break;
case SOP_CMPZ:
g_string_printf(str, "\tovm_status = (v%u.d %s 0.0);\n", USED(instr_sop_r1(oi[i])), cmp_op_strings[instr_sop_cmp(oi[i])]);
break;
case SOP_SQRT:
g_string_printf(str, "\tv%u.d = sqrt(v%u.d);\n", USED(i), USED(instr_sop_r1(oi[i])));
break;
case SOP_COPY:
g_string_printf(str, "\tv%u.d = v%u.d;\n", USED(i), USED(instr_sop_r1(oi[i])));
break;
case SOP_IN:
if (0x3e80 == instr_sop_r1(oi[i])) {
g_string_printf(str, "\tv%u.d = scenario;\n", USED(i));
} else {
g_string_printf(str, "\tv%u.d = in[%u];\n", USED(i), instr_sop_r1(oi[i]));
}
break;
}
break;
case OP_ADD:
g_string_printf(str, "\tv%u.d = v%u.d + v%u.d;\n", USED(i), USED(instr_dop_r1(oi[i])), USED(instr_dop_r2(oi[i])));
break;
case OP_SUB:
g_string_printf(str, "\tv%u.d = v%u.d - v%u.d;\n", USED(i), USED(instr_dop_r1(oi[i])), USED(instr_dop_r2(oi[i])));
break;
case OP_MULT:
g_string_printf(str, "\tv%u.d = v%u.d * v%u.d;\n", USED(i), USED(instr_dop_r1(oi[i])), USED(instr_dop_r2(oi[i])));
break;
case OP_DIV:
g_string_printf(str, "\tv%u.d = (v%u.d == 0.0) ? 0.0 : v%u.d / v%u.d;\n", USED(i), USED(instr_dop_r2(oi[i])), USED(instr_dop_r1(oi[i])), instr_dop_r2(oi[i]));
break;
case OP_OUT:
g_string_printf(str, "\tout[%u] = v%u.d;\n", instr_dop_r1(oi[i]), USED(instr_dop_r2(oi[i])));
break;
case OP_PHI:
g_string_printf(str, "\tv%u.d = ovm_status ? v%u.d : v%u.d;\n", USED(i), USED(instr_dop_r1(oi[i])), USED(instr_dop_r2(oi[i])));
break;
}
g_string_append_len(buf, GSTR_LEN(str));
}
#undef USED
g_string_append_len(buf, CONST_STR_LEN(
"}\n"
"\n"
));
write(f, CONST_STR_LEN(
"#include \"task.h\"\n"
"#include <math.h>\n"
"\n"
"typedef union { gdouble d; guint64 i; } double_int;\n"
"\n"
"static gboolean ovm_status = FALSE;\n"
"\n"
"static double_int v0"
));
for (i = 1; i < ovm->used; i++) {
if (!usedv[i]) continue;
g_string_printf(str, ", v%u", i);
write(f, GSTR_LEN(str));
}
write(f, CONST_STR_LEN(
";\n"
"\n"
"void ovm_init() {\n"
"\tovm_status = FALSE;\n"
"\n"
));
for (i = 0; i < ovm->used; i++) {
if (!usedv[i]) continue;
g_string_printf(str, "\tv%u.i = G_GUINT64_CONSTANT(%" G_GUINT64_FORMAT "); /* %f */ \n", i, uvi[i], vi[i]);
write(f, GSTR_LEN(str));
}
write(f, CONST_STR_LEN(
"}\n"
"\n"
));
write(f, GSTR_LEN(buf));
close(f);
g_string_free(str, TRUE);
g_string_free(buf, TRUE);
}