1 /* -*- mesa-c++  -*-
2  *
3  * Copyright (c) 2019 Collabora LTD
4  *
5  * Author: Gert Wollny <gert.wollny@collabora.com>
6  *
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:
13  *
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
16  * Software.
17  *
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.
25  */
26 
27 
28 #include "sfn_instruction_export.h"
29 #include "sfn_liverange.h"
30 #include "sfn_valuepool.h"
31 
32 namespace r600 {
33 
WriteoutInstruction(instr_type t,const GPRVector & value)34 WriteoutInstruction::WriteoutInstruction(instr_type t, const GPRVector& value):
35    Instruction(t),
36    m_value(value)
37 {
38    add_remappable_src_value(&m_value);
39 }
40 
replace_values(const ValueSet & candidates,PValue new_value)41 void WriteoutInstruction::replace_values(const ValueSet& candidates, PValue new_value)
42 {
43    // I wonder whether we can actually end up here ...
44    for (auto c: candidates) {
45       if (*c == *m_value.reg_i(c->chan()))
46          m_value.set_reg_i(c->chan(), new_value);
47    }
48 
49    replace_values_child(candidates, new_value);
50 }
51 
replace_values_child(UNUSED const ValueSet & candidates,UNUSED PValue new_value)52 void WriteoutInstruction::replace_values_child(UNUSED const ValueSet& candidates,
53                                                UNUSED PValue new_value)
54 {
55 }
56 
remap_registers_child(UNUSED std::vector<rename_reg_pair> & map,UNUSED ValueMap & values)57 void WriteoutInstruction::remap_registers_child(UNUSED std::vector<rename_reg_pair>& map,
58                                                 UNUSED ValueMap& values)
59 {
60 }
61 
ExportInstruction(unsigned loc,const GPRVector & value,ExportType type)62 ExportInstruction::ExportInstruction(unsigned loc, const GPRVector &value, ExportType type):
63    WriteoutInstruction(Instruction::exprt, value),
64    m_type(type),
65    m_loc(loc),
66    m_is_last(false)
67 {
68 }
69 
70 
is_equal_to(const Instruction & lhs) const71 bool ExportInstruction::is_equal_to(const Instruction& lhs) const
72 {
73    assert(lhs.type() == exprt);
74    const auto& oth = static_cast<const ExportInstruction&>(lhs);
75 
76    return (gpr() == oth.gpr()) &&
77          (m_type == oth.m_type) &&
78          (m_loc == oth.m_loc) &&
79          (m_is_last == oth.m_is_last);
80 }
81 
do_print(std::ostream & os) const82 void ExportInstruction::do_print(std::ostream& os) const
83 {
84    os << (m_is_last ? "EXPORT_DONE ":"EXPORT ");
85    switch (m_type) {
86    case et_pixel: os << "PIXEL "; break;
87    case et_pos: os << "POS "; break;
88    case et_param: os << "PARAM "; break;
89    }
90    os << m_loc << " " << gpr();
91 }
92 
update_output_map(OutputRegisterMap & map) const93 void ExportInstruction::update_output_map(OutputRegisterMap& map) const
94 {
95    map[m_loc] = gpr_ptr();
96 }
97 
set_last()98 void ExportInstruction::set_last()
99 {
100    m_is_last = true;
101 }
102 
WriteScratchInstruction(unsigned loc,const GPRVector & value,int align,int align_offset,int writemask)103 WriteScratchInstruction::WriteScratchInstruction(unsigned loc, const GPRVector& value,
104                                                  int align, int align_offset, int writemask):
105    WriteoutInstruction (Instruction::mem_wr_scratch, value),
106    m_loc(loc),
107    m_align(align),
108    m_align_offset(align_offset),
109    m_writemask(writemask),
110    m_array_size(0)
111 {
112 }
113 
WriteScratchInstruction(const PValue & address,const GPRVector & value,int align,int align_offset,int writemask,int array_size)114 WriteScratchInstruction::WriteScratchInstruction(const PValue& address, const GPRVector& value,
115                                                  int align, int align_offset, int writemask, int array_size):
116    WriteoutInstruction (Instruction::mem_wr_scratch, value),
117    m_loc(0),
118    m_address(address),
119    m_align(align),
120    m_align_offset(align_offset),
121    m_writemask(writemask),
122    m_array_size(array_size - 1)
123 {
124    add_remappable_src_value(&m_address);
125 }
126 
is_equal_to(const Instruction & lhs) const127 bool WriteScratchInstruction::is_equal_to(const Instruction& lhs) const
128 {
129    if (lhs.type() != Instruction::mem_wr_scratch)
130       return false;
131    const auto& other = static_cast<const WriteScratchInstruction&>(lhs);
132 
133    if (m_address) {
134       if (!other.m_address)
135          return false;
136       if (*m_address != *other.m_address)
137          return false;
138    } else {
139       if (other.m_address)
140          return false;
141    }
142 
143    return gpr() == other.gpr() &&
144          m_loc == other.m_loc &&
145          m_align == other.m_align &&
146          m_align_offset == other.m_align_offset &&
147          m_writemask == other.m_writemask;
148 }
149 
writemask_to_swizzle(int writemask,char * buf)150 static char *writemask_to_swizzle(int writemask, char *buf)
151 {
152    const char *swz = "xyzw";
153    for (int i = 0; i < 4; ++i) {
154       buf[i] = (writemask & (1 << i)) ? swz[i] : '_';
155    }
156    return buf;
157 }
158 
do_print(std::ostream & os) const159 void WriteScratchInstruction::do_print(std::ostream& os) const
160 {
161    char buf[5];
162 
163    os << "MEM_SCRATCH_WRITE ";
164    if (m_address)
165       os << "@" << *m_address << "+";
166 
167    os << m_loc  << "." << writemask_to_swizzle(m_writemask, buf)
168       << " " <<  gpr()  << " AL:" << m_align << " ALO:" << m_align_offset;
169 }
170 
replace_values_child(const ValueSet & candidates,PValue new_value)171 void WriteScratchInstruction::replace_values_child(const ValueSet& candidates, PValue new_value)
172 {
173    if (!m_address)
174       return;
175 
176    for (auto c: candidates) {
177       if (*c == *m_address)
178          m_address = new_value;
179    }
180 }
181 
remap_registers_child(std::vector<rename_reg_pair> & map,ValueMap & values)182 void WriteScratchInstruction::remap_registers_child(std::vector<rename_reg_pair>& map,
183                            ValueMap& values)
184 {
185    if (!m_address)
186       return;
187    sfn_log << SfnLog::merge << "Remap " << *m_address <<  " of type " << m_address->type() << "\n";
188    assert(m_address->type() == Value::gpr);
189    auto new_index = map[m_address->sel()];
190    if (new_index.valid)
191       m_address = values.get_or_inject(new_index.new_reg, m_address->chan());
192    map[m_address->sel()].used = true;
193 }
194 
StreamOutIntruction(const GPRVector & value,int num_components,int array_base,int comp_mask,int out_buffer,int stream)195 StreamOutIntruction::StreamOutIntruction(const GPRVector& value, int num_components,
196                                          int array_base, int comp_mask, int out_buffer,
197                                          int stream):
198    WriteoutInstruction(Instruction::streamout, value),
199    m_element_size(num_components == 3 ? 3 : num_components - 1),
200    m_burst_count(1),
201    m_array_base(array_base),
202    m_array_size(0xfff),
203    m_writemask(comp_mask),
204    m_output_buffer(out_buffer),
205    m_stream(stream)
206 {
207 }
208 
op() const209 unsigned StreamOutIntruction::op() const
210 {
211    int op = 0;
212    switch (m_output_buffer) {
213    case 0: op = CF_OP_MEM_STREAM0_BUF0; break;
214    case 1: op = CF_OP_MEM_STREAM0_BUF1; break;
215    case 2: op = CF_OP_MEM_STREAM0_BUF2; break;
216    case 3: op = CF_OP_MEM_STREAM0_BUF3; break;
217    }
218    return 4 * m_stream + op;
219 }
220 
is_equal_to(const Instruction & lhs) const221 bool StreamOutIntruction::is_equal_to(const Instruction& lhs) const
222 {
223    assert(lhs.type() == streamout);
224    const auto& oth = static_cast<const StreamOutIntruction&>(lhs);
225 
226    return gpr() == oth.gpr() &&
227          m_element_size == oth.m_element_size &&
228          m_burst_count == oth.m_burst_count &&
229          m_array_base == oth.m_array_base &&
230          m_array_size == oth.m_array_size &&
231          m_writemask == oth.m_writemask &&
232          m_output_buffer == oth.m_output_buffer &&
233          m_stream == oth.m_stream;
234 }
235 
do_print(std::ostream & os) const236 void StreamOutIntruction::do_print(std::ostream& os) const
237 {
238    os << "WRITE STREAM(" << m_stream << ") "  << gpr()
239       << " ES:" << m_element_size
240       << " BC:" << m_burst_count
241       << " BUF:" << m_output_buffer
242       << " ARRAY:" <<  m_array_base;
243    if (m_array_size != 0xfff)
244       os << "+" << m_array_size;
245 }
246 
MemRingOutIntruction(ECFOpCode ring,EMemWriteType type,const GPRVector & value,unsigned base_addr,unsigned ncomp,PValue index)247 MemRingOutIntruction::MemRingOutIntruction(ECFOpCode ring, EMemWriteType type,
248                                            const GPRVector& value,
249                                            unsigned base_addr, unsigned ncomp,
250                                            PValue index):
251    WriteoutInstruction(Instruction::ring, value),
252    m_ring_op(ring),
253    m_type(type),
254    m_base_address(base_addr),
255    m_num_comp(ncomp),
256    m_index(index)
257 {
258    add_remappable_src_value(&m_index);
259 
260    assert(m_ring_op  == cf_mem_ring || m_ring_op  == cf_mem_ring1||
261           m_ring_op  == cf_mem_ring2 || m_ring_op  == cf_mem_ring3);
262    assert(m_num_comp <= 4);
263 }
264 
ncomp() const265 unsigned MemRingOutIntruction::ncomp() const
266 {
267    switch (m_num_comp) {
268    case 1: return 0;
269    case 2: return 1;
270    case 3:
271    case 4: return 3;
272    default:
273       assert(0);
274    }
275    return 3;
276 }
277 
is_equal_to(const Instruction & lhs) const278 bool MemRingOutIntruction::is_equal_to(const Instruction& lhs) const
279 {
280    assert(lhs.type() == streamout);
281    const auto& oth = static_cast<const MemRingOutIntruction&>(lhs);
282 
283    bool equal = gpr() == oth.gpr() &&
284                 m_ring_op == oth.m_ring_op &&
285                 m_type == oth.m_type &&
286                 m_num_comp == oth.m_num_comp &&
287                 m_base_address == oth.m_base_address;
288 
289    if (m_type == mem_write_ind || m_type == mem_write_ind_ack)
290       equal &= (*m_index == *oth.m_index);
291    return equal;
292 
293 }
294 
295 static const char *write_type_str[4] = {"WRITE", "WRITE_IDX", "WRITE_ACK", "WRITE_IDX_ACK" };
do_print(std::ostream & os) const296 void MemRingOutIntruction::do_print(std::ostream& os) const
297 {
298    os << "MEM_RING " << m_ring_op;
299    os << " " << write_type_str[m_type] << " " << m_base_address;
300    os << " " << gpr();
301    if (m_type == mem_write_ind || m_type == mem_write_ind_ack)
302       os << " @" << *m_index;
303    os << " ES:" << m_num_comp;
304 }
305 
306 
replace_values_child(const ValueSet & candidates,PValue new_value)307 void MemRingOutIntruction::replace_values_child(const ValueSet& candidates,
308                                                 PValue new_value)
309 {
310    if (!m_index)
311       return;
312 
313    for (auto c: candidates) {
314       if (*c == *m_index)
315          m_index = new_value;
316    }
317 }
318 
remap_registers_child(std::vector<rename_reg_pair> & map,ValueMap & values)319 void MemRingOutIntruction::remap_registers_child(std::vector<rename_reg_pair>& map,
320                                                  ValueMap& values)
321 {
322    if (!m_index)
323       return;
324 
325    assert(m_index->type() == Value::gpr);
326    auto new_index = map[m_index->sel()];
327    if (new_index.valid)
328       m_index = values.get_or_inject(new_index.new_reg, m_index->chan());
329    map[m_index->sel()].used = true;
330 }
331 
patch_ring(int stream,PValue index)332 void MemRingOutIntruction::patch_ring(int stream, PValue index)
333 {
334    const ECFOpCode ring_op[4] = {cf_mem_ring, cf_mem_ring1, cf_mem_ring2, cf_mem_ring3};
335 
336    assert(stream < 4);
337    m_ring_op = ring_op[stream];
338    m_index = index;
339 }
340 
341 }
342