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_PUSHA
:
215 case TGSI_OPCODE_POPA
:
216 case TGSI_OPCODE_SAD
:
223 /* Check if the opcode has been implemented */
228 memset(&emit_data
, 0, sizeof(emit_data
));
230 assert(info
->num_dst
<= 1);
232 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst
, chan_index
) {
233 emit_data
.output
[chan_index
] = bld_base
->base
.undef
;
237 emit_data
.inst
= inst
;
238 emit_data
.info
= info
;
240 /* Emit the instructions */
241 if (info
->output_mode
== TGSI_OUTPUT_COMPONENTWISE
&& bld_base
->soa
) {
242 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst
, chan_index
) {
243 emit_data
.chan
= chan_index
;
244 if (!action
->fetch_args
) {
245 lp_build_fetch_args(bld_base
, &emit_data
);
247 action
->fetch_args(bld_base
, &emit_data
);
249 action
->emit(action
, bld_base
, &emit_data
);
252 emit_data
.chan
= LP_CHAN_ALL
;
253 if (action
->fetch_args
) {
254 action
->fetch_args(bld_base
, &emit_data
);
256 /* Make sure the output value is stored in emit_data.output[0], unless
257 * the opcode is channel dependent */
258 if (info
->output_mode
!= TGSI_OUTPUT_CHAN_DEPENDENT
) {
261 action
->emit(action
, bld_base
, &emit_data
);
263 /* Replicate the output values */
264 if (info
->output_mode
== TGSI_OUTPUT_REPLICATE
&& bld_base
->soa
) {
265 val
= emit_data
.output
[0];
266 memset(emit_data
.output
, 0, sizeof(emit_data
.output
));
267 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst
, chan_index
) {
268 emit_data
.output
[chan_index
] = val
;
273 if (info
->num_dst
> 0) {
274 bld_base
->emit_store(bld_base
, inst
, info
, emit_data
.output
);
282 struct lp_build_tgsi_context
*bld_base
,
283 const struct tgsi_full_instruction
*inst
,
285 const unsigned chan_index
)
287 const struct tgsi_full_src_register
*reg
= &inst
->Src
[src_op
];
290 enum tgsi_opcode_type stype
= tgsi_opcode_infer_src_type(inst
->Instruction
.Opcode
);
292 if (chan_index
== LP_CHAN_ALL
) {
295 swizzle
= tgsi_util_get_full_src_register_swizzle(reg
, chan_index
);
297 assert(0 && "invalid swizzle in emit_fetch()");
298 return bld_base
->base
.undef
;
302 assert(reg
->Register
.Index
<= bld_base
->info
->file_max
[reg
->Register
.File
]);
304 if (bld_base
->emit_fetch_funcs
[reg
->Register
.File
]) {
305 res
= bld_base
->emit_fetch_funcs
[reg
->Register
.File
](bld_base
, reg
, stype
,
308 assert(0 && "invalid src register in emit_fetch()");
309 return bld_base
->base
.undef
;
312 if (reg
->Register
.Absolute
) {
314 case TGSI_TYPE_FLOAT
:
315 case TGSI_TYPE_DOUBLE
:
316 case TGSI_TYPE_UNTYPED
:
317 /* modifiers on movs assume data is float */
318 res
= lp_build_emit_llvm_unary(bld_base
, TGSI_OPCODE_ABS
, res
);
320 case TGSI_TYPE_UNSIGNED
:
321 case TGSI_TYPE_SIGNED
:
324 /* abs modifier is only legal on floating point types */
330 if (reg
->Register
.Negate
) {
332 case TGSI_TYPE_FLOAT
:
333 case TGSI_TYPE_UNTYPED
:
334 /* modifiers on movs assume data is float */
335 res
= lp_build_negate( &bld_base
->base
, res
);
337 case TGSI_TYPE_DOUBLE
:
338 /* no double build context */
341 case TGSI_TYPE_SIGNED
:
342 case TGSI_TYPE_UNSIGNED
:
343 res
= lp_build_negate( &bld_base
->int_bld
, res
);
353 * Swizzle the argument
357 res
= bld_base
->emit_swizzle(bld_base
, res
,
358 reg
->Register
.SwizzleX
,
359 reg
->Register
.SwizzleY
,
360 reg
->Register
.SwizzleZ
,
361 reg
->Register
.SwizzleW
);
370 lp_build_emit_fetch_texoffset(
371 struct lp_build_tgsi_context
*bld_base
,
372 const struct tgsi_full_instruction
*inst
,
374 const unsigned chan_index
)
376 const struct tgsi_texture_offset
*off
= &inst
->TexOffsets
[tex_off_op
];
377 struct tgsi_full_src_register reg
;
380 enum tgsi_opcode_type stype
= TGSI_TYPE_SIGNED
;
382 /* convert offset "register" to ordinary register so can use normal emit funcs */
383 memset(®
, 0, sizeof(reg
));
384 reg
.Register
.File
= off
->File
;
385 reg
.Register
.Index
= off
->Index
;
386 reg
.Register
.SwizzleX
= off
->SwizzleX
;
387 reg
.Register
.SwizzleY
= off
->SwizzleY
;
388 reg
.Register
.SwizzleZ
= off
->SwizzleZ
;
390 if (chan_index
== LP_CHAN_ALL
) {
393 assert(chan_index
< TGSI_SWIZZLE_W
);
394 swizzle
= tgsi_util_get_src_register_swizzle(®
.Register
, chan_index
);
397 assert(off
->Index
<= bld_base
->info
->file_max
[off
->File
]);
399 if (bld_base
->emit_fetch_funcs
[off
->File
]) {
400 res
= bld_base
->emit_fetch_funcs
[off
->File
](bld_base
, ®
, stype
,
403 assert(0 && "invalid src register in emit_fetch_texoffset()");
404 return bld_base
->base
.undef
;
408 * Swizzle the argument
412 res
= bld_base
->emit_swizzle(bld_base
, res
,
416 /* there's no 4th channel */
427 struct lp_build_tgsi_context
* bld_base
,
428 const struct tgsi_token
*tokens
)
430 struct tgsi_parse_context parse
;
432 if (bld_base
->emit_prologue
) {
433 bld_base
->emit_prologue(bld_base
);
436 if (!lp_bld_tgsi_list_init(bld_base
)) {
440 tgsi_parse_init( &parse
, tokens
);
442 while( !tgsi_parse_end_of_tokens( &parse
) ) {
443 tgsi_parse_token( &parse
);
445 switch( parse
.FullToken
.Token
.Type
) {
446 case TGSI_TOKEN_TYPE_DECLARATION
:
447 /* Inputs already interpolated */
448 bld_base
->emit_declaration(bld_base
, &parse
.FullToken
.FullDeclaration
);
451 case TGSI_TOKEN_TYPE_INSTRUCTION
:
452 lp_bld_tgsi_add_instruction(bld_base
, &parse
.FullToken
.FullInstruction
);
455 case TGSI_TOKEN_TYPE_IMMEDIATE
:
456 bld_base
->emit_immediate(bld_base
, &parse
.FullToken
.FullImmediate
);
459 case TGSI_TOKEN_TYPE_PROPERTY
:
467 while (bld_base
->pc
!= -1) {
468 const struct tgsi_full_instruction
*instr
=
469 bld_base
->instructions
+ bld_base
->pc
;
470 const struct tgsi_opcode_info
*opcode_info
=
471 tgsi_get_opcode_info(instr
->Instruction
.Opcode
);
472 if (!lp_build_tgsi_inst_llvm(bld_base
, instr
)) {
473 _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n",
474 opcode_info
->mnemonic
);
479 tgsi_parse_free(&parse
);
481 FREE(bld_base
->instructions
);
483 if (bld_base
->emit_epilogue
) {
484 bld_base
->emit_epilogue(bld_base
);