if (op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) {
self->expression.vtype = TYPE_FLOAT;
} else
- compile_error(ctx, "cannot determine type of unary operation %s", asm_instr[op].m);
+ compile_error(ctx, "cannot determine type of unary operation %s", util_instr_str[op]);
return self;
}
for (;;) {
if (code->statements[j].opcode != INSTR_DONE)
util_debug("GEN", " %-12s {% 5i,% 5i,% 5i}\n",
- asm_instr[code->statements[j].opcode].m,
+ util_instr_str[code->statements[j].opcode],
code->statements[j].o1.s1,
code->statements[j].o2.s1,
code->statements[j].o3.s1
}
static void prog_print_statement(qc_program *prog, prog_section_statement *st) {
- if (st->opcode >= (sizeof(asm_instr)/sizeof(asm_instr[0]))) {
+ if (st->opcode >= VINSTR_END) {
printf("<illegal instruction %d>\n", st->opcode);
return;
}
printf("->");
printf("%s:", vec_last(prog->function_stack));
}
- printf(" <> %-12s", asm_instr[st->opcode].m);
+ printf(" <> %-12s", util_instr_str[st->opcode]);
if (st->opcode >= INSTR_IF &&
st->opcode <= INSTR_IFNOT)
{
/*=========================== code.c ================================*/
/*===================================================================*/
-/* TODO: cleanup */
/* Note: if you change the order, fix type_sizeof in ir.c */
enum {
TYPE_VOID ,
VINSTR_NRCALL
};
+/* TODO: elide */
+extern const char *util_instr_str[VINSTR_END];
+
/* uhh? */
typedef float qcfloat;
typedef int32_t qcint;
bool GMQCC_WARN vcompile_warning(lex_ctx ctx, int warntype, const char *fmt, va_list ap);
void compile_show_werrors(void);
-/*===================================================================*/
-/*========================= assembler.c =============================*/
-/*===================================================================*/
-/* TODO: remove this ... */
-static const struct {
- const char *m; /* menomic */
- const size_t o; /* operands */
- const size_t l; /* menomic len */
-} asm_instr[] = {
- { "DONE" , 1, 4 },
- { "MUL_F" , 3, 5 },
- { "MUL_V" , 3, 5 },
- { "MUL_FV" , 3, 6 },
- { "MUL_VF" , 3, 6 },
- { "DIV" , 0, 3 },
- { "ADD_F" , 3, 5 },
- { "ADD_V" , 3, 5 },
- { "SUB_F" , 3, 5 },
- { "SUB_V" , 3, 5 },
- { "EQ_F" , 0, 4 },
- { "EQ_V" , 0, 4 },
- { "EQ_S" , 0, 4 },
- { "EQ_E" , 0, 4 },
- { "EQ_FNC" , 0, 6 },
- { "NE_F" , 0, 4 },
- { "NE_V" , 0, 4 },
- { "NE_S" , 0, 4 },
- { "NE_E" , 0, 4 },
- { "NE_FNC" , 0, 6 },
- { "LE" , 0, 2 },
- { "GE" , 0, 2 },
- { "LT" , 0, 2 },
- { "GT" , 0, 2 },
- { "FIELD_F" , 0, 7 },
- { "FIELD_V" , 0, 7 },
- { "FIELD_S" , 0, 7 },
- { "FIELD_ENT" , 0, 9 },
- { "FIELD_FLD" , 0, 9 },
- { "FIELD_FNC" , 0, 9 },
- { "ADDRESS" , 0, 7 },
- { "STORE_F" , 0, 7 },
- { "STORE_V" , 0, 7 },
- { "STORE_S" , 0, 7 },
- { "STORE_ENT" , 0, 9 },
- { "STORE_FLD" , 0, 9 },
- { "STORE_FNC" , 0, 9 },
- { "STOREP_F" , 0, 8 },
- { "STOREP_V" , 0, 8 },
- { "STOREP_S" , 0, 8 },
- { "STOREP_ENT", 0, 10},
- { "STOREP_FLD", 0, 10},
- { "STOREP_FNC", 0, 10},
- { "RETURN" , 0, 6 },
- { "NOT_F" , 0, 5 },
- { "NOT_V" , 0, 5 },
- { "NOT_S" , 0, 5 },
- { "NOT_ENT" , 0, 7 },
- { "NOT_FNC" , 0, 7 },
- { "IF" , 0, 2 },
- { "IFNOT" , 0, 5 },
- { "CALL0" , 1, 5 },
- { "CALL1" , 2, 5 },
- { "CALL2" , 3, 5 },
- { "CALL3" , 4, 5 },
- { "CALL4" , 5, 5 },
- { "CALL5" , 6, 5 },
- { "CALL6" , 7, 5 },
- { "CALL7" , 8, 5 },
- { "CALL8" , 9, 5 },
- { "STATE" , 0, 5 },
- { "GOTO" , 0, 4 },
- { "AND" , 0, 3 },
- { "OR" , 0, 2 },
- { "BITAND" , 0, 6 },
- { "BITOR" , 0, 5 },
-
- { "END" , 0, 3 } /* virtual assembler instruction */
-};
/*===================================================================*/
/*============================= ir.c ================================*/
/*===================================================================*/
{
irerror(self->context, "cannot store to an SSA value");
irerror(self->context, "trying to store: %s <- %s", target->name, what->name);
- irerror(self->context, "instruction: %s", asm_instr[op].m);
+ irerror(self->context, "instruction: %s", util_instr_str[op]);
return false;
}
static const char *qc_opname(int op)
{
if (op < 0) return "<INVALID>";
- if (op < (int)( sizeof(asm_instr) / sizeof(asm_instr[0]) ))
- return asm_instr[op].m;
+ if (op < VINSTR_END)
+ return util_instr_str[op];
switch (op) {
+ case VINSTR_END: return "END";
case VINSTR_PHI: return "PHI";
case VINSTR_JUMP: return "JUMP";
case VINSTR_COND: return "COND";
#include "gmqcc.h"
+/*
+ * Initially this was handled with a table in the gmqcc.h header, but
+ * much to my surprise the contents of the table was duplicated for
+ * each translation unit, causing all these strings to be duplicated
+ * for every .c file it was included into. This method culls back on
+ * it. This is a 'utility' function because the executor also depends
+ * on this for dissasembled bytecode.
+ */
+const char *util_instr_str[VINSTR_END] = {
+ "DONE", "MUL_F", "MUL_V", "MUL_FV",
+ "MUL_VF", "DIV_F", "ADD_F", "ADD_V",
+ "SUB_F", "SUB_V", "EQ_F", "EQ_V",
+ "EQ_S", "EQ_E", "EQ_FNC", "NE_F",
+ "NE_V", "NE_S", "NE_E", "NE_FNC",
+ "LE", "GE", "LT", "GT",
+ "LOAD_F", "LOAD_V", "LOAD_S", "LOAD_ENT",
+ "LOAD_FLD", "LOAD_FNC", "ADDRESS", "STORE_F",
+ "STORE_V", "STORE_S", "STORE_ENT", "STORE_FLD",
+ "STORE_FNC", "STOREP_F", "STOREP_V", "STOREP_S",
+ "STOREP_ENT", "STOREP_FLD", "STOREP_FNC", "RETURN",
+ "NOT_F", "NOT_V", "NOT_S", "NOT_ENT",
+ "NOT_FNC", "IF", "IFNOT", "CALL0",
+ "CALL1", "CALL2", "CALL3", "CALL4",
+ "CALL5", "CALL6", "CALL7", "CALL8",
+ "STATE", "GOTO", "AND", "OR",
+ "BITAND", "BITOR"
+};
+
void util_debug(const char *area, const char *ms, ...) {
va_list va;
if (!OPTS_OPTION_BOOL(OPTION_DEBUG))