r300g/compiler/tests: Add an assembly parser
authorTom Stellard <thomas.stellard@amd.com>
Mon, 11 Mar 2013 00:55:26 +0000 (20:55 -0400)
committerTom Stellard <thomas.stellard@amd.com>
Mon, 1 Jul 2013 04:38:57 +0000 (21:38 -0700)
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 <alexander.deucher@amd.com>
src/gallium/drivers/r300/compiler/tests/omod_two_writers.test [new file with mode: 0644]
src/gallium/drivers/r300/compiler/tests/r300_compiler_tests.h
src/gallium/drivers/r300/compiler/tests/radeon_compiler_optimize_tests.c
src/gallium/drivers/r300/compiler/tests/rc_test_helpers.c
src/gallium/drivers/r300/compiler/tests/rc_test_helpers.h

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 (file)
index 0000000..fb16bb0
--- /dev/null
@@ -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;
+=
index 266addf66d991e06248887269a7bb430006e1ba2..d40834a942b6afd43b001d7a65b189ab0f1636f4 100644 (file)
@@ -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);
index 600228e83b0c1926c49f36c0cd124e219b6e99d9..819fb6c88d522094752db96e8e138d7574fb6af0 100644 (file)
 #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);
 }
 
index 551fe05ece2f11b7334c065ee32f5f461f6795b4..af7b3cee48f0fbf099c08302014c8b06b216e1f3 100644 (file)
@@ -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(&regex, "^[ \n]+$", REG_EXTENDED)) {
+               fprintf(stderr, "Failed to compile whitespace regex\n");
+               return 0;
+       }
+       return regexec(&regex, 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;
+}
index 49a46a94abdfa58b3feea978147b9f3ca5a9eaa6..6cc8d9cdcb4cd4beff5647a362ed2ad0436d537c 100644 (file)
 
 #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);