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