/** * This function implements "Linear Scan Register Allocation" to reduce * the number of temporary registers used by the program. * * We compute the "live interval" for all temporary registers then * examine the overlap of the intervals to allocate new registers. * Basically, if two intervals do not overlap, they can use the same register. */ static void _mesa_reallocate_registers(struct gl_program *prog) { struct interval_list liveIntervals; GLint registerMap[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; GLboolean usedRegs[REG_ALLOCATE_MAX_PROGRAM_TEMPS]; GLuint i; GLint maxTemp = -1; if (dbg) { printf("Optimize: Begin live-interval register reallocation\n"); _mesa_print_program(prog); } for (i = 0; i < REG_ALLOCATE_MAX_PROGRAM_TEMPS; i++){ registerMap[i] = -1; usedRegs[i] = GL_FALSE; } if (!find_live_intervals(prog, &liveIntervals)) { if (dbg) printf("Aborting register reallocation\n"); return; } { struct interval_list activeIntervals; activeIntervals.Num = 0; /* loop over live intervals, allocating a new register for each */ for (i = 0; i < liveIntervals.Num; i++) { const struct interval *live = liveIntervals.Intervals + i; if (dbg) printf("Consider register %u\n", live->Reg); /* Expire old intervals. Intervals which have ended with respect * to the live interval can have their remapped registers freed. */ { GLint j; for (j = 0; j < (GLint) activeIntervals.Num; j++) { const struct interval *inv = activeIntervals.Intervals + j; if (inv->End >= live->Start) { /* Stop now. Since the activeInterval list is sorted * we know we don't have to go further. */ break; } else { /* Interval 'inv' has expired */ const GLint regNew = registerMap[inv->Reg]; ASSERT(regNew >= 0); if (dbg) printf(" expire interval for reg %u\n", inv->Reg); /* remove interval j from active list */ remove_interval(&activeIntervals, inv); j--; /* counter-act j++ in for-loop above */ /* return register regNew to the free pool */ if (dbg) printf(" free reg %d\n", regNew); ASSERT(usedRegs[regNew] == GL_TRUE); usedRegs[regNew] = GL_FALSE; } } } /* find a free register for this live interval */ { const GLint k = alloc_register(usedRegs); if (k < 0) { /* out of registers, give up */ return; } registerMap[live->Reg] = k; maxTemp = MAX2(maxTemp, k); if (dbg) printf(" remap register %u -> %d\n", live->Reg, k); } /* Insert this live interval into the active list which is sorted * by increasing end points. */ insert_interval_by_end(&activeIntervals, live); } } if (maxTemp + 1 < (GLint) liveIntervals.Num) { /* OK, we've reduced the number of registers needed. * Scan the program and replace all the old temporary register * indexes with the new indexes. */ replace_regs(prog, PROGRAM_TEMPORARY, registerMap); prog->NumTemporaries = maxTemp + 1; } if (dbg) { printf("Optimize: End live-interval register reallocation\n"); printf("Num temp regs before: %u after: %u\n", liveIntervals.Num, maxTemp + 1); _mesa_print_program(prog); } }
/** * Consolidate temporary registers to use low numbers. For example, if the * shader only uses temps 4, 5, 8, replace them with 0, 1, 2. */ static void _mesa_consolidate_registers(struct gl_program *prog) { GLboolean tempUsed[MAX_PROGRAM_TEMPS]; GLint tempMap[MAX_PROGRAM_TEMPS]; GLuint tempMax = 0, i; if (dbg) { _mesa_printf("Optimize: Begin register consolidation\n"); } memset(tempUsed, 0, sizeof(tempUsed)); for (i = 0; i < MAX_PROGRAM_TEMPS; i++) { tempMap[i] = -1; } /* set tempUsed[i] if temporary [i] is referenced */ for (i = 0; i < prog->NumInstructions; i++) { const struct prog_instruction *inst = prog->Instructions + i; const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode); GLuint j; for (j = 0; j < numSrc; j++) { if (inst->SrcReg[j].File == PROGRAM_TEMPORARY) { const GLuint index = inst->SrcReg[j].Index; ASSERT(index < MAX_PROGRAM_TEMPS); tempUsed[index] = GL_TRUE; tempMax = MAX2(tempMax, index); break; } } if (inst->DstReg.File == PROGRAM_TEMPORARY) { const GLuint index = inst->DstReg.Index; ASSERT(index < MAX_PROGRAM_TEMPS); tempUsed[index] = GL_TRUE; tempMax = MAX2(tempMax, index); } } /* allocate a new index for each temp that's used */ { GLuint freeTemp = 0; for (i = 0; i <= tempMax; i++) { if (tempUsed[i]) { tempMap[i] = freeTemp++; /*_mesa_printf("replace %u with %u\n", i, tempMap[i]);*/ } } if (freeTemp == tempMax + 1) { /* no consolidation possible */ return; } if (dbg) { _mesa_printf("Replace regs 0..%u with 0..%u\n", tempMax, freeTemp-1); } } replace_regs(prog, PROGRAM_TEMPORARY, tempMap); if (dbg) { _mesa_printf("Optimize: End register consolidation\n"); } }