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.
31 * "Not-quite SSA" and Dead-Code Elimination.
33 * @note This code uses SWIZZLE_NIL in a source register to indicate that
34 * the corresponding component is ignored by the corresponding instruction.
37 #include "radeon_nqssadce.h"
39 #include "radeon_compiler.h"
43 * Return the @ref register_state for the given register (or 0 for untracked
44 * registers, i.e. constants).
46 static struct register_state
*get_reg_state(struct nqssadce_state
* s
, GLuint file
, GLuint index
)
49 case PROGRAM_TEMPORARY
: return &s
->Temps
[index
];
50 case PROGRAM_OUTPUT
: return &s
->Outputs
[index
];
51 case PROGRAM_ADDRESS
: return &s
->Address
;
58 * Left multiplication of a register with a swizzle
60 * @note Works correctly only for X, Y, Z, W swizzles, not for constant swizzles.
62 struct prog_src_register
lmul_swizzle(GLuint swizzle
, struct prog_src_register srcreg
)
64 struct prog_src_register tmp
= srcreg
;
67 tmp
.Negate
= NEGATE_NONE
;
68 for(i
= 0; i
< 4; ++i
) {
69 GLuint swz
= GET_SWZ(swizzle
, i
);
71 tmp
.Swizzle
|= GET_SWZ(srcreg
.Swizzle
, swz
) << (i
*3);
72 tmp
.Negate
|= GET_BIT(srcreg
.Negate
, swz
) << i
;
74 tmp
.Swizzle
|= swz
<< (i
*3);
81 static void track_used_srcreg(struct nqssadce_state
* s
,
82 GLint src
, GLuint sourced
)
84 struct prog_instruction
* inst
= &s
->IP
->I
;
86 GLuint deswz_source
= 0;
88 for(i
= 0; i
< 4; ++i
) {
89 if (GET_BIT(sourced
, i
)) {
90 GLuint swz
= GET_SWZ(inst
->SrcReg
[src
].Swizzle
, i
);
91 deswz_source
|= 1 << swz
;
93 inst
->SrcReg
[src
].Swizzle
&= ~(7 << (3*i
));
94 inst
->SrcReg
[src
].Swizzle
|= SWIZZLE_NIL
<< (3*i
);
98 if (!s
->Descr
->IsNativeSwizzle(inst
->Opcode
, inst
->SrcReg
[src
])) {
99 struct prog_dst_register dstreg
= inst
->DstReg
;
100 dstreg
.File
= PROGRAM_TEMPORARY
;
101 dstreg
.Index
= rc_find_free_temporary(s
->Compiler
);
102 dstreg
.WriteMask
= sourced
;
104 s
->Descr
->BuildSwizzle(s
, dstreg
, inst
->SrcReg
[src
]);
106 inst
->SrcReg
[src
].File
= PROGRAM_TEMPORARY
;
107 inst
->SrcReg
[src
].Index
= dstreg
.Index
;
108 inst
->SrcReg
[src
].Swizzle
= 0;
109 inst
->SrcReg
[src
].Negate
= NEGATE_NONE
;
110 inst
->SrcReg
[src
].Abs
= 0;
111 for(i
= 0; i
< 4; ++i
) {
112 if (GET_BIT(sourced
, i
))
113 inst
->SrcReg
[src
].Swizzle
|= i
<< (3*i
);
115 inst
->SrcReg
[src
].Swizzle
|= SWIZZLE_NIL
<< (3*i
);
117 deswz_source
= sourced
;
120 struct register_state
*regstate
;
122 if (inst
->SrcReg
[src
].RelAddr
) {
123 regstate
= get_reg_state(s
, PROGRAM_ADDRESS
, 0);
125 regstate
->Sourced
|= WRITEMASK_X
;
127 regstate
= get_reg_state(s
, inst
->SrcReg
[src
].File
, inst
->SrcReg
[src
].Index
);
129 regstate
->Sourced
|= deswz_source
& 0xf;
133 static void unalias_srcregs(struct rc_instruction
*inst
, GLuint oldindex
, GLuint newindex
)
135 int nsrc
= _mesa_num_inst_src_regs(inst
->I
.Opcode
);
137 for(i
= 0; i
< nsrc
; ++i
)
138 if (inst
->I
.SrcReg
[i
].File
== PROGRAM_TEMPORARY
&& inst
->I
.SrcReg
[i
].Index
== oldindex
)
139 inst
->I
.SrcReg
[i
].Index
= newindex
;
142 static void unalias_temporary(struct nqssadce_state
* s
, GLuint oldindex
)
144 GLuint newindex
= rc_find_free_temporary(s
->Compiler
);
145 struct rc_instruction
* inst
;
146 for(inst
= s
->Compiler
->Program
.Instructions
.Next
; inst
!= s
->IP
; inst
= inst
->Next
) {
147 if (inst
->I
.DstReg
.File
== PROGRAM_TEMPORARY
&& inst
->I
.DstReg
.Index
== oldindex
)
148 inst
->I
.DstReg
.Index
= newindex
;
149 unalias_srcregs(inst
, oldindex
, newindex
);
151 unalias_srcregs(s
->IP
, oldindex
, newindex
);
156 * Handle one instruction.
158 static void process_instruction(struct nqssadce_state
* s
)
160 struct prog_instruction
*inst
= &s
->IP
->I
;
163 if (inst
->Opcode
== OPCODE_END
)
166 if (inst
->Opcode
!= OPCODE_KIL
) {
167 struct register_state
*regstate
= get_reg_state(s
, inst
->DstReg
.File
, inst
->DstReg
.Index
);
169 rc_error(s
->Compiler
, "NqssaDce: bad destination register (%i[%i])\n",
170 inst
->DstReg
.File
, inst
->DstReg
.Index
);
174 inst
->DstReg
.WriteMask
&= regstate
->Sourced
;
175 regstate
->Sourced
&= ~inst
->DstReg
.WriteMask
;
177 if (inst
->DstReg
.WriteMask
== 0) {
178 struct rc_instruction
* inst_remove
= s
->IP
;
180 rc_remove_instruction(inst_remove
);
184 if (inst
->DstReg
.File
== PROGRAM_TEMPORARY
&& !regstate
->Sourced
)
185 unalias_temporary(s
, inst
->DstReg
.Index
);
188 WriteMask
= inst
->DstReg
.WriteMask
;
190 switch (inst
->Opcode
) {
196 track_used_srcreg(s
, 0, WriteMask
);
204 track_used_srcreg(s
, 0, WriteMask
);
205 track_used_srcreg(s
, 1, WriteMask
);
209 track_used_srcreg(s
, 0, WriteMask
);
210 track_used_srcreg(s
, 1, WriteMask
);
211 track_used_srcreg(s
, 2, WriteMask
);
219 track_used_srcreg(s
, 0, 0x1);
222 track_used_srcreg(s
, 0, 0x7);
223 track_used_srcreg(s
, 1, 0x7);
226 track_used_srcreg(s
, 0, 0xf);
227 track_used_srcreg(s
, 1, 0xf);
233 track_used_srcreg(s
, 0, 0xf);
236 track_used_srcreg(s
, 0, 0x6);
237 track_used_srcreg(s
, 1, 0xa);
242 track_used_srcreg(s
, 0, 0x3);
245 track_used_srcreg(s
, 0, 0xb);
248 rc_error(s
->Compiler
, "NqssaDce: Unknown opcode %d\n", inst
->Opcode
);
255 void rc_calculate_inputs_outputs(struct radeon_compiler
* c
)
257 struct rc_instruction
*inst
;
259 c
->Program
.InputsRead
= 0;
260 c
->Program
.OutputsWritten
= 0;
262 for(inst
= c
->Program
.Instructions
.Next
; inst
!= &c
->Program
.Instructions
; inst
= inst
->Next
)
265 int num_src_regs
= _mesa_num_inst_src_regs(inst
->I
.Opcode
);
267 for (i
= 0; i
< num_src_regs
; ++i
) {
268 if (inst
->I
.SrcReg
[i
].File
== PROGRAM_INPUT
)
269 c
->Program
.InputsRead
|= 1 << inst
->I
.SrcReg
[i
].Index
;
272 if (_mesa_num_inst_dst_regs(inst
->I
.Opcode
)) {
273 if (inst
->I
.DstReg
.File
== PROGRAM_OUTPUT
)
274 c
->Program
.OutputsWritten
|= 1 << inst
->I
.DstReg
.Index
;
279 void radeonNqssaDce(struct radeon_compiler
* c
, struct radeon_nqssadce_descr
* descr
, void * data
)
281 struct nqssadce_state s
;
283 _mesa_bzero(&s
, sizeof(s
));
288 s
.IP
= c
->Program
.Instructions
.Prev
;
290 while(s
.IP
!= &c
->Program
.Instructions
&& !c
->Error
)
291 process_instruction(&s
);
293 rc_calculate_inputs_outputs(c
);