Home | History | Annotate | Download | only in compiler
      1 /*
      2  * Copyright (C) 2008-2009 Nicolai Haehnle.
      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_program_pair.h"
     29 
     30 #include "radeon_compiler_util.h"
     31 
     32 #include <stdlib.h>
     33 
     34 /**
     35  * Return the source slot where we installed the given register access,
     36  * or -1 if no slot was free anymore.
     37  */
     38 int rc_pair_alloc_source(struct rc_pair_instruction *pair,
     39 	unsigned int rgb, unsigned int alpha,
     40 	rc_register_file file, unsigned int index)
     41 {
     42 	int candidate = -1;
     43 	int candidate_quality = -1;
     44 	unsigned int alpha_used = 0;
     45 	unsigned int rgb_used = 0;
     46 	int i;
     47 
     48 	if ((!rgb && !alpha) || file == RC_FILE_NONE)
     49 		return 0;
     50 
     51 	/* Make sure only one presubtract operation is used per instruction. */
     52 	if (file == RC_FILE_PRESUB) {
     53 		if (rgb && pair->RGB.Src[RC_PAIR_PRESUB_SRC].Used
     54 			&& index != pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index) {
     55 				return -1;
     56 		}
     57 
     58 		if (alpha && pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Used
     59 			&& index != pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) {
     60 				return -1;
     61 		}
     62 	}
     63 
     64 	for(i = 0; i < 3; ++i) {
     65 		int q = 0;
     66 		if (rgb) {
     67 			if (pair->RGB.Src[i].Used) {
     68 				if (pair->RGB.Src[i].File != file ||
     69 				    pair->RGB.Src[i].Index != index) {
     70 					rgb_used++;
     71 					continue;
     72 				}
     73 				q++;
     74 			}
     75 		}
     76 		if (alpha) {
     77 			if (pair->Alpha.Src[i].Used) {
     78 				if (pair->Alpha.Src[i].File != file ||
     79 				    pair->Alpha.Src[i].Index != index) {
     80 					alpha_used++;
     81 					continue;
     82 				}
     83 				q++;
     84 			}
     85 		}
     86 		if (q > candidate_quality) {
     87 			candidate_quality = q;
     88 			candidate = i;
     89 		}
     90 	}
     91 
     92 	if (file == RC_FILE_PRESUB) {
     93 		candidate = RC_PAIR_PRESUB_SRC;
     94 	} else if (candidate < 0 || (rgb && rgb_used > 2)
     95 			|| (alpha && alpha_used > 2)) {
     96 		return -1;
     97 	}
     98 
     99 	/* candidate >= 0 */
    100 
    101 	if (rgb) {
    102 		pair->RGB.Src[candidate].Used = 1;
    103 		pair->RGB.Src[candidate].File = file;
    104 		pair->RGB.Src[candidate].Index = index;
    105 		if (candidate == RC_PAIR_PRESUB_SRC) {
    106 			/* For registers with the RC_FILE_PRESUB file,
    107 			 * the index stores the presubtract op. */
    108 			int src_regs = rc_presubtract_src_reg_count(index);
    109 			for(i = 0; i < src_regs; i++) {
    110 				pair->RGB.Src[i].Used = 1;
    111 			}
    112 		}
    113 	}
    114 	if (alpha) {
    115 		pair->Alpha.Src[candidate].Used = 1;
    116 		pair->Alpha.Src[candidate].File = file;
    117 		pair->Alpha.Src[candidate].Index = index;
    118 		if (candidate == RC_PAIR_PRESUB_SRC) {
    119 			/* For registers with the RC_FILE_PRESUB file,
    120 			 * the index stores the presubtract op. */
    121 			int src_regs = rc_presubtract_src_reg_count(index);
    122 			for(i=0; i < src_regs; i++) {
    123 				pair->Alpha.Src[i].Used = 1;
    124 			}
    125 		}
    126 	}
    127 
    128 	return candidate;
    129 }
    130 
    131 static void pair_foreach_source_callback(
    132 	struct rc_pair_instruction * pair,
    133 	void * data,
    134 	rc_pair_foreach_src_fn cb,
    135 	unsigned int swz,
    136 	unsigned int src)
    137 {
    138 	/* swz > 3 means that the swizzle is either not used, or a constant
    139 	 * swizzle (e.g. 0, 1, 0.5). */
    140 	if(swz > 3)
    141 		return;
    142 
    143 	if(swz == RC_SWIZZLE_W) {
    144 		if (src == RC_PAIR_PRESUB_SRC) {
    145 			unsigned int i;
    146 			unsigned int src_count = rc_presubtract_src_reg_count(
    147 				pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index);
    148 			for(i = 0; i < src_count; i++) {
    149 				cb(data, &pair->Alpha.Src[i]);
    150 			}
    151 		} else {
    152 			cb(data, &pair->Alpha.Src[src]);
    153 		}
    154 	} else {
    155 		if (src == RC_PAIR_PRESUB_SRC) {
    156 			unsigned int i;
    157 			unsigned int src_count = rc_presubtract_src_reg_count(
    158 				pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index);
    159 			for(i = 0; i < src_count; i++) {
    160 				cb(data, &pair->RGB.Src[i]);
    161 			}
    162 		}
    163 		else {
    164 			cb(data, &pair->RGB.Src[src]);
    165 		}
    166 	}
    167 }
    168 
    169 void rc_pair_foreach_source_that_alpha_reads(
    170 	struct rc_pair_instruction * pair,
    171 	void * data,
    172 	rc_pair_foreach_src_fn cb)
    173 {
    174 	unsigned int i;
    175 	const struct rc_opcode_info * info =
    176 				rc_get_opcode_info(pair->Alpha.Opcode);
    177 	for(i = 0; i < info->NumSrcRegs; i++) {
    178 		pair_foreach_source_callback(pair, data, cb,
    179 					GET_SWZ(pair->Alpha.Arg[i].Swizzle, 0),
    180 					pair->Alpha.Arg[i].Source);
    181 	}
    182 }
    183 
    184 void rc_pair_foreach_source_that_rgb_reads(
    185 	struct rc_pair_instruction * pair,
    186 	void * data,
    187 	rc_pair_foreach_src_fn cb)
    188 {
    189 	unsigned int i;
    190 	const struct rc_opcode_info * info =
    191 				rc_get_opcode_info(pair->RGB.Opcode);
    192 	for(i = 0; i < info->NumSrcRegs; i++) {
    193 		unsigned int chan;
    194 		unsigned int swz = RC_SWIZZLE_UNUSED;
    195 		/* Find a swizzle that is either X,Y,Z,or W.  We assume here
    196 		 * that if one channel swizzles X,Y, or Z, then none of the
    197 		 * other channels swizzle W, and vice-versa. */
    198 		for(chan = 0; chan < 4; chan++) {
    199 			swz = GET_SWZ(pair->RGB.Arg[i].Swizzle, chan);
    200 			if(swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y
    201 			|| swz == RC_SWIZZLE_Z || swz == RC_SWIZZLE_W)
    202 				continue;
    203 		}
    204 		pair_foreach_source_callback(pair, data, cb,
    205 					swz,
    206 					pair->RGB.Arg[i].Source);
    207 	}
    208 }
    209 
    210 struct rc_pair_instruction_source * rc_pair_get_src(
    211 	struct rc_pair_instruction * pair_inst,
    212 	struct rc_pair_instruction_arg * arg)
    213 {
    214 	unsigned int type;
    215 
    216 	type = rc_source_type_swz(arg->Swizzle);
    217 
    218 	if (type & RC_SOURCE_RGB) {
    219 		return &pair_inst->RGB.Src[arg->Source];
    220 	} else if (type & RC_SOURCE_ALPHA) {
    221 		return &pair_inst->Alpha.Src[arg->Source];
    222 	} else {
    223 		return NULL;
    224 	}
    225 }
    226 
    227 int rc_pair_get_src_index(
    228 	struct rc_pair_instruction * pair_inst,
    229 	struct rc_pair_instruction_source * src)
    230 {
    231 	int i;
    232 	for (i = 0; i < 3; i++) {
    233 		if (&pair_inst->RGB.Src[i] == src
    234 			|| &pair_inst->Alpha.Src[i] == src) {
    235 			return i;
    236 		}
    237 	}
    238 	return -1;
    239 }
    240