diff options
Diffstat (limited to 'src/mesa/drivers/dri/r300/compiler/radeon_dataflow_dealias.c')
-rw-r--r-- | src/mesa/drivers/dri/r300/compiler/radeon_dataflow_dealias.c | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_dealias.c b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_dealias.c new file mode 100644 index 0000000000..4596636970 --- /dev/null +++ b/src/mesa/drivers/dri/r300/compiler/radeon_dataflow_dealias.c @@ -0,0 +1,150 @@ +/* + * 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); + } +} |