r300/compiler: Implement branch emulation for R300 fragment programs
Signed-off-by: Nicolai Hähnle <nhaehnle@gmail.com>
This commit is contained in:
committed by
Marek Olšák
parent
eeabe9d179
commit
4d7ed84431
@@ -8,6 +8,7 @@ LIBNAME = r300compiler
|
||||
C_SOURCES = \
|
||||
radeon_code.c \
|
||||
radeon_compiler.c \
|
||||
radeon_emulate_branches.c \
|
||||
radeon_program.c \
|
||||
radeon_program_print.c \
|
||||
radeon_opcodes.c \
|
||||
|
||||
@@ -46,4 +46,35 @@ void memory_pool_init(struct memory_pool * pool);
|
||||
void memory_pool_destroy(struct memory_pool * pool);
|
||||
void * memory_pool_malloc(struct memory_pool * pool, unsigned int bytes);
|
||||
|
||||
|
||||
/**
|
||||
* Generic helper for growing an array that has separate size/count
|
||||
* and reserved counters to accomodate up to num new element.
|
||||
*
|
||||
* type * Array;
|
||||
* unsigned int Size;
|
||||
* unsigned int Reserved;
|
||||
*
|
||||
* memory_pool_array_reserve(pool, type, Array, Size, Reserved, k);
|
||||
* assert(Size + k < Reserved);
|
||||
*
|
||||
* \note Size is not changed by this macro.
|
||||
*
|
||||
* \warning Array, Size, Reserved have to be lvalues and may be evaluated
|
||||
* several times.
|
||||
*/
|
||||
#define memory_pool_array_reserve(pool, type, array, size, reserved, num) do { \
|
||||
unsigned int _num = (num); \
|
||||
if ((size) + _num > (reserved)) { \
|
||||
unsigned int newreserve = (reserved) * 2; \
|
||||
type * newarray; \
|
||||
if (newreserve < _num) \
|
||||
newreserve = 4 * _num; /* arbitrary heuristic */ \
|
||||
newarray = memory_pool_malloc((pool), newreserve * sizeof(type)); \
|
||||
memcpy(newarray, (array), (size) * sizeof(type)); \
|
||||
(array) = newarray; \
|
||||
(reserved) = newreserve; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#endif /* MEMORY_POOL_H */
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "radeon_dataflow.h"
|
||||
#include "radeon_emulate_branches.h"
|
||||
#include "radeon_program_alu.h"
|
||||
#include "radeon_program_tex.h"
|
||||
#include "r300_fragprog.h"
|
||||
@@ -85,6 +86,14 @@ static void rewrite_depth_out(struct r300_fragment_program_compiler * c)
|
||||
}
|
||||
}
|
||||
|
||||
static void debug_program_log(struct r300_fragment_program_compiler* c, const char * where)
|
||||
{
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Fragment Program: %s\n", where);
|
||||
rc_print_program(&c->Base.Program);
|
||||
}
|
||||
}
|
||||
|
||||
void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c)
|
||||
{
|
||||
rewrite_depth_out(c);
|
||||
@@ -106,6 +115,10 @@ void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c)
|
||||
};
|
||||
radeonLocalTransform(&c->Base, 2, transformations);
|
||||
|
||||
debug_program_log(c, "before emulate branches");
|
||||
|
||||
rc_emulate_branches(&c->Base);
|
||||
|
||||
c->Base.SwizzleCaps = &r300_swizzle_caps;
|
||||
}
|
||||
|
||||
@@ -119,62 +132,41 @@ void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c)
|
||||
common_transformations[0].function = &radeonTransformALU;
|
||||
radeonLocalTransform(&c->Base, 1, common_transformations);
|
||||
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Fragment Program: After native rewrite:\n");
|
||||
rc_print_program(&c->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
if (c->Base.Error)
|
||||
return;
|
||||
|
||||
debug_program_log(c, "after native rewrite");
|
||||
|
||||
rc_dataflow_deadcode(&c->Base, &dataflow_outputs_mark_use, c);
|
||||
if (c->Base.Error)
|
||||
return;
|
||||
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Fragment Program: After deadcode:\n");
|
||||
rc_print_program(&c->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
debug_program_log(c, "after deadcode");
|
||||
|
||||
rc_dataflow_swizzles(&c->Base);
|
||||
if (c->Base.Error)
|
||||
return;
|
||||
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Compiler: after dataflow passes:\n");
|
||||
rc_print_program(&c->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
debug_program_log(c, "after dataflow passes");
|
||||
|
||||
rc_pair_translate(c);
|
||||
if (c->Base.Error)
|
||||
return;
|
||||
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Compiler: after pair translate:\n");
|
||||
rc_print_program(&c->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
debug_program_log(c, "after pair translate");
|
||||
|
||||
rc_pair_schedule(c);
|
||||
if (c->Base.Error)
|
||||
return;
|
||||
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Compiler: after pair scheduling:\n");
|
||||
rc_print_program(&c->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
debug_program_log(c, "after pair scheduling");
|
||||
|
||||
rc_pair_regalloc(c, c->max_temp_regs);
|
||||
|
||||
if (c->Base.Error)
|
||||
return;
|
||||
|
||||
if (c->Base.Debug) {
|
||||
fprintf(stderr, "Compiler: after pair register allocation:\n");
|
||||
rc_print_program(&c->Base.Program);
|
||||
fflush(stderr);
|
||||
}
|
||||
debug_program_log(c, "after register allocation");
|
||||
|
||||
if (c->is_r500) {
|
||||
r500BuildFragmentProgramHwCode(c);
|
||||
|
||||
@@ -160,3 +160,92 @@ void rc_for_all_writes(struct rc_instruction * inst, rc_read_write_fn cb, void *
|
||||
writes_pair(inst, cb, userdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void remap_normal_instruction(struct rc_instruction * fullinst,
|
||||
rc_remap_register_fn cb, void * userdata)
|
||||
{
|
||||
struct rc_sub_instruction * inst = &fullinst->U.I;
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
|
||||
|
||||
if (opcode->HasDstReg) {
|
||||
rc_register_file file = inst->DstReg.File;
|
||||
unsigned int index = inst->DstReg.Index;
|
||||
|
||||
cb(userdata, fullinst, &file, &index);
|
||||
|
||||
inst->DstReg.File = file;
|
||||
inst->DstReg.Index = index;
|
||||
}
|
||||
|
||||
for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
|
||||
rc_register_file file = inst->SrcReg[src].File;
|
||||
unsigned int index = inst->SrcReg[src].Index;
|
||||
|
||||
cb(userdata, fullinst, &file, &index);
|
||||
|
||||
inst->SrcReg[src].File = file;
|
||||
inst->SrcReg[src].Index = index;
|
||||
}
|
||||
}
|
||||
|
||||
static void remap_pair_instruction(struct rc_instruction * fullinst,
|
||||
rc_remap_register_fn cb, void * userdata)
|
||||
{
|
||||
struct rc_pair_instruction * inst = &fullinst->U.P;
|
||||
|
||||
if (inst->RGB.WriteMask) {
|
||||
rc_register_file file = RC_FILE_TEMPORARY;
|
||||
unsigned int index = inst->RGB.DestIndex;
|
||||
|
||||
cb(userdata, fullinst, &file, &index);
|
||||
|
||||
inst->RGB.DestIndex = index;
|
||||
}
|
||||
|
||||
if (inst->Alpha.WriteMask) {
|
||||
rc_register_file file = RC_FILE_TEMPORARY;
|
||||
unsigned int index = inst->Alpha.DestIndex;
|
||||
|
||||
cb(userdata, fullinst, &file, &index);
|
||||
|
||||
inst->Alpha.DestIndex = index;
|
||||
}
|
||||
|
||||
for(unsigned int src = 0; src < 3; ++src) {
|
||||
if (inst->RGB.Src[src].Used) {
|
||||
rc_register_file file = inst->RGB.Src[src].File;
|
||||
unsigned int index = inst->RGB.Src[src].Index;
|
||||
|
||||
cb(userdata, fullinst, &file, &index);
|
||||
|
||||
inst->RGB.Src[src].File = file;
|
||||
inst->RGB.Src[src].Index = index;
|
||||
}
|
||||
|
||||
if (inst->Alpha.Src[src].Used) {
|
||||
rc_register_file file = inst->Alpha.Src[src].File;
|
||||
unsigned int index = inst->Alpha.Src[src].Index;
|
||||
|
||||
cb(userdata, fullinst, &file, &index);
|
||||
|
||||
inst->Alpha.Src[src].File = file;
|
||||
inst->Alpha.Src[src].Index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remap all register accesses according to the given function.
|
||||
* That is, call the function \p cb for each referenced register (both read and written)
|
||||
* and update the given instruction \p inst accordingly
|
||||
* if it modifies its \ref pfile and \ref pindex contents.
|
||||
*/
|
||||
void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata)
|
||||
{
|
||||
if (inst->Type == RC_INSTRUCTION_NORMAL)
|
||||
remap_normal_instruction(inst, cb, userdata);
|
||||
else
|
||||
remap_pair_instruction(inst, cb, userdata);
|
||||
}
|
||||
|
||||
@@ -36,13 +36,17 @@ struct rc_swizzle_caps;
|
||||
|
||||
|
||||
/**
|
||||
* Help analyze the register accesses of instructions.
|
||||
* Help analyze and modify the register accesses of instructions.
|
||||
*/
|
||||
/*@{*/
|
||||
typedef void (*rc_read_write_fn)(void * userdata, struct rc_instruction * inst,
|
||||
rc_register_file file, unsigned int index, unsigned int chan);
|
||||
void rc_for_all_reads(struct rc_instruction * inst, rc_read_write_fn cb, void * userdata);
|
||||
void rc_for_all_writes(struct rc_instruction * inst, rc_read_write_fn cb, void * userdata);
|
||||
|
||||
typedef void (*rc_remap_register_fn)(void * userdata, struct rc_instruction * inst,
|
||||
rc_register_file * pfile, unsigned int * pindex);
|
||||
void rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata);
|
||||
/*@}*/
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
|
||||
*
|
||||
* 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
|
||||
* on the rights to use, copy, modify, merge, publish, distribute, sub
|
||||
* license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHOR(S) AND/OR THEIR 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_emulate_branches.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "radeon_compiler.h"
|
||||
#include "radeon_dataflow.h"
|
||||
|
||||
#define VERBOSE 0
|
||||
|
||||
#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0)
|
||||
|
||||
|
||||
struct proxy_info {
|
||||
unsigned int Proxied:1;
|
||||
unsigned int Index:RC_REGISTER_INDEX_BITS;
|
||||
};
|
||||
|
||||
struct register_proxies {
|
||||
struct proxy_info Temporary[RC_REGISTER_MAX_INDEX];
|
||||
};
|
||||
|
||||
struct branch_info {
|
||||
struct rc_instruction * If;
|
||||
struct rc_instruction * Else;
|
||||
};
|
||||
|
||||
struct emulate_branch_state {
|
||||
struct radeon_compiler * C;
|
||||
|
||||
struct branch_info * Branches;
|
||||
unsigned int BranchCount;
|
||||
unsigned int BranchReserved;
|
||||
};
|
||||
|
||||
|
||||
static void handle_if(struct emulate_branch_state * s, struct rc_instruction * inst)
|
||||
{
|
||||
memory_pool_array_reserve(&s->C->Pool, struct branch_info,
|
||||
s->Branches, s->BranchCount, s->BranchReserved, 1);
|
||||
|
||||
DBG("%s\n", __FUNCTION__);
|
||||
|
||||
struct branch_info * branch = &s->Branches[s->BranchCount++];
|
||||
memset(branch, 0, sizeof(struct branch_info));
|
||||
branch->If = inst;
|
||||
|
||||
/* Make a safety copy of the decision register, because we will need
|
||||
* it at ENDIF time and it might be overwritten in both branches. */
|
||||
struct rc_instruction * inst_mov = rc_insert_new_instruction(s->C, inst->Prev);
|
||||
inst_mov->U.I.Opcode = RC_OPCODE_MOV;
|
||||
inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
|
||||
inst_mov->U.I.DstReg.Index = rc_find_free_temporary(s->C);
|
||||
inst_mov->U.I.DstReg.WriteMask = RC_MASK_X;
|
||||
inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
|
||||
|
||||
inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
|
||||
inst->U.I.SrcReg[0].Index = inst_mov->U.I.DstReg.Index;
|
||||
inst->U.I.SrcReg[0].Swizzle = 0;
|
||||
inst->U.I.SrcReg[0].Abs = 0;
|
||||
inst->U.I.SrcReg[0].Negate = 0;
|
||||
}
|
||||
|
||||
static void handle_else(struct emulate_branch_state * s, struct rc_instruction * inst)
|
||||
{
|
||||
if (!s->BranchCount) {
|
||||
rc_error(s->C, "Encountered ELSE outside of branches");
|
||||
return;
|
||||
}
|
||||
|
||||
DBG("%s\n", __FUNCTION__);
|
||||
|
||||
struct branch_info * branch = &s->Branches[s->BranchCount - 1];
|
||||
branch->Else = inst;
|
||||
}
|
||||
|
||||
|
||||
struct state_and_proxies {
|
||||
struct emulate_branch_state * S;
|
||||
struct register_proxies * Proxies;
|
||||
};
|
||||
|
||||
static struct proxy_info * get_proxy_info(struct state_and_proxies * sap,
|
||||
rc_register_file file, unsigned int index)
|
||||
{
|
||||
if (file == RC_FILE_TEMPORARY) {
|
||||
return &sap->Proxies->Temporary[index];
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void scan_write(void * userdata, struct rc_instruction * inst,
|
||||
rc_register_file file, unsigned int index, unsigned int comp)
|
||||
{
|
||||
struct state_and_proxies * sap = userdata;
|
||||
struct proxy_info * proxy = get_proxy_info(sap, file, index);
|
||||
|
||||
if (proxy && !proxy->Proxied) {
|
||||
proxy->Proxied = 1;
|
||||
proxy->Index = rc_find_free_temporary(sap->S->C);
|
||||
}
|
||||
}
|
||||
|
||||
static void remap_proxy_function(void * userdata, struct rc_instruction * inst,
|
||||
rc_register_file * pfile, unsigned int * pindex)
|
||||
{
|
||||
struct state_and_proxies * sap = userdata;
|
||||
struct proxy_info * proxy = get_proxy_info(sap, *pfile, *pindex);
|
||||
|
||||
if (proxy && proxy->Proxied) {
|
||||
*pfile = RC_FILE_TEMPORARY;
|
||||
*pindex = proxy->Index;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect all writes in the instruction range [begin, end) to proxy
|
||||
* temporary registers.
|
||||
*/
|
||||
static void allocate_and_insert_proxies(struct emulate_branch_state * s,
|
||||
struct register_proxies * proxies,
|
||||
struct rc_instruction * begin,
|
||||
struct rc_instruction * end)
|
||||
{
|
||||
struct state_and_proxies sap;
|
||||
|
||||
sap.S = s;
|
||||
sap.Proxies = proxies;
|
||||
|
||||
for(struct rc_instruction * inst = begin; inst != end; inst = inst->Next) {
|
||||
rc_for_all_writes(inst, scan_write, &sap);
|
||||
rc_remap_registers(inst, remap_proxy_function, &sap);
|
||||
}
|
||||
|
||||
for(unsigned int index = 0; index < RC_REGISTER_MAX_INDEX; ++index) {
|
||||
if (proxies->Temporary[index].Proxied) {
|
||||
struct rc_instruction * inst_mov = rc_insert_new_instruction(s->C, begin->Prev);
|
||||
inst_mov->U.I.Opcode = RC_OPCODE_MOV;
|
||||
inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
|
||||
inst_mov->U.I.DstReg.Index = proxies->Temporary[index].Index;
|
||||
inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZW;
|
||||
inst_mov->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
|
||||
inst_mov->U.I.SrcReg[0].Index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void inject_cmp(struct emulate_branch_state * s,
|
||||
struct rc_instruction * inst_if,
|
||||
struct rc_instruction * inst_endif,
|
||||
rc_register_file file, unsigned int index,
|
||||
struct proxy_info ifproxy,
|
||||
struct proxy_info elseproxy)
|
||||
{
|
||||
struct rc_instruction * inst_cmp = rc_insert_new_instruction(s->C, inst_endif);
|
||||
inst_cmp->U.I.Opcode = RC_OPCODE_CMP;
|
||||
inst_cmp->U.I.DstReg.File = file;
|
||||
inst_cmp->U.I.DstReg.Index = index;
|
||||
inst_cmp->U.I.DstReg.WriteMask = RC_MASK_XYZW;
|
||||
inst_cmp->U.I.SrcReg[0] = inst_if->U.I.SrcReg[0];
|
||||
inst_cmp->U.I.SrcReg[0].Abs = 1;
|
||||
inst_cmp->U.I.SrcReg[0].Negate = RC_MASK_XYZW;
|
||||
inst_cmp->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
|
||||
inst_cmp->U.I.SrcReg[1].Index = ifproxy.Proxied ? ifproxy.Index : index;
|
||||
inst_cmp->U.I.SrcReg[2].File = RC_FILE_TEMPORARY;
|
||||
inst_cmp->U.I.SrcReg[2].Index = elseproxy.Proxied ? elseproxy.Index : index;
|
||||
}
|
||||
|
||||
static void handle_endif(struct emulate_branch_state * s, struct rc_instruction * inst)
|
||||
{
|
||||
if (!s->BranchCount) {
|
||||
rc_error(s->C, "Encountered ENDIF outside of branches");
|
||||
return;
|
||||
}
|
||||
|
||||
DBG("%s\n", __FUNCTION__);
|
||||
|
||||
struct branch_info * branch = &s->Branches[s->BranchCount - 1];
|
||||
struct register_proxies IfProxies;
|
||||
struct register_proxies ElseProxies;
|
||||
|
||||
memset(&IfProxies, 0, sizeof(IfProxies));
|
||||
memset(&ElseProxies, 0, sizeof(ElseProxies));
|
||||
|
||||
allocate_and_insert_proxies(s, &IfProxies, branch->If->Next, branch->Else ? branch->Else : inst);
|
||||
|
||||
if (branch->Else)
|
||||
allocate_and_insert_proxies(s, &ElseProxies, branch->Else->Next, inst);
|
||||
|
||||
/* Insert the CMP instructions at the end. */
|
||||
for(unsigned int index = 0; index < RC_REGISTER_MAX_INDEX; ++index) {
|
||||
if (IfProxies.Temporary[index].Proxied || ElseProxies.Temporary[index].Proxied) {
|
||||
inject_cmp(s, branch->If, inst, RC_FILE_TEMPORARY, index,
|
||||
IfProxies.Temporary[index], ElseProxies.Temporary[index]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove all traces of the branch instructions */
|
||||
rc_remove_instruction(branch->If);
|
||||
if (branch->Else)
|
||||
rc_remove_instruction(branch->Else);
|
||||
rc_remove_instruction(inst);
|
||||
|
||||
s->BranchCount--;
|
||||
|
||||
if (VERBOSE) {
|
||||
DBG("Program after ENDIF handling:\n");
|
||||
rc_print_program(&s->C->Program);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct remap_output_data {
|
||||
unsigned int Output:RC_REGISTER_INDEX_BITS;
|
||||
unsigned int Temporary:RC_REGISTER_INDEX_BITS;
|
||||
};
|
||||
|
||||
static void remap_output_function(void * userdata, struct rc_instruction * inst,
|
||||
rc_register_file * pfile, unsigned int * pindex)
|
||||
{
|
||||
struct remap_output_data * data = userdata;
|
||||
|
||||
if (*pfile == RC_FILE_OUTPUT && *pindex == data->Output) {
|
||||
*pfile = RC_FILE_TEMPORARY;
|
||||
*pindex = data->Temporary;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Output registers cannot be read from and so cannot be dealt with like
|
||||
* temporary registers.
|
||||
*
|
||||
* We do the simplest thing: If an output registers is written within
|
||||
* a branch, then *all* writes to this register are proxied to a
|
||||
* temporary register, and a final MOV is appended to the end of
|
||||
* the program.
|
||||
*/
|
||||
static void fix_output_writes(struct emulate_branch_state * s, struct rc_instruction * inst)
|
||||
{
|
||||
if (!s->BranchCount)
|
||||
return;
|
||||
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
|
||||
|
||||
if (!opcode->HasDstReg)
|
||||
return;
|
||||
|
||||
if (inst->U.I.DstReg.File == RC_FILE_OUTPUT) {
|
||||
struct remap_output_data remap;
|
||||
|
||||
remap.Output = inst->U.I.DstReg.Index;
|
||||
remap.Temporary = rc_find_free_temporary(s->C);
|
||||
|
||||
for(struct rc_instruction * inst = s->C->Program.Instructions.Next;
|
||||
inst != &s->C->Program.Instructions;
|
||||
inst = inst->Next) {
|
||||
rc_remap_registers(inst, &remap_output_function, &remap);
|
||||
}
|
||||
|
||||
struct rc_instruction * inst_mov = rc_insert_new_instruction(s->C, s->C->Program.Instructions.Prev);
|
||||
inst_mov->U.I.Opcode = RC_OPCODE_MOV;
|
||||
inst_mov->U.I.DstReg.File = RC_FILE_OUTPUT;
|
||||
inst_mov->U.I.DstReg.Index = remap.Output;
|
||||
inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZW;
|
||||
inst_mov->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
|
||||
inst_mov->U.I.SrcReg[0].Index = remap.Temporary;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove branch instructions; instead, execute both branches
|
||||
* on different register sets and choose between their results
|
||||
* using CMP instructions in place of the original ENDIF.
|
||||
*/
|
||||
void rc_emulate_branches(struct radeon_compiler * c)
|
||||
{
|
||||
struct emulate_branch_state s;
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.C = c;
|
||||
|
||||
/* Untypical loop because we may remove the current instruction */
|
||||
struct rc_instruction * ptr = c->Program.Instructions.Next;
|
||||
while(ptr != &c->Program.Instructions) {
|
||||
struct rc_instruction * inst = ptr;
|
||||
ptr = ptr->Next;
|
||||
|
||||
if (inst->Type == RC_INSTRUCTION_NORMAL) {
|
||||
switch(inst->U.I.Opcode) {
|
||||
case RC_OPCODE_IF:
|
||||
handle_if(&s, inst);
|
||||
break;
|
||||
case RC_OPCODE_ELSE:
|
||||
handle_else(&s, inst);
|
||||
break;
|
||||
case RC_OPCODE_ENDIF:
|
||||
handle_endif(&s, inst);
|
||||
break;
|
||||
default:
|
||||
fix_output_writes(&s, inst);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
rc_error(c, "%s: unhandled instruction type\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
|
||||
*
|
||||
* 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
|
||||
* on the rights to use, copy, modify, merge, publish, distribute, sub
|
||||
* license, 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 NON-INFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHOR(S) AND/OR THEIR 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. */
|
||||
|
||||
#ifndef RADEON_EMULATE_BRANCHES_H
|
||||
#define RADEON_EMULATE_BRANCHES_H
|
||||
|
||||
struct radeon_compiler;
|
||||
|
||||
void rc_emulate_branches(struct radeon_compiler * c);
|
||||
|
||||
#endif /* RADEON_EMULATE_BRANCHES_H */
|
||||
@@ -196,9 +196,10 @@ static void compute_live_intervals(struct regalloc_state * s)
|
||||
}
|
||||
}
|
||||
|
||||
static void rewrite_register(struct regalloc_state * s,
|
||||
static void remap_register(void * data, struct rc_instruction * inst,
|
||||
rc_register_file * file, unsigned int * index)
|
||||
{
|
||||
struct regalloc_state * s = data;
|
||||
const struct register_info * reg;
|
||||
|
||||
if (*file == RC_FILE_TEMPORARY)
|
||||
@@ -214,74 +215,6 @@ static void rewrite_register(struct regalloc_state * s,
|
||||
}
|
||||
}
|
||||
|
||||
static void rewrite_normal_instruction(struct regalloc_state * s, struct rc_sub_instruction * inst)
|
||||
{
|
||||
const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
|
||||
|
||||
if (opcode->HasDstReg) {
|
||||
rc_register_file file = inst->DstReg.File;
|
||||
unsigned int index = inst->DstReg.Index;
|
||||
|
||||
rewrite_register(s, &file, &index);
|
||||
|
||||
inst->DstReg.File = file;
|
||||
inst->DstReg.Index = index;
|
||||
}
|
||||
|
||||
for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
|
||||
rc_register_file file = inst->SrcReg[src].File;
|
||||
unsigned int index = inst->SrcReg[src].Index;
|
||||
|
||||
rewrite_register(s, &file, &index);
|
||||
|
||||
inst->SrcReg[src].File = file;
|
||||
inst->SrcReg[src].Index = index;
|
||||
}
|
||||
}
|
||||
|
||||
static void rewrite_pair_instruction(struct regalloc_state * s, struct rc_pair_instruction * inst)
|
||||
{
|
||||
if (inst->RGB.WriteMask) {
|
||||
rc_register_file file = RC_FILE_TEMPORARY;
|
||||
unsigned int index = inst->RGB.DestIndex;
|
||||
|
||||
rewrite_register(s, &file, &index);
|
||||
|
||||
inst->RGB.DestIndex = index;
|
||||
}
|
||||
|
||||
if (inst->Alpha.WriteMask) {
|
||||
rc_register_file file = RC_FILE_TEMPORARY;
|
||||
unsigned int index = inst->Alpha.DestIndex;
|
||||
|
||||
rewrite_register(s, &file, &index);
|
||||
|
||||
inst->Alpha.DestIndex = index;
|
||||
}
|
||||
|
||||
for(unsigned int src = 0; src < 3; ++src) {
|
||||
if (inst->RGB.Src[src].Used) {
|
||||
rc_register_file file = inst->RGB.Src[src].File;
|
||||
unsigned int index = inst->RGB.Src[src].Index;
|
||||
|
||||
rewrite_register(s, &file, &index);
|
||||
|
||||
inst->RGB.Src[src].File = file;
|
||||
inst->RGB.Src[src].Index = index;
|
||||
}
|
||||
|
||||
if (inst->Alpha.Src[src].Used) {
|
||||
rc_register_file file = inst->Alpha.Src[src].File;
|
||||
unsigned int index = inst->Alpha.Src[src].Index;
|
||||
|
||||
rewrite_register(s, &file, &index);
|
||||
|
||||
inst->Alpha.Src[src].File = file;
|
||||
inst->Alpha.Src[src].Index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_regalloc(struct regalloc_state * s)
|
||||
{
|
||||
/* Simple and stupid greedy register allocation */
|
||||
@@ -310,10 +243,7 @@ static void do_regalloc(struct regalloc_state * s)
|
||||
for(struct rc_instruction * inst = s->C->Program.Instructions.Next;
|
||||
inst != &s->C->Program.Instructions;
|
||||
inst = inst->Next) {
|
||||
if (inst->Type == RC_INSTRUCTION_NORMAL)
|
||||
rewrite_normal_instruction(s, &inst->U.I);
|
||||
else
|
||||
rewrite_pair_instruction(s, &inst->U.P);
|
||||
rc_remap_registers(inst, &remap_register, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user