From e2c3640540dbe423d2c75d89615854aeb9f560f3 Mon Sep 17 00:00:00 2001 From: Tom Stellard Date: Sun, 10 Mar 2013 20:55:26 -0400 Subject: [PATCH] r300g/compiler/tests: Add an assembly parser The assembly parser can be used to load r300 assembly dumps and run them through any of the r300 compiler passes. Reviewed-by: Alex Deucher --- .../r300/compiler/tests/omod_two_writers.test | 5 + .../r300/compiler/tests/r300_compiler_tests.h | 1 + .../tests/radeon_compiler_optimize_tests.c | 33 ++-- .../r300/compiler/tests/rc_test_helpers.c | 161 +++++++++++++++++- .../r300/compiler/tests/rc_test_helpers.h | 16 ++ 5 files changed, 200 insertions(+), 16 deletions(-) create mode 100644 src/gallium/drivers/r300/compiler/tests/omod_two_writers.test diff --git a/src/gallium/drivers/r300/compiler/tests/omod_two_writers.test b/src/gallium/drivers/r300/compiler/tests/omod_two_writers.test new file mode 100644 index 00000000000..fb16bb08f92 --- /dev/null +++ b/src/gallium/drivers/r300/compiler/tests/omod_two_writers.test @@ -0,0 +1,5 @@ +RCP temp[0].x, const[1].x___; +RCP temp[0].y, const[1]._y__; +MUL temp[1].xy, const[0].xx__, temp[0].xy__; +MOV output[0].xy, temp[1].xy; += diff --git a/src/gallium/drivers/r300/compiler/tests/r300_compiler_tests.h b/src/gallium/drivers/r300/compiler/tests/r300_compiler_tests.h index 266addf66d9..d40834a942b 100644 --- a/src/gallium/drivers/r300/compiler/tests/r300_compiler_tests.h +++ b/src/gallium/drivers/r300/compiler/tests/r300_compiler_tests.h @@ -26,4 +26,5 @@ */ unsigned radeon_compiler_optimize_run_tests(void); +unsigned radeon_compiler_regalloc_run_tests(void); unsigned radeon_compiler_util_run_tests(void); diff --git a/src/gallium/drivers/r300/compiler/tests/radeon_compiler_optimize_tests.c b/src/gallium/drivers/r300/compiler/tests/radeon_compiler_optimize_tests.c index 600228e83b0..819fb6c88d5 100644 --- a/src/gallium/drivers/r300/compiler/tests/radeon_compiler_optimize_tests.c +++ b/src/gallium/drivers/r300/compiler/tests/radeon_compiler_optimize_tests.c @@ -30,30 +30,42 @@ #include "rc_test_helpers.h" #include "unit_test.h" +static unsigned test_rc_optimize( + struct test_result * result, + struct radeon_compiler * c, + const char * filename) +{ + struct rc_test_file test_file; + + test_begin(result); + + if (!load_program(c, &test_file, filename)) { + fprintf(stderr, "Failed to load program\n"); + return 0; + } + + rc_optimize(c, NULL); + return 1; +} + static void test_runner_rc_optimize(struct test_result * result) { + unsigned pass = 1; struct radeon_compiler c; struct rc_instruction *inst; struct rc_instruction *inst_list[3]; unsigned inst_count = 0; float const0[4] = {2.0f, 0.0f, 0.0f, 0.0f}; - unsigned pass = 1; - test_begin(result); init_compiler(&c, RC_FRAGMENT_PROGRAM, 1, 0); rc_constants_add_immediate_vec4(&c.Program.Constants, const0); - add_instruction(&c, "RCP temp[0].x, const[1].x___;"); - add_instruction(&c, "RCP temp[0].y, const[1]._y__;"); - add_instruction(&c, "MUL temp[1].xy, const[0].xx__, temp[0].xy__;"); - add_instruction(&c, "MOV output[0].xy, temp[1].xy;" ); - - rc_optimize(&c, NULL); + test_rc_optimize(result, &c, "omod_two_writers.test"); for(inst = c.Program.Instructions.Next; - inst != &c.Program.Instructions; - inst = inst->Next, inst_count++) { + inst != &c.Program.Instructions; + inst = inst->Next, inst_count++) { inst_list[inst_count] = inst; } @@ -62,6 +74,7 @@ static void test_runner_rc_optimize(struct test_result * result) inst_list[2]->U.I.Opcode != RC_OPCODE_MOV) { pass = 0; } + test_check(result, pass); } diff --git a/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.c b/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.c index 551fe05ece2..af7b3cee48f 100644 --- a/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.c +++ b/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.c @@ -42,6 +42,7 @@ #include "radeon_program.h" #include "radeon_regalloc.h" #include "radeon_swizzle.h" +#include "util/u_math.h" #include "rc_test_helpers.h" @@ -61,6 +62,16 @@ struct match_info { int Length; }; +static int is_whitespace(const char *str) +{ + regex_t regex; + if (regcomp(®ex, "^[ \n]+$", REG_EXTENDED)) { + fprintf(stderr, "Failed to compile whitespace regex\n"); + return 0; + } + return regexec(®ex, str, 0, NULL, 0) != REG_NOMATCH; +} + static int match_length(regmatch_t * matches, int index) { return matches[index].rm_eo - matches[index].rm_so; @@ -124,7 +135,7 @@ int init_rc_normal_src( unsigned int src_index, const char * src_str) { - const char * regex_str = "(-*)(\\|*)([[:lower:]]*)\\[([[:digit:]])\\](\\.*[[:lower:]-]*)"; + const char * regex_str = "(-*)(\\|*)([[:lower:]]*)\\[*([[:digit:]]*)\\]*(\\.*[[:lower:]_]*)"; regmatch_t matches[REGEX_SRC_MATCHES]; struct src_tokens tokens; struct rc_src_register * src_reg = &inst->U.I.SrcReg[src_index]; @@ -187,7 +198,8 @@ int init_rc_normal_src( fprintf(stderr, "First char of swizzle is not valid.\n"); return 0; } - for (i = 0; i < 4; i++, str_index++) { + for (i = 0; i < 4 && str_index < tokens.Swizzle.Length; + i++, str_index++) { if (tokens.Swizzle.String[str_index] == '-') { src_reg->Negate |= (1 << i); str_index++; @@ -218,7 +230,8 @@ int init_rc_normal_src( SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_UNUSED); break; default: - fprintf(stderr, "Unknown src register swizzle.\n"); + fprintf(stderr, "Unknown src register swizzle: %c\n", + tokens.Swizzle.String[str_index]); return 0; } } @@ -251,7 +264,7 @@ int init_rc_normal_dst( struct rc_instruction * inst, const char * dst_str) { - const char * regex_str = "([[:lower:]]*)\\[([[:digit:]]*)\\](\\.*[[:lower:]]*)"; + const char * regex_str = "([[:lower:]]*)\\[*([[:digit:]]*)\\]*(\\.*[[:lower:]]*)"; regmatch_t matches[REGEX_DST_MATCHES]; struct dst_tokens tokens; unsigned int i; @@ -275,6 +288,9 @@ int init_rc_normal_dst( inst->U.I.DstReg.File = RC_FILE_TEMPORARY; } else if (!strncmp(tokens.File.String, "output", tokens.File.Length)) { inst->U.I.DstReg.File = RC_FILE_OUTPUT; + } else if (!strncmp(tokens.File.String, "none", tokens.File.Length)) { + inst->U.I.DstReg.File = RC_FILE_NONE; + return 1; } else { fprintf(stderr, "Unknown dst register file type.\n"); return 0; @@ -314,7 +330,8 @@ int init_rc_normal_dst( inst->U.I.DstReg.WriteMask |= RC_MASK_W; break; default: - fprintf(stderr, "Unknown swizzle in writemask.\n"); + fprintf(stderr, "Unknown swizzle in writemask: %c\n", + tokens.WriteMask.String[i]); return 0; } } @@ -327,6 +344,7 @@ int init_rc_normal_dst( } #define REGEX_INST_MATCHES 7 +#define REGEX_CONST_MATCHES 5 struct inst_tokens { struct match_info Opcode; @@ -351,7 +369,7 @@ int parse_rc_normal_instruction( struct rc_instruction * inst, const char * inst_str) { - const char * regex_str = "([[:upper:]]+)(_SAT)* ([^,]*)[, ]*([^,]*)[, ]*([^,]*)[, ]*([^;]*)"; + const char * regex_str = "[[:digit:]: ]*([[:upper:][:digit:]]+)(_SAT)*[ ]*([^,;]*)[, ]*([^,;]*)[, ]*([^,;]*)[, ]*([^;]*)"; int i; regmatch_t matches[REGEX_INST_MATCHES]; struct inst_tokens tokens; @@ -408,11 +426,24 @@ int parse_rc_normal_instruction( src_str[tokens.Srcs[j].Length] = '\0'; init_rc_normal_src(inst, j, src_str); } + if (info->HasTexture) { + /* XXX: Will this always be XYZW ? */ + inst->U.I.TexSwizzle = RC_SWIZZLE_XYZW; + } break; } return 1; } +#define INDEX_TOKEN_LEN 4 +#define FLOAT_TOKEN_LEN 50 +int parse_constant(unsigned *index, float *data, const char *const_str) +{ + int matched = sscanf(const_str, "const[%d] {%f, %f, %f, %f}", index, + &data[0], &data[1], &data[2], &data[3]); + return matched == 5; +} + int init_rc_normal_instruction( struct rc_instruction * inst, const char * inst_str) @@ -432,6 +463,44 @@ void add_instruction(struct radeon_compiler *c, const char * inst_string) } +int add_constant(struct radeon_compiler *c, const char *const_str) +{ + float data[4]; + unsigned index; + struct rc_constant_list *constants; + struct rc_constant constant; + + if (!parse_constant(&index, data, const_str)) { + return 0; + } + + constants = &c->Program.Constants; + if (constants->_Reserved < index) { + struct rc_constant * newlist; + + constants->_Reserved = index + 100; + + newlist = malloc(sizeof(struct rc_constant) * constants->_Reserved); + if (constants->Constants) { + memcpy(newlist, constants->Constants, + sizeof(struct rc_constant) * + constants->_Reserved); + free(constants->Constants); + } + + constants->Constants = newlist; + } + + memset(&constant, 0, sizeof(constant)); + constant.Type = RC_CONSTANT_IMMEDIATE; + constant.Size = 4; + memcpy(constant.u.Immediate, data, sizeof(float) * 4); + constants->Constants[index] = constant; + constants->Count = MAX2(constants->Count, index + 1); + + return 1; +} + void init_compiler( struct radeon_compiler *c, enum rc_program_type program_type, @@ -439,6 +508,7 @@ void init_compiler( unsigned is_r400) { struct rc_regalloc_state *rs = malloc(sizeof(struct rc_regalloc_state)); + rc_init_regalloc_state(rs); rc_init(c, rs); c->is_r500 = is_r500; @@ -456,3 +526,82 @@ void init_compiler( c->SwizzleCaps = &r300_vertprog_swizzle_caps; } } + +#define MAX_LINE_LENGTH 100 +#define MAX_PATH_LENGTH 100 + +unsigned load_program( + struct radeon_compiler *c, + struct rc_test_file *test, + const char *filename) +{ + char line[MAX_LINE_LENGTH]; + char path[MAX_PATH_LENGTH]; + FILE *file; + unsigned *count; + char **string_store; + unsigned i = 0; + + snprintf(path, MAX_PATH_LENGTH, "compiler/tests/%s", filename); + file = fopen(path, "r"); + if (!file) { + return 0; + } + memset(test, 0, sizeof(struct rc_test_file)); + + count = &test->num_input_lines; + + while (fgets(line, MAX_LINE_LENGTH, file)){ + if (line[MAX_LINE_LENGTH - 2] == '\n') { + fprintf(stderr, "Error line cannot be longer than 100 " + "characters:\n%s\n", line); + return 0; + } + + // Comment + if (line[0] == '#' || is_whitespace(line)) { + continue; + } + + if (line[0] == '=') { + count = &test->num_expected_lines; + continue; + } + + (*count)++; + } + + test->input = malloc(sizeof(char *) * test->num_input_lines); + test->expected = malloc(sizeof(char *) * test->num_expected_lines); + + rewind(file); + string_store = test->input; + + while(fgets(line, MAX_LINE_LENGTH, file)) { + // Comment + char * dst; + if (line[0] == '#' || is_whitespace(line)) { + continue; + } + + if (line[0] == '=') { + i = 0; + string_store = test->expected; + continue; + } + + dst = string_store[i++] = malloc((strlen(line) + 1) * + sizeof (char)); + strcpy(dst, line); + } + + for (i = 0; i < test->num_input_lines; i++) { + if (test->input[i][0] == 'c') { + add_constant(c, test->input[i]); + continue; + } + // XXX: Parse immediates from the file. + add_instruction(c, test->input[i]); + } + return 1; +} diff --git a/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.h b/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.h index 49a46a94abd..6cc8d9cdcb4 100644 --- a/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.h +++ b/src/gallium/drivers/r300/compiler/tests/rc_test_helpers.h @@ -29,6 +29,13 @@ #include "radeon_compiler.h" +struct rc_test_file { + unsigned num_input_lines; + char **input; + unsigned num_expected_lines; + char **expected; +}; + int init_rc_normal_src( struct rc_instruction * inst, unsigned int src_index, @@ -42,14 +49,23 @@ int parse_rc_normal_instruction( struct rc_instruction * inst, const char * inst_str); +int parse_constant(unsigned *index, float *data, const char *const_str); + int init_rc_normal_instruction( struct rc_instruction * inst, const char * inst_str); void add_instruction(struct radeon_compiler *c, const char * inst_string); +int add_constant(struct radeon_compiler *c, const char *const_str); + void init_compiler( struct radeon_compiler *c, enum rc_program_type program_type, unsigned is_r500, unsigned is_r400); + +unsigned load_program( + struct radeon_compiler *c, + struct rc_test_file *test, + const char *filename); -- 2.30.2