2 * Copyright (C) 2009 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_dataflow.h"
30 #include "radeon_program.h"
33 static void reads_normal(struct rc_instruction
* fullinst
, rc_read_write_chan_fn cb
, void * userdata
)
35 struct rc_sub_instruction
* inst
= &fullinst
->U
.I
;
36 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->Opcode
);
38 for(unsigned int src
= 0; src
< opcode
->NumSrcRegs
; ++src
) {
39 unsigned int refmask
= 0;
41 if (inst
->SrcReg
[src
].File
== RC_FILE_NONE
)
44 for(unsigned int chan
= 0; chan
< 4; ++chan
)
45 refmask
|= 1 << GET_SWZ(inst
->SrcReg
[src
].Swizzle
, chan
);
47 refmask
&= RC_MASK_XYZW
;
50 cb(userdata
, fullinst
, inst
->SrcReg
[src
].File
, inst
->SrcReg
[src
].Index
, refmask
);
52 if (refmask
&& inst
->SrcReg
[src
].RelAddr
)
53 cb(userdata
, fullinst
, RC_FILE_ADDRESS
, 0, RC_MASK_X
);
57 static void reads_pair(struct rc_instruction
* fullinst
, rc_read_write_mask_fn cb
, void * userdata
)
59 struct rc_pair_instruction
* inst
= &fullinst
->U
.P
;
60 unsigned int refmasks
[3] = { 0, 0, 0 };
62 if (inst
->RGB
.Opcode
!= RC_OPCODE_NOP
) {
63 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->RGB
.Opcode
);
65 for(unsigned int arg
= 0; arg
< opcode
->NumSrcRegs
; ++arg
) {
66 for(unsigned int chan
= 0; chan
< 3; ++chan
) {
67 unsigned int swz
= GET_SWZ(inst
->RGB
.Arg
[arg
].Swizzle
, chan
);
69 refmasks
[inst
->RGB
.Arg
[arg
].Source
] |= 1 << swz
;
74 if (inst
->Alpha
.Opcode
!= RC_OPCODE_NOP
) {
75 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->Alpha
.Opcode
);
77 for(unsigned int arg
= 0; arg
< opcode
->NumSrcRegs
; ++arg
) {
78 if (inst
->Alpha
.Arg
[arg
].Swizzle
< 4)
79 refmasks
[inst
->Alpha
.Arg
[arg
].Source
] |= 1 << inst
->Alpha
.Arg
[arg
].Swizzle
;
83 for(unsigned int src
= 0; src
< 3; ++src
) {
84 if (inst
->RGB
.Src
[src
].Used
&& (refmasks
[src
] & RC_MASK_XYZ
))
85 cb(userdata
, fullinst
, inst
->RGB
.Src
[src
].File
, inst
->RGB
.Src
[src
].Index
,
86 refmasks
[src
] & RC_MASK_XYZ
);
88 if (inst
->Alpha
.Src
[src
].Used
&& (refmasks
[src
] & RC_MASK_W
))
89 cb(userdata
, fullinst
, inst
->Alpha
.Src
[src
].File
, inst
->Alpha
.Src
[src
].Index
, RC_MASK_W
);
94 * Calls a callback function for all register reads.
96 * This is conservative, i.e. if the same register is referenced multiple times,
97 * the callback may also be called multiple times.
98 * Also, the writemask of the instruction is not taken into account.
100 void rc_for_all_reads_mask(struct rc_instruction
* inst
, rc_read_write_mask_fn cb
, void * userdata
)
102 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
103 reads_normal(inst
, cb
, userdata
);
105 reads_pair(inst
, cb
, userdata
);
111 static void writes_normal(struct rc_instruction
* fullinst
, rc_read_write_mask_fn cb
, void * userdata
)
113 struct rc_sub_instruction
* inst
= &fullinst
->U
.I
;
114 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->Opcode
);
116 if (opcode
->HasDstReg
&& inst
->DstReg
.WriteMask
)
117 cb(userdata
, fullinst
, inst
->DstReg
.File
, inst
->DstReg
.Index
, inst
->DstReg
.WriteMask
);
119 if (inst
->WriteALUResult
)
120 cb(userdata
, fullinst
, RC_FILE_SPECIAL
, RC_SPECIAL_ALU_RESULT
, RC_MASK_X
);
123 static void writes_pair(struct rc_instruction
* fullinst
, rc_read_write_mask_fn cb
, void * userdata
)
125 struct rc_pair_instruction
* inst
= &fullinst
->U
.P
;
127 if (inst
->RGB
.WriteMask
)
128 cb(userdata
, fullinst
, RC_FILE_TEMPORARY
, inst
->RGB
.DestIndex
, inst
->RGB
.WriteMask
);
130 if (inst
->Alpha
.WriteMask
)
131 cb(userdata
, fullinst
, RC_FILE_TEMPORARY
, inst
->Alpha
.DestIndex
, RC_MASK_W
);
133 if (inst
->WriteALUResult
)
134 cb(userdata
, fullinst
, RC_FILE_SPECIAL
, RC_SPECIAL_ALU_RESULT
, RC_MASK_X
);
138 * Calls a callback function for all register writes in the instruction,
139 * reporting writemasks to the callback function.
141 * \warning Does not report output registers for paired instructions!
143 void rc_for_all_writes_mask(struct rc_instruction
* inst
, rc_read_write_mask_fn cb
, void * userdata
)
145 if (inst
->Type
== RC_INSTRUCTION_NORMAL
) {
146 writes_normal(inst
, cb
, userdata
);
148 writes_pair(inst
, cb
, userdata
);
153 struct mask_to_chan_data
{
155 rc_read_write_chan_fn Fn
;
158 static void mask_to_chan_cb(void * data
, struct rc_instruction
* inst
,
159 rc_register_file file
, unsigned int index
, unsigned int mask
)
161 struct mask_to_chan_data
* d
= data
;
162 for(unsigned int chan
= 0; chan
< 4; ++chan
) {
163 if (GET_BIT(mask
, chan
))
164 d
->Fn(d
->UserData
, inst
, file
, index
, chan
);
169 * Calls a callback function for all sourced register channels.
171 * This is conservative, i.e. channels may be called multiple times,
172 * and the writemask of the instruction is not taken into account.
174 void rc_for_all_reads_chan(struct rc_instruction
* inst
, rc_read_write_chan_fn cb
, void * userdata
)
176 struct mask_to_chan_data d
;
177 d
.UserData
= userdata
;
179 rc_for_all_reads_mask(inst
, &mask_to_chan_cb
, &d
);
183 * Calls a callback function for all written register channels.
185 * \warning Does not report output registers for paired instructions!
187 void rc_for_all_writes_chan(struct rc_instruction
* inst
, rc_read_write_chan_fn cb
, void * userdata
)
189 struct mask_to_chan_data d
;
190 d
.UserData
= userdata
;
192 rc_for_all_writes_mask(inst
, &mask_to_chan_cb
, &d
);
195 static void remap_normal_instruction(struct rc_instruction
* fullinst
,
196 rc_remap_register_fn cb
, void * userdata
)
198 struct rc_sub_instruction
* inst
= &fullinst
->U
.I
;
199 const struct rc_opcode_info
* opcode
= rc_get_opcode_info(inst
->Opcode
);
201 if (opcode
->HasDstReg
) {
202 rc_register_file file
= inst
->DstReg
.File
;
203 unsigned int index
= inst
->DstReg
.Index
;
205 cb(userdata
, fullinst
, &file
, &index
);
207 inst
->DstReg
.File
= file
;
208 inst
->DstReg
.Index
= index
;
211 for(unsigned int src
= 0; src
< opcode
->NumSrcRegs
; ++src
) {
212 rc_register_file file
= inst
->SrcReg
[src
].File
;
213 unsigned int index
= inst
->SrcReg
[src
].Index
;
215 cb(userdata
, fullinst
, &file
, &index
);
217 inst
->SrcReg
[src
].File
= file
;
218 inst
->SrcReg
[src
].Index
= index
;
222 static void remap_pair_instruction(struct rc_instruction
* fullinst
,
223 rc_remap_register_fn cb
, void * userdata
)
225 struct rc_pair_instruction
* inst
= &fullinst
->U
.P
;
227 if (inst
->RGB
.WriteMask
) {
228 rc_register_file file
= RC_FILE_TEMPORARY
;
229 unsigned int index
= inst
->RGB
.DestIndex
;
231 cb(userdata
, fullinst
, &file
, &index
);
233 inst
->RGB
.DestIndex
= index
;
236 if (inst
->Alpha
.WriteMask
) {
237 rc_register_file file
= RC_FILE_TEMPORARY
;
238 unsigned int index
= inst
->Alpha
.DestIndex
;
240 cb(userdata
, fullinst
, &file
, &index
);
242 inst
->Alpha
.DestIndex
= index
;
245 for(unsigned int src
= 0; src
< 3; ++src
) {
246 if (inst
->RGB
.Src
[src
].Used
) {
247 rc_register_file file
= inst
->RGB
.Src
[src
].File
;
248 unsigned int index
= inst
->RGB
.Src
[src
].Index
;
250 cb(userdata
, fullinst
, &file
, &index
);
252 inst
->RGB
.Src
[src
].File
= file
;
253 inst
->RGB
.Src
[src
].Index
= index
;
256 if (inst
->Alpha
.Src
[src
].Used
) {
257 rc_register_file file
= inst
->Alpha
.Src
[src
].File
;
258 unsigned int index
= inst
->Alpha
.Src
[src
].Index
;
260 cb(userdata
, fullinst
, &file
, &index
);
262 inst
->Alpha
.Src
[src
].File
= file
;
263 inst
->Alpha
.Src
[src
].Index
= index
;
270 * Remap all register accesses according to the given function.
271 * That is, call the function \p cb for each referenced register (both read and written)
272 * and update the given instruction \p inst accordingly
273 * if it modifies its \ref pfile and \ref pindex contents.
275 void rc_remap_registers(struct rc_instruction
* inst
, rc_remap_register_fn cb
, void * userdata
)
277 if (inst
->Type
== RC_INSTRUCTION_NORMAL
)
278 remap_normal_instruction(inst
, cb
, userdata
);
280 remap_pair_instruction(inst
, cb
, userdata
);