• 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 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 */
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,struct tgsi_full_instruction * inst_to_add)55 unsigned 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  */
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);
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;
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 
138 LLVMValueRef
lp_build_emit_llvm_binary(struct lp_build_tgsi_context * bld_base,unsigned tgsi_opcode,LLVMValueRef arg0,LLVMValueRef arg1)139 lp_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 
152 LLVMValueRef
lp_build_emit_llvm_ternary(struct lp_build_tgsi_context * bld_base,unsigned tgsi_opcode,LLVMValueRef arg0,LLVMValueRef arg1,LLVMValueRef arg2)153 lp_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  */
lp_build_fetch_args(struct lp_build_tgsi_context * bld_base,struct lp_build_emit_data * emit_data)171 void 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  */
188 boolean
lp_build_tgsi_inst_llvm(struct lp_build_tgsi_context * bld_base,const struct tgsi_full_instruction * inst)189 lp_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 
281 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)282 lp_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 
337 boolean
lp_build_tgsi_llvm(struct lp_build_tgsi_context * bld_base,const struct tgsi_token * tokens)338 lp_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