3 * Copyright (c) 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.
28 #include "sfn_instruction_export.h"
29 #include "sfn_liverange.h"
30 #include "sfn_valuepool.h"
34 WriteoutInstruction::WriteoutInstruction(instr_type t
, const GPRVector
& value
):
38 add_remappable_src_value(&m_value
);
41 void WriteoutInstruction::replace_values(const ValueSet
& candiates
, PValue new_value
)
43 // I wonder whether we can actually end up here ...
44 for (auto c
: candiates
) {
45 if (*c
== *m_value
.reg_i(c
->chan()))
46 m_value
.set_reg_i(c
->chan(), new_value
);
49 replace_values_child(candiates
, new_value
);
52 void WriteoutInstruction::replace_values_child(UNUSED
const ValueSet
& candiates
,
53 UNUSED PValue new_value
)
57 void WriteoutInstruction::remap_registers_child(UNUSED
std::vector
<rename_reg_pair
>& map
,
58 UNUSED ValueMap
& values
)
62 ExportInstruction::ExportInstruction(unsigned loc
, const GPRVector
&value
, ExportType type
):
63 WriteoutInstruction(Instruction::exprt
, value
),
71 bool ExportInstruction::is_equal_to(const Instruction
& lhs
) const
73 assert(lhs
.type() == exprt
);
74 const auto& oth
= static_cast<const ExportInstruction
&>(lhs
);
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
);
82 void ExportInstruction::do_print(std::ostream
& os
) const
84 os
<< (m_is_last
? "EXPORT_DONE ":"EXPORT ");
86 case et_pixel
: os
<< "PIXEL "; break;
87 case et_pos
: os
<< "POS "; break;
88 case et_param
: os
<< "PARAM "; break;
90 os
<< m_loc
<< " " << gpr();
93 void ExportInstruction::update_output_map(OutputRegisterMap
& map
) const
95 map
[m_loc
] = gpr_ptr();
98 void ExportInstruction::set_last()
103 WriteScratchInstruction::WriteScratchInstruction(unsigned loc
, const GPRVector
& value
,
104 int align
, int align_offset
, int writemask
):
105 WriteoutInstruction (Instruction::mem_wr_scratch
, value
),
108 m_align_offset(align_offset
),
109 m_writemask(writemask
),
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
),
120 m_align_offset(align_offset
),
121 m_writemask(writemask
),
122 m_array_size(array_size
- 1)
124 add_remappable_src_value(&m_address
);
127 bool WriteScratchInstruction::is_equal_to(const Instruction
& lhs
) const
129 if (lhs
.type() != Instruction::mem_wr_scratch
)
131 const auto& other
= static_cast<const WriteScratchInstruction
&>(lhs
);
134 if (!other
.m_address
)
136 if (*m_address
!= *other
.m_address
)
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
;
150 static char *writemask_to_swizzle(int writemask
, char *buf
)
152 const char *swz
= "xyzw";
153 for (int i
= 0; i
< 4; ++i
) {
154 buf
[i
] = (writemask
& (1 << i
)) ? swz
[i
] : '_';
159 void WriteScratchInstruction::do_print(std::ostream
& os
) const
163 os
<< "MEM_SCRATCH_WRITE ";
165 os
<< "@" << *m_address
<< "+";
167 os
<< m_loc
<< "." << writemask_to_swizzle(m_writemask
, buf
)
168 << " " << gpr() << " AL:" << m_align
<< " ALO:" << m_align_offset
;
171 void WriteScratchInstruction::replace_values_child(const ValueSet
& candiates
, PValue new_value
)
176 for (auto c
: candiates
) {
177 if (*c
== *m_address
)
178 m_address
= new_value
;
182 void WriteScratchInstruction::remap_registers_child(std::vector
<rename_reg_pair
>& map
,
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()];
191 m_address
= values
.get_or_inject(new_index
.new_reg
, m_address
->chan());
192 map
[m_address
->sel()].used
= true;
195 StreamOutIntruction::StreamOutIntruction(const GPRVector
& value
, int num_components
,
196 int array_base
, int comp_mask
, int out_buffer
,
198 WriteoutInstruction(Instruction::streamout
, value
),
199 m_element_size(num_components
== 3 ? 3 : num_components
- 1),
201 m_array_base(array_base
),
203 m_writemask(comp_mask
),
204 m_output_buffer(out_buffer
),
209 unsigned StreamOutIntruction::op() const
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;
218 return 4 * m_stream
+ op
;
221 bool StreamOutIntruction::is_equal_to(const Instruction
& lhs
) const
223 assert(lhs
.type() == streamout
);
224 const auto& oth
= static_cast<const StreamOutIntruction
&>(lhs
);
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
;
236 void StreamOutIntruction::do_print(std::ostream
& os
) const
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
;
247 MemRingOutIntruction::MemRingOutIntruction(ECFOpCode ring
, EMemWriteType type
,
248 const GPRVector
& value
,
249 unsigned base_addr
, unsigned ncomp
,
251 WriteoutInstruction(Instruction::ring
, value
),
254 m_base_address(base_addr
),
258 add_remappable_src_value(&m_index
);
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);
265 unsigned MemRingOutIntruction::ncomp() const
267 switch (m_num_comp
) {
278 bool MemRingOutIntruction::is_equal_to(const Instruction
& lhs
) const
280 assert(lhs
.type() == streamout
);
281 const auto& oth
= static_cast<const MemRingOutIntruction
&>(lhs
);
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
;
289 if (m_type
== mem_write_ind
|| m_type
== mem_write_ind_ack
)
290 equal
&= (*m_index
== *oth
.m_index
);
295 static const char *write_type_str
[4] = {"WRITE", "WRITE_IDX", "WRITE_ACK", "WRITE_IDX_ACK" };
296 void MemRingOutIntruction::do_print(std::ostream
& os
) const
298 os
<< "MEM_RING " << m_ring_op
;
299 os
<< " " << write_type_str
[m_type
] << " " << m_base_address
;
301 if (m_type
== mem_write_ind
|| m_type
== mem_write_ind_ack
)
302 os
<< " @" << *m_index
;
303 os
<< " ES:" << m_num_comp
;
307 void MemRingOutIntruction::replace_values_child(const ValueSet
& candiates
,
313 for (auto c
: candiates
) {
319 void MemRingOutIntruction::remap_registers_child(std::vector
<rename_reg_pair
>& map
,
325 assert(m_index
->type() == Value::gpr
);
326 auto new_index
= map
[m_index
->sel()];
328 m_index
= values
.get_or_inject(new_index
.new_reg
, m_index
->chan());
329 map
[m_index
->sel()].used
= true;