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
match_length(regmatch_t * matches,int index)30 static int match_length(regmatch_t * matches, int index)
31 {
32 return matches[index].rm_eo - matches[index].rm_so;
33 }
34
regex_helper(const char * regex_str,const char * search_str,regmatch_t * matches,int num_matches)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 */
init_rc_normal_src(struct rc_instruction * inst,unsigned int src_index,const char * src_str)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 */
init_rc_normal_dst(struct rc_instruction * inst,const char * dst_str)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 */
init_rc_normal_instruction(struct rc_instruction * inst,const char * inst_str)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