1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2013 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #ifndef TOY_COMPILER_H
29 #define TOY_COMPILER_H
30
31 #include "genhw/genhw.h"
32 #include "util/slab.h"
33
34 #include "ilo_common.h"
35 #include "toy_compiler_reg.h"
36
37 /**
38 * Toy opcodes.
39 */
40 enum toy_opcode {
41 /* 0..127 are reserved for GEN6_OPCODE_x */
42 TOY_OPCODE_LAST_HW = 127,
43
44 TOY_OPCODE_DO,
45
46 /* TGSI register functions */
47 TOY_OPCODE_TGSI_IN,
48 TOY_OPCODE_TGSI_CONST,
49 TOY_OPCODE_TGSI_SV,
50 TOY_OPCODE_TGSI_IMM,
51 TOY_OPCODE_TGSI_INDIRECT_FETCH,
52 TOY_OPCODE_TGSI_INDIRECT_STORE,
53
54 /* TGSI sampling functions */
55 TOY_OPCODE_TGSI_TEX,
56 TOY_OPCODE_TGSI_TXB,
57 TOY_OPCODE_TGSI_TXD,
58 TOY_OPCODE_TGSI_TXL,
59 TOY_OPCODE_TGSI_TXP,
60 TOY_OPCODE_TGSI_TXF,
61 TOY_OPCODE_TGSI_TXQ,
62 TOY_OPCODE_TGSI_TXQ_LZ,
63 TOY_OPCODE_TGSI_TEX2,
64 TOY_OPCODE_TGSI_TXB2,
65 TOY_OPCODE_TGSI_TXL2,
66 TOY_OPCODE_TGSI_SAMPLE,
67 TOY_OPCODE_TGSI_SAMPLE_I,
68 TOY_OPCODE_TGSI_SAMPLE_I_MS,
69 TOY_OPCODE_TGSI_SAMPLE_B,
70 TOY_OPCODE_TGSI_SAMPLE_C,
71 TOY_OPCODE_TGSI_SAMPLE_C_LZ,
72 TOY_OPCODE_TGSI_SAMPLE_D,
73 TOY_OPCODE_TGSI_SAMPLE_L,
74 TOY_OPCODE_TGSI_GATHER4,
75 TOY_OPCODE_TGSI_SVIEWINFO,
76 TOY_OPCODE_TGSI_SAMPLE_POS,
77 TOY_OPCODE_TGSI_SAMPLE_INFO,
78
79 /* math functions */
80 TOY_OPCODE_INV,
81 TOY_OPCODE_LOG,
82 TOY_OPCODE_EXP,
83 TOY_OPCODE_SQRT,
84 TOY_OPCODE_RSQ,
85 TOY_OPCODE_SIN,
86 TOY_OPCODE_COS,
87 TOY_OPCODE_FDIV,
88 TOY_OPCODE_POW,
89 TOY_OPCODE_INT_DIV_QUOTIENT,
90 TOY_OPCODE_INT_DIV_REMAINDER,
91
92 /* URB functions */
93 TOY_OPCODE_URB_WRITE,
94
95 /* GS-specific functions */
96 TOY_OPCODE_EMIT,
97 TOY_OPCODE_ENDPRIM,
98
99 /* FS-specific functions */
100 TOY_OPCODE_DDX,
101 TOY_OPCODE_DDY,
102 TOY_OPCODE_FB_WRITE,
103 TOY_OPCODE_KIL,
104 };
105
106 /**
107 * Toy instruction.
108 */
109 struct toy_inst {
110 unsigned opcode:8; /* enum toy_opcode */
111 unsigned access_mode:1; /* GEN6_ALIGN_x */
112 unsigned mask_ctrl:1; /* GEN6_MASKCTRL_x */
113 unsigned dep_ctrl:2; /* GEN6_DEPCTRL_x */
114 unsigned qtr_ctrl:2; /* GEN6_QTRCTRL_x */
115 unsigned thread_ctrl:2; /* GEN6_THREADCTRL_x */
116 unsigned pred_ctrl:4; /* GEN6_PREDCTRL_x */
117 unsigned pred_inv:1; /* true or false */
118 unsigned exec_size:3; /* GEN6_EXECSIZE_x */
119 unsigned cond_modifier:4; /* GEN6_COND_x */
120 unsigned acc_wr_ctrl:1; /* true or false */
121 unsigned saturate:1; /* true or false */
122
123 /* true if the instruction should be ignored for instruction iteration */
124 unsigned marker:1;
125
126 unsigned pad:1;
127
128 struct toy_dst dst;
129 struct toy_src src[5]; /* match TGSI_FULL_MAX_SRC_REGISTERS */
130
131 struct {
132 int target; /* TGSI_TEXTURE_x */
133 struct toy_src offsets[1]; /* need to be 4 when GATHER4 is supported */
134 } tex;
135
136 struct list_head list;
137 };
138
139 struct toy_compaction_table {
140 uint32_t control[32];
141 uint32_t datatype[32];
142 uint32_t subreg[32];
143 uint32_t src[32];
144
145 uint32_t control_3src[4];
146 uint64_t source_3src[4];
147 };
148
149 /**
150 * Toy compiler.
151 */
152 struct toy_compiler {
153 const struct ilo_dev *dev;
154
155 struct toy_inst templ;
156 struct slab_mempool mempool;
157 struct list_head instructions;
158 struct list_head *iter, *iter_next;
159
160 /* this is not set until toy_compiler_legalize_for_asm() */
161 int num_instructions;
162
163 int rect_linear_width;
164 int next_vrf;
165
166 bool fail;
167 const char *reason;
168 };
169
170 /**
171 * Allocate the given number of VRF registers.
172 */
173 static inline int
tc_alloc_vrf(struct toy_compiler * tc,int count)174 tc_alloc_vrf(struct toy_compiler *tc, int count)
175 {
176 const int vrf = tc->next_vrf;
177
178 tc->next_vrf += count;
179
180 return vrf;
181 }
182
183 /**
184 * Allocate a temporary register.
185 */
186 static inline struct toy_dst
tc_alloc_tmp(struct toy_compiler * tc)187 tc_alloc_tmp(struct toy_compiler *tc)
188 {
189 return tdst(TOY_FILE_VRF, tc_alloc_vrf(tc, 1), 0);
190 }
191
192 /**
193 * Allocate four temporary registers.
194 */
195 static inline void
tc_alloc_tmp4(struct toy_compiler * tc,struct toy_dst * tmp)196 tc_alloc_tmp4(struct toy_compiler *tc, struct toy_dst *tmp)
197 {
198 tmp[0] = tc_alloc_tmp(tc);
199 tmp[1] = tc_alloc_tmp(tc);
200 tmp[2] = tc_alloc_tmp(tc);
201 tmp[3] = tc_alloc_tmp(tc);
202 }
203
204 /**
205 * Duplicate an instruction at the current location.
206 */
207 static inline struct toy_inst *
tc_duplicate_inst(struct toy_compiler * tc,const struct toy_inst * inst)208 tc_duplicate_inst(struct toy_compiler *tc, const struct toy_inst *inst)
209 {
210 struct toy_inst *new_inst;
211
212 new_inst = slab_alloc_st(&tc->mempool);
213 if (!new_inst)
214 return NULL;
215
216 *new_inst = *inst;
217 list_addtail(&new_inst->list, tc->iter_next);
218
219 return new_inst;
220 }
221
222 /**
223 * Move an instruction to the current location.
224 */
225 static inline void
tc_move_inst(struct toy_compiler * tc,struct toy_inst * inst)226 tc_move_inst(struct toy_compiler *tc, struct toy_inst *inst)
227 {
228 list_del(&inst->list);
229 list_addtail(&inst->list, tc->iter_next);
230 }
231
232 /**
233 * Discard an instruction.
234 */
235 static inline void
tc_discard_inst(struct toy_compiler * tc,struct toy_inst * inst)236 tc_discard_inst(struct toy_compiler *tc, struct toy_inst *inst)
237 {
238 list_del(&inst->list);
239 slab_free_st(&tc->mempool, inst);
240 }
241
242 /**
243 * Add a new instruction at the current location, using tc->templ as the
244 * template.
245 */
246 static inline struct toy_inst *
tc_add(struct toy_compiler * tc)247 tc_add(struct toy_compiler *tc)
248 {
249 return tc_duplicate_inst(tc, &tc->templ);
250 }
251
252 /**
253 * A convenient version of tc_add() for instructions with 3 source operands.
254 */
255 static inline struct toy_inst *
tc_add3(struct toy_compiler * tc,unsigned opcode,struct toy_dst dst,struct toy_src src0,struct toy_src src1,struct toy_src src2)256 tc_add3(struct toy_compiler *tc, unsigned opcode,
257 struct toy_dst dst,
258 struct toy_src src0,
259 struct toy_src src1,
260 struct toy_src src2)
261 {
262 struct toy_inst *inst;
263
264 inst = tc_add(tc);
265 if (!inst)
266 return NULL;
267
268 inst->opcode = opcode;
269 inst->dst = dst;
270 inst->src[0] = src0;
271 inst->src[1] = src1;
272 inst->src[2] = src2;
273
274 return inst;
275 }
276
277 /**
278 * A convenient version of tc_add() for instructions with 2 source operands.
279 */
280 static inline struct toy_inst *
tc_add2(struct toy_compiler * tc,int opcode,struct toy_dst dst,struct toy_src src0,struct toy_src src1)281 tc_add2(struct toy_compiler *tc, int opcode,
282 struct toy_dst dst,
283 struct toy_src src0,
284 struct toy_src src1)
285 {
286 return tc_add3(tc, opcode, dst, src0, src1, tsrc_null());
287 }
288
289 /**
290 * A convenient version of tc_add() for instructions with 1 source operand.
291 */
292 static inline struct toy_inst *
tc_add1(struct toy_compiler * tc,unsigned opcode,struct toy_dst dst,struct toy_src src0)293 tc_add1(struct toy_compiler *tc, unsigned opcode,
294 struct toy_dst dst,
295 struct toy_src src0)
296 {
297 return tc_add2(tc, opcode, dst, src0, tsrc_null());
298 }
299
300 /**
301 * A convenient version of tc_add() for instructions without source or
302 * destination operands.
303 */
304 static inline struct toy_inst *
tc_add0(struct toy_compiler * tc,unsigned opcode)305 tc_add0(struct toy_compiler *tc, unsigned opcode)
306 {
307 return tc_add1(tc, opcode, tdst_null(), tsrc_null());
308 }
309
310 #define TC_ALU0(func, opcode) \
311 static inline struct toy_inst * \
312 func(struct toy_compiler *tc) \
313 { \
314 return tc_add0(tc, opcode); \
315 }
316
317 #define TC_ALU1(func, opcode) \
318 static inline struct toy_inst * \
319 func(struct toy_compiler *tc, \
320 struct toy_dst dst, \
321 struct toy_src src) \
322 { \
323 return tc_add1(tc, opcode, dst, src); \
324 }
325
326 #define TC_ALU2(func, opcode) \
327 static inline struct toy_inst * \
328 func(struct toy_compiler *tc, \
329 struct toy_dst dst, \
330 struct toy_src src0, \
331 struct toy_src src1) \
332 { \
333 return tc_add2(tc, opcode, \
334 dst, src0, src1); \
335 }
336
337 #define TC_ALU3(func, opcode) \
338 static inline struct toy_inst * \
339 func(struct toy_compiler *tc, \
340 struct toy_dst dst, \
341 struct toy_src src0, \
342 struct toy_src src1, \
343 struct toy_src src2) \
344 { \
345 return tc_add3(tc, opcode, \
346 dst, src0, src1, src2); \
347 }
348
349 #define TC_CND2(func, opcode) \
350 static inline struct toy_inst * \
351 func(struct toy_compiler *tc, \
352 struct toy_dst dst, \
353 struct toy_src src0, \
354 struct toy_src src1, \
355 unsigned cond_modifier) \
356 { \
357 struct toy_inst *inst; \
358 inst = tc_add2(tc, opcode, \
359 dst, src0, src1); \
360 inst->cond_modifier = cond_modifier; \
361 return inst; \
362 }
363
TC_ALU0(tc_NOP,GEN6_OPCODE_NOP)364 TC_ALU0(tc_NOP, GEN6_OPCODE_NOP)
365 TC_ALU0(tc_ELSE, GEN6_OPCODE_ELSE)
366 TC_ALU0(tc_ENDIF, GEN6_OPCODE_ENDIF)
367 TC_ALU1(tc_MOV, GEN6_OPCODE_MOV)
368 TC_ALU1(tc_RNDD, GEN6_OPCODE_RNDD)
369 TC_ALU1(tc_INV, TOY_OPCODE_INV)
370 TC_ALU1(tc_FRC, GEN6_OPCODE_FRC)
371 TC_ALU1(tc_EXP, TOY_OPCODE_EXP)
372 TC_ALU1(tc_LOG, TOY_OPCODE_LOG)
373 TC_ALU2(tc_ADD, GEN6_OPCODE_ADD)
374 TC_ALU2(tc_MUL, GEN6_OPCODE_MUL)
375 TC_ALU2(tc_AND, GEN6_OPCODE_AND)
376 TC_ALU2(tc_OR, GEN6_OPCODE_OR)
377 TC_ALU2(tc_DP2, GEN6_OPCODE_DP2)
378 TC_ALU2(tc_DP3, GEN6_OPCODE_DP3)
379 TC_ALU2(tc_DP4, GEN6_OPCODE_DP4)
380 TC_ALU2(tc_SHL, GEN6_OPCODE_SHL)
381 TC_ALU2(tc_SHR, GEN6_OPCODE_SHR)
382 TC_ALU2(tc_POW, TOY_OPCODE_POW)
383 TC_ALU3(tc_MAC, GEN6_OPCODE_MAC)
384 TC_CND2(tc_SEL, GEN6_OPCODE_SEL)
385 TC_CND2(tc_CMP, GEN6_OPCODE_CMP)
386 TC_CND2(tc_IF, GEN6_OPCODE_IF)
387 TC_CND2(tc_SEND, GEN6_OPCODE_SEND)
388
389 /**
390 * Upcast a list_head to an instruction.
391 */
392 static inline struct toy_inst *
393 tc_list_to_inst(struct toy_compiler *tc, struct list_head *item)
394 {
395 return container_of(item, (struct toy_inst *) NULL, list);
396 }
397
398 /**
399 * Return the instruction at the current location.
400 */
401 static inline struct toy_inst *
tc_current(struct toy_compiler * tc)402 tc_current(struct toy_compiler *tc)
403 {
404 return (tc->iter != &tc->instructions) ?
405 tc_list_to_inst(tc, tc->iter) : NULL;
406 }
407
408 /**
409 * Set the current location to the head.
410 */
411 static inline void
tc_head(struct toy_compiler * tc)412 tc_head(struct toy_compiler *tc)
413 {
414 tc->iter = &tc->instructions;
415 tc->iter_next = tc->iter->next;
416 }
417
418 /**
419 * Set the current location to the tail.
420 */
421 static inline void
tc_tail(struct toy_compiler * tc)422 tc_tail(struct toy_compiler *tc)
423 {
424 tc->iter = &tc->instructions;
425 tc->iter_next = tc->iter;
426 }
427
428 /**
429 * Advance the current location.
430 */
431 static inline struct toy_inst *
tc_next_no_skip(struct toy_compiler * tc)432 tc_next_no_skip(struct toy_compiler *tc)
433 {
434 /* stay at the tail so that new instructions are added there */
435 if (tc->iter_next == &tc->instructions) {
436 tc_tail(tc);
437 return NULL;
438 }
439
440 tc->iter = tc->iter_next;
441 tc->iter_next = tc->iter_next->next;
442
443 return tc_list_to_inst(tc, tc->iter);
444 }
445
446 /**
447 * Advance the current location, skipping markers.
448 */
449 static inline struct toy_inst *
tc_next(struct toy_compiler * tc)450 tc_next(struct toy_compiler *tc)
451 {
452 struct toy_inst *inst;
453
454 do {
455 inst = tc_next_no_skip(tc);
456 } while (inst && inst->marker);
457
458 return inst;
459 }
460
461 static inline void
tc_fail(struct toy_compiler * tc,const char * reason)462 tc_fail(struct toy_compiler *tc, const char *reason)
463 {
464 if (!tc->fail) {
465 tc->fail = true;
466 tc->reason = reason;
467 }
468 }
469
470 void
471 toy_compiler_init(struct toy_compiler *tc, const struct ilo_dev *dev);
472
473 void
474 toy_compiler_cleanup(struct toy_compiler *tc);
475
476 void
477 toy_compiler_dump(struct toy_compiler *tc);
478
479 void *
480 toy_compiler_assemble(struct toy_compiler *tc, int *size);
481
482 const struct toy_compaction_table *
483 toy_compiler_get_compaction_table(const struct ilo_dev *dev);
484
485 void
486 toy_compiler_disassemble(const struct ilo_dev *dev,
487 const void *kernel, int size,
488 bool dump_hex);
489
490 #endif /* TOY_COMPILER_H */
491