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 */
43unsigned 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
55unsigned 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 */
84static void
85lp_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
98void
99lp_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
110LLVMValueRef
111lp_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
126LLVMValueRef
127lp_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
139LLVMValueRef
140lp_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
154LLVMValueRef
155lp_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 */
174void 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 */
201static 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 */
230boolean
231lp_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
338LLVMValueRef
339lp_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_DOUBLE:
381      case TGSI_TYPE_UNTYPED:
382          /* modifiers on movs assume data is float */
383         res = lp_build_abs(&bld_base->base, res);
384         break;
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
439LLVMValueRef
440lp_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
454LLVMValueRef
455lp_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
510boolean
511lp_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   while (bld_base->pc != -1) {
553      const struct tgsi_full_instruction *instr =
554         bld_base->instructions + bld_base->pc;
555      if (!lp_build_tgsi_inst_llvm(bld_base, instr)) {
556         _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
557                       tgsi_get_opcode_name(instr->Instruction.Opcode));
558         return FALSE;
559      }
560   }
561
562   tgsi_parse_free(&parse);
563
564   FREE(bld_base->instructions);
565
566   if (bld_base->emit_epilogue) {
567      bld_base->emit_epilogue(bld_base);
568   }
569
570   return TRUE;
571}
572