2 * Copyright © 2017 Gert Wollny
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 #include "st_tests_common.h"
26 #include "mesa/program/prog_instruction.h"
27 #include "tgsi/tgsi_info.h"
28 #include "tgsi/tgsi_ureg.h"
29 #include "compiler/glsl/list.h"
30 #include "gtest/gtest.h"
43 /* Implementation of helper and test classes */
44 void *FakeCodeline::mem_ctx
= nullptr;
46 FakeCodeline::FakeCodeline(unsigned _op
, const vector
<int>& _dst
,
47 const vector
<int>& _src
, const vector
<int>&_to
):
51 transform(_dst
.begin(), _dst
.end(), std::back_inserter(dst
),
52 [this](int i
) { return create_dst_register(i
);});
54 transform(_src
.begin(), _src
.end(), std::back_inserter(src
),
55 [this](int i
) { return create_src_register(i
);});
57 transform(_to
.begin(), _to
.end(), std::back_inserter(tex_offsets
),
58 [this](int i
) { return create_src_register(i
);});
62 FakeCodeline::FakeCodeline(unsigned _op
, const vector
<pair
<int,int>>& _dst
,
63 const vector
<pair
<int, const char *>>& _src
,
64 const vector
<pair
<int, const char *>>&_to
,
71 transform(_dst
.begin(), _dst
.end(), std::back_inserter(dst
),
72 [this](pair
<int,int> r
) {
73 return create_dst_register(r
.first
, r
.second
);
76 transform(_src
.begin(), _src
.end(), std::back_inserter(src
),
77 [this](const pair
<int,const char *>& r
) {
78 return create_src_register(r
.first
, r
.second
);
81 transform(_to
.begin(), _to
.end(), std::back_inserter(tex_offsets
),
82 [this](const pair
<int,const char *>& r
) {
83 return create_src_register(r
.first
, r
.second
);
87 FakeCodeline::FakeCodeline(const glsl_to_tgsi_instruction
& instr
):
91 int nsrc
= num_inst_src_regs(&instr
);
92 int ndst
= num_inst_dst_regs(&instr
);
94 copy(instr
.src
, instr
.src
+ nsrc
, std::back_inserter(src
));
95 copy(instr
.dst
, instr
.dst
+ ndst
, std::back_inserter(dst
));
105 template <typename st_reg
>
106 void FakeCodeline::read_reg(const st_reg
& s
)
108 if (s
.file
== PROGRAM_TEMPORARY
) {
109 if (s
.index
> max_temp_id
)
110 max_temp_id
= s
.index
;
114 void FakeCodeline::print(std::ostream
& os
) const
116 const struct tgsi_opcode_info
*info
= tgsi_get_opcode_info(op
);
117 os
<< tgsi_get_opcode_name(info
->opcode
) << " ";
129 bool operator == (const FakeCodeline
& lhs
, const FakeCodeline
& rhs
)
131 if ((lhs
.op
!= rhs
.op
) ||
132 (lhs
.src
.size() != rhs
.src
.size()) ||
133 (lhs
.dst
.size() != rhs
.dst
.size()))
136 return std::equal(lhs
.src
.begin(), lhs
.src
.end(), rhs
.src
.begin()) &&
137 std::equal(lhs
.dst
.begin(), lhs
.dst
.end(), rhs
.dst
.begin());
140 st_src_reg
FakeCodeline::create_src_register(int src_idx
)
142 return create_src_register(src_idx
,
143 src_idx
< 0 ? PROGRAM_INPUT
: PROGRAM_TEMPORARY
);
146 static int swizzle_from_char(const char *sw
)
149 if (!sw
|| sw
[0] == 0)
152 const char *isw
= sw
;
153 for (int i
= 0; i
< 4; ++i
) {
155 case 'x': break; /* is zero */
156 case 'y': swizzle
|= SWIZZLE_Y
<< 3 * i
; break;
157 case 'z': swizzle
|= SWIZZLE_Z
<< 3 * i
; break;
158 case 'w': swizzle
|= SWIZZLE_W
<< 3 * i
; break;
160 assert(!"This test uses an unknown swizzle character");
168 st_src_reg
FakeCodeline::create_src_register(int src_idx
, const char *sw
)
170 st_src_reg result
= create_src_register(src_idx
);
171 result
.swizzle
= swizzle_from_char(sw
);
175 st_src_reg
FakeCodeline::create_src_register(int src_idx
, gl_register_file file
)
179 retval
.index
= src_idx
>= 0 ? src_idx
: 1 - src_idx
;
181 if (file
== PROGRAM_TEMPORARY
) {
182 if (max_temp_id
< src_idx
)
183 max_temp_id
= src_idx
;
184 } else if (file
== PROGRAM_ARRAY
) {
187 retval
.swizzle
= SWIZZLE_XYZW
;
188 retval
.type
= GLSL_TYPE_INT
;
193 st_dst_reg
FakeCodeline::create_dst_register(int dst_idx
)
195 return create_dst_register(dst_idx
, dst_idx
< 0 ?
196 PROGRAM_OUTPUT
: PROGRAM_TEMPORARY
);
199 st_dst_reg
FakeCodeline::create_dst_register(int dst_idx
,int writemask
)
201 gl_register_file file
;
204 file
= PROGRAM_TEMPORARY
;
206 if (max_temp_id
< idx
)
209 file
= PROGRAM_OUTPUT
;
212 return st_dst_reg(file
, writemask
, GLSL_TYPE_INT
, idx
);
215 st_dst_reg
FakeCodeline::create_dst_register(int dst_idx
, gl_register_file file
)
219 retval
.index
= dst_idx
>= 0 ? dst_idx
: 1 - dst_idx
;
221 if (file
== PROGRAM_TEMPORARY
) {
222 if (max_temp_id
< dst_idx
)
223 max_temp_id
= dst_idx
;
224 } else if (file
== PROGRAM_ARRAY
) {
227 retval
.writemask
= 0xF;
228 retval
.type
= GLSL_TYPE_INT
;
233 glsl_to_tgsi_instruction
*FakeCodeline::get_codeline() const
235 glsl_to_tgsi_instruction
*next_instr
= new(mem_ctx
) glsl_to_tgsi_instruction();
237 next_instr
->info
= tgsi_get_opcode_info(op
);
239 assert(src
.size() == num_inst_src_regs(next_instr
));
240 assert(dst
.size() == num_inst_dst_regs(next_instr
));
241 assert(tex_offsets
.size() < 3);
243 copy(src
.begin(), src
.end(), next_instr
->src
);
244 copy(dst
.begin(), dst
.end(), next_instr
->dst
);
246 next_instr
->tex_offset_num_offset
= tex_offsets
.size();
248 if (next_instr
->tex_offset_num_offset
> 0) {
249 next_instr
->tex_offsets
= ralloc_array(mem_ctx
, st_src_reg
, tex_offsets
.size());
250 copy(tex_offsets
.begin(), tex_offsets
.end(), next_instr
->tex_offsets
);
252 next_instr
->tex_offsets
= nullptr;
257 void FakeCodeline::set_mem_ctx(void *ctx
)
262 FakeShader::FakeShader(const vector
<FakeCodeline
>& source
):
266 for (const FakeCodeline
& i
: source
) {
267 int t
= i
.get_max_reg_id();
274 FakeShader::FakeShader(exec_list
*tgsi_prog
):
277 FakeCodeline
nop(TGSI_OPCODE_NOP
);
278 FakeCodeline
& last
= nop
;
280 foreach_in_list(glsl_to_tgsi_instruction
, inst
, tgsi_prog
) {
281 program
.push_back(last
= FakeCodeline(*inst
));
282 if (num_temps
< last
.get_max_reg_id())
283 num_temps
= last
.get_max_reg_id();
288 int FakeShader::get_num_temps() const
293 exec_list
* FakeShader::get_program(void *ctx
) const
295 exec_list
*prog
= new(ctx
) exec_list();
297 for (const FakeCodeline
& i
: program
) {
298 prog
->push_tail(i
.get_codeline());
304 void MesaTestWithMemCtx::SetUp()
306 mem_ctx
= ralloc_context(nullptr);
307 FakeCodeline::set_mem_ctx(mem_ctx
);
310 void MesaTestWithMemCtx::TearDown()
312 ralloc_free(mem_ctx
);
313 FakeCodeline::set_mem_ctx(nullptr);
318 LifetimeEvaluatorTest::lifetime_result
319 LifetimeEvaluatorTest::run(const vector
<FakeCodeline
>& code
, bool& success
)
321 FakeShader
shader(code
);
322 lifetime_result
result(shader
.get_num_temps());
325 get_temp_registers_required_lifetimes(mem_ctx
, shader
.get_program(mem_ctx
),
326 shader
.get_num_temps(),
332 void LifetimeEvaluatorTest::run(const vector
<FakeCodeline
>& code
, const temp_lt_expect
& e
)
334 FakeShader
shader(code
);
335 lifetime_result
result(shader
.get_num_temps());
337 get_temp_registers_required_lifetimes(mem_ctx
, shader
.get_program(mem_ctx
),
338 shader
.get_num_temps(),
340 ASSERT_TRUE(success
);
341 ASSERT_EQ(result
.size(), e
.size());
345 void LifetimeEvaluatorExactTest::check( const vector
<lifetime
>& lifetimes
,
346 const temp_lt_expect
& e
)
348 for (unsigned i
= 1; i
< lifetimes
.size(); ++i
) {
349 EXPECT_EQ(lifetimes
[i
].begin
, e
[i
][0]);
350 EXPECT_EQ(lifetimes
[i
].end
, e
[i
][1]);
354 void LifetimeEvaluatorAtLeastTest::check( const vector
<lifetime
>& lifetimes
,
355 const temp_lt_expect
& e
)
357 for (unsigned i
= 1; i
< lifetimes
.size(); ++i
) {
358 EXPECT_LE(lifetimes
[i
].begin
, e
[i
][0]);
359 EXPECT_GE(lifetimes
[i
].end
, e
[i
][1]);
363 void RegisterRemappingTest::run(const vector
<lifetime
>& lt
,
364 const vector
<int>& expect
)
366 rename_reg_pair proto
{false,0};
367 vector
<rename_reg_pair
> result(lt
.size(), proto
);
369 get_temp_registers_remapping(mem_ctx
, lt
.size(), <
[0], &result
[0]);
371 vector
<int> remap(lt
.size());
372 for (unsigned i
= 0; i
< lt
.size(); ++i
) {
373 remap
[i
] = result
[i
].valid
? result
[i
].new_reg
: i
;
376 std::transform(remap
.begin(), remap
.end(), result
.begin(), remap
.begin(),
377 [](int x
, const rename_reg_pair
& rn
) {
378 return rn
.valid
? rn
.new_reg
: x
;
381 for(unsigned i
= 1; i
< remap
.size(); ++i
) {
382 EXPECT_EQ(remap
[i
], expect
[i
]);
386 void RegisterLifetimeAndRemappingTest::run(const vector
<FakeCodeline
>& code
,
387 const vector
<int>& expect
)
389 FakeShader
shader(code
);
390 std::vector
<lifetime
> lt(shader
.get_num_temps());
391 get_temp_registers_required_lifetimes(mem_ctx
, shader
.get_program(mem_ctx
),
392 shader
.get_num_temps(), <
[0]);
393 this->run(lt
, expect
);