2 * Copyright 2010 Tom Stellard <tstellar@gmail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial
16 * portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #include "radeon_emulate_loops.h"
34 #include "radeon_compiler.h"
36 struct emulate_loop_state
{
37 struct radeon_compiler
* C
;
38 struct loop_info
* Loops
;
39 unsigned int LoopCount
;
40 unsigned int LoopReserved
;
44 struct rc_instruction
* BeginLoop
;
45 struct rc_instruction
* EndLoop
;
48 static unsigned int loop_count_instructions(struct loop_info
* loop
)
50 unsigned int count
= 0;
51 struct rc_instruction
* inst
= loop
->BeginLoop
->Next
;
52 while(inst
!= loop
->EndLoop
){
59 static unsigned int loop_calc_iterations(struct loop_info
* loop
,
60 unsigned int loop_count
, unsigned int max_instructions
)
62 unsigned int icount
= loop_count_instructions(loop
);
63 return max_instructions
/ (loop_count
* icount
);
66 static void loop_unroll(struct emulate_loop_state
* s
,
67 struct loop_info
*loop
, unsigned int iterations
)
70 struct rc_instruction
* ptr
;
71 struct rc_instruction
* first
= loop
->BeginLoop
->Next
;
72 struct rc_instruction
* last
= loop
->EndLoop
->Prev
;
73 struct rc_instruction
* append_to
= last
;
74 rc_remove_instruction(loop
->BeginLoop
);
75 rc_remove_instruction(loop
->EndLoop
);
76 for( i
= 1; i
< iterations
; i
++){
77 for(ptr
= first
; ptr
!= last
->Next
; ptr
= ptr
->Next
){
78 struct rc_instruction
*new = rc_alloc_instruction(s
->C
);
79 memcpy(new, ptr
, sizeof(struct rc_instruction
));
80 rc_insert_instruction(append_to
, new);
87 * This function prepares a loop to be unrolled by converting it into an if
88 * statement. Here is an outline of the conversion process:
89 * BGNLOOP; -> BGNLOOP;
90 * SGE temp[0], temp[1], temp[2]; -> SLT temp[0], temp[1], temp[2];
91 * IF temp[0]; -> IF temp[0];
93 * ENDIF; -> <Loop Body>
94 * <Loop Body> -> ENDIF;
97 * @param inst Pointer to a BGNLOOP instruction.
99 static struct rc_instruction
* transform_loop(struct emulate_loop_state
* s
,
100 struct rc_instruction
* inst
)
102 struct loop_info
*loop
;
103 struct rc_instruction
* ptr
;
105 memory_pool_array_reserve(&s
->C
->Pool
, struct loop_info
,
106 s
->Loops
, s
->LoopCount
, s
->LoopReserved
, 1);
108 loop
= &s
->Loops
[s
->LoopCount
++];
109 memset(loop
, 0, sizeof(struct loop_info
));
111 loop
->BeginLoop
= inst
;
112 /* Reverse the SGE instruction */
114 ptr
->U
.I
.Opcode
= RC_OPCODE_SLT
;
115 while(!loop
->EndLoop
){
116 struct rc_instruction
* endif
;
117 if(ptr
->Type
== RC_INSTRUCTION_NORMAL
){
119 switch(ptr
->U
.I
.Opcode
){
120 case RC_OPCODE_BGNLOOP
:
122 ptr
= transform_loop(s
, ptr
);
125 /* The BRK instruction should always be followed by
126 * an ENDIF. This ENDIF will eventually replace the
127 * ENDLOOP insruction. */
129 rc_remove_instruction(ptr
);
130 rc_remove_instruction(endif
);
132 case RC_OPCODE_ENDLOOP
:
133 /* Insert the ENDIF before ENDLOOP. */
134 rc_insert_instruction(ptr
->Prev
, endif
);
143 static void rc_transform_loops(struct emulate_loop_state
* s
)
145 struct rc_instruction
* ptr
= s
->C
->Program
.Instructions
.Next
;
146 while(ptr
!= &s
->C
->Program
.Instructions
) {
147 if(ptr
->Type
== RC_INSTRUCTION_NORMAL
&&
148 ptr
->U
.I
.Opcode
== RC_OPCODE_BGNLOOP
){
149 ptr
= transform_loop(s
, ptr
);
155 static void rc_unroll_loops(struct emulate_loop_state
*s
,
156 unsigned int max_instructions
)
159 /* Iterate backwards of the list of loops so that loops that nested
160 * loops are unrolled first.
162 for( i
= s
->LoopCount
- 1; i
>= 0; i
-- ){
163 unsigned int iterations
= loop_calc_iterations(&s
->Loops
[i
],
164 s
->LoopCount
, max_instructions
);
165 loop_unroll(s
, &s
->Loops
[i
], iterations
);
169 void rc_emulate_loops(struct radeon_compiler
*c
, unsigned int max_instructions
)
171 struct emulate_loop_state s
;
173 memset(&s
, 0, sizeof(struct emulate_loop_state
));
176 /* We may need to move these two operations to r3xx_(vert|frag)prog.c
177 * and run the optimization passes between them in order to increase
178 * the number of unrolls we can do for each loop.
180 rc_transform_loops(&s
);
182 rc_unroll_loops(&s
, max_instructions
);