Ejemplo n.º 1
0
static void emit_flowcontrol(struct emit_state * s, struct rc_instruction * inst)
{
	unsigned int newip;

	if (s->Code->inst_end >= s->C->max_alu_insts-1) {
		rc_error(s->C, "emit_tex: Too many instructions");
		return;
	}

	newip = ++s->Code->inst_end;

	/* Currently all loops use the same integer constant to intialize
	 * the loop variables. */
	if(!s->Code->int_constants[0]) {
		s->Code->int_constants[0] = R500_FC_INT_CONST_KR(0xff);
		s->Code->int_constant_count = 1;
	}
	s->Code->inst[newip].inst0 = R500_INST_TYPE_FC | R500_INST_ALU_WAIT;

	switch(inst->U.I.Opcode){
	struct branch_info * branch;
	struct r500_loop_info * loop;
	case RC_OPCODE_BGNLOOP:
		memory_pool_array_reserve(&s->C->Pool, struct r500_loop_info,
			s->Loops, s->CurrentLoopDepth, s->LoopsReserved, 1);

		loop = &s->Loops[s->CurrentLoopDepth++];
		memset(loop, 0, sizeof(struct r500_loop_info));
		loop->BranchDepth = s->CurrentBranchDepth;
		loop->BgnLoop = newip;

		s->Code->inst[newip].inst2 = R500_FC_OP_LOOP
			| R500_FC_JUMP_FUNC(0x00)
			| R500_FC_IGNORE_UNCOVERED
			;
		break;
	case RC_OPCODE_BRK:
		loop = &s->Loops[s->CurrentLoopDepth - 1];
		memory_pool_array_reserve(&s->C->Pool, int, loop->Brks,
					loop->BrkCount, loop->BrkReserved, 1);

		loop->Brks[loop->BrkCount++] = newip;
		s->Code->inst[newip].inst2 = R500_FC_OP_BREAKLOOP
			| R500_FC_JUMP_FUNC(0xff)
			| R500_FC_B_OP1_DECR
			| R500_FC_B_POP_CNT(
				s->CurrentBranchDepth - loop->BranchDepth)
			| R500_FC_IGNORE_UNCOVERED
			;
		break;

	case RC_OPCODE_CONT:
		loop = &s->Loops[s->CurrentLoopDepth - 1];
		memory_pool_array_reserve(&s->C->Pool, int, loop->Conts,
					loop->ContCount, loop->ContReserved, 1);
		loop->Conts[loop->ContCount++] = newip;
		s->Code->inst[newip].inst2 = R500_FC_OP_CONTINUE
			| R500_FC_JUMP_FUNC(0xff)
			| R500_FC_B_OP1_DECR
			| R500_FC_B_POP_CNT(
				s->CurrentBranchDepth -	loop->BranchDepth)
			| R500_FC_IGNORE_UNCOVERED
			;
		break;

	case RC_OPCODE_ENDLOOP:
	{
		loop = &s->Loops[s->CurrentLoopDepth - 1];
		/* Emit ENDLOOP */
		s->Code->inst[newip].inst2 = R500_FC_OP_ENDLOOP
			| R500_FC_JUMP_FUNC(0xff)
			| R500_FC_JUMP_ANY
			| R500_FC_IGNORE_UNCOVERED
			;
		/* The constant integer at index 0 is used by all loops. */
		s->Code->inst[newip].inst3 = R500_FC_INT_ADDR(0)
			| R500_FC_JUMP_ADDR(loop->BgnLoop + 1)
			;

		/* Set jump address and int constant for BGNLOOP */
		s->Code->inst[loop->BgnLoop].inst3 = R500_FC_INT_ADDR(0)
			| R500_FC_JUMP_ADDR(newip)
			;

		/* Set jump address for the BRK instructions. */
		while(loop->BrkCount--) {
			s->Code->inst[loop->Brks[loop->BrkCount]].inst3 =
						R500_FC_JUMP_ADDR(newip + 1);
		}

		/* Set jump address for CONT instructions. */
		while(loop->ContCount--) {
			s->Code->inst[loop->Conts[loop->ContCount]].inst3 =
						R500_FC_JUMP_ADDR(newip);
		}
		s->CurrentLoopDepth--;
		break;
	}
	case RC_OPCODE_IF:
		if ( s->CurrentBranchDepth >= R500_PFS_MAX_BRANCH_DEPTH_FULL) {
			rc_error(s->C, "Branch depth exceeds hardware limit");
			return;
		}
		memory_pool_array_reserve(&s->C->Pool, struct branch_info,
				s->Branches, s->CurrentBranchDepth, s->BranchesReserved, 1);

		branch = &s->Branches[s->CurrentBranchDepth++];
		branch->If = newip;
		branch->Else = -1;
		branch->Endif = -1;

		if (s->CurrentBranchDepth > s->MaxBranchDepth)
			s->MaxBranchDepth = s->CurrentBranchDepth;

		/* actual instruction is filled in at ENDIF time */
		break;
	
	case RC_OPCODE_ELSE:
		if (!s->CurrentBranchDepth) {
			rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__);
			return;
		}

		branch = &s->Branches[s->CurrentBranchDepth - 1];
		branch->Else = newip;

		/* actual instruction is filled in at ENDIF time */
		break;

	case RC_OPCODE_ENDIF:
		if (!s->CurrentBranchDepth) {
			rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__);
			return;
		}

		branch = &s->Branches[s->CurrentBranchDepth - 1];
		branch->Endif = newip;

		s->Code->inst[branch->Endif].inst2 = R500_FC_OP_JUMP
			| R500_FC_A_OP_NONE /* no address stack */
			| R500_FC_JUMP_ANY /* docs says set this, but I don't understand why */
			| R500_FC_B_OP0_DECR /* decrement branch counter if stay */
			| R500_FC_B_OP1_NONE /* no branch counter if stay */
			| R500_FC_B_POP_CNT(1)
			;
		s->Code->inst[branch->Endif].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1);
		s->Code->inst[branch->If].inst2 = R500_FC_OP_JUMP
			| R500_FC_A_OP_NONE /* no address stack */
			| R500_FC_JUMP_FUNC(0x0f) /* jump if ALU result is false */
			| R500_FC_B_OP0_INCR /* increment branch counter if stay */
			| R500_FC_IGNORE_UNCOVERED
		;

		if (branch->Else >= 0) {
			/* increment branch counter also if jump */
			s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_INCR;
			s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Else + 1);

			s->Code->inst[branch->Else].inst2 = R500_FC_OP_JUMP
				| R500_FC_A_OP_NONE /* no address stack */
				| R500_FC_B_ELSE /* all active pixels want to jump */
				| R500_FC_B_OP0_NONE /* no counter op if stay */
				| R500_FC_B_OP1_DECR /* decrement branch counter if jump */
				| R500_FC_B_POP_CNT(1)
			;
			s->Code->inst[branch->Else].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1);
		} else {
			/* don't touch branch counter on jump */
			s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_NONE;
			s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1);
		}


		s->CurrentBranchDepth--;
		break;
	default:
		rc_error(s->C, "%s: unknown opcode %s\n", __FUNCTION__, rc_get_opcode_info(inst->U.I.Opcode)->Name);
	}
}
Ejemplo n.º 2
0
static void emit_flowcontrol(struct emit_state * s, struct rc_instruction * inst)
{
	if (s->Code->inst_end >= 511) {
		rc_error(s->C, "emit_tex: Too many instructions");
		return;
	}

	unsigned int newip = ++s->Code->inst_end;

	s->Code->inst[newip].inst0 = R500_INST_TYPE_FC | R500_INST_ALU_WAIT;

	if (inst->U.I.Opcode == RC_OPCODE_IF) {
		if (s->CurrentBranchDepth >= 32) {
			rc_error(s->C, "Branch depth exceeds hardware limit");
			return;
		}

		if (s->CurrentBranchDepth >= s->BranchesReserved)
			grow_branches(s);

		struct branch_info * branch = &s->Branches[s->CurrentBranchDepth++];
		branch->If = newip;
		branch->Else = -1;
		branch->Endif = -1;

		if (s->CurrentBranchDepth > s->MaxBranchDepth)
			s->MaxBranchDepth = s->CurrentBranchDepth;

		/* actual instruction is filled in at ENDIF time */
	} else if (inst->U.I.Opcode == RC_OPCODE_ELSE) {
		if (!s->CurrentBranchDepth) {
			rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__);
			return;
		}

		struct branch_info * branch = &s->Branches[s->CurrentBranchDepth - 1];
		branch->Else = newip;

		/* actual instruction is filled in at ENDIF time */
	} else if (inst->U.I.Opcode == RC_OPCODE_ENDIF) {
		if (!s->CurrentBranchDepth) {
			rc_error(s->C, "%s: got ELSE outside a branch", __FUNCTION__);
			return;
		}

		struct branch_info * branch = &s->Branches[s->CurrentBranchDepth - 1];
		branch->Endif = newip;

		s->Code->inst[branch->If].inst2 = R500_FC_OP_JUMP
			| R500_FC_A_OP_NONE /* no address stack */
			| R500_FC_JUMP_FUNC(0x0f) /* jump if ALU result is false */
			| R500_FC_B_OP0_INCR /* increment branch counter if stay */
		;

		if (branch->Else >= 0) {
			/* increment branch counter also if jump */
			s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_INCR;
			s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Else + 1);

			s->Code->inst[branch->Else].inst2 = R500_FC_OP_JUMP
				| R500_FC_A_OP_NONE /* no address stack */
				| R500_FC_B_ELSE /* all active pixels want to jump */
				| R500_FC_B_OP0_NONE /* no counter op if stay */
				| R500_FC_B_OP1_DECR /* decrement branch counter if jump */
				| R500_FC_B_POP_CNT(1)
			;
			s->Code->inst[branch->Else].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1);
		} else {
			/* don't touch branch counter on jump */
			s->Code->inst[branch->If].inst2 |= R500_FC_B_OP1_NONE;
			s->Code->inst[branch->If].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1);
		}

		s->Code->inst[branch->Endif].inst2 = R500_FC_OP_JUMP
			| R500_FC_A_OP_NONE /* no address stack */
			| R500_FC_JUMP_ANY /* docs says set this, but I don't understand why */
			| R500_FC_B_OP0_DECR /* decrement branch counter if stay */
			| R500_FC_B_OP1_NONE /* no branch counter if stay */
			| R500_FC_B_POP_CNT(1)
		;
		s->Code->inst[branch->Endif].inst3 = R500_FC_JUMP_ADDR(branch->Endif + 1);

		s->CurrentBranchDepth--;
	} else {
		rc_error(s->C, "%s: unknown opcode %i\n", __FUNCTION__, inst->U.I.Opcode);
	}
}