1 /**************************************************************************
3 * Copyright 2011-2012 Advanced Micro Devices, Inc.
4 * Copyright 2010 VMware, Inc.
5 * Copyright 2009 VMware, Inc.
6 * Copyright 2007-2008 VMware, Inc.
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:
17 * The above copyright notice and this permission notice (including the
18 * next paragraph) shall be included in all copies or substantial portions
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.
29 **************************************************************************/
31 #include "gallivm/lp_bld_tgsi.h"
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"
42 /* The user is responsible for freeing list->instructions */
43 unsigned lp_bld_tgsi_list_init(struct lp_build_tgsi_context
* bld_base
)
45 bld_base
->instructions
= (struct tgsi_full_instruction
*)
46 MALLOC( LP_MAX_INSTRUCTIONS
* sizeof(struct tgsi_full_instruction
) );
47 if (!bld_base
->instructions
) {
50 bld_base
->max_instructions
= LP_MAX_INSTRUCTIONS
;
55 unsigned lp_bld_tgsi_add_instruction(
56 struct lp_build_tgsi_context
* bld_base
,
57 const struct tgsi_full_instruction
*inst_to_add
)
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
));
69 bld_base
->instructions
= instructions
;
70 bld_base
->max_instructions
+= LP_MAX_INSTRUCTIONS
;
72 memcpy(bld_base
->instructions
+ bld_base
->num_instructions
, inst_to_add
,
73 sizeof(bld_base
->instructions
[0]));
75 bld_base
->num_instructions
++;
82 * This function assumes that all the args in emit_data have been set.
85 lp_build_action_set_dst_type(
86 struct lp_build_emit_data
* emit_data
,
87 struct lp_build_tgsi_context
*bld_base
,
90 if (emit_data
->arg_count
== 0) {
91 emit_data
->dst_type
= LLVMVoidTypeInContext(bld_base
->base
.gallivm
->context
);
93 /* XXX: Not all opcodes have the same src and dst types. */
94 emit_data
->dst_type
= LLVMTypeOf(emit_data
->args
[0]);
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
)
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
);
112 struct lp_build_tgsi_context
*bld_base
,
113 unsigned tgsi_opcode
,
114 struct lp_build_emit_data
* emit_data
)
116 struct lp_build_tgsi_action
* action
= &bld_base
->op_actions
[tgsi_opcode
];
117 /* XXX: Assert that this is a componentwise or replicate instruction */
119 lp_build_action_set_dst_type(emit_data
, bld_base
, tgsi_opcode
);
121 assert(action
->emit
);
122 action
->emit(action
, bld_base
, emit_data
);
123 return emit_data
->output
[0];
127 lp_build_emit_llvm_unary(
128 struct lp_build_tgsi_context
*bld_base
,
129 unsigned tgsi_opcode
,
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
);
139 lp_build_emit_llvm_binary(
140 struct lp_build_tgsi_context
*bld_base
,
141 unsigned tgsi_opcode
,
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
);
153 lp_build_emit_llvm_ternary(
154 struct lp_build_tgsi_context
*bld_base
,
155 unsigned tgsi_opcode
,
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
);
169 * The default fetch implementation.
171 void lp_build_fetch_args(
172 struct lp_build_tgsi_context
* bld_base
,
173 struct lp_build_emit_data
* emit_data
)
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
,
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
);
186 * It should be assumed that this function ignores writemasks
189 lp_build_tgsi_inst_llvm(
190 struct lp_build_tgsi_context
* bld_base
,
191 const struct tgsi_full_instruction
* inst
)
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
;
203 if (bld_base
->emit_debug
) {
204 bld_base
->emit_debug(bld_base
, inst
, info
);
207 /* Ignore deprecated instructions */
208 switch (inst
->Instruction
.Opcode
) {
210 case TGSI_OPCODE_RCC
:
211 case TGSI_OPCODE_UP2H
:
212 case TGSI_OPCODE_UP2US
:
213 case TGSI_OPCODE_UP4B
:
214 case TGSI_OPCODE_UP4UB
:
215 case TGSI_OPCODE_X2D
:
216 case TGSI_OPCODE_ARA
:
217 case TGSI_OPCODE_BRA
:
218 case TGSI_OPCODE_PUSHA
:
219 case TGSI_OPCODE_POPA
:
220 case TGSI_OPCODE_SAD
:
227 /* Check if the opcode has been implemented */
232 memset(&emit_data
, 0, sizeof(emit_data
));
234 assert(info
->num_dst
<= 1);
236 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst
, chan_index
) {
237 emit_data
.output
[chan_index
] = bld_base
->base
.undef
;
241 emit_data
.inst
= inst
;
242 emit_data
.info
= info
;
244 /* Emit the instructions */
245 if (info
->output_mode
== TGSI_OUTPUT_COMPONENTWISE
&& bld_base
->soa
) {
246 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst
, chan_index
) {
247 emit_data
.chan
= chan_index
;
248 if (!action
->fetch_args
) {
249 lp_build_fetch_args(bld_base
, &emit_data
);
251 action
->fetch_args(bld_base
, &emit_data
);
253 action
->emit(action
, bld_base
, &emit_data
);
256 emit_data
.chan
= LP_CHAN_ALL
;
257 if (action
->fetch_args
) {
258 action
->fetch_args(bld_base
, &emit_data
);
260 /* Make sure the output value is stored in emit_data.output[0], unless
261 * the opcode is channel dependent */
262 if (info
->output_mode
!= TGSI_OUTPUT_CHAN_DEPENDENT
) {
265 action
->emit(action
, bld_base
, &emit_data
);
267 /* Replicate the output values */
268 if (info
->output_mode
== TGSI_OUTPUT_REPLICATE
&& bld_base
->soa
) {
269 val
= emit_data
.output
[0];
270 memset(emit_data
.output
, 0, sizeof(emit_data
.output
));
271 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst
, chan_index
) {
272 emit_data
.output
[chan_index
] = val
;
277 if (info
->num_dst
> 0) {
278 bld_base
->emit_store(bld_base
, inst
, info
, emit_data
.output
);
286 struct lp_build_tgsi_context
*bld_base
,
287 const struct tgsi_full_instruction
*inst
,
289 const unsigned chan_index
)
291 const struct tgsi_full_src_register
*reg
= &inst
->Src
[src_op
];
294 enum tgsi_opcode_type stype
= tgsi_opcode_infer_src_type(inst
->Instruction
.Opcode
);
296 if (chan_index
== LP_CHAN_ALL
) {
299 swizzle
= tgsi_util_get_full_src_register_swizzle(reg
, chan_index
);
301 assert(0 && "invalid swizzle in emit_fetch()");
302 return bld_base
->base
.undef
;
306 assert(reg
->Register
.Index
<= bld_base
->info
->file_max
[reg
->Register
.File
]);
308 if (bld_base
->emit_fetch_funcs
[reg
->Register
.File
]) {
309 res
= bld_base
->emit_fetch_funcs
[reg
->Register
.File
](bld_base
, reg
, stype
,
312 assert(0 && "invalid src register in emit_fetch()");
313 return bld_base
->base
.undef
;
316 if (reg
->Register
.Absolute
) {
318 case TGSI_TYPE_FLOAT
:
319 case TGSI_TYPE_DOUBLE
:
320 case TGSI_TYPE_UNTYPED
:
321 /* modifiers on movs assume data is float */
322 res
= lp_build_emit_llvm_unary(bld_base
, TGSI_OPCODE_ABS
, res
);
324 case TGSI_TYPE_UNSIGNED
:
325 case TGSI_TYPE_SIGNED
:
328 /* abs modifier is only legal on floating point types */
334 if (reg
->Register
.Negate
) {
336 case TGSI_TYPE_FLOAT
:
337 case TGSI_TYPE_UNTYPED
:
338 /* modifiers on movs assume data is float */
339 res
= lp_build_negate( &bld_base
->base
, res
);
341 case TGSI_TYPE_DOUBLE
:
342 /* no double build context */
345 case TGSI_TYPE_SIGNED
:
346 case TGSI_TYPE_UNSIGNED
:
347 res
= lp_build_negate( &bld_base
->int_bld
, res
);
357 * Swizzle the argument
361 res
= bld_base
->emit_swizzle(bld_base
, res
,
362 reg
->Register
.SwizzleX
,
363 reg
->Register
.SwizzleY
,
364 reg
->Register
.SwizzleZ
,
365 reg
->Register
.SwizzleW
);
374 lp_build_emit_fetch_texoffset(
375 struct lp_build_tgsi_context
*bld_base
,
376 const struct tgsi_full_instruction
*inst
,
378 const unsigned chan_index
)
380 const struct tgsi_texture_offset
*off
= &inst
->TexOffsets
[tex_off_op
];
381 struct tgsi_full_src_register reg
;
384 enum tgsi_opcode_type stype
= TGSI_TYPE_SIGNED
;
386 /* convert offset "register" to ordinary register so can use normal emit funcs */
387 memset(®
, 0, sizeof(reg
));
388 reg
.Register
.File
= off
->File
;
389 reg
.Register
.Index
= off
->Index
;
390 reg
.Register
.SwizzleX
= off
->SwizzleX
;
391 reg
.Register
.SwizzleY
= off
->SwizzleY
;
392 reg
.Register
.SwizzleZ
= off
->SwizzleZ
;
394 if (chan_index
== LP_CHAN_ALL
) {
397 assert(chan_index
< TGSI_SWIZZLE_W
);
398 swizzle
= tgsi_util_get_src_register_swizzle(®
.Register
, chan_index
);
401 assert(off
->Index
<= bld_base
->info
->file_max
[off
->File
]);
403 if (bld_base
->emit_fetch_funcs
[off
->File
]) {
404 res
= bld_base
->emit_fetch_funcs
[off
->File
](bld_base
, ®
, stype
,
407 assert(0 && "invalid src register in emit_fetch_texoffset()");
408 return bld_base
->base
.undef
;
412 * Swizzle the argument
416 res
= bld_base
->emit_swizzle(bld_base
, res
,
420 /* there's no 4th channel */
431 struct lp_build_tgsi_context
* bld_base
,
432 const struct tgsi_token
*tokens
)
434 struct tgsi_parse_context parse
;
436 if (bld_base
->emit_prologue
) {
437 bld_base
->emit_prologue(bld_base
);
440 if (!lp_bld_tgsi_list_init(bld_base
)) {
444 tgsi_parse_init( &parse
, tokens
);
446 while( !tgsi_parse_end_of_tokens( &parse
) ) {
447 tgsi_parse_token( &parse
);
449 switch( parse
.FullToken
.Token
.Type
) {
450 case TGSI_TOKEN_TYPE_DECLARATION
:
451 /* Inputs already interpolated */
452 bld_base
->emit_declaration(bld_base
, &parse
.FullToken
.FullDeclaration
);
455 case TGSI_TOKEN_TYPE_INSTRUCTION
:
456 lp_bld_tgsi_add_instruction(bld_base
, &parse
.FullToken
.FullInstruction
);
459 case TGSI_TOKEN_TYPE_IMMEDIATE
:
460 bld_base
->emit_immediate(bld_base
, &parse
.FullToken
.FullImmediate
);
463 case TGSI_TOKEN_TYPE_PROPERTY
:
471 while (bld_base
->pc
!= -1) {
472 const struct tgsi_full_instruction
*instr
=
473 bld_base
->instructions
+ bld_base
->pc
;
474 const struct tgsi_opcode_info
*opcode_info
=
475 tgsi_get_opcode_info(instr
->Instruction
.Opcode
);
476 if (!lp_build_tgsi_inst_llvm(bld_base
, instr
)) {
477 _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
478 opcode_info
->mnemonic
);
483 tgsi_parse_free(&parse
);
485 FREE(bld_base
->instructions
);
487 if (bld_base
->emit_epilogue
) {
488 bld_base
->emit_epilogue(bld_base
);