mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-12-03 09:32:31 +00:00
0c54b0652b
The inconsistencies in clang's handling of casts was bad enough, and its silliness with certain extensions, but discovering that it doesn't support raw strings was just too much. Yes, it gives a 3s boost to qfvis on gmsp3v2.bsp, but it's not worth the hassle.
254 lines
6.5 KiB
C
254 lines
6.5 KiB
C
#include <setjmp.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "QF/va.h"
|
|
|
|
#include "QF/simd/types.h"
|
|
|
|
#define num_tests (sizeof (tests) / sizeof (tests[0]))
|
|
static int test_enabled[num_tests] = { 0 };
|
|
|
|
#include "getopt.h"
|
|
|
|
#include "QF/cmd.h"
|
|
#include "QF/cvar.h"
|
|
|
|
static bfunction_t test_functions[] = {
|
|
{}, // null function
|
|
{ .first_statement = 0 }
|
|
};
|
|
static dprograms_t test_progs = {
|
|
.version = PROG_VERSION,
|
|
};
|
|
static progs_t test_pr;
|
|
|
|
static jmp_buf jump_buffer;
|
|
|
|
static void
|
|
test_debug_handler (prdebug_t event, void *param, void *data)
|
|
{
|
|
progs_t *pr = data;
|
|
|
|
switch (event) {
|
|
case prd_breakpoint:
|
|
if (verbose > 0) {
|
|
printf ("debug: %s\n", prdebug_names[event]);
|
|
}
|
|
longjmp (jump_buffer, 1);
|
|
case prd_subenter:
|
|
if (verbose > 0) {
|
|
printf ("debug: subenter %d\n", *(pr_func_t *) param);
|
|
}
|
|
case prd_subexit:
|
|
break;
|
|
case prd_trace:
|
|
dstatement_t *st = test_pr.pr_statements + test_pr.pr_xstatement;
|
|
if (verbose > 1) {
|
|
printf ("---\n");
|
|
printf ("debug: trace %05x %04x %04x %04x %04x%s\n",
|
|
test_pr.pr_xstatement, st->op, st->a, st->b, st->c,
|
|
pr->globals.stack ? va (0, " %05x", *pr->globals.stack)
|
|
: "");
|
|
printf (" %04x %04x %04x\n",
|
|
st->a + PR_BASE (pr, st, A),
|
|
st->b + PR_BASE (pr, st, B),
|
|
st->c + PR_BASE (pr, st, C));
|
|
}
|
|
if (verbose > 0) {
|
|
PR_PrintStatement (&test_pr, st, 0);
|
|
}
|
|
if (pr->globals.stack) {
|
|
if (*pr->globals.stack & 3) {
|
|
printf ("stack not aligned: %d\n", *pr->globals.stack);
|
|
longjmp (jump_buffer, 3);
|
|
}
|
|
}
|
|
break;
|
|
case prd_runerror:
|
|
printf ("debug: %s: %s\n", prdebug_names[event], (char *)param);
|
|
longjmp (jump_buffer, 3);
|
|
case prd_watchpoint:
|
|
case prd_begin:
|
|
case prd_terminate:
|
|
case prd_error:
|
|
case prd_none:
|
|
printf ("debug: unexpected:%s %p\n", prdebug_names[event], param);
|
|
longjmp (jump_buffer, 2);
|
|
}
|
|
}
|
|
|
|
static void
|
|
setup_test (test_t *test)
|
|
{
|
|
memset (&test_pr, 0, sizeof (test_pr));
|
|
PR_Init (&test_pr);
|
|
PR_Debug_Init (&test_pr);
|
|
test_pr.progs = &test_progs;
|
|
test_pr.debug_handler = test_debug_handler;
|
|
test_pr.debug_data = &test_pr;
|
|
test_pr.pr_trace = 1;
|
|
test_pr.pr_trace_depth = -1;
|
|
if (test->num_functions && test->functions) {
|
|
test_pr.function_table = calloc ((test->num_functions + 2),
|
|
sizeof (bfunction_t));
|
|
memcpy (test_pr.function_table, test_functions,
|
|
2 * sizeof (bfunction_t));
|
|
memcpy (test_pr.function_table + 2, test->functions,
|
|
test->num_functions * sizeof (bfunction_t));
|
|
} else {
|
|
test_pr.function_table = test_functions;
|
|
}
|
|
|
|
pr_uint_t num_globals = test->num_globals;
|
|
num_globals += test->extra_globals + test->stack_size;
|
|
|
|
test_pr.globals_size = num_globals;
|
|
test_pr.pr_globals = Sys_Alloc (num_globals * sizeof (pr_type_t));
|
|
memcpy (test_pr.pr_globals, test->init_globals,
|
|
test->num_globals * sizeof (pr_type_t));
|
|
memset (test_pr.pr_globals + test->num_globals, 0,
|
|
test->extra_globals * sizeof (pr_type_t));
|
|
if (test->stack_size) {
|
|
pr_ptr_t stack = num_globals - test->stack_size;
|
|
test_pr.stack_bottom = stack + 4;
|
|
test_pr.globals.stack = (pr_ptr_t *) (test_pr.pr_globals + stack);
|
|
*test_pr.globals.stack = num_globals;
|
|
}
|
|
if (test->edict_area) {
|
|
test_pr.pr_edict_area = test_pr.pr_globals + test->edict_area;
|
|
}
|
|
if (test->double_time || test->float_time) {
|
|
test_pr.fields.nextthink = test->nextthink;
|
|
test_pr.fields.frame = test->frame;
|
|
test_pr.fields.think = test->think;
|
|
test_pr.globals.self = (pr_uint_t *) &test_pr.pr_globals[test->self];
|
|
if (test->double_time) {
|
|
test_pr.globals.dtime = (double *)&test_pr.pr_globals[test->dtime];
|
|
*test_pr.globals.dtime = *test->double_time;
|
|
}
|
|
if (test->float_time) {
|
|
test_pr.globals.ftime = (float *) &test_pr.pr_globals[test->ftime];
|
|
*test_pr.globals.ftime = *test->float_time;
|
|
}
|
|
}
|
|
|
|
test_progs.statements.count = test->num_statements + 1;
|
|
test_pr.pr_statements
|
|
= malloc ((test->num_statements + 1) * sizeof (dstatement_t));
|
|
memcpy (test_pr.pr_statements, test->statements,
|
|
(test->num_statements + 1) * sizeof (dstatement_t));
|
|
test_pr.pr_statements[test->num_statements] =
|
|
(dstatement_t) { OP_BREAK, 0, 0, 0 };
|
|
|
|
test_pr.pr_strings = (char *) test->strings;
|
|
test_pr.pr_stringsize = test->string_size;
|
|
}
|
|
|
|
static int
|
|
check_result (test_t *test)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (memcmp (test_pr.pr_globals, test->expect_globals,
|
|
test->num_globals * sizeof (pr_int_t)) == 0) {
|
|
ret = 1;
|
|
printf ("test #%zd: %s: OK\n", test - tests, test->desc);
|
|
} else {
|
|
printf ("test #%zd: %s: words differ\n", test - tests, test->desc);
|
|
for (pr_uint_t i = 0; i < test->num_globals; i += 4) {
|
|
pr_ivec4_t *a = (pr_ivec4_t *) &test->expect_globals[i];
|
|
pr_ivec4_t *b = (pr_ivec4_t *) &test_pr.pr_globals[i];
|
|
if (memcmp (a, b, sizeof (pr_ivec4_t))) {
|
|
printf ("-%4x { %8x, %8x %8x %8x }\n", i, VEC4_EXP (*a));
|
|
printf ("+%4x { %8x, %8x %8x %8x }\n", i, VEC4_EXP (*b));
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
run_test (test_t *test)
|
|
{
|
|
int jump_ret;
|
|
int ret = 0;
|
|
|
|
setup_test (test);
|
|
|
|
if (!(jump_ret = setjmp (jump_buffer))) {
|
|
PR_ExecuteProgram (&test_pr, 1);
|
|
printf ("returned from progs\n");
|
|
}
|
|
if (jump_ret == 1) {
|
|
ret = check_result (test);
|
|
} else {
|
|
printf ("test #%zd: %s: critical failure\n", test - tests, test->desc);
|
|
}
|
|
|
|
pr_uint_t num_globals = test->num_globals;
|
|
num_globals += test->extra_globals + test->stack_size;
|
|
if (test->num_functions && test->functions) {
|
|
free (test_pr.function_table);
|
|
}
|
|
Sys_Free (test_pr.pr_globals, num_globals * sizeof (pr_type_t));
|
|
|
|
free (test_pr.pr_statements);
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
main (int argc, char **argv)
|
|
{
|
|
int c;
|
|
size_t i, test;
|
|
int pass = 1;
|
|
|
|
Cmd_Init_Hash ();
|
|
Cvar_Init_Hash ();
|
|
Cmd_Init ();
|
|
Cvar_Init ();
|
|
PR_Init_Cvars ();
|
|
pr_boundscheck = 1;
|
|
|
|
while ((c = getopt (argc, argv, "qvt:")) != EOF) {
|
|
switch (c) {
|
|
case 'q':
|
|
verbose--;
|
|
break;
|
|
case 'v':
|
|
verbose++;
|
|
break;
|
|
case 't':
|
|
test = atoi (optarg);
|
|
if (test < num_tests) {
|
|
test_enabled[test] = 1;
|
|
} else {
|
|
fprintf (stderr, "Bad test number (0 - %zd)\n", num_tests);
|
|
return 1;
|
|
}
|
|
break;
|
|
default:
|
|
fprintf (stderr, "-q (quiet) -v (verbose) and/or -t TEST "
|
|
"(test number)\n");
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < num_tests; i++)
|
|
if (test_enabled[i])
|
|
break;
|
|
if (i == num_tests) {
|
|
for (i = 0; i < num_tests; i++)
|
|
test_enabled[i] = 1;
|
|
}
|
|
|
|
for (i = 0; i < num_tests; i++) {
|
|
if (!test_enabled[i])
|
|
continue;
|
|
pass &= run_test (&tests[i]);
|
|
}
|
|
|
|
return !pass;
|
|
}
|