1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright (C) 2009 Nicolai Haehnle.
3bf215546Sopenharmony_ci * Copyright 2010 Tom Stellard <tstellar@gmail.com>
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * All Rights Reserved.
6bf215546Sopenharmony_ci *
7bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
8bf215546Sopenharmony_ci * a copy of this software and associated documentation files (the
9bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
10bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
11bf215546Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
12bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
13bf215546Sopenharmony_ci * the following conditions:
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
16bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial
17bf215546Sopenharmony_ci * portions of the Software.
18bf215546Sopenharmony_ci *
19bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22bf215546Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
23bf215546Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24bf215546Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25bf215546Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26bf215546Sopenharmony_ci *
27bf215546Sopenharmony_ci */
28bf215546Sopenharmony_ci
29bf215546Sopenharmony_ci#include "radeon_dataflow.h"
30bf215546Sopenharmony_ci
31bf215546Sopenharmony_ci#include "radeon_compiler.h"
32bf215546Sopenharmony_ci#include "radeon_compiler_util.h"
33bf215546Sopenharmony_ci#include "radeon_program.h"
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_cistruct read_write_mask_data {
36bf215546Sopenharmony_ci	void * UserData;
37bf215546Sopenharmony_ci	rc_read_write_mask_fn Cb;
38bf215546Sopenharmony_ci};
39bf215546Sopenharmony_ci
40bf215546Sopenharmony_cistatic void reads_normal_callback(
41bf215546Sopenharmony_ci	void * userdata,
42bf215546Sopenharmony_ci	struct rc_instruction * fullinst,
43bf215546Sopenharmony_ci	struct rc_src_register * src)
44bf215546Sopenharmony_ci{
45bf215546Sopenharmony_ci	struct read_write_mask_data * cb_data = userdata;
46bf215546Sopenharmony_ci	unsigned int refmask = 0;
47bf215546Sopenharmony_ci	unsigned int chan;
48bf215546Sopenharmony_ci	for(chan = 0; chan < 4; chan++) {
49bf215546Sopenharmony_ci		refmask |= 1 << GET_SWZ(src->Swizzle, chan);
50bf215546Sopenharmony_ci	}
51bf215546Sopenharmony_ci	refmask &= RC_MASK_XYZW;
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci	if (refmask) {
54bf215546Sopenharmony_ci		cb_data->Cb(cb_data->UserData, fullinst, src->File,
55bf215546Sopenharmony_ci							src->Index, refmask);
56bf215546Sopenharmony_ci	}
57bf215546Sopenharmony_ci
58bf215546Sopenharmony_ci	if (refmask && src->RelAddr) {
59bf215546Sopenharmony_ci		cb_data->Cb(cb_data->UserData, fullinst, RC_FILE_ADDRESS, 0,
60bf215546Sopenharmony_ci								RC_MASK_X);
61bf215546Sopenharmony_ci	}
62bf215546Sopenharmony_ci}
63bf215546Sopenharmony_ci
64bf215546Sopenharmony_cistatic void pair_get_src_refmasks(unsigned int * refmasks,
65bf215546Sopenharmony_ci					struct rc_pair_instruction * inst,
66bf215546Sopenharmony_ci					unsigned int swz, unsigned int src)
67bf215546Sopenharmony_ci{
68bf215546Sopenharmony_ci	if (swz >= 4)
69bf215546Sopenharmony_ci		return;
70bf215546Sopenharmony_ci
71bf215546Sopenharmony_ci	if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z) {
72bf215546Sopenharmony_ci		if(src == RC_PAIR_PRESUB_SRC) {
73bf215546Sopenharmony_ci			unsigned int i;
74bf215546Sopenharmony_ci			int srcp_regs =
75bf215546Sopenharmony_ci				rc_presubtract_src_reg_count(
76bf215546Sopenharmony_ci				inst->RGB.Src[src].Index);
77bf215546Sopenharmony_ci			for(i = 0; i < srcp_regs; i++) {
78bf215546Sopenharmony_ci				refmasks[i] |= 1 << swz;
79bf215546Sopenharmony_ci			}
80bf215546Sopenharmony_ci		}
81bf215546Sopenharmony_ci		else {
82bf215546Sopenharmony_ci			refmasks[src] |= 1 << swz;
83bf215546Sopenharmony_ci		}
84bf215546Sopenharmony_ci	}
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci	if (swz == RC_SWIZZLE_W) {
87bf215546Sopenharmony_ci		if (src == RC_PAIR_PRESUB_SRC) {
88bf215546Sopenharmony_ci			unsigned int i;
89bf215546Sopenharmony_ci			int srcp_regs = rc_presubtract_src_reg_count(
90bf215546Sopenharmony_ci					inst->Alpha.Src[src].Index);
91bf215546Sopenharmony_ci			for(i = 0; i < srcp_regs; i++) {
92bf215546Sopenharmony_ci				refmasks[i] |= 1 << swz;
93bf215546Sopenharmony_ci			}
94bf215546Sopenharmony_ci		}
95bf215546Sopenharmony_ci		else {
96bf215546Sopenharmony_ci			refmasks[src] |= 1 << swz;
97bf215546Sopenharmony_ci		}
98bf215546Sopenharmony_ci	}
99bf215546Sopenharmony_ci}
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_cistatic void reads_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
102bf215546Sopenharmony_ci{
103bf215546Sopenharmony_ci	struct rc_pair_instruction * inst = &fullinst->U.P;
104bf215546Sopenharmony_ci	unsigned int refmasks[3] = { 0, 0, 0 };
105bf215546Sopenharmony_ci
106bf215546Sopenharmony_ci	unsigned int arg;
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_ci	for(arg = 0; arg < 3; ++arg) {
109bf215546Sopenharmony_ci		unsigned int chan;
110bf215546Sopenharmony_ci		for(chan = 0; chan < 3; ++chan) {
111bf215546Sopenharmony_ci			unsigned int swz_rgb =
112bf215546Sopenharmony_ci				GET_SWZ(inst->RGB.Arg[arg].Swizzle, chan);
113bf215546Sopenharmony_ci			unsigned int swz_alpha =
114bf215546Sopenharmony_ci				GET_SWZ(inst->Alpha.Arg[arg].Swizzle, chan);
115bf215546Sopenharmony_ci			pair_get_src_refmasks(refmasks, inst, swz_rgb,
116bf215546Sopenharmony_ci						inst->RGB.Arg[arg].Source);
117bf215546Sopenharmony_ci			pair_get_src_refmasks(refmasks, inst, swz_alpha,
118bf215546Sopenharmony_ci						inst->Alpha.Arg[arg].Source);
119bf215546Sopenharmony_ci		}
120bf215546Sopenharmony_ci	}
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci	for(unsigned int src = 0; src < 3; ++src) {
123bf215546Sopenharmony_ci		if (inst->RGB.Src[src].Used && (refmasks[src] & RC_MASK_XYZ))
124bf215546Sopenharmony_ci			cb(userdata, fullinst, inst->RGB.Src[src].File, inst->RGB.Src[src].Index,
125bf215546Sopenharmony_ci			   refmasks[src] & RC_MASK_XYZ);
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci		if (inst->Alpha.Src[src].Used && (refmasks[src] & RC_MASK_W))
128bf215546Sopenharmony_ci			cb(userdata, fullinst, inst->Alpha.Src[src].File, inst->Alpha.Src[src].Index, RC_MASK_W);
129bf215546Sopenharmony_ci	}
130bf215546Sopenharmony_ci}
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_cistatic void pair_sub_for_all_args(
133bf215546Sopenharmony_ci	struct rc_instruction * fullinst,
134bf215546Sopenharmony_ci	struct rc_pair_sub_instruction * sub,
135bf215546Sopenharmony_ci	rc_pair_read_arg_fn cb,
136bf215546Sopenharmony_ci	void * userdata)
137bf215546Sopenharmony_ci{
138bf215546Sopenharmony_ci	int i;
139bf215546Sopenharmony_ci	const struct rc_opcode_info * info = rc_get_opcode_info(sub->Opcode);
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci	for(i = 0; i < info->NumSrcRegs; i++) {
142bf215546Sopenharmony_ci		unsigned int src_type;
143bf215546Sopenharmony_ci
144bf215546Sopenharmony_ci		src_type = rc_source_type_swz(sub->Arg[i].Swizzle);
145bf215546Sopenharmony_ci
146bf215546Sopenharmony_ci		if (src_type == RC_SOURCE_NONE)
147bf215546Sopenharmony_ci			continue;
148bf215546Sopenharmony_ci
149bf215546Sopenharmony_ci		if (sub->Arg[i].Source == RC_PAIR_PRESUB_SRC) {
150bf215546Sopenharmony_ci			unsigned int presub_type;
151bf215546Sopenharmony_ci			unsigned int presub_src_count;
152bf215546Sopenharmony_ci			struct rc_pair_instruction_source * src_array;
153bf215546Sopenharmony_ci			unsigned int j;
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci			if (src_type & RC_SOURCE_RGB) {
156bf215546Sopenharmony_ci				presub_type = fullinst->
157bf215546Sopenharmony_ci					U.P.RGB.Src[RC_PAIR_PRESUB_SRC].Index;
158bf215546Sopenharmony_ci				src_array = fullinst->U.P.RGB.Src;
159bf215546Sopenharmony_ci			} else {
160bf215546Sopenharmony_ci				presub_type = fullinst->
161bf215546Sopenharmony_ci					U.P.Alpha.Src[RC_PAIR_PRESUB_SRC].Index;
162bf215546Sopenharmony_ci				src_array = fullinst->U.P.Alpha.Src;
163bf215546Sopenharmony_ci			}
164bf215546Sopenharmony_ci			presub_src_count
165bf215546Sopenharmony_ci				= rc_presubtract_src_reg_count(presub_type);
166bf215546Sopenharmony_ci			for(j = 0; j < presub_src_count; j++) {
167bf215546Sopenharmony_ci				cb(userdata, fullinst, &sub->Arg[i],
168bf215546Sopenharmony_ci								&src_array[j]);
169bf215546Sopenharmony_ci			}
170bf215546Sopenharmony_ci		} else {
171bf215546Sopenharmony_ci			struct rc_pair_instruction_source * src =
172bf215546Sopenharmony_ci				rc_pair_get_src(&fullinst->U.P, &sub->Arg[i]);
173bf215546Sopenharmony_ci			if (src) {
174bf215546Sopenharmony_ci				cb(userdata, fullinst, &sub->Arg[i], src);
175bf215546Sopenharmony_ci			}
176bf215546Sopenharmony_ci		}
177bf215546Sopenharmony_ci	}
178bf215546Sopenharmony_ci}
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci/* This function calls the callback function (cb) for each source used by
181bf215546Sopenharmony_ci * the instruction.
182bf215546Sopenharmony_ci * */
183bf215546Sopenharmony_civoid rc_for_all_reads_src(
184bf215546Sopenharmony_ci	struct rc_instruction * inst,
185bf215546Sopenharmony_ci	rc_read_src_fn cb,
186bf215546Sopenharmony_ci	void * userdata)
187bf215546Sopenharmony_ci{
188bf215546Sopenharmony_ci	const struct rc_opcode_info * opcode =
189bf215546Sopenharmony_ci					rc_get_opcode_info(inst->U.I.Opcode);
190bf215546Sopenharmony_ci
191bf215546Sopenharmony_ci	/* This function only works with normal instructions. */
192bf215546Sopenharmony_ci	if (inst->Type != RC_INSTRUCTION_NORMAL) {
193bf215546Sopenharmony_ci		assert(0);
194bf215546Sopenharmony_ci		return;
195bf215546Sopenharmony_ci	}
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci	for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci		if (inst->U.I.SrcReg[src].File == RC_FILE_NONE)
200bf215546Sopenharmony_ci			continue;
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci		if (inst->U.I.SrcReg[src].File == RC_FILE_PRESUB) {
203bf215546Sopenharmony_ci			unsigned int i;
204bf215546Sopenharmony_ci			unsigned int srcp_regs = rc_presubtract_src_reg_count(
205bf215546Sopenharmony_ci						inst->U.I.PreSub.Opcode);
206bf215546Sopenharmony_ci			for( i = 0; i < srcp_regs; i++) {
207bf215546Sopenharmony_ci				cb(userdata, inst, &inst->U.I.PreSub.SrcReg[i]);
208bf215546Sopenharmony_ci			}
209bf215546Sopenharmony_ci		} else {
210bf215546Sopenharmony_ci			cb(userdata, inst, &inst->U.I.SrcReg[src]);
211bf215546Sopenharmony_ci		}
212bf215546Sopenharmony_ci	}
213bf215546Sopenharmony_ci}
214bf215546Sopenharmony_ci
215bf215546Sopenharmony_ci/**
216bf215546Sopenharmony_ci * This function calls the callback function (cb) for each arg of the RGB and
217bf215546Sopenharmony_ci * alpha components.
218bf215546Sopenharmony_ci */
219bf215546Sopenharmony_civoid rc_pair_for_all_reads_arg(
220bf215546Sopenharmony_ci	struct rc_instruction * inst,
221bf215546Sopenharmony_ci	rc_pair_read_arg_fn cb,
222bf215546Sopenharmony_ci	void * userdata)
223bf215546Sopenharmony_ci{
224bf215546Sopenharmony_ci	/* This function only works with pair instructions. */
225bf215546Sopenharmony_ci	if (inst->Type != RC_INSTRUCTION_PAIR) {
226bf215546Sopenharmony_ci		assert(0);
227bf215546Sopenharmony_ci		return;
228bf215546Sopenharmony_ci	}
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci	pair_sub_for_all_args(inst, &inst->U.P.RGB, cb, userdata);
231bf215546Sopenharmony_ci	pair_sub_for_all_args(inst, &inst->U.P.Alpha, cb, userdata);
232bf215546Sopenharmony_ci}
233bf215546Sopenharmony_ci
234bf215546Sopenharmony_ci/**
235bf215546Sopenharmony_ci * Calls a callback function for all register reads.
236bf215546Sopenharmony_ci *
237bf215546Sopenharmony_ci * This is conservative, i.e. if the same register is referenced multiple times,
238bf215546Sopenharmony_ci * the callback may also be called multiple times.
239bf215546Sopenharmony_ci * Also, the writemask of the instruction is not taken into account.
240bf215546Sopenharmony_ci */
241bf215546Sopenharmony_civoid rc_for_all_reads_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
242bf215546Sopenharmony_ci{
243bf215546Sopenharmony_ci	if (inst->Type == RC_INSTRUCTION_NORMAL) {
244bf215546Sopenharmony_ci		struct read_write_mask_data cb_data;
245bf215546Sopenharmony_ci		cb_data.UserData = userdata;
246bf215546Sopenharmony_ci		cb_data.Cb = cb;
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci		rc_for_all_reads_src(inst, reads_normal_callback, &cb_data);
249bf215546Sopenharmony_ci	} else {
250bf215546Sopenharmony_ci		reads_pair(inst, cb, userdata);
251bf215546Sopenharmony_ci	}
252bf215546Sopenharmony_ci}
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci
255bf215546Sopenharmony_ci
256bf215546Sopenharmony_cistatic void writes_normal(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
257bf215546Sopenharmony_ci{
258bf215546Sopenharmony_ci	struct rc_sub_instruction * inst = &fullinst->U.I;
259bf215546Sopenharmony_ci	const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
260bf215546Sopenharmony_ci
261bf215546Sopenharmony_ci	if (opcode->HasDstReg && inst->DstReg.WriteMask)
262bf215546Sopenharmony_ci		cb(userdata, fullinst, inst->DstReg.File, inst->DstReg.Index, inst->DstReg.WriteMask);
263bf215546Sopenharmony_ci
264bf215546Sopenharmony_ci	if (inst->WriteALUResult)
265bf215546Sopenharmony_ci		cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
266bf215546Sopenharmony_ci}
267bf215546Sopenharmony_ci
268bf215546Sopenharmony_cistatic void writes_pair(struct rc_instruction * fullinst, rc_read_write_mask_fn cb, void * userdata)
269bf215546Sopenharmony_ci{
270bf215546Sopenharmony_ci	struct rc_pair_instruction * inst = &fullinst->U.P;
271bf215546Sopenharmony_ci
272bf215546Sopenharmony_ci	if (inst->RGB.WriteMask)
273bf215546Sopenharmony_ci		cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->RGB.DestIndex, inst->RGB.WriteMask);
274bf215546Sopenharmony_ci
275bf215546Sopenharmony_ci	if (inst->Alpha.WriteMask)
276bf215546Sopenharmony_ci		cb(userdata, fullinst, RC_FILE_TEMPORARY, inst->Alpha.DestIndex, RC_MASK_W);
277bf215546Sopenharmony_ci
278bf215546Sopenharmony_ci	if (inst->WriteALUResult)
279bf215546Sopenharmony_ci		cb(userdata, fullinst, RC_FILE_SPECIAL, RC_SPECIAL_ALU_RESULT, RC_MASK_X);
280bf215546Sopenharmony_ci}
281bf215546Sopenharmony_ci
282bf215546Sopenharmony_ci/**
283bf215546Sopenharmony_ci * Calls a callback function for all register writes in the instruction,
284bf215546Sopenharmony_ci * reporting writemasks to the callback function.
285bf215546Sopenharmony_ci *
286bf215546Sopenharmony_ci * \warning Does not report output registers for paired instructions!
287bf215546Sopenharmony_ci */
288bf215546Sopenharmony_civoid rc_for_all_writes_mask(struct rc_instruction * inst, rc_read_write_mask_fn cb, void * userdata)
289bf215546Sopenharmony_ci{
290bf215546Sopenharmony_ci	if (inst->Type == RC_INSTRUCTION_NORMAL) {
291bf215546Sopenharmony_ci		writes_normal(inst, cb, userdata);
292bf215546Sopenharmony_ci	} else {
293bf215546Sopenharmony_ci		writes_pair(inst, cb, userdata);
294bf215546Sopenharmony_ci	}
295bf215546Sopenharmony_ci}
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci
298bf215546Sopenharmony_cistruct mask_to_chan_data {
299bf215546Sopenharmony_ci	void * UserData;
300bf215546Sopenharmony_ci	rc_read_write_chan_fn Fn;
301bf215546Sopenharmony_ci};
302bf215546Sopenharmony_ci
303bf215546Sopenharmony_cistatic void mask_to_chan_cb(void * data, struct rc_instruction * inst,
304bf215546Sopenharmony_ci		rc_register_file file, unsigned int index, unsigned int mask)
305bf215546Sopenharmony_ci{
306bf215546Sopenharmony_ci	struct mask_to_chan_data * d = data;
307bf215546Sopenharmony_ci	for(unsigned int chan = 0; chan < 4; ++chan) {
308bf215546Sopenharmony_ci		if (GET_BIT(mask, chan))
309bf215546Sopenharmony_ci			d->Fn(d->UserData, inst, file, index, chan);
310bf215546Sopenharmony_ci	}
311bf215546Sopenharmony_ci}
312bf215546Sopenharmony_ci
313bf215546Sopenharmony_ci/**
314bf215546Sopenharmony_ci * Calls a callback function for all sourced register channels.
315bf215546Sopenharmony_ci *
316bf215546Sopenharmony_ci * This is conservative, i.e. channels may be called multiple times,
317bf215546Sopenharmony_ci * and the writemask of the instruction is not taken into account.
318bf215546Sopenharmony_ci */
319bf215546Sopenharmony_civoid rc_for_all_reads_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
320bf215546Sopenharmony_ci{
321bf215546Sopenharmony_ci	struct mask_to_chan_data d;
322bf215546Sopenharmony_ci	d.UserData = userdata;
323bf215546Sopenharmony_ci	d.Fn = cb;
324bf215546Sopenharmony_ci	rc_for_all_reads_mask(inst, &mask_to_chan_cb, &d);
325bf215546Sopenharmony_ci}
326bf215546Sopenharmony_ci
327bf215546Sopenharmony_ci/**
328bf215546Sopenharmony_ci * Calls a callback function for all written register channels.
329bf215546Sopenharmony_ci *
330bf215546Sopenharmony_ci * \warning Does not report output registers for paired instructions!
331bf215546Sopenharmony_ci */
332bf215546Sopenharmony_civoid rc_for_all_writes_chan(struct rc_instruction * inst, rc_read_write_chan_fn cb, void * userdata)
333bf215546Sopenharmony_ci{
334bf215546Sopenharmony_ci	struct mask_to_chan_data d;
335bf215546Sopenharmony_ci	d.UserData = userdata;
336bf215546Sopenharmony_ci	d.Fn = cb;
337bf215546Sopenharmony_ci	rc_for_all_writes_mask(inst, &mask_to_chan_cb, &d);
338bf215546Sopenharmony_ci}
339bf215546Sopenharmony_ci
340bf215546Sopenharmony_cistatic void remap_normal_instruction(struct rc_instruction * fullinst,
341bf215546Sopenharmony_ci		rc_remap_register_fn cb, void * userdata)
342bf215546Sopenharmony_ci{
343bf215546Sopenharmony_ci	struct rc_sub_instruction * inst = &fullinst->U.I;
344bf215546Sopenharmony_ci	const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->Opcode);
345bf215546Sopenharmony_ci	unsigned int remapped_presub = 0;
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci	if (opcode->HasDstReg) {
348bf215546Sopenharmony_ci		rc_register_file file = inst->DstReg.File;
349bf215546Sopenharmony_ci		unsigned int index = inst->DstReg.Index;
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci		cb(userdata, fullinst, &file, &index);
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci		inst->DstReg.File = file;
354bf215546Sopenharmony_ci		inst->DstReg.Index = index;
355bf215546Sopenharmony_ci	}
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci	for(unsigned int src = 0; src < opcode->NumSrcRegs; ++src) {
358bf215546Sopenharmony_ci		rc_register_file file = inst->SrcReg[src].File;
359bf215546Sopenharmony_ci		unsigned int index = inst->SrcReg[src].Index;
360bf215546Sopenharmony_ci
361bf215546Sopenharmony_ci		if (file == RC_FILE_PRESUB) {
362bf215546Sopenharmony_ci			unsigned int i;
363bf215546Sopenharmony_ci			unsigned int srcp_srcs = rc_presubtract_src_reg_count(
364bf215546Sopenharmony_ci						inst->PreSub.Opcode);
365bf215546Sopenharmony_ci			/* Make sure we only remap presubtract sources once in
366bf215546Sopenharmony_ci			 * case more than one source register reads the
367bf215546Sopenharmony_ci			 * presubtract result. */
368bf215546Sopenharmony_ci			if (remapped_presub)
369bf215546Sopenharmony_ci				continue;
370bf215546Sopenharmony_ci
371bf215546Sopenharmony_ci			for(i = 0; i < srcp_srcs; i++) {
372bf215546Sopenharmony_ci				file = inst->PreSub.SrcReg[i].File;
373bf215546Sopenharmony_ci				index = inst->PreSub.SrcReg[i].Index;
374bf215546Sopenharmony_ci				cb(userdata, fullinst, &file, &index);
375bf215546Sopenharmony_ci				inst->PreSub.SrcReg[i].File = file;
376bf215546Sopenharmony_ci				inst->PreSub.SrcReg[i].Index = index;
377bf215546Sopenharmony_ci			}
378bf215546Sopenharmony_ci			remapped_presub = 1;
379bf215546Sopenharmony_ci		}
380bf215546Sopenharmony_ci		else {
381bf215546Sopenharmony_ci			cb(userdata, fullinst, &file, &index);
382bf215546Sopenharmony_ci
383bf215546Sopenharmony_ci			inst->SrcReg[src].File = file;
384bf215546Sopenharmony_ci			inst->SrcReg[src].Index = index;
385bf215546Sopenharmony_ci		}
386bf215546Sopenharmony_ci	}
387bf215546Sopenharmony_ci}
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_cistatic void remap_pair_instruction(struct rc_instruction * fullinst,
390bf215546Sopenharmony_ci		rc_remap_register_fn cb, void * userdata)
391bf215546Sopenharmony_ci{
392bf215546Sopenharmony_ci	struct rc_pair_instruction * inst = &fullinst->U.P;
393bf215546Sopenharmony_ci
394bf215546Sopenharmony_ci	if (inst->RGB.WriteMask) {
395bf215546Sopenharmony_ci		rc_register_file file = RC_FILE_TEMPORARY;
396bf215546Sopenharmony_ci		unsigned int index = inst->RGB.DestIndex;
397bf215546Sopenharmony_ci
398bf215546Sopenharmony_ci		cb(userdata, fullinst, &file, &index);
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_ci		inst->RGB.DestIndex = index;
401bf215546Sopenharmony_ci	}
402bf215546Sopenharmony_ci
403bf215546Sopenharmony_ci	if (inst->Alpha.WriteMask) {
404bf215546Sopenharmony_ci		rc_register_file file = RC_FILE_TEMPORARY;
405bf215546Sopenharmony_ci		unsigned int index = inst->Alpha.DestIndex;
406bf215546Sopenharmony_ci
407bf215546Sopenharmony_ci		cb(userdata, fullinst, &file, &index);
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci		inst->Alpha.DestIndex = index;
410bf215546Sopenharmony_ci	}
411bf215546Sopenharmony_ci
412bf215546Sopenharmony_ci	for(unsigned int src = 0; src < 3; ++src) {
413bf215546Sopenharmony_ci		if (inst->RGB.Src[src].Used) {
414bf215546Sopenharmony_ci			rc_register_file file = inst->RGB.Src[src].File;
415bf215546Sopenharmony_ci			unsigned int index = inst->RGB.Src[src].Index;
416bf215546Sopenharmony_ci
417bf215546Sopenharmony_ci			cb(userdata, fullinst, &file, &index);
418bf215546Sopenharmony_ci
419bf215546Sopenharmony_ci			inst->RGB.Src[src].File = file;
420bf215546Sopenharmony_ci			inst->RGB.Src[src].Index = index;
421bf215546Sopenharmony_ci		}
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci		if (inst->Alpha.Src[src].Used) {
424bf215546Sopenharmony_ci			rc_register_file file = inst->Alpha.Src[src].File;
425bf215546Sopenharmony_ci			unsigned int index = inst->Alpha.Src[src].Index;
426bf215546Sopenharmony_ci
427bf215546Sopenharmony_ci			cb(userdata, fullinst, &file, &index);
428bf215546Sopenharmony_ci
429bf215546Sopenharmony_ci			inst->Alpha.Src[src].File = file;
430bf215546Sopenharmony_ci			inst->Alpha.Src[src].Index = index;
431bf215546Sopenharmony_ci		}
432bf215546Sopenharmony_ci	}
433bf215546Sopenharmony_ci}
434bf215546Sopenharmony_ci
435bf215546Sopenharmony_ci
436bf215546Sopenharmony_ci/**
437bf215546Sopenharmony_ci * Remap all register accesses according to the given function.
438bf215546Sopenharmony_ci * That is, call the function \p cb for each referenced register (both read and written)
439bf215546Sopenharmony_ci * and update the given instruction \p inst accordingly
440bf215546Sopenharmony_ci * if it modifies its \ref pfile and \ref pindex contents.
441bf215546Sopenharmony_ci */
442bf215546Sopenharmony_civoid rc_remap_registers(struct rc_instruction * inst, rc_remap_register_fn cb, void * userdata)
443bf215546Sopenharmony_ci{
444bf215546Sopenharmony_ci	if (inst->Type == RC_INSTRUCTION_NORMAL)
445bf215546Sopenharmony_ci		remap_normal_instruction(inst, cb, userdata);
446bf215546Sopenharmony_ci	else
447bf215546Sopenharmony_ci		remap_pair_instruction(inst, cb, userdata);
448bf215546Sopenharmony_ci}
449bf215546Sopenharmony_ci
450bf215546Sopenharmony_cistruct branch_write_mask {
451bf215546Sopenharmony_ci	unsigned int IfWriteMask:4;
452bf215546Sopenharmony_ci	unsigned int ElseWriteMask:4;
453bf215546Sopenharmony_ci	unsigned int HasElse:1;
454bf215546Sopenharmony_ci};
455bf215546Sopenharmony_ci
456bf215546Sopenharmony_ciunion get_readers_read_cb {
457bf215546Sopenharmony_ci	rc_read_src_fn I;
458bf215546Sopenharmony_ci	rc_pair_read_arg_fn P;
459bf215546Sopenharmony_ci};
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_cistruct get_readers_callback_data {
462bf215546Sopenharmony_ci	struct radeon_compiler * C;
463bf215546Sopenharmony_ci	struct rc_reader_data * ReaderData;
464bf215546Sopenharmony_ci	rc_read_src_fn ReadNormalCB;
465bf215546Sopenharmony_ci	rc_pair_read_arg_fn ReadPairCB;
466bf215546Sopenharmony_ci	rc_read_write_mask_fn WriteCB;
467bf215546Sopenharmony_ci	rc_register_file DstFile;
468bf215546Sopenharmony_ci	unsigned int DstIndex;
469bf215546Sopenharmony_ci	unsigned int DstMask;
470bf215546Sopenharmony_ci	unsigned int AliveWriteMask;
471bf215546Sopenharmony_ci	/*  For convenience, this is indexed starting at 1 */
472bf215546Sopenharmony_ci	struct branch_write_mask BranchMasks[R500_PFS_MAX_BRANCH_DEPTH_FULL + 1];
473bf215546Sopenharmony_ci};
474bf215546Sopenharmony_ci
475bf215546Sopenharmony_cistatic struct rc_reader * add_reader(
476bf215546Sopenharmony_ci	struct memory_pool * pool,
477bf215546Sopenharmony_ci	struct rc_reader_data * data,
478bf215546Sopenharmony_ci	struct rc_instruction * inst,
479bf215546Sopenharmony_ci	unsigned int mask)
480bf215546Sopenharmony_ci{
481bf215546Sopenharmony_ci	struct rc_reader * new;
482bf215546Sopenharmony_ci	memory_pool_array_reserve(pool, struct rc_reader, data->Readers,
483bf215546Sopenharmony_ci				data->ReaderCount, data->ReadersReserved, 1);
484bf215546Sopenharmony_ci	new = &data->Readers[data->ReaderCount++];
485bf215546Sopenharmony_ci	new->Inst = inst;
486bf215546Sopenharmony_ci	new->WriteMask = mask;
487bf215546Sopenharmony_ci	return new;
488bf215546Sopenharmony_ci}
489bf215546Sopenharmony_ci
490bf215546Sopenharmony_cistatic void add_reader_normal(
491bf215546Sopenharmony_ci	struct memory_pool * pool,
492bf215546Sopenharmony_ci	struct rc_reader_data * data,
493bf215546Sopenharmony_ci	struct rc_instruction * inst,
494bf215546Sopenharmony_ci	unsigned int mask,
495bf215546Sopenharmony_ci	struct rc_src_register * src)
496bf215546Sopenharmony_ci{
497bf215546Sopenharmony_ci	struct rc_reader * new = add_reader(pool, data, inst, mask);
498bf215546Sopenharmony_ci	new->U.I.Src = src;
499bf215546Sopenharmony_ci}
500bf215546Sopenharmony_ci
501bf215546Sopenharmony_ci
502bf215546Sopenharmony_cistatic void add_reader_pair(
503bf215546Sopenharmony_ci	struct memory_pool * pool,
504bf215546Sopenharmony_ci	struct rc_reader_data * data,
505bf215546Sopenharmony_ci	struct rc_instruction * inst,
506bf215546Sopenharmony_ci	unsigned int mask,
507bf215546Sopenharmony_ci	struct rc_pair_instruction_arg * arg,
508bf215546Sopenharmony_ci	struct rc_pair_instruction_source * src)
509bf215546Sopenharmony_ci{
510bf215546Sopenharmony_ci	struct rc_reader * new = add_reader(pool, data, inst, mask);
511bf215546Sopenharmony_ci	new->U.P.Src = src;
512bf215546Sopenharmony_ci	new->U.P.Arg = arg;
513bf215546Sopenharmony_ci}
514bf215546Sopenharmony_ci
515bf215546Sopenharmony_cistatic unsigned int get_readers_read_callback(
516bf215546Sopenharmony_ci	struct get_readers_callback_data * cb_data,
517bf215546Sopenharmony_ci	unsigned int has_rel_addr,
518bf215546Sopenharmony_ci	rc_register_file file,
519bf215546Sopenharmony_ci	unsigned int index,
520bf215546Sopenharmony_ci	unsigned int swizzle)
521bf215546Sopenharmony_ci{
522bf215546Sopenharmony_ci	unsigned int shared_mask, read_mask;
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_ci	if (has_rel_addr) {
525bf215546Sopenharmony_ci		cb_data->ReaderData->Abort = 1;
526bf215546Sopenharmony_ci		return RC_MASK_NONE;
527bf215546Sopenharmony_ci	}
528bf215546Sopenharmony_ci
529bf215546Sopenharmony_ci	shared_mask = rc_src_reads_dst_mask(file, index, swizzle,
530bf215546Sopenharmony_ci		cb_data->DstFile, cb_data->DstIndex, cb_data->AliveWriteMask);
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_ci	if (shared_mask == RC_MASK_NONE)
533bf215546Sopenharmony_ci		return shared_mask;
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_ci	/* If we make it this far, it means that this source reads from the
536bf215546Sopenharmony_ci	 * same register written to by d->ReaderData->Writer. */
537bf215546Sopenharmony_ci
538bf215546Sopenharmony_ci	read_mask = rc_swizzle_to_writemask(swizzle);
539bf215546Sopenharmony_ci	if (cb_data->ReaderData->AbortOnRead & read_mask) {
540bf215546Sopenharmony_ci		cb_data->ReaderData->Abort = 1;
541bf215546Sopenharmony_ci		return shared_mask;
542bf215546Sopenharmony_ci	}
543bf215546Sopenharmony_ci
544bf215546Sopenharmony_ci	if (cb_data->ReaderData->LoopDepth > 0) {
545bf215546Sopenharmony_ci		cb_data->ReaderData->AbortOnWrite |=
546bf215546Sopenharmony_ci				(read_mask & cb_data->AliveWriteMask);
547bf215546Sopenharmony_ci	}
548bf215546Sopenharmony_ci
549bf215546Sopenharmony_ci	/* XXX The behavior in this case should be configurable. */
550bf215546Sopenharmony_ci	if ((read_mask & cb_data->AliveWriteMask) != read_mask) {
551bf215546Sopenharmony_ci		cb_data->ReaderData->Abort = 1;
552bf215546Sopenharmony_ci		return shared_mask;
553bf215546Sopenharmony_ci	}
554bf215546Sopenharmony_ci
555bf215546Sopenharmony_ci	return shared_mask;
556bf215546Sopenharmony_ci}
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_cistatic void get_readers_pair_read_callback(
559bf215546Sopenharmony_ci	void * userdata,
560bf215546Sopenharmony_ci	struct rc_instruction * inst,
561bf215546Sopenharmony_ci	struct rc_pair_instruction_arg * arg,
562bf215546Sopenharmony_ci	struct rc_pair_instruction_source * src)
563bf215546Sopenharmony_ci{
564bf215546Sopenharmony_ci	unsigned int shared_mask;
565bf215546Sopenharmony_ci	struct get_readers_callback_data * d = userdata;
566bf215546Sopenharmony_ci
567bf215546Sopenharmony_ci	shared_mask = get_readers_read_callback(d,
568bf215546Sopenharmony_ci				0 /*Pair Instructions don't use RelAddr*/,
569bf215546Sopenharmony_ci				src->File, src->Index, arg->Swizzle);
570bf215546Sopenharmony_ci
571bf215546Sopenharmony_ci	if (shared_mask == RC_MASK_NONE)
572bf215546Sopenharmony_ci		return;
573bf215546Sopenharmony_ci
574bf215546Sopenharmony_ci	if (d->ReadPairCB)
575bf215546Sopenharmony_ci		d->ReadPairCB(d->ReaderData, inst, arg, src);
576bf215546Sopenharmony_ci
577bf215546Sopenharmony_ci	if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
578bf215546Sopenharmony_ci		return;
579bf215546Sopenharmony_ci
580bf215546Sopenharmony_ci	add_reader_pair(&d->C->Pool, d->ReaderData, inst, shared_mask, arg, src);
581bf215546Sopenharmony_ci}
582bf215546Sopenharmony_ci
583bf215546Sopenharmony_ci/**
584bf215546Sopenharmony_ci * This function is used by rc_get_readers_normal() to determine whether inst
585bf215546Sopenharmony_ci * is a reader of userdata->ReaderData->Writer
586bf215546Sopenharmony_ci */
587bf215546Sopenharmony_cistatic void get_readers_normal_read_callback(
588bf215546Sopenharmony_ci	void * userdata,
589bf215546Sopenharmony_ci	struct rc_instruction * inst,
590bf215546Sopenharmony_ci	struct rc_src_register * src)
591bf215546Sopenharmony_ci{
592bf215546Sopenharmony_ci	struct get_readers_callback_data * d = userdata;
593bf215546Sopenharmony_ci	unsigned int shared_mask;
594bf215546Sopenharmony_ci
595bf215546Sopenharmony_ci	shared_mask = get_readers_read_callback(d,
596bf215546Sopenharmony_ci			src->RelAddr, src->File, src->Index, src->Swizzle);
597bf215546Sopenharmony_ci
598bf215546Sopenharmony_ci	if (shared_mask == RC_MASK_NONE)
599bf215546Sopenharmony_ci		return;
600bf215546Sopenharmony_ci	/* The callback function could potentially clear d->ReaderData->Abort,
601bf215546Sopenharmony_ci	 * so we need to call it before we return. */
602bf215546Sopenharmony_ci	if (d->ReadNormalCB)
603bf215546Sopenharmony_ci		d->ReadNormalCB(d->ReaderData, inst, src);
604bf215546Sopenharmony_ci
605bf215546Sopenharmony_ci	if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
606bf215546Sopenharmony_ci		return;
607bf215546Sopenharmony_ci
608bf215546Sopenharmony_ci	add_reader_normal(&d->C->Pool, d->ReaderData, inst, shared_mask, src);
609bf215546Sopenharmony_ci}
610bf215546Sopenharmony_ci
611bf215546Sopenharmony_ci/**
612bf215546Sopenharmony_ci * This function is used by rc_get_readers_normal() to determine when
613bf215546Sopenharmony_ci * userdata->ReaderData->Writer is dead (i. e. All components of its
614bf215546Sopenharmony_ci * destination register have been overwritten by other instructions).
615bf215546Sopenharmony_ci */
616bf215546Sopenharmony_cistatic void get_readers_write_callback(
617bf215546Sopenharmony_ci	void *userdata,
618bf215546Sopenharmony_ci	struct rc_instruction * inst,
619bf215546Sopenharmony_ci	rc_register_file file,
620bf215546Sopenharmony_ci	unsigned int index,
621bf215546Sopenharmony_ci	unsigned int mask)
622bf215546Sopenharmony_ci{
623bf215546Sopenharmony_ci	struct get_readers_callback_data * d = userdata;
624bf215546Sopenharmony_ci
625bf215546Sopenharmony_ci	if (index == d->DstIndex && file == d->DstFile) {
626bf215546Sopenharmony_ci		unsigned int shared_mask = mask & d->DstMask;
627bf215546Sopenharmony_ci		d->ReaderData->AbortOnRead &= ~shared_mask;
628bf215546Sopenharmony_ci		d->AliveWriteMask &= ~shared_mask;
629bf215546Sopenharmony_ci		if (d->ReaderData->AbortOnWrite & shared_mask) {
630bf215546Sopenharmony_ci			d->ReaderData->Abort = 1;
631bf215546Sopenharmony_ci		}
632bf215546Sopenharmony_ci	}
633bf215546Sopenharmony_ci
634bf215546Sopenharmony_ci	if(d->WriteCB)
635bf215546Sopenharmony_ci		d->WriteCB(d->ReaderData, inst, file, index, mask);
636bf215546Sopenharmony_ci}
637bf215546Sopenharmony_ci
638bf215546Sopenharmony_cistatic void push_branch_mask(
639bf215546Sopenharmony_ci	struct get_readers_callback_data * d,
640bf215546Sopenharmony_ci	unsigned int * branch_depth)
641bf215546Sopenharmony_ci{
642bf215546Sopenharmony_ci	(*branch_depth)++;
643bf215546Sopenharmony_ci	if (*branch_depth > R500_PFS_MAX_BRANCH_DEPTH_FULL) {
644bf215546Sopenharmony_ci		d->ReaderData->Abort = 1;
645bf215546Sopenharmony_ci		return;
646bf215546Sopenharmony_ci	}
647bf215546Sopenharmony_ci	d->BranchMasks[*branch_depth].IfWriteMask =
648bf215546Sopenharmony_ci					d->AliveWriteMask;
649bf215546Sopenharmony_ci}
650bf215546Sopenharmony_ci
651bf215546Sopenharmony_cistatic void pop_branch_mask(
652bf215546Sopenharmony_ci	struct get_readers_callback_data * d,
653bf215546Sopenharmony_ci	unsigned int * branch_depth)
654bf215546Sopenharmony_ci{
655bf215546Sopenharmony_ci	struct branch_write_mask * masks = &d->BranchMasks[*branch_depth];
656bf215546Sopenharmony_ci
657bf215546Sopenharmony_ci	if (masks->HasElse) {
658bf215546Sopenharmony_ci		/* Abort on read for components that were written in the IF
659bf215546Sopenharmony_ci		 * block. */
660bf215546Sopenharmony_ci		d->ReaderData->AbortOnRead |=
661bf215546Sopenharmony_ci				masks->IfWriteMask & ~masks->ElseWriteMask;
662bf215546Sopenharmony_ci		/* Abort on read for components that were written in the ELSE
663bf215546Sopenharmony_ci		 * block. */
664bf215546Sopenharmony_ci		d->ReaderData->AbortOnRead |=
665bf215546Sopenharmony_ci				masks->ElseWriteMask & ~d->AliveWriteMask;
666bf215546Sopenharmony_ci
667bf215546Sopenharmony_ci		d->AliveWriteMask = masks->IfWriteMask
668bf215546Sopenharmony_ci			^ ((masks->IfWriteMask ^ masks->ElseWriteMask)
669bf215546Sopenharmony_ci			& (masks->IfWriteMask ^ d->AliveWriteMask));
670bf215546Sopenharmony_ci	} else {
671bf215546Sopenharmony_ci		d->ReaderData->AbortOnRead |=
672bf215546Sopenharmony_ci				masks->IfWriteMask & ~d->AliveWriteMask;
673bf215546Sopenharmony_ci		d->AliveWriteMask = masks->IfWriteMask;
674bf215546Sopenharmony_ci
675bf215546Sopenharmony_ci	}
676bf215546Sopenharmony_ci	memset(masks, 0, sizeof(struct branch_write_mask));
677bf215546Sopenharmony_ci	(*branch_depth)--;
678bf215546Sopenharmony_ci}
679bf215546Sopenharmony_ci
680bf215546Sopenharmony_cistatic void get_readers_for_single_write(
681bf215546Sopenharmony_ci	void * userdata,
682bf215546Sopenharmony_ci	struct rc_instruction * writer,
683bf215546Sopenharmony_ci	rc_register_file dst_file,
684bf215546Sopenharmony_ci	unsigned int dst_index,
685bf215546Sopenharmony_ci	unsigned int dst_mask)
686bf215546Sopenharmony_ci{
687bf215546Sopenharmony_ci	struct rc_instruction * tmp;
688bf215546Sopenharmony_ci	unsigned int branch_depth = 0;
689bf215546Sopenharmony_ci	struct rc_instruction * endloop = NULL;
690bf215546Sopenharmony_ci	unsigned int abort_on_read_at_endloop = 0;
691bf215546Sopenharmony_ci	int readers_before_endloop = -1;
692bf215546Sopenharmony_ci	struct get_readers_callback_data * d = userdata;
693bf215546Sopenharmony_ci
694bf215546Sopenharmony_ci	d->ReaderData->Writer = writer;
695bf215546Sopenharmony_ci	d->ReaderData->AbortOnRead = 0;
696bf215546Sopenharmony_ci	d->ReaderData->AbortOnWrite = 0;
697bf215546Sopenharmony_ci	d->ReaderData->LoopDepth = 0;
698bf215546Sopenharmony_ci	d->ReaderData->InElse = 0;
699bf215546Sopenharmony_ci	d->ReaderData->ReadersAfterEndloop = false;
700bf215546Sopenharmony_ci	d->DstFile = dst_file;
701bf215546Sopenharmony_ci	d->DstIndex = dst_index;
702bf215546Sopenharmony_ci	d->DstMask = dst_mask;
703bf215546Sopenharmony_ci	d->AliveWriteMask = dst_mask;
704bf215546Sopenharmony_ci	memset(d->BranchMasks, 0, sizeof(d->BranchMasks));
705bf215546Sopenharmony_ci
706bf215546Sopenharmony_ci	if (!dst_mask)
707bf215546Sopenharmony_ci		return;
708bf215546Sopenharmony_ci
709bf215546Sopenharmony_ci	for(tmp = writer->Next; tmp != &d->C->Program.Instructions;
710bf215546Sopenharmony_ci							tmp = tmp->Next){
711bf215546Sopenharmony_ci		rc_opcode opcode = rc_get_flow_control_inst(tmp);
712bf215546Sopenharmony_ci		switch(opcode) {
713bf215546Sopenharmony_ci		case RC_OPCODE_BGNLOOP:
714bf215546Sopenharmony_ci			d->ReaderData->LoopDepth++;
715bf215546Sopenharmony_ci			push_branch_mask(d, &branch_depth);
716bf215546Sopenharmony_ci			break;
717bf215546Sopenharmony_ci		case RC_OPCODE_ENDLOOP:
718bf215546Sopenharmony_ci			if (d->ReaderData->LoopDepth > 0) {
719bf215546Sopenharmony_ci				d->ReaderData->LoopDepth--;
720bf215546Sopenharmony_ci				if (d->ReaderData->LoopDepth == 0) {
721bf215546Sopenharmony_ci					d->ReaderData->AbortOnWrite = 0;
722bf215546Sopenharmony_ci				}
723bf215546Sopenharmony_ci				pop_branch_mask(d, &branch_depth);
724bf215546Sopenharmony_ci			} else {
725bf215546Sopenharmony_ci				/* Here we have reached an ENDLOOP without
726bf215546Sopenharmony_ci				 * seeing its BGNLOOP.  These means that
727bf215546Sopenharmony_ci				 * the writer was written inside of a loop,
728bf215546Sopenharmony_ci				 * so it could have readers that are above it
729bf215546Sopenharmony_ci				 * (i.e. they have a lower IP).  To find these
730bf215546Sopenharmony_ci				 * readers we jump to the BGNLOOP instruction
731bf215546Sopenharmony_ci				 * and check each instruction until we get
732bf215546Sopenharmony_ci				 * back to the writer.
733bf215546Sopenharmony_ci				 */
734bf215546Sopenharmony_ci				endloop = tmp;
735bf215546Sopenharmony_ci				tmp = rc_match_endloop(tmp);
736bf215546Sopenharmony_ci				if (!tmp) {
737bf215546Sopenharmony_ci					rc_error(d->C, "Failed to match endloop.\n");
738bf215546Sopenharmony_ci					d->ReaderData->Abort = 1;
739bf215546Sopenharmony_ci					return;
740bf215546Sopenharmony_ci				}
741bf215546Sopenharmony_ci				abort_on_read_at_endloop = d->ReaderData->AbortOnRead;
742bf215546Sopenharmony_ci				d->ReaderData->AbortOnRead |= d->AliveWriteMask;
743bf215546Sopenharmony_ci				continue;
744bf215546Sopenharmony_ci			}
745bf215546Sopenharmony_ci			break;
746bf215546Sopenharmony_ci		case RC_OPCODE_IF:
747bf215546Sopenharmony_ci			push_branch_mask(d, &branch_depth);
748bf215546Sopenharmony_ci			break;
749bf215546Sopenharmony_ci		case RC_OPCODE_ELSE:
750bf215546Sopenharmony_ci			if (branch_depth == 0) {
751bf215546Sopenharmony_ci				d->ReaderData->InElse = 1;
752bf215546Sopenharmony_ci			} else {
753bf215546Sopenharmony_ci				unsigned int temp_mask = d->AliveWriteMask;
754bf215546Sopenharmony_ci				d->AliveWriteMask =
755bf215546Sopenharmony_ci					d->BranchMasks[branch_depth].IfWriteMask;
756bf215546Sopenharmony_ci				d->BranchMasks[branch_depth].ElseWriteMask =
757bf215546Sopenharmony_ci								temp_mask;
758bf215546Sopenharmony_ci				d->BranchMasks[branch_depth].HasElse = 1;
759bf215546Sopenharmony_ci			}
760bf215546Sopenharmony_ci			break;
761bf215546Sopenharmony_ci		case RC_OPCODE_ENDIF:
762bf215546Sopenharmony_ci			if (branch_depth == 0) {
763bf215546Sopenharmony_ci				d->ReaderData->AbortOnRead = d->AliveWriteMask;
764bf215546Sopenharmony_ci				d->ReaderData->InElse = 0;
765bf215546Sopenharmony_ci			}
766bf215546Sopenharmony_ci			else {
767bf215546Sopenharmony_ci				pop_branch_mask(d, &branch_depth);
768bf215546Sopenharmony_ci			}
769bf215546Sopenharmony_ci			break;
770bf215546Sopenharmony_ci		default:
771bf215546Sopenharmony_ci			break;
772bf215546Sopenharmony_ci		}
773bf215546Sopenharmony_ci
774bf215546Sopenharmony_ci		if (d->ReaderData->InElse)
775bf215546Sopenharmony_ci			continue;
776bf215546Sopenharmony_ci
777bf215546Sopenharmony_ci		if (tmp->Type == RC_INSTRUCTION_NORMAL) {
778bf215546Sopenharmony_ci			rc_for_all_reads_src(tmp,
779bf215546Sopenharmony_ci				get_readers_normal_read_callback, d);
780bf215546Sopenharmony_ci		} else {
781bf215546Sopenharmony_ci			rc_pair_for_all_reads_arg(tmp,
782bf215546Sopenharmony_ci				get_readers_pair_read_callback, d);
783bf215546Sopenharmony_ci		}
784bf215546Sopenharmony_ci
785bf215546Sopenharmony_ci		/* Writer was in loop and we have some readers after it.
786bf215546Sopenharmony_ci		 * Set a flag so we can be extra careful in copy propagate.
787bf215546Sopenharmony_ci		 */
788bf215546Sopenharmony_ci		if (readers_before_endloop != -1 &&
789bf215546Sopenharmony_ci			d->ReaderData->ReaderCount > readers_before_endloop)
790bf215546Sopenharmony_ci			d->ReaderData->ReadersAfterEndloop = true;
791bf215546Sopenharmony_ci
792bf215546Sopenharmony_ci		/* This can happen when we jump from an ENDLOOP to BGNLOOP */
793bf215546Sopenharmony_ci		if (tmp == writer) {
794bf215546Sopenharmony_ci			tmp = endloop;
795bf215546Sopenharmony_ci			endloop = NULL;
796bf215546Sopenharmony_ci			d->ReaderData->AbortOnRead = abort_on_read_at_endloop;
797bf215546Sopenharmony_ci			readers_before_endloop = d->ReaderData->ReaderCount;
798bf215546Sopenharmony_ci			continue;
799bf215546Sopenharmony_ci		}
800bf215546Sopenharmony_ci		rc_for_all_writes_mask(tmp, get_readers_write_callback, d);
801bf215546Sopenharmony_ci
802bf215546Sopenharmony_ci		if (d->ReaderData->ExitOnAbort && d->ReaderData->Abort)
803bf215546Sopenharmony_ci			return;
804bf215546Sopenharmony_ci
805bf215546Sopenharmony_ci		if (branch_depth == 0 && !d->AliveWriteMask)
806bf215546Sopenharmony_ci			return;
807bf215546Sopenharmony_ci	}
808bf215546Sopenharmony_ci}
809bf215546Sopenharmony_ci
810bf215546Sopenharmony_cistatic void init_get_readers_callback_data(
811bf215546Sopenharmony_ci	struct get_readers_callback_data * d,
812bf215546Sopenharmony_ci	struct rc_reader_data * reader_data,
813bf215546Sopenharmony_ci	struct radeon_compiler * c,
814bf215546Sopenharmony_ci	rc_read_src_fn read_normal_cb,
815bf215546Sopenharmony_ci	rc_pair_read_arg_fn read_pair_cb,
816bf215546Sopenharmony_ci	rc_read_write_mask_fn write_cb)
817bf215546Sopenharmony_ci{
818bf215546Sopenharmony_ci	reader_data->Abort = 0;
819bf215546Sopenharmony_ci	reader_data->ReaderCount = 0;
820bf215546Sopenharmony_ci	reader_data->ReadersReserved = 0;
821bf215546Sopenharmony_ci	reader_data->Readers = NULL;
822bf215546Sopenharmony_ci
823bf215546Sopenharmony_ci	d->C = c;
824bf215546Sopenharmony_ci	d->ReaderData = reader_data;
825bf215546Sopenharmony_ci	d->ReadNormalCB = read_normal_cb;
826bf215546Sopenharmony_ci	d->ReadPairCB = read_pair_cb;
827bf215546Sopenharmony_ci	d->WriteCB = write_cb;
828bf215546Sopenharmony_ci}
829bf215546Sopenharmony_ci
830bf215546Sopenharmony_ci/**
831bf215546Sopenharmony_ci * This function will create a list of readers via the rc_reader_data struct.
832bf215546Sopenharmony_ci * This function will abort (set the flag data->Abort) and return if it
833bf215546Sopenharmony_ci * encounters an instruction that reads from @param writer and also a different
834bf215546Sopenharmony_ci * instruction.  Here are some examples:
835bf215546Sopenharmony_ci *
836bf215546Sopenharmony_ci * writer = instruction 0;
837bf215546Sopenharmony_ci * 0 MOV TEMP[0].xy, TEMP[1].xy
838bf215546Sopenharmony_ci * 1 MOV TEMP[0].zw, TEMP[2].xy
839bf215546Sopenharmony_ci * 2 MOV TEMP[3], TEMP[0]
840bf215546Sopenharmony_ci * The Abort flag will be set on instruction 2, because it reads values written
841bf215546Sopenharmony_ci * by instructions 0 and 1.
842bf215546Sopenharmony_ci *
843bf215546Sopenharmony_ci * writer = instruction 1;
844bf215546Sopenharmony_ci * 0 IF TEMP[0].x
845bf215546Sopenharmony_ci * 1 MOV TEMP[1], TEMP[2]
846bf215546Sopenharmony_ci * 2 ELSE
847bf215546Sopenharmony_ci * 3 MOV TEMP[1], TEMP[2]
848bf215546Sopenharmony_ci * 4 ENDIF
849bf215546Sopenharmony_ci * 5 MOV TEMP[3], TEMP[1]
850bf215546Sopenharmony_ci * The Abort flag will be set on instruction 5, because it could read from the
851bf215546Sopenharmony_ci * value written by either instruction 1 or 3, depending on the jump decision
852bf215546Sopenharmony_ci * made at instruction 0.
853bf215546Sopenharmony_ci *
854bf215546Sopenharmony_ci * writer = instruction 0;
855bf215546Sopenharmony_ci * 0 MOV TEMP[0], TEMP[1]
856bf215546Sopenharmony_ci * 2 BGNLOOP
857bf215546Sopenharmony_ci * 3 ADD TEMP[0], TEMP[0], none.1
858bf215546Sopenharmony_ci * 4 ENDLOOP
859bf215546Sopenharmony_ci * The Abort flag will be set on instruction 3, because in the first iteration
860bf215546Sopenharmony_ci * of the loop it reads the value written by instruction 0 and in all other
861bf215546Sopenharmony_ci * iterations it reads the value written by instruction 3.
862bf215546Sopenharmony_ci *
863bf215546Sopenharmony_ci * @param read_cb This function will be called for every instruction that
864bf215546Sopenharmony_ci * has been determined to be a reader of writer.
865bf215546Sopenharmony_ci * @param write_cb This function will be called for every instruction after
866bf215546Sopenharmony_ci * writer.
867bf215546Sopenharmony_ci */
868bf215546Sopenharmony_civoid rc_get_readers(
869bf215546Sopenharmony_ci	struct radeon_compiler * c,
870bf215546Sopenharmony_ci	struct rc_instruction * writer,
871bf215546Sopenharmony_ci	struct rc_reader_data * data,
872bf215546Sopenharmony_ci	rc_read_src_fn read_normal_cb,
873bf215546Sopenharmony_ci	rc_pair_read_arg_fn read_pair_cb,
874bf215546Sopenharmony_ci	rc_read_write_mask_fn write_cb)
875bf215546Sopenharmony_ci{
876bf215546Sopenharmony_ci	struct get_readers_callback_data d;
877bf215546Sopenharmony_ci
878bf215546Sopenharmony_ci	init_get_readers_callback_data(&d, data, c, read_normal_cb,
879bf215546Sopenharmony_ci						read_pair_cb, write_cb);
880bf215546Sopenharmony_ci
881bf215546Sopenharmony_ci	rc_for_all_writes_mask(writer, get_readers_for_single_write, &d);
882bf215546Sopenharmony_ci}
883bf215546Sopenharmony_ci
884bf215546Sopenharmony_civoid rc_get_readers_sub(
885bf215546Sopenharmony_ci	struct radeon_compiler * c,
886bf215546Sopenharmony_ci	struct rc_instruction * writer,
887bf215546Sopenharmony_ci	struct rc_pair_sub_instruction * sub_writer,
888bf215546Sopenharmony_ci	struct rc_reader_data * data,
889bf215546Sopenharmony_ci	rc_read_src_fn read_normal_cb,
890bf215546Sopenharmony_ci	rc_pair_read_arg_fn read_pair_cb,
891bf215546Sopenharmony_ci	rc_read_write_mask_fn write_cb)
892bf215546Sopenharmony_ci{
893bf215546Sopenharmony_ci	struct get_readers_callback_data d;
894bf215546Sopenharmony_ci
895bf215546Sopenharmony_ci	init_get_readers_callback_data(&d, data, c, read_normal_cb,
896bf215546Sopenharmony_ci						read_pair_cb, write_cb);
897bf215546Sopenharmony_ci
898bf215546Sopenharmony_ci	if (sub_writer->WriteMask) {
899bf215546Sopenharmony_ci		get_readers_for_single_write(&d, writer, RC_FILE_TEMPORARY,
900bf215546Sopenharmony_ci			sub_writer->DestIndex, sub_writer->WriteMask);
901bf215546Sopenharmony_ci	}
902bf215546Sopenharmony_ci}
903