From 1559dedfd9d417d50bcbbcd809357c06b07d43b2 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 15:41:10 +0200 Subject: [PATCH 01/24] ir_value_set_field --- ir.c | 9 +++++++++ ir.h | 1 + 2 files changed, 10 insertions(+) diff --git a/ir.c b/ir.c index 05a46d4..d007321 100644 --- a/ir.c +++ b/ir.c @@ -646,6 +646,15 @@ bool ir_value_set_vector(ir_value *self, vector v) return true; } +bool ir_value_set_field(ir_value *self, ir_value *fld) +{ + if (self->vtype != TYPE_FIELD) + return false; + self->constval.vpointer = fld; + self->isconst = true; + return true; +} + bool ir_value_set_string(ir_value *self, const char *str) { if (self->vtype != TYPE_STRING) diff --git a/ir.h b/ir.h index e36aa08..dccc970 100644 --- a/ir.h +++ b/ir.h @@ -95,6 +95,7 @@ bool GMQCC_WARN ir_value_set_int(ir_value*, int i); #endif bool GMQCC_WARN ir_value_set_string(ir_value*, const char *s); bool GMQCC_WARN ir_value_set_vector(ir_value*, vector v); +bool GMQCC_WARN ir_value_set_field(ir_value*, ir_value *fld); /*bool ir_value_set_pointer_v(ir_value*, ir_value* p); */ /*bool ir_value_set_pointer_i(ir_value*, int i); */ From f51ad966205fb7f9592dc7aaba4a58a52cfaa36b Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 15:41:37 +0200 Subject: [PATCH 02/24] removing an unused variable --- ast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ast.c b/ast.c index c19fad2..4c90821 100644 --- a/ast.c +++ b/ast.c @@ -940,7 +940,7 @@ bool ast_entfield_codegen(ast_entfield *self, ast_function *func, bool lvalue, i bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_value **out) { ast_expression_codegen *cgen; - ir_value *vec, *field; + ir_value *vec; cgen = self->owner->expression.codegen; if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec)) From 04db054466b6bfd05299cb2f25e4b3923d8823ea Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 16:08:38 +0200 Subject: [PATCH 03/24] -std=gmqcc should add a dot prefix to the globals for fields, the field itself doesn't use the dot prefix for its name though --- ir.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/ir.c b/ir.c index d007321..d831176 100644 --- a/ir.c +++ b/ir.c @@ -2570,13 +2570,42 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field) def.type = field->vtype; def.offset = code_globals_elements; - def.name = field->code.name = code_genstring(field->name); + + /* create a global named the same as the field */ + if (opts_standard == COMPILER_GMQCC) { + /* in our standard, the global gets a dot prefix */ + size_t len = strlen(field->name); + char name[1024]; + + /* we really don't want to have to allocate this, and 1024 + * bytes is more than enough for a variable/field name + */ + if (len+2 >= sizeof(name)) { + printf("invalid field name size: %u\n", (unsigned int)len); + return false; + } + + name[0] = '.'; + strcpy(name+1, field->name); /* no strncpy - we used strlen above */ + name[len+1] = 0; + + def.name = code_genstring(name); + fld.name = def.name + 1; /* we reuse that string table entry */ + } else { + /* in plain QC, there cannot be a global with the same name, + * and so we also name the global the same. + * FIXME: fteqcc should create a global as well + * check if it actually uses the same name. Probably does + */ + def.name = code_genstring(field->name); + fld.name = def.name; + } + + field->code.name = def.name; if (code_defs_add(def) < 0) return false; - fld.name = def.name; - fld.offset = code_fields_elements; fld.type = field->fieldtype; if (fld.type == TYPE_VOID) { @@ -2584,10 +2613,12 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field) return false; } + fld.offset = code_alloc_field(type_sizeof[field->fieldtype]); + if (code_fields_add(fld) < 0) return false; - if (!code_globals_add(code_alloc_field(type_sizeof[field->fieldtype]))) + if (!code_globals_add(fld.offset)) return false; ir_value_code_setaddr(field, code_globals_add(fld.offset)); From 805c08e91475489453a80135f2157eb3a0f52a01 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 16:10:33 +0200 Subject: [PATCH 04/24] ast macros to create a field, generating fields in ast-test --- test/ast-macros.h | 11 +++++++++++ test/ast-test.c | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/test/ast-macros.h b/test/ast-macros.h index ebb3a5b..56df82e 100644 --- a/test/ast-macros.h +++ b/test/ast-macros.h @@ -21,6 +21,17 @@ name = ast_value_new(ctx, #varname, type) #define MKGLOBAL(name) \ assert(globals_add(name) >= 0) +#define FIELD(type, name) \ +name = ast_value_new(ctx, #name, TYPE_FIELD); \ +do { \ + ast_value *field_##name = ast_value_new(ctx, #name, type); \ + name->expression.next = (ast_expression*)field_##name; \ + MKFIELD(name); \ +} while (0) + +#define MKFIELD(name) \ +assert(fields_add(name) >= 0) + #define MKCONSTFLOAT(name, value) \ do { \ name->isconst = true; \ diff --git a/test/ast-test.c b/test/ast-test.c index 3862144..de01d89 100644 --- a/test/ast-test.c +++ b/test/ast-test.c @@ -10,6 +10,7 @@ #define assert(x) do { if ( !(x) ) { printf("Assertion failed: %s\n", #x); abort(); } } while(0) VECTOR_MAKE(ast_value*, globals); +VECTOR_MAKE(ast_value*, fields); VECTOR_MAKE(ast_function*, functions); uint32_t opts_flags[1 + (COUNT_FLAGS / 32)]; @@ -39,6 +40,8 @@ int main() DEFVAR(sHello); DEFVAR(print); + DEFVAR(mema); + /* opts_debug = true; */ BUILTIN(print, TYPE_VOID, -1); @@ -50,6 +53,7 @@ VAR(TYPE_FLOAT, f0); VAR(TYPE_FLOAT, f1); VAR(TYPE_FLOAT, f5); VAR(TYPE_STRING, sHello); +FIELD(TYPE_FLOAT, mema); MKCONSTFLOAT(f0, 0.0); MKCONSTFLOAT(f1, 1.0); MKCONSTFLOAT(f5, 5.0); @@ -81,6 +85,12 @@ ENDFUNCTION(main); ir = ir_builder_new("ast_test"); assert(ir); + /* gen fields */ + for (i = 0; i < fields_elements; ++i) { + if (!ast_global_codegen(fields_data[i], ir)) { + assert(!"failed to generate field"); + } + } /* gen globals */ for (i = 0; i < globals_elements; ++i) { if (!ast_global_codegen(globals_data[i], ir)) { From 7b36bbf7b26c54541142783250617bd4472a3a13 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 16:28:07 +0200 Subject: [PATCH 05/24] ast macros to use the return value of a call, trying to spawn an entity, setting a member, and reading the member back, using print+ftos to print it then --- test/ast-macros.h | 10 ++++++++++ test/ast-test.c | 26 ++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/test/ast-macros.h b/test/ast-macros.h index 56df82e..e11bd8d 100644 --- a/test/ast-macros.h +++ b/test/ast-macros.h @@ -58,6 +58,9 @@ do { \ #define BIN(op, a, b) \ (ast_expression*)ast_binary_new(ctx, INSTR_##op, (ast_expression*)(a), (ast_expression*)(b)) +#define ENTFIELD(a, b) \ +(ast_expression*)ast_entfield_new(ctx, (ast_expression*)(a), (ast_expression*)(b)) + #define CALL(what) \ do { \ ast_call *call = ast_call_new(ctx, (ast_expression*)what); \ @@ -69,6 +72,13 @@ do { \ STATE(call); \ } while(0) +#define ENDCALLWITH(as, where) \ + { \ + ast_expression *as = (ast_expression*)call; \ + where; \ + } \ +} while(0) + #define WHILE(cond) \ do { \ ast_expression *wh_cond = (ast_expression*)(cond); \ diff --git a/test/ast-test.c b/test/ast-test.c index de01d89..0db4a19 100644 --- a/test/ast-test.c +++ b/test/ast-test.c @@ -39,13 +39,23 @@ int main() DEFVAR(f5); DEFVAR(sHello); DEFVAR(print); + DEFVAR(ftos); + DEFVAR(spawn); DEFVAR(mema); + DEFVAR(pawn); /* opts_debug = true; */ BUILTIN(print, TYPE_VOID, -1); PARAM(TYPE_STRING, text); +ENDBUILTIN(); + +BUILTIN(ftos, TYPE_STRING, -2); +PARAM(TYPE_FLOAT, value); +ENDBUILTIN(); + +BUILTIN(spawn, TYPE_ENTITY, -3); ENDBUILTIN(); TESTINIT(); @@ -53,7 +63,10 @@ VAR(TYPE_FLOAT, f0); VAR(TYPE_FLOAT, f1); VAR(TYPE_FLOAT, f5); VAR(TYPE_STRING, sHello); +VAR(TYPE_ENTITY, pawn); + FIELD(TYPE_FLOAT, mema); + MKCONSTFLOAT(f0, 0.0); MKCONSTFLOAT(f1, 1.0); MKCONSTFLOAT(f5, 5.0); @@ -80,6 +93,19 @@ FUNCTION(main, TYPE_VOID); CALLPARAM(sHello) ENDCALL(); + CALL(spawn) + ENDCALLWITH(newent, STATE(ASSIGN(STORE_ENT, pawn, newent))); + + STATE(ASSIGN(STORE_F, ENTFIELD(pawn, mema), f5)); + + CALL(ftos) + CALLPARAM(ENTFIELD(pawn, mema)) + ENDCALLWITH(output, STATE(ASSIGN(STORE_F, vi, output))); + + CALL(print) + CALLPARAM(vi) + ENDCALL(); + ENDFUNCTION(main); ir = ir_builder_new("ast_test"); From 062449ecd6a6b174ab33788dbc291615335524c4 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 16:38:17 +0200 Subject: [PATCH 06/24] ir_block_create_store_op checks whether or not the storetype is an SSA value - do not do that for storeP instructions --- ir.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/ir.c b/ir.c index d831176..f9e9fd2 100644 --- a/ir.c +++ b/ir.c @@ -906,22 +906,26 @@ bool ir_values_overlap(const ir_value *a, const ir_value *b) bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what) { - if (target->store == store_value) { + ir_instr *in = ir_instr_new(self, op); + if (!in) + return false; + + if (target->store == store_value && + (op < INSTR_STOREP_F || op > INSTR_STOREP_FNC)) + { fprintf(stderr, "cannot store to an SSA value\n"); fprintf(stderr, "trying to store: %s <- %s\n", target->name, what->name); + fprintf(stderr, "instruction: %s\n", asm_instr[op].m); return false; - } else { - ir_instr *in = ir_instr_new(self, op); - if (!in) - return false; - if (!ir_instr_op(in, 0, target, true) || - !ir_instr_op(in, 1, what, false) || - !ir_block_instr_add(self, in) ) - { - return false; - } - return true; } + + if (!ir_instr_op(in, 0, target, true) || + !ir_instr_op(in, 1, what, false) || + !ir_block_instr_add(self, in) ) + { + return false; + } + return true; } bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what) From a661536c87e4cd2e7dd2198026020e06be3f4251 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 16:39:04 +0200 Subject: [PATCH 07/24] use the correct STORE instruction, make pawn a local --- test/ast-test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/ast-test.c b/test/ast-test.c index 0db4a19..7a80b91 100644 --- a/test/ast-test.c +++ b/test/ast-test.c @@ -63,7 +63,6 @@ VAR(TYPE_FLOAT, f0); VAR(TYPE_FLOAT, f1); VAR(TYPE_FLOAT, f5); VAR(TYPE_STRING, sHello); -VAR(TYPE_ENTITY, pawn); FIELD(TYPE_FLOAT, mema); @@ -79,9 +78,11 @@ FUNCTION(main, TYPE_VOID); VAR(TYPE_FLOAT, vi); VAR(TYPE_FLOAT, vx); + VAR(TYPE_ENTITY, pawn); MKLOCAL(vi); MKLOCAL(vx); + MKLOCAL(pawn); STATE(ASSIGN(STORE_F, vi, f0)); WHILE(BIN(LT, vi, f5)); @@ -96,8 +97,7 @@ FUNCTION(main, TYPE_VOID); CALL(spawn) ENDCALLWITH(newent, STATE(ASSIGN(STORE_ENT, pawn, newent))); - STATE(ASSIGN(STORE_F, ENTFIELD(pawn, mema), f5)); - + STATE(ASSIGN(STOREP_F, ENTFIELD(pawn, mema), f5)); CALL(ftos) CALLPARAM(ENTFIELD(pawn, mema)) ENDCALLWITH(output, STATE(ASSIGN(STORE_F, vi, output))); From 919d73b0a0167b53875d39eead37222e32aebbed Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 17:31:08 +0200 Subject: [PATCH 08/24] experimental support for spawn() in the executor --- exec.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++- execloop.h | 4 +- gmqcc.h | 1 + 3 files changed, 132 insertions(+), 3 deletions(-) diff --git a/exec.c b/exec.c index c65c6e2..363fb44 100644 --- a/exec.c +++ b/exec.c @@ -13,6 +13,7 @@ MEM_VEC_FUN_APPEND(qc_program, char, strings) MEM_VEC_FUN_RESIZE(qc_program, char, strings) MEM_VEC_FUNCTIONS(qc_program, qcint, globals) MEM_VEC_FUNCTIONS(qc_program, qcint, entitydata) +MEM_VEC_FUNCTIONS(qc_program, bool, entitypool) MEM_VEC_FUNCTIONS(qc_program, qcint, localstack) MEM_VEC_FUN_APPEND(qc_program, qcint, localstack) @@ -34,10 +35,20 @@ static void loaderror(const char *fmt, ...) printf(": %s\n", strerror(err)); } +static void printvmerr(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + putchar('\n'); +} + qc_program* prog_load(const char *filename) { qc_program *prog; prog_header header; + size_t i; FILE *file; file = fopen(filename, "rb"); @@ -108,6 +119,18 @@ qc_program* prog_load(const char *filename) if (!qc_program_strings_resize(prog, prog->strings_count + 16*1024)) goto error; + /* spawn the world entity */ + if (!qc_program_entitypool_add(prog, true)) { + loaderror("failed to allocate world entity\n"); + goto error; + } + for (i = 0; i < prog->entityfields; ++i) { + if (!qc_program_entitydata_add(prog, 0)) { + loaderror("failed to allocate world data\n"); + goto error; + } + } + return prog; error: @@ -119,6 +142,7 @@ error: if (prog->strings) mem_d(prog->strings); if (prog->globals) mem_d(prog->globals); if (prog->entitydata) mem_d(prog->entitydata); + if (prog->entitypool) mem_d(prog->entitypool); mem_d(prog); return NULL; } @@ -133,6 +157,7 @@ void prog_delete(qc_program *prog) MEM_VECTOR_CLEAR(prog, strings); MEM_VECTOR_CLEAR(prog, globals); MEM_VECTOR_CLEAR(prog, entitydata); + MEM_VECTOR_CLEAR(prog, entitypool); MEM_VECTOR_CLEAR(prog, localstack); MEM_VECTOR_CLEAR(prog, stack); MEM_VECTOR_CLEAR(prog, profile); @@ -177,7 +202,57 @@ prog_section_def* prog_getdef(qc_program *prog, qcint off) qcany* prog_getedict(qc_program *prog, qcint e) { - return (qcany*)(prog->entitydata + (prog->entityfields + e)); + if (e >= prog->entitypool_count) { + prog->vmerror++; + printf("Accessing out of bounds edict %i\n", (int)e); + e = 0; + } + return (qcany*)(prog->entitydata + (prog->entityfields * e)); +} + +qcint prog_spawn_entity(qc_program *prog) +{ + size_t i; + qcint e; + for (e = 0; e < (qcint)prog->entitypool_count; ++e) { + if (!prog->entitypool[e]) { + char *data = (char*)(prog->entitydata + (prog->entityfields * e)); + memset(data, 0, prog->entityfields * sizeof(qcint)); + return e; + } + } + if (!qc_program_entitypool_add(prog, true)) { + prog->vmerror++; + printf("Failed to allocate entity\n"); + return 0; + } + for (i = 0; i < prog->entityfields; ++i) { + if (!qc_program_entitydata_add(prog, 0)) { + printf("Failed to allocate entity\n"); + return 0; + } + } + return e; +} + +void prog_free_entity(qc_program *prog, qcint e) +{ + if (!e) { + prog->vmerror++; + printf("Trying to free world entity\n"); + return; + } + if (e >= prog->entitypool_count) { + prog->vmerror++; + printf("Trying to free out of bounds entity\n"); + return; + } + if (!prog->entitypool[e]) { + prog->vmerror++; + printf("Double free on entity\n"); + return; + } + prog->entitypool[e] = false; } qcint prog_tempstring(qc_program *prog, const char *_str) @@ -439,6 +514,8 @@ bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long long jumpcount = 0; prog_section_statement *st; + prog->vmerror = 0; + st = prog->code + prog_enterfunction(prog, func); --st; switch (flags) @@ -477,6 +554,8 @@ bool prog_exec(qc_program *prog, prog_section_function *func, size_t flags, long cleanup: prog->localstack_count = 0; prog->stack_count = 0; + if (prog->vmerror) + return false; return true; } @@ -488,6 +567,19 @@ cleanup: bool opts_debug = false; bool opts_memchk = false; +#define CheckArgs(num) do { \ + if (prog->argc != (num)) { \ + prog->vmerror++; \ + printf("ERROR: invalid number of arguments for %s: %i, expected %i\n", \ + __FUNCTION__, prog->argc, (num)); \ + return -1; \ + } \ +} while (0) + +#define GetGlobal(idx) ((qcany*)(prog->globals + (idx))) +#define GetArg(num) GetGlobal(OFS_PARM0 + 3*(num)) +#define Return(any) *(GetGlobal(OFS_RETURN)) = (any) + static int qc_print(qc_program *prog) { qcany *str = (qcany*)(prog->globals + OFS_PARM0); @@ -495,9 +587,43 @@ static int qc_print(qc_program *prog) return 0; } +static int qc_ftos(qc_program *prog) +{ + char buffer[512]; + qcany *num; + qcany str; + CheckArgs(1); + num = GetArg(0); + snprintf(buffer, sizeof(buffer), "%g", num->_float); + str.string = prog_tempstring(prog, buffer); + Return(str); + return 0; +} + +static int qc_spawn(qc_program *prog) +{ + qcany ent; + CheckArgs(0); + ent.edict = prog_spawn_entity(prog); + Return(ent); + return (ent.edict ? 0 : -1); +} + +static int qc_kill(qc_program *prog) +{ + qcany *ent; + CheckArgs(1); + ent = GetArg(0); + prog_free_entity(prog, ent->edict); + return 0; +} + static prog_builtin qc_builtins[] = { NULL, - &qc_print + &qc_print, + &qc_ftos, + &qc_spawn, + &qc_kill }; static size_t qc_builtins_count = sizeof(qc_builtins) / sizeof(qc_builtins[0]); diff --git a/execloop.h b/execloop.h index 3b6d666..45494af 100644 --- a/execloop.h +++ b/execloop.h @@ -16,7 +16,7 @@ #endif #if !defined(PRVM_ERROR) -# define PRVM_ERROR printf +# define PRVM_ERROR prog->vmerror++, printvmerr #endif #if !defined(PRVM_NAME) @@ -357,6 +357,8 @@ } else st = prog->code + PROG_ENTERFUNCTION(newf); + if (prog->vmerror) + goto cleanup; break; case INSTR_DONE: diff --git a/gmqcc.h b/gmqcc.h index 7f7efce..26428b8 100644 --- a/gmqcc.h +++ b/gmqcc.h @@ -917,6 +917,7 @@ typedef struct qc_program_s { MEM_VECTOR_MAKE(char, strings); MEM_VECTOR_MAKE(qcint, globals); MEM_VECTOR_MAKE(qcint, entitydata); + MEM_VECTOR_MAKE(bool, entitypool); size_t tempstring_start; size_t tempstring_at; From cf04b5ed01d7f90329c36b87d8b2bf7d170ad7b3 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 17:35:55 +0200 Subject: [PATCH 09/24] Need to keep prog->entities up to date when spawning entities --- exec.c | 2 ++ execloop.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/exec.c b/exec.c index 363fb44..835217c 100644 --- a/exec.c +++ b/exec.c @@ -130,6 +130,7 @@ qc_program* prog_load(const char *filename) goto error; } } + prog->entities = 1; return prog; @@ -226,6 +227,7 @@ qcint prog_spawn_entity(qc_program *prog) printf("Failed to allocate entity\n"); return 0; } + prog->entities++; for (i = 0; i < prog->entityfields; ++i) { if (!qc_program_entitydata_add(prog, 0)) { printf("Failed to allocate entity\n"); diff --git a/execloop.h b/execloop.h index 45494af..2929c2d 100644 --- a/execloop.h +++ b/execloop.h @@ -232,7 +232,7 @@ case INSTR_ADDRESS: if (OPA->edict < 0 || OPA->edict >= prog->entities) { - PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number", PRVM_NAME); + PRVM_ERROR ("%s Progs attempted to address an out of bounds edict number %i", PRVM_NAME, OPA->edict); goto cleanup; } if ((unsigned int)(OPB->_int) >= (unsigned int)(prog->entityfields)) From 5f2a775d41c23db495fe24d7414e5e36530785b7 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 17:53:41 +0200 Subject: [PATCH 10/24] generate address of store_return values created with ir_value_out properly --- ir.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ir.c b/ir.c index f9e9fd2..1f38236 100644 --- a/ir.c +++ b/ir.c @@ -529,6 +529,8 @@ void ir_value_code_setaddr(ir_value *self, int32_t gaddr) int32_t ir_value_code_addr(const ir_value *self) { + if (self->store == store_return) + return OFS_RETURN + self->code.addroffset; return self->code.globaladdr + self->code.addroffset; } From 91e3765a000a1fab15232e97538442b6fe5024cc Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 18:05:56 +0200 Subject: [PATCH 11/24] Generating fields using ir_builder_create_field --- ast.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ast.c b/ast.c index 4c90821..d768409 100644 --- a/ast.c +++ b/ast.c @@ -616,6 +616,18 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir) return true; } + if (self->expression.vtype == TYPE_FIELD) { + v = ir_builder_create_field(ir, self->name, self->expression.next->expression.vtype); + if (!v) + return false; + if (self->isconst) { + printf("TODO: constant field pointers with value\n"); + goto error; + } + self->ir_v = v; + return true; + } + v = ir_builder_create_global(ir, self->name, self->expression.vtype); if (!v) return false; From fda4687ece1c20d537833ec85469d4274c9350f4 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 18:06:10 +0200 Subject: [PATCH 12/24] STOREP also has the destination in OPB rather than OPC --- ir.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ir.c b/ir.c index 1f38236..7e1f110 100644 --- a/ir.c +++ b/ir.c @@ -2364,8 +2364,10 @@ tailcall: stmt.o1.u1 = stmt.o3.u1; stmt.o3.u1 = 0; } - else if (stmt.opcode >= INSTR_STORE_F && - stmt.opcode <= INSTR_STORE_FNC) + else if ((stmt.opcode >= INSTR_STORE_F && + stmt.opcode <= INSTR_STORE_FNC) || + (stmt.opcode >= INSTR_STOREP_F && + stmt.opcode <= INSTR_STOREP_FNC)) { /* 2-operand instructions with A -> B */ stmt.o2.u1 = stmt.o3.u1; From 3f234591da69bf113ec059b1100aee74c7f5b9dd Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 18:09:45 +0200 Subject: [PATCH 13/24] testcase for print(ftos(pawn.mema)) slightly changed, now not using a temporary location --- test/ast-test.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/ast-test.c b/test/ast-test.c index 7a80b91..2fb587e 100644 --- a/test/ast-test.c +++ b/test/ast-test.c @@ -100,11 +100,19 @@ FUNCTION(main, TYPE_VOID); STATE(ASSIGN(STOREP_F, ENTFIELD(pawn, mema), f5)); CALL(ftos) CALLPARAM(ENTFIELD(pawn, mema)) +#if 0 ENDCALLWITH(output, STATE(ASSIGN(STORE_F, vi, output))); CALL(print) CALLPARAM(vi) ENDCALL(); +#else + ENDCALLWITH(output, + CALL(print) + CALLPARAM(output) + ENDCALL(); + ); +#endif ENDFUNCTION(main); From 228b3cca41307a8f91f9afe55a80840facacb58a Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 19:08:23 +0200 Subject: [PATCH 14/24] to support .vector's _y and _z we need to add the global-data pointing to _y and _z... --- ir.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/ir.c b/ir.c index 7e1f110..7ba97eb 100644 --- a/ir.c +++ b/ir.c @@ -566,13 +566,29 @@ ir_value* ir_value_vector_member(ir_value *self, unsigned int member) if (self->members[member]) return self->members[member]; - m = ir_value_var(self->name, self->store, TYPE_FLOAT); - if (!m) - return NULL; - m->context = self->context; + if (self->vtype == TYPE_VECTOR) + { + m = ir_value_var(self->name, self->store, TYPE_FLOAT); + if (!m) + return NULL; + m->context = self->context; - self->members[member] = m; - m->code.addroffset = member; + self->members[member] = m; + m->code.addroffset = member; + } + else if (self->vtype == TYPE_FIELD) + { + if (self->fieldtype != TYPE_VECTOR) + return NULL; + m = ir_value_var(self->name, self->store, TYPE_FIELD); + if (!m) + return NULL; + m->fieldtype = TYPE_FLOAT; + m->context = self->context; + + self->members[member] = m; + m->code.addroffset = member; + } return m; } @@ -2628,6 +2644,12 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field) if (!code_globals_add(fld.offset)) return false; + if (fld.type == TYPE_VECTOR) { + if (!code_globals_add(fld.offset+1)) + return false; + if (!code_globals_add(fld.offset+2)) + return false; + } ir_value_code_setaddr(field, code_globals_add(fld.offset)); return field->code.globaladdr >= 0; From bb1f38de5d36b0d7c4a0a9fa8743ae6ecd8a205b Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 19:34:58 +0200 Subject: [PATCH 15/24] also generate _y and _z data for fieldpointers --- ir.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ir.c b/ir.c index 7ba97eb..74923c4 100644 --- a/ir.c +++ b/ir.c @@ -2150,10 +2150,18 @@ static bool gen_global_field(ir_value *global) /* copy the field's value */ ir_value_code_setaddr(global, code_globals_add(code_globals_data[fld->code.globaladdr])); + if (global->fieldtype == TYPE_VECTOR) { + code_globals_add(code_globals_data[fld->code.globaladdr]+1); + code_globals_add(code_globals_data[fld->code.globaladdr]+2); + } } else { ir_value_code_setaddr(global, code_globals_add(0)); + if (global->fieldtype == TYPE_VECTOR) { + code_globals_add(0); + code_globals_add(0); + } } if (global->code.globaladdr < 0) return false; From d4983b0b55442e223f196a7858589c2aad020f1c Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 19:35:08 +0200 Subject: [PATCH 16/24] -fadjust-vector-fields --- flags.def | 1 + 1 file changed, 1 insertion(+) diff --git a/flags.def b/flags.def index a7387d1..79ab71e 100644 --- a/flags.def +++ b/flags.def @@ -5,3 +5,4 @@ GMQCC_DEFINE_FLAG(OVERLAP_LOCALS) GMQCC_DEFINE_FLAG(DARKPLACES_STRING_TABLE_BUG) GMQCC_DEFINE_FLAG(OMIT_NULL_BYTES) +GMQCC_DEFINE_FLAG(ADJUST_VECTOR_FIELDS) From c31c59312bf6afe68cc32c6926db9f0328b5f196 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 19:38:02 +0200 Subject: [PATCH 17/24] ir_block_create_store/p will now honor -fadjust-vector-fields by using STORE_V/STOREP_V instead of _FLD on vector-fields --- ir.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ir.c b/ir.c index 74923c4..d9fdcf7 100644 --- a/ir.c +++ b/ir.c @@ -963,6 +963,11 @@ bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what) #endif op = type_store_instr[vtype]; + if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) { + if (op == INSTR_STORE_FLD && what->fieldtype == TYPE_VECTOR) + op = INSTR_STORE_V; + } + return ir_block_create_store_op(self, op, target, what); } @@ -980,6 +985,10 @@ bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what) vtype = what->vtype; op = type_storep_instr[vtype]; + if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) { + if (op == INSTR_STOREP_FLD && what->fieldtype == TYPE_VECTOR) + op = INSTR_STOREP_V; + } return ir_block_create_store_op(self, op, target, what); } From 20831ddc6c0839f7b85d3c717e8a8e0b3fa46838 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 21:17:49 +0200 Subject: [PATCH 18/24] fixing address check INSTR_STOREP_V in execloop - it kept us from writing to a vector when it was the last declared entityfield --- execloop.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/execloop.h b/execloop.h index 2929c2d..6ccfad4 100644 --- a/execloop.h +++ b/execloop.h @@ -216,7 +216,7 @@ ptr->_int = OPA->_int; break; case INSTR_STOREP_V: - if (OPB->_int < 0 || OPB->_int + 3 >= prog->entitydata_count) + if (OPB->_int < 0 || OPB->_int + 2 >= prog->entitydata_count) { PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int); goto cleanup; From b36fabe4d76fce6c1bc8ab1e3c40fe33165747ce Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 21:18:15 +0200 Subject: [PATCH 19/24] print builtin now prints all the passed strings, not just the first --- exec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/exec.c b/exec.c index 835217c..b957a83 100644 --- a/exec.c +++ b/exec.c @@ -584,8 +584,11 @@ bool opts_memchk = false; static int qc_print(qc_program *prog) { - qcany *str = (qcany*)(prog->globals + OFS_PARM0); - printf("%s", prog_getstring(prog, str->string)); + size_t i; + for (i = 0; i < prog->argc; ++i) { + qcany *str = (qcany*)(prog->globals + OFS_PARM0 + 3*i); + printf("%s", prog_getstring(prog, str->string)); + } return 0; } @@ -656,6 +659,7 @@ int main(int argc, char **argv) if (!strcmp(name, "main")) fnmain = (qcint)i; } + printf("Entity field space: %i\n", (int)prog->entityfields); if (fnmain > 0) { prog_exec(prog, &prog->functions[fnmain], VMXF_TRACE, VM_JUMPS_DEFAULT); From c94c36d68b107037970ad3e0026cd0d9610a2f53 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 21:18:46 +0200 Subject: [PATCH 20/24] testing writing to multiple fields, including a vector field --- test/ast-macros.h | 9 +++++++++ test/ast-test.c | 34 ++++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/test/ast-macros.h b/test/ast-macros.h index e11bd8d..16130ef 100644 --- a/test/ast-macros.h +++ b/test/ast-macros.h @@ -46,6 +46,15 @@ do { \ MKGLOBAL(name); \ } while(0) +#define MKCONSTVECTOR(name, valx, valy, valz) \ +do { \ + name->isconst = true; \ + name->constval.vvec.x = (valx); \ + name->constval.vvec.y = (valy); \ + name->constval.vvec.z = (valz); \ + MKGLOBAL(name); \ +} while(0) + #define STATE(a) \ do { \ ast_expression *exp = (ast_expression*)(a); \ diff --git a/test/ast-test.c b/test/ast-test.c index 2fb587e..0cb0101 100644 --- a/test/ast-test.c +++ b/test/ast-test.c @@ -37,12 +37,17 @@ int main() DEFVAR(f0); DEFVAR(f1); DEFVAR(f5); + DEFVAR(cv3x4x5); + DEFVAR(cv1x1x1); DEFVAR(sHello); + DEFVAR(sNL); DEFVAR(print); DEFVAR(ftos); DEFVAR(spawn); DEFVAR(mema); + DEFVAR(memb); + DEFVAR(memv); DEFVAR(pawn); /* opts_debug = true; */ @@ -63,17 +68,27 @@ VAR(TYPE_FLOAT, f0); VAR(TYPE_FLOAT, f1); VAR(TYPE_FLOAT, f5); VAR(TYPE_STRING, sHello); +VAR(TYPE_STRING, sNL); +VAR(TYPE_VECTOR, cv3x4x5); +VAR(TYPE_VECTOR, cv1x1x1); FIELD(TYPE_FLOAT, mema); +FIELD(TYPE_FLOAT, memb); +FIELD(TYPE_VECTOR, memv); MKCONSTFLOAT(f0, 0.0); MKCONSTFLOAT(f1, 1.0); MKCONSTFLOAT(f5, 5.0); MKCONSTSTRING(sHello, "Hello, World\n"); +MKCONSTSTRING(sNL, "\n"); +MKCONSTVECTOR(cv3x4x5, 3, 4, 5); +MKCONSTVECTOR(cv1x1x1, 1, 1, 1); FUNCTION(foo, TYPE_VOID); ENDFUNCTION(foo); +#define PRINTNL() do { CALL(print) CALLPARAM(sNL) ENDCALL(); } while(0) + FUNCTION(main, TYPE_VOID); VAR(TYPE_FLOAT, vi); @@ -98,21 +113,24 @@ FUNCTION(main, TYPE_VOID); ENDCALLWITH(newent, STATE(ASSIGN(STORE_ENT, pawn, newent))); STATE(ASSIGN(STOREP_F, ENTFIELD(pawn, mema), f5)); + STATE(ASSIGN(STOREP_F, ENTFIELD(pawn, memb), f1)); + STATE(ASSIGN(STOREP_V, ENTFIELD(pawn, memv), cv3x4x5)); CALL(ftos) CALLPARAM(ENTFIELD(pawn, mema)) -#if 0 - ENDCALLWITH(output, STATE(ASSIGN(STORE_F, vi, output))); - - CALL(print) - CALLPARAM(vi) - ENDCALL(); -#else ENDCALLWITH(output, CALL(print) CALLPARAM(output) + CALLPARAM(sNL) + ENDCALL(); + ); + CALL(ftos) + CALLPARAM(ENTFIELD(pawn, memb)) + ENDCALLWITH(output, + CALL(print) + CALLPARAM(output) + CALLPARAM(sNL) ENDCALL(); ); -#endif ENDFUNCTION(main); From 060bddb922c7933f1970828b7fcf3e3a4122d5c8 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 22:11:08 +0200 Subject: [PATCH 21/24] same +1 offset in LOAD_V as STOREP fixed --- execloop.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/execloop.h b/execloop.h index 6ccfad4..b75061e 100644 --- a/execloop.h +++ b/execloop.h @@ -271,7 +271,7 @@ PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME); goto cleanup; } - if (OPB->_int < 0 || OPB->_int + 3 >= prog->entityfields) + if (OPB->_int < 0 || OPB->_int + 3 > prog->entityfields) { PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int); goto cleanup; From 56c23dc11e18c1eee673e7db19c84bde89eb9c47 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 22:14:16 +0200 Subject: [PATCH 22/24] ast_member_new now fixed up for fields, ast_shallow_type added for creation of a type-only ast_expression --- ast.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/ast.c b/ast.c index d768409..e6d28a6 100644 --- a/ast.c +++ b/ast.c @@ -94,6 +94,15 @@ static ast_value* ast_value_copy(const ast_value *self) return cp; } +static ast_expression* ast_shallow_type(lex_ctx ctx, int vtype) +{ + ast_instantiate(ast_expression, ctx, ast_expression_delete_full); + self->expression.codegen = NULL; + self->expression.next = NULL; + self->expression.vtype = vtype; + return self; +} + static ast_expression* ast_type_copy(lex_ctx ctx, const ast_expression *ex) { size_t i; @@ -294,10 +303,22 @@ ast_member* ast_member_new(lex_ctx ctx, ast_expression *owner, unsigned int fiel return NULL; } + if (owner->expression.vtype != TYPE_FLOAT && + owner->expression.vtype != TYPE_FIELD) { + printf("ast_member on an invalid owner of type %i\n", (int)owner->expression.vtype); + mem_d(self); + return NULL; + } + ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_member_codegen); - self->expression.vtype = TYPE_FLOAT; - self->expression.next = NULL; + if (owner->expression.vtype == TYPE_VECTOR) { + self->expression.vtype = TYPE_FLOAT; + self->expression.next = NULL; + } else { + self->expression.vtype = TYPE_FIELD; + self->expression.next = ast_shallow_type(ctx, TYPE_FLOAT); + } self->owner = owner; self->field = field; @@ -958,8 +979,11 @@ bool ast_member_codegen(ast_member *self, ast_function *func, bool lvalue, ir_va if (!(*cgen)((ast_expression*)(self->owner), func, true, &vec)) return false; - if (vec->vtype != TYPE_VECTOR) + if (vec->vtype != TYPE_VECTOR && + !(vec->vtype == TYPE_FIELD && self->owner->expression.next->expression.vtype == TYPE_VECTOR)) + { return false; + } *out = ir_value_vector_member(vec, self->field); From 8b168077c74a7cf1f35738d0d804afb1a50bb4a8 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 22:14:45 +0200 Subject: [PATCH 23/24] IR generation of vector-fields put the 'main' vector offset at the wrong position - fixed that --- ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ir.c b/ir.c index d9fdcf7..e01da4d 100644 --- a/ir.c +++ b/ir.c @@ -2659,6 +2659,7 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field) if (code_fields_add(fld) < 0) return false; + ir_value_code_setaddr(field, code_globals_elements); if (!code_globals_add(fld.offset)) return false; if (fld.type == TYPE_VECTOR) { @@ -2668,7 +2669,6 @@ static bool ir_builder_gen_field(ir_builder *self, ir_value *field) return false; } - ir_value_code_setaddr(field, code_globals_add(fld.offset)); return field->code.globaladdr >= 0; } From b20136e5f4858b5ce1f11eda2e6872a0fd1a5413 Mon Sep 17 00:00:00 2001 From: "Wolfgang (Blub) Bumiller" Date: Sat, 11 Aug 2012 22:14:55 +0200 Subject: [PATCH 24/24] Working vector-field test --- test/ast-macros.h | 3 +++ test/ast-test.c | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/test/ast-macros.h b/test/ast-macros.h index 16130ef..580cd7a 100644 --- a/test/ast-macros.h +++ b/test/ast-macros.h @@ -70,6 +70,9 @@ do { \ #define ENTFIELD(a, b) \ (ast_expression*)ast_entfield_new(ctx, (ast_expression*)(a), (ast_expression*)(b)) +#define VECMEM(vec, mem) \ +(ast_expression*)ast_member_new(ctx, (ast_expression*)(vec), (mem)) + #define CALL(what) \ do { \ ast_call *call = ast_call_new(ctx, (ast_expression*)what); \ diff --git a/test/ast-test.c b/test/ast-test.c index 0cb0101..74800dd 100644 --- a/test/ast-test.c +++ b/test/ast-test.c @@ -131,6 +131,14 @@ FUNCTION(main, TYPE_VOID); CALLPARAM(sNL) ENDCALL(); ); + CALL(ftos) + CALLPARAM(ENTFIELD(pawn, VECMEM(memv, 2))) + ENDCALLWITH(output, + CALL(print) + CALLPARAM(output) + CALLPARAM(sNL) + ENDCALL(); + ); ENDFUNCTION(main);