/** * Find a good ALU instruction or pair of ALU instruction and emit it. * * Prefer emitting full ALU instructions, so that when we reach a point * where no full ALU instruction can be emitted, we have more candidates * for RGB/Alpha pairing. */ static void emit_one_alu(struct schedule_state *s, struct rc_instruction * before) { struct schedule_instruction * sinst; if (s->ReadyFullALU || !(s->ReadyRGB && s->ReadyAlpha)) { if (s->ReadyFullALU) { sinst = s->ReadyFullALU; s->ReadyFullALU = s->ReadyFullALU->NextReady; } else if (s->ReadyRGB) { sinst = s->ReadyRGB; s->ReadyRGB = s->ReadyRGB->NextReady; } else { sinst = s->ReadyAlpha; s->ReadyAlpha = s->ReadyAlpha->NextReady; } rc_insert_instruction(before->Prev, sinst->Instruction); commit_alu_instruction(s, sinst); } else { struct schedule_instruction **prgb; struct schedule_instruction **palpha; /* Some pairings might fail because they require too * many source slots; try all possible pairings if necessary */ for(prgb = &s->ReadyRGB; *prgb; prgb = &(*prgb)->NextReady) { for(palpha = &s->ReadyAlpha; *palpha; palpha = &(*palpha)->NextReady) { struct schedule_instruction * psirgb = *prgb; struct schedule_instruction * psialpha = *palpha; if (!merge_instructions(&psirgb->Instruction->U.P, &psialpha->Instruction->U.P)) continue; *prgb = (*prgb)->NextReady; *palpha = (*palpha)->NextReady; rc_insert_instruction(before->Prev, psirgb->Instruction); commit_alu_instruction(s, psirgb); commit_alu_instruction(s, psialpha); goto success; } } /* No success in pairing; just take the first RGB instruction */ sinst = s->ReadyRGB; s->ReadyRGB = s->ReadyRGB->NextReady; rc_insert_instruction(before->Prev, sinst->Instruction); commit_alu_instruction(s, sinst); success: ; } /* If the instruction we just emitted uses a presubtract value, and * the presubtract sources were written by the previous intstruction, * the previous instruction needs a nop. */ presub_nop(before->Prev); }
static void try_convert_and_pair( struct schedule_state *s, struct schedule_instruction ** inst_list) { struct schedule_instruction * list_ptr = *inst_list; while (list_ptr && *inst_list && (*inst_list)->NextReady) { int paired = 0; if (list_ptr->Instruction->U.P.Alpha.Opcode != RC_OPCODE_NOP && list_ptr->Instruction->U.P.RGB.Opcode != RC_OPCODE_REPL_ALPHA) { goto next; } if (list_ptr->NumWriteValues == 1 && convert_rgb_to_alpha(s, list_ptr)) { struct schedule_instruction * pair_ptr; remove_inst_from_list(inst_list, list_ptr); add_inst_to_list_score(&s->ReadyAlpha, list_ptr); for (pair_ptr = s->ReadyRGB; pair_ptr; pair_ptr = pair_ptr->NextReady) { if (merge_instructions(&pair_ptr->Instruction->U.P, &list_ptr->Instruction->U.P)) { remove_inst_from_list(&s->ReadyAlpha, list_ptr); remove_inst_from_list(&s->ReadyRGB, pair_ptr); pair_ptr->PairedInst = list_ptr; add_inst_to_list(&s->ReadyFullALU, pair_ptr); list_ptr = *inst_list; paired = 1; break; } } } if (!paired) { next: list_ptr = list_ptr->NextReady; } } }
/** * This function attempts to merge RGB and Alpha instructions together. */ static void pair_instructions(struct schedule_state * s) { struct schedule_instruction *rgb_ptr; struct schedule_instruction *alpha_ptr; /* Some pairings might fail because they require too * many source slots; try all possible pairings if necessary */ rgb_ptr = s->ReadyRGB; while(rgb_ptr) { struct schedule_instruction * rgb_next = rgb_ptr->NextReady; alpha_ptr = s->ReadyAlpha; while(alpha_ptr) { struct schedule_instruction * alpha_next = alpha_ptr->NextReady; if (merge_instructions(&rgb_ptr->Instruction->U.P, &alpha_ptr->Instruction->U.P)) { /* Remove RGB and Alpha from their ready lists. */ remove_inst_from_list(&s->ReadyRGB, rgb_ptr); remove_inst_from_list(&s->ReadyAlpha, alpha_ptr); rgb_ptr->PairedInst = alpha_ptr; add_inst_to_list(&s->ReadyFullALU, rgb_ptr); break; } alpha_ptr = alpha_next; } rgb_ptr = rgb_next; } if (!s->Opt) { return; } /* Full instructions that have RC_OPCODE_REPL_ALPHA in the RGB * slot can be converted into Alpha instructions. */ try_convert_and_pair(s, &s->ReadyFullALU); /* Try to convert some of the RGB instructions to Alpha and * try to pair it with another RGB. */ try_convert_and_pair(s, &s->ReadyRGB); }
/** * Find a good ALU instruction or pair of ALU instruction and emit it. * * Prefer emitting full ALU instructions, so that when we reach a point * where no full ALU instruction can be emitted, we have more candidates * for RGB/Alpha pairing. */ static void emit_one_alu(struct schedule_state *s, struct rc_instruction * before) { struct schedule_instruction * sinst; if (s->ReadyFullALU) { sinst = s->ReadyFullALU; s->ReadyFullALU = s->ReadyFullALU->NextReady; rc_insert_instruction(before->Prev, sinst->Instruction); commit_alu_instruction(s, sinst); } else { struct schedule_instruction **prgb; struct schedule_instruction **palpha; struct schedule_instruction *prev; pair: /* Some pairings might fail because they require too * many source slots; try all possible pairings if necessary */ for(prgb = &s->ReadyRGB; *prgb; prgb = &(*prgb)->NextReady) { for(palpha = &s->ReadyAlpha; *palpha; palpha = &(*palpha)->NextReady) { struct schedule_instruction * psirgb = *prgb; struct schedule_instruction * psialpha = *palpha; if (!merge_instructions(&psirgb->Instruction->U.P, &psialpha->Instruction->U.P)) continue; *prgb = (*prgb)->NextReady; *palpha = (*palpha)->NextReady; rc_insert_instruction(before->Prev, psirgb->Instruction); commit_alu_instruction(s, psirgb); commit_alu_instruction(s, psialpha); goto success; } } prev = NULL; /* No success in pairing, now try to convert one of the RGB * instructions to an Alpha so we can pair it with another RGB. */ if (s->ReadyRGB && s->ReadyRGB->NextReady) { for(prgb = &s->ReadyRGB; *prgb; prgb = &(*prgb)->NextReady) { if ((*prgb)->NumWriteValues == 1) { struct schedule_instruction * prgb_next; if (!convert_rgb_to_alpha(s, *prgb)) goto cont_loop; prgb_next = (*prgb)->NextReady; /* Add instruction to the Alpha ready list. */ (*prgb)->NextReady = s->ReadyAlpha; s->ReadyAlpha = *prgb; /* Remove instruction from the RGB ready list.*/ if (prev) prev->NextReady = prgb_next; else s->ReadyRGB = prgb_next; goto pair; } cont_loop: prev = *prgb; } } /* Still no success in pairing, just take the first RGB * or alpha instruction. */ if (s->ReadyRGB) { sinst = s->ReadyRGB; s->ReadyRGB = s->ReadyRGB->NextReady; } else if (s->ReadyAlpha) { sinst = s->ReadyAlpha; s->ReadyAlpha = s->ReadyAlpha->NextReady; } else { /*XXX Something real bad has happened. */ assert(0); } rc_insert_instruction(before->Prev, sinst->Instruction); commit_alu_instruction(s, sinst); success: ; } /* If the instruction we just emitted uses a presubtract value, and * the presubtract sources were written by the previous intstruction, * the previous instruction needs a nop. */ presub_nop(before->Prev); }