gallivm: Remove bogus assert.
[mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_tgsi.c
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 */
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
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
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
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
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
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
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
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 */
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
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_PUSHA:
215 case TGSI_OPCODE_POPA:
216 case TGSI_OPCODE_SAD:
217 /* deprecated? */
218 assert(0);
219 return FALSE;
220 break;
221 }
222
223 /* Check if the opcode has been implemented */
224 if (!action->emit) {
225 return FALSE;
226 }
227
228 memset(&emit_data, 0, sizeof(emit_data));
229
230 assert(info->num_dst <= 1);
231 if (info->num_dst) {
232 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) {
233 emit_data.output[chan_index] = bld_base->base.undef;
234 }
235 }
236
237 emit_data.inst = inst;
238 emit_data.info = info;
239
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);
246 } else {
247 action->fetch_args(bld_base, &emit_data);
248 }
249 action->emit(action, bld_base, &emit_data);
250 }
251 } else {
252 emit_data.chan = LP_CHAN_ALL;
253 if (action->fetch_args) {
254 action->fetch_args(bld_base, &emit_data);
255 }
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) {
259 emit_data.chan = 0;
260 }
261 action->emit(action, bld_base, &emit_data);
262
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;
269 }
270 }
271 }
272
273 if (info->num_dst > 0) {
274 bld_base->emit_store(bld_base, inst, info, emit_data.output);
275 }
276 return TRUE;
277 }
278
279
280 LLVMValueRef
281 lp_build_emit_fetch(
282 struct lp_build_tgsi_context *bld_base,
283 const struct tgsi_full_instruction *inst,
284 unsigned src_op,
285 const unsigned chan_index)
286 {
287 const struct tgsi_full_src_register *reg = &inst->Src[src_op];
288 unsigned swizzle;
289 LLVMValueRef res;
290 enum tgsi_opcode_type stype = tgsi_opcode_infer_src_type(inst->Instruction.Opcode);
291
292 if (chan_index == LP_CHAN_ALL) {
293 swizzle = ~0;
294 } else {
295 swizzle = tgsi_util_get_full_src_register_swizzle(reg, chan_index);
296 if (swizzle > 3) {
297 assert(0 && "invalid swizzle in emit_fetch()");
298 return bld_base->base.undef;
299 }
300 }
301
302 assert(reg->Register.Index <= bld_base->info->file_max[reg->Register.File]);
303
304 if (bld_base->emit_fetch_funcs[reg->Register.File]) {
305 res = bld_base->emit_fetch_funcs[reg->Register.File](bld_base, reg, stype,
306 swizzle);
307 } else {
308 assert(0 && "invalid src register in emit_fetch()");
309 return bld_base->base.undef;
310 }
311
312 if (reg->Register.Absolute) {
313 switch (stype) {
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);
319 break;
320 case TGSI_TYPE_UNSIGNED:
321 case TGSI_TYPE_SIGNED:
322 case TGSI_TYPE_VOID:
323 default:
324 /* abs modifier is only legal on floating point types */
325 assert(0);
326 break;
327 }
328 }
329
330 if (reg->Register.Negate) {
331 switch (stype) {
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 );
336 break;
337 case TGSI_TYPE_DOUBLE:
338 /* no double build context */
339 assert(0);
340 break;
341 case TGSI_TYPE_SIGNED:
342 case TGSI_TYPE_UNSIGNED:
343 res = lp_build_negate( &bld_base->int_bld, res );
344 break;
345 case TGSI_TYPE_VOID:
346 default:
347 assert(0);
348 break;
349 }
350 }
351
352 /*
353 * Swizzle the argument
354 */
355
356 if (swizzle == ~0) {
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);
362 }
363
364 return res;
365
366 }
367
368
369 LLVMValueRef
370 lp_build_emit_fetch_texoffset(
371 struct lp_build_tgsi_context *bld_base,
372 const struct tgsi_full_instruction *inst,
373 unsigned tex_off_op,
374 const unsigned chan_index)
375 {
376 const struct tgsi_texture_offset *off = &inst->TexOffsets[tex_off_op];
377 struct tgsi_full_src_register reg;
378 unsigned swizzle;
379 LLVMValueRef res;
380 enum tgsi_opcode_type stype = TGSI_TYPE_SIGNED;
381
382 /* convert offset "register" to ordinary register so can use normal emit funcs */
383 memset(&reg, 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;
389
390 if (chan_index == LP_CHAN_ALL) {
391 swizzle = ~0;
392 } else {
393 assert(chan_index < TGSI_SWIZZLE_W);
394 swizzle = tgsi_util_get_src_register_swizzle(&reg.Register, chan_index);
395 }
396
397 assert(off->Index <= bld_base->info->file_max[off->File]);
398
399 if (bld_base->emit_fetch_funcs[off->File]) {
400 res = bld_base->emit_fetch_funcs[off->File](bld_base, &reg, stype,
401 swizzle);
402 } else {
403 assert(0 && "invalid src register in emit_fetch_texoffset()");
404 return bld_base->base.undef;
405 }
406
407 /*
408 * Swizzle the argument
409 */
410
411 if (swizzle == ~0) {
412 res = bld_base->emit_swizzle(bld_base, res,
413 off->SwizzleX,
414 off->SwizzleY,
415 off->SwizzleZ,
416 /* there's no 4th channel */
417 off->SwizzleX);
418 }
419
420 return res;
421
422 }
423
424
425 boolean
426 lp_build_tgsi_llvm(
427 struct lp_build_tgsi_context * bld_base,
428 const struct tgsi_token *tokens)
429 {
430 struct tgsi_parse_context parse;
431
432 if (bld_base->emit_prologue) {
433 bld_base->emit_prologue(bld_base);
434 }
435
436 if (!lp_bld_tgsi_list_init(bld_base)) {
437 return FALSE;
438 }
439
440 tgsi_parse_init( &parse, tokens );
441
442 while( !tgsi_parse_end_of_tokens( &parse ) ) {
443 tgsi_parse_token( &parse );
444
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);
449 break;
450
451 case TGSI_TOKEN_TYPE_INSTRUCTION:
452 lp_bld_tgsi_add_instruction(bld_base, &parse.FullToken.FullInstruction);
453 break;
454
455 case TGSI_TOKEN_TYPE_IMMEDIATE:
456 bld_base->emit_immediate(bld_base, &parse.FullToken.FullImmediate);
457 break;
458
459 case TGSI_TOKEN_TYPE_PROPERTY:
460 break;
461
462 default:
463 assert( 0 );
464 }
465 }
466
467 while (bld_base->pc != -1) {
468 struct tgsi_full_instruction *instr = bld_base->instructions +
469 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);
475 return FALSE;
476 }
477 }
478
479 tgsi_parse_free(&parse);
480
481 FREE(bld_base->instructions);
482
483 if (bld_base->emit_epilogue) {
484 bld_base->emit_epilogue(bld_base);
485 }
486
487 return TRUE;
488 }