11c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/*
21c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
31c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
41c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * Permission is hereby granted, free of charge, to any person obtaining a
51c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * copy of this software and associated documentation files (the "Software"),
61c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * to deal in the Software without restriction, including without limitation
71c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * on the rights to use, copy, modify, merge, publish, distribute, sub
81c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * license, and/or sell copies of the Software, and to permit persons to whom
91c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * the Software is furnished to do so, subject to the following conditions:
101c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
111c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * The above copyright notice and this permission notice (including the next
121c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * paragraph) shall be included in all copies or substantial portions of the
131c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * Software.
141c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
151c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
181c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
191c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
201c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
211c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * USE OR OTHER DEALINGS IN THE SOFTWARE. */
221c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
231c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#include "radeon_emulate_branches.h"
241c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
251c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#include <stdio.h>
261c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
271c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#include "radeon_compiler.h"
281c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#include "radeon_dataflow.h"
291c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
301c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define VERBOSE 0
311c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
321c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák#define DBG(...) do { if (VERBOSE) fprintf(stderr, __VA_ARGS__); } while(0)
331c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
341c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
351c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstruct proxy_info {
361c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	unsigned int Proxied:1;
371c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	unsigned int Index:RC_REGISTER_INDEX_BITS;
381c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák};
391c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
401c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstruct register_proxies {
411c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct proxy_info Temporary[RC_REGISTER_MAX_INDEX];
421c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák};
431c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
441c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstruct branch_info {
451c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct rc_instruction * If;
461c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct rc_instruction * Else;
471c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák};
481c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
491c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstruct emulate_branch_state {
501c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct radeon_compiler * C;
511c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
521c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct branch_info * Branches;
531c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	unsigned int BranchCount;
541c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	unsigned int BranchReserved;
551c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák};
561c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
571c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
581c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic void handle_if(struct emulate_branch_state * s, struct rc_instruction * inst)
591c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
601c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct branch_info * branch;
611c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct rc_instruction * inst_mov;
621c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
631c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	memory_pool_array_reserve(&s->C->Pool, struct branch_info,
641c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			s->Branches, s->BranchCount, s->BranchReserved, 1);
651c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
661c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	DBG("%s\n", __FUNCTION__);
671c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
681c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	branch = &s->Branches[s->BranchCount++];
691c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	memset(branch, 0, sizeof(struct branch_info));
701c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	branch->If = inst;
711c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
721c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	/* Make a safety copy of the decision register, because we will need
731c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	 * it at ENDIF time and it might be overwritten in both branches. */
741c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_mov = rc_insert_new_instruction(s->C, inst->Prev);
751c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_mov->U.I.Opcode = RC_OPCODE_MOV;
761c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
771c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_mov->U.I.DstReg.Index = rc_find_free_temporary(s->C);
781c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_mov->U.I.DstReg.WriteMask = RC_MASK_X;
791c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_mov->U.I.SrcReg[0] = inst->U.I.SrcReg[0];
801c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
811c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
821c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst->U.I.SrcReg[0].Index = inst_mov->U.I.DstReg.Index;
831c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst->U.I.SrcReg[0].Swizzle = 0;
841c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst->U.I.SrcReg[0].Abs = 0;
851c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst->U.I.SrcReg[0].Negate = 0;
861c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
871c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
881c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic void handle_else(struct emulate_branch_state * s, struct rc_instruction * inst)
891c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
901c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct branch_info * branch;
911c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
921c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (!s->BranchCount) {
931c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_error(s->C, "Encountered ELSE outside of branches");
941c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		return;
951c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
961c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
971c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	DBG("%s\n", __FUNCTION__);
981c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
991c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	branch = &s->Branches[s->BranchCount - 1];
1001c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	branch->Else = inst;
1011c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
1021c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1031c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1041c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstruct state_and_proxies {
1051c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct emulate_branch_state * S;
1061c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct register_proxies * Proxies;
1071c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák};
1081c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1091c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic struct proxy_info * get_proxy_info(struct state_and_proxies * sap,
1101c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			rc_register_file file, unsigned int index)
1111c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
1121c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (file == RC_FILE_TEMPORARY) {
1131c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		return &sap->Proxies->Temporary[index];
1141c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	} else {
1151c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		return 0;
1161c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
1171c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
1181c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1191c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic void scan_write(void * userdata, struct rc_instruction * inst,
1201c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_register_file file, unsigned int index, unsigned int comp)
1211c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
1221c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct state_and_proxies * sap = userdata;
1231c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct proxy_info * proxy = get_proxy_info(sap, file, index);
1241c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1251c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (proxy && !proxy->Proxied) {
1261c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		proxy->Proxied = 1;
1271c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		proxy->Index = rc_find_free_temporary(sap->S->C);
1281c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
1291c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
1301c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1311c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic void remap_proxy_function(void * userdata, struct rc_instruction * inst,
1321c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_register_file * pfile, unsigned int * pindex)
1331c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
1341c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct state_and_proxies * sap = userdata;
1351c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct proxy_info * proxy = get_proxy_info(sap, *pfile, *pindex);
1361c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1371c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (proxy && proxy->Proxied) {
1381c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		*pfile = RC_FILE_TEMPORARY;
1391c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		*pindex = proxy->Index;
1401c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
1411c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
1421c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1431c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/**
1441c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * Redirect all writes in the instruction range [begin, end) to proxy
1451c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * temporary registers.
1461c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák */
1471c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic void allocate_and_insert_proxies(struct emulate_branch_state * s,
1481c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct register_proxies * proxies,
1491c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct rc_instruction * begin,
1501c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct rc_instruction * end)
1511c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
1521c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct state_and_proxies sap;
1531c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1541c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	sap.S = s;
1551c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	sap.Proxies = proxies;
1561c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1571c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	for(struct rc_instruction * inst = begin; inst != end; inst = inst->Next) {
1581c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_for_all_writes_mask(inst, scan_write, &sap);
1591c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_remap_registers(inst, remap_proxy_function, &sap);
1601c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
1611c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1621c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	for(unsigned int index = 0; index < RC_REGISTER_MAX_INDEX; ++index) {
1631c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		if (proxies->Temporary[index].Proxied) {
1641c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			struct rc_instruction * inst_mov = rc_insert_new_instruction(s->C, begin->Prev);
1651c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			inst_mov->U.I.Opcode = RC_OPCODE_MOV;
1661c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			inst_mov->U.I.DstReg.File = RC_FILE_TEMPORARY;
1671c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			inst_mov->U.I.DstReg.Index = proxies->Temporary[index].Index;
1681c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZW;
1691c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			inst_mov->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
1701c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			inst_mov->U.I.SrcReg[0].Index = index;
1711c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		}
1721c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
1731c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
1741c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1751c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1761c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic void inject_cmp(struct emulate_branch_state * s,
1771c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct rc_instruction * inst_if,
1781c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct rc_instruction * inst_endif,
1791c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_register_file file, unsigned int index,
1801c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct proxy_info ifproxy,
1811c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct proxy_info elseproxy)
1821c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
1831c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct rc_instruction * inst_cmp = rc_insert_new_instruction(s->C, inst_endif);
1841c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.Opcode = RC_OPCODE_CMP;
1851c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.DstReg.File = file;
1861c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.DstReg.Index = index;
1871c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.DstReg.WriteMask = RC_MASK_XYZW;
1881c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.SrcReg[0] = inst_if->U.I.SrcReg[0];
1891c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.SrcReg[0].Abs = 1;
1901c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.SrcReg[0].Negate = RC_MASK_XYZW;
1911c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.SrcReg[1].File = RC_FILE_TEMPORARY;
1921c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.SrcReg[1].Index = ifproxy.Proxied ? ifproxy.Index : index;
1931c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.SrcReg[2].File = RC_FILE_TEMPORARY;
1941c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	inst_cmp->U.I.SrcReg[2].Index = elseproxy.Proxied ? elseproxy.Index : index;
1951c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
1961c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
1971c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic void handle_endif(struct emulate_branch_state * s, struct rc_instruction * inst)
1981c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
1991c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct branch_info * branch;
2001c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct register_proxies IfProxies;
2011c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct register_proxies ElseProxies;
2021c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2031c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (!s->BranchCount) {
2041c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_error(s->C, "Encountered ENDIF outside of branches");
2051c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		return;
2061c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
2071c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2081c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	DBG("%s\n", __FUNCTION__);
2091c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2101c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	branch = &s->Branches[s->BranchCount - 1];
2111c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2121c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	memset(&IfProxies, 0, sizeof(IfProxies));
2131c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	memset(&ElseProxies, 0, sizeof(ElseProxies));
2141c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2151c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	allocate_and_insert_proxies(s, &IfProxies, branch->If->Next, branch->Else ? branch->Else : inst);
2161c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2171c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (branch->Else)
2181c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		allocate_and_insert_proxies(s, &ElseProxies, branch->Else->Next, inst);
2191c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2201c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	/* Insert the CMP instructions at the end. */
2211c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	for(unsigned int index = 0; index < RC_REGISTER_MAX_INDEX; ++index) {
2221c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		if (IfProxies.Temporary[index].Proxied || ElseProxies.Temporary[index].Proxied) {
2231c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			inject_cmp(s, branch->If, inst, RC_FILE_TEMPORARY, index,
2241c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák					IfProxies.Temporary[index], ElseProxies.Temporary[index]);
2251c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		}
2261c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
2271c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2281c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	/* Remove all traces of the branch instructions */
2291c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	rc_remove_instruction(branch->If);
2301c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (branch->Else)
2311c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_remove_instruction(branch->Else);
2321c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	rc_remove_instruction(inst);
2331c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2341c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	s->BranchCount--;
2351c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2361c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (VERBOSE) {
2371c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		DBG("Program after ENDIF handling:\n");
2381c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_print_program(&s->C->Program);
2391c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
2401c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
2411c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2421c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2431c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstruct remap_output_data {
2441c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	unsigned int Output:RC_REGISTER_INDEX_BITS;
2451c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	unsigned int Temporary:RC_REGISTER_INDEX_BITS;
2461c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák};
2471c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2481c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic void remap_output_function(void * userdata, struct rc_instruction * inst,
2491c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		rc_register_file * pfile, unsigned int * pindex)
2501c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
2511c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct remap_output_data * data = userdata;
2521c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2531c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (*pfile == RC_FILE_OUTPUT && *pindex == data->Output) {
2541c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		*pfile = RC_FILE_TEMPORARY;
2551c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		*pindex = data->Temporary;
2561c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
2571c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
2581c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2591c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2601c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/**
2611c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * Output registers cannot be read from and so cannot be dealt with like
2621c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * temporary registers.
2631c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák *
2641c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * We do the simplest thing: If an output registers is written within
2651c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * a branch, then *all* writes to this register are proxied to a
2661c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * temporary register, and a final MOV is appended to the end of
2671c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * the program.
2681c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák */
2691c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákstatic void fix_output_writes(struct emulate_branch_state * s, struct rc_instruction * inst)
2701c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
2711c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	const struct rc_opcode_info * opcode;
2721c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2731c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (!s->BranchCount)
2741c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		return;
2751c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2761c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	opcode = rc_get_opcode_info(inst->U.I.Opcode);
2771c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2781c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (!opcode->HasDstReg)
2791c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		return;
2801c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2811c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	if (inst->U.I.DstReg.File == RC_FILE_OUTPUT) {
2821c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct remap_output_data remap;
2831c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct rc_instruction * inst_mov;
2841c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2851c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		remap.Output = inst->U.I.DstReg.Index;
2861c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		remap.Temporary = rc_find_free_temporary(s->C);
2871c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2881c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		for(struct rc_instruction * inst = s->C->Program.Instructions.Next;
2891c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		    inst != &s->C->Program.Instructions;
2901c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		    inst = inst->Next) {
2911c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			rc_remap_registers(inst, &remap_output_function, &remap);
2921c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		}
2931c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
2941c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		inst_mov = rc_insert_new_instruction(s->C, s->C->Program.Instructions.Prev);
2951c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		inst_mov->U.I.Opcode = RC_OPCODE_MOV;
2961c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		inst_mov->U.I.DstReg.File = RC_FILE_OUTPUT;
2971c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		inst_mov->U.I.DstReg.Index = remap.Output;
2981c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		inst_mov->U.I.DstReg.WriteMask = RC_MASK_XYZW;
2991c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		inst_mov->U.I.SrcReg[0].File = RC_FILE_TEMPORARY;
3001c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		inst_mov->U.I.SrcReg[0].Index = remap.Temporary;
3011c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
3021c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
3031c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
3041c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák/**
3051c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * Remove branch instructions; instead, execute both branches
3061c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * on different register sets and choose between their results
3071c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák * using CMP instructions in place of the original ENDIF.
3081c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák */
3091c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšákvoid rc_emulate_branches(struct radeon_compiler *c, void *user)
3101c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák{
3111c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct emulate_branch_state s;
3121c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	struct rc_instruction * ptr;
3131c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
3141c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	memset(&s, 0, sizeof(s));
3151c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	s.C = c;
3161c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
3171c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	/* Untypical loop because we may remove the current instruction */
3181c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	ptr = c->Program.Instructions.Next;
3191c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	while(ptr != &c->Program.Instructions) {
3201c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		struct rc_instruction * inst = ptr;
3211c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		ptr = ptr->Next;
3221c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák
3231c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		if (inst->Type == RC_INSTRUCTION_NORMAL) {
3241c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			switch(inst->U.I.Opcode) {
3251c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			case RC_OPCODE_IF:
3261c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák				handle_if(&s, inst);
3271c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák				break;
3281c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			case RC_OPCODE_ELSE:
3291c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák				handle_else(&s, inst);
3301c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák				break;
3311c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			case RC_OPCODE_ENDIF:
3321c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák				handle_endif(&s, inst);
3331c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák				break;
3341c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			default:
3351c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák				fix_output_writes(&s, inst);
3361c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák				break;
3371c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			}
3381c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		} else {
3391c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák			rc_error(c, "%s: unhandled instruction type\n", __FUNCTION__);
3401c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák		}
3411c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák	}
3421c2c4ddbd1e97bfd13430521e5c09cb5ce8e36e6Marek Olšák}
343