2 * Copyright (C) 2008 Nicolai Haehnle.
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.
28 #include "radeon_program.h"
32 #include "radeon_compiler.h"
36 * Transform the given clause in the following way:
37 * 1. Replace it with an empty clause
38 * 2. For every instruction in the original clause, try the given
39 * transformations in order.
40 * 3. If one of the transformations returns GL_TRUE, assume that it
41 * has emitted the appropriate instruction(s) into the new clause;
42 * otherwise, copy the instruction verbatim.
44 * \note The transformation is currently not recursive; in other words,
45 * instructions emitted by transformations are not transformed.
47 * \note The transform is called 'local' because it can only look at
48 * one instruction at a time.
50 void radeonLocalTransform(
51 struct radeon_compiler
* c
,
52 int num_transformations
,
53 struct radeon_program_transformation
* transformations
)
55 struct rc_instruction
* inst
= c
->Program
.Instructions
.Next
;
57 while(inst
!= &c
->Program
.Instructions
) {
58 struct rc_instruction
* current
= inst
;
63 for(i
= 0; i
< num_transformations
; ++i
) {
64 struct radeon_program_transformation
* t
= transformations
+ i
;
66 if (t
->function(c
, current
, t
->userData
))
73 * Left multiplication of a register with a swizzle
75 struct rc_src_register
lmul_swizzle(unsigned int swizzle
, struct rc_src_register srcreg
)
77 struct rc_src_register tmp
= srcreg
;
81 for(i
= 0; i
< 4; ++i
) {
82 rc_swizzle swz
= GET_SWZ(swizzle
, i
);
84 tmp
.Swizzle
|= GET_SWZ(srcreg
.Swizzle
, swz
) << (i
*3);
85 tmp
.Negate
|= GET_BIT(srcreg
.Negate
, swz
) << i
;
87 tmp
.Swizzle
|= swz
<< (i
*3);
93 unsigned int rc_find_free_temporary(struct radeon_compiler
* c
)
95 char used
[RC_REGISTER_MAX_INDEX
];
98 memset(used
, 0, sizeof(used
));
100 for (struct rc_instruction
* rcinst
= c
->Program
.Instructions
.Next
; rcinst
!= &c
->Program
.Instructions
; rcinst
= rcinst
->Next
) {
101 const struct rc_sub_instruction
*inst
= &rcinst
->I
;
102 const struct rc_opcode_info
*opcode
= rc_get_opcode_info(inst
->Opcode
);
105 for (k
= 0; k
< opcode
->NumSrcRegs
; k
++) {
106 if (inst
->SrcReg
[k
].File
== RC_FILE_TEMPORARY
)
107 used
[inst
->SrcReg
[k
].Index
] = 1;
110 if (opcode
->HasDstReg
) {
111 if (inst
->DstReg
.File
== RC_FILE_TEMPORARY
)
112 used
[inst
->DstReg
.Index
] = 1;
116 for (i
= 0; i
< RC_REGISTER_MAX_INDEX
; i
++) {
121 rc_error(c
, "Ran out of temporary registers\n");
126 struct rc_instruction
*rc_alloc_instruction(struct radeon_compiler
* c
)
128 struct rc_instruction
* inst
= memory_pool_malloc(&c
->Pool
, sizeof(struct rc_instruction
));
130 memset(inst
, 0, sizeof(struct rc_instruction
));
132 inst
->I
.Opcode
= RC_OPCODE_ILLEGAL_OPCODE
;
133 inst
->I
.DstReg
.WriteMask
= RC_MASK_XYZW
;
134 inst
->I
.SrcReg
[0].Swizzle
= RC_SWIZZLE_XYZW
;
135 inst
->I
.SrcReg
[1].Swizzle
= RC_SWIZZLE_XYZW
;
136 inst
->I
.SrcReg
[2].Swizzle
= RC_SWIZZLE_XYZW
;
142 struct rc_instruction
*rc_insert_new_instruction(struct radeon_compiler
* c
, struct rc_instruction
* after
)
144 struct rc_instruction
* inst
= rc_alloc_instruction(c
);
147 inst
->Next
= after
->Next
;
149 inst
->Prev
->Next
= inst
;
150 inst
->Next
->Prev
= inst
;
155 void rc_remove_instruction(struct rc_instruction
* inst
)
157 inst
->Prev
->Next
= inst
->Next
;
158 inst
->Next
->Prev
= inst
->Prev
;
161 static const char * textarget_to_string(rc_texture_target target
)
164 case RC_TEXTURE_2D_ARRAY
: return "2D_ARRAY";
165 case RC_TEXTURE_1D_ARRAY
: return "1D_ARRAY";
166 case RC_TEXTURE_CUBE
: return "CUBE";
167 case RC_TEXTURE_3D
: return "3D";
168 case RC_TEXTURE_RECT
: return "RECT";
169 case RC_TEXTURE_2D
: return "2D";
170 case RC_TEXTURE_1D
: return "1D";
171 default: return "BAD_TEXTURE_TARGET";
175 static void rc_print_register(FILE * f
, rc_register_file file
, int index
, unsigned int reladdr
)
177 if (file
== RC_FILE_NONE
) {
180 const char * filename
;
182 case RC_FILE_TEMPORARY
: filename
= "temp"; break;
183 case RC_FILE_INPUT
: filename
= "input"; break;
184 case RC_FILE_OUTPUT
: filename
= "output"; break;
185 case RC_FILE_ADDRESS
: filename
= "addr"; break;
186 case RC_FILE_CONSTANT
: filename
= "const"; break;
187 default: filename
= "BAD FILE"; break;
189 fprintf(f
, "%s[%i%s]", filename
, index
, reladdr
? " + addr[0]" : "");
193 static void rc_print_mask(FILE * f
, unsigned int mask
)
195 if (mask
& RC_MASK_X
) fprintf(f
, "x");
196 if (mask
& RC_MASK_Y
) fprintf(f
, "y");
197 if (mask
& RC_MASK_Z
) fprintf(f
, "z");
198 if (mask
& RC_MASK_W
) fprintf(f
, "w");
201 static void rc_print_dst_register(FILE * f
, struct rc_dst_register dst
)
203 rc_print_register(f
, dst
.File
, dst
.Index
, dst
.RelAddr
);
204 if (dst
.WriteMask
!= RC_MASK_XYZW
) {
206 rc_print_mask(f
, dst
.WriteMask
);
210 static void rc_print_swizzle(FILE * f
, unsigned int swizzle
, unsigned int negate
)
213 for(comp
= 0; comp
< 4; ++comp
) {
214 rc_swizzle swz
= GET_SWZ(swizzle
, comp
);
215 if (GET_BIT(negate
, comp
))
218 case RC_SWIZZLE_X
: fprintf(f
, "x"); break;
219 case RC_SWIZZLE_Y
: fprintf(f
, "y"); break;
220 case RC_SWIZZLE_Z
: fprintf(f
, "z"); break;
221 case RC_SWIZZLE_W
: fprintf(f
, "w"); break;
222 case RC_SWIZZLE_ZERO
: fprintf(f
, "0"); break;
223 case RC_SWIZZLE_ONE
: fprintf(f
, "1"); break;
224 case RC_SWIZZLE_HALF
: fprintf(f
, "H"); break;
225 case RC_SWIZZLE_UNUSED
: fprintf(f
, "_"); break;
230 static void rc_print_src_register(FILE * f
, struct rc_src_register src
)
232 int trivial_negate
= (src
.Negate
== RC_MASK_NONE
|| src
.Negate
== RC_MASK_XYZW
);
234 if (src
.Negate
== RC_MASK_XYZW
)
239 rc_print_register(f
, src
.File
, src
.Index
, src
.RelAddr
);
241 if (src
.Abs
&& !trivial_negate
)
244 if (src
.Swizzle
!= RC_SWIZZLE_XYZW
|| !trivial_negate
) {
246 rc_print_swizzle(f
, src
.Swizzle
, trivial_negate
? 0 : src
.Negate
);
249 if (src
.Abs
&& trivial_negate
)
253 static void rc_print_instruction(FILE * f
, struct rc_instruction
* inst
)
255 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->I
.Opcode
);
258 fprintf(f
, "%s", opcode
->Name
);
260 switch(inst
->I
.SaturateMode
) {
261 case RC_SATURATE_NONE
: break;
262 case RC_SATURATE_ZERO_ONE
: fprintf(f
, "_SAT"); break;
263 case RC_SATURATE_MINUS_PLUS_ONE
: fprintf(f
, "_SAT2"); break;
264 default: fprintf(f
, "_BAD_SAT"); break;
267 if (opcode
->HasDstReg
) {
269 rc_print_dst_register(f
, inst
->I
.DstReg
);
270 if (opcode
->NumSrcRegs
)
274 for(reg
= 0; reg
< opcode
->NumSrcRegs
; ++reg
) {
278 rc_print_src_register(f
, inst
->I
.SrcReg
[reg
]);
281 if (opcode
->HasTexture
) {
282 fprintf(f
, ", %s%s[%u]",
283 textarget_to_string(inst
->I
.TexSrcTarget
),
284 inst
->I
.TexShadow
? "SHADOW" : "",
292 * Print program to stderr, default options.
294 void rc_print_program(const struct rc_program
*prog
)
296 unsigned int linenum
= 0;
297 struct rc_instruction
*inst
;
299 fprintf(stderr
, "# Radeon Compiler Program\n");
301 for(inst
= prog
->Instructions
.Next
; inst
!= &prog
->Instructions
; inst
= inst
->Next
) {
302 fprintf(stderr
, "%3d: ", linenum
);
304 rc_print_instruction(stderr
, inst
);