Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4358 Serge 1
/*
2
 * Copyright (c) 2013 Rob Clark 
3
 *
4
 * Permission is hereby granted, free of charge, to any person obtaining a
5
 * copy of this software and associated documentation files (the "Software"),
6
 * to deal in the Software without restriction, including without limitation
7
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
 * and/or sell copies of the Software, and to permit persons to whom the
9
 * Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice (including the next
12
 * paragraph) shall be included in all copies or substantial portions of the
13
 * Software.
14
 *
15
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
 * SOFTWARE.
22
 */
23
 
24
#include "ir-a3xx.h"
25
 
26
#include 
27
#include 
28
#include 
29
#include 
30
#include 
31
#include 
32
 
33
#include "freedreno_util.h"
34
#include "instr-a3xx.h"
35
 
36
/* simple allocator to carve allocations out of an up-front allocated heap,
37
 * so that we can free everything easily in one shot.
38
 */
39
static void * ir3_alloc(struct ir3_shader *shader, int sz)
40
{
41
	void *ptr = &shader->heap[shader->heap_idx];
42
	shader->heap_idx += align(sz, 4);
43
	return ptr;
44
}
45
 
46
struct ir3_shader * ir3_shader_create(void)
47
{
48
	return calloc(1, sizeof(struct ir3_shader));
49
}
50
 
51
void ir3_shader_destroy(struct ir3_shader *shader)
52
{
53
	free(shader);
54
}
55
 
56
#define iassert(cond) do { \
57
	if (!(cond)) { \
58
		assert(cond); \
59
		return -1; \
60
	} } while (0)
61
 
62
static uint32_t reg(struct ir3_register *reg, struct ir3_shader_info *info,
63
		uint32_t repeat, uint32_t valid_flags)
64
{
65
	reg_t val = { .dummy32 = 0 };
66
 
67
	assert(!(reg->flags & ~valid_flags));
68
 
69
	if (!(reg->flags & IR3_REG_R))
70
		repeat = 0;
71
 
72
	if (reg->flags & IR3_REG_IMMED) {
73
		val.iim_val = reg->iim_val;
74
	} else {
75
		int8_t max = (reg->num + repeat) >> 2;
76
 
77
		val.comp = reg->num & 0x3;
78
		val.num  = reg->num >> 2;
79
 
80
		if (reg->flags & IR3_REG_CONST) {
81
			info->max_const = MAX2(info->max_const, max);
82
		} else if ((max != REG_A0) && (max != REG_P0)) {
83
			if (reg->flags & IR3_REG_HALF) {
84
				info->max_half_reg = MAX2(info->max_half_reg, max);
85
			} else {
86
				info->max_reg = MAX2(info->max_reg, max);
87
			}
88
		}
89
	}
90
 
91
	return val.dummy32;
92
}
93
 
94
static int emit_cat0(struct ir3_instruction *instr, void *ptr,
95
		struct ir3_shader_info *info)
96
{
97
	instr_cat0_t *cat0 = ptr;
98
 
99
	cat0->immed    = instr->cat0.immed;
100
	cat0->repeat   = instr->repeat;
101
	cat0->ss       = !!(instr->flags & IR3_INSTR_SS);
102
	cat0->inv      = instr->cat0.inv;
103
	cat0->comp     = instr->cat0.comp;
104
	cat0->opc      = instr->opc;
105
	cat0->jmp_tgt  = !!(instr->flags & IR3_INSTR_JP);
106
	cat0->sync     = !!(instr->flags & IR3_INSTR_SY);
107
	cat0->opc_cat  = 0;
108
 
109
	return 0;
110
}
111
 
112
static uint32_t type_flags(type_t type)
113
{
114
	return (type_size(type) == 32) ? 0 : IR3_REG_HALF;
115
}
116
 
117
static int emit_cat1(struct ir3_instruction *instr, void *ptr,
118
		struct ir3_shader_info *info)
119
{
120
	struct ir3_register *dst = instr->regs[0];
121
	struct ir3_register *src = instr->regs[1];
122
	instr_cat1_t *cat1 = ptr;
123
 
124
	iassert(instr->regs_count == 2);
125
	iassert(!((dst->flags ^ type_flags(instr->cat1.dst_type)) & IR3_REG_HALF));
126
	iassert((src->flags & IR3_REG_IMMED) ||
127
			!((src->flags ^ type_flags(instr->cat1.src_type)) & IR3_REG_HALF));
128
 
129
	if (src->flags & IR3_REG_IMMED) {
130
		cat1->iim_val = src->iim_val;
131
		cat1->src_im  = 1;
132
	} else if (src->flags & IR3_REG_RELATIV) {
133
		cat1->off       = src->offset;
134
		cat1->src_rel   = 1;
135
		cat1->must_be_3 = 3;
136
	} else {
137
		cat1->src  = reg(src, info, instr->repeat,
138
				IR3_REG_IMMED | IR3_REG_RELATIV |
139
				IR3_REG_R | IR3_REG_CONST | IR3_REG_HALF);
140
	}
141
 
142
	cat1->dst      = reg(dst, info, instr->repeat,
143
			IR3_REG_RELATIV | IR3_REG_EVEN |
144
			IR3_REG_R | IR3_REG_POS_INF | IR3_REG_HALF);
145
	cat1->repeat   = instr->repeat;
146
	cat1->src_r    = !!(src->flags & IR3_REG_R);
147
	cat1->ss       = !!(instr->flags & IR3_INSTR_SS);
148
	cat1->dst_type = instr->cat1.dst_type;
149
	cat1->dst_rel  = !!(dst->flags & IR3_REG_RELATIV);
150
	cat1->src_type = instr->cat1.src_type;
151
	cat1->src_c    = !!(src->flags & IR3_REG_CONST);
152
	cat1->even     = !!(dst->flags & IR3_REG_EVEN);
153
	cat1->pos_inf  = !!(dst->flags & IR3_REG_POS_INF);
154
	cat1->jmp_tgt  = !!(instr->flags & IR3_INSTR_JP);
155
	cat1->sync     = !!(instr->flags & IR3_INSTR_SY);
156
	cat1->opc_cat  = 1;
157
 
158
	return 0;
159
}
160
 
161
static int emit_cat2(struct ir3_instruction *instr, void *ptr,
162
		struct ir3_shader_info *info)
163
{
164
	struct ir3_register *dst = instr->regs[0];
165
	struct ir3_register *src1 = instr->regs[1];
166
	struct ir3_register *src2 = instr->regs[2];
167
	instr_cat2_t *cat2 = ptr;
168
 
169
	iassert((instr->regs_count == 2) || (instr->regs_count == 3));
170
 
171
	cat2->src1     = reg(src1, info, instr->repeat,
172
			IR3_REG_RELATIV | IR3_REG_CONST | IR3_REG_IMMED |
173
			IR3_REG_NEGATE | IR3_REG_ABS | IR3_REG_R | IR3_REG_HALF);
174
	cat2->src1_rel = !!(src1->flags & IR3_REG_RELATIV);
175
	cat2->src1_c   = !!(src1->flags & IR3_REG_CONST);
176
	cat2->src1_im  = !!(src1->flags & IR3_REG_IMMED);
177
	cat2->src1_neg = !!(src1->flags & IR3_REG_NEGATE);
178
	cat2->src1_abs = !!(src1->flags & IR3_REG_ABS);
179
	cat2->src1_r   = !!(src1->flags & IR3_REG_R);
180
 
181
	if (src2) {
182
		iassert((src2->flags & IR3_REG_IMMED) ||
183
				!((src1->flags ^ src2->flags) & IR3_REG_HALF));
184
		cat2->src2     = reg(src2, info, instr->repeat,
185
				IR3_REG_RELATIV | IR3_REG_CONST | IR3_REG_IMMED |
186
				IR3_REG_NEGATE | IR3_REG_ABS | IR3_REG_R | IR3_REG_HALF);
187
		cat2->src2_rel = !!(src2->flags & IR3_REG_RELATIV);
188
		cat2->src2_c   = !!(src2->flags & IR3_REG_CONST);
189
		cat2->src2_im  = !!(src2->flags & IR3_REG_IMMED);
190
		cat2->src2_neg = !!(src2->flags & IR3_REG_NEGATE);
191
		cat2->src2_abs = !!(src2->flags & IR3_REG_ABS);
192
		cat2->src2_r   = !!(src2->flags & IR3_REG_R);
193
	}
194
 
195
	cat2->dst      = reg(dst, info, instr->repeat,
196
			IR3_REG_R | IR3_REG_EI | IR3_REG_HALF);
197
	cat2->repeat   = instr->repeat;
198
	cat2->ss       = !!(instr->flags & IR3_INSTR_SS);
199
	cat2->ul       = !!(instr->flags & IR3_INSTR_UL);
200
	cat2->dst_half = !!((src1->flags ^ dst->flags) & IR3_REG_HALF);
201
	cat2->ei       = !!(dst->flags & IR3_REG_EI);
202
	cat2->cond     = instr->cat2.condition;
203
	cat2->full     = ! (src1->flags & IR3_REG_HALF);
204
	cat2->opc      = instr->opc;
205
	cat2->jmp_tgt  = !!(instr->flags & IR3_INSTR_JP);
206
	cat2->sync     = !!(instr->flags & IR3_INSTR_SY);
207
	cat2->opc_cat  = 2;
208
 
209
	return 0;
210
}
211
 
212
static int emit_cat3(struct ir3_instruction *instr, void *ptr,
213
		struct ir3_shader_info *info)
214
{
215
	struct ir3_register *dst = instr->regs[0];
216
	struct ir3_register *src1 = instr->regs[1];
217
	struct ir3_register *src2 = instr->regs[2];
218
	struct ir3_register *src3 = instr->regs[3];
219
	instr_cat3_t *cat3 = ptr;
220
	uint32_t src_flags = 0;
221
 
222
	switch (instr->opc) {
223
	case OPC_MAD_F16:
224
	case OPC_MAD_U16:
225
	case OPC_MAD_S16:
226
	case OPC_SEL_B16:
227
	case OPC_SEL_S16:
228
	case OPC_SEL_F16:
229
	case OPC_SAD_S16:
230
	case OPC_SAD_S32:  // really??
231
		src_flags |= IR3_REG_HALF;
232
		break;
233
	default:
234
		break;
235
	}
236
 
237
	iassert(instr->regs_count == 4);
238
	iassert(!((src1->flags ^ src_flags) & IR3_REG_HALF));
239
	iassert(!((src2->flags ^ src_flags) & IR3_REG_HALF));
240
	iassert(!((src3->flags ^ src_flags) & IR3_REG_HALF));
241
 
242
	cat3->src1     = reg(src1, info, instr->repeat,
243
			IR3_REG_RELATIV | IR3_REG_CONST |
244
			IR3_REG_NEGATE | IR3_REG_R | IR3_REG_HALF);
245
	cat3->src1_rel = !!(src1->flags & IR3_REG_RELATIV);
246
	cat3->src1_c   = !!(src1->flags & IR3_REG_CONST);
247
	cat3->src1_neg = !!(src1->flags & IR3_REG_NEGATE);
248
	cat3->src1_r   = !!(src1->flags & IR3_REG_R);
249
 
250
	cat3->src2     = reg(src2, info, instr->repeat,
251
			IR3_REG_CONST | IR3_REG_NEGATE |
252
			IR3_REG_R | IR3_REG_HALF);
253
	cat3->src2_c   = !!(src2->flags & IR3_REG_CONST);
254
	cat3->src2_neg = !!(src2->flags & IR3_REG_NEGATE);
255
	cat3->src2_r   = !!(src2->flags & IR3_REG_R);
256
 
257
	cat3->src3     = reg(src3, info, instr->repeat,
258
			IR3_REG_RELATIV | IR3_REG_CONST |
259
			IR3_REG_NEGATE | IR3_REG_R | IR3_REG_HALF);
260
	cat3->src3_rel = !!(src3->flags & IR3_REG_RELATIV);
261
	cat3->src3_c   = !!(src3->flags & IR3_REG_CONST);
262
	cat3->src3_neg = !!(src3->flags & IR3_REG_NEGATE);
263
	cat3->src3_r   = !!(src3->flags & IR3_REG_R);
264
 
265
	cat3->dst      = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
266
	cat3->repeat   = instr->repeat;
267
	cat3->ss       = !!(instr->flags & IR3_INSTR_SS);
268
	cat3->ul       = !!(instr->flags & IR3_INSTR_UL);
269
	cat3->dst_half = !!((src_flags ^ dst->flags) & IR3_REG_HALF);
270
	cat3->opc      = instr->opc;
271
	cat3->jmp_tgt  = !!(instr->flags & IR3_INSTR_JP);
272
	cat3->sync     = !!(instr->flags & IR3_INSTR_SY);
273
	cat3->opc_cat  = 3;
274
 
275
	return 0;
276
}
277
 
278
static int emit_cat4(struct ir3_instruction *instr, void *ptr,
279
		struct ir3_shader_info *info)
280
{
281
	struct ir3_register *dst = instr->regs[0];
282
	struct ir3_register *src = instr->regs[1];
283
	instr_cat4_t *cat4 = ptr;
284
 
285
	iassert(instr->regs_count == 2);
286
 
287
	cat4->src      = reg(src, info, instr->repeat,
288
			IR3_REG_RELATIV | IR3_REG_CONST | IR3_REG_IMMED |
289
			IR3_REG_NEGATE | IR3_REG_ABS | IR3_REG_R |
290
			IR3_REG_HALF);
291
	cat4->src_rel  = !!(src->flags & IR3_REG_RELATIV);
292
	cat4->src_c    = !!(src->flags & IR3_REG_CONST);
293
	cat4->src_im   = !!(src->flags & IR3_REG_IMMED);
294
	cat4->src_neg  = !!(src->flags & IR3_REG_NEGATE);
295
	cat4->src_abs  = !!(src->flags & IR3_REG_ABS);
296
	cat4->src_r    = !!(src->flags & IR3_REG_R);
297
 
298
	cat4->dst      = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
299
	cat4->repeat   = instr->repeat;
300
	cat4->ss       = !!(instr->flags & IR3_INSTR_SS);
301
	cat4->ul       = !!(instr->flags & IR3_INSTR_UL);
302
	cat4->dst_half = !!((src->flags ^ dst->flags) & IR3_REG_HALF);
303
	cat4->full     = ! (src->flags & IR3_REG_HALF);
304
	cat4->opc      = instr->opc;
305
	cat4->jmp_tgt  = !!(instr->flags & IR3_INSTR_JP);
306
	cat4->sync     = !!(instr->flags & IR3_INSTR_SY);
307
	cat4->opc_cat  = 4;
308
 
309
	return 0;
310
}
311
 
312
static int emit_cat5(struct ir3_instruction *instr, void *ptr,
313
		struct ir3_shader_info *info)
314
{
315
	struct ir3_register *dst = instr->regs[0];
316
	struct ir3_register *src1 = instr->regs[1];
317
	struct ir3_register *src2 = instr->regs[2];
318
	struct ir3_register *src3 = instr->regs[3];
319
	instr_cat5_t *cat5 = ptr;
320
 
321
	iassert(!((dst->flags ^ type_flags(instr->cat5.type)) & IR3_REG_HALF));
322
 
323
	if (src1) {
324
		cat5->full = ! (src1->flags & IR3_REG_HALF);
325
		cat5->src1 = reg(src1, info, instr->repeat, IR3_REG_HALF);
326
	}
327
 
328
 
329
	if (instr->flags & IR3_INSTR_S2EN) {
330
		if (src2) {
331
			iassert(!((src1->flags ^ src2->flags) & IR3_REG_HALF));
332
			cat5->s2en.src2 = reg(src2, info, instr->repeat, IR3_REG_HALF);
333
		}
334
		if (src3) {
335
			iassert(src3->flags & IR3_REG_HALF);
336
			cat5->s2en.src3 = reg(src3, info, instr->repeat, IR3_REG_HALF);
337
		}
338
		iassert(!(instr->cat5.samp | instr->cat5.tex));
339
	} else {
340
		iassert(!src3);
341
		if (src2) {
342
			iassert(!((src1->flags ^ src2->flags) & IR3_REG_HALF));
343
			cat5->norm.src2 = reg(src2, info, instr->repeat, IR3_REG_HALF);
344
		}
345
		cat5->norm.samp = instr->cat5.samp;
346
		cat5->norm.tex  = instr->cat5.tex;
347
	}
348
 
349
	cat5->dst      = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
350
	cat5->wrmask   = dst->wrmask;
351
	cat5->type     = instr->cat5.type;
352
	cat5->is_3d    = !!(instr->flags & IR3_INSTR_3D);
353
	cat5->is_a     = !!(instr->flags & IR3_INSTR_A);
354
	cat5->is_s     = !!(instr->flags & IR3_INSTR_S);
355
	cat5->is_s2en  = !!(instr->flags & IR3_INSTR_S2EN);
356
	cat5->is_o     = !!(instr->flags & IR3_INSTR_O);
357
	cat5->is_p     = !!(instr->flags & IR3_INSTR_P);
358
	cat5->opc      = instr->opc;
359
	cat5->jmp_tgt  = !!(instr->flags & IR3_INSTR_JP);
360
	cat5->sync     = !!(instr->flags & IR3_INSTR_SY);
361
	cat5->opc_cat  = 5;
362
 
363
	return 0;
364
}
365
 
366
static int emit_cat6(struct ir3_instruction *instr, void *ptr,
367
		struct ir3_shader_info *info)
368
{
369
	struct ir3_register *dst = instr->regs[0];
370
	struct ir3_register *src = instr->regs[1];
371
	instr_cat6_t *cat6 = ptr;
372
 
373
	iassert(instr->regs_count == 2);
374
 
375
	switch (instr->opc) {
376
	/* load instructions: */
377
	case OPC_LDG:
378
	case OPC_LDP:
379
	case OPC_LDL:
380
	case OPC_LDLW:
381
	case OPC_LDLV:
382
	case OPC_PREFETCH: {
383
		instr_cat6a_t *cat6a = ptr;
384
 
385
		iassert(!((dst->flags ^ type_flags(instr->cat6.type)) & IR3_REG_HALF));
386
 
387
		cat6a->must_be_one1  = 1;
388
		cat6a->must_be_one2  = 1;
389
		cat6a->off = instr->cat6.offset;
390
		cat6a->src = reg(src, info, instr->repeat, 0);
391
		cat6a->dst = reg(dst, info, instr->repeat, IR3_REG_R | IR3_REG_HALF);
392
		break;
393
	}
394
	/* store instructions: */
395
	case OPC_STG:
396
	case OPC_STP:
397
	case OPC_STL:
398
	case OPC_STLW:
399
	case OPC_STI: {
400
		instr_cat6b_t *cat6b = ptr;
401
		uint32_t src_flags = type_flags(instr->cat6.type);
402
		uint32_t dst_flags = (instr->opc == OPC_STI) ? IR3_REG_HALF : 0;
403
 
404
		iassert(!((src->flags ^ src_flags) & IR3_REG_HALF));
405
 
406
		cat6b->must_be_one1  = 1;
407
		cat6b->must_be_one2  = 1;
408
		cat6b->src    = reg(src, info, instr->repeat, src_flags);
409
		cat6b->off_hi = instr->cat6.offset >> 8;
410
		cat6b->off    = instr->cat6.offset;
411
		cat6b->dst    = reg(dst, info, instr->repeat, IR3_REG_R | dst_flags);
412
 
413
		break;
414
	}
415
	default:
416
		// TODO
417
		break;
418
	}
419
 
420
	cat6->iim_val  = instr->cat6.iim_val;
421
	cat6->type     = instr->cat6.type;
422
	cat6->opc      = instr->opc;
423
	cat6->jmp_tgt  = !!(instr->flags & IR3_INSTR_JP);
424
	cat6->sync     = !!(instr->flags & IR3_INSTR_SY);
425
	cat6->opc_cat  = 6;
426
 
427
	return 0;
428
}
429
 
430
static int (*emit[])(struct ir3_instruction *instr, void *ptr,
431
		struct ir3_shader_info *info) = {
432
	emit_cat0, emit_cat1, emit_cat2, emit_cat3, emit_cat4, emit_cat5, emit_cat6,
433
};
434
 
435
void * ir3_shader_assemble(struct ir3_shader *shader, struct ir3_shader_info *info)
436
{
437
	uint32_t *ptr, *dwords;
438
	uint32_t i;
439
 
440
	info->max_reg       = -1;
441
	info->max_half_reg  = -1;
442
	info->max_const     = -1;
443
 
444
	/* need a integer number of instruction "groups" (sets of four
445
	 * instructions), so pad out w/ NOPs if needed:
446
	 */
447
	while (shader->instrs_count != align(shader->instrs_count, 4))
448
		ir3_instr_create(shader, 0, OPC_NOP);
449
 
450
	/* each instruction is 64bits: */
451
	info->sizedwords = 2 * shader->instrs_count;
452
 
453
	ptr = dwords = calloc(1, 4 * info->sizedwords);
454
 
455
	for (i = 0; i < shader->instrs_count; i++) {
456
		struct ir3_instruction *instr = shader->instrs[i];
457
		int ret = emit[instr->category](instr, dwords, info);
458
		if (ret)
459
			goto fail;
460
		dwords += 2;
461
	}
462
 
463
	return ptr;
464
 
465
fail:
466
	free(ptr);
467
	return NULL;
468
}
469
 
470
static struct ir3_register * reg_create(struct ir3_shader *shader,
471
		int num, int flags)
472
{
473
	struct ir3_register *reg =
474
			ir3_alloc(shader, sizeof(struct ir3_register));
475
	reg->flags = flags;
476
	reg->num = num;
477
	return reg;
478
}
479
 
480
static void insert_instr(struct ir3_shader *shader,
481
		struct ir3_instruction *instr)
482
{
483
	assert(shader->instrs_count < ARRAY_SIZE(shader->instrs));
484
	shader->instrs[shader->instrs_count++] = instr;
485
}
486
 
487
struct ir3_instruction * ir3_instr_create(struct ir3_shader *shader,
488
		int category, opc_t opc)
489
{
490
	struct ir3_instruction *instr =
491
			ir3_alloc(shader, sizeof(struct ir3_instruction));
492
	instr->shader = shader;
493
	instr->category = category;
494
	instr->opc = opc;
495
	insert_instr(shader, instr);
496
	return instr;
497
}
498
 
499
struct ir3_instruction * ir3_instr_clone(struct ir3_instruction *instr)
500
{
501
	struct ir3_instruction *new_instr =
502
			ir3_alloc(instr->shader, sizeof(struct ir3_instruction));
503
	unsigned i;
504
 
505
	*new_instr = *instr;
506
	insert_instr(instr->shader, new_instr);
507
 
508
	/* clone registers: */
509
	new_instr->regs_count = 0;
510
	for (i = 0; i < instr->regs_count; i++) {
511
		struct ir3_register *reg = instr->regs[i];
512
		struct ir3_register *new_reg =
513
				ir3_reg_create(new_instr, reg->num, reg->flags);
514
		*new_reg = *reg;
515
	}
516
 
517
	return new_instr;
518
}
519
 
520
struct ir3_register * ir3_reg_create(struct ir3_instruction *instr,
521
		int num, int flags)
522
{
523
	struct ir3_register *reg = reg_create(instr->shader, num, flags);
524
	assert(instr->regs_count < ARRAY_SIZE(instr->regs));
525
	instr->regs[instr->regs_count++] = reg;
526
	return reg;
527
}