1 /************************************************************************** 2 * 3 * Copyright 2011-2012 Advanced Micro Devices, Inc. 4 * Copyright 2010 VMware, Inc. 5 * Copyright 2009 VMware, Inc. 6 * Copyright 2007-2008 VMware, Inc. 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 const 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, 0); 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 = {{0}}; 133 emit_data.info = tgsi_get_opcode_info(tgsi_opcode); 134 emit_data.arg_count = 1; 135 emit_data.args[0] = arg0; 136 return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data); 137 } 138 139 LLVMValueRef 140 lp_build_emit_llvm_binary( 141 struct lp_build_tgsi_context *bld_base, 142 unsigned tgsi_opcode, 143 LLVMValueRef arg0, 144 LLVMValueRef arg1) 145 { 146 struct lp_build_emit_data emit_data = {{0}}; 147 emit_data.info = tgsi_get_opcode_info(tgsi_opcode); 148 emit_data.arg_count = 2; 149 emit_data.args[0] = arg0; 150 emit_data.args[1] = arg1; 151 return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data); 152 } 153 154 LLVMValueRef 155 lp_build_emit_llvm_ternary( 156 struct lp_build_tgsi_context *bld_base, 157 unsigned tgsi_opcode, 158 LLVMValueRef arg0, 159 LLVMValueRef arg1, 160 LLVMValueRef arg2) 161 { 162 struct lp_build_emit_data emit_data = {{0}}; 163 emit_data.info = tgsi_get_opcode_info(tgsi_opcode); 164 emit_data.arg_count = 3; 165 emit_data.args[0] = arg0; 166 emit_data.args[1] = arg1; 167 emit_data.args[2] = arg2; 168 return lp_build_emit_llvm(bld_base, tgsi_opcode, &emit_data); 169 } 170 171 /** 172 * The default fetch implementation. 173 */ 174 void lp_build_fetch_args( 175 struct lp_build_tgsi_context * bld_base, 176 struct lp_build_emit_data * emit_data) 177 { 178 unsigned src; 179 for (src = 0; src < emit_data->info->num_src; src++) { 180 emit_data->args[src] = lp_build_emit_fetch(bld_base, emit_data->inst, src, 181 emit_data->src_chan); 182 } 183 emit_data->arg_count = emit_data->info->num_src; 184 lp_build_action_set_dst_type(emit_data, bld_base, 185 emit_data->inst->Instruction.Opcode); 186 } 187 188 /** 189 * with 64-bit src and dst channels aren't 1:1. 190 * check the src/dst types for the opcode, 191 * 1. if neither is 64-bit then src == dst; 192 * 2. if dest is 64-bit 193 * - don't store to y or w 194 * - if src is 64-bit then src == dst. 195 * - else for f2d, d.xy = s.x 196 * - else for f2d, d.zw = s.y 197 * 3. if dst is single, src is 64-bit 198 * - map dst x,z to src xy; 199 * - map dst y,w to src zw; 200 */ 201 static int get_src_chan_idx(unsigned opcode, 202 int dst_chan_index) 203 { 204 enum tgsi_opcode_type dtype = tgsi_opcode_infer_dst_type(opcode, 0); 205 enum tgsi_opcode_type stype = tgsi_opcode_infer_src_type(opcode, 0); 206 207 if (!tgsi_type_is_64bit(dtype) && !tgsi_type_is_64bit(stype)) 208 return dst_chan_index; 209 if (tgsi_type_is_64bit(dtype)) { 210 if (dst_chan_index == 1 || dst_chan_index == 3) 211 return -1; 212 if (tgsi_type_is_64bit(stype)) 213 return dst_chan_index; 214 if (dst_chan_index == 0) 215 return 0; 216 if (dst_chan_index == 2) 217 return 1; 218 } else { 219 if (dst_chan_index == 0 || dst_chan_index == 2) 220 return 0; 221 if (dst_chan_index == 1 || dst_chan_index == 3) 222 return 2; 223 } 224 return -1; 225 } 226 227 /* XXX: COMMENT 228 * It should be assumed that this function ignores writemasks 229 */ 230 boolean 231 lp_build_tgsi_inst_llvm( 232 struct lp_build_tgsi_context * bld_base, 233 const struct tgsi_full_instruction * inst) 234 { 235 unsigned tgsi_opcode = inst->Instruction.Opcode; 236 const struct tgsi_opcode_info * info = tgsi_get_opcode_info(tgsi_opcode); 237 const struct lp_build_tgsi_action * action = 238 &bld_base->op_actions[tgsi_opcode]; 239 struct lp_build_emit_data emit_data; 240 unsigned chan_index; 241 LLVMValueRef val; 242 bld_base->pc++; 243 244 if (bld_base->emit_debug) { 245 bld_base->emit_debug(bld_base, inst, info); 246 } 247 248 /* Ignore deprecated instructions */ 249 switch (inst->Instruction.Opcode) { 250 251 case TGSI_OPCODE_UP2US: 252 case TGSI_OPCODE_UP4B: 253 case TGSI_OPCODE_UP4UB: 254 /* deprecated? */ 255 assert(0); 256 return FALSE; 257 break; 258 } 259 260 /* Check if the opcode has been implemented */ 261 if (!action->emit) { 262 return FALSE; 263 } 264 265 memset(&emit_data, 0, sizeof(emit_data)); 266 267 assert(info->num_dst <= 2); 268 if (info->num_dst) { 269 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) { 270 emit_data.output[chan_index] = bld_base->base.undef; 271 } 272 273 if (info->num_dst >= 2) { 274 TGSI_FOR_EACH_DST1_ENABLED_CHANNEL( inst, chan_index ) { 275 emit_data.output1[chan_index] = bld_base->base.undef; 276 } 277 } 278 } 279 280 emit_data.inst = inst; 281 emit_data.info = info; 282 283 /* Emit the instructions */ 284 if (info->output_mode == TGSI_OUTPUT_COMPONENTWISE && bld_base->soa) { 285 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) { 286 int src_index = get_src_chan_idx(inst->Instruction.Opcode, chan_index); 287 /* ignore channels 1/3 in double dst */ 288 if (src_index == -1) 289 continue; 290 emit_data.chan = chan_index; 291 emit_data.src_chan = src_index; 292 if (!action->fetch_args) { 293 lp_build_fetch_args(bld_base, &emit_data); 294 } else { 295 action->fetch_args(bld_base, &emit_data); 296 } 297 action->emit(action, bld_base, &emit_data); 298 } 299 } else { 300 emit_data.chan = LP_CHAN_ALL; 301 if (action->fetch_args) { 302 action->fetch_args(bld_base, &emit_data); 303 } 304 /* Make sure the output value is stored in emit_data.output[0], unless 305 * the opcode is channel dependent */ 306 if (info->output_mode != TGSI_OUTPUT_CHAN_DEPENDENT) { 307 emit_data.chan = 0; 308 } 309 action->emit(action, bld_base, &emit_data); 310 311 /* Replicate the output values */ 312 if (info->output_mode == TGSI_OUTPUT_REPLICATE && bld_base->soa) { 313 val = emit_data.output[0]; 314 memset(emit_data.output, 0, sizeof(emit_data.output)); 315 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) { 316 emit_data.output[chan_index] = val; 317 } 318 319 if (info->num_dst >= 2) { 320 val = emit_data.output1[0]; 321 memset(emit_data.output1, 0, sizeof(emit_data.output1)); 322 TGSI_FOR_EACH_DST1_ENABLED_CHANNEL(inst, chan_index) { 323 emit_data.output1[chan_index] = val; 324 } 325 } 326 } 327 } 328 329 if (info->num_dst > 0 && info->opcode != TGSI_OPCODE_STORE) { 330 bld_base->emit_store(bld_base, inst, info, 0, emit_data.output); 331 if (info->num_dst >= 2) 332 bld_base->emit_store(bld_base, inst, info, 1, emit_data.output1); 333 } 334 return TRUE; 335 } 336 337 338 LLVMValueRef 339 lp_build_emit_fetch_src( 340 struct lp_build_tgsi_context *bld_base, 341 const struct tgsi_full_src_register *reg, 342 enum tgsi_opcode_type stype, 343 const unsigned chan_index) 344 { 345 unsigned swizzle; 346 LLVMValueRef res; 347 348 if (chan_index == LP_CHAN_ALL) { 349 swizzle = ~0u; 350 } else { 351 swizzle = tgsi_util_get_full_src_register_swizzle(reg, chan_index); 352 if (swizzle > 3) { 353 assert(0 && "invalid swizzle in emit_fetch()"); 354 return bld_base->base.undef; 355 } 356 } 357 358 assert(reg->Register.Index <= bld_base->info->file_max[reg->Register.File]); 359 360 if (bld_base->emit_fetch_funcs[reg->Register.File]) { 361 res = bld_base->emit_fetch_funcs[reg->Register.File](bld_base, reg, stype, 362 swizzle); 363 } else { 364 assert(0 && "invalid src register in emit_fetch()"); 365 return bld_base->base.undef; 366 } 367 368 if (reg->Register.Absolute) { 369 switch (stype) { 370 case TGSI_TYPE_FLOAT: 371 case TGSI_TYPE_DOUBLE: 372 case TGSI_TYPE_UNTYPED: 373 /* modifiers on movs assume data is float */ 374 res = lp_build_abs(&bld_base->base, res); 375 break; 376 case TGSI_TYPE_UNSIGNED: 377 case TGSI_TYPE_SIGNED: 378 case TGSI_TYPE_UNSIGNED64: 379 case TGSI_TYPE_SIGNED64: 380 case TGSI_TYPE_VOID: 381 default: 382 /* abs modifier is only legal on floating point types */ 383 assert(0); 384 break; 385 } 386 } 387 388 if (reg->Register.Negate) { 389 switch (stype) { 390 case TGSI_TYPE_FLOAT: 391 case TGSI_TYPE_UNTYPED: 392 /* modifiers on movs assume data is float */ 393 res = lp_build_negate( &bld_base->base, res ); 394 break; 395 case TGSI_TYPE_DOUBLE: 396 /* no double build context */ 397 assert(0); 398 break; 399 case TGSI_TYPE_SIGNED: 400 case TGSI_TYPE_UNSIGNED: 401 res = lp_build_negate( &bld_base->int_bld, res ); 402 break; 403 case TGSI_TYPE_SIGNED64: 404 case TGSI_TYPE_UNSIGNED64: 405 res = lp_build_negate( &bld_base->int64_bld, res ); 406 break; 407 case TGSI_TYPE_VOID: 408 default: 409 assert(0); 410 break; 411 } 412 } 413 414 /* 415 * Swizzle the argument 416 */ 417 418 if (swizzle == ~0u) { 419 res = bld_base->emit_swizzle(bld_base, res, 420 reg->Register.SwizzleX, 421 reg->Register.SwizzleY, 422 reg->Register.SwizzleZ, 423 reg->Register.SwizzleW); 424 } 425 426 return res; 427 } 428 429 430 LLVMValueRef 431 lp_build_emit_fetch( 432 struct lp_build_tgsi_context *bld_base, 433 const struct tgsi_full_instruction *inst, 434 unsigned src_op, 435 const unsigned chan_index) 436 { 437 const struct tgsi_full_src_register *reg = &inst->Src[src_op]; 438 enum tgsi_opcode_type stype = 439 tgsi_opcode_infer_src_type(inst->Instruction.Opcode, src_op); 440 441 return lp_build_emit_fetch_src(bld_base, reg, stype, chan_index); 442 } 443 444 445 LLVMValueRef 446 lp_build_emit_fetch_texoffset( 447 struct lp_build_tgsi_context *bld_base, 448 const struct tgsi_full_instruction *inst, 449 unsigned tex_off_op, 450 const unsigned chan_index) 451 { 452 const struct tgsi_texture_offset *off = &inst->TexOffsets[tex_off_op]; 453 struct tgsi_full_src_register reg; 454 unsigned swizzle; 455 LLVMValueRef res; 456 enum tgsi_opcode_type stype = TGSI_TYPE_SIGNED; 457 458 /* convert offset "register" to ordinary register so can use normal emit funcs */ 459 memset(®, 0, sizeof(reg)); 460 reg.Register.File = off->File; 461 reg.Register.Index = off->Index; 462 reg.Register.SwizzleX = off->SwizzleX; 463 reg.Register.SwizzleY = off->SwizzleY; 464 reg.Register.SwizzleZ = off->SwizzleZ; 465 466 if (chan_index == LP_CHAN_ALL) { 467 swizzle = ~0; 468 } else { 469 assert(chan_index < TGSI_SWIZZLE_W); 470 swizzle = tgsi_util_get_src_register_swizzle(®.Register, chan_index); 471 } 472 473 assert(off->Index <= bld_base->info->file_max[off->File]); 474 475 if (bld_base->emit_fetch_funcs[off->File]) { 476 res = bld_base->emit_fetch_funcs[off->File](bld_base, ®, stype, 477 swizzle); 478 } else { 479 assert(0 && "invalid src register in emit_fetch_texoffset()"); 480 return bld_base->base.undef; 481 } 482 483 /* 484 * Swizzle the argument 485 */ 486 487 if (swizzle == ~0u) { 488 res = bld_base->emit_swizzle(bld_base, res, 489 off->SwizzleX, 490 off->SwizzleY, 491 off->SwizzleZ, 492 /* there's no 4th channel */ 493 off->SwizzleX); 494 } 495 496 return res; 497 498 } 499 500 501 boolean 502 lp_build_tgsi_llvm( 503 struct lp_build_tgsi_context * bld_base, 504 const struct tgsi_token *tokens) 505 { 506 struct tgsi_parse_context parse; 507 508 if (bld_base->emit_prologue) { 509 bld_base->emit_prologue(bld_base); 510 } 511 512 if (!lp_bld_tgsi_list_init(bld_base)) { 513 return FALSE; 514 } 515 516 tgsi_parse_init( &parse, tokens ); 517 518 while( !tgsi_parse_end_of_tokens( &parse ) ) { 519 tgsi_parse_token( &parse ); 520 521 switch( parse.FullToken.Token.Type ) { 522 case TGSI_TOKEN_TYPE_DECLARATION: 523 /* Inputs already interpolated */ 524 bld_base->emit_declaration(bld_base, &parse.FullToken.FullDeclaration); 525 break; 526 527 case TGSI_TOKEN_TYPE_INSTRUCTION: 528 lp_bld_tgsi_add_instruction(bld_base, &parse.FullToken.FullInstruction); 529 break; 530 531 case TGSI_TOKEN_TYPE_IMMEDIATE: 532 bld_base->emit_immediate(bld_base, &parse.FullToken.FullImmediate); 533 break; 534 535 case TGSI_TOKEN_TYPE_PROPERTY: 536 break; 537 538 default: 539 assert( 0 ); 540 } 541 } 542 543 while (bld_base->pc != -1) { 544 const struct tgsi_full_instruction *instr = 545 bld_base->instructions + bld_base->pc; 546 if (!lp_build_tgsi_inst_llvm(bld_base, instr)) { 547 _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n", 548 tgsi_get_opcode_name(instr->Instruction.Opcode)); 549 return FALSE; 550 } 551 } 552 553 tgsi_parse_free(&parse); 554 555 FREE(bld_base->instructions); 556 557 if (bld_base->emit_epilogue) { 558 bld_base->emit_epilogue(bld_base); 559 } 560 561 return TRUE; 562 } 563