1 /*
2 * Copyright © 2010 Intel Corporation
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include <inttypes.h>
7
8 #include "brw_reg.h"
9 #include "util/macros.h"
10
11 bool
brw_reg_saturate_immediate(brw_reg * reg)12 brw_reg_saturate_immediate(brw_reg *reg)
13 {
14 union {
15 unsigned ud;
16 int d;
17 float f;
18 double df;
19 } imm, sat_imm = { 0 };
20
21 const unsigned size = brw_type_size_bytes(reg->type);
22
23 /* We want to either do a 32-bit or 64-bit data copy, the type is otherwise
24 * irrelevant, so just check the size of the type and copy from/to an
25 * appropriately sized field.
26 */
27 if (size < 8)
28 imm.ud = reg->ud;
29 else
30 imm.df = reg->df;
31
32 switch (reg->type) {
33 case BRW_TYPE_UD:
34 case BRW_TYPE_D:
35 case BRW_TYPE_UW:
36 case BRW_TYPE_W:
37 case BRW_TYPE_UQ:
38 case BRW_TYPE_Q:
39 /* Nothing to do. */
40 return false;
41 case BRW_TYPE_F:
42 sat_imm.f = SATURATE(imm.f);
43 break;
44 case BRW_TYPE_DF:
45 sat_imm.df = SATURATE(imm.df);
46 break;
47 case BRW_TYPE_UB:
48 case BRW_TYPE_B:
49 unreachable("no UB/B immediates");
50 case BRW_TYPE_V:
51 case BRW_TYPE_UV:
52 case BRW_TYPE_VF:
53 unreachable("unimplemented: saturate vector immediate");
54 case BRW_TYPE_HF:
55 unreachable("unimplemented: saturate HF immediate");
56 default:
57 unreachable("invalid type");
58 }
59
60 if (size < 8) {
61 if (imm.ud != sat_imm.ud) {
62 reg->ud = sat_imm.ud;
63 return true;
64 }
65 } else {
66 if (imm.df != sat_imm.df) {
67 reg->df = sat_imm.df;
68 return true;
69 }
70 }
71 return false;
72 }
73
74 bool
brw_reg_negate_immediate(brw_reg * reg)75 brw_reg_negate_immediate(brw_reg *reg)
76 {
77 switch (reg->type) {
78 case BRW_TYPE_D:
79 case BRW_TYPE_UD:
80 reg->d = -reg->d;
81 return true;
82 case BRW_TYPE_W:
83 case BRW_TYPE_UW: {
84 uint16_t value = -(int16_t)reg->ud;
85 reg->ud = value | (uint32_t)value << 16;
86 return true;
87 }
88 case BRW_TYPE_F:
89 reg->f = -reg->f;
90 return true;
91 case BRW_TYPE_VF:
92 reg->ud ^= 0x80808080;
93 return true;
94 case BRW_TYPE_DF:
95 reg->df = -reg->df;
96 return true;
97 case BRW_TYPE_UQ:
98 case BRW_TYPE_Q:
99 reg->d64 = -reg->d64;
100 return true;
101 case BRW_TYPE_UB:
102 case BRW_TYPE_B:
103 unreachable("no UB/B immediates");
104 case BRW_TYPE_UV:
105 case BRW_TYPE_V:
106 assert(!"unimplemented: negate UV/V immediate");
107 case BRW_TYPE_HF:
108 reg->ud ^= 0x80008000;
109 return true;
110 default:
111 unreachable("invalid type");
112 }
113
114 return false;
115 }
116
117 bool
brw_reg_abs_immediate(brw_reg * reg)118 brw_reg_abs_immediate(brw_reg *reg)
119 {
120 switch (reg->type) {
121 case BRW_TYPE_D:
122 reg->d = abs(reg->d);
123 return true;
124 case BRW_TYPE_W: {
125 uint16_t value = abs((int16_t)reg->ud);
126 reg->ud = value | (uint32_t)value << 16;
127 return true;
128 }
129 case BRW_TYPE_F:
130 reg->f = fabsf(reg->f);
131 return true;
132 case BRW_TYPE_DF:
133 reg->df = fabs(reg->df);
134 return true;
135 case BRW_TYPE_VF:
136 reg->ud &= ~0x80808080;
137 return true;
138 case BRW_TYPE_Q:
139 reg->d64 = imaxabs(reg->d64);
140 return true;
141 case BRW_TYPE_UB:
142 case BRW_TYPE_B:
143 unreachable("no UB/B immediates");
144 case BRW_TYPE_UQ:
145 case BRW_TYPE_UD:
146 case BRW_TYPE_UW:
147 case BRW_TYPE_UV:
148 /* Presumably the absolute value modifier on an unsigned source is a
149 * nop, but it would be nice to confirm.
150 */
151 assert(!"unimplemented: abs unsigned immediate");
152 case BRW_TYPE_V:
153 assert(!"unimplemented: abs V immediate");
154 case BRW_TYPE_HF:
155 reg->ud &= ~0x80008000;
156 return true;
157 default:
158 unreachable("invalid type");
159 }
160
161 return false;
162 }
163
164 bool
is_zero() const165 brw_reg::is_zero() const
166 {
167 if (file != IMM)
168 return false;
169
170 assert(brw_type_size_bytes(type) > 1);
171
172 switch (type) {
173 case BRW_TYPE_HF:
174 assert((d & 0xffff) == ((d >> 16) & 0xffff));
175 return (d & 0xffff) == 0 || (d & 0xffff) == 0x8000;
176 case BRW_TYPE_F:
177 return f == 0;
178 case BRW_TYPE_DF:
179 return df == 0;
180 case BRW_TYPE_W:
181 case BRW_TYPE_UW:
182 assert((d & 0xffff) == ((d >> 16) & 0xffff));
183 return (d & 0xffff) == 0;
184 case BRW_TYPE_D:
185 case BRW_TYPE_UD:
186 return d == 0;
187 case BRW_TYPE_UQ:
188 case BRW_TYPE_Q:
189 return u64 == 0;
190 default:
191 return false;
192 }
193 }
194
195 bool
is_one() const196 brw_reg::is_one() const
197 {
198 if (file != IMM)
199 return false;
200
201 assert(brw_type_size_bytes(type) > 1);
202
203 switch (type) {
204 case BRW_TYPE_HF:
205 assert((d & 0xffff) == ((d >> 16) & 0xffff));
206 return (d & 0xffff) == 0x3c00;
207 case BRW_TYPE_F:
208 return f == 1.0f;
209 case BRW_TYPE_DF:
210 return df == 1.0;
211 case BRW_TYPE_W:
212 case BRW_TYPE_UW:
213 assert((d & 0xffff) == ((d >> 16) & 0xffff));
214 return (d & 0xffff) == 1;
215 case BRW_TYPE_D:
216 case BRW_TYPE_UD:
217 return d == 1;
218 case BRW_TYPE_UQ:
219 case BRW_TYPE_Q:
220 return u64 == 1;
221 default:
222 return false;
223 }
224 }
225
226 bool
is_negative_one() const227 brw_reg::is_negative_one() const
228 {
229 if (file != IMM)
230 return false;
231
232 assert(brw_type_size_bytes(type) > 1);
233
234 switch (type) {
235 case BRW_TYPE_HF:
236 assert((d & 0xffff) == ((d >> 16) & 0xffff));
237 return (d & 0xffff) == 0xbc00;
238 case BRW_TYPE_F:
239 return f == -1.0;
240 case BRW_TYPE_DF:
241 return df == -1.0;
242 case BRW_TYPE_W:
243 assert((d & 0xffff) == ((d >> 16) & 0xffff));
244 return (d & 0xffff) == 0xffff;
245 case BRW_TYPE_D:
246 return d == -1;
247 case BRW_TYPE_Q:
248 return d64 == -1;
249 default:
250 return false;
251 }
252 }
253
254 bool
is_null() const255 brw_reg::is_null() const
256 {
257 return file == ARF && nr == BRW_ARF_NULL;
258 }
259
260 bool
is_accumulator() const261 brw_reg::is_accumulator() const
262 {
263 return file == ARF && (nr & 0xF0) == BRW_ARF_ACCUMULATOR;
264 }
265
266 bool
is_address() const267 brw_reg::is_address() const
268 {
269 return file == ADDRESS;
270 }
271
272 unsigned
address_slot(unsigned byte_offset) const273 brw_reg::address_slot(unsigned byte_offset) const
274 {
275 assert(is_address());
276 return (reg_offset(*this) + byte_offset) / 2;
277 }
278
279 bool
equals(const brw_reg & r) const280 brw_reg::equals(const brw_reg &r) const
281 {
282 return brw_regs_equal(this, &r);
283 }
284
285 bool
negative_equals(const brw_reg & r) const286 brw_reg::negative_equals(const brw_reg &r) const
287 {
288 return brw_regs_negative_equal(this, &r);
289 }
290
291 bool
is_contiguous() const292 brw_reg::is_contiguous() const
293 {
294 switch (file) {
295 case ADDRESS:
296 case ARF:
297 case FIXED_GRF:
298 return hstride == BRW_HORIZONTAL_STRIDE_1 &&
299 vstride == width + hstride;
300 case VGRF:
301 case ATTR:
302 return stride == 1;
303 case UNIFORM:
304 case IMM:
305 case BAD_FILE:
306 return true;
307 }
308
309 unreachable("Invalid register file");
310 }
311
312 unsigned
component_size(unsigned width) const313 brw_reg::component_size(unsigned width) const
314 {
315 if (file == ADDRESS || file == ARF || file == FIXED_GRF) {
316 const unsigned w = MIN2(width, 1u << this->width);
317 const unsigned h = width >> this->width;
318 const unsigned vs = vstride ? 1 << (vstride - 1) : 0;
319 const unsigned hs = hstride ? 1 << (hstride - 1) : 0;
320 assert(w > 0);
321 /* Note this rounds up to next horizontal stride to be consistent with
322 * the VGRF case below.
323 */
324 return ((MAX2(1, h) - 1) * vs + MAX2(w * hs, 1)) * brw_type_size_bytes(type);
325 } else {
326 return MAX2(width * stride, 1) * brw_type_size_bytes(type);
327 }
328 }
329