diff options
| author | Nicolai Hähnle <nhaehnle@gmail.com> | 2009-10-11 14:18:11 +0200 | 
|---|---|---|
| committer | Marek Olšák <maraeo@gmail.com> | 2010-04-19 00:34:02 +0200 | 
| commit | 4d7ed844313a4be64e9162369c935ce750cd9b06 (patch) | |
| tree | f6529de79e3ccd5768c0a20849f4fec7b4edd694 | |
| parent | eeabe9d1797765056dcf0ca70ad5fc11b3aa758d (diff) | |
r300/compiler: Implement branch emulation for R300 fragment programs
Signed-off-by: Nicolai Hähnle <nhaehnle@gmail.com>
8 files changed, 512 insertions, 104 deletions
| diff --git a/src/mesa/drivers/dri/r300/compiler/Makefile b/src/mesa/drivers/dri/r300/compiler/Makefile index c8acd3a333..e432afc3d4 100644 --- a/src/mesa/drivers/dri/r300/compiler/Makefile +++ b/src/mesa/drivers/dri/r300/compiler/Makefile @@ -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 \ diff --git a/src/mesa/drivers/dri/r300/compiler/memory_pool.h b/src/mesa/drivers/dri/r300/compiler/memory_pool.h index ce23c319ad..42344d0e3b 100644 --- a/src/mesa/drivers/dri/r300/compiler/memory_pool.h +++ b/src/mesa/drivers/dri/r300/compiler/memory_pool.h @@ -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 */ diff --git a/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c b/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c index 5fe10dbfe8..1e1053483d 100644 --- a/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c +++ b/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c @@ -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); diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.c b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.c index cce9166e64..16e2f3a218 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.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); +} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.h b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.h index 5aa4cb64f3..62cda20eea 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.h +++ b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow.h @@ -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);  /*@}*/ diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_emulate_branches.c b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_branches.c new file mode 100644 index 0000000000..d889612f4f --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_branches.c @@ -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__); +		} +	} +} diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_emulate_branches.h b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_branches.h new file mode 100644 index 0000000000..e07279f093 --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_branches.h @@ -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 */ diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c b/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c index b2fe7f76b2..fdfee86701 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c @@ -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);  	}  } | 
