1
2#include "radeon_compiler.h"
3#include "radeon_compiler_util.h"
4#include "radeon_dataflow.h"
5#include "radeon_program.h"
6#include "radeon_program_constants.h"
7
8struct vert_fc_state {
9	struct radeon_compiler *C;
10	unsigned BranchDepth;
11	unsigned LoopDepth;
12	unsigned LoopsReserved;
13	int PredStack[R500_PVS_MAX_LOOP_DEPTH];
14	int PredicateReg;
15	unsigned InCFBreak;
16};
17
18static void build_pred_src(
19	struct rc_src_register * src,
20	struct vert_fc_state * fc_state)
21{
22	src->Swizzle = RC_MAKE_SWIZZLE(RC_SWIZZLE_UNUSED, RC_SWIZZLE_UNUSED,
23					RC_SWIZZLE_UNUSED, RC_SWIZZLE_W);
24	src->File = RC_FILE_TEMPORARY;
25	src->Index = fc_state->PredicateReg;
26}
27
28static void build_pred_dst(
29	struct rc_dst_register * dst,
30	struct vert_fc_state * fc_state)
31{
32	dst->WriteMask = RC_MASK_W;
33	dst->File = RC_FILE_TEMPORARY;
34	dst->Index = fc_state->PredicateReg;
35}
36
37static void mark_write(void * userdata,	struct rc_instruction * inst,
38		rc_register_file file,	unsigned int index, unsigned int mask)
39{
40	unsigned int * writemasks = userdata;
41
42	if (file != RC_FILE_TEMPORARY)
43		return;
44
45	if (index >= R300_VS_MAX_TEMPS)
46		return;
47
48	writemasks[index] |= mask;
49}
50
51static int reserve_predicate_reg(struct vert_fc_state * fc_state)
52{
53	int i;
54	unsigned int writemasks[RC_REGISTER_MAX_INDEX];
55	struct rc_instruction * inst;
56	memset(writemasks, 0, sizeof(writemasks));
57	for(inst = fc_state->C->Program.Instructions.Next;
58				inst != &fc_state->C->Program.Instructions;
59				inst = inst->Next) {
60		rc_for_all_writes_mask(inst, mark_write, writemasks);
61	}
62
63	for(i = 0; i < fc_state->C->max_temp_regs; i++) {
64		/* Most of the control flow instructions only write the
65		 * W component of the Predicate Register, but
66		 * the docs say that ME_PRED_SET_CLR and
67		 * ME_PRED_SET_RESTORE write all components of the
68		 * register, so we must reserve a register that has
69		 * all its components free. */
70		if (!writemasks[i]) {
71			fc_state->PredicateReg = i;
72			break;
73		}
74	}
75	if (i == fc_state->C->max_temp_regs) {
76		rc_error(fc_state->C, "No free temporary to use for"
77				" predicate stack counter.\n");
78		return -1;
79	}
80	return 1;
81}
82
83static void lower_bgnloop(
84	struct rc_instruction * inst,
85	struct vert_fc_state * fc_state)
86{
87	struct rc_instruction * new_inst =
88			rc_insert_new_instruction(fc_state->C, inst->Prev);
89
90	if ((!fc_state->C->is_r500
91		&& fc_state->LoopsReserved >= R300_VS_MAX_LOOP_DEPTH)
92	     || fc_state->LoopsReserved >= R500_PVS_MAX_LOOP_DEPTH) {
93		rc_error(fc_state->C, "Loops are nested too deep.");
94		return;
95	}
96
97	if (fc_state->LoopDepth == 0 && fc_state->BranchDepth == 0) {
98		if (fc_state->PredicateReg == -1) {
99			if (reserve_predicate_reg(fc_state) == -1) {
100				return;
101			}
102		}
103
104		/* Initialize the predicate bit to true. */
105		new_inst->U.I.Opcode = RC_ME_PRED_SEQ;
106		build_pred_dst(&new_inst->U.I.DstReg, fc_state);
107		new_inst->U.I.SrcReg[0].Index = 0;
108		new_inst->U.I.SrcReg[0].File = RC_FILE_NONE;
109		new_inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_0000;
110	} else {
111		fc_state->PredStack[fc_state->LoopDepth] =
112						fc_state->PredicateReg;
113		/* Copy the the current predicate value to this loop's
114		 * predicate register */
115
116		/* Use the old predicate value for src0 */
117		build_pred_src(&new_inst->U.I.SrcReg[0], fc_state);
118
119		/* Reserve this loop's predicate register */
120		if (reserve_predicate_reg(fc_state) == -1) {
121			return;
122		}
123
124		/* Copy the old predicate value to the new register */
125		new_inst->U.I.Opcode = RC_OPCODE_ADD;
126		build_pred_dst(&new_inst->U.I.DstReg, fc_state);
127		new_inst->U.I.SrcReg[1].Index = 0;
128		new_inst->U.I.SrcReg[1].File = RC_FILE_NONE;
129		new_inst->U.I.SrcReg[1].Swizzle = RC_SWIZZLE_0000;
130	}
131
132}
133
134static void lower_brk(
135	struct rc_instruction * inst,
136	struct vert_fc_state * fc_state)
137{
138	if (fc_state->LoopDepth == 1) {
139		inst->U.I.Opcode = RC_OPCODE_RCP;
140		inst->U.I.DstReg.Pred = RC_PRED_INV;
141		inst->U.I.SrcReg[0].Index = 0;
142		inst->U.I.SrcReg[0].File = RC_FILE_NONE;
143		inst->U.I.SrcReg[0].Swizzle = RC_SWIZZLE_0000;
144	} else {
145		inst->U.I.Opcode = RC_ME_PRED_SET_CLR;
146		inst->U.I.DstReg.Pred = RC_PRED_SET;
147	}
148
149	build_pred_dst(&inst->U.I.DstReg, fc_state);
150}
151
152static void lower_endloop(
153	struct rc_instruction * inst,
154	struct vert_fc_state * fc_state)
155{
156	struct rc_instruction * new_inst =
157			rc_insert_new_instruction(fc_state->C, inst);
158
159	new_inst->U.I.Opcode = RC_ME_PRED_SET_RESTORE;
160	build_pred_dst(&new_inst->U.I.DstReg, fc_state);
161	/* Restore the previous predicate register. */
162	fc_state->PredicateReg = fc_state->PredStack[fc_state->LoopDepth - 1];
163	build_pred_src(&new_inst->U.I.SrcReg[0], fc_state);
164}
165
166static void lower_if(
167	struct rc_instruction * inst,
168	struct vert_fc_state * fc_state)
169{
170	/* Reserve a temporary to use as our predicate stack counter, if we
171	 * don't already have one. */
172	if (fc_state->PredicateReg == -1) {
173		/* If we are inside a loop, the Predicate Register should
174		 * have already been defined. */
175		assert(fc_state->LoopDepth == 0);
176
177		if (reserve_predicate_reg(fc_state) == -1) {
178			return;
179		}
180	}
181
182	if (inst->Next->U.I.Opcode == RC_OPCODE_BRK) {
183		fc_state->InCFBreak = 1;
184	}
185	if ((fc_state->BranchDepth == 0 && fc_state->LoopDepth == 0)
186			|| (fc_state->LoopDepth == 1 && fc_state->InCFBreak)) {
187		if (fc_state->InCFBreak) {
188			inst->U.I.Opcode = RC_ME_PRED_SEQ;
189			inst->U.I.DstReg.Pred = RC_PRED_SET;
190		} else {
191			inst->U.I.Opcode = RC_ME_PRED_SNEQ;
192		}
193	} else {
194		unsigned swz;
195		inst->U.I.Opcode = RC_VE_PRED_SNEQ_PUSH;
196		memcpy(&inst->U.I.SrcReg[1], &inst->U.I.SrcReg[0],
197						sizeof(inst->U.I.SrcReg[1]));
198		swz = rc_get_scalar_src_swz(inst->U.I.SrcReg[1].Swizzle);
199		/* VE_PRED_SNEQ_PUSH needs to the branch condition to be in the
200		 * w component */
201		inst->U.I.SrcReg[1].Swizzle = RC_MAKE_SWIZZLE(RC_SWIZZLE_UNUSED,
202				RC_SWIZZLE_UNUSED, RC_SWIZZLE_UNUSED, swz);
203		build_pred_src(&inst->U.I.SrcReg[0], fc_state);
204	}
205	build_pred_dst(&inst->U.I.DstReg, fc_state);
206}
207
208void rc_vert_fc(struct radeon_compiler *c, void *user)
209{
210	struct rc_instruction * inst;
211	struct vert_fc_state fc_state;
212
213	memset(&fc_state, 0, sizeof(fc_state));
214	fc_state.PredicateReg = -1;
215	fc_state.C = c;
216
217	for(inst = c->Program.Instructions.Next;
218					inst != &c->Program.Instructions;
219					inst = inst->Next) {
220
221		switch (inst->U.I.Opcode) {
222
223		case RC_OPCODE_BGNLOOP:
224			lower_bgnloop(inst, &fc_state);
225			fc_state.LoopDepth++;
226			break;
227
228		case RC_OPCODE_BRK:
229			lower_brk(inst, &fc_state);
230			break;
231
232		case RC_OPCODE_ENDLOOP:
233			if (fc_state.BranchDepth != 0
234					|| fc_state.LoopDepth != 1) {
235				lower_endloop(inst, &fc_state);
236			}
237			fc_state.LoopDepth--;
238			/* Skip PRED_RESTORE */
239			inst = inst->Next;
240			break;
241		case RC_OPCODE_IF:
242			lower_if(inst, &fc_state);
243			fc_state.BranchDepth++;
244			break;
245
246		case RC_OPCODE_ELSE:
247			inst->U.I.Opcode = RC_ME_PRED_SET_INV;
248			build_pred_dst(&inst->U.I.DstReg, &fc_state);
249			build_pred_src(&inst->U.I.SrcReg[0], &fc_state);
250			break;
251
252		case RC_OPCODE_ENDIF:
253			if (fc_state.LoopDepth == 1 && fc_state.InCFBreak) {
254				struct rc_instruction * to_delete = inst;
255				inst = inst->Prev;
256				rc_remove_instruction(to_delete);
257				/* XXX: Delete the endif instruction */
258			} else {
259				inst->U.I.Opcode = RC_ME_PRED_SET_POP;
260				build_pred_dst(&inst->U.I.DstReg, &fc_state);
261				build_pred_src(&inst->U.I.SrcReg[0], &fc_state);
262			}
263			fc_state.InCFBreak = 0;
264			fc_state.BranchDepth--;
265			break;
266
267		default:
268			if (fc_state.BranchDepth || fc_state.LoopDepth) {
269				inst->U.I.DstReg.Pred = RC_PRED_SET;
270			}
271			break;
272		}
273
274		if (c->Error) {
275			return;
276		}
277	}
278}
279