1 /**************************************************************************
2 *
3 * Copyright 2011-2012 Advanced Micro Devices, Inc.
4 * Copyright 2010 VMware, Inc.
5 * Copyright 2009 VMware, Inc.
6 * Copyright 2007-2008 VMware, Inc.
7 * All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the
11 * "Software"), to deal in the Software without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sub license, and/or sell copies of the Software, and to
14 * permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
16 *
17 * The above copyright notice and this permission notice (including the
18 * next paragraph) shall be included in all copies or substantial portions
19 * of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
24 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
25 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 *
29 **************************************************************************/
30
31 #include "gallivm/lp_bld_tgsi.h"
32
33 #include "gallivm/lp_bld_arit.h"
34 #include "gallivm/lp_bld_gather.h"
35 #include "gallivm/lp_bld_init.h"
36 #include "gallivm/lp_bld_intr.h"
37 #include "tgsi/tgsi_info.h"
38 #include "tgsi/tgsi_parse.h"
39 #include "tgsi/tgsi_util.h"
40 #include "util/u_memory.h"
41
42 /* The user is responsible for freeing list->instructions */
lp_bld_tgsi_list_init(struct lp_build_tgsi_context * bld_base)43 unsigned lp_bld_tgsi_list_init(struct lp_build_tgsi_context * bld_base)
44 {
45 bld_base->instructions = (struct tgsi_full_instruction *)
46 MALLOC( LP_MAX_INSTRUCTIONS * sizeof(struct tgsi_full_instruction) );
47 if (!bld_base->instructions) {
48 return 0;
49 }
50 bld_base->max_instructions = LP_MAX_INSTRUCTIONS;
51 return 1;
52 }
53
54
lp_bld_tgsi_add_instruction(struct lp_build_tgsi_context * bld_base,const struct tgsi_full_instruction * inst_to_add)55 unsigned lp_bld_tgsi_add_instruction(
56 struct lp_build_tgsi_context * bld_base,
57 const struct tgsi_full_instruction *inst_to_add)
58 {
59
60 if (bld_base->num_instructions == bld_base->max_instructions) {
61 struct tgsi_full_instruction *instructions;
62 instructions = REALLOC(bld_base->instructions, bld_base->max_instructions
63 * sizeof(struct tgsi_full_instruction),
64 (bld_base->max_instructions + LP_MAX_INSTRUCTIONS)
65 * sizeof(struct tgsi_full_instruction));
66 if (!instructions) {
67 return 0;
68 }
69 bld_base->instructions = instructions;
70 bld_base->max_instructions += LP_MAX_INSTRUCTIONS;
71 }
72 memcpy(bld_base->instructions + bld_base->num_instructions, inst_to_add,
73 sizeof(bld_base->instructions[0]));
74
75 bld_base->num_instructions++;
76
77 return 1;
78 }
79
80
81 /**
82 * This function assumes that all the args in emit_data have been set.
83 */
84 static void
lp_build_action_set_dst_type(struct lp_build_emit_data * emit_data,struct lp_build_tgsi_context * bld_base,unsigned tgsi_opcode)85 lp_build_action_set_dst_type(
86 struct lp_build_emit_data * emit_data,
87 struct lp_build_tgsi_context *bld_base,
88 unsigned tgsi_opcode)
89 {
90 if (emit_data->arg_count == 0) {
91 emit_data->dst_type = LLVMVoidTypeInContext(bld_base->base.gallivm->context);
92 } else {
93 /* XXX: Not all opcodes have the same src and dst types. */
94 emit_data->dst_type = LLVMTypeOf(emit_data->args[0]);
95 }
96 }
97
98 void
lp_build_tgsi_intrinsic(const struct lp_build_tgsi_action * action,struct lp_build_tgsi_context * bld_base,struct lp_build_emit_data * emit_data)99 lp_build_tgsi_intrinsic(
100 const struct lp_build_tgsi_action * action,
101 struct lp_build_tgsi_context * bld_base,
102 struct lp_build_emit_data * emit_data)
103 {
104 struct lp_build_context * base = &bld_base->base;
105 emit_data->output[emit_data->chan] = lp_build_intrinsic(
106 base->gallivm->builder, action->intr_name,
107 emit_data->dst_type, emit_data->args, emit_data->arg_count, 0);
108 }
109
110 LLVMValueRef
lp_build_emit_llvm(struct lp_build_tgsi_context * bld_base,unsigned tgsi_opcode,struct lp_build_emit_data * emit_data)111 lp_build_emit_llvm(
112 struct lp_build_tgsi_context *bld_base,
113 unsigned tgsi_opcode,
114 struct lp_build_emit_data * emit_data)
115 {
116 struct lp_build_tgsi_action * action = &bld_base->op_actions[tgsi_opcode];
117 /* XXX: Assert that this is a componentwise or replicate instruction */
118
119 lp_build_action_set_dst_type(emit_data, bld_base, tgsi_opcode);
120 emit_data->chan = 0;
121 assert(action->emit);
122 action->emit(action, bld_base, emit_data);
123 return emit_data->output[0];
124 }
125
126 LLVMValueRef
lp_build_emit_llvm_unary(struct lp_build_tgsi_context * bld_base,unsigned tgsi_opcode,LLVMValueRef arg0)127 lp_build_emit_llvm_unary(
128 struct lp_build_tgsi_context *bld_base,
129 unsigned tgsi_opcode,
130 LLVMValueRef arg0)
131 {
132 struct lp_build_emit_data emit_data = {{0}};
133 emit_data.info = tgsi_get_opcode_info(tgsi_opcode);
134 emit_data.arg_count = 1;
135 emit_data.args[0] = arg0;
136 return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
137 }
138
139 LLVMValueRef
lp_build_emit_llvm_binary(struct lp_build_tgsi_context * bld_base,unsigned tgsi_opcode,LLVMValueRef arg0,LLVMValueRef arg1)140 lp_build_emit_llvm_binary(
141 struct lp_build_tgsi_context *bld_base,
142 unsigned tgsi_opcode,
143 LLVMValueRef arg0,
144 LLVMValueRef arg1)
145 {
146 struct lp_build_emit_data emit_data = {{0}};
147 emit_data.info = tgsi_get_opcode_info(tgsi_opcode);
148 emit_data.arg_count = 2;
149 emit_data.args[0] = arg0;
150 emit_data.args[1] = arg1;
151 return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
152 }
153
154 LLVMValueRef
lp_build_emit_llvm_ternary(struct lp_build_tgsi_context * bld_base,unsigned tgsi_opcode,LLVMValueRef arg0,LLVMValueRef arg1,LLVMValueRef arg2)155 lp_build_emit_llvm_ternary(
156 struct lp_build_tgsi_context *bld_base,
157 unsigned tgsi_opcode,
158 LLVMValueRef arg0,
159 LLVMValueRef arg1,
160 LLVMValueRef arg2)
161 {
162 struct lp_build_emit_data emit_data = {{0}};
163 emit_data.info = tgsi_get_opcode_info(tgsi_opcode);
164 emit_data.arg_count = 3;
165 emit_data.args[0] = arg0;
166 emit_data.args[1] = arg1;
167 emit_data.args[2] = arg2;
168 return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
169 }
170
171 /**
172 * The default fetch implementation.
173 */
lp_build_fetch_args(struct lp_build_tgsi_context * bld_base,struct lp_build_emit_data * emit_data)174 void lp_build_fetch_args(
175 struct lp_build_tgsi_context * bld_base,
176 struct lp_build_emit_data * emit_data)
177 {
178 unsigned src;
179 for (src = 0; src < emit_data->info->num_src; src++) {
180 emit_data->args[src] = lp_build_emit_fetch(bld_base, emit_data->inst, src,
181 emit_data->src_chan);
182 }
183 emit_data->arg_count = emit_data->info->num_src;
184 lp_build_action_set_dst_type(emit_data, bld_base,
185 emit_data->inst->Instruction.Opcode);
186 }
187
188 /**
189 * with 64-bit src and dst channels aren't 1:1.
190 * check the src/dst types for the opcode,
191 * 1. if neither is 64-bit then src == dst;
192 * 2. if dest is 64-bit
193 * - don't store to y or w
194 * - if src is 64-bit then src == dst.
195 * - else for f2d, d.xy = s.x
196 * - else for f2d, d.zw = s.y
197 * 3. if dst is single, src is 64-bit
198 * - map dst x,z to src xy;
199 * - map dst y,w to src zw;
200 */
get_src_chan_idx(enum tgsi_opcode opcode,int dst_chan_index)201 static int get_src_chan_idx(enum tgsi_opcode opcode,
202 int dst_chan_index)
203 {
204 enum tgsi_opcode_type dtype = tgsi_opcode_infer_dst_type(opcode, 0);
205 enum tgsi_opcode_type stype = tgsi_opcode_infer_src_type(opcode, 0);
206
207 if (!tgsi_type_is_64bit(dtype) && !tgsi_type_is_64bit(stype))
208 return dst_chan_index;
209 if (tgsi_type_is_64bit(dtype)) {
210 if (dst_chan_index == 1 || dst_chan_index == 3)
211 return -1;
212 if (tgsi_type_is_64bit(stype))
213 return dst_chan_index;
214 if (dst_chan_index == 0)
215 return 0;
216 if (dst_chan_index == 2)
217 return 1;
218 } else {
219 if (dst_chan_index == 0 || dst_chan_index == 2)
220 return 0;
221 if (dst_chan_index == 1 || dst_chan_index == 3)
222 return 2;
223 }
224 return -1;
225 }
226
227 /* XXX: COMMENT
228 * It should be assumed that this function ignores writemasks
229 */
230 boolean
lp_build_tgsi_inst_llvm(struct lp_build_tgsi_context * bld_base,const struct tgsi_full_instruction * inst)231 lp_build_tgsi_inst_llvm(
232 struct lp_build_tgsi_context * bld_base,
233 const struct tgsi_full_instruction * inst)
234 {
235 enum tgsi_opcode opcode = inst->Instruction.Opcode;
236 const struct tgsi_opcode_info * info = tgsi_get_opcode_info(opcode);
237 const struct lp_build_tgsi_action * action =
238 &bld_base->op_actions[opcode];
239 struct lp_build_emit_data emit_data;
240 unsigned chan_index;
241 LLVMValueRef val;
242 bld_base->pc++;
243
244 if (bld_base->emit_debug) {
245 bld_base->emit_debug(bld_base, inst, info);
246 }
247
248 /* Ignore deprecated instructions */
249 switch (inst->Instruction.Opcode) {
250
251 case TGSI_OPCODE_UP2US:
252 case TGSI_OPCODE_UP4B:
253 case TGSI_OPCODE_UP4UB:
254 /* deprecated? */
255 assert(0);
256 return FALSE;
257 break;
258 }
259
260 /* Check if the opcode has been implemented */
261 if (!action->emit) {
262 return FALSE;
263 }
264
265 memset(&emit_data, 0, sizeof(emit_data));
266
267 assert(info->num_dst <= 2);
268 if (info->num_dst) {
269 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
270 emit_data.output[chan_index] = bld_base->base.undef;
271 }
272
273 if (info->num_dst >= 2) {
274 TGSI_FOR_EACH_DST1_ENABLED_CHANNEL( inst, chan_index ) {
275 emit_data.output1[chan_index] = bld_base->base.undef;
276 }
277 }
278 }
279
280 emit_data.inst = inst;
281 emit_data.info = info;
282
283 /* Emit the instructions */
284 if (info->output_mode == TGSI_OUTPUT_COMPONENTWISE && bld_base->soa) {
285 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
286 int src_index = get_src_chan_idx(inst->Instruction.Opcode, chan_index);
287 /* ignore channels 1/3 in double dst */
288 if (src_index == -1)
289 continue;
290 emit_data.chan = chan_index;
291 emit_data.src_chan = src_index;
292 if (!action->fetch_args) {
293 lp_build_fetch_args(bld_base, &emit_data);
294 } else {
295 action->fetch_args(bld_base, &emit_data);
296 }
297 action->emit(action, bld_base, &emit_data);
298 }
299 } else {
300 emit_data.chan = LP_CHAN_ALL;
301 if (action->fetch_args) {
302 action->fetch_args(bld_base, &emit_data);
303 }
304 /* Make sure the output value is stored in emit_data.output[0], unless
305 * the opcode is channel dependent */
306 if (info->output_mode != TGSI_OUTPUT_CHAN_DEPENDENT) {
307 emit_data.chan = 0;
308 }
309 action->emit(action, bld_base, &emit_data);
310
311 /* Replicate the output values */
312 if (info->output_mode == TGSI_OUTPUT_REPLICATE && bld_base->soa) {
313 val = emit_data.output[0];
314 memset(emit_data.output, 0, sizeof(emit_data.output));
315 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
316 emit_data.output[chan_index] = val;
317 }
318
319 if (info->num_dst >= 2) {
320 val = emit_data.output1[0];
321 memset(emit_data.output1, 0, sizeof(emit_data.output1));
322 TGSI_FOR_EACH_DST1_ENABLED_CHANNEL(inst, chan_index) {
323 emit_data.output1[chan_index] = val;
324 }
325 }
326 }
327 }
328
329 if (info->num_dst > 0 && info->opcode != TGSI_OPCODE_STORE) {
330 bld_base->emit_store(bld_base, inst, info, 0, emit_data.output);
331 if (info->num_dst >= 2)
332 bld_base->emit_store(bld_base, inst, info, 1, emit_data.output1);
333 }
334 return TRUE;
335 }
336
337
338 LLVMValueRef
lp_build_emit_fetch_src(struct lp_build_tgsi_context * bld_base,const struct tgsi_full_src_register * reg,enum tgsi_opcode_type stype,const unsigned chan_index)339 lp_build_emit_fetch_src(
340 struct lp_build_tgsi_context *bld_base,
341 const struct tgsi_full_src_register *reg,
342 enum tgsi_opcode_type stype,
343 const unsigned chan_index)
344 {
345 unsigned swizzle;
346 LLVMValueRef res;
347
348 if (chan_index == LP_CHAN_ALL) {
349 swizzle = ~0u;
350 } else {
351 swizzle = tgsi_util_get_full_src_register_swizzle(reg, chan_index);
352 if (swizzle > 3) {
353 assert(0 && "invalid swizzle in emit_fetch()");
354 return bld_base->base.undef;
355 }
356 if (tgsi_type_is_64bit(stype)) {
357 unsigned swizzle2;
358 swizzle2 = tgsi_util_get_full_src_register_swizzle(reg, chan_index + 1);
359 if (swizzle2 > 3) {
360 assert(0 && "invalid swizzle in emit_fetch()");
361 return bld_base->base.undef;
362 }
363 swizzle |= (swizzle2 << 16);
364 }
365 }
366
367 assert(reg->Register.Index <= bld_base->info->file_max[reg->Register.File]);
368
369 if (bld_base->emit_fetch_funcs[reg->Register.File]) {
370 res = bld_base->emit_fetch_funcs[reg->Register.File](bld_base, reg, stype,
371 swizzle);
372 } else {
373 assert(0 && "invalid src register in emit_fetch()");
374 return bld_base->base.undef;
375 }
376
377 if (reg->Register.Absolute) {
378 switch (stype) {
379 case TGSI_TYPE_FLOAT:
380 case TGSI_TYPE_UNTYPED:
381 /* modifiers on movs assume data is float */
382 res = lp_build_abs(&bld_base->base, res);
383 break;
384 case TGSI_TYPE_DOUBLE:
385 case TGSI_TYPE_UNSIGNED:
386 case TGSI_TYPE_SIGNED:
387 case TGSI_TYPE_UNSIGNED64:
388 case TGSI_TYPE_SIGNED64:
389 case TGSI_TYPE_VOID:
390 default:
391 /* abs modifier is only legal on floating point types */
392 assert(0);
393 break;
394 }
395 }
396
397 if (reg->Register.Negate) {
398 switch (stype) {
399 case TGSI_TYPE_FLOAT:
400 case TGSI_TYPE_UNTYPED:
401 /* modifiers on movs assume data is float */
402 res = lp_build_negate( &bld_base->base, res );
403 break;
404 case TGSI_TYPE_DOUBLE:
405 /* no double build context */
406 assert(0);
407 break;
408 case TGSI_TYPE_SIGNED:
409 case TGSI_TYPE_UNSIGNED:
410 res = lp_build_negate( &bld_base->int_bld, res );
411 break;
412 case TGSI_TYPE_SIGNED64:
413 case TGSI_TYPE_UNSIGNED64:
414 res = lp_build_negate( &bld_base->int64_bld, res );
415 break;
416 case TGSI_TYPE_VOID:
417 default:
418 assert(0);
419 break;
420 }
421 }
422
423 /*
424 * Swizzle the argument
425 */
426
427 if (swizzle == ~0u) {
428 res = bld_base->emit_swizzle(bld_base, res,
429 reg->Register.SwizzleX,
430 reg->Register.SwizzleY,
431 reg->Register.SwizzleZ,
432 reg->Register.SwizzleW);
433 }
434
435 return res;
436 }
437
438
439 LLVMValueRef
lp_build_emit_fetch(struct lp_build_tgsi_context * bld_base,const struct tgsi_full_instruction * inst,unsigned src_op,const unsigned chan_index)440 lp_build_emit_fetch(
441 struct lp_build_tgsi_context *bld_base,
442 const struct tgsi_full_instruction *inst,
443 unsigned src_op,
444 const unsigned chan_index)
445 {
446 const struct tgsi_full_src_register *reg = &inst->Src[src_op];
447 enum tgsi_opcode_type stype =
448 tgsi_opcode_infer_src_type(inst->Instruction.Opcode, src_op);
449
450 return lp_build_emit_fetch_src(bld_base, reg, stype, chan_index);
451 }
452
453
454 LLVMValueRef
lp_build_emit_fetch_texoffset(struct lp_build_tgsi_context * bld_base,const struct tgsi_full_instruction * inst,unsigned tex_off_op,const unsigned chan_index)455 lp_build_emit_fetch_texoffset(
456 struct lp_build_tgsi_context *bld_base,
457 const struct tgsi_full_instruction *inst,
458 unsigned tex_off_op,
459 const unsigned chan_index)
460 {
461 const struct tgsi_texture_offset *off = &inst->TexOffsets[tex_off_op];
462 struct tgsi_full_src_register reg;
463 unsigned swizzle;
464 LLVMValueRef res;
465 enum tgsi_opcode_type stype = TGSI_TYPE_SIGNED;
466
467 /* convert offset "register" to ordinary register so can use normal emit funcs */
468 memset(®, 0, sizeof(reg));
469 reg.Register.File = off->File;
470 reg.Register.Index = off->Index;
471 reg.Register.SwizzleX = off->SwizzleX;
472 reg.Register.SwizzleY = off->SwizzleY;
473 reg.Register.SwizzleZ = off->SwizzleZ;
474
475 if (chan_index == LP_CHAN_ALL) {
476 swizzle = ~0;
477 } else {
478 assert(chan_index < TGSI_SWIZZLE_W);
479 swizzle = tgsi_util_get_src_register_swizzle(®.Register, chan_index);
480 }
481
482 assert(off->Index <= bld_base->info->file_max[off->File]);
483
484 if (bld_base->emit_fetch_funcs[off->File]) {
485 res = bld_base->emit_fetch_funcs[off->File](bld_base, ®, stype,
486 swizzle);
487 } else {
488 assert(0 && "invalid src register in emit_fetch_texoffset()");
489 return bld_base->base.undef;
490 }
491
492 /*
493 * Swizzle the argument
494 */
495
496 if (swizzle == ~0u) {
497 res = bld_base->emit_swizzle(bld_base, res,
498 off->SwizzleX,
499 off->SwizzleY,
500 off->SwizzleZ,
501 /* there's no 4th channel */
502 off->SwizzleX);
503 }
504
505 return res;
506
507 }
508
509
510 boolean
lp_build_tgsi_llvm(struct lp_build_tgsi_context * bld_base,const struct tgsi_token * tokens)511 lp_build_tgsi_llvm(
512 struct lp_build_tgsi_context * bld_base,
513 const struct tgsi_token *tokens)
514 {
515 struct tgsi_parse_context parse;
516
517 if (bld_base->emit_prologue) {
518 bld_base->emit_prologue(bld_base);
519 }
520
521 if (!lp_bld_tgsi_list_init(bld_base)) {
522 return FALSE;
523 }
524
525 tgsi_parse_init( &parse, tokens );
526
527 while( !tgsi_parse_end_of_tokens( &parse ) ) {
528 tgsi_parse_token( &parse );
529
530 switch( parse.FullToken.Token.Type ) {
531 case TGSI_TOKEN_TYPE_DECLARATION:
532 /* Inputs already interpolated */
533 bld_base->emit_declaration(bld_base, &parse.FullToken.FullDeclaration);
534 break;
535
536 case TGSI_TOKEN_TYPE_INSTRUCTION:
537 lp_bld_tgsi_add_instruction(bld_base, &parse.FullToken.FullInstruction);
538 break;
539
540 case TGSI_TOKEN_TYPE_IMMEDIATE:
541 bld_base->emit_immediate(bld_base, &parse.FullToken.FullImmediate);
542 break;
543
544 case TGSI_TOKEN_TYPE_PROPERTY:
545 break;
546
547 default:
548 assert( 0 );
549 }
550 }
551
552 if (bld_base->emit_prologue_post_decl) {
553 bld_base->emit_prologue_post_decl(bld_base);
554 }
555
556 while (bld_base->pc != -1) {
557 const struct tgsi_full_instruction *instr =
558 bld_base->instructions + bld_base->pc;
559 if (!lp_build_tgsi_inst_llvm(bld_base, instr)) {
560 _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
561 tgsi_get_opcode_name(instr->Instruction.Opcode));
562 return FALSE;
563 }
564 }
565
566 tgsi_parse_free(&parse);
567
568 FREE(bld_base->instructions);
569
570 if (bld_base->emit_epilogue) {
571 bld_base->emit_epilogue(bld_base);
572 }
573
574 return TRUE;
575 }
576