static unsigned int loop_max_possible_iterations(struct radeon_compiler *c,
			struct loop_info * loop)
{
	unsigned int total_i = rc_recompute_ips(c);
	unsigned int loop_i = (loop->EndLoop->IP - loop->BeginLoop->IP) - 1;
	/* +1 because the program already has one iteration of the loop. */
	return 1 + ((c->max_alu_insts - total_i) / loop_i);
}
static void compute_live_intervals(struct regalloc_state * s)
{
	rc_recompute_ips(s->C);

	for(struct rc_instruction * inst = s->C->Program.Instructions.Next;
	    inst != &s->C->Program.Instructions;
	    inst = inst->Next) {
		rc_for_all_reads(inst, scan_callback, s);
		rc_for_all_writes(inst, scan_callback, s);
	}
}
/**
 * This function renames registers in an attempt to get the code close to
 * SSA form.  After this function has completed, most of the register are only
 * written to one time, with a few exceptions.
 *
 * This function assumes all the instructions are still of type
 * RC_INSTRUCTION_NORMAL.
 */
void rc_rename_regs(struct radeon_compiler *c, void *user)
{
	unsigned int i, used_length;
	int new_index;
	struct rc_instruction * inst;
	struct rc_reader_data reader_data;
	unsigned char * used;

	/* XXX Remove this once the register allocation works with flow control. */
	for(inst = c->Program.Instructions.Next;
					inst != &c->Program.Instructions;
					inst = inst->Next) {
		if (inst->U.I.Opcode == RC_OPCODE_BGNLOOP)
			return;
	}

	used_length = 2 * rc_recompute_ips(c);
	used = memory_pool_malloc(&c->Pool, sizeof(unsigned char) * used_length);
	memset(used, 0, sizeof(unsigned char) * used_length);

	rc_get_used_temporaries(c, used, used_length);
	for(inst = c->Program.Instructions.Next;
					inst != &c->Program.Instructions;
					inst = inst->Next) {

		if (inst->U.I.DstReg.File != RC_FILE_TEMPORARY)
			continue;

		reader_data.ExitOnAbort = 1;
		rc_get_readers(c, inst, &reader_data, NULL, NULL, NULL);

		if (reader_data.Abort || reader_data.ReaderCount == 0)
			continue;

		new_index = rc_find_free_temporary_list(c, used, used_length,
						RC_MASK_XYZW);
		if (new_index < 0) {
			rc_error(c, "Ran out of temporary registers\n");
			return;
		}

		reader_data.Writer->U.I.DstReg.Index = new_index;
		for(i = 0; i < reader_data.ReaderCount; i++) {
			reader_data.Readers[i].U.I.Src->Index = new_index;
		}
	}
}
static void compute_live_intervals(struct radeon_compiler *c,
				   struct regalloc_state *s)
{
	memset(s, 0, sizeof(*s));
	s->C = c;
	s->NumHwTemporaries = c->max_temp_regs;
	s->HwTemporary =
		memory_pool_malloc(&c->Pool,
				   s->NumHwTemporaries * sizeof(struct hardware_register));
	memset(s->HwTemporary, 0, s->NumHwTemporaries * sizeof(struct hardware_register));

	rc_recompute_ips(s->C);

	for(struct rc_instruction * inst = s->C->Program.Instructions.Next;
	    inst != &s->C->Program.Instructions;
	    inst = inst->Next) {

		/* For all instructions inside of a loop, the ENDLOOP
		 * instruction is used as the end of the live interval. */
		if (inst->U.I.Opcode == RC_OPCODE_BGNLOOP && !s->end_loop) {
			int loops = 1;
			struct rc_instruction * tmp;
			for(tmp = inst->Next;
					tmp != &s->C->Program.Instructions;
					tmp = tmp->Next) {
				if (tmp->U.I.Opcode == RC_OPCODE_BGNLOOP) {
					loops++;
				} else if (tmp->U.I.Opcode
							== RC_OPCODE_ENDLOOP) {
					if(!--loops) {
						s->end_loop = tmp->IP;
						break;
					}
				}
			}
		}

		if (inst->IP == s->end_loop)
			s->end_loop = 0;

		rc_for_all_reads_mask(inst, scan_callback, s);
		rc_for_all_writes_mask(inst, scan_callback, s);
	}
}
Beispiel #5
0
static void allocate_temporary_registers(struct radeon_compiler *c, void *user)
{
	struct r300_vertex_program_compiler *compiler = (struct r300_vertex_program_compiler*)c;
	struct rc_instruction *inst;
	struct rc_instruction *end_loop = NULL;
	unsigned int num_orig_temps = 0;
	char hwtemps[RC_REGISTER_MAX_INDEX];
	struct temporary_allocation * ta;
	unsigned int i, j;

	memset(hwtemps, 0, sizeof(hwtemps));

	rc_recompute_ips(c);

	/* Pass 1: Count original temporaries. */
	for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) {
		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);

		for (i = 0; i < opcode->NumSrcRegs; ++i) {
			if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) {
				if (inst->U.I.SrcReg[i].Index >= num_orig_temps)
					num_orig_temps = inst->U.I.SrcReg[i].Index + 1;
			}
		}

		if (opcode->HasDstReg) {
			if (inst->U.I.DstReg.File == RC_FILE_TEMPORARY) {
				if (inst->U.I.DstReg.Index >= num_orig_temps)
					num_orig_temps = inst->U.I.DstReg.Index + 1;
			}
		}
	}

	ta = (struct temporary_allocation*)memory_pool_malloc(&compiler->Base.Pool,
			sizeof(struct temporary_allocation) * num_orig_temps);
	memset(ta, 0, sizeof(struct temporary_allocation) * num_orig_temps);

	/* Pass 2: Determine original temporary lifetimes */
	for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) {
		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);
		/* Instructions inside of loops need to use the ENDLOOP
		 * instruction as their LastRead. */
		if (!end_loop && inst->U.I.Opcode == RC_OPCODE_BGNLOOP) {
			int endloops = 1;
			struct rc_instruction * ptr;
			for(ptr = inst->Next;
				ptr != &compiler->Base.Program.Instructions;
							ptr = ptr->Next){
				if (ptr->U.I.Opcode == RC_OPCODE_BGNLOOP) {
					endloops++;
				} else if (ptr->U.I.Opcode == RC_OPCODE_ENDLOOP) {
					endloops--;
					if (endloops <= 0) {
						end_loop = ptr;
						break;
					}
				}
			}
		}

		if (inst == end_loop) {
			end_loop = NULL;
			continue;
		}

		for (i = 0; i < opcode->NumSrcRegs; ++i) {
			if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) {
				ta[inst->U.I.SrcReg[i].Index].LastRead = end_loop ? end_loop : inst;
			}
		}
	}

	/* Pass 3: Register allocation */
	for(inst = compiler->Base.Program.Instructions.Next; inst != &compiler->Base.Program.Instructions; inst = inst->Next) {
		const struct rc_opcode_info * opcode = rc_get_opcode_info(inst->U.I.Opcode);

		for (i = 0; i < opcode->NumSrcRegs; ++i) {
			if (inst->U.I.SrcReg[i].File == RC_FILE_TEMPORARY) {
				unsigned int orig = inst->U.I.SrcReg[i].Index;
				inst->U.I.SrcReg[i].Index = ta[orig].HwTemp;

				if (ta[orig].Allocated && inst == ta[orig].LastRead)
					hwtemps[ta[orig].HwTemp] = 0;
			}
		}

		if (opcode->HasDstReg) {
			if (inst->U.I.DstReg.File == RC_FILE_TEMPORARY) {
				unsigned int orig = inst->U.I.DstReg.Index;

				if (!ta[orig].Allocated) {
					for(j = 0; j < c->max_temp_regs; ++j) {
						if (!hwtemps[j])
							break;
					}
					ta[orig].Allocated = 1;
					ta[orig].HwTemp = j;
					hwtemps[ta[orig].HwTemp] = 1;
				}

				inst->U.I.DstReg.Index = ta[orig].HwTemp;
			}
		}
	}
}