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(®ex, regex_str, REG_EXTENDED); 47 if (err_code) { 48 regerror(err_code, ®ex, 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(®ex, 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, ®ex, 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