Subversion Repositories Kolibri OS

Rev

Rev 4358 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/*
2
 * Copyright 2011 Tom Stellard 
3
 * Copyright 2013 Advanced Micro Devices, Inc.
4
 *
5
 * All Rights Reserved.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining
8
 * a copy of this software and associated documentation files (the
9
 * "Software"), to deal in the Software without restriction, including
10
 * without limitation the rights to use, copy, modify, merge, publish,
11
 * distribute, sublicense, and/or sell copies of the Software, and to
12
 * permit persons to whom the Software is furnished to do so, subject to
13
 * the following conditions:
14
 *
15
 * The above copyright notice and this permission notice (including the
16
 * next paragraph) shall be included in all copies or substantial
17
 * portions of the Software.
18
 *
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22
 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
23
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
 *
27
 * Author: Tom Stellard 
28
 */
29
 
30
#include 
31
#include 
32
#include 
33
#include 
34
#include 
35
#include 
36
 
37
#include "r500_fragprog.h"
38
#include "r300_fragprog_swizzle.h"
39
#include "radeon_compiler.h"
40
#include "radeon_compiler_util.h"
41
#include "radeon_opcodes.h"
42
#include "radeon_program.h"
43
#include "radeon_regalloc.h"
44
#include "radeon_swizzle.h"
45
#include "util/u_math.h"
46
 
47
#include "rc_test_helpers.h"
48
 
49
/* This file contains some helper functions for filling out the rc_instruction
50
 * data structures.  These functions take a string as input based on the format
51
 * output by rc_program_print().
52
 */
53
 
54
#define VERBOSE 0
55
 
56
#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0)
57
 
58
#define REGEX_ERR_BUF_SIZE 50
59
 
60
struct match_info {
61
	const char * String;
62
	int Length;
63
};
64
 
65
static int is_whitespace(const char *str)
66
{
67
	regex_t regex;
68
	if (regcomp(®ex, "^[ \n]+$", REG_EXTENDED)) {
69
		fprintf(stderr, "Failed to compile whitespace regex\n");
70
		return 0;
71
	}
72
	return regexec(®ex, str, 0, NULL, 0) != REG_NOMATCH;
73
}
74
 
75
static int match_length(regmatch_t * matches, int index)
76
{
77
	return matches[index].rm_eo - matches[index].rm_so;
78
}
79
 
80
static int regex_helper(
81
	const char * regex_str,
82
	const char * search_str,
83
	regmatch_t * matches,
84
	int num_matches)
85
{
86
	char err_buf[REGEX_ERR_BUF_SIZE];
87
	regex_t regex;
88
	int err_code;
89
	unsigned int i;
90
 
91
	err_code = regcomp(®ex, regex_str, REG_EXTENDED);
92
	if (err_code) {
93
		regerror(err_code, ®ex, err_buf, REGEX_ERR_BUF_SIZE);
94
		fprintf(stderr, "Failed to compile regex: %s\n", err_buf);
95
		return 0;
96
	}
97
 
98
	err_code = regexec(®ex, search_str, num_matches, matches, 0);
99
	DBG("Search string: '%s'\n", search_str);
100
	for (i = 0; i < num_matches; i++) {
101
		DBG("Match %u start = %d end = %d\n", i,
102
					matches[i].rm_so, matches[i].rm_eo);
103
	}
104
	if (err_code) {
105
		regerror(err_code, ®ex, err_buf, REGEX_ERR_BUF_SIZE);
106
		fprintf(stderr, "Failed to match regex: %s\n", err_buf);
107
		return 0;
108
	}
109
	return 1;
110
}
111
 
112
#define REGEX_SRC_MATCHES 6
113
 
114
struct src_tokens {
115
	struct match_info Negate;
116
	struct match_info Abs;
117
	struct match_info File;
118
	struct match_info Index;
119
	struct match_info Swizzle;
120
};
121
 
122
/**
123
 * Initialize the source register at index src_index for the instruction based
124
 * on src_str.
125
 *
126
 * NOTE: Warning in init_rc_normal_instruction() applies to this function as
127
 * well.
128
 *
129
 * @param src_str A string that represents the source register.  The format for
130
 * this string is the same that is output by rc_program_print.
131
 * @return 1 On success, 0 on failure
132
 */
133
int init_rc_normal_src(
134
	struct rc_instruction * inst,
135
	unsigned int src_index,
136
	const char * src_str)
137
{
138
	const char * regex_str = "(-*)(\\|*)([[:lower:]]*)\\[*([[:digit:]]*)\\]*(\\.*[[:lower:]_]*)";
139
	regmatch_t matches[REGEX_SRC_MATCHES];
140
	struct src_tokens tokens;
141
	struct rc_src_register * src_reg = &inst->U.I.SrcReg[src_index];
142
	unsigned int i;
143
 
144
	/* Execute the regex */
145
	if (!regex_helper(regex_str, src_str, matches, REGEX_SRC_MATCHES)) {
146
		fprintf(stderr, "Failed to execute regex for src register.\n");
147
		return 0;
148
	}
149
 
150
	/* Create Tokens */
151
	tokens.Negate.String = src_str + matches[1].rm_so;
152
	tokens.Negate.Length = match_length(matches, 1);
153
	tokens.Abs.String = src_str + matches[2].rm_so;
154
	tokens.Abs.Length = match_length(matches, 2);
155
	tokens.File.String = src_str + matches[3].rm_so;
156
	tokens.File.Length = match_length(matches, 3);
157
	tokens.Index.String = src_str + matches[4].rm_so;
158
	tokens.Index.Length = match_length(matches, 4);
159
	tokens.Swizzle.String = src_str + matches[5].rm_so;
160
	tokens.Swizzle.Length = match_length(matches, 5);
161
 
162
	/* Negate */
163
	if (tokens.Negate.Length  > 0) {
164
		src_reg->Negate = RC_MASK_XYZW;
165
	}
166
 
167
	/* Abs */
168
	if (tokens.Abs.Length > 0) {
169
		src_reg->Abs = 1;
170
	}
171
 
172
	/* File */
173
	if (!strncmp(tokens.File.String, "temp", tokens.File.Length)) {
174
		src_reg->File = RC_FILE_TEMPORARY;
175
	} else if (!strncmp(tokens.File.String, "input", tokens.File.Length)) {
176
		src_reg->File = RC_FILE_INPUT;
177
	} else if (!strncmp(tokens.File.String, "const", tokens.File.Length)) {
178
		src_reg->File = RC_FILE_CONSTANT;
179
	} else if (!strncmp(tokens.File.String, "none", tokens.File.Length)) {
180
		src_reg->File = RC_FILE_NONE;
181
	}
182
 
183
	/* Index */
184
	errno = 0;
185
	src_reg->Index = strtol(tokens.Index.String, NULL, 10);
186
	if (errno > 0) {
187
		fprintf(stderr, "Could not convert src register index.\n");
188
		return 0;
189
	}
190
 
191
	/* Swizzle */
192
	if (tokens.Swizzle.Length == 0) {
193
		src_reg->Swizzle = RC_SWIZZLE_XYZW;
194
	} else {
195
		int str_index = 1;
196
		src_reg->Swizzle = RC_MAKE_SWIZZLE_SMEAR(RC_SWIZZLE_UNUSED);
197
		if (tokens.Swizzle.String[0] != '.') {
198
			fprintf(stderr, "First char of swizzle is not valid.\n");
199
			return 0;
200
		}
201
		for (i = 0; i < 4 && str_index < tokens.Swizzle.Length;
202
							i++, str_index++) {
203
			if (tokens.Swizzle.String[str_index] == '-') {
204
				src_reg->Negate |= (1 << i);
205
				str_index++;
206
			}
207
			switch(tokens.Swizzle.String[str_index]) {
208
			case 'x':
209
				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_X);
210
				break;
211
			case 'y':
212
				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_Y);
213
				break;
214
			case 'z':
215
				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_Z);
216
				break;
217
			case 'w':
218
				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_W);
219
				break;
220
			case '1':
221
				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_ONE);
222
				break;
223
			case '0':
224
				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_ZERO);
225
				break;
226
			case 'H':
227
				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_HALF);
228
				break;
229
			case '_':
230
				SET_SWZ(src_reg->Swizzle, i, RC_SWIZZLE_UNUSED);
231
				break;
232
			default:
233
				fprintf(stderr, "Unknown src register swizzle: %c\n",
234
						tokens.Swizzle.String[str_index]);
235
				return 0;
236
			}
237
		}
238
	}
239
	DBG("File=%u index=%u swizzle=%x negate=%u abs=%u\n",
240
			src_reg->File, src_reg->Index, src_reg->Swizzle,
241
			src_reg->Negate, src_reg->Abs);
242
	return 1;
243
}
244
 
245
#define REGEX_DST_MATCHES 4
246
 
247
struct dst_tokens {
248
	struct match_info File;
249
	struct match_info Index;
250
	struct match_info WriteMask;
251
};
252
 
253
/**
254
 * Initialize the destination for the instruction based on dst_str.
255
 *
256
 * NOTE: Warning in init_rc_normal_instruction() applies to this function as
257
 * well.
258
 *
259
 * @param dst_str A string that represents the destination register.  The format
260
 * for this string is the same that is output by rc_program_print.
261
 * @return 1 On success, 0 on failure
262
 */
263
int init_rc_normal_dst(
264
	struct rc_instruction * inst,
265
	const char * dst_str)
266
{
267
	const char * regex_str = "([[:lower:]]*)\\[*([[:digit:]]*)\\]*(\\.*[[:lower:]]*)";
268
	regmatch_t matches[REGEX_DST_MATCHES];
269
	struct dst_tokens tokens;
270
	unsigned int i;
271
 
272
	/* Execute the regex */
273
	if (!regex_helper(regex_str, dst_str, matches, REGEX_DST_MATCHES)) {
274
		fprintf(stderr, "Failed to execute regex for dst register.\n");
275
		return 0;
276
	}
277
 
278
	/* Create Tokens */
279
	tokens.File.String = dst_str + matches[1].rm_so;
280
	tokens.File.Length = match_length(matches, 1);
281
	tokens.Index.String = dst_str + matches[2].rm_so;
282
	tokens.Index.Length = match_length(matches, 2);
283
	tokens.WriteMask.String = dst_str + matches[3].rm_so;
284
	tokens.WriteMask.Length = match_length(matches, 3);
285
 
286
	/* File Type */
287
	if (!strncmp(tokens.File.String, "temp", tokens.File.Length)) {
288
		inst->U.I.DstReg.File = RC_FILE_TEMPORARY;
289
	} else if (!strncmp(tokens.File.String, "output", tokens.File.Length)) {
290
		inst->U.I.DstReg.File = RC_FILE_OUTPUT;
291
	} else if (!strncmp(tokens.File.String, "none", tokens.File.Length)) {
292
		inst->U.I.DstReg.File = RC_FILE_NONE;
293
		return 1;
294
	} else {
295
		fprintf(stderr, "Unknown dst register file type.\n");
296
		return 0;
297
	}
298
 
299
	/* File Index */
300
	errno = 0;
301
	inst->U.I.DstReg.Index = strtol(tokens.Index.String, NULL, 10);
302
 
303
	if (errno > 0) {
304
		fprintf(stderr, "Could not convert dst register index\n");
305
		return 0;
306
	}
307
 
308
	/* WriteMask */
309
	if (tokens.WriteMask.Length == 0) {
310
		inst->U.I.DstReg.WriteMask = RC_MASK_XYZW;
311
	} else {
312
		inst->U.I.DstReg.WriteMask = 0;
313
		/* The first character should be '.' */
314
		if (tokens.WriteMask.String[0] != '.') {
315
			fprintf(stderr, "1st char of writemask is not valid.\n");
316
			return 0;
317
		}
318
		for (i = 1; i < tokens.WriteMask.Length; i++) {
319
			switch(tokens.WriteMask.String[i]) {
320
			case 'x':
321
				inst->U.I.DstReg.WriteMask |= RC_MASK_X;
322
				break;
323
			case 'y':
324
				inst->U.I.DstReg.WriteMask |= RC_MASK_Y;
325
				break;
326
			case 'z':
327
				inst->U.I.DstReg.WriteMask |= RC_MASK_Z;
328
				break;
329
			case 'w':
330
				inst->U.I.DstReg.WriteMask |= RC_MASK_W;
331
				break;
332
			default:
333
				fprintf(stderr, "Unknown swizzle in writemask: %c\n",
334
							tokens.WriteMask.String[i]);
335
				return 0;
336
			}
337
		}
338
	}
339
	DBG("Dst Reg File=%u Index=%d Writemask=%d\n",
340
			inst->U.I.DstReg.File,
341
			inst->U.I.DstReg.Index,
342
			inst->U.I.DstReg.WriteMask);
343
	return 1;
344
}
345
 
346
#define REGEX_INST_MATCHES 7
347
#define REGEX_CONST_MATCHES 5
348
 
349
struct inst_tokens {
350
	struct match_info Opcode;
351
	struct match_info Sat;
352
	struct match_info Dst;
353
	struct match_info Srcs[3];
354
};
355
 
356
/**
357
 * Initialize a normal instruction based on inst_str.
358
 *
359
 * WARNING: This function might not be able to handle every kind of format that
360
 * rc_program_print() can output.  If you are having problems with a
361
 * particular string, you may need to add support for it to this functions.
362
 *
363
 * @param inst_str A string that represents the source register.  The format for
364
 * this string is the same that is output by rc_program_print.
365
 * @return 1 On success, 0 on failure
366
 */
367
 
368
int parse_rc_normal_instruction(
369
	struct rc_instruction * inst,
370
	const char * inst_str)
371
{
372
	const char * regex_str = "[[:digit:]: ]*([[:upper:][:digit:]]+)(_SAT)*[ ]*([^,;]*)[, ]*([^,;]*)[, ]*([^,;]*)[, ]*([^;]*)";
373
	int i;
374
	regmatch_t matches[REGEX_INST_MATCHES];
375
	struct inst_tokens tokens;
376
 
377
	/* Execute the regex */
378
	if (!regex_helper(regex_str, inst_str, matches, REGEX_INST_MATCHES)) {
379
		return 0;
380
	}
381
	memset(&tokens, 0, sizeof(tokens));
382
 
383
	/* Create Tokens */
384
	tokens.Opcode.String = inst_str + matches[1].rm_so;
385
	tokens.Opcode.Length = match_length(matches, 1);
386
	if (matches[2].rm_so > -1) {
387
		tokens.Sat.String = inst_str + matches[2].rm_so;
388
		tokens.Sat.Length = match_length(matches, 2);
389
	}
390
 
391
 
392
	/* Fill out the rest of the instruction. */
393
	inst->Type = RC_INSTRUCTION_NORMAL;
394
 
395
	for (i = 0; i < MAX_RC_OPCODE; i++) {
396
		const struct rc_opcode_info * info = rc_get_opcode_info(i);
397
		unsigned int first_src = 3;
398
		unsigned int j;
399
		if (strncmp(tokens.Opcode.String, info->Name, tokens.Opcode.Length)) {
400
			continue;
401
		}
402
		inst->U.I.Opcode = info->Opcode;
403
		if (info->HasDstReg) {
404
			char * dst_str;
405
			tokens.Dst.String = inst_str + matches[3].rm_so;
406
			tokens.Dst.Length = match_length(matches, 3);
407
			first_src++;
408
 
409
			dst_str = malloc(sizeof(char) * (tokens.Dst.Length + 1));
410
			strncpy(dst_str, tokens.Dst.String, tokens.Dst.Length);
411
			dst_str[tokens.Dst.Length] = '\0';
412
			init_rc_normal_dst(inst, dst_str);
413
			free(dst_str);
414
		}
415
		for (j = 0; j < info->NumSrcRegs; j++) {
416
			char * src_str;
417
			tokens.Srcs[j].String =
418
				inst_str + matches[first_src + j].rm_so;
419
			tokens.Srcs[j].Length =
420
				match_length(matches, first_src + j);
421
 
422
			src_str = malloc(sizeof(char) *
423
						(tokens.Srcs[j].Length + 1));
424
			strncpy(src_str, tokens.Srcs[j].String,
425
						tokens.Srcs[j].Length);
426
			src_str[tokens.Srcs[j].Length] = '\0';
427
			init_rc_normal_src(inst, j, src_str);
428
		}
429
		if (info->HasTexture) {
430
			/* XXX: Will this always be XYZW ? */
431
			inst->U.I.TexSwizzle = RC_SWIZZLE_XYZW;
432
		}
433
		break;
434
	}
435
	return 1;
436
}
437
 
438
#define INDEX_TOKEN_LEN 4
439
#define FLOAT_TOKEN_LEN 50
440
int parse_constant(unsigned *index, float *data, const char *const_str)
441
{
442
	int matched = sscanf(const_str, "const[%d] {%f, %f, %f, %f}", index,
443
				&data[0], &data[1], &data[2], &data[3]);
444
	return matched == 5;
445
}
446
 
447
int init_rc_normal_instruction(
448
	struct rc_instruction * inst,
449
	const char * inst_str)
450
{
451
	/* Initialize inst */
452
	memset(inst, 0, sizeof(struct rc_instruction));
453
 
454
	return parse_rc_normal_instruction(inst, inst_str);
455
}
456
 
457
void add_instruction(struct radeon_compiler *c, const char * inst_string)
458
{
459
	struct rc_instruction * new_inst =
460
		rc_insert_new_instruction(c, c->Program.Instructions.Prev);
461
 
462
	parse_rc_normal_instruction(new_inst, inst_string);
463
 
464
}
465
 
466
int add_constant(struct radeon_compiler *c, const char *const_str)
467
{
468
	float data[4];
469
	unsigned index;
470
	struct rc_constant_list *constants;
471
	struct rc_constant constant;
472
 
473
	if (!parse_constant(&index, data, const_str)) {
474
		return 0;
475
	}
476
 
477
	constants = &c->Program.Constants;
478
	if (constants->_Reserved < index) {
479
		struct rc_constant * newlist;
480
 
481
		constants->_Reserved = index + 100;
482
 
483
		newlist = malloc(sizeof(struct rc_constant) * constants->_Reserved);
484
		if (constants->Constants) {
485
			memcpy(newlist, constants->Constants,
486
				sizeof(struct rc_constant) *
487
					constants->_Reserved);
488
			free(constants->Constants);
489
		}
490
 
491
		constants->Constants = newlist;
492
	}
493
 
494
	memset(&constant, 0, sizeof(constant));
495
	constant.Type = RC_CONSTANT_IMMEDIATE;
496
	constant.Size = 4;
497
	memcpy(constant.u.Immediate, data, sizeof(float) * 4);
498
	constants->Constants[index] = constant;
499
	constants->Count = MAX2(constants->Count, index + 1);
500
 
501
	return 1;
502
}
503
 
504
void init_compiler(
505
	struct radeon_compiler *c,
506
	enum rc_program_type program_type,
507
	unsigned is_r500,
508
	unsigned is_r400)
509
{
510
	struct rc_regalloc_state *rs = malloc(sizeof(struct rc_regalloc_state));
511
	rc_init_regalloc_state(rs);
512
	rc_init(c, rs);
513
 
514
	c->is_r500 = is_r500;
515
	c->max_temp_regs = is_r500 ? 128 : (is_r400 ? 64 : 32);
516
	c->max_constants = is_r500 ? 256 : 32;
517
	c->max_alu_insts = (is_r500 || is_r400) ? 512 : 64;
518
	c->max_tex_insts = (is_r500 || is_r400) ? 512 : 32;
519
	if (program_type == RC_FRAGMENT_PROGRAM) {
520
		c->has_half_swizzles = 1;
521
		c->has_presub = 1;
522
		c->has_omod = 1;
523
		c->SwizzleCaps =
524
			is_r500 ? &r500_swizzle_caps : &r300_swizzle_caps;
525
	} else {
526
		c->SwizzleCaps = &r300_vertprog_swizzle_caps;
527
	}
528
}
529
 
530
#define MAX_LINE_LENGTH 100
531
#define MAX_PATH_LENGTH 100
532
 
533
unsigned load_program(
534
	struct radeon_compiler *c,
535
	struct rc_test_file *test,
536
	const char *filename)
537
{
538
	char line[MAX_LINE_LENGTH];
539
	char path[MAX_PATH_LENGTH];
540
	FILE *file;
541
	unsigned *count;
542
	char **string_store;
543
	unsigned i = 0;
544
 
4401 Serge 545
	memset(line, 0, sizeof(line));
4358 Serge 546
	snprintf(path, MAX_PATH_LENGTH, "compiler/tests/%s", filename);
547
	file = fopen(path, "r");
548
	if (!file) {
549
		return 0;
550
	}
551
	memset(test, 0, sizeof(struct rc_test_file));
552
 
553
	count = &test->num_input_lines;
554
 
555
	while (fgets(line, MAX_LINE_LENGTH, file)){
4401 Serge 556
		char last_char = line[MAX_LINE_LENGTH - 1];
557
		if (last_char && last_char != '\n') {
4358 Serge 558
			fprintf(stderr, "Error line cannot be longer than 100 "
559
				"characters:\n%s\n", line);
560
			return 0;
561
		}
562
 
563
		// Comment
564
		if (line[0] == '#' || is_whitespace(line)) {
565
			continue;
566
		}
567
 
568
		if (line[0] == '=') {
569
			count = &test->num_expected_lines;
570
			continue;
571
		}
572
 
573
		(*count)++;
574
	}
575
 
576
	test->input = malloc(sizeof(char *) * test->num_input_lines);
577
	test->expected = malloc(sizeof(char *) * test->num_expected_lines);
578
 
579
	rewind(file);
580
	string_store = test->input;
581
 
582
	while(fgets(line, MAX_LINE_LENGTH, file)) {
583
		// Comment
584
		char * dst;
585
		if (line[0] == '#' || is_whitespace(line)) {
586
			continue;
587
		}
588
 
589
		if (line[0] == '=') {
590
			i = 0;
591
			string_store = test->expected;
592
			continue;
593
		}
594
 
595
		dst = string_store[i++] = malloc((strlen(line) + 1) *
596
							sizeof (char));
597
		strcpy(dst, line);
598
	}
599
 
600
	for (i = 0; i < test->num_input_lines; i++) {
601
		if (test->input[i][0] == 'c') {
602
			add_constant(c, test->input[i]);
603
			continue;
604
		}
605
		// XXX: Parse immediates from the file.
606
		add_instruction(c, test->input[i]);
607
	}
608
	return 1;
609
}