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