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_DIV: 215 case TGSI_OPCODE_PUSHA: 216 case TGSI_OPCODE_POPA: 217 case TGSI_OPCODE_SAD: 218 /* deprecated? */ 219 assert(0); 220 return FALSE; 221 break; 222 } 223 224 /* Check if the opcode has been implemented */ 225 if (!action->emit) { 226 return FALSE; 227 } 228 229 memset(&emit_data, 0, sizeof(emit_data)); 230 231 assert(info->num_dst <= 1); 232 if (info->num_dst) { 233 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) { 234 emit_data.output[chan_index] = bld_base->base.undef; 235 } 236 } 237 238 emit_data.inst = inst; 239 emit_data.info = info; 240 241 /* Emit the instructions */ 242 if (info->output_mode == TGSI_OUTPUT_COMPONENTWISE && bld_base->soa) { 243 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) { 244 emit_data.chan = chan_index; 245 if (!action->fetch_args) { 246 lp_build_fetch_args(bld_base, &emit_data); 247 } else { 248 action->fetch_args(bld_base, &emit_data); 249 } 250 action->emit(action, bld_base, &emit_data); 251 } 252 } else { 253 emit_data.chan = LP_CHAN_ALL; 254 if (action->fetch_args) { 255 action->fetch_args(bld_base, &emit_data); 256 } 257 /* Make sure the output value is stored in emit_data.output[0], unless 258 * the opcode is channel dependent */ 259 if (info->output_mode != TGSI_OUTPUT_CHAN_DEPENDENT) { 260 emit_data.chan = 0; 261 } 262 action->emit(action, bld_base, &emit_data); 263 264 /* Replicate the output values */ 265 if (info->output_mode == TGSI_OUTPUT_REPLICATE && bld_base->soa) { 266 val = emit_data.output[0]; 267 memset(emit_data.output, 0, sizeof(emit_data.output)); 268 TGSI_FOR_EACH_DST0_ENABLED_CHANNEL(inst, chan_index) { 269 emit_data.output[chan_index] = val; 270 } 271 } 272 } 273 274 if (info->num_dst > 0) { 275 bld_base->emit_store(bld_base, inst, info, emit_data.output); 276 } 277 return TRUE; 278 } 279 280 281 LLVMValueRef 282 lp_build_emit_fetch( 283 struct lp_build_tgsi_context *bld_base, 284 const struct tgsi_full_instruction *inst, 285 unsigned src_op, 286 const unsigned chan_index) 287 { 288 const struct tgsi_full_src_register *reg = &inst->Src[src_op]; 289 unsigned swizzle; 290 LLVMValueRef res; 291 enum tgsi_opcode_type stype = tgsi_opcode_infer_src_type(inst->Instruction.Opcode); 292 293 if (chan_index == LP_CHAN_ALL) { 294 swizzle = ~0; 295 } else { 296 swizzle = tgsi_util_get_full_src_register_swizzle(reg, chan_index); 297 if (swizzle > 3) { 298 assert(0 && "invalid swizzle in emit_fetch()"); 299 return bld_base->base.undef; 300 } 301 } 302 303 assert(reg->Register.Index <= bld_base->info->file_max[reg->Register.File]); 304 305 if (bld_base->emit_fetch_funcs[reg->Register.File]) { 306 res = bld_base->emit_fetch_funcs[reg->Register.File](bld_base, reg, stype, 307 swizzle); 308 } else { 309 assert(0 && "invalid src register in emit_fetch()"); 310 return bld_base->base.undef; 311 } 312 313 if (reg->Register.Absolute) { 314 res = lp_build_emit_llvm_unary(bld_base, TGSI_OPCODE_ABS, res); 315 } 316 317 if (reg->Register.Negate) { 318 res = lp_build_negate( &bld_base->base, res ); 319 } 320 321 /* 322 * Swizzle the argument 323 */ 324 325 if (swizzle == ~0) { 326 res = bld_base->emit_swizzle(bld_base, res, 327 reg->Register.SwizzleX, 328 reg->Register.SwizzleY, 329 reg->Register.SwizzleZ, 330 reg->Register.SwizzleW); 331 } 332 333 return res; 334 335 } 336 337 boolean 338 lp_build_tgsi_llvm( 339 struct lp_build_tgsi_context * bld_base, 340 const struct tgsi_token *tokens) 341 { 342 struct tgsi_parse_context parse; 343 344 if (bld_base->emit_prologue) { 345 bld_base->emit_prologue(bld_base); 346 } 347 348 if (!lp_bld_tgsi_list_init(bld_base)) { 349 return FALSE; 350 } 351 352 tgsi_parse_init( &parse, tokens ); 353 354 while( !tgsi_parse_end_of_tokens( &parse ) ) { 355 tgsi_parse_token( &parse ); 356 357 switch( parse.FullToken.Token.Type ) { 358 case TGSI_TOKEN_TYPE_DECLARATION: 359 /* Inputs already interpolated */ 360 bld_base->emit_declaration(bld_base, &parse.FullToken.FullDeclaration); 361 break; 362 363 case TGSI_TOKEN_TYPE_INSTRUCTION: 364 lp_bld_tgsi_add_instruction(bld_base, &parse.FullToken.FullInstruction); 365 break; 366 367 case TGSI_TOKEN_TYPE_IMMEDIATE: 368 bld_base->emit_immediate(bld_base, &parse.FullToken.FullImmediate); 369 break; 370 371 case TGSI_TOKEN_TYPE_PROPERTY: 372 break; 373 374 default: 375 assert( 0 ); 376 } 377 } 378 379 while (bld_base->pc != -1) { 380 struct tgsi_full_instruction *instr = bld_base->instructions + 381 bld_base->pc; 382 const struct tgsi_opcode_info *opcode_info = 383 tgsi_get_opcode_info(instr->Instruction.Opcode); 384 if (!lp_build_tgsi_inst_llvm(bld_base, instr)) { 385 _debug_printf("warning: failed to translate tgsi opcode %s to LLVM\n", 386 opcode_info->mnemonic); 387 return FALSE; 388 } 389 } 390 391 tgsi_parse_free(&parse); 392 393 FREE(bld_base->instructions); 394 395 if (bld_base->emit_epilogue) { 396 bld_base->emit_epilogue(bld_base); 397 } 398 399 return TRUE; 400 } 401