make_xmm( xmm_src ) );
}
-
-
-
-
-
-
/**
* Register fetch.
*/
-
static void
emit_fetch(
struct x86_function *func,
/**
* Register store.
*/
-
static void
emit_store(
struct x86_function *func,
/**
* High-level instruction translators.
*/
-
static void
emit_tex( struct x86_function *func,
const struct tgsi_full_instruction *inst,
get_temp( TEMP_R0, 3 ),
make_xmm( 3 ) );
-
if (projected) {
FETCH( func, *inst, 3, 0, 3 );
args[0] = get_temp( TEMP_R0, 0 );
args[1] = get_sampler_ptr( unit );
-
emit_func_call( func,
0,
args,
/* This mask stores component bits that were already tested. Note that
* we test if the value is less than zero, so 1.0 and 0.0 need not to be
- * tested. */
+ * tested.
+ */
uniquemask = 0;
FOR_EACH_CHANNEL( chan_index ) {
/**
- * Check if inst src/dest regs use indirect addressing into temporary
- * register file.
+ * Check if inst src/dest regs use indirect addressing into temporary,
+ * input or output register files.
*/
static boolean
-indirect_temp_reference(const struct tgsi_full_instruction *inst)
+indirect_reg_reference(const struct tgsi_full_instruction *inst)
{
uint i;
for (i = 0; i < inst->Instruction.NumSrcRegs; i++) {
const struct tgsi_full_src_register *reg = &inst->Src[i];
- if (reg->Register.File == TGSI_FILE_TEMPORARY &&
+ if ((reg->Register.File == TGSI_FILE_TEMPORARY ||
+ reg->Register.File == TGSI_FILE_INPUT ||
+ reg->Register.File == TGSI_FILE_OUTPUT) &&
reg->Register.Indirect)
return TRUE;
}
for (i = 0; i < inst->Instruction.NumDstRegs; i++) {
const struct tgsi_full_dst_register *reg = &inst->Dst[i];
- if (reg->Register.File == TGSI_FILE_TEMPORARY &&
+ if ((reg->Register.File == TGSI_FILE_TEMPORARY ||
+ reg->Register.File == TGSI_FILE_INPUT ||
+ reg->Register.File == TGSI_FILE_OUTPUT) &&
reg->Register.Indirect)
return TRUE;
}
unsigned chan_index;
/* we can't handle indirect addressing into temp register file yet */
- if (indirect_temp_reference(inst))
+ if (indirect_reg_reference(inst))
return FALSE;
switch (inst->Instruction.Opcode) {
break;
case TGSI_OPCODE_MUL:
+ /* do all fetches and adds, storing results in temp regs */
FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
- FETCH( func, *inst, 0, 0, chan_index );
- FETCH( func, *inst, 1, 1, chan_index );
- emit_mul( func, 0, 1 );
- STORE( func, *inst, 0, 0, chan_index );
+ int r = chan_index + 1;
+ FETCH( func, *inst, 0, 0, chan_index ); /* load xmm[0] */
+ FETCH( func, *inst, r, 1, chan_index ); /* load xmm[r] */
+ emit_mul( func, r, 0 ); /* xmm[r] = xmm[r] * xmm[0] */
+ }
+ /* do all stores of the temp regs */
+ FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
+ int r = chan_index + 1;
+ STORE( func, *inst, r, 0, chan_index ); /* store xmm[r] */
}
break;
case TGSI_OPCODE_ADD:
+ /* do all fetches and adds, storing results in temp regs */
FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
- FETCH( func, *inst, 0, 0, chan_index );
- FETCH( func, *inst, 1, 1, chan_index );
- emit_add( func, 0, 1 );
- STORE( func, *inst, 0, 0, chan_index );
+ int r = chan_index + 1;
+ FETCH( func, *inst, 0, 0, chan_index ); /* load xmm[0] */
+ FETCH( func, *inst, r, 1, chan_index ); /* load xmm[r] */
+ emit_add( func, r, 0 ); /* xmm[r] = xmm[r] + xmm[0] */
+ }
+ /* do all stores of the temp regs */
+ FOR_EACH_DST0_ENABLED_CHANNEL( *inst, chan_index ) {
+ int r = chan_index + 1;
+ STORE( func, *inst, r, 0, chan_index ); /* store xmm[r] */
}
break;
return 0;
break;
- case TGSI_OPCODE_BGNFOR:
- return 0;
- break;
-
- case TGSI_OPCODE_REP:
- return 0;
- break;
-
case TGSI_OPCODE_ELSE:
return 0;
break;
return 0;
break;
- case TGSI_OPCODE_ENDFOR:
- return 0;
- break;
-
- case TGSI_OPCODE_ENDREP:
- return 0;
- break;
-
case TGSI_OPCODE_PUSHA:
return 0;
break;
x86_pop( func, x86_make_reg( file_REG32, reg_BX ) );
}
+
+/**
+ * Check if the instructions dst register is the same as any src
+ * register and warn if there's a posible SOA dependency.
+ */
+static void
+check_soa_dependencies(const struct tgsi_full_instruction *inst)
+{
+ switch (inst->Instruction.Opcode) {
+ case TGSI_OPCODE_ADD:
+ case TGSI_OPCODE_MOV:
+ case TGSI_OPCODE_MUL:
+ case TGSI_OPCODE_XPD:
+ /* OK - these opcodes correctly handle SOA dependencies */
+ break;
+ default:
+ if (tgsi_check_soa_dependencies(inst)) {
+ uint opcode = inst->Instruction.Opcode;
+
+ /* XXX: we only handle src/dst aliasing in a few opcodes
+ * currently. Need to use an additional temporay to hold
+ * the result in the cases where the code is too opaque to
+ * fix.
+ */
+ if (opcode != TGSI_OPCODE_MOV) {
+ debug_printf("Warning: src/dst aliasing in instruction"
+ " is not handled:\n");
+ tgsi_dump_instruction(inst, 1);
+ }
+ }
+ }
+}
+
+
/**
* Translate a TGSI vertex/fragment shader to SSE2 code.
* Slightly different things are done for vertex vs. fragment shaders.
x86_make_disp( get_machine_base(),
Offset( struct tgsi_exec_machine, Samplers ) ) );
-
while( !tgsi_parse_end_of_tokens( &parse ) && ok ) {
tgsi_parse_token( &parse );
if (!ok) {
uint opcode = parse.FullToken.FullInstruction.Instruction.Opcode;
+ uint proc = parse.FullHeader.Processor.Processor;
debug_printf("failed to translate tgsi opcode %d (%s) to SSE (%s)\n",
opcode,
tgsi_get_opcode_name(opcode),
- parse.FullHeader.Processor.Processor == TGSI_PROCESSOR_VERTEX ?
- "vertex shader" : "fragment shader");
+ tgsi_get_processor_name(proc));
}
- if (tgsi_check_soa_dependencies(&parse.FullToken.FullInstruction)) {
- uint opcode = parse.FullToken.FullInstruction.Instruction.Opcode;
-
- /* XXX: we only handle src/dst aliasing in a few opcodes
- * currently. Need to use an additional temporay to hold
- * the result in the cases where the code is too opaque to
- * fix.
- */
- if (opcode != TGSI_OPCODE_MOV) {
- debug_printf("Warning: src/dst aliasing in instruction"
- " is not handled:\n");
- tgsi_dump_instruction(&parse.FullToken.FullInstruction, 1);
- }
- }
+ check_soa_dependencies(&parse.FullToken.FullInstruction);
break;
case TGSI_TOKEN_TYPE_IMMEDIATE:
}
#endif /* PIPE_ARCH_X86 */
-