From c1753046a91305e67df62e6abe12339daad2c6d0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 26 Jun 2001 07:21:20 +0000 Subject: [PATCH] start on actually generating code. doesn't work yet (getting a weird type redeclaration error and not all expressions are handled yet). --- tools/qfcc/include/expr.h | 2 + tools/qfcc/include/qfcc.h | 7 + tools/qfcc/source/expr.c | 252 +++++++++++++++++++++++++++++++++- tools/qfcc/source/pr_imm.c | 99 +++++++++++++ tools/qfcc/source/pr_lex.c | 4 + tools/qfcc/source/pr_opcode.c | 13 +- tools/qfcc/source/qc-lex.l | 1 - tools/qfcc/source/qc-parse.y | 6 +- 8 files changed, 378 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 0399239ea..398f097c2 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -55,3 +55,5 @@ void print_expr (expr_t *e); expr_t *binary_expr (int op, expr_t *e1, expr_t *e2); expr_t *unary_expr (int op, expr_t *e); expr_t *function_expr (expr_t *e1, expr_t *e2); + +void emit_expr (expr_t *e); diff --git a/tools/qfcc/include/qfcc.h b/tools/qfcc/include/qfcc.h index cd2abd5cd..68e9debbb 100644 --- a/tools/qfcc/include/qfcc.h +++ b/tools/qfcc/include/qfcc.h @@ -329,6 +329,7 @@ extern type_t type_field; extern type_t type_function; extern type_t type_pointer; extern type_t type_floatfield; +extern type_t type_quaternion; extern def_t def_void; extern def_t def_string; @@ -338,6 +339,7 @@ extern def_t def_entity; extern def_t def_field; extern def_t def_function; extern def_t def_pointer; +extern def_t def_quaternion; struct function_s { @@ -390,6 +392,8 @@ extern opcode_t *op_ifnot; extern opcode_t *op_state; extern opcode_t *op_goto; +statref_t *PR_NewStatref (dstatement_t *st, int field); +void PR_AddStatementRef (def_t *def, dstatement_t *st, int field); def_t *PR_Statement (opcode_t *op, def_t *var_a, def_t *var_b); opcode_t *PR_Opcode_Find (const char *name, int priority, def_t *var_a, def_t *var_b, def_t *var_c); @@ -398,6 +402,8 @@ void PR_Opcode_Init (void); //============================================================================ +#include "expr.h" + extern qboolean pr_dumpasm; @@ -426,6 +432,7 @@ void PR_LexString (void); type_t *PR_ParseType (void); char *PR_ParseName (void); def_t *PR_ParseImmediate (def_t *def); +def_t *PR_ReuseConstant (expr_t *expr, def_t *def); qboolean PR_Check (token_type_t type, const char *string); void PR_Expect (token_type_t type, const char *string); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 34a35ecfe..90e63fe3b 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1,9 +1,9 @@ #include #include +#include #include "qfcc.h" -#include "expr.h" #include "scope.h" #include "qc-parse.h" @@ -34,6 +34,17 @@ static type_t *types[] = { &type_pointer, }; +static expr_type expr_types[] = { + ex_label, // ev_void (ick) + ex_string, // ev_string + ex_float, // ev_float + ex_vector, // ev_vector + ex_label, // ev_entity (ick) + ex_label, // ev_field (ick) + ex_label, // ev_func (ick) + ex_label, // ev_pointer (ick) +}; + static etype_t get_type (expr_t *e) { @@ -630,3 +641,242 @@ function_expr (expr_t *e1, expr_t *e2) e->e.expr.e2 = e2; return e; } + +def_t * +emit_statement (opcode_t *op, def_t *var_a, def_t *var_b, def_t *var_c) +{ + dstatement_t *statement; + + statement = &statements[numstatements]; + numstatements++; + statement_linenums[statement - statements] = pr_source_line; + statement->op = op->opcode; + statement->a = var_a ? var_a->ofs : 0; + statement->b = var_b ? var_b->ofs : 0; + if (op->type_c == &def_void || op->right_associative) { + // ifs, gotos, and assignments don't need vars allocated + var_c = NULL; + statement->c = 0; + } else { // allocate result space + if (!var_c) + var_c = PR_GetTempDef (op->type_c->type, pr_scope); + statement->c = var_c->ofs; + } + PR_AddStatementRef (var_a, statement, 0); + PR_AddStatementRef (var_b, statement, 1); + PR_AddStatementRef (var_c, statement, 2); + + if (op->right_associative) + return var_a; + return var_c; +} + +def_t *emit_sub_expr (expr_t *e, def_t *dest); + +def_t * +emit_function_call (expr_t *e, def_t *dest) +{ + def_t *func = emit_sub_expr (e->e.expr.e1, 0); + def_t *arg; + expr_t *earg; + opcode_t *op; + int count = 0, ind; + + for (earg = e->e.expr.e2; earg; earg = earg->next) + count++; + ind = count; + for (earg = e->e.expr.e2; earg; earg = earg->next) { + ind--; + arg = emit_sub_expr (earg, 0); + def_parms[ind].type = arg->type; + op = PR_Opcode_Find ("=", 5, arg, &def_parms[ind], &def_parms[ind]); + emit_statement (op, arg, &def_parms[ind], 0); + } + op = PR_Opcode_Find (va ("", count), -1, &def_function, &def_void, &def_void); + emit_statement (op, func, 0, dest); + + def_ret.type = func->type->aux_type; + return &def_ret; +} + +def_t * +emit_sub_expr (expr_t *e, def_t *dest) +{ + opcode_t *op; + char *operator; + def_t *def_a, *def_b; + int priority; + + if (e->type == ex_expr && e->e.expr.op == 'c') + return emit_function_call (e, dest); + + switch (e->type) { + default: + case ex_label: + case ex_block: + abort (); + case ex_expr: + def_a = emit_sub_expr (e->e.expr.e1, 0); + def_b = emit_sub_expr (e->e.expr.e2, 0); + switch (e->e.expr.op) { + case AND: + operator = "&&"; + priority = 6; + break; + case OR: + operator = "||"; + priority = 6; + break; + case '=': + operator = "="; + priority = 6; + break; + case EQ: + operator = "=="; + priority = 4; + break; + case NE: + operator = "!="; + priority = 4; + break; + case LE: + operator = "<="; + priority = 4; + break; + case GE: + operator = ">="; + priority = 4; + break; + case LT: + operator = "<"; + priority = 4; + break; + case GT: + operator = ">"; + priority = 4; + break; + case '+': + operator = "+"; + priority = 3; + break; + case '-': + operator = "-"; + priority = 3; + break; + case '*': + operator = "*"; + priority = 2; + break; + case '/': + operator = "/"; + priority = 2; + break; + case '&': + operator = "&"; + priority = 2; + break; + case '|': + operator = "|"; + priority = 2; + break; + case '.': + operator = "."; + priority = 1; + break; + default: + abort (); + } + op = PR_Opcode_Find (operator, priority, def_a, def_b, dest); + return emit_statement (op, def_a, def_b, dest); + case ex_uexpr: + if (e->e.expr.op == '!') { + operator = "!"; + priority = -1; + def_a = emit_sub_expr (e->e.expr.e1, 0); + def_b = &def_void; + } else if (e->e.expr.op == '-') { + static expr_t zero; + + zero.type = expr_types[get_type (e->e.expr.e1)]; + + operator = "-"; + priority = 3; + def_a = PR_ReuseConstant (&zero, 0); + def_b = emit_sub_expr (e->e.expr.e1, 0); + } else { + abort (); + } + op = PR_Opcode_Find (operator, priority, def_a, def_b, dest); + return emit_statement (op, def_a, def_b, dest); + case ex_def: + return e->e.def; + case ex_int: + case ex_float: + case ex_string: + case ex_vector: + case ex_quaternion: + return PR_ReuseConstant (e, 0); + } +} + +void +emit_expr (expr_t *e) +{ + def_t *def; + statref_t *ref; + dstatement_t *st; + + switch (e->type) { + case ex_label: + break; + case ex_block: + for (e = e->e.block.head; e; e = e->next) + emit_expr (e); + break; + case ex_expr: + switch (e->e.expr.op) { + case '=': + break; + case 'n': + break; + case 'i': + break; + case 'c': + break; + default: + fprintf (stderr, + "%s:%d: warning: unused expression ignored\n", + strings + s_file, pr_source_line); + } + break; + case ex_uexpr: + switch (e->e.expr.op) { + case 'r': + def = 0; + if (e->e.expr.e1) + def = emit_sub_expr (e->e.expr.e1, 0); + PR_Statement (op_return, def, 0); + return; + case 'g': + st = &statements[numstatements]; + PR_Statement (op_goto, 0, 0); + if (e->e.label.statement) { + st->a = e->e.label.statement - st; + } else { + ref = PR_NewStatref (st, 0); + ref->next = e->e.label.refs; + e->e.label.refs = ref; + } + return; + } + case ex_def: + case ex_int: + case ex_float: + case ex_string: + case ex_vector: + case ex_quaternion: + fprintf (stderr, "%s:%d: warning: unused expression ignored\n", + strings + s_file, pr_source_line); + break; + } +} diff --git a/tools/qfcc/source/pr_imm.c b/tools/qfcc/source/pr_imm.c index 5bd17fe8a..c3287291b 100644 --- a/tools/qfcc/source/pr_imm.c +++ b/tools/qfcc/source/pr_imm.c @@ -27,6 +27,7 @@ static hashtab_t *string_imm_defs; static hashtab_t *float_imm_defs; static hashtab_t *vector_imm_defs; +static hashtab_t *quaternion_imm_defs; static const char * string_imm_get_key (void *_def, void *unused) @@ -54,6 +55,17 @@ vector_imm_get_key (void *_def, void *unused) return rep; } +static const char * +quaternion_imm_get_key (void *_def, void *unused) +{ + def_t *def = (def_t*)_def; + static char rep[60]; + sprintf (rep, "\001quaternion:%08X\001%08X\001%08X\001%08X\001", + G_INT(def->ofs), G_INT(def->ofs+1), + G_INT(def->ofs+2), G_INT(def->ofs+3)); + return rep; +} + /* PR_ParseImmediate @@ -131,3 +143,90 @@ PR_ParseImmediate (def_t *def) return cn; } + +def_t * +PR_ReuseConstant (expr_t *e, def_t *def) +{ + def_t *cn = 0; + char rep[60]; + hashtab_t *tab = 0; + type_t *type; + + if (!string_imm_defs) { + string_imm_defs = Hash_NewTable (16381, string_imm_get_key, 0, 0); + float_imm_defs = Hash_NewTable (16381, float_imm_get_key, 0, 0); + vector_imm_defs = Hash_NewTable (16381, vector_imm_get_key, 0, 0); + quaternion_imm_defs = Hash_NewTable (16381, quaternion_imm_get_key, 0, 0); + } + switch (e->type) { + case ex_int: + e->e.float_val = e->e.int_val; //FIXME + case ex_float: + sprintf (rep, "\001float:%08X\001", *(int*)&pr_immediate._float); + cn = (def_t*) Hash_Find (float_imm_defs, rep); + tab = float_imm_defs; + type = &type_float; + //printf ("%f\n",pr_immediate._float); + break; + case ex_string: + cn = (def_t*) Hash_Find (string_imm_defs, pr_immediate_string); + tab = string_imm_defs; + type = &type_string; + //printf ("%s\n",pr_immediate_string); + break; + case ex_vector: + sprintf (rep, "\001vector:%08X\001%08X\001%08X\001", + *(int*)&e->e.vector_val[0], + *(int*)&e->e.vector_val[1], + *(int*)&e->e.vector_val[2]); + cn = (def_t*) Hash_Find (vector_imm_defs, rep); + tab = vector_imm_defs; + type = &type_vector; + //printf ("%f %f %f\n",pr_immediate.vector[0], pr_immediate.vector[1], pr_immediate.vector[2]); + break; + case ex_quaternion: + sprintf (rep, "\001quaternion:%08X\001%08X\001%08X\001%08X\001", + *(int*)&e->e.quaternion_val[0], + *(int*)&e->e.quaternion_val[1], + *(int*)&e->e.quaternion_val[2], + *(int*)&e->e.quaternion_val[3]); + cn = (def_t*) Hash_Find (quaternion_imm_defs, rep); + tab = vector_imm_defs; + type = &type_quaternion; + //printf ("%f %f %f\n",pr_immediate.vector[0], pr_immediate.vector[1], pr_immediate.vector[2]); + break; + default: + abort (); + } + if (cn) { + //printf("found\n"); + if (def) { + PR_FreeLocation (def); + def->ofs = cn->ofs; + def->initialized = 1; + cn = def; + } + return cn; + } + // allocate a new one + // always share immediates + if (def) { + cn = def; + } else { + cn = PR_NewDef (pr_immediate_type, "IMMEDIATE", 0); + cn->ofs = PR_NewLocation (pr_immediate_type); + pr_global_defs[cn->ofs] = cn; + } + cn->initialized = 1; + // copy the immediate to the global area + if (e->type == ex_string) + e->e.int_val = CopyString (e->e.string_val); + + memcpy (pr_globals + cn->ofs, &e->e, 4 * type_size[type->type]); + + Hash_Add (tab, cn); + + PR_Lex (); + + return cn; +} diff --git a/tools/qfcc/source/pr_lex.c b/tools/qfcc/source/pr_lex.c index 156b79c4e..61de07365 100644 --- a/tools/qfcc/source/pr_lex.c +++ b/tools/qfcc/source/pr_lex.c @@ -60,6 +60,7 @@ type_t type_field = { ev_field, &def_field }; // type_function is a void() function used for state defs type_t type_function = { ev_func, &def_function, NULL, &type_void }; type_t type_pointer = { ev_pointer, &def_pointer }; +type_t type_quaternion = { ev_quaternion, &def_quaternion }; type_t type_floatfield = { ev_field, &def_field, NULL, &type_float }; @@ -73,6 +74,7 @@ def_t def_entity = { &type_entity, "temp" }; def_t def_field = { &type_field, "temp" }; def_t def_function = { &type_function, "temp" }; def_t def_pointer = { &type_pointer, "temp" }; +def_t def_quaternion = { &type_quaternion, "temp"}; def_t def_ret, def_parms[MAX_PARMS]; @@ -684,7 +686,9 @@ PR_ParseError (const char *error, ...) printf ("%s:%i:%s\n", strings + s_file, pr_source_line, string); +#ifndef NEW_PARSER longjmp (pr_parse_abort, 1); +#endif } diff --git a/tools/qfcc/source/pr_opcode.c b/tools/qfcc/source/pr_opcode.c index 69180d3d5..c1663a9e1 100644 --- a/tools/qfcc/source/pr_opcode.c +++ b/tools/qfcc/source/pr_opcode.c @@ -131,15 +131,22 @@ opcode_t pr_opcodes[] = { {"|", "BITOR", OP_BITOR, 2, false, &def_float, &def_float, &def_float, PROG_ID_VERSION}, }; +statref_t * +PR_NewStatref (dstatement_t *st, int field) +{ + statref_t *ref = calloc (1, sizeof (statref_t)); + ref->statement = st; + ref->field = field; + return ref; +} + void PR_AddStatementRef (def_t *def, dstatement_t *st, int field) { if (def) { - statref_t *ref = calloc (1, sizeof (statref_t)); + statref_t *ref = PR_NewStatref (st, field); ref->next = def->refs; def->refs = ref; - ref->statement = st; - ref->field = field; } } diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 7cfd3aa9f..fa24c42b0 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -1,7 +1,6 @@ %{ #include #include "qfcc.h" -#include "expr.h" #include "scope.h" #include "qc-parse.h" diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 78bb0be3a..85cb64054 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1,6 +1,5 @@ %{ #include "qfcc.h" -#include "expr.h" #define YYDEBUG 1 #define YYERROR_VERBOSE 1 @@ -538,6 +537,11 @@ build_function (function_t *f) void emit_function (function_t *f, expr_t *e) { + pr_scope = f->def; + while (e) { + emit_expr (e); + e = e->next; + } /*PR_PrintType (f->def->type); printf (" %s =\n", f->def->name); while (e) {