Home | History | Annotate | Download | only in compiler
      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 
      8 struct 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 
     18 static 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 
     28 static 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 
     37 static 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 
     51 static 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 
     83 static 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 
    134 static 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 
    152 static 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 
    166 static 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 
    208 void 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