1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2011 Tom Stellard <tstellar@gmail.com>
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
7bf215546Sopenharmony_ci * a copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial
16bf215546Sopenharmony_ci * portions of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22bf215546Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23bf215546Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24bf215546Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci */
27bf215546Sopenharmony_ci
28bf215546Sopenharmony_ci#include <stdio.h>
29bf215546Sopenharmony_ci#include <stdlib.h>
30bf215546Sopenharmony_ci#include "radeon_variable.h"
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ci#include "memory_pool.h"
33bf215546Sopenharmony_ci#include "radeon_compiler_util.h"
34bf215546Sopenharmony_ci#include "radeon_dataflow.h"
35bf215546Sopenharmony_ci#include "radeon_list.h"
36bf215546Sopenharmony_ci#include "radeon_opcodes.h"
37bf215546Sopenharmony_ci#include "radeon_program.h"
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci/**
40bf215546Sopenharmony_ci * Rewrite the index and writemask for the destination register of var
41bf215546Sopenharmony_ci * and its friends to new_index and new_writemask.  This function also takes
42bf215546Sopenharmony_ci * care of rewriting the swizzles for the sources of var.
43bf215546Sopenharmony_ci */
44bf215546Sopenharmony_civoid rc_variable_change_dst(
45bf215546Sopenharmony_ci	struct rc_variable * var,
46bf215546Sopenharmony_ci	unsigned int new_index,
47bf215546Sopenharmony_ci	unsigned int new_writemask)
48bf215546Sopenharmony_ci{
49bf215546Sopenharmony_ci	struct rc_variable * var_ptr;
50bf215546Sopenharmony_ci	struct rc_list * readers;
51bf215546Sopenharmony_ci	unsigned int old_mask = rc_variable_writemask_sum(var);
52bf215546Sopenharmony_ci	unsigned int conversion_swizzle =
53bf215546Sopenharmony_ci			rc_make_conversion_swizzle(old_mask, new_writemask);
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci	for (var_ptr = var; var_ptr; var_ptr = var_ptr->Friend) {
56bf215546Sopenharmony_ci		if (var_ptr->Inst->Type == RC_INSTRUCTION_NORMAL) {
57bf215546Sopenharmony_ci			rc_normal_rewrite_writemask(var_ptr->Inst,
58bf215546Sopenharmony_ci							conversion_swizzle);
59bf215546Sopenharmony_ci			var_ptr->Inst->U.I.DstReg.Index = new_index;
60bf215546Sopenharmony_ci		} else {
61bf215546Sopenharmony_ci			struct rc_pair_sub_instruction * sub;
62bf215546Sopenharmony_ci			if (var_ptr->Dst.WriteMask == RC_MASK_W) {
63bf215546Sopenharmony_ci				assert(new_writemask & RC_MASK_W);
64bf215546Sopenharmony_ci				sub = &var_ptr->Inst->U.P.Alpha;
65bf215546Sopenharmony_ci			} else {
66bf215546Sopenharmony_ci				sub = &var_ptr->Inst->U.P.RGB;
67bf215546Sopenharmony_ci				rc_pair_rewrite_writemask(sub,
68bf215546Sopenharmony_ci							conversion_swizzle);
69bf215546Sopenharmony_ci			}
70bf215546Sopenharmony_ci			sub->DestIndex = new_index;
71bf215546Sopenharmony_ci		}
72bf215546Sopenharmony_ci	}
73bf215546Sopenharmony_ci
74bf215546Sopenharmony_ci	readers = rc_variable_readers_union(var);
75bf215546Sopenharmony_ci
76bf215546Sopenharmony_ci	for ( ; readers; readers = readers->Next) {
77bf215546Sopenharmony_ci		struct rc_reader * reader = readers->Item;
78bf215546Sopenharmony_ci		if (reader->Inst->Type == RC_INSTRUCTION_NORMAL) {
79bf215546Sopenharmony_ci			reader->U.I.Src->Index = new_index;
80bf215546Sopenharmony_ci			reader->U.I.Src->Swizzle = rc_rewrite_swizzle(
81bf215546Sopenharmony_ci				reader->U.I.Src->Swizzle, conversion_swizzle);
82bf215546Sopenharmony_ci		} else {
83bf215546Sopenharmony_ci			struct rc_pair_instruction * pair_inst =
84bf215546Sopenharmony_ci							&reader->Inst->U.P;
85bf215546Sopenharmony_ci			unsigned int src_type = rc_source_type_swz(
86bf215546Sopenharmony_ci							reader->U.P.Arg->Swizzle);
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci			int src_index = reader->U.P.Arg->Source;
89bf215546Sopenharmony_ci			if (src_index == RC_PAIR_PRESUB_SRC) {
90bf215546Sopenharmony_ci				src_index = rc_pair_get_src_index(
91bf215546Sopenharmony_ci						pair_inst, reader->U.P.Src);
92bf215546Sopenharmony_ci			}
93bf215546Sopenharmony_ci			rc_pair_remove_src(reader->Inst, src_type,
94bf215546Sopenharmony_ci							src_index);
95bf215546Sopenharmony_ci			/* Reuse the source index of the source that
96bf215546Sopenharmony_ci			 * was just deleted and set its register
97bf215546Sopenharmony_ci			 * index.  We can't use rc_pair_alloc_source
98bf215546Sopenharmony_ci			 * for this because it might return a source
99bf215546Sopenharmony_ci			 * index that is already being used. */
100bf215546Sopenharmony_ci			if (src_type & RC_SOURCE_RGB) {
101bf215546Sopenharmony_ci				pair_inst->RGB.Src[src_index]
102bf215546Sopenharmony_ci					.Used =	1;
103bf215546Sopenharmony_ci				pair_inst->RGB.Src[src_index]
104bf215546Sopenharmony_ci					.Index = new_index;
105bf215546Sopenharmony_ci				pair_inst->RGB.Src[src_index]
106bf215546Sopenharmony_ci					.File = RC_FILE_TEMPORARY;
107bf215546Sopenharmony_ci			}
108bf215546Sopenharmony_ci			if (src_type & RC_SOURCE_ALPHA) {
109bf215546Sopenharmony_ci				pair_inst->Alpha.Src[src_index]
110bf215546Sopenharmony_ci					.Used = 1;
111bf215546Sopenharmony_ci				pair_inst->Alpha.Src[src_index]
112bf215546Sopenharmony_ci					.Index = new_index;
113bf215546Sopenharmony_ci				pair_inst->Alpha.Src[src_index]
114bf215546Sopenharmony_ci					.File = RC_FILE_TEMPORARY;
115bf215546Sopenharmony_ci			}
116bf215546Sopenharmony_ci			reader->U.P.Arg->Swizzle = rc_rewrite_swizzle(
117bf215546Sopenharmony_ci				reader->U.P.Arg->Swizzle, conversion_swizzle);
118bf215546Sopenharmony_ci			if (reader->U.P.Arg->Source != RC_PAIR_PRESUB_SRC) {
119bf215546Sopenharmony_ci				reader->U.P.Arg->Source = src_index;
120bf215546Sopenharmony_ci			}
121bf215546Sopenharmony_ci		}
122bf215546Sopenharmony_ci	}
123bf215546Sopenharmony_ci}
124bf215546Sopenharmony_ci
125bf215546Sopenharmony_ci/**
126bf215546Sopenharmony_ci * Compute the live intervals for var and its friends.
127bf215546Sopenharmony_ci */
128bf215546Sopenharmony_civoid rc_variable_compute_live_intervals(struct rc_variable * var)
129bf215546Sopenharmony_ci{
130bf215546Sopenharmony_ci	while(var) {
131bf215546Sopenharmony_ci		unsigned int i;
132bf215546Sopenharmony_ci		unsigned int start = var->Inst->IP;
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci		for (i = 0; i < var->ReaderCount; i++) {
135bf215546Sopenharmony_ci			unsigned int chan;
136bf215546Sopenharmony_ci			unsigned int chan_start = start;
137bf215546Sopenharmony_ci			unsigned int chan_end = var->Readers[i].Inst->IP;
138bf215546Sopenharmony_ci			unsigned int mask = var->Readers[i].WriteMask;
139bf215546Sopenharmony_ci			struct rc_instruction * inst;
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci			/* Extend the live interval of T0 to the start of the
142bf215546Sopenharmony_ci			 * loop for sequences like:
143bf215546Sopenharmony_ci			 * BGNLOOP
144bf215546Sopenharmony_ci			 * read T0
145bf215546Sopenharmony_ci			 * ...
146bf215546Sopenharmony_ci			 * write T0
147bf215546Sopenharmony_ci			 * ENDLOOP
148bf215546Sopenharmony_ci			 */
149bf215546Sopenharmony_ci			if (var->Readers[i].Inst->IP < start) {
150bf215546Sopenharmony_ci				struct rc_instruction * bgnloop =
151bf215546Sopenharmony_ci					rc_match_endloop(var->Readers[i].Inst);
152bf215546Sopenharmony_ci				chan_start = bgnloop->IP;
153bf215546Sopenharmony_ci			}
154bf215546Sopenharmony_ci
155bf215546Sopenharmony_ci			/* Extend the live interval of T0 to the start of the
156bf215546Sopenharmony_ci			 * loop in case there is a BRK instruction in the loop
157bf215546Sopenharmony_ci			 * (we don't actually check for a BRK instruction we
158bf215546Sopenharmony_ci			 * assume there is one somewhere in the loop, which
159bf215546Sopenharmony_ci			 * there usually is) for sequences like:
160bf215546Sopenharmony_ci			 * BGNLOOP
161bf215546Sopenharmony_ci			 * ...
162bf215546Sopenharmony_ci			 * conditional BRK
163bf215546Sopenharmony_ci			 * ...
164bf215546Sopenharmony_ci			 * write T0
165bf215546Sopenharmony_ci			 * ENDLOOP
166bf215546Sopenharmony_ci			 * read T0
167bf215546Sopenharmony_ci			 ***************************************************
168bf215546Sopenharmony_ci			 * Extend the live interval of T0 to the end of the
169bf215546Sopenharmony_ci			 * loop for sequences like:
170bf215546Sopenharmony_ci			 * write T0
171bf215546Sopenharmony_ci			 * BGNLOOP
172bf215546Sopenharmony_ci			 * ...
173bf215546Sopenharmony_ci			 * read T0
174bf215546Sopenharmony_ci			 * ENDLOOP
175bf215546Sopenharmony_ci			 */
176bf215546Sopenharmony_ci			for (inst = var->Inst; inst != var->Readers[i].Inst;
177bf215546Sopenharmony_ci							inst = inst->Next) {
178bf215546Sopenharmony_ci				rc_opcode op = rc_get_flow_control_inst(inst);
179bf215546Sopenharmony_ci				if (op == RC_OPCODE_ENDLOOP) {
180bf215546Sopenharmony_ci					struct rc_instruction * bgnloop =
181bf215546Sopenharmony_ci						rc_match_endloop(inst);
182bf215546Sopenharmony_ci					if (bgnloop->IP < chan_start) {
183bf215546Sopenharmony_ci						chan_start = bgnloop->IP;
184bf215546Sopenharmony_ci					}
185bf215546Sopenharmony_ci				} else if (op == RC_OPCODE_BGNLOOP) {
186bf215546Sopenharmony_ci					struct rc_instruction * endloop =
187bf215546Sopenharmony_ci						rc_match_bgnloop(inst);
188bf215546Sopenharmony_ci					if (endloop->IP > chan_end) {
189bf215546Sopenharmony_ci						chan_end = endloop->IP;
190bf215546Sopenharmony_ci					}
191bf215546Sopenharmony_ci				}
192bf215546Sopenharmony_ci			}
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci			for (chan = 0; chan < 4; chan++) {
195bf215546Sopenharmony_ci				if ((mask >> chan) & 0x1) {
196bf215546Sopenharmony_ci					if (!var->Live[chan].Used
197bf215546Sopenharmony_ci					|| chan_start < var->Live[chan].Start) {
198bf215546Sopenharmony_ci						var->Live[chan].Start =
199bf215546Sopenharmony_ci								chan_start;
200bf215546Sopenharmony_ci					}
201bf215546Sopenharmony_ci					if (!var->Live[chan].Used
202bf215546Sopenharmony_ci					|| chan_end > var->Live[chan].End) {
203bf215546Sopenharmony_ci						var->Live[chan].End = chan_end;
204bf215546Sopenharmony_ci					}
205bf215546Sopenharmony_ci					var->Live[chan].Used = 1;
206bf215546Sopenharmony_ci				}
207bf215546Sopenharmony_ci			}
208bf215546Sopenharmony_ci		}
209bf215546Sopenharmony_ci		var = var->Friend;
210bf215546Sopenharmony_ci	}
211bf215546Sopenharmony_ci}
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci/**
214bf215546Sopenharmony_ci * @return 1 if a and b share a reader
215bf215546Sopenharmony_ci * @return 0 if they do not
216bf215546Sopenharmony_ci */
217bf215546Sopenharmony_cistatic unsigned int readers_intersect(
218bf215546Sopenharmony_ci	struct rc_variable * a,
219bf215546Sopenharmony_ci	struct rc_variable * b)
220bf215546Sopenharmony_ci{
221bf215546Sopenharmony_ci	unsigned int a_index, b_index;
222bf215546Sopenharmony_ci	for (a_index = 0; a_index < a->ReaderCount; a_index++) {
223bf215546Sopenharmony_ci		struct rc_reader reader_a = a->Readers[a_index];
224bf215546Sopenharmony_ci		for (b_index = 0; b_index < b->ReaderCount; b_index++) {
225bf215546Sopenharmony_ci			struct rc_reader reader_b = b->Readers[b_index];
226bf215546Sopenharmony_ci			if (reader_a.Inst->Type == RC_INSTRUCTION_NORMAL
227bf215546Sopenharmony_ci				&& reader_b.Inst->Type == RC_INSTRUCTION_NORMAL
228bf215546Sopenharmony_ci				&& reader_a.U.I.Src == reader_b.U.I.Src) {
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci				return 1;
231bf215546Sopenharmony_ci			}
232bf215546Sopenharmony_ci			if (reader_a.Inst->Type == RC_INSTRUCTION_PAIR
233bf215546Sopenharmony_ci				&& reader_b.Inst->Type == RC_INSTRUCTION_PAIR
234bf215546Sopenharmony_ci				&& reader_a.U.P.Src == reader_b.U.P.Src) {
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci				return 1;
237bf215546Sopenharmony_ci			}
238bf215546Sopenharmony_ci		}
239bf215546Sopenharmony_ci	}
240bf215546Sopenharmony_ci	return 0;
241bf215546Sopenharmony_ci}
242bf215546Sopenharmony_ci
243bf215546Sopenharmony_civoid rc_variable_add_friend(
244bf215546Sopenharmony_ci	struct rc_variable * var,
245bf215546Sopenharmony_ci	struct rc_variable * friend)
246bf215546Sopenharmony_ci{
247bf215546Sopenharmony_ci	assert(var->Dst.Index == friend->Dst.Index);
248bf215546Sopenharmony_ci	while(var->Friend) {
249bf215546Sopenharmony_ci		var = var->Friend;
250bf215546Sopenharmony_ci	}
251bf215546Sopenharmony_ci	var->Friend = friend;
252bf215546Sopenharmony_ci}
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_cistruct rc_variable * rc_variable(
255bf215546Sopenharmony_ci	struct radeon_compiler * c,
256bf215546Sopenharmony_ci	unsigned int DstFile,
257bf215546Sopenharmony_ci	unsigned int DstIndex,
258bf215546Sopenharmony_ci	unsigned int DstWriteMask,
259bf215546Sopenharmony_ci	struct rc_reader_data * reader_data)
260bf215546Sopenharmony_ci{
261bf215546Sopenharmony_ci	struct rc_variable * new =
262bf215546Sopenharmony_ci			memory_pool_malloc(&c->Pool, sizeof(struct rc_variable));
263bf215546Sopenharmony_ci	memset(new, 0, sizeof(struct rc_variable));
264bf215546Sopenharmony_ci	new->C = c;
265bf215546Sopenharmony_ci	new->Dst.File = DstFile;
266bf215546Sopenharmony_ci	new->Dst.Index = DstIndex;
267bf215546Sopenharmony_ci	new->Dst.WriteMask = DstWriteMask;
268bf215546Sopenharmony_ci	if (reader_data) {
269bf215546Sopenharmony_ci		new->Inst = reader_data->Writer;
270bf215546Sopenharmony_ci		new->ReaderCount = reader_data->ReaderCount;
271bf215546Sopenharmony_ci		new->Readers = reader_data->Readers;
272bf215546Sopenharmony_ci	}
273bf215546Sopenharmony_ci	return new;
274bf215546Sopenharmony_ci}
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_cistatic void get_variable_helper(
277bf215546Sopenharmony_ci	struct rc_list ** variable_list,
278bf215546Sopenharmony_ci	struct rc_variable * variable)
279bf215546Sopenharmony_ci{
280bf215546Sopenharmony_ci	struct rc_list * list_ptr;
281bf215546Sopenharmony_ci	for (list_ptr = *variable_list; list_ptr; list_ptr = list_ptr->Next) {
282bf215546Sopenharmony_ci		struct rc_variable * var;
283bf215546Sopenharmony_ci		for (var = list_ptr->Item; var; var = var->Friend) {
284bf215546Sopenharmony_ci			if (readers_intersect(var, variable)) {
285bf215546Sopenharmony_ci				rc_variable_add_friend(var, variable);
286bf215546Sopenharmony_ci				return;
287bf215546Sopenharmony_ci			}
288bf215546Sopenharmony_ci		}
289bf215546Sopenharmony_ci	}
290bf215546Sopenharmony_ci	rc_list_add(variable_list, rc_list(&variable->C->Pool, variable));
291bf215546Sopenharmony_ci}
292bf215546Sopenharmony_ci
293bf215546Sopenharmony_cistatic void get_variable_pair_helper(
294bf215546Sopenharmony_ci	struct rc_list ** variable_list,
295bf215546Sopenharmony_ci	struct radeon_compiler * c,
296bf215546Sopenharmony_ci	struct rc_instruction * inst,
297bf215546Sopenharmony_ci	struct rc_pair_sub_instruction * sub_inst)
298bf215546Sopenharmony_ci{
299bf215546Sopenharmony_ci	struct rc_reader_data reader_data;
300bf215546Sopenharmony_ci	struct rc_variable * new_var;
301bf215546Sopenharmony_ci	rc_register_file file;
302bf215546Sopenharmony_ci	unsigned int writemask;
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci	if (sub_inst->Opcode == RC_OPCODE_NOP) {
305bf215546Sopenharmony_ci		return;
306bf215546Sopenharmony_ci	}
307bf215546Sopenharmony_ci	memset(&reader_data, 0, sizeof(struct rc_reader_data));
308bf215546Sopenharmony_ci	rc_get_readers_sub(c, inst, sub_inst, &reader_data, NULL, NULL, NULL);
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci	if (reader_data.ReaderCount == 0) {
311bf215546Sopenharmony_ci		return;
312bf215546Sopenharmony_ci	}
313bf215546Sopenharmony_ci
314bf215546Sopenharmony_ci	if (sub_inst->WriteMask) {
315bf215546Sopenharmony_ci		file = RC_FILE_TEMPORARY;
316bf215546Sopenharmony_ci		writemask = sub_inst->WriteMask;
317bf215546Sopenharmony_ci	} else if (sub_inst->OutputWriteMask) {
318bf215546Sopenharmony_ci		file = RC_FILE_OUTPUT;
319bf215546Sopenharmony_ci		writemask = sub_inst->OutputWriteMask;
320bf215546Sopenharmony_ci	} else {
321bf215546Sopenharmony_ci		writemask = 0;
322bf215546Sopenharmony_ci		file = RC_FILE_NONE;
323bf215546Sopenharmony_ci	}
324bf215546Sopenharmony_ci	new_var = rc_variable(c, file, sub_inst->DestIndex, writemask,
325bf215546Sopenharmony_ci								&reader_data);
326bf215546Sopenharmony_ci	get_variable_helper(variable_list, new_var);
327bf215546Sopenharmony_ci}
328bf215546Sopenharmony_ci
329bf215546Sopenharmony_ci/**
330bf215546Sopenharmony_ci * Compare function for sorting variable pointers by the lowest instruction
331bf215546Sopenharmony_ci * IP from it and its friends.
332bf215546Sopenharmony_ci */
333bf215546Sopenharmony_cistatic int cmpfunc_variable_by_ip (const void * a, const void * b) {
334bf215546Sopenharmony_ci	struct rc_variable * var_a = *(struct rc_variable **)a;
335bf215546Sopenharmony_ci	struct rc_variable * var_b = *(struct rc_variable **)b;
336bf215546Sopenharmony_ci	unsigned int min_ip_a = var_a->Inst->IP;
337bf215546Sopenharmony_ci	unsigned int min_ip_b = var_b->Inst->IP;
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_ci	/* Find the minimal IP of a variable and its friends */
340bf215546Sopenharmony_ci	while (var_a->Friend) {
341bf215546Sopenharmony_ci		var_a = var_a->Friend;
342bf215546Sopenharmony_ci		if (var_a->Inst->IP < min_ip_a)
343bf215546Sopenharmony_ci			min_ip_a = var_a->Inst->IP;
344bf215546Sopenharmony_ci	}
345bf215546Sopenharmony_ci	while (var_b->Friend) {
346bf215546Sopenharmony_ci		var_b = var_b->Friend;
347bf215546Sopenharmony_ci		if (var_b->Inst->IP < min_ip_b)
348bf215546Sopenharmony_ci			min_ip_b = var_b->Inst->IP;
349bf215546Sopenharmony_ci	}
350bf215546Sopenharmony_ci
351bf215546Sopenharmony_ci	return (int)min_ip_a - (int)min_ip_b;
352bf215546Sopenharmony_ci}
353bf215546Sopenharmony_ci
354bf215546Sopenharmony_ci/**
355bf215546Sopenharmony_ci * Generate a list of variables used by the shader program.  Each instruction
356bf215546Sopenharmony_ci * that writes to a register is considered a variable.  The struct rc_variable
357bf215546Sopenharmony_ci * data structure includes a list of readers and is essentially a
358bf215546Sopenharmony_ci * definition-use chain.  Any two variables that share a reader are considered
359bf215546Sopenharmony_ci * "friends" and they are linked together via the Friend attribute.
360bf215546Sopenharmony_ci */
361bf215546Sopenharmony_cistruct rc_list * rc_get_variables(struct radeon_compiler * c)
362bf215546Sopenharmony_ci{
363bf215546Sopenharmony_ci	struct rc_instruction * inst;
364bf215546Sopenharmony_ci	struct rc_list * variable_list = NULL;
365bf215546Sopenharmony_ci
366bf215546Sopenharmony_ci	/* We search for the variables in two loops in order to get it right in
367bf215546Sopenharmony_ci	 * the following specific case
368bf215546Sopenharmony_ci	 *
369bf215546Sopenharmony_ci	 * IF aluresult.x___;
370bf215546Sopenharmony_ci	 *   ...
371bf215546Sopenharmony_ci	 *   MAD temp[0].xyz, src0.000, src0.111, src0.000
372bf215546Sopenharmony_ci	 *   MAD temp[0].w, src0.0, src0.1, src0.0
373bf215546Sopenharmony_ci	 * ELSE;
374bf215546Sopenharmony_ci	 *   ...
375bf215546Sopenharmony_ci	 *   TXB temp[0], temp[1].xy_w, 2D[0] SEM_WAIT SEM_ACQUIRE;
376bf215546Sopenharmony_ci	 * ENDIF;
377bf215546Sopenharmony_ci	 * src0.xyz = input[0], src0.w = input[0], src1.xyz = temp[0], src1.w = temp[0] SEM_WAIT
378bf215546Sopenharmony_ci	 * MAD temp[1].xyz, src0.xyz, src1.xyz, src0.000
379bf215546Sopenharmony_ci	 * MAD temp[1].w, src0.w, src1.w, src0.0
380bf215546Sopenharmony_ci	 *
381bf215546Sopenharmony_ci	 * If we go just in one loop, we will first create two variables for the
382bf215546Sopenharmony_ci	 * temp[0].xyz and temp[0].w. This happens because they don't share a reader
383bf215546Sopenharmony_ci	 * as the src1.xyz and src1.w of the instruction where the value is used are
384bf215546Sopenharmony_ci	 * in theory independent. They are not because the same register is written
385bf215546Sopenharmony_ci	 * also by the texture instruction in the other branch and TEX can't write xyz
386bf215546Sopenharmony_ci	 * and w separatelly.
387bf215546Sopenharmony_ci	 *
388bf215546Sopenharmony_ci	 * Therefore first search for RC_INSTRUCTION_NORMAL to create variables from
389bf215546Sopenharmony_ci	 * the texture instruction and than the pair instructions will be properly
390bf215546Sopenharmony_ci	 * marked as friends. So we will end with only one variable here as we should.
391bf215546Sopenharmony_ci	 *
392bf215546Sopenharmony_ci	 * This doesn't matter before the pair translation, because everything is
393bf215546Sopenharmony_ci	 * RC_INSTRUCTION_NORMAL.
394bf215546Sopenharmony_ci	 */
395bf215546Sopenharmony_ci	for (inst = c->Program.Instructions.Next;
396bf215546Sopenharmony_ci					inst != &c->Program.Instructions;
397bf215546Sopenharmony_ci					inst = inst->Next) {
398bf215546Sopenharmony_ci		if (inst->Type == RC_INSTRUCTION_NORMAL) {
399bf215546Sopenharmony_ci			struct rc_reader_data reader_data;
400bf215546Sopenharmony_ci			struct rc_variable * new_var;
401bf215546Sopenharmony_ci			memset(&reader_data, 0, sizeof(reader_data));
402bf215546Sopenharmony_ci			rc_get_readers(c, inst, &reader_data, NULL, NULL, NULL);
403bf215546Sopenharmony_ci			if (reader_data.ReaderCount == 0) {
404bf215546Sopenharmony_ci				continue;
405bf215546Sopenharmony_ci			}
406bf215546Sopenharmony_ci			new_var = rc_variable(c, inst->U.I.DstReg.File,
407bf215546Sopenharmony_ci				inst->U.I.DstReg.Index,
408bf215546Sopenharmony_ci				inst->U.I.DstReg.WriteMask, &reader_data);
409bf215546Sopenharmony_ci			get_variable_helper(&variable_list, new_var);
410bf215546Sopenharmony_ci		}
411bf215546Sopenharmony_ci	}
412bf215546Sopenharmony_ci
413bf215546Sopenharmony_ci	bool needs_sorting = false;
414bf215546Sopenharmony_ci	for (inst = c->Program.Instructions.Next;
415bf215546Sopenharmony_ci					inst != &c->Program.Instructions;
416bf215546Sopenharmony_ci					inst = inst->Next) {
417bf215546Sopenharmony_ci		if (inst->Type != RC_INSTRUCTION_NORMAL) {
418bf215546Sopenharmony_ci			needs_sorting = true;
419bf215546Sopenharmony_ci			get_variable_pair_helper(&variable_list, c, inst,
420bf215546Sopenharmony_ci							&inst->U.P.RGB);
421bf215546Sopenharmony_ci			get_variable_pair_helper(&variable_list, c, inst,
422bf215546Sopenharmony_ci							&inst->U.P.Alpha);
423bf215546Sopenharmony_ci		}
424bf215546Sopenharmony_ci	}
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_ci	if (variable_list && needs_sorting) {
427bf215546Sopenharmony_ci		unsigned int count = rc_list_count(variable_list);
428bf215546Sopenharmony_ci		struct rc_variable **variables = memory_pool_malloc(&c->Pool,
429bf215546Sopenharmony_ci				sizeof(struct rc_variable *) * count);
430bf215546Sopenharmony_ci
431bf215546Sopenharmony_ci		struct rc_list * current = variable_list;
432bf215546Sopenharmony_ci		for(unsigned int i = 0; current; i++, current = current->Next) {
433bf215546Sopenharmony_ci			struct rc_variable * var = current->Item;
434bf215546Sopenharmony_ci			variables[i] = var;
435bf215546Sopenharmony_ci		}
436bf215546Sopenharmony_ci
437bf215546Sopenharmony_ci		qsort(variables, count, sizeof(struct rc_variable *), cmpfunc_variable_by_ip);
438bf215546Sopenharmony_ci
439bf215546Sopenharmony_ci		current = variable_list;
440bf215546Sopenharmony_ci		for(unsigned int i = 0; current; i++, current = current->Next) {
441bf215546Sopenharmony_ci			current->Item = variables[i];
442bf215546Sopenharmony_ci		}
443bf215546Sopenharmony_ci	}
444bf215546Sopenharmony_ci
445bf215546Sopenharmony_ci	return variable_list;
446bf215546Sopenharmony_ci}
447bf215546Sopenharmony_ci
448bf215546Sopenharmony_ci/**
449bf215546Sopenharmony_ci * @return The bitwise or of the writemasks of a variable and all of its
450bf215546Sopenharmony_ci * friends.
451bf215546Sopenharmony_ci */
452bf215546Sopenharmony_ciunsigned int rc_variable_writemask_sum(struct rc_variable * var)
453bf215546Sopenharmony_ci{
454bf215546Sopenharmony_ci	unsigned int writemask = 0;
455bf215546Sopenharmony_ci	while(var) {
456bf215546Sopenharmony_ci		writemask |= var->Dst.WriteMask;
457bf215546Sopenharmony_ci		var = var->Friend;
458bf215546Sopenharmony_ci	}
459bf215546Sopenharmony_ci	return writemask;
460bf215546Sopenharmony_ci}
461bf215546Sopenharmony_ci
462bf215546Sopenharmony_ci/*
463bf215546Sopenharmony_ci * @return A list of readers for a variable and its friends.  Readers
464bf215546Sopenharmony_ci * that read from two different variable friends are only included once in
465bf215546Sopenharmony_ci * this list.
466bf215546Sopenharmony_ci */
467bf215546Sopenharmony_cistruct rc_list * rc_variable_readers_union(struct rc_variable * var)
468bf215546Sopenharmony_ci{
469bf215546Sopenharmony_ci	struct rc_list * list = NULL;
470bf215546Sopenharmony_ci	while (var) {
471bf215546Sopenharmony_ci		unsigned int i;
472bf215546Sopenharmony_ci		for (i = 0; i < var->ReaderCount; i++) {
473bf215546Sopenharmony_ci			struct rc_list * temp;
474bf215546Sopenharmony_ci			struct rc_reader * a = &var->Readers[i];
475bf215546Sopenharmony_ci			unsigned int match = 0;
476bf215546Sopenharmony_ci			for (temp = list; temp; temp = temp->Next) {
477bf215546Sopenharmony_ci				struct rc_reader * b = temp->Item;
478bf215546Sopenharmony_ci				if (a->Inst->Type != b->Inst->Type) {
479bf215546Sopenharmony_ci					continue;
480bf215546Sopenharmony_ci				}
481bf215546Sopenharmony_ci				if (a->Inst->Type == RC_INSTRUCTION_NORMAL) {
482bf215546Sopenharmony_ci					if (a->U.I.Src == b->U.I.Src) {
483bf215546Sopenharmony_ci						match = 1;
484bf215546Sopenharmony_ci						break;
485bf215546Sopenharmony_ci					}
486bf215546Sopenharmony_ci				}
487bf215546Sopenharmony_ci				if (a->Inst->Type == RC_INSTRUCTION_PAIR) {
488bf215546Sopenharmony_ci					if (a->U.P.Arg == b->U.P.Arg
489bf215546Sopenharmony_ci					    && a->U.P.Src == b->U.P.Src) {
490bf215546Sopenharmony_ci						match = 1;
491bf215546Sopenharmony_ci						break;
492bf215546Sopenharmony_ci					}
493bf215546Sopenharmony_ci				}
494bf215546Sopenharmony_ci			}
495bf215546Sopenharmony_ci			if (match) {
496bf215546Sopenharmony_ci				continue;
497bf215546Sopenharmony_ci			}
498bf215546Sopenharmony_ci			rc_list_add(&list, rc_list(&var->C->Pool, a));
499bf215546Sopenharmony_ci		}
500bf215546Sopenharmony_ci		var = var->Friend;
501bf215546Sopenharmony_ci	}
502bf215546Sopenharmony_ci	return list;
503bf215546Sopenharmony_ci}
504bf215546Sopenharmony_ci
505bf215546Sopenharmony_cistatic unsigned int reader_equals_src(
506bf215546Sopenharmony_ci	struct rc_reader reader,
507bf215546Sopenharmony_ci	unsigned int src_type,
508bf215546Sopenharmony_ci	void * src)
509bf215546Sopenharmony_ci{
510bf215546Sopenharmony_ci	if (reader.Inst->Type != src_type) {
511bf215546Sopenharmony_ci		return 0;
512bf215546Sopenharmony_ci	}
513bf215546Sopenharmony_ci	if (src_type == RC_INSTRUCTION_NORMAL) {
514bf215546Sopenharmony_ci		return reader.U.I.Src == src;
515bf215546Sopenharmony_ci	} else {
516bf215546Sopenharmony_ci		return reader.U.P.Src == src;
517bf215546Sopenharmony_ci	}
518bf215546Sopenharmony_ci}
519bf215546Sopenharmony_ci
520bf215546Sopenharmony_cistatic unsigned int variable_writes_src(
521bf215546Sopenharmony_ci	struct rc_variable * var,
522bf215546Sopenharmony_ci	unsigned int src_type,
523bf215546Sopenharmony_ci	void * src)
524bf215546Sopenharmony_ci{
525bf215546Sopenharmony_ci	unsigned int i;
526bf215546Sopenharmony_ci	for (i = 0; i < var->ReaderCount; i++) {
527bf215546Sopenharmony_ci		if (reader_equals_src(var->Readers[i], src_type, src)) {
528bf215546Sopenharmony_ci			return 1;
529bf215546Sopenharmony_ci		}
530bf215546Sopenharmony_ci	}
531bf215546Sopenharmony_ci	return 0;
532bf215546Sopenharmony_ci}
533bf215546Sopenharmony_ci
534bf215546Sopenharmony_ci
535bf215546Sopenharmony_cistruct rc_list * rc_variable_list_get_writers(
536bf215546Sopenharmony_ci	struct rc_list * var_list,
537bf215546Sopenharmony_ci	unsigned int src_type,
538bf215546Sopenharmony_ci	void * src)
539bf215546Sopenharmony_ci{
540bf215546Sopenharmony_ci	struct rc_list * list_ptr;
541bf215546Sopenharmony_ci	struct rc_list * writer_list = NULL;
542bf215546Sopenharmony_ci	for (list_ptr = var_list; list_ptr; list_ptr = list_ptr->Next) {
543bf215546Sopenharmony_ci		struct rc_variable * var = list_ptr->Item;
544bf215546Sopenharmony_ci		if (variable_writes_src(var, src_type, src)) {
545bf215546Sopenharmony_ci			struct rc_variable * friend;
546bf215546Sopenharmony_ci			rc_list_add(&writer_list, rc_list(&var->C->Pool, var));
547bf215546Sopenharmony_ci			for (friend = var->Friend; friend;
548bf215546Sopenharmony_ci						friend = friend->Friend) {
549bf215546Sopenharmony_ci				if (variable_writes_src(friend, src_type, src)) {
550bf215546Sopenharmony_ci					rc_list_add(&writer_list,
551bf215546Sopenharmony_ci						rc_list(&var->C->Pool, friend));
552bf215546Sopenharmony_ci				}
553bf215546Sopenharmony_ci			}
554bf215546Sopenharmony_ci			/* Once we have identified the variable and its
555bf215546Sopenharmony_ci			 * friends that write this source, we can stop
556bf215546Sopenharmony_ci			 * stop searching, because we know none of the
557bf215546Sopenharmony_ci			 * other variables in the list will write this source.
558bf215546Sopenharmony_ci			 * If they did they would be friends of var.
559bf215546Sopenharmony_ci			 */
560bf215546Sopenharmony_ci			break;
561bf215546Sopenharmony_ci		}
562bf215546Sopenharmony_ci	}
563bf215546Sopenharmony_ci	return writer_list;
564bf215546Sopenharmony_ci}
565bf215546Sopenharmony_ci
566bf215546Sopenharmony_cistruct rc_list * rc_variable_list_get_writers_one_reader(
567bf215546Sopenharmony_ci	struct rc_list * var_list,
568bf215546Sopenharmony_ci	unsigned int src_type,
569bf215546Sopenharmony_ci	void * src)
570bf215546Sopenharmony_ci{
571bf215546Sopenharmony_ci	struct rc_list * writer_list =
572bf215546Sopenharmony_ci		rc_variable_list_get_writers(var_list, src_type, src);
573bf215546Sopenharmony_ci	struct rc_list * reader_list =
574bf215546Sopenharmony_ci		rc_variable_readers_union(writer_list->Item);
575bf215546Sopenharmony_ci	if (rc_list_count(reader_list) > 1) {
576bf215546Sopenharmony_ci		return NULL;
577bf215546Sopenharmony_ci	} else {
578bf215546Sopenharmony_ci		return writer_list;
579bf215546Sopenharmony_ci	}
580bf215546Sopenharmony_ci}
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_civoid rc_variable_print(struct rc_variable * var)
583bf215546Sopenharmony_ci{
584bf215546Sopenharmony_ci	unsigned int i;
585bf215546Sopenharmony_ci	while (var) {
586bf215546Sopenharmony_ci		fprintf(stderr, "%u: TEMP[%u].%u: ",
587bf215546Sopenharmony_ci			var->Inst->IP, var->Dst.Index, var->Dst.WriteMask);
588bf215546Sopenharmony_ci		for (i = 0; i < 4; i++) {
589bf215546Sopenharmony_ci			fprintf(stderr, "chan %u: start=%u end=%u ", i,
590bf215546Sopenharmony_ci					var->Live[i].Start, var->Live[i].End);
591bf215546Sopenharmony_ci		}
592bf215546Sopenharmony_ci		fprintf(stderr, "%u readers\n", var->ReaderCount);
593bf215546Sopenharmony_ci		if (var->Friend) {
594bf215546Sopenharmony_ci			fprintf(stderr, "Friend: \n\t");
595bf215546Sopenharmony_ci		}
596bf215546Sopenharmony_ci		var = var->Friend;
597bf215546Sopenharmony_ci	}
598bf215546Sopenharmony_ci}
599