1/**************************************************************************
2 *
3 * Copyright 2011-2012 Advanced Micro Devices, Inc.
4 * Copyright 2010 VMware, Inc.
5 * Copyright 2009 VMware, Inc.
6 * Copyright 2007-2008 Tungsten Graphics, Inc., Cedar Park, Texas.
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   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);
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;
133   emit_data.arg_count = 1;
134   emit_data.args[0] = arg0;
135   return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
136}
137
138LLVMValueRef
139lp_build_emit_llvm_binary(
140   struct lp_build_tgsi_context *bld_base,
141   unsigned tgsi_opcode,
142   LLVMValueRef arg0,
143   LLVMValueRef arg1)
144{
145   struct lp_build_emit_data emit_data;
146   emit_data.arg_count = 2;
147   emit_data.args[0] = arg0;
148   emit_data.args[1] = arg1;
149   return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
150}
151
152LLVMValueRef
153lp_build_emit_llvm_ternary(
154   struct lp_build_tgsi_context *bld_base,
155   unsigned tgsi_opcode,
156   LLVMValueRef arg0,
157   LLVMValueRef arg1,
158   LLVMValueRef arg2)
159{
160   struct lp_build_emit_data emit_data;
161   emit_data.arg_count = 3;
162   emit_data.args[0] = arg0;
163   emit_data.args[1] = arg1;
164   emit_data.args[2] = arg2;
165   return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data);
166}
167
168/**
169 * The default fetch implementation.
170 */
171void lp_build_fetch_args(
172   struct lp_build_tgsi_context * bld_base,
173   struct lp_build_emit_data * emit_data)
174{
175   unsigned src;
176   for (src = 0; src < emit_data->info->num_src; src++) {
177      emit_data->args[src] = lp_build_emit_fetch(bld_base, emit_data->inst, src,
178                                               emit_data->chan);
179   }
180   emit_data->arg_count = emit_data->info->num_src;
181   lp_build_action_set_dst_type(emit_data, bld_base,
182		emit_data->inst->Instruction.Opcode);
183}
184
185/* XXX: COMMENT
186 * It should be assumed that this function ignores writemasks
187 */
188boolean
189lp_build_tgsi_inst_llvm(
190   struct lp_build_tgsi_context * bld_base,
191   const struct tgsi_full_instruction * inst)
192{
193   unsigned tgsi_opcode = inst->Instruction.Opcode;
194   const struct tgsi_opcode_info * info = tgsi_get_opcode_info(tgsi_opcode);
195   const struct lp_build_tgsi_action * action =
196                                         &bld_base->op_actions[tgsi_opcode];
197   struct lp_build_emit_data emit_data;
198   unsigned chan_index;
199   LLVMValueRef val;
200
201   bld_base->pc++;
202
203   /* Ignore deprecated instructions */
204   switch (inst->Instruction.Opcode) {
205
206   case TGSI_OPCODE_RCC:
207   case TGSI_OPCODE_UP2H:
208   case TGSI_OPCODE_UP2US:
209   case TGSI_OPCODE_UP4B:
210   case TGSI_OPCODE_UP4UB:
211   case TGSI_OPCODE_X2D:
212   case TGSI_OPCODE_ARA:
213   case TGSI_OPCODE_BRA:
214   case TGSI_OPCODE_DIV:
215   case TGSI_OPCODE_PUSHA:
216   case TGSI_OPCODE_POPA:
217   case TGSI_OPCODE_SAD:
218      /* deprecated? */
219      assert(0);
220      return FALSE;
221      break;
222   }
223
224   /* Check if the opcode has been implemented */
225   if (!action->emit) {
226      return FALSE;
227   }
228
229   memset(&emit_data, 0, sizeof(emit_data));
230
231   assert(info->num_dst <= 1);
232   if (info->num_dst) {
233      TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
234         emit_data.output[chan_index] = bld_base->base.undef;
235      }
236   }
237
238   emit_data.inst = inst;
239   emit_data.info = info;
240
241   /* Emit the instructions */
242   if (info->output_mode == TGSI_OUTPUT_COMPONENTWISE && bld_base->soa) {
243      TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
244         emit_data.chan = chan_index;
245         if (!action->fetch_args) {
246            lp_build_fetch_args(bld_base, &emit_data);
247         } else {
248             action->fetch_args(bld_base, &emit_data);
249         }
250         action->emit(action, bld_base, &emit_data);
251      }
252   } else {
253      emit_data.chan = LP_CHAN_ALL;
254      if (action->fetch_args) {
255         action->fetch_args(bld_base, &emit_data);
256      }
257      /* Make sure the output value is stored in emit_data.output[0], unless
258       * the opcode is channel dependent */
259      if (info->output_mode != TGSI_OUTPUT_CHAN_DEPENDENT) {
260         emit_data.chan = 0;
261      }
262      action->emit(action, bld_base, &emit_data);
263
264      /* Replicate the output values */
265      if (info->output_mode == TGSI_OUTPUT_REPLICATE && bld_base->soa) {
266         val = emit_data.output[0];
267         memset(emit_data.output, 0, sizeof(emit_data.output));
268         TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) {
269            emit_data.output[chan_index] = val;
270         }
271      }
272   }
273
274   if (info->num_dst > 0) {
275      bld_base->emit_store(bld_base, inst, info, emit_data.output);
276   }
277   return TRUE;
278}
279
280
281LLVMValueRef
282lp_build_emit_fetch(
283   struct lp_build_tgsi_context *bld_base,
284   const struct tgsi_full_instruction *inst,
285   unsigned src_op,
286   const unsigned chan_index)
287{
288   const struct tgsi_full_src_register *reg = &inst->Src[src_op];
289   unsigned swizzle;
290   LLVMValueRef res;
291   enum tgsi_opcode_type stype = tgsi_opcode_infer_src_type(inst->Instruction.Opcode);
292
293   if (chan_index == LP_CHAN_ALL) {
294      swizzle = ~0;
295   } else {
296      swizzle = tgsi_util_get_full_src_register_swizzle(reg, chan_index);
297      if (swizzle > 3) {
298         assert(0 && "invalid swizzle in emit_fetch()");
299         return bld_base->base.undef;
300      }
301   }
302
303   assert(reg->Register.Index <= bld_base->info->file_max[reg->Register.File]);
304
305   if (bld_base->emit_fetch_funcs[reg->Register.File]) {
306      res = bld_base->emit_fetch_funcs[reg->Register.File](bld_base, reg, stype,
307                                                           swizzle);
308   } else {
309      assert(0 && "invalid src register in emit_fetch()");
310      return bld_base->base.undef;
311   }
312
313   if (reg->Register.Absolute) {
314      res = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_ABS, res);
315   }
316
317   if (reg->Register.Negate) {
318      res = lp_build_negate( &bld_base->base, res );
319   }
320
321   /*
322    * Swizzle the argument
323    */
324
325   if (swizzle == ~0) {
326      res = bld_base->emit_swizzle(bld_base, res,
327                     reg->Register.SwizzleX,
328                     reg->Register.SwizzleY,
329                     reg->Register.SwizzleZ,
330                     reg->Register.SwizzleW);
331   }
332
333   return res;
334
335}
336
337boolean
338lp_build_tgsi_llvm(
339   struct lp_build_tgsi_context * bld_base,
340   const struct tgsi_token *tokens)
341{
342   struct tgsi_parse_context parse;
343
344   if (bld_base->emit_prologue) {
345      bld_base->emit_prologue(bld_base);
346   }
347
348   if (!lp_bld_tgsi_list_init(bld_base)) {
349      return FALSE;
350   }
351
352   tgsi_parse_init( &parse, tokens );
353
354   while( !tgsi_parse_end_of_tokens( &parse ) ) {
355      tgsi_parse_token( &parse );
356
357      switch( parse.FullToken.Token.Type ) {
358      case TGSI_TOKEN_TYPE_DECLARATION:
359         /* Inputs already interpolated */
360         bld_base->emit_declaration(bld_base, &parse.FullToken.FullDeclaration);
361         break;
362
363      case TGSI_TOKEN_TYPE_INSTRUCTION:
364         lp_bld_tgsi_add_instruction(bld_base, &parse.FullToken.FullInstruction);
365         break;
366
367      case TGSI_TOKEN_TYPE_IMMEDIATE:
368         bld_base->emit_immediate(bld_base, &parse.FullToken.FullImmediate);
369         break;
370
371      case TGSI_TOKEN_TYPE_PROPERTY:
372         break;
373
374      default:
375         assert( 0 );
376      }
377   }
378
379   while (bld_base->pc != -1) {
380      struct tgsi_full_instruction *instr = bld_base->instructions +
381							bld_base->pc;
382      const struct tgsi_opcode_info *opcode_info =
383         tgsi_get_opcode_info(instr->Instruction.Opcode);
384      if (!lp_build_tgsi_inst_llvm(bld_base, instr)) {
385         _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
386                       opcode_info->mnemonic);
387         return FALSE;
388      }
389   }
390
391   tgsi_parse_free(&parse);
392
393   FREE(bld_base->instructions);
394
395   if (bld_base->emit_epilogue) {
396      bld_base->emit_epilogue(bld_base);
397   }
398
399   return TRUE;
400}
401