3 * Copyright (c) 2018-2019 Collabora LTD
5 * Author: Gert Wollny <gert.wollny@collabora.com>
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * on the rights to use, copy, modify, merge, publish, distribute, sub
11 * license, and/or sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice (including the next
15 * paragraph) shall be included in all copies or substantial portions of the
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 * USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include "sfn_debug.h"
28 #include "sfn_value_gpr.h"
29 #include "sfn_valuepool.h"
41 ValuePool::ValuePool():
42 m_next_register_index(0),
43 current_temp_reg_index(0),
48 PValue
ValuePool::m_undef
= Value::zero
;
50 GPRVector
ValuePool::vec_from_nir(const nir_dest
& dst
, int num_components
)
52 std::array
<PValue
, 4> result
;
53 for (int i
= 0; i
< 4; ++i
)
54 result
[i
] = from_nir(dst
, i
< num_components
? i
: 7);
55 return GPRVector(result
);
58 std::vector
<PValue
> ValuePool::varvec_from_nir(const nir_dest
& dst
, int num_components
)
60 std::vector
<PValue
> result(num_components
);
61 for (int i
= 0; i
< num_components
; ++i
)
62 result
[i
] = from_nir(dst
, i
);
67 std::vector
<PValue
> ValuePool::varvec_from_nir(const nir_src
& src
, int num_components
)
69 std::vector
<PValue
> result(num_components
);
71 for (i
= 0; i
< num_components
; ++i
)
72 result
[i
] = from_nir(src
, i
);
78 PValue
ValuePool::from_nir(const nir_src
& v
, unsigned component
, unsigned swizzled
)
80 sfn_log
<< SfnLog::reg
<< "Search " << (v
.is_ssa
? "ssa_reg " : "reg ")
81 << (v
.is_ssa
? v
.ssa
->index
: v
.reg
.reg
->index
);
84 int idx
= lookup_register_index(v
);
85 sfn_log
<< SfnLog::reg
<< " -> got index " << idx
<< "\n";
87 auto reg
= lookup_register(idx
, swizzled
, false);
89 if (reg
->type() == Value::gpr_vector
) {
90 auto& array
= static_cast<GPRArray
&>(*reg
);
91 reg
= array
.get_indirect(v
.reg
.base_offset
,
93 from_nir(*v
.reg
.indirect
, 0, 0) : nullptr,
99 assert(0 && "local registers should always be found");
102 unsigned index
= v
.ssa
->index
;
103 /* For undefs we use zero and let ()yet to be implemeneted dce deal with it */
104 if (m_ssa_undef
.find(index
) != m_ssa_undef
.end())
108 int idx
= lookup_register_index(v
);
109 sfn_log
<< SfnLog::reg
<< " -> got index " << idx
<< "\n";
111 auto reg
= lookup_register(idx
, swizzled
, false);
117 auto literal_val
= m_literal_constants
.find(index
);
118 if (literal_val
!= m_literal_constants
.end()) {
119 switch (literal_val
->second
->def
.bit_size
) {
121 return PValue(new LiteralValue(literal_val
->second
->value
[swizzled
].b
? 0xffffffff : 0, component
));
123 return literal(literal_val
->second
->value
[swizzled
].u32
);
125 sfn_log
<< SfnLog::reg
<< "Unsupported bit size " << literal_val
->second
->def
.bit_size
126 << " fall back to 32\n";
127 return PValue(new LiteralValue(literal_val
->second
->value
[swizzled
].u32
, component
));
131 unsigned uindex
= (index
<< 2) + swizzled
;
132 auto u
= m_uniforms
.find(uindex
);
133 if (u
!= m_uniforms
.end())
139 PValue
ValuePool::from_nir(const nir_src
& v
, unsigned component
)
141 return from_nir(v
, component
, component
);
144 PValue
ValuePool::from_nir(const nir_tex_src
&v
, unsigned component
)
146 return from_nir(v
.src
, component
, component
);
149 PValue
ValuePool::from_nir(const nir_alu_src
&v
, unsigned component
)
151 return from_nir(v
.src
, component
, v
.swizzle
[component
]);
154 PValue
ValuePool::get_temp_register()
156 if (next_temp_reg_comp
> 3) {
157 current_temp_reg_index
= allocate_temp_register();
158 next_temp_reg_comp
= 0;
160 return PValue(new GPRValue(current_temp_reg_index
, next_temp_reg_comp
++));
163 GPRVector
ValuePool::get_temp_vec4()
165 int sel
= allocate_temp_register();
166 return GPRVector(sel
, {0,1,2,3});
169 PValue
ValuePool::create_register_from_nir_src(const nir_src
& src
, int comp
)
171 int idx
= src
.is_ssa
? get_dst_ssa_register_index(*src
.ssa
):
172 get_local_register_index(*src
.reg
.reg
);
174 auto retval
= lookup_register(idx
, comp
, false);
175 if (!retval
|| retval
->type() != Value::gpr
|| retval
->type() != Value::gpr_array_value
)
176 retval
= create_register(idx
, comp
);
180 PValue
ValuePool::from_nir(const nir_alu_dest
&v
, unsigned component
)
182 //assert(v->write_mask & (1 << component));
183 return from_nir(v
.dest
, component
);
186 int ValuePool::lookup_register_index(const nir_dest
& dst
)
188 return dst
.is_ssa
? get_dst_ssa_register_index(dst
.ssa
):
189 get_local_register_index(*dst
.reg
.reg
);
192 int ValuePool::lookup_register_index(const nir_src
& src
) const
197 get_ssa_register_index(*src
.ssa
) :
198 get_local_register_index(*src
.reg
.reg
);
200 sfn_log
<< SfnLog::reg
<< " LIDX:" << index
;
202 auto r
= m_register_map
.find(index
);
203 if (r
== m_register_map
.end()) {
206 return static_cast<int>(r
->second
.index
);
210 int ValuePool::allocate_component(unsigned index
, unsigned comp
, bool pre_alloc
)
213 return allocate_with_mask(index
, 1 << comp
, pre_alloc
);
216 int ValuePool::allocate_temp_register()
218 return m_next_register_index
++;
222 PValue
ValuePool::from_nir(const nir_dest
& v
, unsigned component
)
224 int idx
= lookup_register_index(v
);
225 sfn_log
<< SfnLog::reg
<< __func__
<< ": ";
227 sfn_log
<< "ssa_" << v
.ssa
.index
;
229 sfn_log
<< "r" << v
.reg
.reg
->index
;
230 sfn_log
<< " -> " << idx
<< "\n";
232 auto retval
= lookup_register(idx
, component
, false);
234 retval
= create_register(idx
, component
);
236 if (retval
->type() == Value::gpr_vector
) {
238 auto& array
= static_cast<GPRArray
&>(*retval
);
239 retval
= array
.get_indirect(v
.reg
.base_offset
,
241 from_nir(*v
.reg
.indirect
, 0, 0) : nullptr,
248 ValueMap
ValuePool::get_temp_registers() const
252 for (auto& v
: m_registers
) {
253 if (v
.second
->type() == Value::gpr
)
254 result
.insert(v
.second
);
255 else if (v
.second
->type() == Value::gpr_vector
) {
256 auto& array
= static_cast<GPRArray
&>(*v
.second
);
257 array
.collect_registers(result
);
263 static const char swz
[] = "xyzw01?_";
265 PValue
ValuePool::create_register(unsigned sel
, unsigned swizzle
)
267 sfn_log
<< SfnLog::reg
268 <<"Create register " << sel
<< '.' << swz
[swizzle
] << "\n";
269 auto retval
= PValue(new GPRValue(sel
, swizzle
));
270 m_registers
[(sel
<< 3) + swizzle
] = retval
;
274 bool ValuePool::inject_register(unsigned sel
, unsigned swizzle
,
275 const PValue
& reg
, bool map
)
277 uint32_t ssa_index
= sel
;
280 auto pos
= m_ssa_register_map
.find(sel
);
281 if (pos
== m_ssa_register_map
.end())
282 ssa_index
= m_next_register_index
++;
284 ssa_index
= pos
->second
;
287 sfn_log
<< SfnLog::reg
288 << "Inject register " << sel
<< '.' << swz
[swizzle
]
289 << " at index " << ssa_index
<< " ...";
292 m_ssa_register_map
[sel
] = ssa_index
;
294 allocate_with_mask(ssa_index
, swizzle
, true);
296 unsigned idx
= (ssa_index
<< 3) + swizzle
;
297 auto p
= m_registers
.find(idx
);
298 if ( (p
!= m_registers
.end()) && *p
->second
!= *reg
) {
299 std::cerr
<< "Register location (" << ssa_index
<< ", " << swizzle
<< ") was already reserved\n";
303 sfn_log
<< SfnLog::reg
<< " at idx:" << idx
<< " to " << *reg
<< "\n";
304 m_registers
[idx
] = reg
;
306 if (m_next_register_index
<= ssa_index
)
307 m_next_register_index
= ssa_index
+ 1;
312 PValue
ValuePool::lookup_register(unsigned sel
, unsigned swizzle
,
317 sfn_log
<< SfnLog::reg
318 << "lookup register " << sel
<< '.' << swz
[swizzle
] << "("
319 << ((sel
<< 3) + swizzle
) << ")...";
322 auto reg
= m_registers
.find((sel
<< 3) + swizzle
);
323 if (reg
!= m_registers
.end()) {
324 sfn_log
<< SfnLog::reg
<< " -> Found " << *reg
->second
<< "\n";
325 retval
= reg
->second
;
326 } else if (swizzle
== 7) {
327 PValue retval
= create_register(sel
, swizzle
);
328 sfn_log
<< SfnLog::reg
<< " -> Created " << *retval
<< "\n";
329 } else if (required
) {
330 sfn_log
<< SfnLog::reg
<< "Register (" << sel
<< ", "
331 << swizzle
<< ") not found but required\n";
332 assert(0 && "Unallocated register value requested\n");
334 sfn_log
<< SfnLog::reg
<< " -> Not required and not allocated\n";
338 unsigned ValuePool::get_dst_ssa_register_index(const nir_ssa_def
& ssa
)
340 sfn_log
<< SfnLog::reg
<< __func__
<< ": search dst ssa "
343 auto pos
= m_ssa_register_map
.find(ssa
.index
);
344 if (pos
== m_ssa_register_map
.end()) {
345 sfn_log
<< SfnLog::reg
<< " Need to allocate ...";
346 allocate_ssa_register(ssa
);
347 pos
= m_ssa_register_map
.find(ssa
.index
);
348 assert(pos
!= m_ssa_register_map
.end());
350 sfn_log
<< SfnLog::reg
<< "... got " << pos
->second
<< "\n";
354 unsigned ValuePool::get_ssa_register_index(const nir_ssa_def
& ssa
) const
356 sfn_log
<< SfnLog::reg
<< __func__
<< ": search ssa "
359 auto pos
= m_ssa_register_map
.find(ssa
.index
);
360 sfn_log
<< SfnLog::reg
<< " got " << pos
->second
<< "\n";
361 if (pos
== m_ssa_register_map
.end()) {
362 sfn_log
<< SfnLog::reg
<< __func__
<< ": ssa register "
363 << ssa
.index
<< " lookup failed\n";
369 unsigned ValuePool::get_local_register_index(const nir_register
& reg
)
371 auto pos
= m_local_register_map
.find(reg
.index
);
372 if (pos
== m_local_register_map
.end()) {
373 allocate_local_register(reg
);
374 pos
= m_local_register_map
.find(reg
.index
);
375 assert(pos
!= m_local_register_map
.end());
380 unsigned ValuePool::get_local_register_index(const nir_register
& reg
) const
382 auto pos
= m_local_register_map
.find(reg
.index
);
383 if (pos
== m_local_register_map
.end()) {
384 sfn_log
<< SfnLog::err
<< __func__
<< ": local register "
385 << reg
.index
<< " lookup failed";
391 void ValuePool::allocate_ssa_register(const nir_ssa_def
& ssa
)
393 sfn_log
<< SfnLog::reg
<< "ValuePool: Allocate ssa register " << ssa
.index
394 << " as " << m_next_register_index
<< "\n";
395 int index
= m_next_register_index
++;
396 m_ssa_register_map
[ssa
.index
] = index
;
397 allocate_with_mask(index
, 0xf, true);
400 void ValuePool::allocate_arrays(array_list
& arrays
)
403 int current_index
= m_next_register_index
;
404 unsigned instance
= 0;
406 while (!arrays
.empty()) {
407 auto a
= arrays
.top();
410 /* This is a bit hackish, return an id that encodes the array merge. To make sure
411 * that the mapping doesn't go wrong we have to make sure the arrays is longer than
412 * the number of instances in this arrays slot */
413 if (a
.ncomponents
+ ncomponents
> 4 ||
414 a
.length
< instance
) {
415 current_index
= m_next_register_index
;
420 if (ncomponents
== 0)
421 m_next_register_index
+= a
.length
;
423 uint32_t mask
= ((1 << a
.ncomponents
) - 1) << ncomponents
;
425 PValue array
= PValue(new GPRArray(current_index
, a
.length
, mask
, ncomponents
));
427 sfn_log
<< SfnLog::reg
<< "Add array at "<< current_index
428 << " of size " << a
.length
<< " with " << a
.ncomponents
429 << " components, mask " << mask
<< "\n";
431 m_local_register_map
[a
.index
] = current_index
+ instance
;
433 for (unsigned i
= 0; i
< a
.ncomponents
; ++i
)
434 m_registers
[((current_index
+ instance
) << 3) + i
] = array
;
436 VRec next_reg
= {current_index
+ instance
, mask
, mask
};
437 m_register_map
[current_index
+ instance
] = next_reg
;
439 ncomponents
+= a
.ncomponents
;
444 void ValuePool::allocate_local_register(const nir_register
& reg
)
446 int index
= m_next_register_index
++;
447 m_local_register_map
[reg
.index
] = index
;
448 allocate_with_mask(index
, 0xf, true);
450 /* Create actual register and map it */;
451 for (int i
= 0; i
< 4; ++i
) {
452 int k
= (index
<< 3) + i
;
453 m_registers
[k
] = PValue(new GPRValue(index
, i
));
457 void ValuePool::allocate_local_register(const nir_register
& reg
, array_list
& arrays
)
459 sfn_log
<< SfnLog::reg
<< "ValuePool: Allocate local register " << reg
.index
460 << " as " << m_next_register_index
<< "\n";
462 if (reg
.num_array_elems
) {
463 array_entry ae
= {reg
.index
, reg
.num_array_elems
, reg
.num_components
};
467 allocate_local_register(reg
);
470 bool ValuePool::create_undef(nir_ssa_undef_instr
* instr
)
472 m_ssa_undef
.insert(instr
->def
.index
);
476 bool ValuePool::set_literal_constant(nir_load_const_instr
* instr
)
478 sfn_log
<< SfnLog::reg
<< "Add literal " << instr
->def
.index
<< "\n";
479 m_literal_constants
[instr
->def
.index
] = instr
;
483 const nir_load_const_instr
* ValuePool::get_literal_constant(int index
)
485 sfn_log
<< SfnLog::reg
<< "Try to locate literal " << index
<< "...";
486 auto literal
= m_literal_constants
.find(index
);
487 if (literal
== m_literal_constants
.end()) {
488 sfn_log
<< SfnLog::reg
<< " not found\n";
491 sfn_log
<< SfnLog::reg
<< " found\n";
492 return literal
->second
;
495 void ValuePool::add_uniform(unsigned index
, const PValue
& value
)
497 sfn_log
<< SfnLog::reg
<< "Reserve " << *value
<< " as " << index
<< "\n";
498 m_uniforms
[index
] = value
;
501 PValue
ValuePool::uniform(unsigned index
)
503 sfn_log
<< SfnLog::reg
<< "Search index " << index
<< "\n";
504 auto i
= m_uniforms
.find(index
);
505 return i
== m_uniforms
.end() ? PValue() : i
->second
;
508 int ValuePool::allocate_with_mask(unsigned index
, unsigned mask
, bool pre_alloc
)
511 VRec next_register
= { index
, mask
};
513 sfn_log
<< SfnLog::reg
<< (pre_alloc
? "Pre-alloc" : "Allocate")
514 << " register (" << index
<< ", " << mask
<< ")\n";
516 auto r
= m_register_map
.find(index
);
518 if (r
!= m_register_map
.end()) {
519 if ((r
->second
.mask
& next_register
.mask
) &&
520 !(r
->second
.pre_alloc_mask
& next_register
.mask
)) {
521 std::cerr
<< "r600 ERR: register ("
522 << index
<< ", " << mask
523 << ") already allocated as (" << r
->second
.index
<< ", "
524 << r
->second
.mask
<< ", " << r
->second
.pre_alloc_mask
528 r
->second
.mask
|= next_register
.mask
;
530 r
->second
.pre_alloc_mask
|= next_register
.mask
;
531 retval
= r
->second
.index
;
535 next_register
.pre_alloc_mask
= mask
;
536 m_register_map
[index
] = next_register
;
537 retval
= next_register
.index
;
540 sfn_log
<< SfnLog::reg
<< "Allocate register (" << index
<< "," << mask
<< ") in R"
546 PValue
ValuePool::literal(uint32_t value
)
548 auto l
= m_literals
.find(value
);
549 if (l
!= m_literals
.end())
552 m_literals
[value
] = PValue(new LiteralValue(value
));
553 return m_literals
[value
];