2 * Copyright 2009 Nicolai Hähnle <nhaehnle@gmail.com>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE. */
23 #include "radeon_compiler.h"
29 #include "radeon_program.h"
32 void rc_init(struct radeon_compiler
* c
)
34 memset(c
, 0, sizeof(*c
));
36 memory_pool_init(&c
->Pool
);
37 c
->Program
.Instructions
.Prev
= &c
->Program
.Instructions
;
38 c
->Program
.Instructions
.Next
= &c
->Program
.Instructions
;
39 c
->Program
.Instructions
.U
.I
.Opcode
= RC_OPCODE_ILLEGAL_OPCODE
;
42 void rc_destroy(struct radeon_compiler
* c
)
44 rc_constants_destroy(&c
->Program
.Constants
);
45 memory_pool_destroy(&c
->Pool
);
49 void rc_debug(struct radeon_compiler
* c
, const char * fmt
, ...)
57 vfprintf(stderr
, fmt
, ap
);
61 void rc_error(struct radeon_compiler
* c
, const char * fmt
, ...)
68 /* Only remember the first error */
73 written
= vsnprintf(buf
, sizeof(buf
), fmt
, ap
);
76 if (written
< sizeof(buf
)) {
77 c
->ErrorMsg
= strdup(buf
);
79 c
->ErrorMsg
= malloc(written
+ 1);
82 vsnprintf(c
->ErrorMsg
, written
+ 1, fmt
, ap
);
88 fprintf(stderr
, "r300compiler error: ");
91 vfprintf(stderr
, fmt
, ap
);
96 int rc_if_fail_helper(struct radeon_compiler
* c
, const char * file
, int line
, const char * assertion
)
98 rc_error(c
, "ICE at %s:%i: assertion failed: %s\n", file
, line
, assertion
);
103 * Recompute c->Program.InputsRead and c->Program.OutputsWritten
104 * based on which inputs and outputs are actually referenced
105 * in program instructions.
107 void rc_calculate_inputs_outputs(struct radeon_compiler
* c
)
109 struct rc_instruction
*inst
;
111 c
->Program
.InputsRead
= 0;
112 c
->Program
.OutputsWritten
= 0;
114 for(inst
= c
->Program
.Instructions
.Next
; inst
!= &c
->Program
.Instructions
; inst
= inst
->Next
)
116 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->U
.I
.Opcode
);
119 for (i
= 0; i
< opcode
->NumSrcRegs
; ++i
) {
120 if (inst
->U
.I
.SrcReg
[i
].File
== RC_FILE_INPUT
)
121 c
->Program
.InputsRead
|= 1 << inst
->U
.I
.SrcReg
[i
].Index
;
124 if (opcode
->HasDstReg
) {
125 if (inst
->U
.I
.DstReg
.File
== RC_FILE_OUTPUT
)
126 c
->Program
.OutputsWritten
|= 1 << inst
->U
.I
.DstReg
.Index
;
132 * Rewrite the program such that everything that source the given input
133 * register will source new_input instead.
135 void rc_move_input(struct radeon_compiler
* c
, unsigned input
, struct rc_src_register new_input
)
137 struct rc_instruction
* inst
;
139 c
->Program
.InputsRead
&= ~(1 << input
);
141 for(inst
= c
->Program
.Instructions
.Next
; inst
!= &c
->Program
.Instructions
; inst
= inst
->Next
) {
142 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->U
.I
.Opcode
);
145 for(i
= 0; i
< opcode
->NumSrcRegs
; ++i
) {
146 if (inst
->U
.I
.SrcReg
[i
].File
== RC_FILE_INPUT
&& inst
->U
.I
.SrcReg
[i
].Index
== input
) {
147 inst
->U
.I
.SrcReg
[i
].File
= new_input
.File
;
148 inst
->U
.I
.SrcReg
[i
].Index
= new_input
.Index
;
149 inst
->U
.I
.SrcReg
[i
].Swizzle
= combine_swizzles(new_input
.Swizzle
, inst
->U
.I
.SrcReg
[i
].Swizzle
);
150 if (!inst
->U
.I
.SrcReg
[i
].Abs
) {
151 inst
->U
.I
.SrcReg
[i
].Negate
^= new_input
.Negate
;
152 inst
->U
.I
.SrcReg
[i
].Abs
= new_input
.Abs
;
155 c
->Program
.InputsRead
|= 1 << new_input
.Index
;
163 * Rewrite the program such that everything that writes into the given
164 * output register will instead write to new_output. The new_output
165 * writemask is honoured.
167 void rc_move_output(struct radeon_compiler
* c
, unsigned output
, unsigned new_output
, unsigned writemask
)
169 struct rc_instruction
* inst
;
171 c
->Program
.OutputsWritten
&= ~(1 << output
);
173 for(inst
= c
->Program
.Instructions
.Next
; inst
!= &c
->Program
.Instructions
; inst
= inst
->Next
) {
174 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->U
.I
.Opcode
);
176 if (opcode
->HasDstReg
) {
177 if (inst
->U
.I
.DstReg
.File
== RC_FILE_OUTPUT
&& inst
->U
.I
.DstReg
.Index
== output
) {
178 inst
->U
.I
.DstReg
.Index
= new_output
;
179 inst
->U
.I
.DstReg
.WriteMask
&= writemask
;
181 c
->Program
.OutputsWritten
|= 1 << new_output
;
189 * Rewrite the program such that a given output is duplicated.
191 void rc_copy_output(struct radeon_compiler
* c
, unsigned output
, unsigned dup_output
)
193 unsigned tempreg
= rc_find_free_temporary(c
);
194 struct rc_instruction
* inst
;
196 for(inst
= c
->Program
.Instructions
.Next
; inst
!= &c
->Program
.Instructions
; inst
= inst
->Next
) {
197 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->U
.I
.Opcode
);
199 if (opcode
->HasDstReg
) {
200 if (inst
->U
.I
.DstReg
.File
== RC_FILE_OUTPUT
&& inst
->U
.I
.DstReg
.Index
== output
) {
201 inst
->U
.I
.DstReg
.File
= RC_FILE_TEMPORARY
;
202 inst
->U
.I
.DstReg
.Index
= tempreg
;
207 inst
= rc_insert_new_instruction(c
, c
->Program
.Instructions
.Prev
);
208 inst
->U
.I
.Opcode
= RC_OPCODE_MOV
;
209 inst
->U
.I
.DstReg
.File
= RC_FILE_OUTPUT
;
210 inst
->U
.I
.DstReg
.Index
= output
;
212 inst
->U
.I
.SrcReg
[0].File
= RC_FILE_TEMPORARY
;
213 inst
->U
.I
.SrcReg
[0].Index
= tempreg
;
214 inst
->U
.I
.SrcReg
[0].Swizzle
= RC_SWIZZLE_XYZW
;
216 inst
= rc_insert_new_instruction(c
, c
->Program
.Instructions
.Prev
);
217 inst
->U
.I
.Opcode
= RC_OPCODE_MOV
;
218 inst
->U
.I
.DstReg
.File
= RC_FILE_OUTPUT
;
219 inst
->U
.I
.DstReg
.Index
= dup_output
;
221 inst
->U
.I
.SrcReg
[0].File
= RC_FILE_TEMPORARY
;
222 inst
->U
.I
.SrcReg
[0].Index
= tempreg
;
223 inst
->U
.I
.SrcReg
[0].Swizzle
= RC_SWIZZLE_XYZW
;
225 c
->Program
.OutputsWritten
|= 1 << dup_output
;
230 * Introduce standard code fragment to deal with fragment.position.
232 void rc_transform_fragment_wpos(struct radeon_compiler
* c
, unsigned wpos
, unsigned new_input
)
234 unsigned tempregi
= rc_find_free_temporary(c
);
235 struct rc_instruction
* inst_rcp
;
236 struct rc_instruction
* inst_mul
;
237 struct rc_instruction
* inst_mad
;
238 struct rc_instruction
* inst
;
240 c
->Program
.InputsRead
&= ~(1 << wpos
);
241 c
->Program
.InputsRead
|= 1 << new_input
;
243 /* perspective divide */
244 inst_rcp
= rc_insert_new_instruction(c
, &c
->Program
.Instructions
);
245 inst_rcp
->U
.I
.Opcode
= RC_OPCODE_RCP
;
247 inst_rcp
->U
.I
.DstReg
.File
= RC_FILE_TEMPORARY
;
248 inst_rcp
->U
.I
.DstReg
.Index
= tempregi
;
249 inst_rcp
->U
.I
.DstReg
.WriteMask
= RC_MASK_W
;
251 inst_rcp
->U
.I
.SrcReg
[0].File
= RC_FILE_INPUT
;
252 inst_rcp
->U
.I
.SrcReg
[0].Index
= new_input
;
253 inst_rcp
->U
.I
.SrcReg
[0].Swizzle
= RC_SWIZZLE_WWWW
;
255 inst_mul
= rc_insert_new_instruction(c
, inst_rcp
);
256 inst_mul
->U
.I
.Opcode
= RC_OPCODE_MUL
;
258 inst_mul
->U
.I
.DstReg
.File
= RC_FILE_TEMPORARY
;
259 inst_mul
->U
.I
.DstReg
.Index
= tempregi
;
260 inst_mul
->U
.I
.DstReg
.WriteMask
= RC_MASK_XYZ
;
262 inst_mul
->U
.I
.SrcReg
[0].File
= RC_FILE_INPUT
;
263 inst_mul
->U
.I
.SrcReg
[0].Index
= new_input
;
265 inst_mul
->U
.I
.SrcReg
[1].File
= RC_FILE_TEMPORARY
;
266 inst_mul
->U
.I
.SrcReg
[1].Index
= tempregi
;
267 inst_mul
->U
.I
.SrcReg
[1].Swizzle
= RC_SWIZZLE_WWWW
;
269 /* viewport transformation */
270 inst_mad
= rc_insert_new_instruction(c
, inst_mul
);
271 inst_mad
->U
.I
.Opcode
= RC_OPCODE_MAD
;
273 inst_mad
->U
.I
.DstReg
.File
= RC_FILE_TEMPORARY
;
274 inst_mad
->U
.I
.DstReg
.Index
= tempregi
;
275 inst_mad
->U
.I
.DstReg
.WriteMask
= RC_MASK_XYZ
;
277 inst_mad
->U
.I
.SrcReg
[0].File
= RC_FILE_TEMPORARY
;
278 inst_mad
->U
.I
.SrcReg
[0].Index
= tempregi
;
279 inst_mad
->U
.I
.SrcReg
[0].Swizzle
= RC_MAKE_SWIZZLE(RC_SWIZZLE_X
, RC_SWIZZLE_Y
, RC_SWIZZLE_Z
, RC_SWIZZLE_ZERO
);
281 inst_mad
->U
.I
.SrcReg
[1].File
= RC_FILE_CONSTANT
;
282 inst_mad
->U
.I
.SrcReg
[1].Index
= rc_constants_add_state(&c
->Program
.Constants
, RC_STATE_R300_WINDOW_DIMENSION
, 0);
283 inst_mad
->U
.I
.SrcReg
[1].Swizzle
= RC_MAKE_SWIZZLE(RC_SWIZZLE_X
, RC_SWIZZLE_Y
, RC_SWIZZLE_Z
, RC_SWIZZLE_ZERO
);
285 inst_mad
->U
.I
.SrcReg
[2].File
= RC_FILE_CONSTANT
;
286 inst_mad
->U
.I
.SrcReg
[2].Index
= inst_mad
->U
.I
.SrcReg
[1].Index
;
287 inst_mad
->U
.I
.SrcReg
[2].Swizzle
= RC_MAKE_SWIZZLE(RC_SWIZZLE_X
, RC_SWIZZLE_Y
, RC_SWIZZLE_Z
, RC_SWIZZLE_ZERO
);
289 for (inst
= inst_mad
->Next
; inst
!= &c
->Program
.Instructions
; inst
= inst
->Next
) {
290 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->U
.I
.Opcode
);
293 for(i
= 0; i
< opcode
->NumSrcRegs
; i
++) {
294 if (inst
->U
.I
.SrcReg
[i
].File
== RC_FILE_INPUT
&&
295 inst
->U
.I
.SrcReg
[i
].Index
== wpos
) {
296 inst
->U
.I
.SrcReg
[i
].File
= RC_FILE_TEMPORARY
;
297 inst
->U
.I
.SrcReg
[i
].Index
= tempregi
;