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_UP2H
:
211 case TGSI_OPCODE_UP2US
:
212 case TGSI_OPCODE_UP4B
:
213 case TGSI_OPCODE_UP4UB
:
214 case TGSI_OPCODE_X2D
:
215 case TGSI_OPCODE_BRA
:
216 case TGSI_OPCODE_PUSHA
:
217 case TGSI_OPCODE_POPA
:
218 case TGSI_OPCODE_SAD
:
225 /* Check if the opcode has been implemented */
230 memset(&emit_data
, 0, sizeof(emit_data
));
232 assert(info
->num_dst
<= 1);
234 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst
, chan_index
) {
235 emit_data
.output
[chan_index
] = bld_base
->base
.undef
;
239 emit_data
.inst
= inst
;
240 emit_data
.info
= info
;
242 /* Emit the instructions */
243 if (info
->output_mode
== TGSI_OUTPUT_COMPONENTWISE
&& bld_base
->soa
) {
244 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst
, chan_index
) {
245 emit_data
.chan
= chan_index
;
246 if (!action
->fetch_args
) {
247 lp_build_fetch_args(bld_base
, &emit_data
);
249 action
->fetch_args(bld_base
, &emit_data
);
251 action
->emit(action
, bld_base
, &emit_data
);
254 emit_data
.chan
= LP_CHAN_ALL
;
255 if (action
->fetch_args
) {
256 action
->fetch_args(bld_base
, &emit_data
);
258 /* Make sure the output value is stored in emit_data.output[0], unless
259 * the opcode is channel dependent */
260 if (info
->output_mode
!= TGSI_OUTPUT_CHAN_DEPENDENT
) {
263 action
->emit(action
, bld_base
, &emit_data
);
265 /* Replicate the output values */
266 if (info
->output_mode
== TGSI_OUTPUT_REPLICATE
&& bld_base
->soa
) {
267 val
= emit_data
.output
[0];
268 memset(emit_data
.output
, 0, sizeof(emit_data
.output
));
269 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst
, chan_index
) {
270 emit_data
.output
[chan_index
] = val
;
275 if (info
->num_dst
> 0) {
276 bld_base
->emit_store(bld_base
, inst
, info
, emit_data
.output
);
284 struct lp_build_tgsi_context
*bld_base
,
285 const struct tgsi_full_instruction
*inst
,
287 const unsigned chan_index
)
289 const struct tgsi_full_src_register
*reg
= &inst
->Src
[src_op
];
292 enum tgsi_opcode_type stype
= tgsi_opcode_infer_src_type(inst
->Instruction
.Opcode
);
294 if (chan_index
== LP_CHAN_ALL
) {
297 swizzle
= tgsi_util_get_full_src_register_swizzle(reg
, chan_index
);
299 assert(0 && "invalid swizzle in emit_fetch()");
300 return bld_base
->base
.undef
;
304 assert(reg
->Register
.Index
<= bld_base
->info
->file_max
[reg
->Register
.File
]);
306 if (bld_base
->emit_fetch_funcs
[reg
->Register
.File
]) {
307 res
= bld_base
->emit_fetch_funcs
[reg
->Register
.File
](bld_base
, reg
, stype
,
310 assert(0 && "invalid src register in emit_fetch()");
311 return bld_base
->base
.undef
;
314 if (reg
->Register
.Absolute
) {
316 case TGSI_TYPE_FLOAT
:
317 case TGSI_TYPE_DOUBLE
:
318 case TGSI_TYPE_UNTYPED
:
319 /* modifiers on movs assume data is float */
320 res
= lp_build_emit_llvm_unary(bld_base
, TGSI_OPCODE_ABS
, res
);
322 case TGSI_TYPE_UNSIGNED
:
323 case TGSI_TYPE_SIGNED
:
326 /* abs modifier is only legal on floating point types */
332 if (reg
->Register
.Negate
) {
334 case TGSI_TYPE_FLOAT
:
335 case TGSI_TYPE_UNTYPED
:
336 /* modifiers on movs assume data is float */
337 res
= lp_build_negate( &bld_base
->base
, res
);
339 case TGSI_TYPE_DOUBLE
:
340 /* no double build context */
343 case TGSI_TYPE_SIGNED
:
344 case TGSI_TYPE_UNSIGNED
:
345 res
= lp_build_negate( &bld_base
->int_bld
, res
);
355 * Swizzle the argument
359 res
= bld_base
->emit_swizzle(bld_base
, res
,
360 reg
->Register
.SwizzleX
,
361 reg
->Register
.SwizzleY
,
362 reg
->Register
.SwizzleZ
,
363 reg
->Register
.SwizzleW
);
372 lp_build_emit_fetch_texoffset(
373 struct lp_build_tgsi_context
*bld_base
,
374 const struct tgsi_full_instruction
*inst
,
376 const unsigned chan_index
)
378 const struct tgsi_texture_offset
*off
= &inst
->TexOffsets
[tex_off_op
];
379 struct tgsi_full_src_register reg
;
382 enum tgsi_opcode_type stype
= TGSI_TYPE_SIGNED
;
384 /* convert offset "register" to ordinary register so can use normal emit funcs */
385 memset(®
, 0, sizeof(reg
));
386 reg
.Register
.File
= off
->File
;
387 reg
.Register
.Index
= off
->Index
;
388 reg
.Register
.SwizzleX
= off
->SwizzleX
;
389 reg
.Register
.SwizzleY
= off
->SwizzleY
;
390 reg
.Register
.SwizzleZ
= off
->SwizzleZ
;
392 if (chan_index
== LP_CHAN_ALL
) {
395 assert(chan_index
< TGSI_SWIZZLE_W
);
396 swizzle
= tgsi_util_get_src_register_swizzle(®
.Register
, chan_index
);
399 assert(off
->Index
<= bld_base
->info
->file_max
[off
->File
]);
401 if (bld_base
->emit_fetch_funcs
[off
->File
]) {
402 res
= bld_base
->emit_fetch_funcs
[off
->File
](bld_base
, ®
, stype
,
405 assert(0 && "invalid src register in emit_fetch_texoffset()");
406 return bld_base
->base
.undef
;
410 * Swizzle the argument
414 res
= bld_base
->emit_swizzle(bld_base
, res
,
418 /* there's no 4th channel */
429 struct lp_build_tgsi_context
* bld_base
,
430 const struct tgsi_token
*tokens
)
432 struct tgsi_parse_context parse
;
434 if (bld_base
->emit_prologue
) {
435 bld_base
->emit_prologue(bld_base
);
438 if (!lp_bld_tgsi_list_init(bld_base
)) {
442 tgsi_parse_init( &parse
, tokens
);
444 while( !tgsi_parse_end_of_tokens( &parse
) ) {
445 tgsi_parse_token( &parse
);
447 switch( parse
.FullToken
.Token
.Type
) {
448 case TGSI_TOKEN_TYPE_DECLARATION
:
449 /* Inputs already interpolated */
450 bld_base
->emit_declaration(bld_base
, &parse
.FullToken
.FullDeclaration
);
453 case TGSI_TOKEN_TYPE_INSTRUCTION
:
454 lp_bld_tgsi_add_instruction(bld_base
, &parse
.FullToken
.FullInstruction
);
457 case TGSI_TOKEN_TYPE_IMMEDIATE
:
458 bld_base
->emit_immediate(bld_base
, &parse
.FullToken
.FullImmediate
);
461 case TGSI_TOKEN_TYPE_PROPERTY
:
469 while (bld_base
->pc
!= -1) {
470 const struct tgsi_full_instruction
*instr
=
471 bld_base
->instructions
+ bld_base
->pc
;
472 const struct tgsi_opcode_info
*opcode_info
=
473 tgsi_get_opcode_info(instr
->Instruction
.Opcode
);
474 if (!lp_build_tgsi_inst_llvm(bld_base
, instr
)) {
475 _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
476 opcode_info
->mnemonic
);
481 tgsi_parse_free(&parse
);
483 FREE(bld_base
->instructions
);
485 if (bld_base
->emit_epilogue
) {
486 bld_base
->emit_epilogue(bld_base
);