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