From 59e78406357ef49519e0d12927602b534ef56204 Mon Sep 17 00:00:00 2001 From: Rudolf Polzer Date: Mon, 23 Sep 2024 15:02:27 +0200 Subject: [PATCH] Remove the `jumpabsolute` member from `mstatement_s`. This reduces the struct from 20 to 16 bytes, and thus may save some RAM. It also may improve CPU cache behavior by keeping more QC code in L1 and L2 cache, and possibly also improve instruction processing inside the CPU as all statements are aligned the same way. On `srv04`, this speeds up Xonotic's `serverbench` from 58.92s real, 57.72s user to 57.72s real, 56.59s user (median of 25). --- pr_comp.h | 3 +-- prvm_edict.c | 11 ++--------- prvm_exec.c | 13 ++++++++++--- prvm_execprogram.h | 6 +++--- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/pr_comp.h b/pr_comp.h index f69b63200..7ca0c28a4 100644 --- a/pr_comp.h +++ b/pr_comp.h @@ -409,8 +409,7 @@ mfunction_t; typedef struct mstatement_s { opcode_t op; - int operand[3]; // always a global or -1 for unused - int jumpabsolute; // only used by IF, IFNOT, GOTO + int operand[3]; // always a global, or a relative statement offset ([0] for GOTO, [1] for IF/IFNOT), or -1 for unused } mstatement_t; diff --git a/prvm_edict.c b/prvm_edict.c index cc318e991..3d5101876 100644 --- a/prvm_edict.c +++ b/prvm_edict.c @@ -2294,19 +2294,17 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data prog->error_cmd("%s: out of bounds IF/IFNOT (statement %d) in %s", __func__, i, prog->name); prog->statements[i].op = op; prog->statements[i].operand[0] = remapglobal(a); - prog->statements[i].operand[1] = -1; + prog->statements[i].operand[1] = b; prog->statements[i].operand[2] = -1; - prog->statements[i].jumpabsolute = i + b; break; case OP_GOTO: a = (short)a; if (a + i < 0 || a + i >= prog->progs_numstatements) prog->error_cmd("%s: out of bounds GOTO (statement %d) in %s", __func__, i, prog->name); prog->statements[i].op = op; - prog->statements[i].operand[0] = -1; + prog->statements[i].operand[0] = a; prog->statements[i].operand[1] = -1; prog->statements[i].operand[2] = -1; - prog->statements[i].jumpabsolute = i + a; break; default: Con_DPrintf("%s: unknown opcode %d at statement %d in %s\n", __func__, (int)op, i, prog->name); @@ -2316,7 +2314,6 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data prog->statements[i].operand[0] = 0; prog->statements[i].operand[1] = prog->statements[i].operand[2] = op; - prog->statements[i].jumpabsolute = -1; break; case OP_STORE_I: case OP_ADD_I: @@ -2427,7 +2424,6 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data prog->statements[i].operand[0] = remapglobal(a); prog->statements[i].operand[1] = remapglobal(b); prog->statements[i].operand[2] = remapglobal(c); - prog->statements[i].jumpabsolute = -1; break; // global none global case OP_NOT_F: @@ -2441,7 +2437,6 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data prog->statements[i].operand[0] = remapglobal(a); prog->statements[i].operand[1] = -1; prog->statements[i].operand[2] = remapglobal(c); - prog->statements[i].jumpabsolute = -1; break; // 2 globals case OP_STOREP_F: @@ -2466,7 +2461,6 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data prog->statements[i].operand[0] = remapglobal(a); prog->statements[i].operand[1] = remapglobal(b); prog->statements[i].operand[2] = -1; - prog->statements[i].jumpabsolute = -1; break; // 1 global case OP_CALL0: @@ -2493,7 +2487,6 @@ void PRVM_Prog_Load(prvm_prog_t *prog, const char *filename, unsigned char *data prog->statements[i].operand[0] = remapglobal(a); prog->statements[i].operand[1] = -1; prog->statements[i].operand[2] = -1; - prog->statements[i].jumpabsolute = -1; break; } } diff --git a/prvm_exec.c b/prvm_exec.c index 3c68f6d1d..e7f546809 100644 --- a/prvm_exec.c +++ b/prvm_exec.c @@ -332,10 +332,17 @@ static void PRVM_PrintStatement(prvm_prog_t *prog, mstatement_t *s) for ( ; i<10 ; i++) Con_Print(" "); - if (s->operand[0] >= 0) Con_Printf( "%s", PRVM_GlobalString(prog, s->operand[0], valuebuf, sizeof(valuebuf))); - if (s->operand[1] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[1], valuebuf, sizeof(valuebuf))); + if (s->op == OP_GOTO) { + Con_Printf("statement %i", (int)(s - prog->statements) + s->operand[0]); + } else { + if (s->operand[0] >= 0) Con_Printf( "%s", PRVM_GlobalString(prog, s->operand[0], valuebuf, sizeof(valuebuf))); + } + if (s->op == OP_IF || s->op == OP_IFNOT) { + Con_Printf(", statement %i", (int)(s - prog->statements) + s->operand[1]); + } else { + if (s->operand[1] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[1], valuebuf, sizeof(valuebuf))); + } if (s->operand[2] >= 0) Con_Printf(", %s", PRVM_GlobalString(prog, s->operand[2], valuebuf, sizeof(valuebuf))); - if (s->jumpabsolute >= 0) Con_Printf(", statement %i", s->jumpabsolute); Con_Print("\n"); } diff --git a/prvm_execprogram.h b/prvm_execprogram.h index 2a70bfc8c..34dd8d29d 100644 --- a/prvm_execprogram.h +++ b/prvm_execprogram.h @@ -637,7 +637,7 @@ int i; // and entity, string, field values can never have that value { ADVANCE_PROFILE_BEFORE_JUMP(); - st = cached_statements + st->jumpabsolute - 1; // offset the st++ + st += st->operand[1] - 1; // offset the st++ startst = st; // no bounds check needed, it is done when loading progs if (++jumpcount == 10000000 && prvm_runawaycheck) @@ -657,7 +657,7 @@ int i; // and entity, string, field values can never have that value { ADVANCE_PROFILE_BEFORE_JUMP(); - st = cached_statements + st->jumpabsolute - 1; // offset the st++ + st += st->operand[1] - 1; // offset the st++ startst = st; // no bounds check needed, it is done when loading progs if (++jumpcount == 10000000 && prvm_runawaycheck) @@ -671,7 +671,7 @@ int i; HANDLE_OPCODE(OP_GOTO): ADVANCE_PROFILE_BEFORE_JUMP(); - st = cached_statements + st->jumpabsolute - 1; // offset the st++ + st += st->operand[0] - 1; // offset the st++ startst = st; // no bounds check needed, it is done when loading progs if (++jumpcount == 10000000 && prvm_runawaycheck)