Mesa (master): Revert "r300/compiler: Remove obsolete compiler passes"

Tom Stellard tstellar at kemper.freedesktop.org
Sun Apr 3 06:24:31 UTC 2011


Module: Mesa
Branch: master
Commit: 381d32af74e305041b5e75930a32795db94e0e15
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=381d32af74e305041b5e75930a32795db94e0e15

Author: Tom Stellard <tstellar at gmail.com>
Date:   Sat Apr  2 23:14:12 2011 -0700

Revert "r300/compiler: Remove obsolete compiler passes"

This reverts commit 9f013a8233197d4a0482661cb37cfeac1a61b804.

These passes are still need for non-GLSL paths like g3dvl and ARB
programs.

---

 src/mesa/drivers/dri/r300/compiler/Makefile        |    1 +
 src/mesa/drivers/dri/r300/compiler/SConscript      |    1 +
 src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c |    5 +
 src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c |    2 +
 .../dri/r300/compiler/radeon_emulate_branches.c    |  342 ++++++++++++++++++++
 .../dri/r300/compiler/radeon_emulate_branches.h    |   30 ++
 .../dri/r300/compiler/radeon_emulate_loops.c       |   34 ++
 7 files changed, 415 insertions(+), 0 deletions(-)

diff --git a/src/mesa/drivers/dri/r300/compiler/Makefile b/src/mesa/drivers/dri/r300/compiler/Makefile
index 12e5c2e..51b896a 100644
--- a/src/mesa/drivers/dri/r300/compiler/Makefile
+++ b/src/mesa/drivers/dri/r300/compiler/Makefile
@@ -9,6 +9,7 @@ C_SOURCES = \
 		radeon_code.c \
 		radeon_compiler.c \
 		radeon_compiler_util.c \
+		radeon_emulate_branches.c \
 		radeon_emulate_loops.c \
 		radeon_program.c \
 		radeon_program_print.c \
diff --git a/src/mesa/drivers/dri/r300/compiler/SConscript b/src/mesa/drivers/dri/r300/compiler/SConscript
index f1a4837..2b4bce1 100755
--- a/src/mesa/drivers/dri/r300/compiler/SConscript
+++ b/src/mesa/drivers/dri/r300/compiler/SConscript
@@ -25,6 +25,7 @@ r300compiler = env.ConvenienceLibrary(
         'radeon_optimize.c',
         'radeon_remove_constants.c',
         'radeon_rename_regs.c',
+        'radeon_emulate_branches.c',
         'radeon_emulate_loops.c',
         'radeon_dataflow.c',
         'radeon_dataflow_deadcode.c',
diff --git a/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c b/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c
index 005a150..9286733 100644
--- a/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c
+++ b/src/mesa/drivers/dri/r300/compiler/r3xx_fragprog.c
@@ -26,6 +26,7 @@
 
 #include "radeon_compiler_util.h"
 #include "radeon_dataflow.h"
+#include "radeon_emulate_branches.h"
 #include "radeon_emulate_loops.h"
 #include "radeon_program_alu.h"
 #include "radeon_program_tex.h"
@@ -129,11 +130,15 @@ void r3xx_compile_fragment_program(struct r300_fragment_program_compiler* c)
 		/* This transformation needs to be done before any of the IF
 		 * instructions are modified. */
 		{"transform KILP",		1, 1,		rc_transform_KILP,		NULL},
+		{"unroll loops",		1, is_r500,	rc_unroll_loops,		NULL},
+		{"transform loops",		1, !is_r500,	rc_transform_loops,		NULL},
+		{"emulate branches",		1, !is_r500,	rc_emulate_branches,		NULL},
 		{"saturate output writes",	1, sat_out,	rc_local_transform,		saturate_output},
 		{"transform TEX",		1, 1,		rc_local_transform,		rewrite_tex},
 		{"native rewrite",		1, is_r500,	rc_local_transform,		native_rewrite_r500},
 		{"native rewrite",		1, !is_r500,	rc_local_transform,		native_rewrite_r300},
 		{"deadcode",			1, opt,		rc_dataflow_deadcode,		dataflow_outputs_mark_use},
+		{"emulate loops",		1, !is_r500,	rc_emulate_loops,		NULL},
 		{"dataflow optimize",		1, opt,		rc_optimize,			NULL},
 		{"dataflow swizzles",		1, 1,		rc_dataflow_swizzles,		NULL},
 		{"dead constants",		1, 1,		rc_remove_unused_constants,	&c->code->constants_remap_table},
diff --git a/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c b/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c
index 76cbdb0..8ad2175 100644
--- a/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c
+++ b/src/mesa/drivers/dri/r300/compiler/r3xx_vertprog.c
@@ -30,6 +30,7 @@
 #include "radeon_dataflow.h"
 #include "radeon_program_alu.h"
 #include "radeon_swizzle.h"
+#include "radeon_emulate_branches.h"
 #include "radeon_emulate_loops.h"
 #include "radeon_remove_constants.h"
 
@@ -998,6 +999,7 @@ void r3xx_compile_vertex_program(struct r300_vertex_program_compiler *c)
 		/* NAME				DUMP PREDICATE	FUNCTION			PARAM */
 		{"add artificial outputs",	0, 1,		rc_vs_add_artificial_outputs,	NULL},
 		{"transform loops",		1, 1,		rc_transform_loops,		NULL},
+		{"emulate branches",		1, !is_r500,	rc_emulate_branches,		NULL},
 		{"emulate negative addressing", 1, 1,		rc_emulate_negative_addressing,	NULL},
 		{"native rewrite",		1, is_r500,	rc_local_transform,		alu_rewrite_r500},
 		{"native rewrite",		1, !is_r500,	rc_local_transform,		alu_rewrite_r300},
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 0000000..7bede34
--- /dev/null
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_branches.c
@@ -0,0 +1,342 @@
+/*
+ * Copyright 2009 Nicolai Hähnle <nhaehnle at 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)
+{
+	struct branch_info * branch;
+	struct rc_instruction * inst_mov;
+
+	memory_pool_array_reserve(&s->C->Pool, struct branch_info,
+			s->Branches, s->BranchCount, s->BranchReserved, 1);
+
+	DBG("%s\n", __FUNCTION__);
+
+	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. */
+	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)
+{
+	struct branch_info * branch;
+
+	if (!s->BranchCount) {
+		rc_error(s->C, "Encountered ELSE outside of branches");
+		return;
+	}
+
+	DBG("%s\n", __FUNCTION__);
+
+	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_mask(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)
+{
+	struct branch_info * branch;
+	struct register_proxies IfProxies;
+	struct register_proxies ElseProxies;
+
+	if (!s->BranchCount) {
+		rc_error(s->C, "Encountered ENDIF outside of branches");
+		return;
+	}
+
+	DBG("%s\n", __FUNCTION__);
+
+	branch = &s->Branches[s->BranchCount - 1];
+
+	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)
+{
+	const struct rc_opcode_info * opcode;
+
+	if (!s->BranchCount)
+		return;
+
+	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;
+		struct rc_instruction * inst_mov;
+
+		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);
+		}
+
+		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, void *user)
+{
+	struct emulate_branch_state s;
+	struct rc_instruction * ptr;
+
+	memset(&s, 0, sizeof(s));
+	s.C = c;
+
+	/* Untypical loop because we may remove the current 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 0000000..818ab84
--- /dev/null
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_branches.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2009 Nicolai Hähnle <nhaehnle at 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, void *user);
+
+#endif /* RADEON_EMULATE_BRANCHES_H */
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_emulate_loops.c b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_loops.c
index 049a819..205eecd 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_emulate_loops.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_loops.c
@@ -486,3 +486,37 @@ void rc_transform_loops(struct radeon_compiler *c, void *user)
 		}
 	}
 }
+
+void rc_unroll_loops(struct radeon_compiler *c, void *user)
+{
+	struct rc_instruction * inst;
+	struct loop_info loop;
+
+	for(inst = c->Program.Instructions.Next;
+			inst != &c->Program.Instructions; inst = inst->Next) {
+
+		if (inst->U.I.Opcode == RC_OPCODE_BGNLOOP) {
+			if (build_loop_info(c, &loop, inst)) {
+				try_unroll_loop(c, &loop);
+			}
+		}
+	}
+}
+
+void rc_emulate_loops(struct radeon_compiler *c, void *user)
+{
+	struct emulate_loop_state * s = &c->loop_state;
+	int i;
+	/* Iterate backwards of the list of loops so that loops that nested
+	 * loops are unrolled first.
+	 */
+	for( i = s->LoopCount - 1; i >= 0; i-- ){
+		unsigned int iterations;
+
+		if(!s->Loops[i].EndLoop){
+			continue;
+		}
+		iterations = loop_max_possible_iterations(s->C, &s->Loops[i]);
+		unroll_loop(s->C, &s->Loops[i], iterations);
+	}
+}




More information about the mesa-commit mailing list