1 /*
2 * Copyright 2008-2009 Nicolai Haehnle.
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "radeon_program_pair.h"
7
8 #include "radeon_compiler_util.h"
9
10 #include <stdlib.h>
11
12 /**
13 * Return the source slot where we installed the given register access,
14 * or -1 if no slot was free anymore.
15 */
rc_pair_alloc_source(struct rc_pair_instruction * pair,unsigned int rgb,unsigned int alpha,rc_register_file file,unsigned int index)16 int rc_pair_alloc_source(struct rc_pair_instruction *pair,
17 unsigned int rgb, unsigned int alpha,
18 rc_register_file file, unsigned int index)
19 {
20 int candidate = -1;
21 int candidate_quality = -1;
22 unsigned int alpha_used = 0;
23 unsigned int rgb_used = 0;
24 int i;
25
26 if ((!rgb && !alpha) || file == RC_FILE_NONE)
27 return 0;
28
29 /* Make sure only one presubtract operation is used per instruction. */
30 if (file == RC_FILE_PRESUB) {
31 if (rgb && pair->RGB.Src[RC_PAIR_PRESUB_SRC].Used
32 && index != pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index) {
33 return -1;
34 }
35
36 if (alpha && pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Used
37 && index != pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index) {
38 return -1;
39 }
40 }
41
42 for(i = 0; i < 3; ++i) {
43 int q = 0;
44 if (rgb) {
45 if (pair->RGB.Src[i].Used) {
46 if (pair->RGB.Src[i].File != file ||
47 pair->RGB.Src[i].Index != index) {
48 rgb_used++;
49 continue;
50 }
51 q++;
52 }
53 }
54 if (alpha) {
55 if (pair->Alpha.Src[i].Used) {
56 if (pair->Alpha.Src[i].File != file ||
57 pair->Alpha.Src[i].Index != index) {
58 alpha_used++;
59 continue;
60 }
61 q++;
62 }
63 }
64 if (q > candidate_quality) {
65 candidate_quality = q;
66 candidate = i;
67 }
68 }
69
70 if (file == RC_FILE_PRESUB) {
71 candidate = RC_PAIR_PRESUB_SRC;
72 } else if (candidate < 0 || (rgb && rgb_used > 2)
73 || (alpha && alpha_used > 2)) {
74 return -1;
75 }
76
77 /* candidate >= 0 */
78
79 if (rgb) {
80 pair->RGB.Src[candidate].Used = 1;
81 pair->RGB.Src[candidate].File = file;
82 pair->RGB.Src[candidate].Index = index;
83 if (candidate == RC_PAIR_PRESUB_SRC) {
84 /* For registers with the RC_FILE_PRESUB file,
85 * the index stores the presubtract op. */
86 int src_regs = rc_presubtract_src_reg_count(index);
87 for(i = 0; i < src_regs; i++) {
88 pair->RGB.Src[i].Used = 1;
89 }
90 }
91 }
92 if (alpha) {
93 pair->Alpha.Src[candidate].Used = 1;
94 pair->Alpha.Src[candidate].File = file;
95 pair->Alpha.Src[candidate].Index = index;
96 if (candidate == RC_PAIR_PRESUB_SRC) {
97 /* For registers with the RC_FILE_PRESUB file,
98 * the index stores the presubtract op. */
99 int src_regs = rc_presubtract_src_reg_count(index);
100 for(i=0; i < src_regs; i++) {
101 pair->Alpha.Src[i].Used = 1;
102 }
103 }
104 }
105
106 return candidate;
107 }
108
pair_foreach_source_callback(struct rc_pair_instruction * pair,void * data,rc_pair_foreach_src_fn cb,unsigned int swz,unsigned int src)109 static void pair_foreach_source_callback(
110 struct rc_pair_instruction * pair,
111 void * data,
112 rc_pair_foreach_src_fn cb,
113 unsigned int swz,
114 unsigned int src)
115 {
116 /* swz > 3 means that the swizzle is either not used, or a constant
117 * swizzle (e.g. 0, 1, 0.5). */
118 if(swz > 3)
119 return;
120
121 if(swz == RC_SWIZZLE_W) {
122 if (src == RC_PAIR_PRESUB_SRC) {
123 unsigned int i;
124 unsigned int src_count = rc_presubtract_src_reg_count(
125 pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index);
126 for(i = 0; i < src_count; i++) {
127 cb(data, &pair->Alpha.Src[i]);
128 }
129 } else {
130 cb(data, &pair->Alpha.Src[src]);
131 }
132 } else {
133 if (src == RC_PAIR_PRESUB_SRC) {
134 unsigned int i;
135 unsigned int src_count = rc_presubtract_src_reg_count(
136 pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index);
137 for(i = 0; i < src_count; i++) {
138 cb(data, &pair->RGB.Src[i]);
139 }
140 }
141 else {
142 cb(data, &pair->RGB.Src[src]);
143 }
144 }
145 }
146
rc_pair_foreach_source_that_alpha_reads(struct rc_pair_instruction * pair,void * data,rc_pair_foreach_src_fn cb)147 void rc_pair_foreach_source_that_alpha_reads(
148 struct rc_pair_instruction * pair,
149 void * data,
150 rc_pair_foreach_src_fn cb)
151 {
152 unsigned int i;
153 const struct rc_opcode_info * info =
154 rc_get_opcode_info(pair->Alpha.Opcode);
155 for(i = 0; i < info->NumSrcRegs; i++) {
156 pair_foreach_source_callback(pair, data, cb,
157 GET_SWZ(pair->Alpha.Arg[i].Swizzle, 0),
158 pair->Alpha.Arg[i].Source);
159 }
160 }
161
rc_pair_foreach_source_that_rgb_reads(struct rc_pair_instruction * pair,void * data,rc_pair_foreach_src_fn cb)162 void rc_pair_foreach_source_that_rgb_reads(
163 struct rc_pair_instruction * pair,
164 void * data,
165 rc_pair_foreach_src_fn cb)
166 {
167 unsigned int i;
168 const struct rc_opcode_info * info =
169 rc_get_opcode_info(pair->RGB.Opcode);
170 for(i = 0; i < info->NumSrcRegs; i++) {
171 unsigned int chan;
172 unsigned int swz = RC_SWIZZLE_UNUSED;
173 /* Find a swizzle that is either X,Y,Z,or W. We assume here
174 * that if one channel swizzles X,Y, or Z, then none of the
175 * other channels swizzle W, and vice-versa. */
176 for(chan = 0; chan < 4; chan++) {
177 swz = GET_SWZ(pair->RGB.Arg[i].Swizzle, chan);
178 if(swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y
179 || swz == RC_SWIZZLE_Z || swz == RC_SWIZZLE_W)
180 continue;
181 }
182 pair_foreach_source_callback(pair, data, cb,
183 swz,
184 pair->RGB.Arg[i].Source);
185 }
186 }
187
rc_pair_get_src(struct rc_pair_instruction * pair_inst,struct rc_pair_instruction_arg * arg)188 struct rc_pair_instruction_source * rc_pair_get_src(
189 struct rc_pair_instruction * pair_inst,
190 struct rc_pair_instruction_arg * arg)
191 {
192 unsigned int type;
193
194 type = rc_source_type_swz(arg->Swizzle);
195
196 if (type & RC_SOURCE_RGB) {
197 return &pair_inst->RGB.Src[arg->Source];
198 } else if (type & RC_SOURCE_ALPHA) {
199 return &pair_inst->Alpha.Src[arg->Source];
200 } else {
201 return NULL;
202 }
203 }
204
rc_pair_get_src_index(struct rc_pair_instruction * pair_inst,struct rc_pair_instruction_source * src)205 int rc_pair_get_src_index(
206 struct rc_pair_instruction * pair_inst,
207 struct rc_pair_instruction_source * src)
208 {
209 int i;
210 for (i = 0; i < 3; i++) {
211 if (&pair_inst->RGB.Src[i] == src
212 || &pair_inst->Alpha.Src[i] == src) {
213 return i;
214 }
215 }
216 return -1;
217 }
218