Home | History | Annotate | Download | only in tests
      1 #include <errno.h>
      2 #include <regex.h>
      3 #include <stdlib.h>
      4 #include <stdio.h>
      5 #include <string.h>
      6 #include <sys/types.h>
      7 
      8 #include "../radeon_compiler_util.h"
      9 #include "../radeon_opcodes.h"
     10 #include "../radeon_program.h"
     11 
     12 #include "rc_test_helpers.h"
     13 
     14 /* This file contains some helper functions for filling out the rc_instruction
     15  * data structures.  These functions take a string as input based on the format
     16  * output by rc_program_print().
     17  */
     18 
     19 #define VERBOSE 0
     20 
     21 #define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0)
     22 
     23 #define REGEX_ERR_BUF_SIZE 50
     24 
     25 struct match_info {
     26 	const char * String;
     27 	int Length;
     28 };
     29 
     30 static int match_length(regmatch_t * matches, int index)
     31 {
     32 	return matches[index].rm_eo - matches[index].rm_so;
     33 }
     34 
     35 static int regex_helper(
     36 	const char * regex_str,
     37 	const char * search_str,
     38 	regmatch_t * matches,
     39 	int num_matches)
     40 {
     41 	char err_buf[REGEX_ERR_BUF_SIZE];
     42 	regex_t regex;
     43 	int err_code;
     44 	unsigned int i;
     45 
     46 	err_code = regcomp(&regex, regex_str, REG_EXTENDED);
     47 	if (err_code) {
     48 		regerror(err_code, &regex, err_buf, REGEX_ERR_BUF_SIZE);
     49 		fprintf(stderr, "Failed to compile regex: %s\n", err_buf);
     50 		return 0;
     51 	}
     52 
     53 	err_code = regexec(&regex, search_str, num_matches, matches, 0);
     54 	DBG("Search string: '%s'\n", search_str);
     55 	for (i = 0; i < num_matches; i++) {
     56 		DBG("Match %u start = %d end = %d\n", i,
     57 					matches[i].rm_so, matches[i].rm_eo);
     58 	}
     59 	if (err_code) {
     60 		regerror(err_code, &regex, err_buf, REGEX_ERR_BUF_SIZE);
     61 		fprintf(stderr, "Failed to match regex: %s\n", err_buf);
     62 		return 0;
     63 	}
     64 	return 1;
     65 }
     66 
     67 #define REGEX_SRC_MATCHES 6
     68 
     69 struct src_tokens {
     70 	struct match_info Negate;
     71 	struct match_info Abs;
     72 	struct match_info File;
     73 	struct match_info Index;
     74 	struct match_info Swizzle;
     75 };
     76 
     77 /**
     78  * Initialize the source register at index src_index for the instruction based
     79  * on src_str.
     80  *
     81  * NOTE: Warning in init_rc_normal_instruction() applies to this function as
     82  * well.
     83  *
     84  * @param src_str A string that represents the source register.  The format for
     85  * this string is the same that is output by rc_program_print.
     86  * @return 1 On success, 0 on failure
     87  */
     88 int init_rc_normal_src(
     89 	struct rc_instruction * inst,
     90 	unsigned int src_index,
     91 	const char * src_str)
     92 {
     93 	const char * regex_str = "(-*)(\\|*)([[:lower:]]*)\\[([[:digit:]])\\](\\.*[[:lower:]-]*)";
     94 	regmatch_t matches[REGEX_SRC_MATCHES];
     95 	struct src_tokens tokens;
     96 	struct rc_src_register * src_reg = &inst->U.I.SrcReg[src_index];
     97 	unsigned int i;
     98 
     99 	/* Execute the regex */
    100 	if (!regex_helper(regex_str, src_str, matches, REGEX_SRC_MATCHES)) {
    101 		fprintf(stderr, "Failed to execute regex for src register.\n");
    102 		return 0;
    103 	}
    104 
    105 	/* Create Tokens */
    106 	tokens.Negate.String = src_str + matches[1].rm_so;
    107 	tokens.Negate.Length = match_length(matches, 1);
    108 	tokens.Abs.String = src_str + matches[2].rm_so;
    109 	tokens.Abs.Length = match_length(matches, 2);
    110 	tokens.File.String = src_str + matches[3].rm_so;
    111 	tokens.File.Length = match_length(matches, 3);
    112 	tokens.Index.String = src_str + matches[4].rm_so;
    113 	tokens.Index.Length = match_length(matches, 4);
    114 	tokens.Swizzle.String = src_str + matches[5].rm_so;
    115 	tokens.Swizzle.Length = match_length(matches, 5);
    116 
    117 	/* Negate */
    118 	if (tokens.Negate.Length  > 0) {
    119 		src_reg->Negate = RC_MASK_XYZW;
    120 	}
    121 
    122 	/* Abs */
    123 	if (tokens.Abs.Length > 0) {
    124 		src_reg->Abs = 1;
    125 	}
    126 
    127 	/* File */
    128 	if (!strncmp(tokens.File.String, "temp", tokens.File.Length)) {
    129 		src_reg->File = RC_FILE_TEMPORARY;
    130 	} else if (!strncmp(tokens.File.String, "input", tokens.File.Length)) {
    131 		src_reg->File = RC_FILE_INPUT;
    132 	} else if (!strncmp(tokens.File.String, "const", tokens.File.Length)) {
    133 		src_reg->File = RC_FILE_CONSTANT;
    134 	} else if (!strncmp(tokens.File.String, "none", tokens.File.Length)) {
    135 		src_reg->File = RC_FILE_NONE;
    136 	}
    137 
    138 	/* Index */
    139 	errno = 0;
    140 	src_reg->Index = strtol(tokens.Index.String, NULL, 10);
    141 	if (errno > 0) {
    142 		fprintf(stderr, "Could not convert src register index.\n");
    143 		return 0;
    144 	}
    145 
    146 	/* Swizzle */
    147 	if (tokens.Swizzle.Length == 0) {
    148 		src_reg->Swizzle = RC_SWIZZLE_XYZW;
    149 	} else {
    150 		int str_index = 1;
    151 		src_reg->Swizzle = RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_UNUSED);
    152 		if (tokens.Swizzle.String[0] != '.') {
    153 			fprintf(stderr, "First char of swizzle is not valid.\n");
    154 			return 0;
    155 		}
    156 		for (i = 0; i < 4; i++, str_index++) {
    157 			if (tokens.Swizzle.String[str_index] == '-') {
    158 				src_reg->Negate |= (1 << i);
    159 				str_index++;
    160 			}
    161 			switch(tokens.Swizzle.String[str_index]) {
    162 			case 'x':
    163 				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_X);
    164 				break;
    165 			case 'y':
    166 				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_Y);
    167 				break;
    168 			case 'z':
    169 				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_Z);
    170 				break;
    171 			case 'w':
    172 				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_W);
    173 				break;
    174 			case '1':
    175 				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_ONE);
    176 				break;
    177 			case '0':
    178 				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_ZERO);
    179 				break;
    180 			case 'H':
    181 				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_HALF);
    182 				break;
    183 			case '_':
    184 				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_UNUSED);
    185 				break;
    186 			default:
    187 				fprintf(stderr, "Unknown src register swizzle.\n");
    188 				return 0;
    189 			}
    190 		}
    191 	}
    192 	DBG("File=%u index=%u swizzle=%x negate=%u abs=%u\n",
    193 			src_reg->File, src_reg->Index, src_reg->Swizzle,
    194 			src_reg->Negate, src_reg->Abs);
    195 	return 1;
    196 }
    197 
    198 #define REGEX_DST_MATCHES 4
    199 
    200 struct dst_tokens {
    201 	struct match_info File;
    202 	struct match_info Index;
    203 	struct match_info WriteMask;
    204 };
    205 
    206 /**
    207  * Initialize the destination for the instruction based on dst_str.
    208  *
    209  * NOTE: Warning in init_rc_normal_instruction() applies to this function as
    210  * well.
    211  *
    212  * @param dst_str A string that represents the destination register.  The format
    213  * for this string is the same that is output by rc_program_print.
    214  * @return 1 On success, 0 on failure
    215  */
    216 int init_rc_normal_dst(
    217 	struct rc_instruction * inst,
    218 	const char * dst_str)
    219 {
    220 	const char * regex_str = "([[:lower:]]*)\\[([[:digit:]]*)\\](\\.*[[:lower:]]*)";
    221 	regmatch_t matches[REGEX_DST_MATCHES];
    222 	struct dst_tokens tokens;
    223 	unsigned int i;
    224 
    225 	/* Execute the regex */
    226 	if (!regex_helper(regex_str, dst_str, matches, REGEX_DST_MATCHES)) {
    227 		fprintf(stderr, "Failed to execute regex for dst register.\n");
    228 		return 0;
    229 	}
    230 
    231 	/* Create Tokens */
    232 	tokens.File.String = dst_str + matches[1].rm_so;
    233 	tokens.File.Length = match_length(matches, 1);
    234 	tokens.Index.String = dst_str + matches[2].rm_so;
    235 	tokens.Index.Length = match_length(matches, 2);
    236 	tokens.WriteMask.String = dst_str + matches[3].rm_so;
    237 	tokens.WriteMask.Length = match_length(matches, 3);
    238 
    239 	/* File Type */
    240 	if (!strncmp(tokens.File.String, "temp", tokens.File.Length)) {
    241 		inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
    242 	} else if (!strncmp(tokens.File.String, "output", tokens.File.Length)) {
    243 		inst->U.I.DstReg.File = RC_FILE_OUTPUT;
    244 	} else {
    245 		fprintf(stderr, "Unknown dst register file type.\n");
    246 		return 0;
    247 	}
    248 
    249 	/* File Index */
    250 	errno = 0;
    251 	inst->U.I.DstReg.Index = strtol(tokens.Index.String, NULL, 10);
    252 
    253 	if (errno > 0) {
    254 		fprintf(stderr, "Could not convert dst register index\n");
    255 		return 0;
    256 	}
    257 
    258 	/* WriteMask */
    259 	if (tokens.WriteMask.Length == 0) {
    260 		inst->U.I.DstReg.WriteMask = RC_MASK_XYZW;
    261 	} else {
    262 		/* The first character should be '.' */
    263 		if (tokens.WriteMask.String[0] != '.') {
    264 			fprintf(stderr, "1st char of writemask is not valid.\n");
    265 			return 0;
    266 		}
    267 		for (i = 1; i < tokens.WriteMask.Length; i++) {
    268 			switch(tokens.WriteMask.String[i]) {
    269 			case 'x':
    270 				inst->U.I.DstReg.WriteMask |= RC_MASK_X;
    271 				break;
    272 			case 'y':
    273 				inst->U.I.DstReg.WriteMask |= RC_MASK_Y;
    274 				break;
    275 			case 'z':
    276 				inst->U.I.DstReg.WriteMask |= RC_MASK_Z;
    277 				break;
    278 			case 'w':
    279 				inst->U.I.DstReg.WriteMask |= RC_MASK_W;
    280 				break;
    281 			default:
    282 				fprintf(stderr, "Unknown swizzle in writemask.\n");
    283 				return 0;
    284 			}
    285 		}
    286 	}
    287 	DBG("Dst Reg File=%u Index=%d Writemask=%d\n",
    288 			inst->U.I.DstReg.File,
    289 			inst->U.I.DstReg.Index,
    290 			inst->U.I.DstReg.WriteMask);
    291 	return 1;
    292 }
    293 
    294 #define REGEX_INST_MATCHES 7
    295 
    296 struct inst_tokens {
    297 	struct match_info Opcode;
    298 	struct match_info Sat;
    299 	struct match_info Dst;
    300 	struct match_info Srcs[3];
    301 };
    302 
    303 /**
    304  * Initialize a normal instruction based on inst_str.
    305  *
    306  * WARNING: This function might not be able to handle every kind of format that
    307  * rc_program_print() can output.  If you are having problems with a
    308  * particular string, you may need to add support for it to this functions.
    309  *
    310  * @param inst_str A string that represents the source register.  The format for
    311  * this string is the same that is output by rc_program_print.
    312  * @return 1 On success, 0 on failure
    313  */
    314 int init_rc_normal_instruction(
    315 	struct rc_instruction * inst,
    316 	const char * inst_str)
    317 {
    318 	const char * regex_str = "([[:upper:]]+)(_SAT)* ([^,]*)[, ]*([^,]*)[, ]*([^,]*)[, ]*([^;]*)";
    319 	int i;
    320 	regmatch_t matches[REGEX_INST_MATCHES];
    321 	struct inst_tokens tokens;
    322 
    323 	/* Initialize inst */
    324 	memset(inst, 0, sizeof(struct rc_instruction));
    325 	inst->Type = RC_INSTRUCTION_NORMAL;
    326 
    327 	/* Execute the regex */
    328 	if (!regex_helper(regex_str, inst_str, matches, REGEX_INST_MATCHES)) {
    329 		return 0;
    330 	}
    331 	memset(&tokens, 0, sizeof(tokens));
    332 
    333 	/* Create Tokens */
    334 	tokens.Opcode.String = inst_str + matches[1].rm_so;
    335 	tokens.Opcode.Length = match_length(matches, 1);
    336 	if (matches[2].rm_so > -1) {
    337 		tokens.Sat.String = inst_str + matches[2].rm_so;
    338 		tokens.Sat.Length = match_length(matches, 2);
    339 	}
    340 
    341 
    342 	/* Fill out the rest of the instruction. */
    343 	for (i = 0; i < MAX_RC_OPCODE; i++) {
    344 		const struct rc_opcode_info * info = rc_get_opcode_info(i);
    345 		unsigned int first_src = 3;
    346 		unsigned int j;
    347 		if (strncmp(tokens.Opcode.String, info->Name, tokens.Opcode.Length)) {
    348 			continue;
    349 		}
    350 		inst->U.I.Opcode = info->Opcode;
    351 		if (info->HasDstReg) {
    352 			char * dst_str;
    353 			tokens.Dst.String = inst_str + matches[3].rm_so;
    354 			tokens.Dst.Length = match_length(matches, 3);
    355 			first_src++;
    356 
    357 			dst_str = malloc(sizeof(char) * (tokens.Dst.Length + 1));
    358 			strncpy(dst_str, tokens.Dst.String, tokens.Dst.Length);
    359 			dst_str[tokens.Dst.Length] = '\0';
    360 			init_rc_normal_dst(inst, dst_str);
    361 			free(dst_str);
    362 		}
    363 		for (j = 0; j < info->NumSrcRegs; j++) {
    364 			char * src_str;
    365 			tokens.Srcs[j].String =
    366 				inst_str + matches[first_src + j].rm_so;
    367 			tokens.Srcs[j].Length =
    368 				match_length(matches, first_src + j);
    369 
    370 			src_str = malloc(sizeof(char) *
    371 						(tokens.Srcs[j].Length + 1));
    372 			strncpy(src_str, tokens.Srcs[j].String,
    373 						tokens.Srcs[j].Length);
    374 			src_str[tokens.Srcs[j].Length] = '\0';
    375 			init_rc_normal_src(inst, j, src_str);
    376 		}
    377 		break;
    378 	}
    379 	return 1;
    380 }
    381