blob: f2b7ec786abe8eeec8c540bd7759c2218566cb60 [file] [log] [blame]
/*
* Copyright © 2020 Valve Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
*/
#include "helpers.h"
#include <stdio.h>
#include <sstream>
#include <llvm-c/Target.h>
using namespace aco;
ac_shader_config config;
radv_shader_info info;
std::unique_ptr<Program> program;
Builder bld(NULL);
Temp inputs[16];
Temp exec_input;
const char *subvariant = "";
void create_program(enum chip_class chip_class, Stage stage, unsigned wave_size, enum radeon_family family)
{
memset(&config, 0, sizeof(config));
info.wave_size = wave_size;
program.reset(new Program);
aco::init_program(program.get(), stage, &info, chip_class, family, &config);
Block *block = program->create_and_insert_block();
block->kind = block_kind_top_level;
bld = Builder(program.get(), &program->blocks[0]);
config.float_mode = program->blocks[0].fp_mode.val;
}
bool setup_cs(const char *input_spec, enum chip_class chip_class,
enum radeon_family family, unsigned wave_size)
{
const char *old_subvariant = subvariant;
subvariant = "";
if (!set_variant(chip_class, old_subvariant))
return false;
memset(&info, 0, sizeof(info));
info.cs.block_size[0] = 1;
info.cs.block_size[1] = 1;
info.cs.block_size[2] = 1;
create_program(chip_class, compute_cs, wave_size, family);
if (input_spec) {
unsigned num_inputs = DIV_ROUND_UP(strlen(input_spec), 3u);
aco_ptr<Instruction> startpgm{create_instruction<Pseudo_instruction>(aco_opcode::p_startpgm, Format::PSEUDO, 0, num_inputs + 1)};
for (unsigned i = 0; i < num_inputs; i++) {
RegClass cls(input_spec[i * 3] == 'v' ? RegType::vgpr : RegType::sgpr, input_spec[i * 3 + 1] - '0');
inputs[i] = bld.tmp(cls);
startpgm->definitions[i] = Definition(inputs[i]);
}
exec_input = bld.tmp(program->lane_mask);
startpgm->definitions[num_inputs] = bld.exec(Definition(exec_input));
bld.insert(std::move(startpgm));
}
return true;
}
void finish_program(Program *program)
{
for (Block& BB : program->blocks) {
for (unsigned idx : BB.linear_preds)
program->blocks[idx].linear_succs.emplace_back(BB.index);
for (unsigned idx : BB.logical_preds)
program->blocks[idx].logical_succs.emplace_back(BB.index);
}
for (Block& block : program->blocks) {
if (block.linear_succs.size() == 0) {
block.kind |= block_kind_uniform;
Builder bld(program, &block);
if (program->wb_smem_l1_on_end)
bld.smem(aco_opcode::s_dcache_wb, false);
bld.sopp(aco_opcode::s_endpgm);
}
}
}
void finish_validator_test()
{
finish_program(program.get());
aco_print_program(program.get(), output);
fprintf(output, "Validation results:\n");
if (aco::validate(program.get(), output))
fprintf(output, "Validation passed\n");
else
fprintf(output, "Validation failed\n");
}
void finish_opt_test()
{
finish_program(program.get());
if (!aco::validate(program.get(), output)) {
fail_test("Validation before optimization failed");
return;
}
aco::optimize(program.get());
if (!aco::validate(program.get(), output)) {
fail_test("Validation after optimization failed");
return;
}
aco_print_program(program.get(), output);
}
void finish_to_hw_instr_test()
{
finish_program(program.get());
aco::lower_to_hw_instr(program.get());
aco_print_program(program.get(), output);
}
void finish_assembler_test()
{
finish_program(program.get());
std::vector<uint32_t> binary;
unsigned exec_size = emit_program(program.get(), binary);
/* we could use CLRX for disassembly but that would require it to be
* installed */
if (program->chip_class == GFX10_3 && LLVM_VERSION_MAJOR < 9) {
skip_test("LLVM 11 needed for GFX10_3 disassembly");
} else if (program->chip_class == GFX10 && LLVM_VERSION_MAJOR < 9) {
skip_test("LLVM 9 needed for GFX10 disassembly");
} else if (program->chip_class >= GFX8) {
std::ostringstream ss;
print_asm(program.get(), binary, exec_size / 4u, ss);
fputs(ss.str().c_str(), output);
} else {
//TODO: maybe we should use CLRX and skip this test if it's not available?
for (uint32_t dword : binary)
fprintf(output, "%.8x\n", dword);
}
}
void writeout(unsigned i, Temp tmp)
{
if (tmp.id())
bld.pseudo(aco_opcode::p_unit_test, Operand(i), tmp);
else
bld.pseudo(aco_opcode::p_unit_test, Operand(i));
}