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 */
16 int
rc_pair_alloc_source(struct rc_pair_instruction * pair,unsigned int rgb,unsigned int alpha,rc_register_file file,unsigned int index)17 rc_pair_alloc_source(struct rc_pair_instruction *pair, 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 || pair->RGB.Src[i].Index != index) {
47 rgb_used++;
48 continue;
49 }
50 q++;
51 }
52 }
53 if (alpha) {
54 if (pair->Alpha.Src[i].Used) {
55 if (pair->Alpha.Src[i].File != file || pair->Alpha.Src[i].Index != index) {
56 alpha_used++;
57 continue;
58 }
59 q++;
60 }
61 }
62 if (q > candidate_quality) {
63 candidate_quality = q;
64 candidate = i;
65 }
66 }
67
68 if (file == RC_FILE_PRESUB) {
69 candidate = RC_PAIR_PRESUB_SRC;
70 } else if (candidate < 0 || (rgb && rgb_used > 2) || (alpha && alpha_used > 2)) {
71 return -1;
72 }
73
74 /* candidate >= 0 */
75
76 if (rgb) {
77 pair->RGB.Src[candidate].Used = 1;
78 pair->RGB.Src[candidate].File = file;
79 pair->RGB.Src[candidate].Index = index;
80 if (candidate == RC_PAIR_PRESUB_SRC) {
81 /* For registers with the RC_FILE_PRESUB file,
82 * the index stores the presubtract op. */
83 int src_regs = rc_presubtract_src_reg_count(index);
84 for (i = 0; i < src_regs; i++) {
85 pair->RGB.Src[i].Used = 1;
86 }
87 }
88 }
89 if (alpha) {
90 pair->Alpha.Src[candidate].Used = 1;
91 pair->Alpha.Src[candidate].File = file;
92 pair->Alpha.Src[candidate].Index = index;
93 if (candidate == RC_PAIR_PRESUB_SRC) {
94 /* For registers with the RC_FILE_PRESUB file,
95 * the index stores the presubtract op. */
96 int src_regs = rc_presubtract_src_reg_count(index);
97 for (i = 0; i < src_regs; i++) {
98 pair->Alpha.Src[i].Used = 1;
99 }
100 }
101 }
102
103 return candidate;
104 }
105
106 static void
pair_foreach_source_callback(struct rc_pair_instruction * pair,void * data,rc_pair_foreach_src_fn cb,unsigned int swz,unsigned int src)107 pair_foreach_source_callback(struct rc_pair_instruction *pair, void *data,
108 rc_pair_foreach_src_fn cb, unsigned int swz, unsigned int src)
109 {
110 /* swz > 3 means that the swizzle is either not used, or a constant
111 * swizzle (e.g. 0, 1, 0.5). */
112 if (swz > 3)
113 return;
114
115 if (swz == RC_SWIZZLE_W) {
116 if (src == RC_PAIR_PRESUB_SRC) {
117 unsigned int i;
118 unsigned int src_count =
119 rc_presubtract_src_reg_count(pair->Alpha.Src[RC_PAIR_PRESUB_SRC].Index);
120 for (i = 0; i < src_count; i++) {
121 cb(data, &pair->Alpha.Src[i]);
122 }
123 } else {
124 cb(data, &pair->Alpha.Src[src]);
125 }
126 } else {
127 if (src == RC_PAIR_PRESUB_SRC) {
128 unsigned int i;
129 unsigned int src_count =
130 rc_presubtract_src_reg_count(pair->RGB.Src[RC_PAIR_PRESUB_SRC].Index);
131 for (i = 0; i < src_count; i++) {
132 cb(data, &pair->RGB.Src[i]);
133 }
134 } else {
135 cb(data, &pair->RGB.Src[src]);
136 }
137 }
138 }
139
140 void
rc_pair_foreach_source_that_alpha_reads(struct rc_pair_instruction * pair,void * data,rc_pair_foreach_src_fn cb)141 rc_pair_foreach_source_that_alpha_reads(struct rc_pair_instruction *pair, void *data,
142 rc_pair_foreach_src_fn cb)
143 {
144 unsigned int i;
145 const struct rc_opcode_info *info = rc_get_opcode_info(pair->Alpha.Opcode);
146 for (i = 0; i < info->NumSrcRegs; i++) {
147 pair_foreach_source_callback(pair, data, cb, GET_SWZ(pair->Alpha.Arg[i].Swizzle, 0),
148 pair->Alpha.Arg[i].Source);
149 }
150 }
151
152 void
rc_pair_foreach_source_that_rgb_reads(struct rc_pair_instruction * pair,void * data,rc_pair_foreach_src_fn cb)153 rc_pair_foreach_source_that_rgb_reads(struct rc_pair_instruction *pair, void *data,
154 rc_pair_foreach_src_fn cb)
155 {
156 unsigned int i;
157 const struct rc_opcode_info *info = rc_get_opcode_info(pair->RGB.Opcode);
158 for (i = 0; i < info->NumSrcRegs; i++) {
159 unsigned int chan;
160 unsigned int swz = RC_SWIZZLE_UNUSED;
161 /* Find a swizzle that is either X,Y,Z,or W. We assume here
162 * that if one channel swizzles X,Y, or Z, then none of the
163 * other channels swizzle W, and vice-versa. */
164 for (chan = 0; chan < 4; chan++) {
165 swz = GET_SWZ(pair->RGB.Arg[i].Swizzle, chan);
166 if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y || swz == RC_SWIZZLE_Z ||
167 swz == RC_SWIZZLE_W)
168 continue;
169 }
170 pair_foreach_source_callback(pair, data, cb, swz, pair->RGB.Arg[i].Source);
171 }
172 }
173
174 struct rc_pair_instruction_source *
rc_pair_get_src(struct rc_pair_instruction * pair_inst,struct rc_pair_instruction_arg * arg)175 rc_pair_get_src(struct rc_pair_instruction *pair_inst, struct rc_pair_instruction_arg *arg)
176 {
177 unsigned int type;
178
179 type = rc_source_type_swz(arg->Swizzle);
180
181 if (type & RC_SOURCE_RGB) {
182 return &pair_inst->RGB.Src[arg->Source];
183 } else if (type & RC_SOURCE_ALPHA) {
184 return &pair_inst->Alpha.Src[arg->Source];
185 } else {
186 return NULL;
187 }
188 }
189
190 int
rc_pair_get_src_index(struct rc_pair_instruction * pair_inst,struct rc_pair_instruction_source * src)191 rc_pair_get_src_index(struct rc_pair_instruction *pair_inst, struct rc_pair_instruction_source *src)
192 {
193 int i;
194 for (i = 0; i < 3; i++) {
195 if (&pair_inst->RGB.Src[i] == src || &pair_inst->Alpha.Src[i] == src) {
196 return i;
197 }
198 }
199 return -1;
200 }
201