diff options
author | Tom Stellard <[email protected]> | 2010-06-10 19:18:20 -0700 |
---|---|---|
committer | Marek Olšák <[email protected]> | 2010-06-11 22:06:59 +0200 |
commit | 3eca311b725649cf8766253b57939359578cae66 (patch) | |
tree | bf7adbdf6f54e0e5de2d9af92e0c1a8d9249274b /src | |
parent | bde34a76b5b49d624c06c53a28ff8be3812810a7 (diff) |
r300/compiler: Handle more complex conditionals in loops.
Diffstat (limited to 'src')
-rw-r--r-- | src/mesa/drivers/dri/r300/compiler/radeon_emulate_loops.c | 155 |
1 files changed, 84 insertions, 71 deletions
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_emulate_loops.c b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_loops.c index 1bf1dcfb0e9..4c5d29f4217 100644 --- a/src/mesa/drivers/dri/r300/compiler/radeon_emulate_loops.c +++ b/src/mesa/drivers/dri/r300/compiler/radeon_emulate_loops.c @@ -47,6 +47,10 @@ struct emulate_loop_state { struct loop_info { struct rc_instruction * BeginLoop; + struct rc_instruction * Cond; + struct rc_instruction * If; + struct rc_instruction * Brk; + struct rc_instruction * EndIf; struct rc_instruction * EndLoop; }; @@ -293,37 +297,12 @@ static int transform_const_loop(struct emulate_loop_state * s, count_inst.Amount); DBG("Loop will have %d iterations.\n", iterations); + /* Prepare loop for unrolling */ - /* Remove the first 4 instructions inside the loop, which are part - * of the conditional and no longer needed. - */ - /* SLT/SGE/SGT/SLE */ - if(loop->BeginLoop->Next->U.I.Opcode != RC_OPCODE_SLT && - loop->BeginLoop->Next->U.I.Opcode != RC_OPCODE_SGE && - loop->BeginLoop->Next->U.I.Opcode != RC_OPCODE_SGT && - loop->BeginLoop->Next->U.I.Opcode != RC_OPCODE_SLE){ - rc_error(s->C,"Unexpected instruction, expected LT,GT,LE,GE\n"); - return 0; - } - /* IF */ - rc_remove_instruction(loop->BeginLoop->Next); - if(loop->BeginLoop->Next->U.I.Opcode != RC_OPCODE_IF){ - rc_error(s->C,"Unexpected instruction, expected IF\n"); - return 0; - } - rc_remove_instruction(loop->BeginLoop->Next); - /* BRK */ - if(loop->BeginLoop->Next->U.I.Opcode != RC_OPCODE_BRK){ - rc_error(s->C,"Unexpected instruction, expected BRK\n"); - return 0; - } - rc_remove_instruction(loop->BeginLoop->Next); - /* ENDIF */ - if(loop->BeginLoop->Next->U.I.Opcode != RC_OPCODE_ENDIF){ - rc_error(s->C,"Unexpected instruction, expected ENDIF\n"); - return 0; - } - rc_remove_instruction(loop->BeginLoop->Next); + rc_remove_instruction(loop->Cond); + rc_remove_instruction(loop->If); + rc_remove_instruction(loop->Brk); + rc_remove_instruction(loop->EndIf); loop_unroll(s, loop, iterations); loop->EndLoop = NULL; @@ -334,6 +313,7 @@ static int transform_const_loop(struct emulate_loop_state * s, * This function prepares a loop to be unrolled by converting it into an if * statement. Here is an outline of the conversion process: * BGNLOOP; -> BGNLOOP; + * <Additional conditional code> -> <Additional conditional code> * SGE/SLT temp[0], temp[1], temp[2]; -> SLT/SGE temp[0], temp[1], temp[2]; * IF temp[0]; -> IF temp[0]; * BRK; -> @@ -342,7 +322,10 @@ static int transform_const_loop(struct emulate_loop_state * s, * ENDLOOP; -> ENDLOOP * * @param inst A pointer to a BGNLOOP instruction. - * @return A pointer to the ENDLOOP instruction. + * @return If the loop can be unrolled, a pointer to the first instruction of + * the unrolled loop. + * Otherwise, A pointer to the ENDLOOP instruction. + * Null if there is an error. */ static struct rc_instruction * transform_loop(struct emulate_loop_state * s, struct rc_instruction * inst) @@ -355,27 +338,79 @@ static struct rc_instruction * transform_loop(struct emulate_loop_state * s, loop = &s->Loops[s->LoopCount++]; memset(loop, 0, sizeof(struct loop_info)); + if(inst->U.I.Opcode != RC_OPCODE_BGNLOOP){ + rc_error(s->C, "expected BGNLOOP\n", __FUNCTION__); + return NULL; + } loop->BeginLoop = inst; - + + for(ptr = loop->BeginLoop->Next; !loop->EndLoop; ptr = ptr->Next){ + switch(ptr->U.I.Opcode){ + case RC_OPCODE_BGNLOOP: + /* Nested loop */ + ptr = transform_loop(s, ptr); + if(!ptr){ + return NULL; + } + break; + case RC_OPCODE_BRK: + loop->Brk = ptr; + if(ptr->Next->U.I.Opcode != RC_OPCODE_ENDIF){ + rc_error(s->C, + "%s: expected ENDIF\n",__FUNCTION__); + return NULL; + } + loop->EndIf = ptr->Next; + if(ptr->Prev->U.I.Opcode != RC_OPCODE_IF){ + rc_error(s->C, + "%s: expected IF\n", __FUNCTION__); + return NULL; + } + loop->If = ptr->Prev; + switch(loop->If->Prev->U.I.Opcode){ + case RC_OPCODE_SLT: + case RC_OPCODE_SGE: + case RC_OPCODE_SGT: + case RC_OPCODE_SLE: + case RC_OPCODE_SEQ: + case RC_OPCODE_SNE: + break; + default: + rc_error(s->C, "%s expected conditional\n", + __FUNCTION__); + return NULL; + } + loop->Cond = loop->If->Prev; + ptr = loop->EndIf; + break; + case RC_OPCODE_ENDLOOP: + loop->EndLoop = ptr; + break; + } + } /* Reverse the conditional instruction */ - ptr = inst->Next; - switch(ptr->U.I.Opcode){ + switch(loop->Cond->U.I.Opcode){ case RC_OPCODE_SGE: - ptr->U.I.Opcode = RC_OPCODE_SLT; + loop->Cond->U.I.Opcode = RC_OPCODE_SLT; break; case RC_OPCODE_SLT: - ptr->U.I.Opcode = RC_OPCODE_SGE; + loop->Cond->U.I.Opcode = RC_OPCODE_SGE; break; case RC_OPCODE_SLE: - ptr->U.I.Opcode = RC_OPCODE_SGT; + loop->Cond->U.I.Opcode = RC_OPCODE_SGT; break; case RC_OPCODE_SGT: - ptr->U.I.Opcode = RC_OPCODE_SLE; + loop->Cond->U.I.Opcode = RC_OPCODE_SLE; break; - default: - rc_error(s->C, - "Loop does not start with a conditional instruction."); + case RC_OPCODE_SEQ: + loop->Cond->U.I.Opcode = RC_OPCODE_SNE; + break; + case RC_OPCODE_SNE: + loop->Cond->U.I.Opcode = RC_OPCODE_SEQ; break; + default: + rc_error(s->C, "loop->Cond is not a conditional.\n"); + return NULL; } /* Check if the number of loops is known at compile time. */ @@ -383,36 +418,11 @@ static struct rc_instruction * transform_loop(struct emulate_loop_state * s, return loop->BeginLoop->Next; } - while(!loop->EndLoop){ - struct rc_instruction * endif; - if(ptr->Type == RC_INSTRUCTION_NORMAL){ - } - switch(ptr->U.I.Opcode){ - case RC_OPCODE_BGNLOOP: - /* Nested loop */ - ptr = transform_loop(s, ptr); - break; - case RC_OPCODE_BRK: - /* The BRK instruction should always be followed by - * an ENDIF. This ENDIF will eventually replace the - * ENDLOOP insruction. */ - if(ptr->Next->U.I.Opcode != RC_OPCODE_ENDIF){ - rc_error(s->C, - "transform_loop: expected ENDIF\n"); - } - endif = ptr->Next; - rc_remove_instruction(ptr); - rc_remove_instruction(endif); - break; - case RC_OPCODE_ENDLOOP: - /* Insert the ENDIF before ENDLOOP. */ - rc_insert_instruction(ptr->Prev, endif); - loop->EndLoop = ptr; - break; - } - ptr = ptr->Next; - } - return ptr; + /* Prepare the loop to be unrolled */ + rc_remove_instruction(loop->Brk); + rc_remove_instruction(loop->EndIf); + rc_insert_instruction(loop->EndLoop->Prev, loop->EndIf); + return loop->EndLoop; } static void rc_transform_loops(struct emulate_loop_state * s) @@ -422,6 +432,9 @@ static void rc_transform_loops(struct emulate_loop_state * s) if(ptr->Type == RC_INSTRUCTION_NORMAL && ptr->U.I.Opcode == RC_OPCODE_BGNLOOP){ ptr = transform_loop(s, ptr); + if(!ptr){ + return; + } } ptr = ptr->Next; } |