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(&reg, 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(&reg.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, &reg, 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