mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-04-28 13:00:42 +02:00
r300/compiler: Introduce control flow instructions and refactor dataflow
Note that control flow instruction support isn't actually fully functional yet. Signed-off-by: Nicolai Hähnle <nhaehnle@gmail.com>
This commit is contained in:
parent
6d25b9125e
commit
b7cf887ca7
15 changed files with 429 additions and 774 deletions
|
|
@ -106,11 +106,11 @@ static unsigned translate_opcode(unsigned opcode)
|
|||
/* case TGSI_OPCODE_DP2: return RC_OPCODE_DP2; */
|
||||
case TGSI_OPCODE_TXL: return RC_OPCODE_TXL;
|
||||
/* case TGSI_OPCODE_BRK: return RC_OPCODE_BRK; */
|
||||
/* case TGSI_OPCODE_IF: return RC_OPCODE_IF; */
|
||||
case TGSI_OPCODE_IF: return RC_OPCODE_IF;
|
||||
/* case TGSI_OPCODE_LOOP: return RC_OPCODE_LOOP; */
|
||||
/* case TGSI_OPCODE_REP: return RC_OPCODE_REP; */
|
||||
/* case TGSI_OPCODE_ELSE: return RC_OPCODE_ELSE; */
|
||||
/* case TGSI_OPCODE_ENDIF: return RC_OPCODE_ENDIF; */
|
||||
case TGSI_OPCODE_ELSE: return RC_OPCODE_ELSE;
|
||||
case TGSI_OPCODE_ENDIF: return RC_OPCODE_ENDIF;
|
||||
/* case TGSI_OPCODE_ENDLOOP: return RC_OPCODE_ENDLOOP; */
|
||||
/* case TGSI_OPCODE_ENDREP: return RC_OPCODE_ENDREP; */
|
||||
/* case TGSI_OPCODE_PUSHA: return RC_OPCODE_PUSHA; */
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ C_SOURCES = \
|
|||
radeon_program_alu.c \
|
||||
radeon_program_pair.c \
|
||||
radeon_dataflow.c \
|
||||
radeon_dataflow_annotate.c \
|
||||
radeon_dataflow_dealias.c \
|
||||
radeon_dataflow_deadcode.c \
|
||||
radeon_dataflow_swizzles.c \
|
||||
r3xx_fragprog.c \
|
||||
r300_fragprog.c \
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "radeon_dataflow.h"
|
||||
#include "radeon_program_alu.h"
|
||||
#include "r300_fragprog.h"
|
||||
#include "r300_fragprog_swizzle.h"
|
||||
|
|
@ -107,17 +108,23 @@ void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c)
|
|||
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Fragment Program: After native rewrite:\n");
|
||||
rc_print_program(&c->Base.Program, 0);
|
||||
rc_print_program(&c->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
rc_dataflow_deadcode(&c->Base, &dataflow_outputs_mark_use, c);
|
||||
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Fragment Program: After deadcode:\n");
|
||||
rc_print_program(&c->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
rc_dataflow_annotate(&c->Base, &dataflow_outputs_mark_use, c);
|
||||
rc_dataflow_dealias(&c->Base);
|
||||
rc_dataflow_swizzles(&c->Base);
|
||||
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Compiler: after dataflow passes:\n");
|
||||
rc_print_program(&c->Base.Program, 0);
|
||||
rc_print_program(&c->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -588,7 +588,7 @@ void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* compiler)
|
|||
|
||||
if (compiler->Base.Debug) {
|
||||
fprintf(stderr, "Vertex program after native rewrite:\n");
|
||||
rc_print_program(&compiler->Base.Program, 0);
|
||||
rc_print_program(&compiler->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
|
@ -605,21 +605,25 @@ void r3xx_compile_vertex_program(struct r300_vertex_program_compiler* compiler)
|
|||
|
||||
if (compiler->Base.Debug) {
|
||||
fprintf(stderr, "Vertex program after source conflict resolve:\n");
|
||||
rc_print_program(&compiler->Base.Program, 0);
|
||||
rc_print_program(&compiler->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
rc_dataflow_deadcode(&compiler->Base, &dataflow_outputs_mark_used, compiler);
|
||||
|
||||
if (compiler->Base.Debug) {
|
||||
fprintf(stderr, "Vertex program after deadcode:\n");
|
||||
rc_print_program(&compiler->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
rc_dataflow_annotate(&compiler->Base, &dataflow_outputs_mark_used, compiler);
|
||||
rc_dataflow_dealias(&compiler->Base);
|
||||
rc_dataflow_swizzles(&compiler->Base);
|
||||
|
||||
/* This invalidates dataflow annotations and should be replaced
|
||||
* by a future generic register allocation pass. */
|
||||
allocate_temporary_registers(compiler);
|
||||
|
||||
if (compiler->Base.Debug) {
|
||||
fprintf(stderr, "Vertex program after dataflow:\n");
|
||||
rc_print_program(&compiler->Base.Program, 0);
|
||||
rc_print_program(&compiler->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,77 +30,3 @@
|
|||
#include "radeon_compiler.h"
|
||||
|
||||
|
||||
static void add_ref_to_vector(struct rc_dataflow_ref * ref, struct rc_dataflow_vector * vector)
|
||||
{
|
||||
ref->Vector = vector;
|
||||
ref->Prev = &vector->Refs;
|
||||
ref->Next = vector->Refs.Next;
|
||||
ref->Prev->Next = ref;
|
||||
ref->Next->Prev = ref;
|
||||
}
|
||||
|
||||
struct rc_dataflow_ref * rc_dataflow_create_ref(struct radeon_compiler * c,
|
||||
struct rc_dataflow_vector * vector, struct rc_instruction * inst)
|
||||
{
|
||||
struct rc_dataflow_ref * ref = memory_pool_malloc(&c->Pool, sizeof(struct rc_dataflow_ref));
|
||||
ref->ReadInstruction = inst;
|
||||
ref->UseMask = 0;
|
||||
|
||||
add_ref_to_vector(ref, vector);
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
struct rc_dataflow_vector * rc_dataflow_create_vector(struct radeon_compiler * c,
|
||||
rc_register_file file, unsigned int index, struct rc_instruction * inst)
|
||||
{
|
||||
struct rc_dataflow_vector * vec = memory_pool_malloc(&c->Pool, sizeof(struct rc_dataflow_vector));
|
||||
|
||||
memset(vec, 0, sizeof(struct rc_dataflow_vector));
|
||||
vec->File = file;
|
||||
vec->Index = index;
|
||||
vec->WriteInstruction = inst;
|
||||
|
||||
vec->Refs.Next = vec->Refs.Prev = &vec->Refs;
|
||||
|
||||
return vec;
|
||||
}
|
||||
|
||||
void rc_dataflow_remove_ref(struct rc_dataflow_ref * ref)
|
||||
{
|
||||
ref->Prev->Next = ref->Next;
|
||||
ref->Next->Prev = ref->Prev;
|
||||
}
|
||||
|
||||
void rc_dataflow_remove_instruction(struct rc_instruction * inst)
|
||||
{
|
||||
for(unsigned int i = 0; i < 3; ++i) {
|
||||
if (inst->Dataflow.SrcReg[i]) {
|
||||
rc_dataflow_remove_ref(inst->Dataflow.SrcReg[i]);
|
||||
inst->Dataflow.SrcReg[i] = 0;
|
||||
}
|
||||
if (inst->Dataflow.SrcRegAddress[i]) {
|
||||
rc_dataflow_remove_ref(inst->Dataflow.SrcRegAddress[i]);
|
||||
inst->Dataflow.SrcRegAddress[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->Dataflow.DstReg) {
|
||||
while(inst->Dataflow.DstReg->Refs.Next != &inst->Dataflow.DstReg->Refs) {
|
||||
struct rc_dataflow_ref * ref = inst->Dataflow.DstReg->Refs.Next;
|
||||
rc_dataflow_remove_ref(ref);
|
||||
if (inst->Dataflow.DstRegPrev)
|
||||
add_ref_to_vector(ref, inst->Dataflow.DstRegPrev->Vector);
|
||||
}
|
||||
|
||||
inst->Dataflow.DstReg->WriteInstruction = 0;
|
||||
inst->Dataflow.DstReg = 0;
|
||||
}
|
||||
|
||||
if (inst->Dataflow.DstRegPrev) {
|
||||
rc_dataflow_remove_ref(inst->Dataflow.DstRegPrev);
|
||||
inst->Dataflow.DstRegPrev = 0;
|
||||
}
|
||||
|
||||
inst->Dataflow.DstRegAliased = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,79 +34,14 @@ struct radeon_compiler;
|
|||
struct rc_instruction;
|
||||
struct rc_swizzle_caps;
|
||||
|
||||
struct rc_dataflow_vector;
|
||||
|
||||
struct rc_dataflow_ref {
|
||||
struct rc_dataflow_vector * Vector;
|
||||
|
||||
/**
|
||||
* Linked list of references to the above-mentioned vector.
|
||||
* The linked list is \em not sorted.
|
||||
*/
|
||||
/*@{*/
|
||||
struct rc_dataflow_ref * Prev;
|
||||
struct rc_dataflow_ref * Next;
|
||||
/*@}*/
|
||||
|
||||
unsigned int UseMask:4;
|
||||
struct rc_instruction * ReadInstruction;
|
||||
};
|
||||
|
||||
struct rc_dataflow_vector {
|
||||
rc_register_file File:3;
|
||||
unsigned int Index:RC_REGISTER_INDEX_BITS;
|
||||
|
||||
/** For private use in compiler passes. MUST BE RESET TO 0 by the end of each pass.
|
||||
* The annotate pass uses this bit to track whether a vector is in the
|
||||
* update stack.
|
||||
*/
|
||||
unsigned int PassBit:1;
|
||||
/** Which of the components have been written with useful values */
|
||||
unsigned int ValidMask:4;
|
||||
/** Which of the components are used downstream */
|
||||
unsigned int UseMask:4;
|
||||
/** The instruction that produced this vector */
|
||||
struct rc_instruction * WriteInstruction;
|
||||
|
||||
/** Linked list of references to this vector */
|
||||
struct rc_dataflow_ref Refs;
|
||||
};
|
||||
|
||||
struct rc_instruction_dataflow {
|
||||
struct rc_dataflow_ref * SrcReg[3];
|
||||
struct rc_dataflow_ref * SrcRegAddress[3];
|
||||
|
||||
/** Reference the components of the destination register
|
||||
* that are carried over without being overwritten */
|
||||
struct rc_dataflow_ref * DstRegPrev;
|
||||
/** Indicates whether the destination register was in use
|
||||
* before this instruction */
|
||||
unsigned int DstRegAliased:1;
|
||||
struct rc_dataflow_vector * DstReg;
|
||||
};
|
||||
|
||||
/**
|
||||
* General functions for manipulating the dataflow structures.
|
||||
*/
|
||||
/*@{*/
|
||||
struct rc_dataflow_ref * rc_dataflow_create_ref(struct radeon_compiler * c,
|
||||
struct rc_dataflow_vector * vector, struct rc_instruction * inst);
|
||||
struct rc_dataflow_vector * rc_dataflow_create_vector(struct radeon_compiler * c,
|
||||
rc_register_file file, unsigned int index, struct rc_instruction * inst);
|
||||
void rc_dataflow_remove_ref(struct rc_dataflow_ref * ref);
|
||||
|
||||
void rc_dataflow_remove_instruction(struct rc_instruction * inst);
|
||||
/*@}*/
|
||||
|
||||
|
||||
/**
|
||||
* Compiler passes based on dataflow structures.
|
||||
* Compiler passes based on dataflow analysis.
|
||||
*/
|
||||
/*@{*/
|
||||
typedef void (*rc_dataflow_mark_outputs_fn)(void * userdata, void * data,
|
||||
void (*mark_fn)(void * data, unsigned int index, unsigned int mask));
|
||||
void rc_dataflow_annotate(struct radeon_compiler * c, rc_dataflow_mark_outputs_fn dce, void * userdata);
|
||||
void rc_dataflow_dealias(struct radeon_compiler * c);
|
||||
void rc_dataflow_deadcode(struct radeon_compiler * c, rc_dataflow_mark_outputs_fn dce, void * userdata);
|
||||
void rc_dataflow_swizzles(struct radeon_compiler * c);
|
||||
/*@}*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,365 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Nicolai Haehnle.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "radeon_dataflow.h"
|
||||
|
||||
#include "radeon_compiler.h"
|
||||
|
||||
|
||||
struct dataflow_state {
|
||||
struct radeon_compiler * C;
|
||||
unsigned int DCE:1;
|
||||
unsigned int UpdateRunning:1;
|
||||
|
||||
struct rc_dataflow_vector * Input[RC_REGISTER_MAX_INDEX];
|
||||
struct rc_dataflow_vector * Output[RC_REGISTER_MAX_INDEX];
|
||||
struct rc_dataflow_vector * Temporary[RC_REGISTER_MAX_INDEX];
|
||||
struct rc_dataflow_vector * Address;
|
||||
|
||||
struct rc_dataflow_vector ** UpdateStack;
|
||||
unsigned int UpdateStackSize;
|
||||
unsigned int UpdateStackReserved;
|
||||
};
|
||||
|
||||
static void mark_vector_use(struct dataflow_state * s, struct rc_dataflow_vector * vector, unsigned int mask);
|
||||
|
||||
static struct rc_dataflow_vector * get_register_contents(struct dataflow_state * s,
|
||||
rc_register_file file, unsigned int index)
|
||||
{
|
||||
if (file == RC_FILE_INPUT || file == RC_FILE_OUTPUT || file == RC_FILE_TEMPORARY) {
|
||||
if (index >= RC_REGISTER_MAX_INDEX)
|
||||
return 0; /* cannot happen, but be defensive */
|
||||
|
||||
if (file == RC_FILE_TEMPORARY)
|
||||
return s->Temporary[index];
|
||||
if (file == RC_FILE_INPUT)
|
||||
return s->Input[index];
|
||||
if (file == RC_FILE_OUTPUT)
|
||||
return s->Output[index];
|
||||
}
|
||||
|
||||
if (file == RC_FILE_ADDRESS)
|
||||
return s->Address;
|
||||
|
||||
return 0; /* can happen, constant register file */
|
||||
}
|
||||
|
||||
static void mark_ref_use(struct dataflow_state * s, struct rc_dataflow_ref * ref, unsigned int mask)
|
||||
{
|
||||
if (!(mask & ~ref->UseMask))
|
||||
return;
|
||||
|
||||
ref->UseMask |= mask;
|
||||
mark_vector_use(s, ref->Vector, ref->UseMask);
|
||||
}
|
||||
|
||||
static void mark_source_use(struct dataflow_state * s, struct rc_instruction * inst,
|
||||
unsigned int src, unsigned int srcmask)
|
||||
{
|
||||
unsigned int refmask = 0;
|
||||
|
||||
for(unsigned int i = 0; i < 4; ++i) {
|
||||
if (GET_BIT(srcmask, i))
|
||||
refmask |= 1 << GET_SWZ(inst->I.SrcReg[src].Swizzle, i);
|
||||
}
|
||||
|
||||
/* get rid of spurious bits from ZERO, ONE, etc. swizzles */
|
||||
refmask &= RC_MASK_XYZW;
|
||||
|
||||
if (!refmask)
|
||||
return; /* can happen if the swizzle contains constant components */
|
||||
|
||||
if (inst->Dataflow.SrcReg[src])
|
||||
mark_ref_use(s, inst->Dataflow.SrcReg[src], refmask);
|
||||
|
||||
if (inst->Dataflow.SrcRegAddress[src])
|
||||
mark_ref_use(s, inst->Dataflow.SrcRegAddress[src], RC_MASK_X);
|
||||
}
|
||||
|
||||
static void compute_sources_for_writemask(
|
||||
struct rc_instruction * inst,
|
||||
unsigned int writemask,
|
||||
unsigned int *srcmasks)
|
||||
{
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode);
|
||||
|
||||
srcmasks[0] = 0;
|
||||
srcmasks[1] = 0;
|
||||
srcmasks[2] = 0;
|
||||
|
||||
if (inst->I.Opcode == RC_OPCODE_KIL)
|
||||
srcmasks[0] |= RC_MASK_XYZW;
|
||||
|
||||
if (!writemask)
|
||||
return;
|
||||
|
||||
if (opcode->IsComponentwise) {
|
||||
for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src)
|
||||
srcmasks[src] |= writemask;
|
||||
} else if (opcode->IsStandardScalar) {
|
||||
for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src)
|
||||
srcmasks[src] |= RC_MASK_X;
|
||||
} else {
|
||||
switch(inst->I.Opcode) {
|
||||
case RC_OPCODE_ARL:
|
||||
srcmasks[0] |= RC_MASK_X;
|
||||
break;
|
||||
case RC_OPCODE_DP3:
|
||||
srcmasks[0] |= RC_MASK_XYZ;
|
||||
srcmasks[1] |= RC_MASK_XYZ;
|
||||
break;
|
||||
case RC_OPCODE_DP4:
|
||||
srcmasks[0] |= RC_MASK_XYZW;
|
||||
srcmasks[1] |= RC_MASK_XYZW;
|
||||
break;
|
||||
case RC_OPCODE_TEX:
|
||||
case RC_OPCODE_TXB:
|
||||
case RC_OPCODE_TXP:
|
||||
srcmasks[0] |= RC_MASK_XYZW;
|
||||
break;
|
||||
case RC_OPCODE_DST:
|
||||
srcmasks[0] |= 0x6;
|
||||
srcmasks[1] |= 0xa;
|
||||
break;
|
||||
case RC_OPCODE_EXP:
|
||||
case RC_OPCODE_LOG:
|
||||
srcmasks[0] |= RC_MASK_XY;
|
||||
break;
|
||||
case RC_OPCODE_LIT:
|
||||
srcmasks[0] |= 0xb;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_instruction_source_use(struct dataflow_state * s,
|
||||
struct rc_instruction * inst, unsigned int writemask)
|
||||
{
|
||||
unsigned int srcmasks[3];
|
||||
|
||||
compute_sources_for_writemask(inst, writemask, srcmasks);
|
||||
|
||||
for(unsigned int src = 0; src < 3; ++src)
|
||||
mark_source_use(s, inst, src, srcmasks[src]);
|
||||
}
|
||||
|
||||
static void run_update(struct dataflow_state * s)
|
||||
{
|
||||
s->UpdateRunning = 1;
|
||||
|
||||
while(s->UpdateStackSize) {
|
||||
struct rc_dataflow_vector * vector = s->UpdateStack[--s->UpdateStackSize];
|
||||
vector->PassBit = 0;
|
||||
|
||||
if (vector->WriteInstruction) {
|
||||
struct rc_instruction * inst = vector->WriteInstruction;
|
||||
|
||||
if (inst->Dataflow.DstRegPrev) {
|
||||
unsigned int carryover = vector->UseMask & ~inst->I.DstReg.WriteMask;
|
||||
|
||||
if (carryover)
|
||||
mark_ref_use(s, inst->Dataflow.DstRegPrev, carryover);
|
||||
}
|
||||
|
||||
mark_instruction_source_use(
|
||||
s, vector->WriteInstruction,
|
||||
vector->UseMask & inst->I.DstReg.WriteMask);
|
||||
}
|
||||
}
|
||||
|
||||
s->UpdateRunning = 0;
|
||||
}
|
||||
|
||||
static void mark_vector_use(struct dataflow_state * s, struct rc_dataflow_vector * vector, unsigned int mask)
|
||||
{
|
||||
if (!(mask & ~vector->UseMask))
|
||||
return; /* no new used bits */
|
||||
|
||||
vector->UseMask |= mask;
|
||||
if (vector->PassBit)
|
||||
return;
|
||||
|
||||
if (s->UpdateStackSize >= s->UpdateStackReserved) {
|
||||
unsigned int new_reserve = 2 * s->UpdateStackReserved;
|
||||
struct rc_dataflow_vector ** new_stack;
|
||||
|
||||
if (!new_reserve)
|
||||
new_reserve = 16;
|
||||
|
||||
new_stack = memory_pool_malloc(&s->C->Pool, new_reserve * sizeof(struct rc_dataflow_vector *));
|
||||
memcpy(new_stack, s->UpdateStack, s->UpdateStackSize * sizeof(struct rc_dataflow_vector *));
|
||||
|
||||
s->UpdateStack = new_stack;
|
||||
s->UpdateStackReserved = new_reserve;
|
||||
}
|
||||
|
||||
s->UpdateStack[s->UpdateStackSize++] = vector;
|
||||
vector->PassBit = 1;
|
||||
|
||||
if (!s->UpdateRunning)
|
||||
run_update(s);
|
||||
}
|
||||
|
||||
static void annotate_instruction(struct dataflow_state * s, struct rc_instruction * inst)
|
||||
{
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode);
|
||||
unsigned int src;
|
||||
|
||||
for(src = 0; src < opcode->NumSrcRegs; ++src) {
|
||||
struct rc_dataflow_vector * vector = get_register_contents(s, inst->I.SrcReg[src].File, inst->I.SrcReg[src].Index);
|
||||
if (vector) {
|
||||
inst->Dataflow.SrcReg[src] = rc_dataflow_create_ref(s->C, vector, inst);
|
||||
}
|
||||
if (inst->I.SrcReg[src].RelAddr) {
|
||||
struct rc_dataflow_vector * addr = get_register_contents(s, RC_FILE_ADDRESS, 0);
|
||||
if (addr)
|
||||
inst->Dataflow.SrcRegAddress[src] = rc_dataflow_create_ref(s->C, addr, inst);
|
||||
}
|
||||
}
|
||||
|
||||
mark_instruction_source_use(s, inst, 0); /* for KIL */
|
||||
|
||||
if (opcode->HasDstReg) {
|
||||
struct rc_dataflow_vector * oldvec = get_register_contents(s, inst->I.DstReg.File, inst->I.DstReg.Index);
|
||||
struct rc_dataflow_vector * newvec = rc_dataflow_create_vector(s->C, inst->I.DstReg.File, inst->I.DstReg.Index, inst);
|
||||
|
||||
newvec->ValidMask = inst->I.DstReg.WriteMask;
|
||||
|
||||
if (oldvec) {
|
||||
unsigned int carryover = oldvec->ValidMask & ~inst->I.DstReg.WriteMask;
|
||||
|
||||
if (oldvec->ValidMask)
|
||||
inst->Dataflow.DstRegAliased = 1;
|
||||
|
||||
if (carryover) {
|
||||
inst->Dataflow.DstRegPrev = rc_dataflow_create_ref(s->C, oldvec, inst);
|
||||
newvec->ValidMask |= carryover;
|
||||
|
||||
if (!s->DCE)
|
||||
mark_ref_use(s, inst->Dataflow.DstRegPrev, carryover);
|
||||
}
|
||||
}
|
||||
|
||||
inst->Dataflow.DstReg = newvec;
|
||||
|
||||
if (newvec->File == RC_FILE_TEMPORARY)
|
||||
s->Temporary[newvec->Index] = newvec;
|
||||
else if (newvec->File == RC_FILE_OUTPUT)
|
||||
s->Output[newvec->Index] = newvec;
|
||||
else
|
||||
s->Address = newvec;
|
||||
|
||||
if (!s->DCE)
|
||||
mark_vector_use(s, newvec, inst->I.DstReg.WriteMask);
|
||||
}
|
||||
}
|
||||
|
||||
static void init_inputs(struct dataflow_state * s)
|
||||
{
|
||||
unsigned int index;
|
||||
|
||||
for(index = 0; index < 32; ++index) {
|
||||
if (s->C->Program.InputsRead & (1 << index)) {
|
||||
s->Input[index] = rc_dataflow_create_vector(s->C, RC_FILE_INPUT, index, 0);
|
||||
s->Input[index]->ValidMask = RC_MASK_XYZW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_output_use(void * data, unsigned int index, unsigned int mask)
|
||||
{
|
||||
struct dataflow_state * s = data;
|
||||
struct rc_dataflow_vector * vec = s->Output[index];
|
||||
|
||||
if (vec)
|
||||
mark_vector_use(s, vec, mask);
|
||||
}
|
||||
|
||||
void rc_dataflow_annotate(struct radeon_compiler * c, rc_dataflow_mark_outputs_fn dce, void * userdata)
|
||||
{
|
||||
struct dataflow_state s;
|
||||
struct rc_instruction * inst;
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.C = c;
|
||||
s.DCE = dce ? 1 : 0;
|
||||
|
||||
init_inputs(&s);
|
||||
|
||||
for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) {
|
||||
annotate_instruction(&s, inst);
|
||||
}
|
||||
|
||||
if (s.DCE) {
|
||||
dce(userdata, &s, &mark_output_use);
|
||||
|
||||
for(inst = c->Program.Instructions.Next; inst != &c->Program.Instructions; inst = inst->Next) {
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode);
|
||||
|
||||
if (opcode->HasDstReg) {
|
||||
unsigned int redundant_writes = inst->I.DstReg.WriteMask & ~inst->Dataflow.DstReg->UseMask;
|
||||
|
||||
inst->I.DstReg.WriteMask &= ~redundant_writes;
|
||||
|
||||
if (!inst->I.DstReg.WriteMask) {
|
||||
struct rc_instruction * todelete = inst;
|
||||
inst = inst->Prev;
|
||||
rc_remove_instruction(todelete);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int srcmasks[3];
|
||||
compute_sources_for_writemask(inst, inst->I.DstReg.WriteMask, srcmasks);
|
||||
|
||||
for(unsigned int src = 0; src < 3; ++src) {
|
||||
for(unsigned int chan = 0; chan < 4; ++chan) {
|
||||
if (!GET_BIT(srcmasks[src], chan))
|
||||
SET_SWZ(inst->I.SrcReg[src].Swizzle, chan, RC_SWIZZLE_UNUSED);
|
||||
}
|
||||
|
||||
if (inst->Dataflow.SrcReg[src]) {
|
||||
if (!inst->Dataflow.SrcReg[src]->UseMask) {
|
||||
rc_dataflow_remove_ref(inst->Dataflow.SrcReg[src]);
|
||||
inst->Dataflow.SrcReg[src] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->Dataflow.SrcRegAddress[src]) {
|
||||
if (!inst->Dataflow.SrcRegAddress[src]->UseMask) {
|
||||
rc_dataflow_remove_ref(inst->Dataflow.SrcRegAddress[src]);
|
||||
inst->Dataflow.SrcRegAddress[src] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc_calculate_inputs_outputs(c);
|
||||
}
|
||||
}
|
||||
253
src/mesa/drivers/dri/r300/compiler/radeon_dataflow_deadcode.c
Normal file
253
src/mesa/drivers/dri/r300/compiler/radeon_dataflow_deadcode.c
Normal file
|
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Nicolai Haehnle.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "radeon_dataflow.h"
|
||||
|
||||
#include "radeon_compiler.h"
|
||||
|
||||
|
||||
struct updatemask_state {
|
||||
unsigned char Output[RC_REGISTER_MAX_INDEX];
|
||||
unsigned char Temporary[RC_REGISTER_MAX_INDEX];
|
||||
unsigned char Address;
|
||||
};
|
||||
|
||||
struct instruction_state {
|
||||
unsigned char WriteMask;
|
||||
unsigned char SrcReg[3];
|
||||
};
|
||||
|
||||
struct branchinfo {
|
||||
unsigned int HaveElse:1;
|
||||
|
||||
struct updatemask_state StoreEndif;
|
||||
struct updatemask_state StoreElse;
|
||||
};
|
||||
|
||||
struct deadcode_state {
|
||||
struct radeon_compiler * C;
|
||||
struct instruction_state * Instructions;
|
||||
|
||||
struct updatemask_state R;
|
||||
|
||||
struct branchinfo * BranchStack;
|
||||
unsigned int BranchStackSize;
|
||||
unsigned int BranchStackReserved;
|
||||
};
|
||||
|
||||
|
||||
static void or_updatemasks(
|
||||
struct updatemask_state * dst,
|
||||
struct updatemask_state * a,
|
||||
struct updatemask_state * b)
|
||||
{
|
||||
for(unsigned int i = 0; i < RC_REGISTER_MAX_INDEX; ++i) {
|
||||
dst->Output[i] = a->Output[i] | b->Output[i];
|
||||
dst->Temporary[i] = a->Temporary[i] | b->Temporary[i];
|
||||
}
|
||||
|
||||
dst->Address = a->Address | b->Address;
|
||||
}
|
||||
|
||||
static void push_branch(struct deadcode_state * s)
|
||||
{
|
||||
if (s->BranchStackSize >= s->BranchStackReserved) {
|
||||
unsigned int new_reserve = 2 * s->BranchStackReserved;
|
||||
struct branchinfo * new_stack;
|
||||
|
||||
if (!new_reserve)
|
||||
new_reserve = 4;
|
||||
|
||||
new_stack = memory_pool_malloc(&s->C->Pool, new_reserve * sizeof(struct branchinfo));
|
||||
memcpy(new_stack, s->BranchStack, s->BranchStackSize * sizeof(struct branchinfo));
|
||||
|
||||
s->BranchStack = new_stack;
|
||||
s->BranchStackReserved = new_reserve;
|
||||
}
|
||||
|
||||
struct branchinfo * branch = &s->BranchStack[s->BranchStackSize++];
|
||||
branch->HaveElse = 0;
|
||||
memcpy(&branch->StoreEndif, &s->R, sizeof(s->R));
|
||||
}
|
||||
|
||||
static unsigned char * get_used_ptr(struct deadcode_state *s, rc_register_file file, unsigned int index)
|
||||
{
|
||||
if (file == RC_FILE_OUTPUT || file == RC_FILE_TEMPORARY) {
|
||||
if (index >= RC_REGISTER_MAX_INDEX) {
|
||||
rc_error(s->C, "%s: index %i is out of bounds for file %i\n", __FUNCTION__, index, file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (file == RC_FILE_OUTPUT)
|
||||
return &s->R.Output[index];
|
||||
else
|
||||
return &s->R.Temporary[index];
|
||||
} else if (file == RC_FILE_ADDRESS) {
|
||||
return &s->R.Address;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mark_used(struct deadcode_state * s, rc_register_file file, unsigned int index, unsigned int mask)
|
||||
{
|
||||
unsigned char * pused = get_used_ptr(s, file, index);
|
||||
if (pused)
|
||||
*pused |= mask;
|
||||
}
|
||||
|
||||
static void update_instruction(struct deadcode_state * s, struct rc_instruction * inst)
|
||||
{
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode);
|
||||
struct instruction_state * insts = &s->Instructions[inst->IP];
|
||||
unsigned int usedmask = 0;
|
||||
|
||||
if (opcode->HasDstReg) {
|
||||
unsigned char * pused = get_used_ptr(s, inst->I.DstReg.File, inst->I.DstReg.Index);
|
||||
if (pused) {
|
||||
usedmask = *pused & inst->I.DstReg.WriteMask;
|
||||
*pused &= ~usedmask;
|
||||
}
|
||||
}
|
||||
|
||||
insts->WriteMask |= usedmask;
|
||||
|
||||
unsigned int srcmasks[3];
|
||||
rc_compute_sources_for_writemask(opcode, usedmask, srcmasks);
|
||||
|
||||
for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
|
||||
unsigned int refmask = 0;
|
||||
unsigned int newsrcmask = srcmasks[src] & ~insts->SrcReg[src];
|
||||
insts->SrcReg[src] |= newsrcmask;
|
||||
|
||||
for(unsigned int chan = 0; chan < 4; ++chan) {
|
||||
if (GET_BIT(newsrcmask, chan))
|
||||
refmask |= 1 << GET_SWZ(inst->I.SrcReg[src].Swizzle, chan);
|
||||
}
|
||||
|
||||
/* get rid of spurious bits from ZERO, ONE, etc. swizzles */
|
||||
refmask &= RC_MASK_XYZW;
|
||||
|
||||
if (!refmask)
|
||||
continue;
|
||||
|
||||
mark_used(s, inst->I.SrcReg[src].File, inst->I.SrcReg[src].Index, refmask);
|
||||
|
||||
if (inst->I.SrcReg[src].RelAddr)
|
||||
mark_used(s, RC_FILE_ADDRESS, 0, RC_MASK_X);
|
||||
}
|
||||
}
|
||||
|
||||
static void mark_output_use(void * data, unsigned int index, unsigned int mask)
|
||||
{
|
||||
struct deadcode_state * s = data;
|
||||
|
||||
mark_used(s, RC_FILE_OUTPUT, index, mask);
|
||||
}
|
||||
|
||||
void rc_dataflow_deadcode(struct radeon_compiler * c, rc_dataflow_mark_outputs_fn dce, void * userdata)
|
||||
{
|
||||
struct deadcode_state s;
|
||||
unsigned int nr_instructions;
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.C = c;
|
||||
|
||||
nr_instructions = rc_recompute_ips(c);
|
||||
s.Instructions = memory_pool_malloc(&c->Pool, sizeof(struct instruction_state)*nr_instructions);
|
||||
memset(s.Instructions, 0, sizeof(struct instruction_state)*nr_instructions);
|
||||
|
||||
dce(userdata, &s, &mark_output_use);
|
||||
|
||||
for(struct rc_instruction * inst = c->Program.Instructions.Prev;
|
||||
inst != &c->Program.Instructions;
|
||||
inst = inst->Prev) {
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode);
|
||||
|
||||
if (opcode->IsControlFlow) {
|
||||
if (opcode->Opcode == RC_OPCODE_ENDIF) {
|
||||
push_branch(&s);
|
||||
} else {
|
||||
if (s.BranchStackSize) {
|
||||
struct branchinfo * branch = &s.BranchStack[s.BranchStackSize-1];
|
||||
|
||||
if (opcode->Opcode == RC_OPCODE_IF) {
|
||||
or_updatemasks(&s.R,
|
||||
&s.R,
|
||||
branch->HaveElse ? &branch->StoreElse : &branch->StoreEndif);
|
||||
|
||||
s.BranchStackSize--;
|
||||
} else if (opcode->Opcode == RC_OPCODE_ELSE) {
|
||||
if (branch->HaveElse) {
|
||||
rc_error(c, "%s: Multiple ELSE for one IF/ENDIF\n", __FUNCTION__);
|
||||
} else {
|
||||
memcpy(&branch->StoreElse, &s.R, sizeof(s.R));
|
||||
memcpy(&s.R, &branch->StoreEndif, sizeof(s.R));
|
||||
branch->HaveElse = 1;
|
||||
}
|
||||
} else {
|
||||
rc_error(c, "%s: Unhandled control flow instruction %s\n", __FUNCTION__, opcode->Name);
|
||||
}
|
||||
} else {
|
||||
rc_error(c, "%s: Unexpected control flow instruction\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_instruction(&s, inst);
|
||||
}
|
||||
|
||||
unsigned int ip = 0;
|
||||
for(struct rc_instruction * inst = c->Program.Instructions.Next;
|
||||
inst != &c->Program.Instructions;
|
||||
inst = inst->Next, ++ip) {
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode);
|
||||
|
||||
if (opcode->HasDstReg) {
|
||||
if (s.Instructions[ip].WriteMask) {
|
||||
inst->I.DstReg.WriteMask = s.Instructions[ip].WriteMask;
|
||||
} else {
|
||||
struct rc_instruction * todelete = inst;
|
||||
inst = inst->Prev;
|
||||
rc_remove_instruction(todelete);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int srcmasks[3];
|
||||
rc_compute_sources_for_writemask(opcode, s.Instructions[ip].WriteMask, srcmasks);
|
||||
|
||||
for(unsigned int src = 0; src < 3; ++src) {
|
||||
for(unsigned int chan = 0; chan < 4; ++chan) {
|
||||
if (!GET_BIT(srcmasks[src], chan))
|
||||
SET_SWZ(inst->I.SrcReg[src].Swizzle, chan, RC_SWIZZLE_UNUSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rc_calculate_inputs_outputs(c);
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 Nicolai Haehnle.
|
||||
*
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial
|
||||
* portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "radeon_dataflow.h"
|
||||
|
||||
#include "radeon_compiler.h"
|
||||
|
||||
|
||||
#define DEALIAS_LIST_SIZE 128
|
||||
|
||||
struct dealias_state {
|
||||
struct radeon_compiler * C;
|
||||
|
||||
unsigned int OldIndex:RC_REGISTER_INDEX_BITS;
|
||||
unsigned int NewIndex:RC_REGISTER_INDEX_BITS;
|
||||
unsigned int DealiasFail:1;
|
||||
|
||||
struct rc_dataflow_vector * List[DEALIAS_LIST_SIZE];
|
||||
unsigned int Length;
|
||||
};
|
||||
|
||||
static void push_dealias_vector(struct dealias_state * s, struct rc_dataflow_vector * vec)
|
||||
{
|
||||
if (s->Length >= DEALIAS_LIST_SIZE) {
|
||||
rc_debug(s->C, "%s: list size exceeded\n", __FUNCTION__);
|
||||
s->DealiasFail = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc_assert(s->C, vec->File == RC_FILE_TEMPORARY && vec->Index == s->OldIndex))
|
||||
return;
|
||||
|
||||
s->List[s->Length++] = vec;
|
||||
}
|
||||
|
||||
static void run_dealias(struct dealias_state * s)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for(i = 0; i < s->Length && !s->DealiasFail; ++i) {
|
||||
struct rc_dataflow_vector * vec = s->List[i];
|
||||
struct rc_dataflow_ref * ref;
|
||||
|
||||
for(ref = vec->Refs.Next; ref != &vec->Refs; ref = ref->Next) {
|
||||
if (ref->ReadInstruction->Dataflow.DstRegPrev == ref)
|
||||
push_dealias_vector(s, ref->ReadInstruction->Dataflow.DstReg);
|
||||
}
|
||||
}
|
||||
|
||||
if (s->DealiasFail)
|
||||
return;
|
||||
|
||||
for(i = 0; i < s->Length; ++i) {
|
||||
struct rc_dataflow_vector * vec = s->List[i];
|
||||
struct rc_dataflow_ref * ref;
|
||||
|
||||
vec->Index = s->NewIndex;
|
||||
vec->WriteInstruction->I.DstReg.Index = s->NewIndex;
|
||||
|
||||
for(ref = vec->Refs.Next; ref != &vec->Refs; ref = ref->Next) {
|
||||
struct rc_instruction * inst = ref->ReadInstruction;
|
||||
unsigned int i;
|
||||
|
||||
for(i = 0; i < 3; ++i) {
|
||||
if (inst->Dataflow.SrcReg[i] == ref) {
|
||||
if (rc_assert(s->C, inst->I.SrcReg[i].File == RC_FILE_TEMPORARY &&
|
||||
inst->I.SrcReg[i].Index == s->OldIndex))
|
||||
return;
|
||||
|
||||
inst->I.SrcReg[i].Index = s->NewIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Breaks register aliasing to reduce multiple assignments to a single register.
|
||||
*
|
||||
* This affects sequences like:
|
||||
* MUL r0, ...;
|
||||
* MAD r0, r1, r2, r0;
|
||||
* In this example, a new register will be used for the destination of the
|
||||
* second MAD.
|
||||
*
|
||||
* The purpose of this dealiasing is to make the resulting code more SSA-like
|
||||
* and therefore make it easier to move instructions around.
|
||||
* This is of crucial importance for R300 fragment programs, where de-aliasing
|
||||
* can help to reduce texture indirections, but other targets can benefit from
|
||||
* it as well.
|
||||
*
|
||||
* \note When compiling GLSL, there may be some benefit gained from breaking
|
||||
* up vectors whose components are unrelated. This is not done yet and should
|
||||
* be investigated at some point (of course, a matching pass to re-merge
|
||||
* components would be required).
|
||||
*/
|
||||
void rc_dataflow_dealias(struct radeon_compiler * c)
|
||||
{
|
||||
struct dealias_state s;
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.C = c;
|
||||
|
||||
struct rc_instruction * inst;
|
||||
for(inst = c->Program.Instructions.Prev; inst != &c->Program.Instructions; inst = inst->Prev) {
|
||||
if (!inst->Dataflow.DstRegAliased || inst->Dataflow.DstReg->File != RC_FILE_TEMPORARY)
|
||||
continue;
|
||||
|
||||
if (inst->Dataflow.DstReg->UseMask & ~inst->I.DstReg.WriteMask)
|
||||
continue;
|
||||
|
||||
s.OldIndex = inst->I.DstReg.Index;
|
||||
s.NewIndex = rc_find_free_temporary(c);
|
||||
s.DealiasFail = 0;
|
||||
s.Length = 0;
|
||||
|
||||
inst->Dataflow.DstRegAliased = 0;
|
||||
if (inst->Dataflow.DstRegPrev) {
|
||||
rc_dataflow_remove_ref(inst->Dataflow.DstRegPrev);
|
||||
inst->Dataflow.DstRegPrev = 0;
|
||||
}
|
||||
|
||||
push_dealias_vector(&s, inst->Dataflow.DstReg);
|
||||
run_dealias(&s);
|
||||
}
|
||||
}
|
||||
|
|
@ -37,8 +37,6 @@ static void rewrite_source(struct radeon_compiler * c,
|
|||
struct rc_swizzle_split split;
|
||||
unsigned int tempreg = rc_find_free_temporary(c);
|
||||
unsigned int usemask;
|
||||
struct rc_dataflow_ref * oldref = inst->Dataflow.SrcReg[src];
|
||||
struct rc_dataflow_vector * vector = 0;
|
||||
|
||||
usemask = 0;
|
||||
for(unsigned int chan = 0; chan < 4; ++chan) {
|
||||
|
|
@ -75,30 +73,8 @@ static void rewrite_source(struct radeon_compiler * c,
|
|||
else if (masked_negate == split.Phase[phase])
|
||||
mov->I.SrcReg[0].Negate = RC_MASK_XYZW;
|
||||
|
||||
if (oldref) {
|
||||
mov->Dataflow.SrcReg[0] = rc_dataflow_create_ref(c, oldref->Vector, mov);
|
||||
mov->Dataflow.SrcReg[0]->UseMask = phase_refmask;
|
||||
}
|
||||
|
||||
mov->Dataflow.DstReg = rc_dataflow_create_vector(c, RC_FILE_TEMPORARY, tempreg, mov);
|
||||
mov->Dataflow.DstReg->ValidMask = split.Phase[phase];
|
||||
|
||||
if (vector) {
|
||||
mov->Dataflow.DstRegPrev = rc_dataflow_create_ref(c, vector, mov);
|
||||
mov->Dataflow.DstRegPrev->UseMask = vector->ValidMask;
|
||||
mov->Dataflow.DstReg->ValidMask |= vector->ValidMask;
|
||||
mov->Dataflow.DstRegAliased = 1;
|
||||
}
|
||||
|
||||
mov->Dataflow.DstReg->UseMask = mov->Dataflow.DstReg->ValidMask;
|
||||
vector = mov->Dataflow.DstReg;
|
||||
}
|
||||
|
||||
if (oldref)
|
||||
rc_dataflow_remove_ref(oldref);
|
||||
inst->Dataflow.SrcReg[src] = rc_dataflow_create_ref(c, vector, inst);
|
||||
inst->Dataflow.SrcReg[src]->UseMask = usemask;
|
||||
|
||||
inst->I.SrcReg[src].File = RC_FILE_TEMPORARY;
|
||||
inst->I.SrcReg[src].Index = tempreg;
|
||||
inst->I.SrcReg[src].Swizzle = 0;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include "radeon_opcodes.h"
|
||||
|
||||
#include "radeon_program_constants.h"
|
||||
|
||||
struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = {
|
||||
{
|
||||
.Opcode = RC_OPCODE_NOP,
|
||||
|
|
@ -339,9 +341,85 @@ struct rc_opcode_info rc_opcodes[MAX_RC_OPCODE] = {
|
|||
.NumSrcRegs = 1,
|
||||
.HasDstReg = 1
|
||||
},
|
||||
{
|
||||
.Opcode = RC_OPCODE_IF,
|
||||
.Name = "IF",
|
||||
.IsControlFlow = 1,
|
||||
.NumSrcRegs = 1
|
||||
},
|
||||
{
|
||||
.Opcode = RC_OPCODE_ELSE,
|
||||
.Name = "ELSE",
|
||||
.IsControlFlow = 1,
|
||||
.NumSrcRegs = 0
|
||||
},
|
||||
{
|
||||
.Opcode = RC_OPCODE_ENDIF,
|
||||
.Name = "ENDIF",
|
||||
.IsControlFlow = 1,
|
||||
.NumSrcRegs = 0
|
||||
},
|
||||
{
|
||||
.Opcode = RC_OPCODE_REPL_ALPHA,
|
||||
.Name = "REPL_ALPHA",
|
||||
.HasDstReg = 1
|
||||
}
|
||||
};
|
||||
|
||||
void rc_compute_sources_for_writemask(
|
||||
const struct rc_opcode_info * opcode,
|
||||
unsigned int writemask,
|
||||
unsigned int *srcmasks)
|
||||
{
|
||||
srcmasks[0] = 0;
|
||||
srcmasks[1] = 0;
|
||||
srcmasks[2] = 0;
|
||||
|
||||
if (opcode->Opcode == RC_OPCODE_KIL)
|
||||
srcmasks[0] |= RC_MASK_XYZW;
|
||||
else if (opcode->Opcode == RC_OPCODE_IF)
|
||||
srcmasks[0] |= RC_MASK_X;
|
||||
|
||||
if (!writemask)
|
||||
return;
|
||||
|
||||
if (opcode->IsComponentwise) {
|
||||
for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src)
|
||||
srcmasks[src] |= writemask;
|
||||
} else if (opcode->IsStandardScalar) {
|
||||
for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src)
|
||||
srcmasks[src] |= RC_MASK_X;
|
||||
} else {
|
||||
switch(opcode->Opcode) {
|
||||
case RC_OPCODE_ARL:
|
||||
srcmasks[0] |= RC_MASK_X;
|
||||
break;
|
||||
case RC_OPCODE_DP3:
|
||||
srcmasks[0] |= RC_MASK_XYZ;
|
||||
srcmasks[1] |= RC_MASK_XYZ;
|
||||
break;
|
||||
case RC_OPCODE_DP4:
|
||||
srcmasks[0] |= RC_MASK_XYZW;
|
||||
srcmasks[1] |= RC_MASK_XYZW;
|
||||
break;
|
||||
case RC_OPCODE_TEX:
|
||||
case RC_OPCODE_TXB:
|
||||
case RC_OPCODE_TXP:
|
||||
srcmasks[0] |= RC_MASK_XYZW;
|
||||
break;
|
||||
case RC_OPCODE_DST:
|
||||
srcmasks[0] |= 0x6;
|
||||
srcmasks[1] |= 0xa;
|
||||
break;
|
||||
case RC_OPCODE_EXP:
|
||||
case RC_OPCODE_LOG:
|
||||
srcmasks[0] |= RC_MASK_XY;
|
||||
break;
|
||||
case RC_OPCODE_LIT:
|
||||
srcmasks[0] |= 0xb;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,18 @@ typedef enum {
|
|||
RC_OPCODE_TXL,
|
||||
RC_OPCODE_TXP,
|
||||
|
||||
/** branch instruction:
|
||||
* If src0.x != 0.0, continue with the next instruction;
|
||||
* otherwise, jump to matching RC_OPCODE_ELSE or RC_OPCODE_ENDIF.
|
||||
*/
|
||||
RC_OPCODE_IF,
|
||||
|
||||
/** branch instruction: jump to matching RC_OPCODE_ENDIF */
|
||||
RC_OPCODE_ELSE,
|
||||
|
||||
/** branch instruction: has no effect */
|
||||
RC_OPCODE_ENDIF,
|
||||
|
||||
/** special instruction, used in R300-R500 fragment program pair instructions
|
||||
* indicates that the result of the alpha operation shall be replicated
|
||||
* across all other channels */
|
||||
|
|
@ -188,6 +200,9 @@ struct rc_opcode_info {
|
|||
unsigned int NumSrcRegs:2;
|
||||
unsigned int HasDstReg:1;
|
||||
|
||||
/** true if this instruction affects control flow */
|
||||
unsigned int IsControlFlow:1;
|
||||
|
||||
/** true if this is a vector instruction that operates on components in parallel
|
||||
* without any cross-component interaction */
|
||||
unsigned int IsComponentwise:1;
|
||||
|
|
@ -207,4 +222,9 @@ static inline const struct rc_opcode_info * rc_get_opcode_info(rc_opcode opcode)
|
|||
return &rc_opcodes[opcode];
|
||||
}
|
||||
|
||||
void rc_compute_sources_for_writemask(
|
||||
const struct rc_opcode_info * opcode,
|
||||
unsigned int writemask,
|
||||
unsigned int *srcmasks);
|
||||
|
||||
#endif /* RADEON_OPCODES_H */
|
||||
|
|
|
|||
|
|
@ -154,7 +154,24 @@ struct rc_instruction *rc_insert_new_instruction(struct radeon_compiler * c, str
|
|||
|
||||
void rc_remove_instruction(struct rc_instruction * inst)
|
||||
{
|
||||
rc_dataflow_remove_instruction(inst);
|
||||
inst->Prev->Next = inst->Next;
|
||||
inst->Next->Prev = inst->Prev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of instructions in the program.
|
||||
*/
|
||||
unsigned int rc_recompute_ips(struct radeon_compiler * c)
|
||||
{
|
||||
unsigned int ip = 0;
|
||||
|
||||
for(struct rc_instruction * inst = c->Program.Instructions.Next;
|
||||
inst != &c->Program.Instructions;
|
||||
inst = inst->Next) {
|
||||
inst->IP = ip++;
|
||||
}
|
||||
|
||||
c->Program.Instructions.IP = 0xcafedead;
|
||||
|
||||
return ip;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
#include "radeon_opcodes.h"
|
||||
#include "radeon_code.h"
|
||||
#include "radeon_program_constants.h"
|
||||
#include "radeon_dataflow.h"
|
||||
|
||||
struct radeon_compiler;
|
||||
|
||||
|
|
@ -73,33 +72,33 @@ struct rc_dst_register {
|
|||
* instruction types may be valid.
|
||||
*/
|
||||
struct rc_sub_instruction {
|
||||
struct rc_src_register SrcReg[3];
|
||||
struct rc_dst_register DstReg;
|
||||
struct rc_src_register SrcReg[3];
|
||||
struct rc_dst_register DstReg;
|
||||
|
||||
/**
|
||||
* Opcode of this instruction, according to \ref rc_opcode enums.
|
||||
*/
|
||||
rc_opcode Opcode:8;
|
||||
/**
|
||||
* Opcode of this instruction, according to \ref rc_opcode enums.
|
||||
*/
|
||||
rc_opcode Opcode:8;
|
||||
|
||||
/**
|
||||
* Saturate each value of the result to the range [0,1] or [-1,1],
|
||||
* according to \ref rc_saturate_mode enums.
|
||||
*/
|
||||
rc_saturate_mode SaturateMode:2;
|
||||
/**
|
||||
* Saturate each value of the result to the range [0,1] or [-1,1],
|
||||
* according to \ref rc_saturate_mode enums.
|
||||
*/
|
||||
rc_saturate_mode SaturateMode:2;
|
||||
|
||||
/**
|
||||
* \name Extra fields for TEX, TXB, TXD, TXL, TXP instructions.
|
||||
*/
|
||||
/*@{*/
|
||||
/** Source texture unit. */
|
||||
unsigned int TexSrcUnit:5;
|
||||
/**
|
||||
* \name Extra fields for TEX, TXB, TXD, TXL, TXP instructions.
|
||||
*/
|
||||
/*@{*/
|
||||
/** Source texture unit. */
|
||||
unsigned int TexSrcUnit:5;
|
||||
|
||||
/** Source texture target, one of the \ref rc_texture_target enums */
|
||||
rc_texture_target TexSrcTarget:3;
|
||||
/** Source texture target, one of the \ref rc_texture_target enums */
|
||||
rc_texture_target TexSrcTarget:3;
|
||||
|
||||
/** True if tex instruction should do shadow comparison */
|
||||
unsigned int TexShadow:1;
|
||||
/*@}*/
|
||||
/** True if tex instruction should do shadow comparison */
|
||||
unsigned int TexShadow:1;
|
||||
/*@}*/
|
||||
};
|
||||
|
||||
struct rc_instruction {
|
||||
|
|
@ -109,13 +108,11 @@ struct rc_instruction {
|
|||
struct rc_sub_instruction I;
|
||||
|
||||
/**
|
||||
* Dataflow annotations.
|
||||
*
|
||||
* These are not supplied by the caller of the compiler,
|
||||
* but filled in during compilation stages that make use of
|
||||
* dataflow analysis.
|
||||
* Warning: IPs are not stable. If you want to use them,
|
||||
* you need to recompute them at the beginning of each pass
|
||||
* using \ref rc_recompute_ips
|
||||
*/
|
||||
struct rc_instruction_dataflow Dataflow;
|
||||
unsigned int IP;
|
||||
};
|
||||
|
||||
struct rc_program {
|
||||
|
|
@ -210,10 +207,8 @@ struct rc_instruction *rc_alloc_instruction(struct radeon_compiler * c);
|
|||
struct rc_instruction *rc_insert_new_instruction(struct radeon_compiler * c, struct rc_instruction * after);
|
||||
void rc_remove_instruction(struct rc_instruction * inst);
|
||||
|
||||
enum {
|
||||
RC_PRINT_DATAFLOW = 0x1
|
||||
};
|
||||
unsigned int rc_recompute_ips(struct radeon_compiler * c);
|
||||
|
||||
void rc_print_program(const struct rc_program *prog, unsigned int flags);
|
||||
void rc_print_program(const struct rc_program *prog);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
static void print_comment(FILE * f)
|
||||
{
|
||||
fprintf(f, " # ");
|
||||
}
|
||||
|
||||
static const char * textarget_to_string(rc_texture_target target)
|
||||
{
|
||||
switch(target) {
|
||||
|
|
@ -121,19 +116,7 @@ static void rc_print_src_register(FILE * f, struct rc_src_register src)
|
|||
fprintf(f, "|");
|
||||
}
|
||||
|
||||
static void rc_print_ref(FILE * f, struct rc_dataflow_ref * ref)
|
||||
{
|
||||
fprintf(f, "ref(%p", ref->Vector);
|
||||
|
||||
if (ref->UseMask != RC_MASK_XYZW) {
|
||||
fprintf(f, ".");
|
||||
rc_print_mask(f, ref->UseMask);
|
||||
}
|
||||
|
||||
fprintf(f, ")");
|
||||
}
|
||||
|
||||
static void rc_print_instruction(FILE * f, unsigned int flags, struct rc_instruction * inst)
|
||||
static void rc_print_instruction(FILE * f, struct rc_instruction * inst)
|
||||
{
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->I.Opcode);
|
||||
unsigned int reg;
|
||||
|
|
@ -169,45 +152,22 @@ static void rc_print_instruction(FILE * f, unsigned int flags, struct rc_instruc
|
|||
}
|
||||
|
||||
fprintf(f, ";\n");
|
||||
|
||||
if (flags & RC_PRINT_DATAFLOW) {
|
||||
print_comment(f);
|
||||
|
||||
fprintf(f, "Dst = %p", inst->Dataflow.DstReg);
|
||||
if (inst->Dataflow.DstRegAliased)
|
||||
fprintf(f, " aliased");
|
||||
if (inst->Dataflow.DstRegPrev) {
|
||||
fprintf(f, " from ");
|
||||
rc_print_ref(f, inst->Dataflow.DstRegPrev);
|
||||
}
|
||||
|
||||
for(reg = 0; reg < opcode->NumSrcRegs; ++reg) {
|
||||
fprintf(f, ", ");
|
||||
if (inst->Dataflow.SrcReg[reg])
|
||||
rc_print_ref(f, inst->Dataflow.SrcReg[reg]);
|
||||
else
|
||||
fprintf(f, "<no ref>");
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print program to stderr, default options.
|
||||
*/
|
||||
void rc_print_program(const struct rc_program *prog, unsigned int flags)
|
||||
void rc_print_program(const struct rc_program *prog)
|
||||
{
|
||||
unsigned int linenum = 0;
|
||||
struct rc_instruction *inst;
|
||||
|
||||
fprintf(stderr, "# Radeon Compiler Program%s\n",
|
||||
flags & RC_PRINT_DATAFLOW ? " (with dataflow annotations)" : "");
|
||||
fprintf(stderr, "# Radeon Compiler Program\n");
|
||||
|
||||
for(inst = prog->Instructions.Next; inst != &prog->Instructions; inst = inst->Next) {
|
||||
fprintf(stderr, "%3d: ", linenum);
|
||||
|
||||
rc_print_instruction(stderr, flags, inst);
|
||||
rc_print_instruction(stderr, inst);
|
||||
|
||||
linenum++;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue