mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-27 04:00:10 +01:00
pvr: Add new Rogue compiler framework
Signed-off-by: Simon Perretta <simon.perretta@imgtec.com> Acked-by: Frank Binns <frank.binns@imgtec.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/20430>
This commit is contained in:
parent
5038a049f1
commit
d187418f63
58 changed files with 10002 additions and 4595 deletions
|
|
@ -1594,6 +1594,32 @@ PowerVR driver environment variables
|
|||
A comma-separated list of debug options. Use `PVR_DEBUG=help` to
|
||||
print a list of available options.
|
||||
|
||||
.. envvar:: ROGUE_DEBUG
|
||||
|
||||
a comma-separated list of named flags for the Rogue compiler,
|
||||
which do various things:
|
||||
|
||||
``nir``
|
||||
Print the input NIR to stdout.
|
||||
``nir_passes``
|
||||
Print the output of each NIR pass to stdout.
|
||||
``ir``
|
||||
Print the input Rogue IR to stdout.
|
||||
``ir_passes``
|
||||
Print the output of each Rogue IR pass to stdout.
|
||||
``ir_details``
|
||||
Includes additional details when printing Rogue IR.
|
||||
``vld_skip``
|
||||
Skips the compiler validation step.
|
||||
``vld_nonfatal``
|
||||
Prints all the validation errors instead of stopping after the first.
|
||||
|
||||
.. envvar:: ROGUE_COLOR
|
||||
|
||||
if set to ``auto`` Rogue IR will be colorized if stdout is not a pipe.
|
||||
Color is forced off if set to ``off``/``0`` or on if set to ``on``/``1``.
|
||||
Defaults to ``auto``.
|
||||
|
||||
i915 driver environment variables
|
||||
---------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -226,6 +226,38 @@ ForEachMacros: [
|
|||
'nir_foreach_use',
|
||||
'nir_foreach_use_safe',
|
||||
'nir_foreach_variable_with_modes',
|
||||
'rogue_foreach_block',
|
||||
'rogue_foreach_block_safe',
|
||||
'rogue_foreach_block_rev',
|
||||
'rogue_foreach_block_safe_rev',
|
||||
'rogue_foreach_block_use',
|
||||
'rogue_foreach_block_use_safe',
|
||||
'rogue_foreach_drc_trxn',
|
||||
'rogue_foreach_drc_trxn_safe',
|
||||
'rogue_foreach_phase_in_set',
|
||||
'rogue_foreach_phase_in_set_rev',
|
||||
'rogue_foreach_imm_use',
|
||||
'rogue_foreach_imm_use_safe',
|
||||
'rogue_foreach_instr_group_in_block',
|
||||
'rogue_foreach_instr_group_in_block_safe',
|
||||
'rogue_foreach_instr_group_in_shader',
|
||||
'rogue_foreach_instr_group_in_shader_safe',
|
||||
'rogue_foreach_instr_in_block',
|
||||
'rogue_foreach_instr_in_block_safe',
|
||||
'rogue_foreach_instr_in_block_rev',
|
||||
'rogue_foreach_instr_in_block_safe_rev',
|
||||
'rogue_foreach_instr_in_shader',
|
||||
'rogue_foreach_instr_in_shader_safe',
|
||||
'rogue_foreach_instr_in_shader_rev',
|
||||
'rogue_foreach_instr_in_shader_safe_rev',
|
||||
'rogue_foreach_reg',
|
||||
'rogue_foreach_reg_safe',
|
||||
'rogue_foreach_reg_use',
|
||||
'rogue_foreach_reg_use_safe',
|
||||
'rogue_foreach_reg_write',
|
||||
'rogue_foreach_reg_write_safe',
|
||||
'rogue_foreach_regarray',
|
||||
'rogue_foreach_regarray_safe',
|
||||
'rb_tree_foreach',
|
||||
'rb_tree_foreach_safe',
|
||||
'u_foreach_bit',
|
||||
|
|
|
|||
|
|
@ -21,25 +21,35 @@
|
|||
|
||||
with_imagination_tools = with_tools.contains('imagination')
|
||||
|
||||
inc_rogue = include_directories([
|
||||
'.',
|
||||
])
|
||||
|
||||
libpowervr_rogue_files = files(
|
||||
'nir/rogue_nir_constreg.c',
|
||||
'nir/rogue_nir_lower_io.c',
|
||||
'nir/rogue_nir_pfo.c',
|
||||
|
||||
'rogue.c',
|
||||
'rogue_build_data.c',
|
||||
'rogue_compiler.c',
|
||||
'rogue_builder.c',
|
||||
'rogue_compile.c',
|
||||
'rogue_constreg.c',
|
||||
'rogue_dump.c',
|
||||
'rogue_debug.c',
|
||||
'rogue_encode.c',
|
||||
'rogue_encoders.c',
|
||||
'rogue_instr.c',
|
||||
'rogue_info.c',
|
||||
'rogue_nir.c',
|
||||
'rogue_operand.c',
|
||||
'rogue_regalloc.c',
|
||||
'rogue_shader.c',
|
||||
'rogue_util.c',
|
||||
'rogue_print.c',
|
||||
'rogue_validate.c',
|
||||
|
||||
'passes/rogue_constreg.c',
|
||||
'passes/rogue_copy_prop.c',
|
||||
'passes/rogue_dce.c',
|
||||
'passes/rogue_lower_pseudo_ops.c',
|
||||
'passes/rogue_regalloc.c',
|
||||
'passes/rogue_schedule_instr_groups.c',
|
||||
'passes/rogue_schedule_uvsw.c',
|
||||
'passes/rogue_schedule_wdf.c',
|
||||
'passes/rogue_trim.c',
|
||||
)
|
||||
|
||||
libpowervr_rogue = shared_library(
|
||||
|
|
@ -61,20 +71,4 @@ libpowervr_rogue = shared_library(
|
|||
install : true,
|
||||
)
|
||||
|
||||
rogue_compiler = executable(
|
||||
'rogue_compiler',
|
||||
'tools/offline_compiler.c',
|
||||
link_with : [libpowervr_rogue],
|
||||
dependencies : [idep_mesautil, idep_nir],
|
||||
include_directories : [
|
||||
inc_mesa,
|
||||
inc_include,
|
||||
inc_src,
|
||||
inc_mapi,
|
||||
inc_gallium,
|
||||
inc_gallium_aux,
|
||||
inc_compiler,
|
||||
],
|
||||
build_by_default : with_imagination_tools,
|
||||
install : with_imagination_tools,
|
||||
)
|
||||
subdir('tools')
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "nir/nir.h"
|
||||
#include "nir/nir_builder.h"
|
||||
#include "nir/nir_search_helpers.h"
|
||||
#include "rogue_constreg.h"
|
||||
#include "rogue_nir.h"
|
||||
|
||||
/* TODO: optimize: if value is in const regs, replace, else, use shared regs and
|
||||
* notify driver they need to be populated?
|
||||
*/
|
||||
|
||||
/* Replaces multiple ssa uses from load_const with a single use -> a register.
|
||||
*/
|
||||
void rogue_nir_constreg(nir_shader *shader)
|
||||
{
|
||||
nir_function_impl *impl = nir_shader_get_entrypoint(shader);
|
||||
nir_builder b;
|
||||
|
||||
nir_builder_init(&b, impl);
|
||||
|
||||
/* Find load_const instructions. */
|
||||
nir_foreach_block (block, impl) {
|
||||
nir_foreach_instr_safe (instr, block) {
|
||||
if (instr->type != nir_instr_type_load_const)
|
||||
continue;
|
||||
|
||||
nir_load_const_instr *load_const = nir_instr_as_load_const(instr);
|
||||
|
||||
/* Skip values that can be pulled from constant registers. */
|
||||
uint32_t value = nir_const_value_as_uint(load_const->value[0], 32);
|
||||
size_t const_reg = rogue_constreg_lookup(value);
|
||||
if (const_reg != ROGUE_NO_CONST_REG)
|
||||
continue;
|
||||
|
||||
b.cursor = nir_after_instr(&load_const->instr);
|
||||
nir_ssa_def *mov = nir_mov(&b, &load_const->def);
|
||||
|
||||
nir_foreach_use_safe (use_src, &load_const->def) {
|
||||
if (use_src->parent_instr == mov->parent_instr)
|
||||
continue;
|
||||
|
||||
/* Skip when used as an index for intrinsics, as we want to
|
||||
* access that value directly.
|
||||
*/
|
||||
if (use_src->parent_instr->type == nir_instr_type_intrinsic)
|
||||
continue;
|
||||
|
||||
nir_instr_rewrite_src_ssa(use_src->parent_instr, use_src, mov);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,14 +21,21 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "nir/nir.h"
|
||||
#include "nir/nir_builder.h"
|
||||
#include "nir/nir_search_helpers.h"
|
||||
#include "rogue_nir.h"
|
||||
#include "rogue_nir_helpers.h"
|
||||
#include "rogue.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* \file rogue_nir_lower_io.c
|
||||
*
|
||||
* \brief Contains the rogue_nir_lower_io pass.
|
||||
*/
|
||||
|
||||
static void lower_vulkan_resource_index(nir_builder *b,
|
||||
nir_intrinsic_instr *intr,
|
||||
|
|
@ -67,7 +74,7 @@ static void lower_load_ubo_to_scalar(nir_builder *b, nir_intrinsic_instr *intr)
|
|||
nir_ssa_def *loads[NIR_MAX_VEC_COMPONENTS];
|
||||
|
||||
for (uint8_t i = 0; i < intr->num_components; i++) {
|
||||
size_t scaled_range = nir_intrinsic_range(intr) / intr->num_components;
|
||||
unsigned scaled_range = nir_intrinsic_range(intr) / intr->num_components;
|
||||
nir_intrinsic_instr *chan_intr =
|
||||
nir_intrinsic_instr_create(b->shader, intr->intrinsic);
|
||||
nir_ssa_dest_init(&chan_intr->instr,
|
||||
|
|
@ -155,6 +162,7 @@ static bool lower_impl(nir_function_impl *impl, void *layout)
|
|||
return progress;
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
bool rogue_nir_lower_io(nir_shader *shader, void *layout)
|
||||
{
|
||||
bool progress = false;
|
||||
|
|
|
|||
|
|
@ -24,7 +24,14 @@
|
|||
#include "nir/nir.h"
|
||||
#include "nir/nir_builder.h"
|
||||
#include "nir/nir_search_helpers.h"
|
||||
#include "rogue_nir.h"
|
||||
#include "rogue.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
/**
|
||||
* \file rogue_nir_pfo.c
|
||||
*
|
||||
* \brief Contains the rogue_nir_pfo pass.
|
||||
*/
|
||||
|
||||
static void insert_pfo(nir_builder *b,
|
||||
nir_intrinsic_instr *store_output,
|
||||
|
|
@ -44,6 +51,7 @@ static void insert_pfo(nir_builder *b,
|
|||
nir_intrinsic_set_src_type(store_output, nir_type_uint32);
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
void rogue_nir_pfo(nir_shader *shader)
|
||||
{
|
||||
nir_function_impl *impl = nir_shader_get_entrypoint(shader);
|
||||
|
|
|
|||
|
|
@ -21,24 +21,41 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_DUMP_H
|
||||
#define ROGUE_DUMP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "rogue_instr.h"
|
||||
#include "rogue_operand.h"
|
||||
#include "rogue_shader.h"
|
||||
#include "rogue.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
PUBLIC
|
||||
bool rogue_dump_operand(const struct rogue_operand *operand, FILE *fp);
|
||||
#include <stdbool.h>
|
||||
|
||||
PUBLIC
|
||||
bool rogue_dump_instr(const struct rogue_instr *instr, FILE *fp);
|
||||
/**
|
||||
* \file rogue_constreg.c
|
||||
*
|
||||
* \brief Contains the rogue_constreg pass.
|
||||
*/
|
||||
|
||||
/* Converts immediate values to constant register values. */
|
||||
/* TODO: For values that aren't in constant registers, either insert a bitwise
|
||||
* mov, or ask driver to put it into shared regs. */
|
||||
PUBLIC
|
||||
bool rogue_dump_shader(const struct rogue_shader *shader, FILE *fp);
|
||||
bool rogue_constreg(rogue_shader *shader)
|
||||
{
|
||||
if (shader->is_grouped)
|
||||
return false;
|
||||
|
||||
#endif /* ROGUE_DUMP_H */
|
||||
bool progress = false;
|
||||
|
||||
rogue_foreach_imm_use_safe (imm_use, shader) {
|
||||
unsigned index = rogue_constreg_lookup(*imm_use->imm);
|
||||
if (index == ROGUE_NO_CONST_REG)
|
||||
unreachable("Immediate value not in constant registers.");
|
||||
|
||||
rogue_reg *reg = rogue_const_reg(shader, index);
|
||||
|
||||
struct list_head imm_use_link = imm_use->link;
|
||||
if (rogue_src_imm_replace(imm_use, reg)) {
|
||||
list_del(&imm_use_link);
|
||||
progress |= true;
|
||||
}
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
160
src/imagination/rogue/passes/rogue_copy_prop.c
Normal file
160
src/imagination/rogue/passes/rogue_copy_prop.c
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "rogue.h"
|
||||
#include "rogue_builder.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file rogue_copy_prop.c
|
||||
*
|
||||
* \brief Contains the rogue_copy_prop pass.
|
||||
*/
|
||||
|
||||
static bool can_back_prop(rogue_alu_instr *mov)
|
||||
{
|
||||
/* TODO: Check for src/dst modifiers when support is added for them. */
|
||||
|
||||
if (!rogue_ref_is_reg(&mov->src[0].ref) || !rogue_ref_is_reg(&mov->dst.ref))
|
||||
return false;
|
||||
|
||||
if (mov->src[0].ref.reg->regarray)
|
||||
return false;
|
||||
|
||||
/* Vertex outputs require uvsw.write; only back-propagate if the parent
|
||||
* instruction is also a mov. */
|
||||
if (mov->dst.ref.reg->class == ROGUE_REG_CLASS_VTXOUT) {
|
||||
rogue_reg_write *write =
|
||||
list_first_entry(&mov->src[0].ref.reg->writes, rogue_reg_write, link);
|
||||
|
||||
if (write->instr->type != ROGUE_INSTR_TYPE_ALU)
|
||||
return false;
|
||||
|
||||
rogue_alu_instr *alu = rogue_instr_as_alu(write->instr);
|
||||
if (alu->op != ROGUE_ALU_OP_MOV)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Is the source register only written to once? */
|
||||
if (!list_is_singular(&mov->src[0].ref.reg->writes))
|
||||
return false;
|
||||
|
||||
/* Is this the only instruction that writes to this register? */
|
||||
if (!list_is_singular(&mov->dst.ref.reg->writes))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool can_forward_prop(rogue_alu_instr *mov)
|
||||
{
|
||||
/* TODO: Check for src/dst modifiers when support is added for them. */
|
||||
|
||||
if (!rogue_ref_is_reg(&mov->src[0].ref) || !rogue_ref_is_reg(&mov->dst.ref))
|
||||
return false;
|
||||
|
||||
if (mov->dst.ref.reg->regarray)
|
||||
return false;
|
||||
|
||||
if (mov->dst.ref.reg->class != ROGUE_REG_CLASS_SSA)
|
||||
return false;
|
||||
|
||||
/* Is the source register written to more than once (driver-supplied regs can
|
||||
* have zero writes)? */
|
||||
if (list_length(&mov->src[0].ref.reg->writes) > 1)
|
||||
return false;
|
||||
|
||||
/* Is this the only instruction that writes to this register? */
|
||||
if (!list_is_singular(&mov->dst.ref.reg->writes))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rogue_back_prop(rogue_alu_instr *mov)
|
||||
{
|
||||
rogue_reg *mov_src = mov->src[0].ref.reg;
|
||||
rogue_reg *mov_dst = mov->dst.ref.reg;
|
||||
|
||||
rogue_reg_write *write =
|
||||
list_first_entry(&mov_src->writes, rogue_reg_write, link);
|
||||
|
||||
if (!rogue_dst_reg_replace(write, mov_dst))
|
||||
return false;
|
||||
|
||||
rogue_instr_delete(&mov->instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rogue_forward_prop(rogue_alu_instr *mov)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
rogue_reg *mov_src = mov->src[0].ref.reg;
|
||||
rogue_reg *mov_dst = mov->dst.ref.reg;
|
||||
|
||||
rogue_foreach_reg_use_safe (use, mov_dst)
|
||||
if (rogue_can_replace_reg_use(use, mov_src))
|
||||
success &= rogue_src_reg_replace(use, mov_src);
|
||||
else
|
||||
success = false;
|
||||
|
||||
if (!success)
|
||||
return false;
|
||||
|
||||
rogue_instr_delete(&mov->instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Copy propagation pass. */
|
||||
/* Forward and back, so that regarrays can be handled to a degree (making sure
|
||||
* to propagate the regarray register rather than replace it and mess up the
|
||||
* contiguous numbering). */
|
||||
PUBLIC
|
||||
bool rogue_copy_prop(rogue_shader *shader)
|
||||
{
|
||||
if (shader->is_grouped)
|
||||
return false;
|
||||
|
||||
bool progress = false;
|
||||
|
||||
rogue_foreach_instr_in_shader_safe (instr, shader) {
|
||||
if (instr->type != ROGUE_INSTR_TYPE_ALU)
|
||||
continue;
|
||||
|
||||
rogue_alu_instr *mov = rogue_instr_as_alu(instr);
|
||||
if (mov->op != ROGUE_ALU_OP_MOV)
|
||||
continue;
|
||||
|
||||
if (can_forward_prop(mov))
|
||||
progress |= rogue_forward_prop(mov);
|
||||
else if (can_back_prop(mov))
|
||||
progress |= rogue_back_prop(mov);
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
133
src/imagination/rogue/passes/rogue_dce.c
Normal file
133
src/imagination/rogue/passes/rogue_dce.c
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "rogue.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file rogue_dce.c
|
||||
*
|
||||
* \brief Contains the rogue_dce pass.
|
||||
*/
|
||||
|
||||
/* TODO:
|
||||
* 0) Add bools/flags to registers in rogue_info that specifies whether they can
|
||||
* be I/O registers (i.e. populated by driver/used by driver).
|
||||
* 1) Loop through instructions and delete ones that have their destinations
|
||||
* unused (with exception of pixel output, shared, etc.).
|
||||
* 2) Loop through registers and delete ones that have no uses/writes.
|
||||
*/
|
||||
|
||||
static bool rogue_dce_alu_instr(rogue_alu_instr *alu)
|
||||
{
|
||||
bool progress = false;
|
||||
|
||||
switch (alu->op) {
|
||||
case ROGUE_ALU_OP_MOV:
|
||||
case ROGUE_ALU_OP_MBYP:
|
||||
if (!alu->mod && rogue_alu_dst_src_equal(&alu->dst, &alu->src[0])) {
|
||||
rogue_instr_delete(&alu->instr);
|
||||
progress = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
static bool rogue_dce_instrs(rogue_shader *shader)
|
||||
{
|
||||
bool progress = false;
|
||||
|
||||
rogue_foreach_instr_in_shader_safe (instr, shader) {
|
||||
switch (instr->type) {
|
||||
case ROGUE_INSTR_TYPE_ALU:
|
||||
progress |= rogue_dce_alu_instr(rogue_instr_as_alu(instr));
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_BACKEND:
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_CTRL:
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Unsupported instruction type.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* TODO: Do this in rogue_trim instead? */
|
||||
static bool rogue_try_release_reg(rogue_reg *reg)
|
||||
{
|
||||
/* Check if the register is used or written to. */
|
||||
if (!rogue_reg_is_unused(reg))
|
||||
return false;
|
||||
|
||||
/* Check if the register is part of a regarray. */
|
||||
if (reg->regarray)
|
||||
return false;
|
||||
|
||||
/* Register is unused, delete it. */
|
||||
rogue_reg_delete(reg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rogue_dce_regs(rogue_shader *shader)
|
||||
{
|
||||
bool progress = false;
|
||||
|
||||
/* Remove unused SSA/temp registers that aren't in any regarrays. */
|
||||
rogue_foreach_reg_safe (reg, shader, ROGUE_REG_CLASS_SSA) {
|
||||
progress |= rogue_try_release_reg(reg);
|
||||
}
|
||||
|
||||
rogue_foreach_reg_safe (reg, shader, ROGUE_REG_CLASS_TEMP) {
|
||||
progress |= rogue_try_release_reg(reg);
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
bool rogue_dce(rogue_shader *shader)
|
||||
{
|
||||
if (shader->is_grouped)
|
||||
return false;
|
||||
|
||||
bool progress = false;
|
||||
|
||||
progress |= rogue_dce_instrs(shader);
|
||||
progress |= rogue_dce_regs(shader);
|
||||
|
||||
return progress;
|
||||
}
|
||||
166
src/imagination/rogue/passes/rogue_lower_pseudo_ops.c
Normal file
166
src/imagination/rogue/passes/rogue_lower_pseudo_ops.c
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "rogue.h"
|
||||
#include "rogue_builder.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file rogue_lower_pseudo_ops.c
|
||||
*
|
||||
* \brief Contains the rogue_lower_pseudo_ops pass.
|
||||
*/
|
||||
|
||||
static inline bool rogue_lower_FABS(rogue_builder *b, rogue_alu_instr *fabs)
|
||||
{
|
||||
rogue_alu_instr *mbyp = rogue_MBYP(b, fabs->dst.ref, fabs->src[0].ref);
|
||||
rogue_merge_instr_comment(&mbyp->instr, &fabs->instr, "fabs");
|
||||
rogue_set_alu_src_mod(mbyp, 0, ROGUE_ALU_SRC_MOD_ABS);
|
||||
rogue_instr_delete(&fabs->instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool rogue_lower_FNEG(rogue_builder *b, rogue_alu_instr *fneg)
|
||||
{
|
||||
rogue_alu_instr *mbyp = rogue_MBYP(b, fneg->dst.ref, fneg->src[0].ref);
|
||||
rogue_merge_instr_comment(&mbyp->instr, &fneg->instr, "fneg");
|
||||
rogue_set_alu_src_mod(mbyp, 0, ROGUE_ALU_SRC_MOD_NEG);
|
||||
rogue_instr_delete(&fneg->instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool rogue_lower_FNABS(rogue_builder *b, rogue_alu_instr *fnabs)
|
||||
{
|
||||
rogue_alu_instr *mbyp = rogue_MBYP(b, fnabs->dst.ref, fnabs->src[0].ref);
|
||||
rogue_merge_instr_comment(&mbyp->instr, &fnabs->instr, "fnabs");
|
||||
rogue_set_alu_src_mod(mbyp, 0, ROGUE_ALU_SRC_MOD_ABS);
|
||||
rogue_set_alu_src_mod(mbyp, 0, ROGUE_ALU_SRC_MOD_NEG);
|
||||
rogue_instr_delete(&fnabs->instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool rogue_lower_MOV(rogue_builder *b, rogue_alu_instr *mov)
|
||||
{
|
||||
rogue_instr *instr;
|
||||
|
||||
/* If we're writing to a vertex output register, we need to use uvsw.write.
|
||||
*/
|
||||
if (rogue_ref_is_reg(&mov->dst.ref) &&
|
||||
mov->dst.ref.reg->class == ROGUE_REG_CLASS_VTXOUT) {
|
||||
instr = &rogue_UVSW_WRITE(b, mov->dst.ref, mov->src[0].ref)->instr;
|
||||
} else {
|
||||
instr = &rogue_MBYP(b, mov->dst.ref, mov->src[0].ref)->instr;
|
||||
}
|
||||
|
||||
rogue_merge_instr_comment(instr, &mov->instr, "mov");
|
||||
rogue_instr_delete(&mov->instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool rogue_lower_alu_instr(rogue_builder *b, rogue_alu_instr *alu)
|
||||
{
|
||||
switch (alu->op) {
|
||||
case ROGUE_ALU_OP_MOV:
|
||||
return rogue_lower_MOV(b, alu);
|
||||
|
||||
case ROGUE_ALU_OP_FABS:
|
||||
return rogue_lower_FABS(b, alu);
|
||||
|
||||
case ROGUE_ALU_OP_FNEG:
|
||||
return rogue_lower_FNEG(b, alu);
|
||||
|
||||
case ROGUE_ALU_OP_FNABS:
|
||||
return rogue_lower_FNABS(b, alu);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool rogue_lower_END(rogue_builder *b, rogue_ctrl_instr *end)
|
||||
{
|
||||
rogue_ctrl_instr *nop = rogue_NOP(b);
|
||||
rogue_merge_instr_comment(&nop->instr, &end->instr, "end");
|
||||
rogue_set_ctrl_op_mod(nop, ROGUE_CTRL_OP_MOD_END);
|
||||
rogue_instr_delete(&end->instr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool rogue_lower_ctrl_instr(rogue_builder *b,
|
||||
rogue_ctrl_instr *ctrl)
|
||||
{
|
||||
switch (ctrl->op) {
|
||||
case ROGUE_CTRL_OP_END:
|
||||
return rogue_lower_END(b, ctrl);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* TODO: This should only really be called after a distribute_src_mods pass (to
|
||||
* come later). */
|
||||
PUBLIC
|
||||
bool rogue_lower_pseudo_ops(rogue_shader *shader)
|
||||
{
|
||||
if (shader->is_grouped)
|
||||
return false;
|
||||
|
||||
bool progress = false;
|
||||
|
||||
rogue_builder b;
|
||||
rogue_builder_init(&b, shader);
|
||||
|
||||
rogue_foreach_instr_in_shader_safe (instr, shader) {
|
||||
/* Skip real ops. */
|
||||
if (rogue_instr_supported_phases(instr))
|
||||
continue;
|
||||
|
||||
b.cursor = rogue_cursor_before_instr(instr);
|
||||
switch (instr->type) {
|
||||
case ROGUE_INSTR_TYPE_ALU:
|
||||
progress |= rogue_lower_alu_instr(&b, rogue_instr_as_alu(instr));
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_CTRL:
|
||||
progress |= rogue_lower_ctrl_instr(&b, rogue_instr_as_ctrl(instr));
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
281
src/imagination/rogue/passes/rogue_regalloc.c
Normal file
281
src/imagination/rogue/passes/rogue_regalloc.c
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "rogue.h"
|
||||
#include "util/macros.h"
|
||||
#include "util/register_allocate.h"
|
||||
#include "util/sparse_array.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file rogue_regalloc.c
|
||||
*
|
||||
* \brief Contains the rogue_regalloc pass.
|
||||
*/
|
||||
|
||||
/* TODO: Tweak this value. */
|
||||
#define ROGUE_SSA_LIVE_RANGE_NODE_SIZE 512
|
||||
|
||||
/* TODO: Internal register support for high register pressure regs. */
|
||||
|
||||
typedef struct rogue_live_range {
|
||||
unsigned start;
|
||||
unsigned end;
|
||||
} rogue_live_range;
|
||||
|
||||
PUBLIC
|
||||
bool rogue_regalloc(rogue_shader *shader)
|
||||
{
|
||||
if (shader->is_grouped)
|
||||
return false;
|
||||
|
||||
bool progress = false;
|
||||
|
||||
unsigned num_ssa_regs = list_length(&shader->regs[ROGUE_REG_CLASS_SSA]);
|
||||
if (!num_ssa_regs)
|
||||
return false;
|
||||
|
||||
/* If we already have some temps in use in the shader, we'll skip using them
|
||||
* for allocation. */
|
||||
unsigned num_temp_regs = list_length(&shader->regs[ROGUE_REG_CLASS_TEMP]);
|
||||
unsigned hw_temps = rogue_reg_infos[ROGUE_REG_CLASS_TEMP].num;
|
||||
|
||||
struct ra_regs *ra_regs = ra_alloc_reg_set(shader, hw_temps, true);
|
||||
|
||||
for (enum rogue_regalloc_class c = 0; c < ROGUE_REGALLOC_CLASS_COUNT; ++c) {
|
||||
ASSERTED struct ra_class *ra_class =
|
||||
ra_alloc_contig_reg_class(ra_regs, regalloc_info[c].stride);
|
||||
assert(c == ra_class_index(ra_class));
|
||||
}
|
||||
|
||||
for (unsigned t = num_temp_regs; t < hw_temps; ++t)
|
||||
for (enum rogue_regalloc_class c = 0; c < ROGUE_REGALLOC_CLASS_COUNT; ++c)
|
||||
if (!(t % regalloc_info[c].stride))
|
||||
ra_class_add_reg(ra_get_class_from_index(ra_regs, c), t);
|
||||
|
||||
ra_set_finalize(ra_regs, NULL);
|
||||
|
||||
struct util_sparse_array ssa_live_range;
|
||||
util_sparse_array_init(&ssa_live_range,
|
||||
sizeof(rogue_live_range),
|
||||
ROGUE_SSA_LIVE_RANGE_NODE_SIZE);
|
||||
|
||||
/* Populate live ranges. */
|
||||
rogue_foreach_reg (reg, shader, ROGUE_REG_CLASS_SSA) {
|
||||
rogue_live_range *live_range =
|
||||
util_sparse_array_get(&ssa_live_range, reg->index);
|
||||
rogue_reg_write *write =
|
||||
list_first_entry(®->writes, rogue_reg_write, link);
|
||||
|
||||
live_range->start = write->instr->index;
|
||||
live_range->end = live_range->start;
|
||||
|
||||
rogue_foreach_reg_use (use, reg)
|
||||
live_range->end = MAX2(live_range->end, use->instr->index);
|
||||
|
||||
/* Here dirty represents whether the register has been added to the regset
|
||||
* yet or not. */
|
||||
reg->dirty = false;
|
||||
}
|
||||
|
||||
struct ra_graph *ra_graph =
|
||||
ra_alloc_interference_graph(ra_regs, num_ssa_regs);
|
||||
ralloc_steal(ra_regs, ra_graph);
|
||||
|
||||
/* Set register class for regarrays/vectors. */
|
||||
rogue_foreach_regarray (regarray, shader) {
|
||||
enum rogue_reg_class class = regarray->regs[0]->class;
|
||||
if (class != ROGUE_REG_CLASS_SSA)
|
||||
continue;
|
||||
|
||||
if (regarray->parent)
|
||||
continue;
|
||||
|
||||
if (regarray->size != 4)
|
||||
unreachable("Unsupported regarray size.");
|
||||
|
||||
ra_set_node_class(ra_graph,
|
||||
regarray->regs[0]->index,
|
||||
ra_get_class_from_index(ra_regs,
|
||||
ROGUE_REGALLOC_CLASS_TEMP_4));
|
||||
|
||||
for (unsigned u = 0; u < regarray->size; ++u)
|
||||
regarray->regs[u]->dirty = true;
|
||||
}
|
||||
|
||||
/* Set register class for "standalone" registers. */
|
||||
rogue_foreach_reg (reg, shader, ROGUE_REG_CLASS_SSA) {
|
||||
if (reg->dirty)
|
||||
continue;
|
||||
|
||||
ra_set_node_class(ra_graph,
|
||||
reg->index,
|
||||
ra_get_class_from_index(ra_regs,
|
||||
ROGUE_REGALLOC_CLASS_TEMP_1));
|
||||
reg->dirty = true;
|
||||
}
|
||||
|
||||
/* Build interference graph from overlapping live ranges. */
|
||||
for (unsigned index0 = 0; index0 < num_ssa_regs; ++index0) {
|
||||
rogue_live_range *live_range0 =
|
||||
util_sparse_array_get(&ssa_live_range, index0);
|
||||
|
||||
for (unsigned index1 = 0; index1 < num_ssa_regs; ++index1) {
|
||||
if (index0 == index1)
|
||||
continue;
|
||||
|
||||
rogue_live_range *live_range1 =
|
||||
util_sparse_array_get(&ssa_live_range, index1);
|
||||
|
||||
/* If the live ranges overlap, those register nodes interfere. */
|
||||
if (!(live_range0->start >= live_range1->end ||
|
||||
live_range1->start >= live_range0->end))
|
||||
ra_add_node_interference(ra_graph, index0, index1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Same src/dst interferences are disabled for the moment.
|
||||
* This may need to be re-enabled in the future as certain instructions have
|
||||
* restrictions on this.
|
||||
*/
|
||||
#if 0
|
||||
/* Add node interferences such that the same register can't be used for
|
||||
* both an instruction's source and destination.
|
||||
*/
|
||||
rogue_foreach_instr_in_shader (instr, shader) {
|
||||
switch (instr->type) {
|
||||
case ROGUE_INSTR_TYPE_ALU:
|
||||
{
|
||||
const rogue_alu_instr *alu = rogue_instr_as_alu(instr);
|
||||
const rogue_alu_op_info *info = &rogue_alu_op_infos[alu->op];
|
||||
|
||||
if (rogue_ref_get_reg_class(&alu->dst.ref) != ROGUE_REG_CLASS_SSA)
|
||||
continue;
|
||||
|
||||
for (unsigned s = 0; s < info->num_srcs; ++s) {
|
||||
if (!rogue_ref_is_reg(&alu->src[s].ref))
|
||||
continue;
|
||||
|
||||
if (rogue_ref_get_reg_class(&alu->src[s].ref) != ROGUE_REG_CLASS_SSA)
|
||||
continue;
|
||||
|
||||
ra_add_node_interference(ra_graph, rogue_ref_get_reg_index(&alu->dst.ref), rogue_ref_get_reg_index(&alu->src[s].ref));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ROGUE_INSTR_TYPE_BACKEND:
|
||||
{
|
||||
const rogue_backend_instr *backend = rogue_instr_as_backend(instr);
|
||||
const rogue_backend_op_info *info = &rogue_backend_op_infos[backend->op];
|
||||
|
||||
for (unsigned d = 0; d < info->num_dsts; ++d) {
|
||||
if (rogue_ref_get_reg_class(&backend->dst[d].ref) != ROGUE_REG_CLASS_SSA)
|
||||
continue;
|
||||
|
||||
for (unsigned s = 0; s < info->num_srcs; ++s) {
|
||||
if (!rogue_ref_is_reg(&backend->src[s].ref))
|
||||
continue;
|
||||
|
||||
if (rogue_ref_get_reg_class(&backend->src[s].ref) != ROGUE_REG_CLASS_SSA)
|
||||
continue;
|
||||
|
||||
ra_add_node_interference(ra_graph, rogue_ref_get_reg_index(&backend->dst[d].ref), rogue_ref_get_reg_index(&backend->src[s].ref));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ROGUE_INSTR_TYPE_CTRL:
|
||||
{
|
||||
/* TODO: Support control instructions with I/O. */
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
unreachable("Unsupported instruction type.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* TODO: Spilling support. */
|
||||
if (!ra_allocate(ra_graph))
|
||||
unreachable("Register allocation failed.");
|
||||
|
||||
/* Replace regarray SSA registers with allocated physical registers first.
|
||||
* Don't want to be in a situation where the reg is updated before the
|
||||
* regarray.
|
||||
*/
|
||||
rogue_foreach_regarray (regarray, shader) {
|
||||
enum rogue_reg_class class = regarray->regs[0]->class;
|
||||
if (class != ROGUE_REG_CLASS_SSA)
|
||||
continue;
|
||||
|
||||
if (regarray->parent)
|
||||
continue;
|
||||
|
||||
unsigned start_index = regarray->regs[0]->index;
|
||||
unsigned new_base_index = ra_get_node_reg(ra_graph, start_index);
|
||||
for (unsigned u = 0; u < regarray->size; ++u) {
|
||||
enum rogue_regalloc_class ra_class =
|
||||
ra_class_index(ra_get_node_class(ra_graph, start_index + u));
|
||||
enum rogue_reg_class new_class = regalloc_info[ra_class].class;
|
||||
|
||||
/* Register should not have already been used. */
|
||||
assert(!BITSET_TEST(shader->regs_used[new_class], new_base_index + u));
|
||||
progress |= rogue_reg_rewrite(shader,
|
||||
regarray->regs[u],
|
||||
new_class,
|
||||
new_base_index + u);
|
||||
}
|
||||
}
|
||||
|
||||
/* Replace remaining standalone SSA registers with allocated physical
|
||||
* registers. */
|
||||
rogue_foreach_reg_safe (reg, shader, ROGUE_REG_CLASS_SSA) {
|
||||
assert(!reg->regarray);
|
||||
unsigned new_index = ra_get_node_reg(ra_graph, reg->index);
|
||||
|
||||
enum rogue_regalloc_class ra_class =
|
||||
ra_class_index(ra_get_node_class(ra_graph, reg->index));
|
||||
enum rogue_reg_class new_class = regalloc_info[ra_class].class;
|
||||
|
||||
/* First time using new register, modify in place. */
|
||||
if (!BITSET_TEST(shader->regs_used[new_class], new_index)) {
|
||||
progress |= rogue_reg_rewrite(shader, reg, new_class, new_index);
|
||||
} else {
|
||||
/* Register has already been used, replace references and delete. */
|
||||
assert(list_is_singular(®->writes)); /* SSA reg. */
|
||||
rogue_reg *new_reg = rogue_temp_reg(shader, new_index);
|
||||
progress |= rogue_reg_replace(reg, new_reg);
|
||||
}
|
||||
}
|
||||
|
||||
util_sparse_array_finish(&ssa_live_range);
|
||||
ralloc_free(ra_regs);
|
||||
return progress;
|
||||
}
|
||||
635
src/imagination/rogue/passes/rogue_schedule_instr_groups.c
Normal file
635
src/imagination/rogue/passes/rogue_schedule_instr_groups.c
Normal file
|
|
@ -0,0 +1,635 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "rogue.h"
|
||||
#include "rogue_builder.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file rogue_schedule_instr_groups.c
|
||||
*
|
||||
* \brief Contains the rogue_schedule_instr_groups pass.
|
||||
*/
|
||||
|
||||
static inline void rogue_set_io_sel(rogue_instr_group_io_sel *map,
|
||||
enum rogue_io io,
|
||||
rogue_ref *ref,
|
||||
bool is_dst)
|
||||
{
|
||||
/* Hookup feedthrough outputs to W0 using IS4. */
|
||||
if (is_dst && rogue_io_is_ft(io)) {
|
||||
*(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS4)) = rogue_ref_io(io);
|
||||
io = ROGUE_IO_W0;
|
||||
}
|
||||
|
||||
/* Pack source */
|
||||
if (!is_dst && io == ROGUE_IO_IS3) {
|
||||
enum rogue_io src = ROGUE_IO_S0;
|
||||
*(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) = rogue_ref_io(src);
|
||||
*(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS3)) =
|
||||
rogue_ref_io(ROGUE_IO_FTE);
|
||||
io = src;
|
||||
}
|
||||
|
||||
if (!is_dst && rogue_io_is_dst(io)) {
|
||||
enum rogue_io dst_ft = (io == ROGUE_IO_W0 ? ROGUE_IO_IS4 : ROGUE_IO_IS5);
|
||||
enum rogue_io src = ROGUE_IO_S0;
|
||||
*(rogue_instr_group_io_sel_ref(map, dst_ft)) = rogue_ref_io(ROGUE_IO_FTE);
|
||||
*(rogue_instr_group_io_sel_ref(map, ROGUE_IO_IS0)) = rogue_ref_io(src);
|
||||
io = src;
|
||||
}
|
||||
|
||||
*(rogue_instr_group_io_sel_ref(map, io)) = *ref;
|
||||
}
|
||||
|
||||
/* TODO NEXT: Abort if anything in sel map is already set. */
|
||||
/* TODO NEXT: Assert that these are register refs being set. */
|
||||
|
||||
static void rogue_lower_alu_io(rogue_alu_instr *alu, rogue_instr_group *group)
|
||||
{
|
||||
const rogue_alu_op_info *info = &rogue_alu_op_infos[alu->op];
|
||||
enum rogue_instr_phase phase = alu->instr.index;
|
||||
|
||||
rogue_set_io_sel(&group->io_sel,
|
||||
info->phase_io[phase].dst,
|
||||
&alu->dst.ref,
|
||||
true);
|
||||
alu->dst.ref = rogue_ref_io(info->phase_io[phase].dst);
|
||||
|
||||
for (unsigned u = 0; u < info->num_srcs; ++u) {
|
||||
if (info->phase_io[phase].src[u] == ROGUE_IO_INVALID)
|
||||
continue;
|
||||
|
||||
rogue_set_io_sel(&group->io_sel,
|
||||
info->phase_io[phase].src[u],
|
||||
&alu->src[u].ref,
|
||||
false);
|
||||
alu->src[u].ref = rogue_ref_io(info->phase_io[phase].src[u]);
|
||||
}
|
||||
}
|
||||
|
||||
static void rogue_lower_backend_io(rogue_backend_instr *backend,
|
||||
rogue_instr_group *group)
|
||||
{
|
||||
const rogue_backend_op_info *info = &rogue_backend_op_infos[backend->op];
|
||||
|
||||
for (unsigned u = 0; u < info->num_dsts; ++u) {
|
||||
if (info->phase_io.dst[u] == ROGUE_IO_INVALID)
|
||||
continue;
|
||||
|
||||
rogue_set_io_sel(&group->io_sel,
|
||||
info->phase_io.dst[u],
|
||||
&backend->dst[u].ref,
|
||||
true);
|
||||
backend->dst[u].ref = rogue_ref_io(info->phase_io.dst[u]);
|
||||
}
|
||||
|
||||
for (unsigned u = 0; u < info->num_srcs; ++u) {
|
||||
if (info->phase_io.src[u] == ROGUE_IO_INVALID)
|
||||
continue;
|
||||
|
||||
rogue_set_io_sel(&group->io_sel,
|
||||
info->phase_io.src[u],
|
||||
&backend->src[u].ref,
|
||||
false);
|
||||
backend->src[u].ref = rogue_ref_io(info->phase_io.src[u]);
|
||||
}
|
||||
}
|
||||
|
||||
static void rogue_lower_ctrl_io(rogue_ctrl_instr *ctrl,
|
||||
rogue_instr_group *group)
|
||||
{
|
||||
/* TODO: Support control instructions with I/O. */
|
||||
}
|
||||
|
||||
static void rogue_lower_instr_group_io(rogue_instr *instr,
|
||||
rogue_instr_group *group)
|
||||
{
|
||||
switch (instr->type) {
|
||||
case ROGUE_INSTR_TYPE_ALU:
|
||||
rogue_lower_alu_io(rogue_instr_as_alu(instr), group);
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_BACKEND:
|
||||
rogue_lower_backend_io(rogue_instr_as_backend(instr), group);
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_CTRL:
|
||||
rogue_lower_ctrl_io(rogue_instr_as_ctrl(instr), group);
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Invalid instruction group type.");
|
||||
}
|
||||
}
|
||||
|
||||
/* This function uses unreachables rather than asserts because some Rogue IR
|
||||
* instructions are pseudo-instructions that need lowering on certain cores, but
|
||||
* real instructions on others, so these mistakes are more likely to happen.
|
||||
*/
|
||||
static inline void rogue_instr_group_put(rogue_instr *instr,
|
||||
rogue_instr_group *group)
|
||||
{
|
||||
uint64_t supported_phases = rogue_instr_supported_phases(instr);
|
||||
if (!supported_phases)
|
||||
unreachable("Can't schedule pseudo-instructions.");
|
||||
else if (!util_is_power_of_two_or_zero64(supported_phases))
|
||||
unreachable("Multi-phase instructions unsupported.");
|
||||
|
||||
enum rogue_instr_phase phase =
|
||||
rogue_get_supported_phase(supported_phases, group->header.phases);
|
||||
if (phase == ROGUE_INSTR_PHASE_INVALID)
|
||||
unreachable("Failed to schedule group instruction.");
|
||||
|
||||
/* Update phases. */
|
||||
instr->group = group;
|
||||
instr->index = phase;
|
||||
group->instrs[phase] = instr;
|
||||
group->header.phases |= BITFIELD_BIT(phase);
|
||||
|
||||
/* Update repeat count. */
|
||||
group->header.repeat = instr->repeat;
|
||||
instr->repeat = 0;
|
||||
|
||||
/* Set end flag. */
|
||||
group->header.end = instr->end;
|
||||
|
||||
/* Set conditional execution flag. */
|
||||
/* TODO: Set this from the instruction. */
|
||||
group->header.exec_cond = ROGUE_EXEC_COND_PE_TRUE;
|
||||
|
||||
/* Lower I/O to sources/destinations/ISS. */
|
||||
rogue_lower_instr_group_io(instr, group);
|
||||
}
|
||||
|
||||
static inline void rogue_move_instr_to_group(rogue_instr *instr,
|
||||
rogue_instr_group *group)
|
||||
{
|
||||
/* Remove instruction from block instructions list. */
|
||||
list_del(&instr->link);
|
||||
|
||||
/* ralloc_steal instr context from block to instruction group */
|
||||
ralloc_steal(group, instr);
|
||||
|
||||
/* Assign instruction to instruction group. */
|
||||
rogue_instr_group_put(instr, group);
|
||||
}
|
||||
|
||||
static void rogue_lower_regs(rogue_shader *shader)
|
||||
{
|
||||
rogue_foreach_reg (reg, shader, ROGUE_REG_CLASS_INTERNAL) {
|
||||
rogue_reg_rewrite(shader,
|
||||
reg,
|
||||
ROGUE_REG_CLASS_SPECIAL,
|
||||
reg->index + ROGUE_INTERNAL0_OFFSET);
|
||||
}
|
||||
|
||||
rogue_foreach_reg_safe (reg, shader, ROGUE_REG_CLASS_CONST) {
|
||||
rogue_reg_rewrite(shader, reg, ROGUE_REG_CLASS_SPECIAL, reg->index);
|
||||
}
|
||||
|
||||
rogue_foreach_reg_safe (reg, shader, ROGUE_REG_CLASS_PIXOUT) {
|
||||
rogue_reg_rewrite(shader,
|
||||
reg,
|
||||
ROGUE_REG_CLASS_SPECIAL,
|
||||
reg->index +
|
||||
(reg->index < ROGUE_PIXOUT_GROUP
|
||||
? ROGUE_PIXOUT0_OFFSET
|
||||
: (ROGUE_PIXOUT4_OFFSET - ROGUE_PIXOUT_GROUP)));
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned rogue_reg_bank_bits(const rogue_ref *ref)
|
||||
{
|
||||
const rogue_reg *reg;
|
||||
|
||||
if (rogue_ref_is_reg(ref))
|
||||
reg = ref->reg;
|
||||
else if (rogue_ref_is_regarray(ref))
|
||||
reg = ref->regarray->regs[0];
|
||||
else
|
||||
unreachable("Non-register reference.");
|
||||
|
||||
unsigned bits = util_last_bit(rogue_reg_bank_encoding(reg->class));
|
||||
return !bits ? 1 : bits;
|
||||
}
|
||||
|
||||
static unsigned rogue_reg_index_bits(const rogue_ref *ref)
|
||||
{
|
||||
const rogue_reg *reg;
|
||||
|
||||
if (rogue_ref_is_reg(ref))
|
||||
reg = ref->reg;
|
||||
else if (rogue_ref_is_regarray(ref))
|
||||
reg = ref->regarray->regs[0];
|
||||
else
|
||||
unreachable("Non-register reference.");
|
||||
|
||||
unsigned bits = util_last_bit(reg->index);
|
||||
return !bits ? 1 : bits;
|
||||
}
|
||||
|
||||
static void rogue_calc_dsts_size(rogue_instr_group *group)
|
||||
{
|
||||
const rogue_instr_group_io_sel *io_sel = &group->io_sel;
|
||||
|
||||
unsigned num_dsts = !rogue_ref_is_null(&io_sel->dsts[0]) +
|
||||
!rogue_ref_is_null(&io_sel->dsts[1]);
|
||||
unsigned bank_bits[ROGUE_ISA_DSTS] = { 0 };
|
||||
unsigned index_bits[ROGUE_ISA_DSTS] = { 0 };
|
||||
|
||||
if (!num_dsts) {
|
||||
return;
|
||||
} else if (num_dsts == 1) {
|
||||
const rogue_ref *dst_ref = !rogue_ref_is_null(&io_sel->dsts[0])
|
||||
? &io_sel->dsts[0]
|
||||
: &io_sel->dsts[1];
|
||||
bank_bits[0] = rogue_reg_bank_bits(dst_ref);
|
||||
index_bits[0] = rogue_reg_index_bits(dst_ref);
|
||||
} else {
|
||||
bank_bits[0] = rogue_reg_bank_bits(&io_sel->dsts[0]);
|
||||
bank_bits[1] = rogue_reg_bank_bits(&io_sel->dsts[1]);
|
||||
index_bits[0] = rogue_reg_index_bits(&io_sel->dsts[0]);
|
||||
index_bits[1] = rogue_reg_index_bits(&io_sel->dsts[1]);
|
||||
}
|
||||
|
||||
for (unsigned u = 0; u < ROGUE_REG_DST_VARIANTS; ++u) {
|
||||
const rogue_reg_dst_info *info = &rogue_reg_dst_infos[u];
|
||||
|
||||
if ((info->num_dsts < num_dsts) || (info->bank_bits[0] < bank_bits[0]) ||
|
||||
(info->bank_bits[1] < bank_bits[1]) ||
|
||||
(info->index_bits[0] < index_bits[0]) ||
|
||||
(info->index_bits[1] < index_bits[1]))
|
||||
continue;
|
||||
|
||||
group->encode_info.dst_index = u;
|
||||
group->size.dsts = info->bytes;
|
||||
group->size.total += group->size.dsts;
|
||||
return;
|
||||
}
|
||||
|
||||
unreachable("Unable to encode instruction group dsts.");
|
||||
}
|
||||
|
||||
static void rogue_calc_iss_size(rogue_instr_group *group)
|
||||
{
|
||||
group->size.iss = (group->header.alu == ROGUE_ALU_MAIN);
|
||||
group->size.total += group->size.iss;
|
||||
}
|
||||
|
||||
static void rogue_calc_srcs_size(rogue_instr_group *group, bool upper_srcs)
|
||||
{
|
||||
const rogue_instr_group_io_sel *io_sel = &group->io_sel;
|
||||
unsigned mux_bits = 0;
|
||||
|
||||
unsigned offset = upper_srcs ? 3 : 0;
|
||||
const rogue_reg_src_info *info_array =
|
||||
upper_srcs ? rogue_reg_upper_src_infos : rogue_reg_lower_src_infos;
|
||||
|
||||
unsigned *src_index = upper_srcs ? &group->encode_info.upper_src_index
|
||||
: &group->encode_info.lower_src_index;
|
||||
unsigned *srcs = upper_srcs ? &group->size.upper_srcs
|
||||
: &group->size.lower_srcs;
|
||||
|
||||
/* Special case: some control instructions have no sources. */
|
||||
if (group->header.alu == ROGUE_ALU_CONTROL) {
|
||||
const rogue_ctrl_instr *ctrl =
|
||||
rogue_instr_as_ctrl(group->instrs[ROGUE_INSTR_PHASE_CTRL]);
|
||||
if (!rogue_ctrl_op_has_srcs(ctrl->op))
|
||||
return;
|
||||
} else if (!upper_srcs && group->header.alu == ROGUE_ALU_MAIN) {
|
||||
/* Special case, IS0 */
|
||||
if (rogue_ref_is_io(&io_sel->iss[0])) {
|
||||
switch (io_sel->iss[0].io) {
|
||||
case ROGUE_IO_S0:
|
||||
mux_bits = 0;
|
||||
break;
|
||||
case ROGUE_IO_S3:
|
||||
mux_bits = 1;
|
||||
break;
|
||||
case ROGUE_IO_S4:
|
||||
mux_bits = 2;
|
||||
break;
|
||||
case ROGUE_IO_S5:
|
||||
mux_bits = 2;
|
||||
break;
|
||||
case ROGUE_IO_S1:
|
||||
mux_bits = 3;
|
||||
break;
|
||||
case ROGUE_IO_S2:
|
||||
mux_bits = 3;
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("IS0 set to invalid value.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned num_srcs = 1;
|
||||
if (!rogue_ref_is_null(&io_sel->srcs[2 + offset]))
|
||||
num_srcs = 3;
|
||||
else if (!rogue_ref_is_null(&io_sel->srcs[1 + offset]))
|
||||
num_srcs = 2;
|
||||
|
||||
unsigned bank_bits[ROGUE_ISA_SRCS / 2] = { 0 };
|
||||
unsigned index_bits[ROGUE_ISA_SRCS / 2] = { 0 };
|
||||
|
||||
for (unsigned u = 0; u < ARRAY_SIZE(bank_bits); ++u) {
|
||||
const rogue_ref *src = &io_sel->srcs[u + offset];
|
||||
if (rogue_ref_is_null(src))
|
||||
continue;
|
||||
|
||||
bank_bits[u] = rogue_reg_bank_bits(src);
|
||||
index_bits[u] = rogue_reg_index_bits(src);
|
||||
}
|
||||
|
||||
for (unsigned u = 0; u < ROGUE_REG_SRC_VARIANTS; ++u) {
|
||||
const rogue_reg_src_info *info = &info_array[u];
|
||||
|
||||
if ((info->num_srcs < num_srcs) || (info->mux_bits < mux_bits) ||
|
||||
(info->bank_bits[0] < bank_bits[0]) ||
|
||||
(info->bank_bits[1] < bank_bits[1]) ||
|
||||
(info->bank_bits[2] < bank_bits[2]) ||
|
||||
(info->index_bits[0] < index_bits[0]) ||
|
||||
(info->index_bits[1] < index_bits[1]) ||
|
||||
(info->index_bits[2] < index_bits[2])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*src_index = u;
|
||||
*srcs = info->bytes;
|
||||
group->size.total += *srcs;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unreachable("Unable to encode instruction group srcs.");
|
||||
}
|
||||
|
||||
#define SM(src_mod) ROGUE_ALU_SRC_MOD_##src_mod
|
||||
#define DM(dst_mod) ROGUE_ALU_DST_MOD_##dst_mod
|
||||
#define OM(op_mod) ROGUE_ALU_OP_MOD_##op_mod
|
||||
static void rogue_calc_alu_instrs_size(rogue_instr_group *group,
|
||||
rogue_alu_instr *alu,
|
||||
enum rogue_instr_phase phase)
|
||||
{
|
||||
switch (alu->op) {
|
||||
/* TODO: All single source have 1 byte and optional extra byte w/ext,
|
||||
* commonise some of these when adding support for more single source
|
||||
* instructions.
|
||||
*/
|
||||
case ROGUE_ALU_OP_MBYP:
|
||||
if (rogue_alu_src_mod_is_set(alu, 0, SM(NEG)) ||
|
||||
rogue_alu_src_mod_is_set(alu, 0, SM(ABS))) {
|
||||
group->size.instrs[phase] = 2;
|
||||
} else {
|
||||
group->size.instrs[phase] = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case ROGUE_ALU_OP_FMUL:
|
||||
group->size.instrs[phase] = 1;
|
||||
break;
|
||||
|
||||
case ROGUE_ALU_OP_FMAD:
|
||||
if (rogue_alu_op_mod_is_set(alu, OM(LP)) ||
|
||||
rogue_alu_src_mod_is_set(alu, 1, SM(ABS)) ||
|
||||
rogue_alu_src_mod_is_set(alu, 1, SM(NEG)) ||
|
||||
rogue_alu_src_mod_is_set(alu, 2, SM(FLR)) ||
|
||||
rogue_alu_src_mod_is_set(alu, 2, SM(ABS))) {
|
||||
group->size.instrs[phase] = 2;
|
||||
} else {
|
||||
group->size.instrs[phase] = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case ROGUE_ALU_OP_PCK_U8888:
|
||||
group->size.instrs[phase] = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Invalid alu op.");
|
||||
}
|
||||
}
|
||||
#undef OM
|
||||
#undef DM
|
||||
#undef SM
|
||||
|
||||
static void rogue_calc_backend_instrs_size(rogue_instr_group *group,
|
||||
rogue_backend_instr *backend,
|
||||
enum rogue_instr_phase phase)
|
||||
{
|
||||
switch (backend->op) {
|
||||
case ROGUE_BACKEND_OP_FITRP_PIXEL:
|
||||
group->size.instrs[phase] = 2;
|
||||
break;
|
||||
|
||||
case ROGUE_BACKEND_OP_UVSW_WRITETHENEMITTHENENDTASK:
|
||||
case ROGUE_BACKEND_OP_UVSW_WRITE:
|
||||
group->size.instrs[phase] = 2;
|
||||
break;
|
||||
|
||||
case ROGUE_BACKEND_OP_UVSW_EMIT:
|
||||
case ROGUE_BACKEND_OP_UVSW_ENDTASK:
|
||||
case ROGUE_BACKEND_OP_UVSW_EMITTHENENDTASK:
|
||||
group->size.instrs[phase] = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Invalid backend op.");
|
||||
}
|
||||
}
|
||||
|
||||
static void rogue_calc_ctrl_instrs_size(rogue_instr_group *group,
|
||||
rogue_ctrl_instr *ctrl,
|
||||
enum rogue_instr_phase phase)
|
||||
{
|
||||
switch (ctrl->op) {
|
||||
case ROGUE_CTRL_OP_WDF:
|
||||
group->size.instrs[phase] = 0;
|
||||
break;
|
||||
|
||||
case ROGUE_CTRL_OP_NOP:
|
||||
group->size.instrs[phase] = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Invalid ctrl op.");
|
||||
}
|
||||
}
|
||||
|
||||
static void rogue_calc_instrs_size(rogue_instr_group *group)
|
||||
{
|
||||
rogue_foreach_phase_in_set (p, group->header.phases) {
|
||||
const rogue_instr *instr = group->instrs[p];
|
||||
|
||||
switch (instr->type) {
|
||||
case ROGUE_INSTR_TYPE_ALU:
|
||||
rogue_calc_alu_instrs_size(group, rogue_instr_as_alu(instr), p);
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_BACKEND:
|
||||
rogue_calc_backend_instrs_size(group,
|
||||
rogue_instr_as_backend(instr),
|
||||
p);
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_CTRL:
|
||||
rogue_calc_ctrl_instrs_size(group, rogue_instr_as_ctrl(instr), p);
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Invalid instruction type.");
|
||||
}
|
||||
|
||||
group->size.total += group->size.instrs[p];
|
||||
}
|
||||
}
|
||||
|
||||
static void rogue_calc_header_size(rogue_instr_group *group)
|
||||
{
|
||||
group->size.header = 2;
|
||||
if (group->header.alu != ROGUE_ALU_MAIN ||
|
||||
(group->header.end || group->header.repeat > 1 ||
|
||||
group->header.exec_cond > ROGUE_EXEC_COND_P0_TRUE)) {
|
||||
group->size.header = 3;
|
||||
}
|
||||
|
||||
group->size.total += group->size.header;
|
||||
}
|
||||
|
||||
static void rogue_calc_padding_size(rogue_instr_group *group)
|
||||
{
|
||||
group->size.word_padding = (group->size.total % 2);
|
||||
group->size.total += group->size.word_padding;
|
||||
}
|
||||
|
||||
static void rogue_finalise_instr_group(rogue_instr_group *group)
|
||||
{
|
||||
rogue_calc_dsts_size(group);
|
||||
rogue_calc_iss_size(group);
|
||||
rogue_calc_srcs_size(group, true);
|
||||
rogue_calc_srcs_size(group, false);
|
||||
rogue_calc_instrs_size(group);
|
||||
rogue_calc_header_size(group);
|
||||
rogue_calc_padding_size(group);
|
||||
}
|
||||
|
||||
static void rogue_finalise_shader_offsets(rogue_shader *shader)
|
||||
{
|
||||
rogue_instr_group *penultimate_group = NULL;
|
||||
rogue_instr_group *last_group = NULL;
|
||||
|
||||
/* Set instruction group offsets. */
|
||||
unsigned offset = 0;
|
||||
rogue_foreach_instr_group_in_shader (group, shader) {
|
||||
group->size.offset = offset;
|
||||
offset += group->size.total;
|
||||
|
||||
penultimate_group = last_group;
|
||||
last_group = group;
|
||||
}
|
||||
|
||||
/* Ensure the final instruction group has a total size and offset that are a
|
||||
* multiple of the icache alignment. */
|
||||
unsigned total_align = last_group->size.total % ROGUE_ISA_ICACHE_ALIGN;
|
||||
unsigned offset_align = last_group->size.offset % ROGUE_ISA_ICACHE_ALIGN;
|
||||
|
||||
if (total_align) {
|
||||
unsigned padding = ROGUE_ISA_ICACHE_ALIGN - total_align;
|
||||
/* Pad the size of the last instruction. */
|
||||
last_group->size.align_padding += padding;
|
||||
last_group->size.total += padding;
|
||||
}
|
||||
|
||||
if (offset_align) {
|
||||
unsigned padding = ROGUE_ISA_ICACHE_ALIGN - offset_align;
|
||||
/* Pad the size of the penultimate instruction. */
|
||||
penultimate_group->size.align_padding += padding;
|
||||
penultimate_group->size.total += padding;
|
||||
/* Update the offset of the last instruction. */
|
||||
last_group->size.offset += padding;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: This just puts single instructions into groups for now. Later we need
|
||||
* to:
|
||||
* - create rules for what instructions can be co-issued/groups.
|
||||
* - schedule/shuffle instructions to get them ready for grouping (also need to
|
||||
* implement ways to stop certain instructions being rearranged, etc. first!)
|
||||
*/
|
||||
PUBLIC
|
||||
bool rogue_schedule_instr_groups(rogue_shader *shader, bool multi_instr_groups)
|
||||
{
|
||||
if (shader->is_grouped)
|
||||
return false;
|
||||
|
||||
if (multi_instr_groups) {
|
||||
unreachable("Multi instruction groups are unsupported.");
|
||||
return false;
|
||||
}
|
||||
|
||||
rogue_lower_regs(shader);
|
||||
|
||||
unsigned g = 0;
|
||||
rogue_foreach_block (block, shader) {
|
||||
struct list_head instr_groups;
|
||||
list_inithead(&instr_groups);
|
||||
|
||||
rogue_foreach_instr_in_block_safe (instr, block) {
|
||||
enum rogue_alu group_alu = ROGUE_ALU_INVALID;
|
||||
switch (instr->type) {
|
||||
case ROGUE_INSTR_TYPE_ALU:
|
||||
case ROGUE_INSTR_TYPE_BACKEND:
|
||||
group_alu = ROGUE_ALU_MAIN;
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_CTRL:
|
||||
group_alu = ROGUE_ALU_CONTROL;
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Invalid instruction type.");
|
||||
}
|
||||
|
||||
rogue_instr_group *group = rogue_instr_group_create(block, group_alu);
|
||||
group->index = g++;
|
||||
|
||||
rogue_move_instr_to_group(instr, group);
|
||||
rogue_finalise_instr_group(group);
|
||||
list_addtail(&group->link, &instr_groups);
|
||||
}
|
||||
|
||||
list_replace(&instr_groups, &block->instrs);
|
||||
}
|
||||
|
||||
shader->next_instr = g;
|
||||
shader->is_grouped = true;
|
||||
|
||||
rogue_finalise_shader_offsets(shader);
|
||||
|
||||
return true;
|
||||
}
|
||||
95
src/imagination/rogue/passes/rogue_schedule_uvsw.c
Normal file
95
src/imagination/rogue/passes/rogue_schedule_uvsw.c
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "rogue.h"
|
||||
#include "rogue_builder.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file rogue_schedule_uvsw.c
|
||||
*
|
||||
* \brief Contains the rogue_schedule_uvsw pass.
|
||||
*/
|
||||
|
||||
/* TODO: See if maybe this can/should be done in rogue_lower_END instead? */
|
||||
|
||||
/* Schedules UVSW task control instructions. */
|
||||
PUBLIC
|
||||
bool rogue_schedule_uvsw(rogue_shader *shader, bool latency_hiding)
|
||||
{
|
||||
if (shader->is_grouped)
|
||||
return false;
|
||||
|
||||
/* TODO: Support for other shader types that write to the unified vertex
|
||||
* store. */
|
||||
if (shader->stage != MESA_SHADER_VERTEX)
|
||||
return false;
|
||||
|
||||
/* TODO: Add support for delayed scheduling (latency hiding). */
|
||||
if (latency_hiding)
|
||||
unreachable("Latency hiding is unimplemented.");
|
||||
|
||||
rogue_builder b;
|
||||
rogue_builder_init(&b, shader);
|
||||
|
||||
/* Check whether there are uvsw.writes. */
|
||||
bool uvsw_write_present = false;
|
||||
rogue_foreach_instr_in_shader (instr, shader) {
|
||||
if (instr->type != ROGUE_INSTR_TYPE_BACKEND)
|
||||
continue;
|
||||
|
||||
rogue_backend_instr *backend = rogue_instr_as_backend(instr);
|
||||
if (backend->op != ROGUE_BACKEND_OP_UVSW_WRITE)
|
||||
continue;
|
||||
|
||||
uvsw_write_present = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!uvsw_write_present)
|
||||
return false;
|
||||
|
||||
/* Insert emit/end task before the final instruction (nop.end). */
|
||||
rogue_block *final_block =
|
||||
list_last_entry(&shader->blocks, rogue_block, link);
|
||||
rogue_instr *final_instr =
|
||||
list_last_entry(&final_block->instrs, rogue_instr, link);
|
||||
|
||||
if (!rogue_instr_is_nop_end(final_instr))
|
||||
unreachable("UVSW emit/end task need to be the final instruction.");
|
||||
|
||||
b.cursor = rogue_cursor_before_instr(final_instr);
|
||||
|
||||
/* TODO: If instruction before nop.end is uvsw.write then
|
||||
* UVSW_WRITETHENEMITTHENENDTASK. */
|
||||
|
||||
rogue_UVSW_EMIT(&b);
|
||||
rogue_UVSW_ENDTASK(&b);
|
||||
|
||||
/* TODO: replace nop.end and add end flag to final uvsw instruction instead.
|
||||
*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -21,54 +21,53 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_VALIDATE_H
|
||||
#define ROGUE_VALIDATE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "rogue_instr.h"
|
||||
#include "rogue_operand.h"
|
||||
#include "rogue_shader.h"
|
||||
#include "rogue.h"
|
||||
#include "rogue_builder.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
/**
|
||||
* \brief Register rule description.
|
||||
*/
|
||||
struct rogue_register_rule {
|
||||
enum rogue_register_access access;
|
||||
size_t max;
|
||||
enum rogue_register_modifier modifiers;
|
||||
};
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \brief Instruction operand rule description.
|
||||
* \file rogue_schedule_wdf.c
|
||||
*
|
||||
* \brief Contains the rogue_schedule_wdf pass.
|
||||
*/
|
||||
struct rogue_instr_operand_rule {
|
||||
uint64_t mask;
|
||||
ssize_t min;
|
||||
ssize_t max;
|
||||
ssize_t align;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Instruction rule description.
|
||||
*/
|
||||
struct rogue_instr_rule {
|
||||
uint64_t flags; /** A mask of #rogue_instr_flag values. */
|
||||
size_t num_operands;
|
||||
struct rogue_instr_operand_rule *operand_rules;
|
||||
};
|
||||
static bool
|
||||
rogue_insert_wdf(rogue_builder *b, rogue_drc_trxn *drc_trxn, unsigned num)
|
||||
{
|
||||
assert(drc_trxn->acquire);
|
||||
|
||||
if (drc_trxn->release)
|
||||
return false;
|
||||
|
||||
b->cursor = rogue_cursor_after_instr(drc_trxn->acquire);
|
||||
drc_trxn->release = &rogue_WDF(b, rogue_ref_drc_trxn(num, drc_trxn))->instr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Schedules WDF instructions for DRC transactions. */
|
||||
PUBLIC
|
||||
bool rogue_validate_operand(const struct rogue_operand *operand);
|
||||
bool rogue_schedule_wdf(rogue_shader *shader, bool latency_hiding)
|
||||
{
|
||||
if (shader->is_grouped)
|
||||
return false;
|
||||
|
||||
PUBLIC
|
||||
bool rogue_validate_instr(const struct rogue_instr *instr);
|
||||
/* TODO: Add support for delayed scheduling (latency hiding). */
|
||||
if (latency_hiding)
|
||||
unreachable("Latency hiding is unimplemented.");
|
||||
|
||||
PUBLIC
|
||||
bool rogue_validate_shader(const struct rogue_shader *shader);
|
||||
bool progress = false;
|
||||
|
||||
#endif /* ROGUE_VALIDATE_H */
|
||||
rogue_builder b;
|
||||
rogue_builder_init(&b, shader);
|
||||
|
||||
rogue_foreach_drc_trxn (drc_trxn, shader, 0)
|
||||
progress |= rogue_insert_wdf(&b, drc_trxn, 0);
|
||||
|
||||
rogue_foreach_drc_trxn (drc_trxn, shader, 1)
|
||||
progress |= rogue_insert_wdf(&b, drc_trxn, 1);
|
||||
|
||||
return progress;
|
||||
}
|
||||
106
src/imagination/rogue/passes/rogue_trim.c
Normal file
106
src/imagination/rogue/passes/rogue_trim.c
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "rogue.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file rogue_trim.c
|
||||
*
|
||||
* \brief Contains the rogue_trim pass.
|
||||
*/
|
||||
|
||||
static bool rogue_trim_instrs(rogue_shader *shader)
|
||||
{
|
||||
bool progress = false;
|
||||
|
||||
shader->next_block = 0;
|
||||
shader->next_instr = 0;
|
||||
|
||||
rogue_foreach_block (block, shader) {
|
||||
progress |= (block->index != shader->next_block);
|
||||
block->index = shader->next_block++;
|
||||
rogue_foreach_instr_in_block (instr, block) {
|
||||
progress |= (instr->index != shader->next_instr);
|
||||
instr->index = shader->next_instr++;
|
||||
}
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
static bool rogue_trim_regs(rogue_shader *shader)
|
||||
{
|
||||
bool progress = false;
|
||||
|
||||
rogue_reset_reg_usage(shader, ROGUE_REG_CLASS_SSA);
|
||||
rogue_reset_reg_usage(shader, ROGUE_REG_CLASS_TEMP);
|
||||
|
||||
unsigned index[ROGUE_REG_CLASS_COUNT] = { 0 };
|
||||
|
||||
rogue_foreach_regarray (regarray, shader) {
|
||||
enum rogue_reg_class class = regarray->regs[0]->class;
|
||||
if (class != ROGUE_REG_CLASS_SSA && class != ROGUE_REG_CLASS_TEMP)
|
||||
continue;
|
||||
|
||||
if (regarray->parent)
|
||||
continue;
|
||||
|
||||
for (unsigned u = 0; u < regarray->size; ++u)
|
||||
progress |=
|
||||
rogue_reg_set(shader, regarray->regs[u], class, index[class]++);
|
||||
}
|
||||
|
||||
rogue_foreach_reg (reg, shader, ROGUE_REG_CLASS_SSA) {
|
||||
if (reg->dirty)
|
||||
continue;
|
||||
|
||||
progress |= rogue_reg_set(shader, reg, reg->class, index[reg->class]++);
|
||||
}
|
||||
|
||||
rogue_foreach_reg (reg, shader, ROGUE_REG_CLASS_TEMP) {
|
||||
if (reg->dirty)
|
||||
continue;
|
||||
|
||||
progress |= rogue_reg_set(shader, reg, reg->class, index[reg->class]++);
|
||||
}
|
||||
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* Renumbers instructions, blocks, and temp/ssa registers. */
|
||||
PUBLIC
|
||||
bool rogue_trim(rogue_shader *shader)
|
||||
{
|
||||
if (shader->is_grouped)
|
||||
return false;
|
||||
|
||||
bool progress = false;
|
||||
|
||||
progress |= rogue_trim_instrs(shader);
|
||||
progress |= rogue_trim_regs(shader);
|
||||
|
||||
return progress;
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -21,31 +21,47 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_CONSTREGS_H
|
||||
#define ROGUE_CONSTREGS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util/macros.h"
|
||||
#include "util/u_math.h"
|
||||
|
||||
#define ROGUE_NO_CONST_REG SIZE_MAX
|
||||
|
||||
PUBLIC
|
||||
size_t rogue_constreg_lookup(uint32_t value);
|
||||
|
||||
/**
|
||||
* \brief Determines whether a given floating point value exists in a constant
|
||||
* register.
|
||||
* \file rogue_alu_instrs.def
|
||||
*
|
||||
* \param[in] value The value required.
|
||||
* \return The index of the constant register containing the value, or
|
||||
* ROGUE_NO_CONST_REG if the value is not found.
|
||||
* \brief Contains macros defining ALU instructions.
|
||||
*/
|
||||
static inline size_t rogue_constreg_lookup_float(float value)
|
||||
{
|
||||
return rogue_constreg_lookup(fui(value));
|
||||
}
|
||||
|
||||
#endif /* ROGUE_CONSTREGS_H */
|
||||
/*
|
||||
* ROGUE_BUILDER_DEFINE_ALUs
|
||||
* s: Number of sources.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_BUILDER_DEFINE_ALU1
|
||||
#define ROGUE_BUILDER_DEFINE_ALU1(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_ALU1 */
|
||||
|
||||
#ifndef ROGUE_BUILDER_DEFINE_ALU2
|
||||
#define ROGUE_BUILDER_DEFINE_ALU2(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_ALU2 */
|
||||
|
||||
#ifndef ROGUE_BUILDER_DEFINE_ALU3
|
||||
#define ROGUE_BUILDER_DEFINE_ALU3(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_ALU3 */
|
||||
|
||||
ROGUE_BUILDER_DEFINE_ALU1(MOV)
|
||||
ROGUE_BUILDER_DEFINE_ALU1(MBYP)
|
||||
|
||||
ROGUE_BUILDER_DEFINE_ALU1(FABS)
|
||||
ROGUE_BUILDER_DEFINE_ALU1(FNEG)
|
||||
ROGUE_BUILDER_DEFINE_ALU1(FNABS)
|
||||
|
||||
ROGUE_BUILDER_DEFINE_ALU1(PCK_U8888)
|
||||
|
||||
ROGUE_BUILDER_DEFINE_ALU2(FADD)
|
||||
ROGUE_BUILDER_DEFINE_ALU2(FMUL)
|
||||
|
||||
ROGUE_BUILDER_DEFINE_ALU2(FMAX)
|
||||
ROGUE_BUILDER_DEFINE_ALU2(FMIN)
|
||||
|
||||
ROGUE_BUILDER_DEFINE_ALU3(SEL)
|
||||
ROGUE_BUILDER_DEFINE_ALU3(FMAD)
|
||||
|
||||
#undef ROGUE_BUILDER_DEFINE_ALU3
|
||||
#undef ROGUE_BUILDER_DEFINE_ALU2
|
||||
#undef ROGUE_BUILDER_DEFINE_ALU1
|
||||
|
|
@ -21,33 +21,39 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_ENCODERS_H
|
||||
#define ROGUE_ENCODERS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util/macros.h"
|
||||
|
||||
/* Returns false if input was invalid. */
|
||||
typedef bool (*field_encoder_t)(uint64_t *value, size_t inputs, ...);
|
||||
|
||||
bool rogue_encoder_pass(uint64_t *value, size_t inputs, ...);
|
||||
bool rogue_encoder_drc(uint64_t *value, size_t inputs, ...);
|
||||
bool rogue_encoder_imm(uint64_t *value, size_t inputs, ...);
|
||||
bool rogue_encoder_ls_1_16(uint64_t *value, size_t inputs, ...);
|
||||
|
||||
/**
|
||||
* \brief Macro to declare the rogue_encoder_reg variants.
|
||||
* \file rogue_backend_instrs.def
|
||||
*
|
||||
* \brief Contains macros defining backend instructions.
|
||||
*/
|
||||
#define ROGUE_ENCODER_REG_VARIANT(bank_bits, num_bits) \
|
||||
bool rogue_encoder_reg_##bank_bits##_##num_bits(uint64_t *value, \
|
||||
size_t inputs, \
|
||||
...);
|
||||
ROGUE_ENCODER_REG_VARIANT(2, 8)
|
||||
ROGUE_ENCODER_REG_VARIANT(3, 8)
|
||||
ROGUE_ENCODER_REG_VARIANT(3, 11)
|
||||
#undef ROGUE_ENCODER_REG_VARIANT
|
||||
|
||||
#endif /* ROGUE_ENCODERS_H */
|
||||
/*
|
||||
* ROGUE_BUILDER_DEFINE_BACKENDds
|
||||
* d: Number of destinations.
|
||||
* s: Number of sources.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_BUILDER_DEFINE_BACKEND00
|
||||
#define ROGUE_BUILDER_DEFINE_BACKEND00(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_BACKEND00 */
|
||||
|
||||
#ifndef ROGUE_BUILDER_DEFINE_BACKEND11
|
||||
#define ROGUE_BUILDER_DEFINE_BACKEND11(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_BACKEND11 */
|
||||
|
||||
#ifndef ROGUE_BUILDER_DEFINE_BACKEND14
|
||||
#define ROGUE_BUILDER_DEFINE_BACKEND14(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_BACKEND14 */
|
||||
|
||||
ROGUE_BUILDER_DEFINE_BACKEND00(UVSW_EMIT)
|
||||
ROGUE_BUILDER_DEFINE_BACKEND00(UVSW_ENDTASK)
|
||||
ROGUE_BUILDER_DEFINE_BACKEND00(UVSW_EMITTHENENDTASK)
|
||||
|
||||
ROGUE_BUILDER_DEFINE_BACKEND11(UVSW_WRITE)
|
||||
ROGUE_BUILDER_DEFINE_BACKEND11(UVSW_WRITETHENEMITTHENENDTASK)
|
||||
|
||||
ROGUE_BUILDER_DEFINE_BACKEND14(FITRP_PIXEL)
|
||||
|
||||
#undef ROGUE_BUILDER_DEFINE_BACKEND14
|
||||
#undef ROGUE_BUILDER_DEFINE_BACKEND11
|
||||
#undef ROGUE_BUILDER_DEFINE_BACKEND00
|
||||
|
|
@ -21,10 +21,23 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "rogue_operand.h"
|
||||
|
||||
/**
|
||||
* \file rogue_operand.c
|
||||
* \file rogue_bitwise_instrs.def
|
||||
*
|
||||
* \brief Contains functions to manipulate Rogue instruction operands.
|
||||
* \brief Contains macros defining bitwise instructions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* ROGUE_BUILDER_DEFINE_BITWISEds
|
||||
* d: Number of destinations.
|
||||
* s: Number of sources.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_BUILDER_DEFINE_BITWISE22
|
||||
#define ROGUE_BUILDER_DEFINE_BITWISE22(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_BITWISE22 */
|
||||
|
||||
ROGUE_BUILDER_DEFINE_BITWISE22(MOV2)
|
||||
ROGUE_BUILDER_DEFINE_BITWISE22(BYP)
|
||||
|
||||
#undef ROGUE_BUILDER_DEFINE_BITWISE22
|
||||
|
|
@ -29,9 +29,7 @@
|
|||
|
||||
#include "compiler/shader_enums.h"
|
||||
#include "nir/nir.h"
|
||||
#include "rogue_build_data.h"
|
||||
#include "rogue_nir_helpers.h"
|
||||
#include "rogue_operand.h"
|
||||
#include "rogue.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#define __pvr_address_type uint64_t
|
||||
|
|
@ -44,6 +42,14 @@
|
|||
#undef __pvr_get_address
|
||||
#undef __pvr_address_type
|
||||
|
||||
/**
|
||||
* \file rogue_build_data.c
|
||||
*
|
||||
* \brief Contains functions to collect build data for the driver.
|
||||
*/
|
||||
|
||||
/* N.B. This will all be hoisted into the driver. */
|
||||
|
||||
/**
|
||||
* \brief Allocates the coefficient registers that will contain the iterator
|
||||
* data for the fragment shader input varyings.
|
||||
|
|
@ -51,11 +57,11 @@
|
|||
* \param[in] args The iterator argument data.
|
||||
* \return The total number of coefficient registers required by the iterators.
|
||||
*/
|
||||
static size_t alloc_iterator_regs(struct rogue_iterator_args *args)
|
||||
static unsigned alloc_iterator_regs(struct rogue_iterator_args *args)
|
||||
{
|
||||
size_t coeffs = 0;
|
||||
unsigned coeffs = 0;
|
||||
|
||||
for (size_t u = 0; u < args->num_fpu_iterators; ++u) {
|
||||
for (unsigned u = 0; u < args->num_fpu_iterators; ++u) {
|
||||
/* Ensure there aren't any gaps. */
|
||||
assert(args->base[u] == ~0);
|
||||
|
||||
|
|
@ -77,10 +83,10 @@ static size_t alloc_iterator_regs(struct rogue_iterator_args *args)
|
|||
* \param[in] components The number of components in the varying.
|
||||
*/
|
||||
static void reserve_iterator(struct rogue_iterator_args *args,
|
||||
size_t i,
|
||||
unsigned i,
|
||||
enum glsl_interp_mode type,
|
||||
bool f16,
|
||||
size_t components)
|
||||
unsigned components)
|
||||
{
|
||||
struct ROGUE_PDSINST_DOUT_FIELDS_DOUTI_SRC data = { 0 };
|
||||
|
||||
|
|
@ -126,6 +132,18 @@ static void reserve_iterator(struct rogue_iterator_args *args,
|
|||
++args->num_fpu_iterators;
|
||||
}
|
||||
|
||||
static inline unsigned nir_count_variables_with_modes(const nir_shader *nir,
|
||||
nir_variable_mode mode)
|
||||
{
|
||||
unsigned count = 0;
|
||||
|
||||
nir_foreach_variable_with_modes (var, nir, mode) {
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Collects the fragment shader I/O data to feed-back to the driver.
|
||||
*
|
||||
|
|
@ -134,13 +152,12 @@ static void reserve_iterator(struct rogue_iterator_args *args,
|
|||
* \param[in] common_data Common build data.
|
||||
* \param[in] fs_data Fragment-specific build data.
|
||||
* \param[in] nir NIR fragment shader.
|
||||
* \return true if successful, otherwise false.
|
||||
*/
|
||||
static bool collect_io_data_fs(struct rogue_common_build_data *common_data,
|
||||
static void collect_io_data_fs(struct rogue_common_build_data *common_data,
|
||||
struct rogue_fs_build_data *fs_data,
|
||||
nir_shader *nir)
|
||||
{
|
||||
size_t num_inputs = nir_count_variables_with_modes(nir, nir_var_shader_in);
|
||||
unsigned num_inputs = nir_count_variables_with_modes(nir, nir_var_shader_in);
|
||||
assert(num_inputs < (ARRAY_SIZE(fs_data->iterator_args.fpu_iterators) - 1));
|
||||
|
||||
/* Process inputs (if present). */
|
||||
|
|
@ -155,8 +172,8 @@ static bool collect_io_data_fs(struct rogue_common_build_data *common_data,
|
|||
1);
|
||||
|
||||
nir_foreach_shader_in_variable (var, nir) {
|
||||
size_t i = (var->data.location - VARYING_SLOT_VAR0) + 1;
|
||||
size_t components = glsl_get_components(var->type);
|
||||
unsigned i = (var->data.location - VARYING_SLOT_VAR0) + 1;
|
||||
unsigned components = glsl_get_components(var->type);
|
||||
enum glsl_interp_mode interp = var->data.interpolation;
|
||||
bool f16 = glsl_type_is_16bit(var->type);
|
||||
|
||||
|
|
@ -173,12 +190,10 @@ static bool collect_io_data_fs(struct rogue_common_build_data *common_data,
|
|||
|
||||
common_data->coeffs = alloc_iterator_regs(&fs_data->iterator_args);
|
||||
assert(common_data->coeffs);
|
||||
assert(common_data->coeffs < ROGUE_MAX_REG_COEFF);
|
||||
assert(common_data->coeffs <= rogue_reg_infos[ROGUE_REG_CLASS_COEFF].num);
|
||||
}
|
||||
|
||||
/* TODO: Process outputs. */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -187,11 +202,11 @@ static bool collect_io_data_fs(struct rogue_common_build_data *common_data,
|
|||
* \param[in] inputs The vertex shader input data.
|
||||
* \return The total number of vertex input registers required.
|
||||
*/
|
||||
static size_t alloc_vs_inputs(struct rogue_vertex_inputs *inputs)
|
||||
static unsigned alloc_vs_inputs(struct rogue_vertex_inputs *inputs)
|
||||
{
|
||||
size_t vs_inputs = 0;
|
||||
unsigned vs_inputs = 0;
|
||||
|
||||
for (size_t u = 0; u < inputs->num_input_vars; ++u) {
|
||||
for (unsigned u = 0; u < inputs->num_input_vars; ++u) {
|
||||
/* Ensure there aren't any gaps. */
|
||||
assert(inputs->base[u] == ~0);
|
||||
|
||||
|
|
@ -208,11 +223,11 @@ static size_t alloc_vs_inputs(struct rogue_vertex_inputs *inputs)
|
|||
* \param[in] outputs The vertex shader output data.
|
||||
* \return The total number of vertex outputs required.
|
||||
*/
|
||||
static size_t alloc_vs_outputs(struct rogue_vertex_outputs *outputs)
|
||||
static unsigned alloc_vs_outputs(struct rogue_vertex_outputs *outputs)
|
||||
{
|
||||
size_t vs_outputs = 0;
|
||||
unsigned vs_outputs = 0;
|
||||
|
||||
for (size_t u = 0; u < outputs->num_output_vars; ++u) {
|
||||
for (unsigned u = 0; u < outputs->num_output_vars; ++u) {
|
||||
/* Ensure there aren't any gaps. */
|
||||
assert(outputs->base[u] == ~0);
|
||||
|
||||
|
|
@ -229,12 +244,12 @@ static size_t alloc_vs_outputs(struct rogue_vertex_outputs *outputs)
|
|||
* \param[in] outputs The vertex shader output data.
|
||||
* \return The number of varyings used.
|
||||
*/
|
||||
static size_t count_vs_varyings(struct rogue_vertex_outputs *outputs)
|
||||
static unsigned count_vs_varyings(struct rogue_vertex_outputs *outputs)
|
||||
{
|
||||
size_t varyings = 0;
|
||||
unsigned varyings = 0;
|
||||
|
||||
/* Skip the position. */
|
||||
for (size_t u = 1; u < outputs->num_output_vars; ++u)
|
||||
for (unsigned u = 1; u < outputs->num_output_vars; ++u)
|
||||
varyings += outputs->components[u];
|
||||
|
||||
return varyings;
|
||||
|
|
@ -248,8 +263,8 @@ static size_t count_vs_varyings(struct rogue_vertex_outputs *outputs)
|
|||
* \param[in] components The number of components in the input.
|
||||
*/
|
||||
static void reserve_vs_input(struct rogue_vertex_inputs *inputs,
|
||||
size_t i,
|
||||
size_t components)
|
||||
unsigned i,
|
||||
unsigned components)
|
||||
{
|
||||
assert(components >= 1 && components <= 4);
|
||||
|
||||
|
|
@ -268,8 +283,8 @@ static void reserve_vs_input(struct rogue_vertex_inputs *inputs,
|
|||
* \param[in] components The number of components in the output.
|
||||
*/
|
||||
static void reserve_vs_output(struct rogue_vertex_outputs *outputs,
|
||||
size_t i,
|
||||
size_t components)
|
||||
unsigned i,
|
||||
unsigned components)
|
||||
{
|
||||
assert(components >= 1 && components <= 4);
|
||||
|
||||
|
|
@ -288,20 +303,19 @@ static void reserve_vs_output(struct rogue_vertex_outputs *outputs,
|
|||
* \param[in] common_data Common build data.
|
||||
* \param[in] vs_data Vertex-specific build data.
|
||||
* \param[in] nir NIR vertex shader.
|
||||
* \return true if successful, otherwise false.
|
||||
*/
|
||||
static bool collect_io_data_vs(struct rogue_common_build_data *common_data,
|
||||
static void collect_io_data_vs(struct rogue_common_build_data *common_data,
|
||||
struct rogue_vs_build_data *vs_data,
|
||||
nir_shader *nir)
|
||||
{
|
||||
ASSERTED bool out_pos_present = false;
|
||||
ASSERTED size_t num_outputs =
|
||||
ASSERTED unsigned num_outputs =
|
||||
nir_count_variables_with_modes(nir, nir_var_shader_out);
|
||||
|
||||
/* Process inputs. */
|
||||
nir_foreach_shader_in_variable (var, nir) {
|
||||
size_t components = glsl_get_components(var->type);
|
||||
size_t i = var->data.location - VERT_ATTRIB_GENERIC0;
|
||||
unsigned components = glsl_get_components(var->type);
|
||||
unsigned i = var->data.location - VERT_ATTRIB_GENERIC0;
|
||||
|
||||
/* Check that inputs are F32. */
|
||||
/* TODO: Support other types. */
|
||||
|
|
@ -317,7 +331,8 @@ static bool collect_io_data_vs(struct rogue_common_build_data *common_data,
|
|||
|
||||
vs_data->num_vertex_input_regs = alloc_vs_inputs(&vs_data->inputs);
|
||||
assert(vs_data->num_vertex_input_regs);
|
||||
assert(vs_data->num_vertex_input_regs < ROGUE_MAX_REG_VERTEX_IN);
|
||||
assert(vs_data->num_vertex_input_regs <
|
||||
rogue_reg_infos[ROGUE_REG_CLASS_VTXIN].num);
|
||||
|
||||
/* Process outputs. */
|
||||
|
||||
|
|
@ -325,7 +340,7 @@ static bool collect_io_data_vs(struct rogue_common_build_data *common_data,
|
|||
assert(num_outputs > 0 && "Invalid number of vertex shader outputs.");
|
||||
|
||||
nir_foreach_shader_out_variable (var, nir) {
|
||||
size_t components = glsl_get_components(var->type);
|
||||
unsigned components = glsl_get_components(var->type);
|
||||
|
||||
/* Check that outputs are F32. */
|
||||
/* TODO: Support other types. */
|
||||
|
|
@ -339,7 +354,7 @@ static bool collect_io_data_vs(struct rogue_common_build_data *common_data,
|
|||
reserve_vs_output(&vs_data->outputs, 0, components);
|
||||
} else if ((var->data.location >= VARYING_SLOT_VAR0) &&
|
||||
(var->data.location <= VARYING_SLOT_VAR31)) {
|
||||
size_t i = (var->data.location - VARYING_SLOT_VAR0) + 1;
|
||||
unsigned i = (var->data.location - VARYING_SLOT_VAR0) + 1;
|
||||
reserve_vs_output(&vs_data->outputs, i, components);
|
||||
} else {
|
||||
unreachable("Unsupported vertex output type.");
|
||||
|
|
@ -351,11 +366,10 @@ static bool collect_io_data_vs(struct rogue_common_build_data *common_data,
|
|||
|
||||
vs_data->num_vertex_outputs = alloc_vs_outputs(&vs_data->outputs);
|
||||
assert(vs_data->num_vertex_outputs);
|
||||
assert(vs_data->num_vertex_outputs < ROGUE_MAX_VERTEX_OUTPUTS);
|
||||
assert(vs_data->num_vertex_outputs <
|
||||
rogue_reg_infos[ROGUE_REG_CLASS_VTXOUT].num);
|
||||
|
||||
vs_data->num_varyings = count_vs_varyings(&vs_data->outputs);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -364,11 +378,11 @@ static bool collect_io_data_vs(struct rogue_common_build_data *common_data,
|
|||
* \param[in] ubo_data The UBO data.
|
||||
* \return The total number of coefficient registers required by the iterators.
|
||||
*/
|
||||
static size_t alloc_ubos(struct rogue_ubo_data *ubo_data)
|
||||
static unsigned alloc_ubos(struct rogue_ubo_data *ubo_data)
|
||||
{
|
||||
size_t shareds = 0;
|
||||
unsigned shareds = 0;
|
||||
|
||||
for (size_t u = 0; u < ubo_data->num_ubo_entries; ++u) {
|
||||
for (unsigned u = 0; u < ubo_data->num_ubo_entries; ++u) {
|
||||
/* Ensure there aren't any gaps. */
|
||||
assert(ubo_data->dest[u] == ~0);
|
||||
|
||||
|
|
@ -388,11 +402,11 @@ static size_t alloc_ubos(struct rogue_ubo_data *ubo_data)
|
|||
* \param[in] size The size required by the UBO (in dwords).
|
||||
*/
|
||||
static void reserve_ubo(struct rogue_ubo_data *ubo_data,
|
||||
size_t desc_set,
|
||||
size_t binding,
|
||||
size_t size)
|
||||
unsigned desc_set,
|
||||
unsigned binding,
|
||||
unsigned size)
|
||||
{
|
||||
size_t i = ubo_data->num_ubo_entries;
|
||||
unsigned i = ubo_data->num_ubo_entries;
|
||||
assert(i < ARRAY_SIZE(ubo_data->desc_set));
|
||||
|
||||
ubo_data->desc_set[i] = desc_set;
|
||||
|
|
@ -407,16 +421,15 @@ static void reserve_ubo(struct rogue_ubo_data *ubo_data,
|
|||
*
|
||||
* \param[in] common_data Common build data.
|
||||
* \param[in] nir NIR shader.
|
||||
* \return true if successful, otherwise false.
|
||||
*/
|
||||
static bool collect_ubo_data(struct rogue_common_build_data *common_data,
|
||||
static void collect_ubo_data(struct rogue_common_build_data *common_data,
|
||||
nir_shader *nir)
|
||||
{
|
||||
/* Iterate over each UBO. */
|
||||
nir_foreach_variable_with_modes (var, nir, nir_var_mem_ubo) {
|
||||
size_t desc_set = var->data.driver_location;
|
||||
size_t binding = var->data.binding;
|
||||
size_t ubo_size_regs = 0;
|
||||
unsigned desc_set = var->data.driver_location;
|
||||
unsigned binding = var->data.binding;
|
||||
unsigned ubo_size_regs = 0;
|
||||
|
||||
nir_function_impl *entry = nir_shader_get_entrypoint(nir);
|
||||
/* Iterate over each load_ubo that uses this UBO. */
|
||||
|
|
@ -430,21 +443,20 @@ static bool collect_ubo_data(struct rogue_common_build_data *common_data,
|
|||
continue;
|
||||
|
||||
assert(nir_src_num_components(intr->src[0]) == 2);
|
||||
assert(nir_intr_src_is_const(intr, 0));
|
||||
|
||||
size_t load_desc_set = nir_intr_src_comp_const(intr, 0, 0);
|
||||
size_t load_binding = nir_intr_src_comp_const(intr, 0, 1);
|
||||
unsigned load_desc_set = nir_src_comp_as_uint(intr->src[0], 0);
|
||||
unsigned load_binding = nir_src_comp_as_uint(intr->src[0], 1);
|
||||
|
||||
if (load_desc_set != desc_set || load_binding != binding)
|
||||
continue;
|
||||
|
||||
ASSERTED size_t size_bytes = nir_intrinsic_range(intr);
|
||||
ASSERTED unsigned size_bytes = nir_intrinsic_range(intr);
|
||||
assert(size_bytes == ROGUE_REG_SIZE_BYTES);
|
||||
|
||||
size_t offset_bytes = nir_intrinsic_range_base(intr);
|
||||
unsigned offset_bytes = nir_intrinsic_range_base(intr);
|
||||
assert(!(offset_bytes % ROGUE_REG_SIZE_BYTES));
|
||||
|
||||
size_t offset_regs = offset_bytes / ROGUE_REG_SIZE_BYTES;
|
||||
unsigned offset_regs = offset_bytes / ROGUE_REG_SIZE_BYTES;
|
||||
|
||||
/* TODO: Put offsets in a BITSET_DECLARE and check for gaps. */
|
||||
|
||||
|
|
@ -460,9 +472,7 @@ static bool collect_ubo_data(struct rogue_common_build_data *common_data,
|
|||
}
|
||||
|
||||
common_data->shareds = alloc_ubos(&common_data->ubo_data);
|
||||
assert(common_data->shareds < ROGUE_MAX_REG_SHARED);
|
||||
|
||||
return true;
|
||||
assert(common_data->shareds < rogue_reg_infos[ROGUE_REG_CLASS_SHARED].num);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -475,16 +485,15 @@ static bool collect_ubo_data(struct rogue_common_build_data *common_data,
|
|||
*
|
||||
* \param[in] ctx Shared multi-stage build context.
|
||||
* \param[in] nir NIR shader.
|
||||
* \return true if successful, otherwise false.
|
||||
*/
|
||||
bool rogue_collect_io_data(struct rogue_build_ctx *ctx, nir_shader *nir)
|
||||
PUBLIC
|
||||
void rogue_collect_io_data(struct rogue_build_ctx *ctx, nir_shader *nir)
|
||||
{
|
||||
gl_shader_stage stage = nir->info.stage;
|
||||
struct rogue_common_build_data *common_data = &ctx->common_data[stage];
|
||||
|
||||
/* Collect stage-agnostic data. */
|
||||
if (!collect_ubo_data(common_data, nir))
|
||||
return false;
|
||||
collect_ubo_data(common_data, nir);
|
||||
|
||||
/* Collect stage-specific data. */
|
||||
switch (stage) {
|
||||
|
|
@ -498,7 +507,7 @@ bool rogue_collect_io_data(struct rogue_build_ctx *ctx, nir_shader *nir)
|
|||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
unreachable("Unsupported stage.");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -510,11 +519,12 @@ bool rogue_collect_io_data(struct rogue_build_ctx *ctx, nir_shader *nir)
|
|||
* \param[in] component The requested component.
|
||||
* \return The coefficient register index.
|
||||
*/
|
||||
size_t rogue_coeff_index_fs(struct rogue_iterator_args *args,
|
||||
gl_varying_slot location,
|
||||
size_t component)
|
||||
PUBLIC
|
||||
unsigned rogue_coeff_index_fs(struct rogue_iterator_args *args,
|
||||
gl_varying_slot location,
|
||||
unsigned component)
|
||||
{
|
||||
size_t i;
|
||||
unsigned i;
|
||||
|
||||
/* Special case: W coefficient. */
|
||||
if (location == ~0) {
|
||||
|
|
@ -542,11 +552,12 @@ size_t rogue_coeff_index_fs(struct rogue_iterator_args *args,
|
|||
* \param[in] component The requested component.
|
||||
* \return The vertex output index.
|
||||
*/
|
||||
size_t rogue_output_index_vs(struct rogue_vertex_outputs *outputs,
|
||||
gl_varying_slot location,
|
||||
size_t component)
|
||||
PUBLIC
|
||||
unsigned rogue_output_index_vs(struct rogue_vertex_outputs *outputs,
|
||||
gl_varying_slot location,
|
||||
unsigned component)
|
||||
{
|
||||
size_t i;
|
||||
unsigned i;
|
||||
|
||||
if (location == VARYING_SLOT_POS) {
|
||||
/* Always at location 0. */
|
||||
|
|
@ -575,16 +586,17 @@ size_t rogue_output_index_vs(struct rogue_vertex_outputs *outputs,
|
|||
* \param[in] offset_bytes The UBO offset in bytes.
|
||||
* \return The UBO offset shared register index.
|
||||
*/
|
||||
size_t rogue_ubo_reg(struct rogue_ubo_data *ubo_data,
|
||||
size_t desc_set,
|
||||
size_t binding,
|
||||
size_t offset_bytes)
|
||||
PUBLIC
|
||||
unsigned rogue_ubo_reg(struct rogue_ubo_data *ubo_data,
|
||||
unsigned desc_set,
|
||||
unsigned binding,
|
||||
unsigned offset_bytes)
|
||||
{
|
||||
size_t ubo_index = ~0;
|
||||
size_t offset_regs;
|
||||
unsigned ubo_index = ~0;
|
||||
unsigned offset_regs;
|
||||
|
||||
/* Find UBO located at (desc_set, binding). */
|
||||
for (size_t u = 0; u < ubo_data->num_ubo_entries; ++u) {
|
||||
for (unsigned u = 0; u < ubo_data->num_ubo_entries; ++u) {
|
||||
if (ubo_data->dest[u] == ~0)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,180 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_BUILD_DATA_H
|
||||
#define ROGUE_BUILD_DATA_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "compiler/shader_enums.h"
|
||||
#include "nir/nir.h"
|
||||
#include "rogue.h"
|
||||
|
||||
/* Max number of I/O varying variables.
|
||||
* Fragment shader: MAX_VARYING + 1 (W coefficient).
|
||||
* Vertex shader: MAX_VARYING + 1 (position slot).
|
||||
*/
|
||||
#define ROGUE_MAX_IO_VARYING_VARS (MAX_VARYING + 1)
|
||||
|
||||
/* VERT_ATTRIB_GENERIC0-15 */
|
||||
#define ROGUE_MAX_IO_ATTRIB_VARS 16
|
||||
|
||||
/* Max buffers entries that can be used. */
|
||||
/* TODO: Currently UBOs are the only supported buffers. */
|
||||
#define ROGUE_MAX_BUFFERS 24
|
||||
|
||||
struct rogue_compiler;
|
||||
struct rogue_shader;
|
||||
struct rogue_shader_binary;
|
||||
|
||||
/**
|
||||
* \brief UBO data.
|
||||
*/
|
||||
struct rogue_ubo_data {
|
||||
size_t num_ubo_entries;
|
||||
size_t desc_set[ROGUE_MAX_BUFFERS];
|
||||
size_t binding[ROGUE_MAX_BUFFERS];
|
||||
size_t dest[ROGUE_MAX_BUFFERS];
|
||||
size_t size[ROGUE_MAX_BUFFERS];
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Compile time constants that need uploading.
|
||||
*/
|
||||
struct rogue_compile_time_consts_data {
|
||||
/* TODO: Output these from the compiler. */
|
||||
/* TODO: Add the other types. */
|
||||
struct {
|
||||
size_t num;
|
||||
size_t dest;
|
||||
/* TODO: This should probably be bigger. Big enough to account for all
|
||||
* available writable special constant regs.
|
||||
*/
|
||||
uint32_t value[ROGUE_MAX_BUFFERS];
|
||||
} static_consts;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Per-stage common build data.
|
||||
*/
|
||||
struct rogue_common_build_data {
|
||||
size_t temps;
|
||||
size_t internals;
|
||||
size_t coeffs;
|
||||
size_t shareds;
|
||||
|
||||
struct rogue_ubo_data ubo_data;
|
||||
struct rogue_compile_time_consts_data compile_time_consts_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Arguments for the FPU iterator(s)
|
||||
* (produces varyings for the fragment shader).
|
||||
*/
|
||||
struct rogue_iterator_args {
|
||||
uint32_t num_fpu_iterators;
|
||||
uint32_t fpu_iterators[ROGUE_MAX_IO_VARYING_VARS];
|
||||
uint32_t destination[ROGUE_MAX_IO_VARYING_VARS];
|
||||
size_t base[ROGUE_MAX_IO_VARYING_VARS];
|
||||
size_t components[ROGUE_MAX_IO_VARYING_VARS];
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Vertex input register allocations.
|
||||
*/
|
||||
struct rogue_vertex_inputs {
|
||||
size_t num_input_vars;
|
||||
size_t base[ROGUE_MAX_IO_ATTRIB_VARS];
|
||||
size_t components[ROGUE_MAX_IO_ATTRIB_VARS];
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Vertex output allocations.
|
||||
*/
|
||||
struct rogue_vertex_outputs {
|
||||
size_t num_output_vars;
|
||||
size_t base[ROGUE_MAX_IO_VARYING_VARS];
|
||||
size_t components[ROGUE_MAX_IO_VARYING_VARS];
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Stage-specific build data.
|
||||
*/
|
||||
struct rogue_build_data {
|
||||
struct rogue_fs_build_data {
|
||||
struct rogue_iterator_args iterator_args;
|
||||
enum rogue_msaa_mode msaa_mode;
|
||||
bool phas; /* Indicates the presence of PHAS instruction. */
|
||||
} fs;
|
||||
struct rogue_vs_build_data {
|
||||
struct rogue_vertex_inputs inputs;
|
||||
size_t num_vertex_input_regs; /* Final number of inputs. */
|
||||
|
||||
struct rogue_vertex_outputs outputs;
|
||||
size_t num_vertex_outputs; /* Final number of outputs. */
|
||||
|
||||
size_t num_varyings; /* Final number of varyings. */
|
||||
} vs;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Shared multi-stage build context.
|
||||
*/
|
||||
struct rogue_build_ctx {
|
||||
struct rogue_compiler *compiler;
|
||||
|
||||
/* Shaders in various stages of compilations. */
|
||||
nir_shader *nir[MESA_SHADER_FRAGMENT + 1];
|
||||
struct rogue_shader *rogue[MESA_SHADER_FRAGMENT + 1];
|
||||
struct rogue_shader_binary *binary[MESA_SHADER_FRAGMENT + 1];
|
||||
|
||||
struct rogue_common_build_data common_data[MESA_SHADER_FRAGMENT + 1];
|
||||
struct rogue_build_data stage_data;
|
||||
};
|
||||
|
||||
PUBLIC
|
||||
struct rogue_build_ctx *
|
||||
rogue_create_build_context(struct rogue_compiler *compiler);
|
||||
|
||||
PUBLIC
|
||||
bool rogue_collect_io_data(struct rogue_build_ctx *ctx, nir_shader *nir);
|
||||
|
||||
PUBLIC
|
||||
size_t rogue_coeff_index_fs(struct rogue_iterator_args *args,
|
||||
gl_varying_slot location,
|
||||
size_t component);
|
||||
|
||||
PUBLIC
|
||||
size_t rogue_output_index_vs(struct rogue_vertex_outputs *outputs,
|
||||
gl_varying_slot location,
|
||||
size_t component);
|
||||
|
||||
PUBLIC
|
||||
size_t rogue_ubo_reg(struct rogue_ubo_data *ubo_data,
|
||||
size_t desc_set,
|
||||
size_t binding,
|
||||
size_t offset_bytes);
|
||||
|
||||
#endif /* ROGUE_BUILD_DATA_H */
|
||||
364
src/imagination/rogue/rogue_builder.c
Normal file
364
src/imagination/rogue/rogue_builder.c
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "rogue.h"
|
||||
#include "rogue_builder.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
/**
|
||||
* \file rogue_builder.c
|
||||
*
|
||||
* \brief Contains helper functions for building Rogue shaders.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Inserts an instruction at the current builder context position.
|
||||
*
|
||||
* \param[in] b The builder context.
|
||||
* \param[in] instr The instruction to insert.
|
||||
*/
|
||||
static inline void rogue_builder_insert_instr(rogue_builder *b,
|
||||
rogue_instr *instr)
|
||||
{
|
||||
rogue_instr_insert(instr, b->cursor);
|
||||
b->cursor = rogue_cursor_after_instr(instr);
|
||||
}
|
||||
|
||||
/* ALU instructions */
|
||||
|
||||
static inline rogue_alu_instr *rogue_build_alu(rogue_builder *b,
|
||||
enum rogue_alu_op op,
|
||||
rogue_ref dst,
|
||||
unsigned num_srcs,
|
||||
rogue_ref srcs[num_srcs])
|
||||
{
|
||||
rogue_alu_instr *alu =
|
||||
rogue_alu_instr_create(rogue_cursor_block(b->cursor), op);
|
||||
|
||||
alu->dst.ref = dst;
|
||||
for (unsigned i = 0; i < num_srcs; ++i) {
|
||||
alu->src[i].ref = srcs[i];
|
||||
alu->src[i].index = i;
|
||||
}
|
||||
|
||||
rogue_builder_insert_instr(b, &alu->instr);
|
||||
return alu;
|
||||
}
|
||||
|
||||
static inline rogue_alu_instr *rogue_build_alu1(rogue_builder *b,
|
||||
enum rogue_alu_op op,
|
||||
rogue_ref dst,
|
||||
rogue_ref src0)
|
||||
{
|
||||
rogue_ref srcs[] = { src0 };
|
||||
return rogue_build_alu(b, op, dst, 1, srcs);
|
||||
}
|
||||
|
||||
static inline rogue_alu_instr *rogue_build_alu2(rogue_builder *b,
|
||||
enum rogue_alu_op op,
|
||||
rogue_ref dst,
|
||||
rogue_ref src0,
|
||||
rogue_ref src1)
|
||||
{
|
||||
rogue_ref srcs[] = { src0, src1 };
|
||||
return rogue_build_alu(b, op, dst, 2, srcs);
|
||||
}
|
||||
|
||||
static inline rogue_alu_instr *rogue_build_alu3(rogue_builder *b,
|
||||
enum rogue_alu_op op,
|
||||
rogue_ref dst,
|
||||
rogue_ref src0,
|
||||
rogue_ref src1,
|
||||
rogue_ref src2)
|
||||
{
|
||||
rogue_ref srcs[] = { src0, src1, src2 };
|
||||
return rogue_build_alu(b, op, dst, 3, srcs);
|
||||
}
|
||||
|
||||
/* TODO: Static inline in rogue.h? */
|
||||
#define ROGUE_BUILDER_DEFINE_ALU1(op) \
|
||||
PUBLIC \
|
||||
rogue_alu_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst, \
|
||||
rogue_ref src0) \
|
||||
{ \
|
||||
assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 1); \
|
||||
return rogue_build_alu1(b, ROGUE_ALU_OP_##op, dst, src0); \
|
||||
}
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_ALU2(op) \
|
||||
PUBLIC \
|
||||
rogue_alu_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst, \
|
||||
rogue_ref src0, \
|
||||
rogue_ref src1) \
|
||||
{ \
|
||||
assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 2); \
|
||||
return rogue_build_alu2(b, ROGUE_ALU_OP_##op, dst, src0, src1); \
|
||||
}
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_ALU3(op) \
|
||||
PUBLIC \
|
||||
rogue_alu_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst, \
|
||||
rogue_ref src0, \
|
||||
rogue_ref src1, \
|
||||
rogue_ref src2) \
|
||||
{ \
|
||||
assert(rogue_alu_op_infos[ROGUE_ALU_OP_##op].num_srcs == 3); \
|
||||
return rogue_build_alu3(b, ROGUE_ALU_OP_##op, dst, src0, src1, src2); \
|
||||
}
|
||||
|
||||
#include "rogue_alu_instrs.def"
|
||||
|
||||
static inline rogue_backend_instr *rogue_build_backend(rogue_builder *b,
|
||||
enum rogue_backend_op op,
|
||||
unsigned num_dsts,
|
||||
rogue_ref dsts[num_dsts],
|
||||
unsigned num_srcs,
|
||||
rogue_ref srcs[num_srcs])
|
||||
{
|
||||
rogue_backend_instr *backend =
|
||||
rogue_backend_instr_create(rogue_cursor_block(b->cursor), op);
|
||||
|
||||
for (unsigned i = 0; i < num_dsts; ++i) {
|
||||
backend->dst[i].ref = dsts[i];
|
||||
backend->dst[i].index = i;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < num_srcs; ++i) {
|
||||
backend->src[i].ref = srcs[i];
|
||||
backend->src[i].index = i;
|
||||
}
|
||||
|
||||
rogue_builder_insert_instr(b, &backend->instr);
|
||||
return backend;
|
||||
}
|
||||
|
||||
static inline rogue_backend_instr *
|
||||
rogue_build_backend00(rogue_builder *b, enum rogue_backend_op op)
|
||||
{
|
||||
return rogue_build_backend(b, op, 0, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static inline rogue_backend_instr *
|
||||
rogue_build_backend11(rogue_builder *b,
|
||||
enum rogue_backend_op op,
|
||||
rogue_ref dst0,
|
||||
rogue_ref src0)
|
||||
{
|
||||
rogue_ref dsts[] = { dst0 };
|
||||
rogue_ref srcs[] = { src0 };
|
||||
return rogue_build_backend(b, op, 1, dsts, 1, srcs);
|
||||
}
|
||||
|
||||
static inline rogue_backend_instr *
|
||||
rogue_build_backend14(rogue_builder *b,
|
||||
enum rogue_backend_op op,
|
||||
rogue_ref dst0,
|
||||
rogue_ref src0,
|
||||
rogue_ref src1,
|
||||
rogue_ref src2,
|
||||
rogue_ref src3)
|
||||
{
|
||||
rogue_ref dsts[] = { dst0 };
|
||||
rogue_ref srcs[] = { src0, src1, src2, src3 };
|
||||
return rogue_build_backend(b, op, 1, dsts, 4, srcs);
|
||||
}
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_BACKEND00(op) \
|
||||
PUBLIC \
|
||||
rogue_backend_instr *rogue_##op(rogue_builder *b) \
|
||||
{ \
|
||||
assert(rogue_backend_op_infos[ROGUE_BACKEND_OP_##op].num_dsts == 0); \
|
||||
assert(rogue_backend_op_infos[ROGUE_BACKEND_OP_##op].num_srcs == 0); \
|
||||
return rogue_build_backend00(b, ROGUE_BACKEND_OP_##op); \
|
||||
}
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_BACKEND11(op) \
|
||||
PUBLIC \
|
||||
rogue_backend_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst0, \
|
||||
rogue_ref src0) \
|
||||
{ \
|
||||
assert(rogue_backend_op_infos[ROGUE_BACKEND_OP_##op].num_dsts == 1); \
|
||||
assert(rogue_backend_op_infos[ROGUE_BACKEND_OP_##op].num_srcs == 1); \
|
||||
return rogue_build_backend11(b, ROGUE_BACKEND_OP_##op, dst0, src0); \
|
||||
}
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_BACKEND14(op) \
|
||||
PUBLIC \
|
||||
rogue_backend_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst0, \
|
||||
rogue_ref src0, \
|
||||
rogue_ref src1, \
|
||||
rogue_ref src2, \
|
||||
rogue_ref src3) \
|
||||
{ \
|
||||
assert(rogue_backend_op_infos[ROGUE_BACKEND_OP_##op].num_dsts == 1); \
|
||||
assert(rogue_backend_op_infos[ROGUE_BACKEND_OP_##op].num_srcs == 4); \
|
||||
return rogue_build_backend14(b, \
|
||||
ROGUE_BACKEND_OP_##op, \
|
||||
dst0, \
|
||||
src0, \
|
||||
src1, \
|
||||
src2, \
|
||||
src3); \
|
||||
}
|
||||
|
||||
#include "rogue_backend_instrs.def"
|
||||
|
||||
static inline rogue_ctrl_instr *rogue_build_ctrl(rogue_builder *b,
|
||||
enum rogue_ctrl_op op,
|
||||
rogue_block *target_block,
|
||||
unsigned num_dsts,
|
||||
rogue_ref dsts[num_dsts],
|
||||
unsigned num_srcs,
|
||||
rogue_ref srcs[num_srcs])
|
||||
{
|
||||
rogue_ctrl_instr *ctrl =
|
||||
rogue_ctrl_instr_create(rogue_cursor_block(b->cursor), op);
|
||||
|
||||
ctrl->target_block = target_block;
|
||||
|
||||
for (unsigned i = 0; i < num_dsts; ++i) {
|
||||
ctrl->dst[i].ref = dsts[i];
|
||||
ctrl->dst[i].index = i;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < num_srcs; ++i) {
|
||||
ctrl->src[i].ref = srcs[i];
|
||||
ctrl->src[i].index = i;
|
||||
}
|
||||
|
||||
rogue_builder_insert_instr(b, &ctrl->instr);
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
static inline rogue_ctrl_instr *
|
||||
rogue_build_ctrlb(rogue_builder *b, enum rogue_ctrl_op op, rogue_block *block)
|
||||
{
|
||||
return rogue_build_ctrl(b, op, block, 0, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static inline rogue_ctrl_instr *rogue_build_ctrl00(rogue_builder *b,
|
||||
enum rogue_ctrl_op op)
|
||||
{
|
||||
return rogue_build_ctrl(b, op, NULL, 0, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
static inline rogue_ctrl_instr *
|
||||
rogue_build_ctrl01(rogue_builder *b, enum rogue_ctrl_op op, rogue_ref src0)
|
||||
{
|
||||
rogue_ref srcs[] = { src0 };
|
||||
return rogue_build_ctrl(b, op, NULL, 0, NULL, 1, srcs);
|
||||
}
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_CTRLB(op) \
|
||||
PUBLIC \
|
||||
rogue_ctrl_instr *rogue_##op(rogue_builder *b, rogue_block *block) \
|
||||
{ \
|
||||
assert(rogue_ctrl_op_infos[ROGUE_CTRL_OP_##op].has_target); \
|
||||
assert(rogue_ctrl_op_infos[ROGUE_CTRL_OP_##op].num_dsts == 0); \
|
||||
assert(rogue_ctrl_op_infos[ROGUE_CTRL_OP_##op].num_srcs == 0); \
|
||||
return rogue_build_ctrlb(b, ROGUE_CTRL_OP_##op, block); \
|
||||
}
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_CTRL00(op) \
|
||||
PUBLIC \
|
||||
rogue_ctrl_instr *rogue_##op(rogue_builder *b) \
|
||||
{ \
|
||||
assert(!rogue_ctrl_op_infos[ROGUE_CTRL_OP_##op].has_target); \
|
||||
assert(rogue_ctrl_op_infos[ROGUE_CTRL_OP_##op].num_dsts == 0); \
|
||||
assert(rogue_ctrl_op_infos[ROGUE_CTRL_OP_##op].num_srcs == 0); \
|
||||
return rogue_build_ctrl00(b, ROGUE_CTRL_OP_##op); \
|
||||
}
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_CTRL01(op) \
|
||||
PUBLIC \
|
||||
rogue_ctrl_instr *rogue_##op(rogue_builder *b, rogue_ref src0) \
|
||||
{ \
|
||||
assert(!rogue_ctrl_op_infos[ROGUE_CTRL_OP_##op].has_target); \
|
||||
assert(rogue_ctrl_op_infos[ROGUE_CTRL_OP_##op].num_dsts == 0); \
|
||||
assert(rogue_ctrl_op_infos[ROGUE_CTRL_OP_##op].num_srcs == 1); \
|
||||
return rogue_build_ctrl01(b, ROGUE_CTRL_OP_##op, src0); \
|
||||
}
|
||||
|
||||
#include "rogue_ctrl_instrs.def"
|
||||
|
||||
static inline rogue_bitwise_instr *rogue_build_bitwise(rogue_builder *b,
|
||||
enum rogue_bitwise_op op,
|
||||
unsigned num_dsts,
|
||||
rogue_ref dsts[num_dsts],
|
||||
unsigned num_srcs,
|
||||
rogue_ref srcs[num_srcs])
|
||||
{
|
||||
rogue_bitwise_instr *bitwise =
|
||||
rogue_bitwise_instr_create(rogue_cursor_block(b->cursor), op);
|
||||
|
||||
for (unsigned i = 0; i < num_dsts; ++i) {
|
||||
bitwise->dst[i].ref = dsts[i];
|
||||
bitwise->dst[i].index = i;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < num_srcs; ++i) {
|
||||
bitwise->src[i].ref = srcs[i];
|
||||
bitwise->src[i].index = i;
|
||||
}
|
||||
|
||||
rogue_builder_insert_instr(b, &bitwise->instr);
|
||||
return bitwise;
|
||||
}
|
||||
|
||||
static inline rogue_bitwise_instr *
|
||||
rogue_build_bitwise22(rogue_builder *b,
|
||||
enum rogue_bitwise_op op,
|
||||
rogue_ref dst0,
|
||||
rogue_ref dst1,
|
||||
rogue_ref src0,
|
||||
rogue_ref src1)
|
||||
{
|
||||
rogue_ref dsts[] = { dst0, dst1 };
|
||||
rogue_ref srcs[] = { src0, src1 };
|
||||
return rogue_build_bitwise(b, op, 2, dsts, 2, srcs);
|
||||
}
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_BITWISE22(op) \
|
||||
PUBLIC \
|
||||
rogue_bitwise_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst0, \
|
||||
rogue_ref dst1, \
|
||||
rogue_ref src0, \
|
||||
rogue_ref src1) \
|
||||
{ \
|
||||
assert(rogue_bitwise_op_infos[ROGUE_BITWISE_OP_##op].num_dsts == 2); \
|
||||
assert(rogue_bitwise_op_infos[ROGUE_BITWISE_OP_##op].num_srcs == 2); \
|
||||
return rogue_build_bitwise22(b, \
|
||||
ROGUE_BITWISE_OP_##op, \
|
||||
dst0, \
|
||||
dst1, \
|
||||
src0, \
|
||||
src1); \
|
||||
}
|
||||
|
||||
#include "rogue_bitwise_instrs.def"
|
||||
153
src/imagination/rogue/rogue_builder.h
Normal file
153
src/imagination/rogue/rogue_builder.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_BUILDER_H
|
||||
#define ROGUE_BUILDER_H
|
||||
|
||||
/**
|
||||
* \file rogue_builder.h
|
||||
*
|
||||
* \brief Contains helper functions for building Rogue shaders.
|
||||
*/
|
||||
|
||||
#include "rogue.h"
|
||||
|
||||
/** Rogue builder context. */
|
||||
typedef struct rogue_builder {
|
||||
rogue_shader *shader; /** The shader being built. */
|
||||
rogue_cursor cursor; /** The current position in the shader. */
|
||||
} rogue_builder;
|
||||
|
||||
/**
|
||||
* \brief Initialises a Rogue builder context.
|
||||
*
|
||||
* \param[in] b The builder context.
|
||||
* \param[in] shader The shader.
|
||||
*/
|
||||
static inline void rogue_builder_init(rogue_builder *b, rogue_shader *shader)
|
||||
{
|
||||
b->shader = shader;
|
||||
b->cursor = rogue_cursor_before_shader(shader);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Inserts a basic block at the current builder context position.
|
||||
*
|
||||
* \param[in] b The builder context.
|
||||
* \param[in] block The basic block to insert.
|
||||
*/
|
||||
static inline void rogue_builder_insert_block(rogue_builder *b,
|
||||
rogue_block *block)
|
||||
{
|
||||
rogue_block_insert(block, b->cursor);
|
||||
b->cursor = rogue_cursor_after_block(block);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Inserts a new basic block at the current builder context position.
|
||||
*
|
||||
* \param[in] b The builder context.
|
||||
* \param[in] label The (optional) basic block label.
|
||||
* \return The new block.
|
||||
*/
|
||||
static inline rogue_block *rogue_push_block_labelled(rogue_builder *b,
|
||||
const char *label)
|
||||
{
|
||||
rogue_block *block = rogue_block_create(b->shader, label);
|
||||
rogue_builder_insert_block(b, block);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Inserts a new basic block at the current builder context position.
|
||||
*
|
||||
* \param[in] b The builder context.
|
||||
* \return The new block.
|
||||
*/
|
||||
static inline rogue_block *rogue_push_block(rogue_builder *b)
|
||||
{
|
||||
return rogue_push_block_labelled(b, NULL);
|
||||
}
|
||||
|
||||
/* ALU instructions. */
|
||||
#define ROGUE_BUILDER_DEFINE_ALU1(op) \
|
||||
rogue_alu_instr *rogue_##op(rogue_builder *b, rogue_ref dst, rogue_ref src0);
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_ALU2(op) \
|
||||
rogue_alu_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst, \
|
||||
rogue_ref src0, \
|
||||
rogue_ref src1);
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_ALU3(op) \
|
||||
rogue_alu_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst, \
|
||||
rogue_ref src0, \
|
||||
rogue_ref src1, \
|
||||
rogue_ref src2);
|
||||
|
||||
#include "rogue_alu_instrs.def"
|
||||
|
||||
/* Backend instructions. */
|
||||
#define ROGUE_BUILDER_DEFINE_BACKEND00(op) \
|
||||
rogue_backend_instr *rogue_##op(rogue_builder *b);
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_BACKEND11(op) \
|
||||
rogue_backend_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst0, \
|
||||
rogue_ref src0);
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_BACKEND14(op) \
|
||||
rogue_backend_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst0, \
|
||||
rogue_ref src0, \
|
||||
rogue_ref src1, \
|
||||
rogue_ref src2, \
|
||||
rogue_ref src3);
|
||||
|
||||
#include "rogue_backend_instrs.def"
|
||||
|
||||
/* Ctrl instructions. */
|
||||
#define ROGUE_BUILDER_DEFINE_CTRLB(op) \
|
||||
rogue_ctrl_instr *rogue_##op(rogue_builder *b, rogue_block *block);
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_CTRL00(op) \
|
||||
rogue_ctrl_instr *rogue_##op(rogue_builder *b);
|
||||
|
||||
#define ROGUE_BUILDER_DEFINE_CTRL01(op) \
|
||||
rogue_ctrl_instr *rogue_##op(rogue_builder *b, rogue_ref src0);
|
||||
|
||||
#include "rogue_ctrl_instrs.def"
|
||||
|
||||
/* Bitwise instructions. */
|
||||
#define ROGUE_BUILDER_DEFINE_BITWISE22(op) \
|
||||
rogue_bitwise_instr *rogue_##op(rogue_builder *b, \
|
||||
rogue_ref dst0, \
|
||||
rogue_ref dst1, \
|
||||
rogue_ref src0, \
|
||||
rogue_ref src1);
|
||||
|
||||
#include "rogue_bitwise_instrs.def"
|
||||
|
||||
#endif /* ROGUE_BUILDER_H */
|
||||
403
src/imagination/rogue/rogue_compile.c
Normal file
403
src/imagination/rogue/rogue_compile.c
Normal file
|
|
@ -0,0 +1,403 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "compiler/spirv/nir_spirv.h"
|
||||
#include "nir/nir.h"
|
||||
#include "rogue.h"
|
||||
#include "rogue_builder.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
/**
|
||||
* \file rogue_compile.c
|
||||
*
|
||||
* \brief Contains NIR to Rogue translation functions, and Rogue passes.
|
||||
*/
|
||||
|
||||
static void trans_nir_jump_return(rogue_builder *b, nir_jump_instr *jump)
|
||||
{
|
||||
rogue_END(b);
|
||||
}
|
||||
|
||||
static void trans_nir_jump(rogue_builder *b, nir_jump_instr *jump)
|
||||
{
|
||||
switch (jump->type) {
|
||||
case nir_jump_return:
|
||||
return trans_nir_jump_return(b, jump);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unreachable("Unimplemented NIR jump instruction type.");
|
||||
}
|
||||
|
||||
static void trans_nir_intrinsic_load_input_fs(rogue_builder *b,
|
||||
nir_intrinsic_instr *intr)
|
||||
{
|
||||
struct rogue_fs_build_data *fs_data = &b->shader->ctx->stage_data.fs;
|
||||
|
||||
unsigned load_size = nir_dest_num_components(intr->dest);
|
||||
assert(load_size == 1); /* TODO: We can support larger load sizes. */
|
||||
|
||||
rogue_reg *dst = rogue_ssa_reg(b->shader, intr->dest.reg.reg->index);
|
||||
|
||||
struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr);
|
||||
unsigned component = nir_intrinsic_component(intr);
|
||||
unsigned coeff_index = rogue_coeff_index_fs(&fs_data->iterator_args,
|
||||
io_semantics.location,
|
||||
component);
|
||||
unsigned wcoeff_index = rogue_coeff_index_fs(&fs_data->iterator_args, ~0, 0);
|
||||
|
||||
rogue_regarray *coeffs = rogue_coeff_regarray(b->shader,
|
||||
ROGUE_COEFF_ALIGN * load_size,
|
||||
coeff_index);
|
||||
rogue_regarray *wcoeffs =
|
||||
rogue_coeff_regarray(b->shader, ROGUE_COEFF_ALIGN, wcoeff_index);
|
||||
|
||||
rogue_instr *instr = &rogue_FITRP_PIXEL(b,
|
||||
rogue_ref_reg(dst),
|
||||
rogue_ref_drc(0),
|
||||
rogue_ref_regarray(coeffs),
|
||||
rogue_ref_regarray(wcoeffs),
|
||||
rogue_ref_val(load_size))
|
||||
->instr;
|
||||
rogue_add_instr_comment(instr, "load_input_fs");
|
||||
}
|
||||
|
||||
static void trans_nir_intrinsic_load_input_vs(rogue_builder *b,
|
||||
nir_intrinsic_instr *intr)
|
||||
{
|
||||
ASSERTED unsigned load_size = nir_dest_num_components(intr->dest);
|
||||
assert(load_size == 1); /* TODO: We can support larger load sizes. */
|
||||
|
||||
rogue_reg *dst = rogue_ssa_reg(b->shader, intr->dest.reg.reg->index);
|
||||
|
||||
struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr);
|
||||
unsigned component = nir_intrinsic_component(intr);
|
||||
/* TODO: Get these properly with the intrinsic index (ssa argument) */
|
||||
unsigned vtxin_index =
|
||||
((io_semantics.location - VERT_ATTRIB_GENERIC0) * 3) + component;
|
||||
|
||||
rogue_reg *src = rogue_vtxin_reg(b->shader, vtxin_index);
|
||||
rogue_instr *instr =
|
||||
&rogue_MOV(b, rogue_ref_reg(dst), rogue_ref_reg(src))->instr;
|
||||
rogue_add_instr_comment(instr, "load_input_vs");
|
||||
}
|
||||
|
||||
static void trans_nir_intrinsic_load_input(rogue_builder *b,
|
||||
nir_intrinsic_instr *intr)
|
||||
{
|
||||
switch (b->shader->stage) {
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
return trans_nir_intrinsic_load_input_fs(b, intr);
|
||||
|
||||
case MESA_SHADER_VERTEX:
|
||||
return trans_nir_intrinsic_load_input_vs(b, intr);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unreachable("Unimplemented NIR load_input variant.");
|
||||
}
|
||||
|
||||
static void trans_nir_intrinsic_store_output_fs(rogue_builder *b,
|
||||
nir_intrinsic_instr *intr)
|
||||
{
|
||||
ASSERTED unsigned store_size = nir_src_num_components(intr->src[0]);
|
||||
assert(store_size == 1);
|
||||
|
||||
nir_const_value *const_value = nir_src_as_const_value(intr->src[1]);
|
||||
/* TODO: When hoisting I/O allocation to the driver, check if this is
|
||||
* correct.
|
||||
*/
|
||||
unsigned pixout_index = nir_const_value_as_uint(*const_value, 32);
|
||||
|
||||
rogue_reg *dst = rogue_pixout_reg(b->shader, pixout_index);
|
||||
rogue_reg *src = rogue_ssa_reg(b->shader, intr->src[0].reg.reg->index);
|
||||
|
||||
rogue_instr *instr =
|
||||
&rogue_MOV(b, rogue_ref_reg(dst), rogue_ref_reg(src))->instr;
|
||||
rogue_add_instr_comment(instr, "store_output_fs");
|
||||
}
|
||||
|
||||
static void trans_nir_intrinsic_store_output_vs(rogue_builder *b,
|
||||
nir_intrinsic_instr *intr)
|
||||
{
|
||||
struct rogue_vs_build_data *vs_data = &b->shader->ctx->stage_data.vs;
|
||||
|
||||
ASSERTED unsigned store_size = nir_src_num_components(intr->src[0]);
|
||||
assert(store_size == 1);
|
||||
|
||||
struct nir_io_semantics io_semantics = nir_intrinsic_io_semantics(intr);
|
||||
unsigned component = nir_intrinsic_component(intr);
|
||||
unsigned vtxout_index = rogue_output_index_vs(&vs_data->outputs,
|
||||
io_semantics.location,
|
||||
component);
|
||||
|
||||
rogue_reg *dst = rogue_vtxout_reg(b->shader, vtxout_index);
|
||||
rogue_reg *src = rogue_ssa_reg(b->shader, intr->src[0].reg.reg->index);
|
||||
|
||||
rogue_instr *instr =
|
||||
&rogue_MOV(b, rogue_ref_reg(dst), rogue_ref_reg(src))->instr;
|
||||
rogue_add_instr_comment(instr, "store_output_vs");
|
||||
}
|
||||
|
||||
static void trans_nir_intrinsic_store_output(rogue_builder *b,
|
||||
nir_intrinsic_instr *intr)
|
||||
{
|
||||
switch (b->shader->stage) {
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
return trans_nir_intrinsic_store_output_fs(b, intr);
|
||||
|
||||
case MESA_SHADER_VERTEX:
|
||||
return trans_nir_intrinsic_store_output_vs(b, intr);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unreachable("Unimplemented NIR store_output variant.");
|
||||
}
|
||||
|
||||
static void trans_nir_intrinsic_load_ubo(rogue_builder *b,
|
||||
nir_intrinsic_instr *intr)
|
||||
{
|
||||
struct rogue_ubo_data *ubo_data =
|
||||
&b->shader->ctx->common_data[b->shader->stage].ubo_data;
|
||||
|
||||
unsigned desc_set = nir_src_comp_as_uint(intr->src[0], 0);
|
||||
unsigned binding = nir_src_comp_as_uint(intr->src[0], 1);
|
||||
unsigned offset = nir_intrinsic_range_base(intr);
|
||||
|
||||
unsigned sh_index = rogue_ubo_reg(ubo_data, desc_set, binding, offset);
|
||||
|
||||
rogue_reg *dst = rogue_ssa_reg(b->shader, intr->dest.reg.reg->index);
|
||||
rogue_reg *src = rogue_shared_reg(b->shader, sh_index);
|
||||
rogue_instr *instr =
|
||||
&rogue_MOV(b, rogue_ref_reg(dst), rogue_ref_reg(src))->instr;
|
||||
rogue_add_instr_comment(instr, "load_ubo");
|
||||
}
|
||||
|
||||
static void trans_nir_intrinsic(rogue_builder *b, nir_intrinsic_instr *intr)
|
||||
{
|
||||
switch (intr->intrinsic) {
|
||||
case nir_intrinsic_load_input:
|
||||
return trans_nir_intrinsic_load_input(b, intr);
|
||||
|
||||
case nir_intrinsic_store_output:
|
||||
return trans_nir_intrinsic_store_output(b, intr);
|
||||
|
||||
case nir_intrinsic_load_ubo:
|
||||
return trans_nir_intrinsic_load_ubo(b, intr);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unreachable("Unimplemented NIR intrinsic instruction.");
|
||||
}
|
||||
|
||||
static void trans_nir_alu_pack_unorm_4x8(rogue_builder *b, nir_alu_instr *alu)
|
||||
{
|
||||
rogue_reg *dst = rogue_ssa_reg(b->shader, alu->dest.dest.reg.reg->index);
|
||||
rogue_regarray *src_array =
|
||||
rogue_ssa_vec_regarray(b->shader, 4, alu->src[0].src.reg.reg->index, 0);
|
||||
|
||||
rogue_alu_instr *pck_u8888 =
|
||||
rogue_PCK_U8888(b, rogue_ref_reg(dst), rogue_ref_regarray(src_array));
|
||||
rogue_set_instr_repeat(&pck_u8888->instr, 4);
|
||||
rogue_set_alu_op_mod(pck_u8888, ROGUE_ALU_OP_MOD_SCALE);
|
||||
}
|
||||
|
||||
static void trans_nir_alu_mov(rogue_builder *b, nir_alu_instr *alu)
|
||||
{
|
||||
rogue_reg *dst;
|
||||
|
||||
unsigned dst_index = alu->dest.dest.reg.reg->index;
|
||||
if (alu->dest.dest.reg.reg->num_components > 1) {
|
||||
assert(util_is_power_of_two_nonzero(alu->dest.write_mask));
|
||||
dst =
|
||||
rogue_ssa_vec_reg(b->shader, dst_index, ffs(alu->dest.write_mask) - 1);
|
||||
} else {
|
||||
dst = rogue_ssa_reg(b->shader, dst_index);
|
||||
}
|
||||
|
||||
if (alu->src[0].src.is_ssa) {
|
||||
/* Immediate/constant source. */
|
||||
nir_const_value *const_value = nir_src_as_const_value(alu->src[0].src);
|
||||
unsigned imm = nir_const_value_as_uint(*const_value, 32);
|
||||
rogue_MOV(b, rogue_ref_reg(dst), rogue_ref_imm(imm));
|
||||
} else {
|
||||
/* Register source. */
|
||||
rogue_reg *src = rogue_ssa_reg(b->shader, alu->src[0].src.reg.reg->index);
|
||||
rogue_MOV(b, rogue_ref_reg(dst), rogue_ref_reg(src));
|
||||
}
|
||||
}
|
||||
|
||||
static void trans_nir_alu_fmul(rogue_builder *b, nir_alu_instr *alu)
|
||||
{
|
||||
rogue_reg *dst = rogue_ssa_reg(b->shader, alu->dest.dest.reg.reg->index);
|
||||
rogue_reg *src0 = rogue_ssa_reg(b->shader, alu->src[0].src.reg.reg->index);
|
||||
rogue_reg *src1 = rogue_ssa_reg(b->shader, alu->src[1].src.reg.reg->index);
|
||||
|
||||
rogue_FMUL(b, rogue_ref_reg(dst), rogue_ref_reg(src0), rogue_ref_reg(src1));
|
||||
}
|
||||
|
||||
static void trans_nir_alu_ffma(rogue_builder *b, nir_alu_instr *alu)
|
||||
{
|
||||
rogue_reg *dst = rogue_ssa_reg(b->shader, alu->dest.dest.reg.reg->index);
|
||||
rogue_reg *src0 = rogue_ssa_reg(b->shader, alu->src[0].src.reg.reg->index);
|
||||
rogue_reg *src1 = rogue_ssa_reg(b->shader, alu->src[1].src.reg.reg->index);
|
||||
rogue_reg *src2 = rogue_ssa_reg(b->shader, alu->src[2].src.reg.reg->index);
|
||||
|
||||
rogue_FMAD(b,
|
||||
rogue_ref_reg(dst),
|
||||
rogue_ref_reg(src0),
|
||||
rogue_ref_reg(src1),
|
||||
rogue_ref_reg(src2));
|
||||
}
|
||||
|
||||
static void trans_nir_alu(rogue_builder *b, nir_alu_instr *alu)
|
||||
{
|
||||
switch (alu->op) {
|
||||
case nir_op_pack_unorm_4x8:
|
||||
return trans_nir_alu_pack_unorm_4x8(b, alu);
|
||||
return;
|
||||
|
||||
case nir_op_mov:
|
||||
return trans_nir_alu_mov(b, alu);
|
||||
|
||||
case nir_op_fmul:
|
||||
return trans_nir_alu_fmul(b, alu);
|
||||
|
||||
case nir_op_ffma:
|
||||
return trans_nir_alu_ffma(b, alu);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unreachable("Unimplemented NIR ALU instruction.");
|
||||
}
|
||||
|
||||
static inline void rogue_feedback_used_regs(rogue_build_ctx *ctx,
|
||||
const rogue_shader *shader)
|
||||
{
|
||||
/* TODO NEXT: Use this counting method elsewhere as well. */
|
||||
ctx->common_data[shader->stage].temps =
|
||||
__bitset_count(shader->regs_used[ROGUE_REG_CLASS_TEMP],
|
||||
BITSET_WORDS(rogue_reg_infos[ROGUE_REG_CLASS_TEMP].num));
|
||||
ctx->common_data[shader->stage].internals = __bitset_count(
|
||||
shader->regs_used[ROGUE_REG_CLASS_INTERNAL],
|
||||
BITSET_WORDS(rogue_reg_infos[ROGUE_REG_CLASS_INTERNAL].num));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Translates a NIR shader to Rogue.
|
||||
*
|
||||
* \param[in] ctx Shared multi-stage build context.
|
||||
* \param[in] nir NIR shader.
|
||||
* \return A rogue_shader* if successful, or NULL if unsuccessful.
|
||||
*/
|
||||
PUBLIC
|
||||
rogue_shader *rogue_nir_to_rogue(rogue_build_ctx *ctx, const nir_shader *nir)
|
||||
{
|
||||
gl_shader_stage stage = nir->info.stage;
|
||||
struct rogue_shader *shader = rogue_shader_create(ctx, stage);
|
||||
if (!shader)
|
||||
return NULL;
|
||||
|
||||
shader->ctx = ctx;
|
||||
|
||||
/* Make sure we only have a single function. */
|
||||
assert(exec_list_length(&nir->functions) == 1);
|
||||
|
||||
rogue_builder b;
|
||||
rogue_builder_init(&b, shader);
|
||||
|
||||
/* Translate shader entrypoint. */
|
||||
nir_function_impl *entry = nir_shader_get_entrypoint((nir_shader *)nir);
|
||||
nir_foreach_block (block, entry) {
|
||||
rogue_push_block(&b);
|
||||
|
||||
nir_foreach_instr (instr, block) {
|
||||
switch (instr->type) {
|
||||
case nir_instr_type_alu:
|
||||
trans_nir_alu(&b, nir_instr_as_alu(instr));
|
||||
break;
|
||||
|
||||
case nir_instr_type_intrinsic:
|
||||
trans_nir_intrinsic(&b, nir_instr_as_intrinsic(instr));
|
||||
break;
|
||||
|
||||
case nir_instr_type_load_const:
|
||||
/* trans_nir_load_const(&b, nir_instr_as_load_const(instr)); */
|
||||
break;
|
||||
|
||||
case nir_instr_type_jump:
|
||||
trans_nir_jump(&b, nir_instr_as_jump(instr));
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Unimplemented NIR instruction type.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply passes. */
|
||||
rogue_shader_passes(shader);
|
||||
|
||||
rogue_feedback_used_regs(ctx, shader);
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Performs Rogue passes on a shader.
|
||||
*
|
||||
* \param[in] shader The shader.
|
||||
*/
|
||||
PUBLIC
|
||||
void rogue_shader_passes(rogue_shader *shader)
|
||||
{
|
||||
rogue_validate_shader(shader, "before passes");
|
||||
|
||||
if (ROGUE_DEBUG(IR_PASSES))
|
||||
rogue_print_pass_debug(shader, "before passes", stdout);
|
||||
|
||||
/* Passes */
|
||||
ROGUE_PASS_V(shader, rogue_constreg);
|
||||
ROGUE_PASS_V(shader, rogue_copy_prop);
|
||||
ROGUE_PASS_V(shader, rogue_dce);
|
||||
ROGUE_PASS_V(shader, rogue_lower_pseudo_ops);
|
||||
ROGUE_PASS_V(shader, rogue_schedule_wdf, false);
|
||||
ROGUE_PASS_V(shader, rogue_schedule_uvsw, false);
|
||||
ROGUE_PASS_V(shader, rogue_trim);
|
||||
ROGUE_PASS_V(shader, rogue_regalloc);
|
||||
ROGUE_PASS_V(shader, rogue_dce);
|
||||
ROGUE_PASS_V(shader, rogue_schedule_instr_groups, false);
|
||||
|
||||
if (ROGUE_DEBUG(IR))
|
||||
rogue_print_pass_debug(shader, "after passes", stdout);
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 <stddef.h>
|
||||
|
||||
#include "compiler/glsl_types.h"
|
||||
#include "rogue_compiler.h"
|
||||
#include "util/ralloc.h"
|
||||
|
||||
/**
|
||||
* \file rogue_compiler.c
|
||||
*
|
||||
* \brief Contains the Rogue compiler interface.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Creates and sets up a Rogue compiler context.
|
||||
*
|
||||
* \param[in] dev_info Device info pointer.
|
||||
* \return A pointer to the new compiler context, or NULL on failure.
|
||||
*/
|
||||
struct rogue_compiler *
|
||||
rogue_compiler_create(const struct pvr_device_info *dev_info)
|
||||
{
|
||||
struct rogue_compiler *compiler;
|
||||
|
||||
compiler = rzalloc_size(NULL, sizeof(*compiler));
|
||||
if (!compiler)
|
||||
return NULL;
|
||||
|
||||
compiler->dev_info = dev_info;
|
||||
|
||||
/* TODO: Additional compiler setup (allocators? error message output
|
||||
* location?).
|
||||
*/
|
||||
|
||||
glsl_type_singleton_init_or_ref();
|
||||
|
||||
return compiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Destroys and frees a compiler context.
|
||||
*
|
||||
* \param[in] compiler The compiler context.
|
||||
*/
|
||||
void rogue_compiler_destroy(struct rogue_compiler *compiler)
|
||||
{
|
||||
glsl_type_singleton_decref();
|
||||
|
||||
ralloc_free(compiler);
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_COMPILER_H
|
||||
#define ROGUE_COMPILER_H
|
||||
|
||||
#include "util/macros.h"
|
||||
|
||||
struct pvr_device_info;
|
||||
|
||||
/**
|
||||
* \brief Compiler context.
|
||||
*/
|
||||
struct rogue_compiler {
|
||||
const struct pvr_device_info *dev_info;
|
||||
};
|
||||
|
||||
PUBLIC
|
||||
struct rogue_compiler *
|
||||
rogue_compiler_create(const struct pvr_device_info *dev_info);
|
||||
|
||||
PUBLIC
|
||||
void rogue_compiler_destroy(struct rogue_compiler *compiler);
|
||||
|
||||
#endif /* ROGUE_COMPILER_H */
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rogue_constreg.h"
|
||||
#include "rogue.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
/**
|
||||
|
|
@ -37,10 +37,10 @@
|
|||
/**
|
||||
* \brief Mapping of constant register values and their indices.
|
||||
*/
|
||||
struct rogue_constreg {
|
||||
typedef struct rogue_constreg_map {
|
||||
uint32_t value;
|
||||
size_t index;
|
||||
};
|
||||
unsigned index;
|
||||
} rogue_constreg_map;
|
||||
|
||||
#define CONSTREG(VALUE, INDEX) \
|
||||
{ \
|
||||
|
|
@ -50,7 +50,7 @@ struct rogue_constreg {
|
|||
/**
|
||||
* \brief Constant register values (sorted for bsearch).
|
||||
*/
|
||||
static const struct rogue_constreg const_regs[] = {
|
||||
static const rogue_constreg_map const_regs[] = {
|
||||
CONSTREG(0x00000000U, 0U), /* 0 (INT32) / 0.0 (Float) */
|
||||
CONSTREG(0x00000001U, 1U), /* 1 (INT32) */
|
||||
CONSTREG(0x00000002U, 2U), /* 2 (INT32) */
|
||||
|
|
@ -153,7 +153,7 @@ static const struct rogue_constreg const_regs[] = {
|
|||
#undef CONSTREG
|
||||
|
||||
/**
|
||||
* \brief Comparison function for bsearch() to support struct rogue_constreg.
|
||||
* \brief Comparison function for bsearch() to support rogue_constreg_map.
|
||||
*
|
||||
* \param[in] lhs The left hand side of the comparison.
|
||||
* \param[in] rhs The right hand side of the comparison.
|
||||
|
|
@ -161,8 +161,8 @@ static const struct rogue_constreg const_regs[] = {
|
|||
*/
|
||||
static int constreg_cmp(const void *lhs, const void *rhs)
|
||||
{
|
||||
const struct rogue_constreg *l = lhs;
|
||||
const struct rogue_constreg *r = rhs;
|
||||
const rogue_constreg_map *l = lhs;
|
||||
const rogue_constreg_map *r = rhs;
|
||||
|
||||
if (l->value < r->value)
|
||||
return -1;
|
||||
|
|
@ -173,24 +173,24 @@ static int constreg_cmp(const void *lhs, const void *rhs)
|
|||
}
|
||||
|
||||
/**
|
||||
* \brief Determines whether a given integer value exists in a constant
|
||||
* register.
|
||||
* \brief Determines whether a given value exists in a constant register.
|
||||
*
|
||||
* \param[in] value The value required.
|
||||
* \param[in] imm The immediate value required.
|
||||
* \return The index of the constant register containing the value, or
|
||||
* ROGUE_NO_CONST_REG if the value is not found.
|
||||
*/
|
||||
size_t rogue_constreg_lookup(uint32_t value)
|
||||
PUBLIC
|
||||
unsigned rogue_constreg_lookup(rogue_imm_t imm)
|
||||
{
|
||||
struct rogue_constreg constreg_target = {
|
||||
.value = value,
|
||||
rogue_constreg_map constreg_target = {
|
||||
.value = imm.u32,
|
||||
};
|
||||
const struct rogue_constreg *constreg;
|
||||
const rogue_constreg_map *constreg;
|
||||
|
||||
constreg = bsearch(&constreg_target,
|
||||
const_regs,
|
||||
ARRAY_SIZE(const_regs),
|
||||
sizeof(struct rogue_constreg),
|
||||
sizeof(rogue_constreg_map),
|
||||
constreg_cmp);
|
||||
if (!constreg)
|
||||
return ROGUE_NO_CONST_REG;
|
||||
|
|
|
|||
|
|
@ -21,50 +21,45 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_REGALLOC_H
|
||||
#define ROGUE_REGALLOC_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "util/list.h"
|
||||
|
||||
/**
|
||||
* \brief Register classes used for allocation.
|
||||
* \file rogue_ctrl_instrs.def
|
||||
*
|
||||
* \brief Contains macros defining control instructions.
|
||||
*/
|
||||
enum rogue_reg_class {
|
||||
ROGUE_REG_CLASS_TEMP,
|
||||
ROGUE_REG_CLASS_VEC4,
|
||||
|
||||
ROGUE_REG_CLASS_COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Register data for each class.
|
||||
/*
|
||||
* B - B: Block destination operand.
|
||||
* XY - X: Num destinations, Y: Num sources.
|
||||
*/
|
||||
struct rogue_reg_data {
|
||||
enum rogue_operand_type type;
|
||||
size_t count;
|
||||
size_t stride;
|
||||
|
||||
size_t offset;
|
||||
struct ra_class *class;
|
||||
size_t num_used;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Register allocation context.
|
||||
/*
|
||||
* ROGUE_BUILDER_DEFINE_CTRLB
|
||||
* B: Block destination operand.
|
||||
*
|
||||
* ROGUE_BUILDER_DEFINE_CTRLds
|
||||
* d: Number of destinations.
|
||||
* s: Number of sources.
|
||||
*/
|
||||
struct rogue_ra {
|
||||
struct ra_regs *regs;
|
||||
|
||||
struct rogue_reg_data reg_data[ROGUE_REG_CLASS_COUNT];
|
||||
};
|
||||
#ifndef ROGUE_BUILDER_DEFINE_CTRLB
|
||||
#define ROGUE_BUILDER_DEFINE_CTRLB(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_CTRLB */
|
||||
|
||||
struct rogue_ra *rogue_ra_init(void *mem_ctx);
|
||||
bool rogue_ra_alloc(struct list_head *instr_list,
|
||||
struct rogue_ra *ra,
|
||||
size_t *temps_used,
|
||||
size_t *internals_used);
|
||||
#ifndef ROGUE_BUILDER_DEFINE_CTRL00
|
||||
#define ROGUE_BUILDER_DEFINE_CTRL00(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_CTRL00 */
|
||||
|
||||
#endif /* ROGUE_REGALLOC_H */
|
||||
#ifndef ROGUE_BUILDER_DEFINE_CTRL01
|
||||
#define ROGUE_BUILDER_DEFINE_CTRL01(...)
|
||||
#endif /* ROGUE_BUILDER_DEFINE_CTRL01 */
|
||||
|
||||
ROGUE_BUILDER_DEFINE_CTRLB(BA)
|
||||
|
||||
ROGUE_BUILDER_DEFINE_CTRL00(END)
|
||||
ROGUE_BUILDER_DEFINE_CTRL00(NOP)
|
||||
|
||||
ROGUE_BUILDER_DEFINE_CTRL01(WDF)
|
||||
|
||||
#undef ROGUE_BUILDER_DEFINE_CTRL01
|
||||
#undef ROGUE_BUILDER_DEFINE_CTRL00
|
||||
#undef ROGUE_BUILDER_DEFINE_CTRLB
|
||||
85
src/imagination/rogue/rogue_debug.c
Normal file
85
src/imagination/rogue/rogue_debug.c
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "nir/nir.h"
|
||||
#include "rogue.h"
|
||||
#include "util/macros.h"
|
||||
#include "util/u_debug.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* \file rogue_debug.c
|
||||
*
|
||||
* \brief Contains debugging functions and data.
|
||||
*/
|
||||
|
||||
static const struct debug_named_value rogue_debug_options[] = {
|
||||
{ "nir", ROGUE_DEBUG_NIR, "Print NIR" },
|
||||
{ "nir_passes", ROGUE_DEBUG_NIR_PASSES, "Print NIR passes" },
|
||||
{ "ir", ROGUE_DEBUG_IR, "Print Rogue IR" },
|
||||
{ "ir_passes", ROGUE_DEBUG_IR_PASSES, "Print Rogue IR passes" },
|
||||
{ "ir_details",
|
||||
ROGUE_DEBUG_IR_DETAILS,
|
||||
"Print Rogue IR details (with ir/ir_passes enabled)" },
|
||||
{ "vld_skip", ROGUE_DEBUG_VLD_SKIP, "Skip Rogue IR validation" },
|
||||
{ "vld_nonfatal", ROGUE_DEBUG_VLD_NONFATAL, "Non-fatal Rogue IR validation" },
|
||||
DEBUG_NAMED_VALUE_END,
|
||||
};
|
||||
|
||||
#define ROGUE_DEBUG_DEFAULT 0U
|
||||
DEBUG_GET_ONCE_FLAGS_OPTION(rogue_debug,
|
||||
"ROGUE_DEBUG",
|
||||
rogue_debug_options,
|
||||
ROGUE_DEBUG_DEFAULT)
|
||||
|
||||
PUBLIC
|
||||
unsigned long rogue_debug = ROGUE_DEBUG_DEFAULT;
|
||||
|
||||
DEBUG_GET_ONCE_OPTION(rogue_color, "ROGUE_COLOR", NULL)
|
||||
|
||||
bool rogue_color = false;
|
||||
|
||||
static void rogue_debug_init_once(void)
|
||||
{
|
||||
/* Get debug flags. */
|
||||
rogue_debug = debug_get_option_rogue_debug();
|
||||
|
||||
/* Get/parse color option. */
|
||||
const char *color_opt = debug_get_option_rogue_color();
|
||||
if (!color_opt || !strcmp(color_opt, "auto") || !strcmp(color_opt, "a"))
|
||||
rogue_color = isatty(fileno(stdout));
|
||||
else if (!strcmp(color_opt, "on") || !strcmp(color_opt, "1"))
|
||||
rogue_color = true;
|
||||
else if (!strcmp(color_opt, "off") || !strcmp(color_opt, "0"))
|
||||
rogue_color = false;
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
void rogue_debug_init(void)
|
||||
{
|
||||
static once_flag flag = ONCE_FLAG_INIT;
|
||||
call_once(&flag, rogue_debug_init_once);
|
||||
}
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rogue_dump.h"
|
||||
#include "rogue_shader.h"
|
||||
#include "rogue_util.h"
|
||||
#include "util/bitscan.h"
|
||||
|
||||
/**
|
||||
* \file rogue_dump.c
|
||||
*
|
||||
* \brief Contains functions to dump Rogue data structures into a textual
|
||||
* format.
|
||||
*/
|
||||
|
||||
static const char *const rogue_operand_string[ROGUE_OPERAND_TYPE_COUNT] = {
|
||||
[ROGUE_OPERAND_TYPE_REG_TEMP] = "r",
|
||||
[ROGUE_OPERAND_TYPE_REG_COEFF] = "cf",
|
||||
[ROGUE_OPERAND_TYPE_REG_CONST] = "c",
|
||||
[ROGUE_OPERAND_TYPE_REG_SHARED] = "sh",
|
||||
[ROGUE_OPERAND_TYPE_REG_PIXEL_OUT] = "po",
|
||||
[ROGUE_OPERAND_TYPE_REG_VERTEX_IN] = "vi",
|
||||
[ROGUE_OPERAND_TYPE_REG_INTERNAL] = "i",
|
||||
[ROGUE_OPERAND_TYPE_IMMEDIATE] = "#",
|
||||
[ROGUE_OPERAND_TYPE_DRC] = "drc",
|
||||
[ROGUE_OPERAND_TYPE_VREG] = "V",
|
||||
};
|
||||
|
||||
static const char *const rogue_opcode_string[ROGUE_OP_COUNT] = {
|
||||
[ROGUE_OP_NOP] = "nop",
|
||||
[ROGUE_OP_END_FRAG] = "end.frag",
|
||||
[ROGUE_OP_END_VERT] = "end.vert",
|
||||
[ROGUE_OP_WDF] = "wdf",
|
||||
[ROGUE_OP_PIX_ITER_W] = "pixiter.w",
|
||||
[ROGUE_OP_MAX] = "max",
|
||||
[ROGUE_OP_MIN] = "min",
|
||||
[ROGUE_OP_PACK_U8888] = "pack.u8888",
|
||||
[ROGUE_OP_MOV] = "mov",
|
||||
[ROGUE_OP_MOV_IMM] = "mov.imm",
|
||||
[ROGUE_OP_FMA] = "fma",
|
||||
[ROGUE_OP_MUL] = "mul",
|
||||
[ROGUE_OP_VTXOUT] = "vtxout",
|
||||
};
|
||||
|
||||
static const char *const rogue_instr_flag_string[ROGUE_INSTR_FLAG_COUNT] = {
|
||||
[ROGUE_INSTR_FLAG_SAT] = "sat",
|
||||
[ROGUE_INSTR_FLAG_LP] = "lp",
|
||||
[ROGUE_INSTR_FLAG_OLCHK] = "olchk",
|
||||
};
|
||||
|
||||
static const char rogue_vector_string[4] = {
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
'w',
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Dumps an operand as text to a file pointer.
|
||||
*
|
||||
* \param[in] operand The operand.
|
||||
* \param[in] fp The file pointer.
|
||||
* \return true if successful, otherwise false.
|
||||
*/
|
||||
bool rogue_dump_operand(const struct rogue_operand *operand, FILE *fp)
|
||||
{
|
||||
ASSERT_OPERAND_RANGE(operand->type);
|
||||
|
||||
fprintf(fp, "%s", rogue_operand_string[operand->type]);
|
||||
|
||||
if (operand->type == ROGUE_OPERAND_TYPE_IMMEDIATE)
|
||||
fprintf(fp, "%" PRIu64, operand->immediate.value);
|
||||
else if (operand->type == ROGUE_OPERAND_TYPE_DRC)
|
||||
fprintf(fp, "%zu", operand->drc.number);
|
||||
else if (rogue_check_bitset(rogue_onehot(operand->type), ROGUE_MASK_ANY_REG))
|
||||
fprintf(fp, "%zu", operand->reg.number);
|
||||
else if (operand->type == ROGUE_OPERAND_TYPE_VREG) {
|
||||
fprintf(fp, "%zu", operand->vreg.number);
|
||||
if (operand->vreg.is_vector)
|
||||
fprintf(fp, ".%c", rogue_vector_string[operand->vreg.component]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Dumps an instruction as text to a file pointer.
|
||||
*
|
||||
* \param[in] instr The instruction.
|
||||
* \param[in] fp The file pointer.
|
||||
* \return true if successful, otherwise false.
|
||||
*/
|
||||
bool rogue_dump_instr(const struct rogue_instr *instr, FILE *fp)
|
||||
{
|
||||
uint64_t flags = 0U;
|
||||
|
||||
ASSERT_OPCODE_RANGE(instr->opcode);
|
||||
|
||||
flags = instr->flags;
|
||||
|
||||
fprintf(fp, "%s", rogue_opcode_string[instr->opcode]);
|
||||
|
||||
/* Iterate over each flag bit and print its string form. */
|
||||
while (flags) {
|
||||
uint64_t flag = u_bit_scan64(&flags);
|
||||
ASSERT_INSTR_FLAG_RANGE(flag);
|
||||
fprintf(fp, ".%s", rogue_instr_flag_string[flag]);
|
||||
}
|
||||
|
||||
if (instr->num_operands)
|
||||
fprintf(fp, " ");
|
||||
|
||||
/* Dump each operand. */
|
||||
for (size_t u = 0U; u < instr->num_operands; ++u) {
|
||||
CHECKF(rogue_dump_operand(&instr->operands[u], fp),
|
||||
"Failed to dump operand.");
|
||||
if (u < (instr->num_operands - 1))
|
||||
fprintf(fp, ", ");
|
||||
}
|
||||
|
||||
fprintf(fp, ";");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Dumps a shader as text to a file pointer.
|
||||
*
|
||||
* \param[in] shader The shader.
|
||||
* \param[in] fp The file pointer.
|
||||
* \return true if successful, otherwise false.
|
||||
*/
|
||||
bool rogue_dump_shader(const struct rogue_shader *shader, FILE *fp)
|
||||
{
|
||||
/* Dump the shader stage. */
|
||||
fprintf(fp, "# %s shader\n", _mesa_shader_stage_to_string(shader->stage));
|
||||
|
||||
/* Dump each instruction. */
|
||||
foreach_instr (instr, &shader->instr_list) {
|
||||
CHECKF(rogue_dump_instr(instr, fp), "Failed to dump instruction.");
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
fprintf(fp, "\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_ENCODE_H
|
||||
#define ROGUE_ENCODE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "util/macros.h"
|
||||
|
||||
struct rogue_instr;
|
||||
struct rogue_shader;
|
||||
|
||||
PUBLIC
|
||||
bool rogue_encode_instr(const struct rogue_instr *instr, FILE *fp);
|
||||
|
||||
PUBLIC
|
||||
bool rogue_encode_shader(const struct rogue_shader *shader, FILE *fp);
|
||||
|
||||
#endif /* ROGUE_ENCODE_H */
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rogue_encoders.h"
|
||||
#include "rogue_util.h"
|
||||
#include "util/bitscan.h"
|
||||
|
||||
/**
|
||||
* \brief Passes the input value through unchanged.
|
||||
*
|
||||
* \param[in] value Pointer to the destination value.
|
||||
* \param[in] inputs Number of inputs provided.
|
||||
* \param[in] ... Input value(s).
|
||||
* \return true if encoding was successful.
|
||||
*/
|
||||
bool rogue_encoder_pass(uint64_t *value, size_t inputs, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
assert(inputs == 1);
|
||||
|
||||
va_start(args, inputs);
|
||||
*value = va_arg(args, uint64_t);
|
||||
va_end(args);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Encoder for DRC values.
|
||||
*
|
||||
* \sa #rogue_encoder_pass()
|
||||
*
|
||||
* \param[in] value Pointer to the destination value.
|
||||
* \param[in] inputs Number of inputs provided.
|
||||
* \param[in] ... Input value(s).
|
||||
* \return true if encoding was successful.
|
||||
*/
|
||||
bool rogue_encoder_drc(uint64_t *value, size_t inputs, ...)
|
||||
__attribute__((alias("rogue_encoder_pass")));
|
||||
|
||||
/**
|
||||
* \brief Encoder for immediate values.
|
||||
*
|
||||
* \sa #rogue_encoder_pass()
|
||||
*
|
||||
* \param[in] value Pointer to the destination value.
|
||||
* \param[in] inputs Number of inputs provided.
|
||||
* \param[in] ... Input value(s).
|
||||
* \return true if encoding was successful.
|
||||
*/
|
||||
bool rogue_encoder_imm(uint64_t *value, size_t inputs, ...)
|
||||
__attribute__((alias("rogue_encoder_pass")));
|
||||
|
||||
/**
|
||||
* \brief Encodes input ranges {1..15 -> 1-15} and {16 -> 0}.
|
||||
*
|
||||
* The input should be in the range 1-16; the function represents 1-15 normally
|
||||
* and represents 16 by 0.
|
||||
*
|
||||
* \param[in] value Pointer to the destination value.
|
||||
* \param[in] inputs Number of inputs provided.
|
||||
* \param[in] ... Input value(s).
|
||||
* \return true if encoding was successful.
|
||||
*/
|
||||
bool rogue_encoder_ls_1_16(uint64_t *value, size_t inputs, ...)
|
||||
{
|
||||
va_list args;
|
||||
uint64_t input;
|
||||
|
||||
assert(inputs == 1);
|
||||
|
||||
va_start(args, inputs);
|
||||
input = va_arg(args, uint64_t);
|
||||
va_end(args);
|
||||
|
||||
/* Validate the input range. */
|
||||
if (!input || input > 16) {
|
||||
*value = UINT64_MAX;
|
||||
return false;
|
||||
}
|
||||
|
||||
*value = input % 16;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Encodes registers according to the number of bits needed to specify
|
||||
* the bank number and register number.
|
||||
*
|
||||
* \param[in] value Pointer to the destination value.
|
||||
* \param[in] bank_bits The number of bits used to represent the register bank.
|
||||
* \param[in] bank the register bank
|
||||
* \param[in] num_bits The number of bits used to represent the register number.
|
||||
* \param[in] num The register number.
|
||||
* \return true if encoding was successful.
|
||||
*/
|
||||
static bool rogue_encoder_reg(uint64_t *value,
|
||||
size_t bank_bits,
|
||||
size_t bank,
|
||||
size_t num_bits,
|
||||
size_t num)
|
||||
{
|
||||
/* Verify "num" fits in "num_bits" and "bank" fits in "bank_bits". */
|
||||
assert(util_last_bit64(num) <= num_bits);
|
||||
assert(util_last_bit64(bank) <= bank_bits);
|
||||
|
||||
*value = num;
|
||||
*value |= (bank << num_bits);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Macro to define the rogue_encoder_reg variants.
|
||||
*/
|
||||
#define ROGUE_ENCODER_REG_VARIANT(bank_bits, num_bits) \
|
||||
bool rogue_encoder_reg_##bank_bits##_##num_bits(uint64_t *value, \
|
||||
size_t inputs, \
|
||||
...) \
|
||||
{ \
|
||||
va_list args; \
|
||||
size_t bank; \
|
||||
size_t num; \
|
||||
assert(inputs == 2); \
|
||||
va_start(args, inputs); \
|
||||
bank = va_arg(args, size_t); \
|
||||
num = va_arg(args, size_t); \
|
||||
va_end(args); \
|
||||
return rogue_encoder_reg(value, bank_bits, bank, num_bits, num); \
|
||||
}
|
||||
|
||||
ROGUE_ENCODER_REG_VARIANT(2, 8)
|
||||
ROGUE_ENCODER_REG_VARIANT(3, 8)
|
||||
ROGUE_ENCODER_REG_VARIANT(3, 11)
|
||||
|
||||
#undef ROGUE_ENCODER_REG_VARIANT
|
||||
443
src/imagination/rogue/rogue_info.c
Normal file
443
src/imagination/rogue/rogue_info.c
Normal file
|
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "rogue.h"
|
||||
|
||||
/**
|
||||
* \file rogue_info.c
|
||||
*
|
||||
* \brief Contains information and definitions for defined types and structures.
|
||||
*/
|
||||
|
||||
/* TODO: Adjust according to core configurations. */
|
||||
/* TODO: Remaining restrictions, e.g. some registers are only
|
||||
* usable by a particular instruction (vertex output) etc. */
|
||||
#define S(n) BITFIELD64_BIT(ROGUE_IO_S##n - 1)
|
||||
const rogue_reg_info rogue_reg_infos[ROGUE_REG_CLASS_COUNT] = {
|
||||
[ROGUE_REG_CLASS_INVALID] = { .name = "!INVALID!", .str = "!INVALID!", },
|
||||
[ROGUE_REG_CLASS_SSA] = { .name = "ssa", .str = "R", },
|
||||
[ROGUE_REG_CLASS_TEMP] = { .name = "temp", .str = "r", .num = 248, },
|
||||
[ROGUE_REG_CLASS_COEFF] = { .name = "coeff", .str = "cf", .num = 4096, .supported_io_srcs = S(0) | S(2) | S(3), },
|
||||
[ROGUE_REG_CLASS_SHARED] = { .name = "shared", .str = "sh", .num = 4096, .supported_io_srcs = S(0) | S(2) | S(3), },
|
||||
[ROGUE_REG_CLASS_SPECIAL] = { .name = "special", .str = "sr", .num = 240, }, /* TODO NEXT: Only S1, S2, S4. */
|
||||
[ROGUE_REG_CLASS_INTERNAL] = { .name = "internal", .str = "i", .num = 8, },
|
||||
[ROGUE_REG_CLASS_CONST] = { .name = "const", .str = "sc", .num = 240, },
|
||||
[ROGUE_REG_CLASS_PIXOUT] = { .name = "pixout", .str = "po", .num = 8, .supported_io_srcs = S(0) | S(2) | S(3), },
|
||||
[ROGUE_REG_CLASS_VTXIN] = { .name = "vtxin", .str = "vi", .num = 248, },
|
||||
[ROGUE_REG_CLASS_VTXOUT] = { .name = "vtxout", .str = "vo", .num = 256, },
|
||||
};
|
||||
#undef S
|
||||
|
||||
const rogue_regalloc_info regalloc_info[ROGUE_REGALLOC_CLASS_COUNT] = {
|
||||
[ROGUE_REGALLOC_CLASS_TEMP_1] = { .class = ROGUE_REG_CLASS_TEMP, .stride = 1, },
|
||||
[ROGUE_REGALLOC_CLASS_TEMP_4] = { .class = ROGUE_REG_CLASS_TEMP, .stride = 4, },
|
||||
};
|
||||
|
||||
const rogue_reg_dst_info rogue_reg_dst_infos[ROGUE_REG_DST_VARIANTS] = {
|
||||
{
|
||||
.num_dsts = 1,
|
||||
.bank_bits = { 1 },
|
||||
.index_bits = { 6 },
|
||||
.bytes = 1,
|
||||
},
|
||||
{
|
||||
.num_dsts = 1,
|
||||
.bank_bits = { 3 },
|
||||
.index_bits = { 11 },
|
||||
.bytes = 2,
|
||||
},
|
||||
{
|
||||
.num_dsts = 2,
|
||||
.bank_bits = { 1, 1 },
|
||||
.index_bits = { 7, 6 },
|
||||
.bytes = 2,
|
||||
},
|
||||
{
|
||||
.num_dsts = 2,
|
||||
.bank_bits = { 3, 3 },
|
||||
.index_bits = { 8, 8 },
|
||||
.bytes = 3,
|
||||
},
|
||||
{
|
||||
.num_dsts = 2,
|
||||
.bank_bits = { 3, 3 },
|
||||
.index_bits = { 11, 11 },
|
||||
.bytes = 4,
|
||||
},
|
||||
};
|
||||
|
||||
const rogue_reg_src_info rogue_reg_lower_src_infos[ROGUE_REG_SRC_VARIANTS] = {
|
||||
{
|
||||
.num_srcs = 1,
|
||||
.mux_bits = 0,
|
||||
.bank_bits = { 1 },
|
||||
.index_bits = { 6 },
|
||||
.bytes = 1,
|
||||
},
|
||||
{
|
||||
.num_srcs = 1,
|
||||
.mux_bits = 2,
|
||||
.bank_bits = { 3 },
|
||||
.index_bits = { 11 },
|
||||
.bytes = 3,
|
||||
},
|
||||
{
|
||||
.num_srcs = 2,
|
||||
.mux_bits = 0,
|
||||
.bank_bits = { 1, 1 },
|
||||
.index_bits = { 6, 5 },
|
||||
.bytes = 2,
|
||||
},
|
||||
{
|
||||
.num_srcs = 2,
|
||||
.mux_bits = 2,
|
||||
.bank_bits = { 2, 2 },
|
||||
.index_bits = { 7, 7 },
|
||||
.bytes = 3,
|
||||
},
|
||||
{
|
||||
.num_srcs = 2,
|
||||
.mux_bits = 3,
|
||||
.bank_bits = { 3, 2 },
|
||||
.index_bits = { 11, 8 },
|
||||
.bytes = 4,
|
||||
},
|
||||
{
|
||||
.num_srcs = 3,
|
||||
.mux_bits = 2,
|
||||
.bank_bits = { 2, 2, 2 },
|
||||
.index_bits = { 7, 7, 6 },
|
||||
.bytes = 4,
|
||||
},
|
||||
{
|
||||
.num_srcs = 3,
|
||||
.mux_bits = 3,
|
||||
.bank_bits = { 3, 2, 3 },
|
||||
.index_bits = { 8, 8, 8 },
|
||||
.bytes = 5,
|
||||
},
|
||||
{
|
||||
.num_srcs = 3,
|
||||
.mux_bits = 3,
|
||||
.bank_bits = { 3, 2, 3 },
|
||||
.index_bits = { 11, 8, 11 },
|
||||
.bytes = 6,
|
||||
},
|
||||
};
|
||||
|
||||
const rogue_reg_src_info rogue_reg_upper_src_infos[ROGUE_REG_SRC_VARIANTS] = {
|
||||
{
|
||||
.num_srcs = 1,
|
||||
.bank_bits = { 1 },
|
||||
.index_bits = { 6 },
|
||||
.bytes = 1,
|
||||
},
|
||||
{
|
||||
.num_srcs = 1,
|
||||
.bank_bits = { 3 },
|
||||
.index_bits = { 11 },
|
||||
.bytes = 3,
|
||||
},
|
||||
{
|
||||
.num_srcs = 2,
|
||||
.bank_bits = { 1, 1 },
|
||||
.index_bits = { 6, 5 },
|
||||
.bytes = 2,
|
||||
},
|
||||
{
|
||||
.num_srcs = 2,
|
||||
.bank_bits = { 2, 2 },
|
||||
.index_bits = { 7, 7 },
|
||||
.bytes = 3,
|
||||
},
|
||||
{
|
||||
.num_srcs = 2,
|
||||
.bank_bits = { 3, 2 },
|
||||
.index_bits = { 11, 8 },
|
||||
.bytes = 4,
|
||||
},
|
||||
{
|
||||
.num_srcs = 3,
|
||||
.bank_bits = { 2, 2, 2 },
|
||||
.index_bits = { 7, 7, 6 },
|
||||
.bytes = 4,
|
||||
},
|
||||
{
|
||||
.num_srcs = 3,
|
||||
.bank_bits = { 3, 2, 2 },
|
||||
.index_bits = { 8, 8, 8 },
|
||||
.bytes = 5,
|
||||
},
|
||||
{
|
||||
.num_srcs = 3,
|
||||
.bank_bits = { 3, 2, 2 },
|
||||
.index_bits = { 11, 8, 8 },
|
||||
.bytes = 6,
|
||||
},
|
||||
};
|
||||
|
||||
const rogue_alu_op_mod_info rogue_alu_op_mod_infos[ROGUE_ALU_OP_MOD_COUNT] = {
|
||||
[ROGUE_ALU_OP_MOD_LP] = { .str = "lp", },
|
||||
[ROGUE_ALU_OP_MOD_SAT] = { .str = "sat", },
|
||||
[ROGUE_ALU_OP_MOD_SCALE] = { .str = "scale", },
|
||||
[ROGUE_ALU_OP_MOD_ROUNDZERO] = { .str = "roundzero", },
|
||||
};
|
||||
|
||||
const rogue_alu_dst_mod_info rogue_alu_dst_mod_infos[ROGUE_ALU_DST_MOD_COUNT] = {
|
||||
[ROGUE_ALU_DST_MOD_E0] = { .str = "e0", },
|
||||
[ROGUE_ALU_DST_MOD_E1] = { .str = "e1", },
|
||||
[ROGUE_ALU_DST_MOD_E2] = { .str = "e2", },
|
||||
[ROGUE_ALU_DST_MOD_E3] = { .str = "e3", },
|
||||
};
|
||||
|
||||
const rogue_alu_src_mod_info rogue_alu_src_mod_infos[ROGUE_ALU_SRC_MOD_COUNT] = {
|
||||
[ROGUE_ALU_SRC_MOD_FLR] = { .str = "flr", },
|
||||
[ROGUE_ALU_SRC_MOD_ABS] = { .str = "abs", },
|
||||
[ROGUE_ALU_SRC_MOD_NEG] = { .str = "neg", },
|
||||
};
|
||||
|
||||
const rogue_ctrl_op_mod_info rogue_ctrl_op_mod_infos[ROGUE_CTRL_OP_MOD_COUNT] = {
|
||||
[ROGUE_CTRL_OP_MOD_END] = { .str = "end", },
|
||||
};
|
||||
|
||||
#define OM(op_mod) BITFIELD64_BIT(ROGUE_CTRL_OP_MOD_##op_mod)
|
||||
const rogue_ctrl_op_info rogue_ctrl_op_infos[ROGUE_CTRL_OP_COUNT] = {
|
||||
[ROGUE_CTRL_OP_INVALID] = { .str = "!INVALID!", },
|
||||
[ROGUE_CTRL_OP_END] = { .str = "end", .ends_block = true, },
|
||||
[ROGUE_CTRL_OP_NOP] = { .str = "nop",
|
||||
.supported_op_mods = OM(END),
|
||||
},
|
||||
[ROGUE_CTRL_OP_BA] = { .str = "ba", .has_target = true, .ends_block = true, },
|
||||
[ROGUE_CTRL_OP_WDF] = { .str = "wdf", .num_srcs = 1, },
|
||||
};
|
||||
#undef OM
|
||||
|
||||
#define IO(io) ROGUE_IO_##io
|
||||
#define OM(op_mod) BITFIELD64_BIT(ROGUE_BACKEND_OP_MOD_##op_mod)
|
||||
const rogue_backend_op_info rogue_backend_op_infos[ROGUE_BACKEND_OP_COUNT] = {
|
||||
[ROGUE_BACKEND_OP_INVALID] = { .str = "!INVALID!", },
|
||||
[ROGUE_BACKEND_OP_UVSW_WRITE] = { .str = "uvsw.write", .num_dsts = 1, .num_srcs = 1,
|
||||
.phase_io = { .src[0] = IO(W0), },
|
||||
},
|
||||
[ROGUE_BACKEND_OP_UVSW_EMIT] = { .str = "uvsw.emit", },
|
||||
[ROGUE_BACKEND_OP_UVSW_ENDTASK] = { .str = "uvsw.endtask", },
|
||||
|
||||
[ROGUE_BACKEND_OP_UVSW_EMITTHENENDTASK] = { .str = "uvsw.emitthenendtask", },
|
||||
[ROGUE_BACKEND_OP_UVSW_WRITETHENEMITTHENENDTASK] = { .str = "uvsw.writethenemitthenendtask", .num_dsts = 1, .num_srcs = 1,
|
||||
.phase_io = { .src[0] = IO(W0), },
|
||||
},
|
||||
[ROGUE_BACKEND_OP_FITRP_PIXEL] = { .str = "fitrp.pixel", .num_dsts = 1, .num_srcs = 4,
|
||||
.phase_io = { .dst[0] = IO(S3), .src[1] = IO(S0), .src[2] = IO(S2), },
|
||||
.supported_op_mods = OM(SAT),
|
||||
},
|
||||
};
|
||||
#undef OM
|
||||
#undef IO
|
||||
|
||||
const rogue_backend_op_mod_info rogue_backend_op_mod_infos[ROGUE_BACKEND_OP_MOD_COUNT] = {
|
||||
[ROGUE_BACKEND_OP_MOD_SAT] = { .str = "sat", },
|
||||
};
|
||||
|
||||
const rogue_bitwise_op_info rogue_bitwise_op_infos[ROGUE_BITWISE_OP_COUNT] = {
|
||||
[ROGUE_BITWISE_OP_INVALID] = { .str = "", },
|
||||
[ROGUE_BITWISE_OP_BYP] = { .str = "byp", .num_dsts = 2, .num_srcs = 2, },
|
||||
[ROGUE_BITWISE_OP_MOV2] = { .str = "mov2", .num_dsts = 2, .num_srcs = 2, },
|
||||
};
|
||||
|
||||
const rogue_io_info rogue_io_infos[ROGUE_IO_COUNT] = {
|
||||
[ROGUE_IO_INVALID] = { .str = "!INVALID!", },
|
||||
[ROGUE_IO_S0] = { .str = "s0", },
|
||||
[ROGUE_IO_S1] = { .str = "s1", },
|
||||
[ROGUE_IO_S2] = { .str = "s2", },
|
||||
[ROGUE_IO_S3] = { .str = "s3", },
|
||||
[ROGUE_IO_S4] = { .str = "s4", },
|
||||
[ROGUE_IO_S5] = { .str = "s5", },
|
||||
[ROGUE_IO_W0] = { .str = "w0", },
|
||||
[ROGUE_IO_W1] = { .str = "w1", },
|
||||
[ROGUE_IO_IS0] = { .str = "is0", },
|
||||
[ROGUE_IO_IS1] = { .str = "is1", },
|
||||
[ROGUE_IO_IS2] = { .str = "is2", },
|
||||
[ROGUE_IO_IS3] = { .str = "is3", },
|
||||
[ROGUE_IO_IS4] = { .str = "is4/w0", },
|
||||
[ROGUE_IO_IS5] = { .str = "is5/w1", },
|
||||
[ROGUE_IO_FT0] = { .str = "ft0", },
|
||||
[ROGUE_IO_FT1] = { .str = "ft1", },
|
||||
[ROGUE_IO_FT2] = { .str = "ft2", },
|
||||
[ROGUE_IO_FTE] = { .str = "fte", },
|
||||
[ROGUE_IO_FT3] = { .str = "ft3", },
|
||||
[ROGUE_IO_FT4] = { .str = "ft4", },
|
||||
[ROGUE_IO_FT5] = { .str = "ft5", },
|
||||
[ROGUE_IO_P0] = { .str = "p0", },
|
||||
};
|
||||
|
||||
#define SM(src_mod) BITFIELD64_BIT(ROGUE_ALU_SRC_MOD_##src_mod)
|
||||
#define DM(dst_mod) BITFIELD64_BIT(ROGUE_ALU_DST_MOD_##dst_mod)
|
||||
#define OM(op_mod) BITFIELD64_BIT(ROGUE_ALU_OP_MOD_##op_mod)
|
||||
#define P(type) BITFIELD64_BIT(ROGUE_INSTR_PHASE_##type)
|
||||
#define PH(type) ROGUE_INSTR_PHASE_##type
|
||||
#define IO(io) ROGUE_IO_##io
|
||||
#define T(type) BITFIELD64_BIT(ROGUE_REF_TYPE_##type - 1)
|
||||
const rogue_alu_op_info rogue_alu_op_infos[ROGUE_ALU_OP_COUNT] = {
|
||||
[ROGUE_ALU_OP_INVALID] = { .str = "!INVALID!", },
|
||||
[ROGUE_ALU_OP_MBYP] = { .str = "mbyp", .num_srcs = 1,
|
||||
.supported_phases = P(0),
|
||||
.phase_io[PH(0)] = { .dst = IO(FT0), .src[0] = IO(S0), },
|
||||
.supported_src_mods = {
|
||||
[0] = SM(ABS) | SM(NEG),
|
||||
},
|
||||
.supported_dst_types = T(REG),
|
||||
.supported_src_types = {
|
||||
[0] = T(REG),
|
||||
},
|
||||
},
|
||||
[ROGUE_ALU_OP_FADD] = { .str = "fadd", .num_srcs = 2,
|
||||
.supported_phases = P(0),
|
||||
.phase_io[PH(0)] = { .dst = IO(FT0), .src[0] = IO(S0), .src[1] = IO(S1), },
|
||||
.supported_op_mods = OM(LP) | OM(SAT),
|
||||
.supported_src_mods = {
|
||||
[0] = SM(FLR) | SM(ABS) | SM(NEG),
|
||||
[1] = SM(ABS),
|
||||
},
|
||||
},
|
||||
[ROGUE_ALU_OP_FMUL] = { .str = "fmul", .num_srcs = 2,
|
||||
.supported_phases = P(0),
|
||||
.phase_io[PH(0)] = { .dst = IO(FT0), .src[0] = IO(S0), .src[1] = IO(S1), },
|
||||
.supported_op_mods = OM(LP) | OM(SAT),
|
||||
.supported_src_mods = {
|
||||
[0] = SM(FLR) | SM(ABS) | SM(NEG),
|
||||
[1] = SM(ABS),
|
||||
},
|
||||
.supported_dst_types = T(REG),
|
||||
.supported_src_types = {
|
||||
[0] = T(REG),
|
||||
[1] = T(REG),
|
||||
},
|
||||
},
|
||||
[ROGUE_ALU_OP_FMAD] = { .str = "fmad", .num_srcs = 3,
|
||||
.supported_phases = P(0),
|
||||
.phase_io[PH(0)] = { .dst = IO(FT0), .src[0] = IO(S0), .src[1] = IO(S1), .src[2] = IO(S2), },
|
||||
.supported_op_mods = OM(LP) | OM(SAT),
|
||||
.supported_src_mods = {
|
||||
[0] = SM(ABS) | SM(NEG),
|
||||
[1] = SM(ABS) | SM(NEG),
|
||||
[2] = SM(FLR) | SM(ABS) | SM(NEG),
|
||||
},
|
||||
.supported_dst_types = T(REG),
|
||||
.supported_src_types = {
|
||||
[0] = T(REG),
|
||||
[1] = T(REG),
|
||||
[2] = T(REG),
|
||||
},
|
||||
},
|
||||
/* TODO: Implement */
|
||||
[ROGUE_ALU_OP_TST] = { .str = "tst", .num_srcs = 2, },
|
||||
[ROGUE_ALU_OP_PCK_U8888] = { .str = "pck.u8888", .num_srcs = 1,
|
||||
.supported_phases = P(2_PCK),
|
||||
.phase_io[PH(2_PCK)] = { .dst = IO(FT2), .src[0] = IO(IS3), },
|
||||
.supported_op_mods = OM(SCALE) | OM(ROUNDZERO),
|
||||
.supported_dst_types = T(REG),
|
||||
.supported_src_types = {
|
||||
[0] = T(REGARRAY),
|
||||
},
|
||||
},
|
||||
/* This mov is "fake" since it can be lowered to a MBYP, make a new instruction for real mov (call it MOVD?). */
|
||||
[ROGUE_ALU_OP_MOV] = { .str = "mov", .num_srcs = 1,
|
||||
.supported_dst_types = T(REG),
|
||||
.supported_src_types = {
|
||||
[0] = T(REG) | T(IMM),
|
||||
},
|
||||
},
|
||||
[ROGUE_ALU_OP_FABS] = { .str = "fabs", .num_srcs = 1, },
|
||||
[ROGUE_ALU_OP_FNEG] = { .str = "fneg", .num_srcs = 1, },
|
||||
[ROGUE_ALU_OP_FNABS] = { .str = "fnabs", .num_srcs = 1, },
|
||||
|
||||
[ROGUE_ALU_OP_FMAX] = { .str = "fmax", .num_srcs = 2, }, /* TODO */
|
||||
[ROGUE_ALU_OP_FMIN] = { .str = "fmin", .num_srcs = 2, }, /* TODO */
|
||||
[ROGUE_ALU_OP_SEL] = { .str = "sel", .num_srcs = 3, }, /* TODO */
|
||||
};
|
||||
#undef T
|
||||
#undef IO
|
||||
#undef PH
|
||||
#undef P
|
||||
#undef OM
|
||||
#undef DM
|
||||
#undef SM
|
||||
|
||||
const char *const rogue_comp_test_str[ROGUE_COMP_TEST_COUNT] = {
|
||||
[ROGUE_COMP_TEST_NONE] = "!INVALID!", [ROGUE_COMP_TEST_EQ] = "eq",
|
||||
[ROGUE_COMP_TEST_GT] = "gt", [ROGUE_COMP_TEST_GE] = "ge",
|
||||
[ROGUE_COMP_TEST_NE] = "ne", [ROGUE_COMP_TEST_LT] = "lt",
|
||||
[ROGUE_COMP_TEST_LE] = "le",
|
||||
};
|
||||
|
||||
const char *const rogue_comp_type_str[ROGUE_COMP_TYPE_COUNT] = {
|
||||
[ROGUE_COMP_TYPE_NONE] = "!INVALID!", [ROGUE_COMP_TYPE_F32] = "f32",
|
||||
[ROGUE_COMP_TYPE_U16] = "u16", [ROGUE_COMP_TYPE_S16] = "s16",
|
||||
[ROGUE_COMP_TYPE_U8] = "u8", [ROGUE_COMP_TYPE_S8] = "s8",
|
||||
[ROGUE_COMP_TYPE_U32] = "u32", [ROGUE_COMP_TYPE_S32] = "s32",
|
||||
};
|
||||
|
||||
const char *rogue_instr_type_str[ROGUE_INSTR_TYPE_COUNT] = {
|
||||
[ROGUE_INSTR_TYPE_INVALID] = "!INVALID!",
|
||||
|
||||
[ROGUE_INSTR_TYPE_ALU] = "alu",
|
||||
/* [ROGUE_INSTR_TYPE_CMPLX] = "cmplx", */
|
||||
[ROGUE_INSTR_TYPE_BACKEND] = "backend",
|
||||
[ROGUE_INSTR_TYPE_CTRL] = "ctrl",
|
||||
[ROGUE_INSTR_TYPE_BITWISE] = "bitwise",
|
||||
/* [ROGUE_INSTR_TYPE_F16SOP] = "f16sop", */
|
||||
};
|
||||
|
||||
const char *const rogue_alu_str[ROGUE_ALU_COUNT] = {
|
||||
[ROGUE_ALU_INVALID] = "!INVALID!",
|
||||
[ROGUE_ALU_MAIN] = "main",
|
||||
[ROGUE_ALU_BITWISE] = "bitwise",
|
||||
[ROGUE_ALU_CONTROL] = "control",
|
||||
};
|
||||
|
||||
const char *const rogue_instr_phase_str[ROGUE_ALU_COUNT][ROGUE_INSTR_PHASE_COUNT] = {
|
||||
/** Main/ALU (and backend) instructions. */
|
||||
[ROGUE_ALU_MAIN] = {
|
||||
[ROGUE_INSTR_PHASE_0] = "p0",
|
||||
[ROGUE_INSTR_PHASE_1] = "p1",
|
||||
[ROGUE_INSTR_PHASE_2_PCK] = "p2pck",
|
||||
[ROGUE_INSTR_PHASE_2_TST] = "p2tst",
|
||||
[ROGUE_INSTR_PHASE_2_MOV] = "p2mov",
|
||||
[ROGUE_INSTR_PHASE_BACKEND] = "backend",
|
||||
},
|
||||
|
||||
/** Bitwise instructions. */
|
||||
[ROGUE_ALU_BITWISE] = {
|
||||
[ROGUE_INSTR_PHASE_0_BITMASK] = "p0bm",
|
||||
[ROGUE_INSTR_PHASE_0_SHIFT1] = "p0shf1",
|
||||
[ROGUE_INSTR_PHASE_0_COUNT] = "p0cnt",
|
||||
[ROGUE_INSTR_PHASE_1_LOGICAL] = "p1log",
|
||||
[ROGUE_INSTR_PHASE_2_SHIFT2] = "p2shf2",
|
||||
[ROGUE_INSTR_PHASE_2_TEST] = "p2tst",
|
||||
},
|
||||
|
||||
/** Control instructions (no co-issuing). */
|
||||
[ROGUE_ALU_CONTROL] = {
|
||||
[ROGUE_INSTR_PHASE_CTRL] = "ctrl",
|
||||
},
|
||||
};
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rogue_instr.h"
|
||||
#include "rogue_operand.h"
|
||||
#include "rogue_util.h"
|
||||
#include "util/ralloc.h"
|
||||
|
||||
/**
|
||||
* \file rogue_instr.c
|
||||
*
|
||||
* \brief Contains functions to manipulate Rogue instructions.
|
||||
*/
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
static const size_t instr_operand_count[ROGUE_OP_COUNT] = {
|
||||
[ROGUE_OP_NOP] = 0,
|
||||
[ROGUE_OP_END_FRAG] = 0,
|
||||
[ROGUE_OP_END_VERT] = 0,
|
||||
[ROGUE_OP_WDF] = 1,
|
||||
[ROGUE_OP_PIX_ITER_W] = 5,
|
||||
[ROGUE_OP_MAX] = 3,
|
||||
[ROGUE_OP_MIN] = 3,
|
||||
[ROGUE_OP_PACK_U8888] = 2,
|
||||
[ROGUE_OP_MOV] = 2,
|
||||
[ROGUE_OP_MOV_IMM] = 2,
|
||||
[ROGUE_OP_FMA] = 4,
|
||||
[ROGUE_OP_MUL] = 3,
|
||||
[ROGUE_OP_VTXOUT] = 2,
|
||||
};
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* \brief Returns the number of operands an instruction takes.
|
||||
*
|
||||
* \param[in] opcode The instruction opcode.
|
||||
* \return The number of operands.
|
||||
*/
|
||||
static inline size_t rogue_instr_num_operands(enum rogue_opcode opcode)
|
||||
{
|
||||
ASSERT_OPCODE_RANGE(opcode);
|
||||
|
||||
return instr_operand_count[opcode];
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocates and sets up a Rogue instruction.
|
||||
*
|
||||
* \param[in] mem_ctx The memory context for the instruction.
|
||||
* \param[in] opcode The instruction opcode.
|
||||
* \return A rogue_instr* if successful, or NULL if unsuccessful.
|
||||
*/
|
||||
struct rogue_instr *rogue_instr_create(void *mem_ctx, enum rogue_opcode opcode)
|
||||
{
|
||||
struct rogue_instr *instr;
|
||||
|
||||
ASSERT_OPCODE_RANGE(opcode);
|
||||
|
||||
instr = rzalloc_size(mem_ctx, sizeof(*instr));
|
||||
if (!instr)
|
||||
return NULL;
|
||||
|
||||
instr->opcode = opcode;
|
||||
instr->num_operands = rogue_instr_num_operands(opcode);
|
||||
|
||||
/* Allocate space for operand array. */
|
||||
if (instr->num_operands) {
|
||||
instr->operands = rzalloc_array_size(instr,
|
||||
sizeof(*instr->operands),
|
||||
instr->num_operands);
|
||||
if (!instr->operands) {
|
||||
ralloc_free(instr);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return instr;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets a Rogue instruction flag.
|
||||
*
|
||||
* \param[in] instr The instruction.
|
||||
* \param[in] flag The flag to set.
|
||||
* \return true if valid, otherwise false.
|
||||
*/
|
||||
bool rogue_instr_set_flag(struct rogue_instr *instr, enum rogue_instr_flag flag)
|
||||
{
|
||||
instr->flags = ROH(flag);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets a Rogue instruction operand to an immediate value.
|
||||
*
|
||||
* \param[in] instr The instruction.
|
||||
* \param[in] index The operand index.
|
||||
* \param[in] value The value to set.
|
||||
* \return true if valid, otherwise false.
|
||||
*/
|
||||
bool rogue_instr_set_operand_imm(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
uint64_t value)
|
||||
{
|
||||
ASSERT_INSTR_OPERAND_INDEX(instr, index);
|
||||
|
||||
instr->operands[index].type = ROGUE_OPERAND_TYPE_IMMEDIATE;
|
||||
instr->operands[index].immediate.value = value;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets a Rogue instruction operand to a DRC number.
|
||||
*
|
||||
* \param[in] instr The instruction.
|
||||
* \param[in] index The operand index.
|
||||
* \param[in] number The DRC number to set.
|
||||
* \return true if valid, otherwise false.
|
||||
*/
|
||||
bool rogue_instr_set_operand_drc(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
size_t number)
|
||||
{
|
||||
ASSERT_INSTR_OPERAND_INDEX(instr, index);
|
||||
|
||||
instr->operands[index].type = ROGUE_OPERAND_TYPE_DRC;
|
||||
instr->operands[index].drc.number = number;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets a Rogue instruction operand to a register.
|
||||
*
|
||||
* \param[in] instr The instruction.
|
||||
* \param[in] index The operand index.
|
||||
* \param[in] type The register type to set.
|
||||
* \param[in] number The register number to set.
|
||||
* \return true if valid, otherwise false.
|
||||
*/
|
||||
bool rogue_instr_set_operand_reg(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
enum rogue_operand_type type,
|
||||
size_t number)
|
||||
{
|
||||
ASSERT_INSTR_OPERAND_INDEX(instr, index);
|
||||
ASSERT_OPERAND_REG(type);
|
||||
|
||||
instr->operands[index].type = type;
|
||||
instr->operands[index].reg.number = number;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets a Rogue instruction operand to a virtual register.
|
||||
*
|
||||
* \param[in] instr The instruction.
|
||||
* \param[in] index The operand index.
|
||||
* \param[in] number The register number to set.
|
||||
* \return true if valid, otherwise false.
|
||||
*/
|
||||
bool rogue_instr_set_operand_vreg(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
size_t number)
|
||||
{
|
||||
ASSERT_INSTR_OPERAND_INDEX(instr, index);
|
||||
|
||||
instr->operands[index].type = ROGUE_OPERAND_TYPE_VREG;
|
||||
instr->operands[index].vreg.number = number;
|
||||
instr->operands[index].vreg.is_vector = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Sets a Rogue instruction operand to a virtual register
|
||||
* that is a vector type.
|
||||
*
|
||||
* \param[in] instr The instruction.
|
||||
* \param[in] index The operand index.
|
||||
* \param[in] component The vector component.
|
||||
* \param[in] number The register number to set.
|
||||
* \return true if valid, otherwise false.
|
||||
*/
|
||||
bool rogue_instr_set_operand_vreg_vec(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
size_t component,
|
||||
size_t number)
|
||||
{
|
||||
ASSERT_INSTR_OPERAND_INDEX(instr, index);
|
||||
|
||||
instr->operands[index].type = ROGUE_OPERAND_TYPE_VREG;
|
||||
instr->operands[index].vreg.number = number;
|
||||
instr->operands[index].vreg.is_vector = true;
|
||||
instr->operands[index].vreg.component = component;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_INSTR_H
|
||||
#define ROGUE_INSTR_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rogue_operand.h"
|
||||
#include "util/list.h"
|
||||
|
||||
/**
|
||||
* \brief Instruction opcodes.
|
||||
*/
|
||||
enum rogue_opcode {
|
||||
ROGUE_OP_NOP = 0, /** No-operation. */
|
||||
ROGUE_OP_END_FRAG, /** Fragment shader end. */
|
||||
ROGUE_OP_END_VERT, /** Vertex shader end. */
|
||||
ROGUE_OP_WDF, /** Write data fence. */
|
||||
|
||||
ROGUE_OP_PIX_ITER_W, /** Pixel iteration with coefficients. */
|
||||
|
||||
ROGUE_OP_MAX, /** Returns the largest out of two floats. */
|
||||
ROGUE_OP_MIN, /** Returns the smallest out of two floats. */
|
||||
|
||||
ROGUE_OP_PACK_U8888, /** Scales the four input floats:
|
||||
* [0.0f, 0.1f] -> [0, 255] and packs them
|
||||
* into a 32-bit unsigned integer.
|
||||
*/
|
||||
|
||||
ROGUE_OP_MOV, /** Register move instruction. */
|
||||
ROGUE_OP_MOV_IMM, /** Move immediate instruction. */
|
||||
|
||||
ROGUE_OP_FMA, /** Fused-multiply-add (float). */
|
||||
ROGUE_OP_MUL, /** Multiply (float). */
|
||||
|
||||
ROGUE_OP_VTXOUT, /** Writes the input register
|
||||
* to the given vertex output index.
|
||||
*/
|
||||
|
||||
ROGUE_OP_COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Instruction flags.
|
||||
*/
|
||||
enum rogue_instr_flag {
|
||||
ROGUE_INSTR_FLAG_SAT = 0, /** Saturate values to 0.0 ... 1.0. */
|
||||
ROGUE_INSTR_FLAG_LP, /** Low-precision modifier. */
|
||||
ROGUE_INSTR_FLAG_OLCHK, /** Overlap check (pixel write). */
|
||||
|
||||
ROGUE_INSTR_FLAG_COUNT,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Instruction description.
|
||||
*/
|
||||
struct rogue_instr {
|
||||
enum rogue_opcode opcode;
|
||||
|
||||
size_t num_operands;
|
||||
struct rogue_operand *operands;
|
||||
|
||||
uint64_t flags; /** A mask of #rogue_instr_flag values. */
|
||||
|
||||
struct list_head node; /** Linked list node. */
|
||||
};
|
||||
|
||||
struct rogue_instr *rogue_instr_create(void *mem_ctx, enum rogue_opcode opcode);
|
||||
|
||||
bool rogue_instr_set_flag(struct rogue_instr *instr,
|
||||
enum rogue_instr_flag flag);
|
||||
|
||||
bool rogue_instr_set_operand_imm(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
uint64_t value);
|
||||
bool rogue_instr_set_operand_drc(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
size_t number);
|
||||
bool rogue_instr_set_operand_reg(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
enum rogue_operand_type type,
|
||||
size_t number);
|
||||
bool rogue_instr_set_operand_vreg(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
size_t number);
|
||||
bool rogue_instr_set_operand_vreg_vec(struct rogue_instr *instr,
|
||||
size_t index,
|
||||
size_t component,
|
||||
size_t number);
|
||||
#endif /* ROGUE_INSTR_H */
|
||||
963
src/imagination/rogue/rogue_isa.h
Normal file
963
src/imagination/rogue/rogue_isa.h
Normal file
|
|
@ -0,0 +1,963 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_ISA_H
|
||||
#define ROGUE_ISA_H
|
||||
|
||||
/**
|
||||
* \file rogue_isa.h
|
||||
*
|
||||
* \brief Contains hardware ISA definitions and encodings.
|
||||
*/
|
||||
|
||||
/* Source/destination encodings. */
|
||||
|
||||
/* Internal source selector. */
|
||||
typedef struct rogue_iss_encoding {
|
||||
unsigned is1 : 1;
|
||||
unsigned is2 : 1;
|
||||
unsigned is3 : 2;
|
||||
unsigned is4 : 2;
|
||||
unsigned is5 : 2;
|
||||
} PACKED rogue_iss_encoding;
|
||||
static_assert(sizeof(rogue_iss_encoding) == 1,
|
||||
"sizeof(rogue_iss_encoding) != 1");
|
||||
|
||||
typedef struct rogue_dbN {
|
||||
union {
|
||||
struct {
|
||||
unsigned _0 : 1;
|
||||
unsigned _2_1 : 2;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_dbN;
|
||||
static_assert(sizeof(rogue_dbN) == 1, "sizeof(rogue_dbN) != 1");
|
||||
|
||||
typedef struct rogue_dN {
|
||||
union {
|
||||
struct {
|
||||
unsigned _5_0 : 6;
|
||||
unsigned _7_6 : 2;
|
||||
unsigned _10_8 : 3;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_dN;
|
||||
static_assert(sizeof(rogue_dN) == 2, "sizeof(rogue_dN) != 2");
|
||||
|
||||
typedef struct rogue_db0 {
|
||||
union {
|
||||
struct {
|
||||
unsigned _0 : 1;
|
||||
unsigned _2_1 : 2;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_db0;
|
||||
static_assert(sizeof(rogue_db0) == 1, "sizeof(rogue_db0) != 1");
|
||||
|
||||
typedef struct rogue_db1 {
|
||||
union {
|
||||
struct {
|
||||
unsigned _0 : 1;
|
||||
unsigned _2_1 : 2;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_db1;
|
||||
static_assert(sizeof(rogue_db0) == 1, "sizeof(rogue_db0) != 1");
|
||||
|
||||
typedef struct rogue_d0 {
|
||||
union {
|
||||
struct {
|
||||
unsigned _6_0 : 7;
|
||||
unsigned _7 : 1;
|
||||
unsigned _10_8 : 3;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint16_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_d0;
|
||||
static_assert(sizeof(rogue_d0) == 2, "sizeof(rogue_d0) != 2");
|
||||
|
||||
typedef struct rogue_d1 {
|
||||
union {
|
||||
struct {
|
||||
unsigned _5_0 : 6;
|
||||
unsigned _7_6 : 2;
|
||||
unsigned _10_8 : 3;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint16_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_d1;
|
||||
static_assert(sizeof(rogue_d1) == 2, "sizeof(rogue_d1) != 2");
|
||||
|
||||
typedef struct rogue_dest_map_encoding {
|
||||
/* Byte 0 */
|
||||
union {
|
||||
struct {
|
||||
unsigned dN_5_0 : 6;
|
||||
unsigned dbN_0 : 1;
|
||||
unsigned ext0 : 1;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned d0_6_0 : 7;
|
||||
unsigned db0_0 : 1;
|
||||
} PACKED;
|
||||
};
|
||||
|
||||
/* Byte 1 */
|
||||
union {
|
||||
struct {
|
||||
unsigned dN_7_6 : 2;
|
||||
unsigned dbN_2_1 : 2;
|
||||
unsigned dN_10_8 : 3;
|
||||
unsigned rsvd1 : 1;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned d1_5_0 : 6;
|
||||
unsigned db1_0 : 1;
|
||||
unsigned ext1 : 1;
|
||||
} PACKED;
|
||||
};
|
||||
|
||||
/* Byte 2 */
|
||||
struct {
|
||||
unsigned d0_7 : 1;
|
||||
unsigned db0_2_1 : 2;
|
||||
unsigned d1_7_6 : 2;
|
||||
unsigned db1_2_1 : 2;
|
||||
unsigned ext2 : 1;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 3 */
|
||||
struct {
|
||||
unsigned d0_10_8 : 3;
|
||||
unsigned d1_10_8 : 3;
|
||||
unsigned rsvd3 : 2;
|
||||
} PACKED;
|
||||
} PACKED rogue_dest_map_encoding;
|
||||
static_assert(sizeof(rogue_dest_map_encoding) == 4,
|
||||
"sizeof(rogue_dest_map_encoding) != 4");
|
||||
|
||||
/****************/
|
||||
|
||||
typedef struct rogue_source_map_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned sA_5_0 : 6;
|
||||
unsigned sbA_0 : 1;
|
||||
unsigned ext0 : 1;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 1 */
|
||||
union {
|
||||
struct {
|
||||
unsigned sA_7_6 : 2;
|
||||
unsigned sbA_2_1 : 2;
|
||||
unsigned mux_1_0 : 2;
|
||||
unsigned : 2;
|
||||
} PACKED sA_1;
|
||||
|
||||
struct {
|
||||
unsigned sB_4_0 : 5;
|
||||
unsigned sbB_0 : 1;
|
||||
unsigned ext1 : 1;
|
||||
unsigned sel : 1;
|
||||
} PACKED;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 2 */
|
||||
union {
|
||||
/* Common def. */
|
||||
struct sA_sC_10_8 {
|
||||
unsigned sA_10_8 : 3;
|
||||
unsigned sC_10_8 : 3;
|
||||
unsigned rsvd5 : 2;
|
||||
} PACKED sA_2;
|
||||
|
||||
struct {
|
||||
unsigned sB_6_5 : 2;
|
||||
unsigned sA_6 : 1;
|
||||
unsigned sbB_1 : 1;
|
||||
unsigned sbA_1 : 1;
|
||||
unsigned mux_1_0 : 2;
|
||||
unsigned ext2 : 1;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned : 3;
|
||||
unsigned rsvd2 : 5;
|
||||
} PACKED;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 3 */
|
||||
union {
|
||||
/* Common def. */
|
||||
struct sB_sC_mux2 {
|
||||
union {
|
||||
struct {
|
||||
unsigned sB_7 : 1;
|
||||
unsigned sA_7 : 1;
|
||||
unsigned rsvd3 : 1;
|
||||
unsigned sbA_2 : 1;
|
||||
unsigned mux_2 : 1;
|
||||
unsigned sA_10_8 : 3;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned : 2;
|
||||
unsigned ext4 : 1;
|
||||
unsigned : 2;
|
||||
unsigned sC_7_6 : 2;
|
||||
unsigned sbC_2 : 1;
|
||||
} PACKED;
|
||||
} PACKED;
|
||||
} PACKED sB_3;
|
||||
|
||||
struct {
|
||||
unsigned sC_5_0 : 6;
|
||||
unsigned sbC_1_0 : 2;
|
||||
} PACKED;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 4 */
|
||||
struct sB_sC_mux2 sC_4;
|
||||
|
||||
/* Byte 5 */
|
||||
struct sA_sC_10_8 sC_5;
|
||||
} PACKED rogue_source_map_encoding;
|
||||
static_assert(sizeof(rogue_source_map_encoding) == 6,
|
||||
"sizeof(rogue_source_map_encoding) == 6");
|
||||
|
||||
typedef struct rogue_sbA {
|
||||
union {
|
||||
struct {
|
||||
unsigned _0 : 1;
|
||||
unsigned _2_1 : 2;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned : 1;
|
||||
unsigned _1 : 1;
|
||||
unsigned _2 : 1;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_sbA;
|
||||
static_assert(sizeof(rogue_sbA) == 1, "sizeof(rogue_sbA) != 1");
|
||||
|
||||
typedef struct rogue_sA {
|
||||
union {
|
||||
struct {
|
||||
unsigned _5_0 : 6;
|
||||
unsigned _7_6 : 2;
|
||||
unsigned _10_8 : 3;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned : 6;
|
||||
unsigned _6 : 1;
|
||||
unsigned _7 : 1;
|
||||
unsigned : 8;
|
||||
} PACKED;
|
||||
|
||||
uint16_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_sA;
|
||||
static_assert(sizeof(rogue_sA) == 2, "sizeof(rogue_sA) != 2");
|
||||
|
||||
typedef struct rogue_sbB {
|
||||
union {
|
||||
struct {
|
||||
unsigned _0 : 1;
|
||||
unsigned _1 : 1;
|
||||
unsigned : 6;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_sbB;
|
||||
static_assert(sizeof(rogue_sbB) == 1, "sizeof(rogue_sbB) != 1");
|
||||
|
||||
typedef struct rogue_sB {
|
||||
union {
|
||||
struct {
|
||||
unsigned _4_0 : 5;
|
||||
unsigned _6_5 : 2;
|
||||
unsigned _7 : 1;
|
||||
unsigned : 8;
|
||||
} PACKED;
|
||||
|
||||
uint16_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_sB;
|
||||
static_assert(sizeof(rogue_sB) == 2, "sizeof(rogue_sB) != 2");
|
||||
|
||||
typedef struct rogue_sbC {
|
||||
union {
|
||||
struct {
|
||||
unsigned _1_0 : 2;
|
||||
unsigned _2 : 1;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_sbC;
|
||||
static_assert(sizeof(rogue_sbC) == 1, "sizeof(rogue_sbC) != 1");
|
||||
|
||||
typedef struct rogue_sC {
|
||||
union {
|
||||
struct {
|
||||
unsigned _5_0 : 6;
|
||||
unsigned _7_6 : 2;
|
||||
unsigned _10_8 : 3;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint16_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_sC;
|
||||
static_assert(sizeof(rogue_sC) == 2, "sizeof(rogue_sC) != 2");
|
||||
|
||||
typedef struct rogue_mux {
|
||||
union {
|
||||
struct {
|
||||
unsigned _1_0 : 2;
|
||||
unsigned _2 : 1;
|
||||
unsigned : 5;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_mux;
|
||||
static_assert(sizeof(rogue_mux) == 1, "sizeof(rogue_mux) != 1");
|
||||
|
||||
enum reg_bank {
|
||||
BANK_SPECIAL = 0b000,
|
||||
BANK_TEMP = 0b001,
|
||||
BANK_VTXIN = 0b010,
|
||||
BANK_COEFF = 0b011,
|
||||
BANK_SHARED = 0b100,
|
||||
BANK_COEFF_ALT = 0b101,
|
||||
BANK_IDX0 = 0b110,
|
||||
BANK_IDX1 = 0b111,
|
||||
};
|
||||
|
||||
enum is0 {
|
||||
IS0_S0 = 0b000,
|
||||
IS0_S3 = 0b001,
|
||||
IS0_S4 = 0b010,
|
||||
IS0_S5 = 0b011,
|
||||
IS0_S1 = 0b100,
|
||||
IS0_S2 = 0b101,
|
||||
};
|
||||
|
||||
enum is1 {
|
||||
IS1_FT0 = 0b0,
|
||||
IS1_FTE = 0b1,
|
||||
};
|
||||
|
||||
enum is2 {
|
||||
IS2_FT1 = 0b0,
|
||||
IS2_FTE = 0b1,
|
||||
};
|
||||
|
||||
enum is3 {
|
||||
IS3_FT0 = 0b00,
|
||||
IS3_FT1 = 0b01,
|
||||
IS3_S2 = 0b10,
|
||||
IS3_FTE = 0b11,
|
||||
};
|
||||
|
||||
enum is4 {
|
||||
IS4_FT0 = 0b00,
|
||||
IS4_FT1 = 0b01,
|
||||
IS4_FT2 = 0b10,
|
||||
IS4_FTE = 0b11,
|
||||
};
|
||||
|
||||
enum is5 {
|
||||
IS5_FT0 = 0b00,
|
||||
IS5_FT1 = 0b01,
|
||||
IS5_FT2 = 0b10,
|
||||
IS5_FTE = 0b11,
|
||||
};
|
||||
|
||||
/* Single source instructions. */
|
||||
|
||||
typedef struct rogue_single_pck_encoding {
|
||||
/* Byte 1 */
|
||||
union {
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
unsigned format : 5;
|
||||
unsigned scale : 1;
|
||||
unsigned elem : 2;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned : 5;
|
||||
unsigned rtz : 1;
|
||||
unsigned : 2;
|
||||
} PACKED;
|
||||
} PACKED;
|
||||
} PACKED upck;
|
||||
|
||||
struct {
|
||||
unsigned format : 5;
|
||||
unsigned scale : 1;
|
||||
unsigned rtz : 1;
|
||||
unsigned prog : 1;
|
||||
} PACKED pck;
|
||||
} PACKED;
|
||||
} PACKED rogue_single_pck_encoding;
|
||||
static_assert(sizeof(rogue_single_pck_encoding) == 1,
|
||||
"sizeof(rogue_single_pck_encoding) != 1");
|
||||
|
||||
enum pck_fmt {
|
||||
PCK_FMT_U8888 = 0b00000,
|
||||
PCK_FMT_S8888 = 0b00001,
|
||||
PCK_FMT_O8888 = 0b00010,
|
||||
PCK_FMT_U1616 = 0b00011,
|
||||
PCK_FMT_S1616 = 0b00100,
|
||||
PCK_FMT_O1616 = 0b00101,
|
||||
PCK_FMT_U32 = 0b00110,
|
||||
PCK_FMT_S32 = 0b00111,
|
||||
PCK_FMT_U1010102 = 0b01000,
|
||||
PCK_FMT_S1010102 = 0b01001,
|
||||
PCK_FMT_U111110 = 0b01010,
|
||||
PCK_FMT_S111110 = 0b01011,
|
||||
PCK_FMT_F111110 = 0b01100,
|
||||
PCK_FMT_F16F16 = 0b01110,
|
||||
PCK_FMT_F32 = 0b01111,
|
||||
PCK_FMT_COV = 0b10000,
|
||||
PCK_FMT_U565U565 = 0b10001,
|
||||
PCK_FMT_D24S8 = 0b10010,
|
||||
PCK_FMT_S8D24 = 0b10011,
|
||||
PCK_FMT_F32_MASK = 0b10100,
|
||||
PCK_FMT_2F10F10F10 = 0b10101,
|
||||
PCK_FMT_S8888OGL = 0b10110,
|
||||
PCK_FMT_S1616OGL = 0b10111,
|
||||
PCK_FMT_ZERO = 0b11110,
|
||||
PCK_FMT_ONE = 0b11111,
|
||||
};
|
||||
|
||||
typedef struct rogue_single_mbyp_encoding {
|
||||
/* Byte 1 */
|
||||
struct {
|
||||
unsigned s0abs : 1;
|
||||
unsigned s0neg : 1;
|
||||
unsigned : 6;
|
||||
} PACKED;
|
||||
} PACKED rogue_single_mbyp_encoding;
|
||||
static_assert(sizeof(rogue_single_mbyp_encoding) == 1,
|
||||
"sizeof(rogue_single_mbyp_encoding) != 1");
|
||||
|
||||
enum snglop {
|
||||
SNGLOP_RCP = 0b0000,
|
||||
SNGLOP_RSQ = 0b0001,
|
||||
SNGLOP_LOG = 0b0010,
|
||||
SNGLOP_EXP = 0b0011,
|
||||
SNGLOP_F16SOP = 0b0100,
|
||||
SNGLOP_LOGCN = 0b0101,
|
||||
SNGLOP_GAMMA = 0b0110,
|
||||
SNGLOP_BYP = 0b0111,
|
||||
SNGLOP_DSX = 0b1000,
|
||||
SNGLOP_DSY = 0b1001,
|
||||
SNGLOP_DSXF = 0b1010,
|
||||
SNGLOP_DSYF = 0b1011,
|
||||
SNGLOP_PCK = 0b1100,
|
||||
SNGLOP_RED = 0b1101,
|
||||
SNGLOP_SINC = 0b1110,
|
||||
SNGLOP_ARCTANC = 0b1111,
|
||||
};
|
||||
|
||||
typedef struct rogue_alu_single_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned snglop : 4;
|
||||
unsigned ext0 : 1;
|
||||
unsigned : 3;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 1+ */
|
||||
union {
|
||||
rogue_single_mbyp_encoding mbyp;
|
||||
rogue_single_pck_encoding pck;
|
||||
} PACKED;
|
||||
} PACKED rogue_alu_single_encoding;
|
||||
static_assert(sizeof(rogue_alu_single_encoding) == 2,
|
||||
"sizeof(rogue_alu_single_encoding) != 2");
|
||||
|
||||
typedef struct rogue_alu_fmad_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned sat : 1;
|
||||
unsigned s2neg : 1;
|
||||
unsigned s0abs : 1;
|
||||
unsigned s0neg : 1;
|
||||
unsigned ext : 1;
|
||||
unsigned : 3;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 1 */
|
||||
struct {
|
||||
unsigned s2abs : 1;
|
||||
unsigned s2flr : 1;
|
||||
unsigned s1neg : 1;
|
||||
unsigned s1abs : 1;
|
||||
unsigned lp : 1;
|
||||
unsigned : 3;
|
||||
} PACKED;
|
||||
} PACKED rogue_alu_fmad_encoding;
|
||||
static_assert(sizeof(rogue_alu_fmad_encoding) == 2,
|
||||
"sizeof(rogue_alu_fmad_encoding) != 2");
|
||||
|
||||
typedef struct rogue_alu_fdual_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned s0flr : 1;
|
||||
unsigned s1abs : 1;
|
||||
unsigned s0abs : 1;
|
||||
unsigned s0neg : 1;
|
||||
unsigned sat : 1;
|
||||
unsigned lp : 1;
|
||||
unsigned : 2;
|
||||
} PACKED;
|
||||
} PACKED rogue_alu_fdual_encoding;
|
||||
static_assert(sizeof(rogue_alu_fdual_encoding) == 1,
|
||||
"sizeof(rogue_alu_fdual_encoding) != 1");
|
||||
|
||||
typedef struct rogue_alu_tst_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned pwen : 1;
|
||||
unsigned tstop_2_0 : 3;
|
||||
unsigned ext : 1;
|
||||
unsigned : 3;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 1 */
|
||||
struct {
|
||||
unsigned tstop_3 : 1;
|
||||
unsigned : 1;
|
||||
unsigned elem : 2;
|
||||
unsigned p2end : 1;
|
||||
unsigned type : 3;
|
||||
} PACKED;
|
||||
} PACKED rogue_alu_tst_encoding;
|
||||
static_assert(sizeof(rogue_alu_tst_encoding) == 2,
|
||||
"sizeof(rogue_alu_tst_encoding) != 2");
|
||||
|
||||
typedef struct rogue_tstop {
|
||||
union {
|
||||
struct {
|
||||
unsigned _2_0 : 3;
|
||||
unsigned _3 : 1;
|
||||
unsigned : 4;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_tstop;
|
||||
static_assert(sizeof(rogue_tstop) == 1, "sizeof(rogue_tstop) != 1");
|
||||
|
||||
enum tstop {
|
||||
TSTOP_Z = 0b0000,
|
||||
TSTOP_GZ = 0b0001,
|
||||
TSTOP_GEZ = 0b0010,
|
||||
TSTOP_IC = 0b0011,
|
||||
TSTOP_EQ = 0b0100,
|
||||
TSTOP_GT = 0b0101,
|
||||
TSTOP_GE = 0b0110,
|
||||
TSTOP_NE = 0b0111,
|
||||
TSTOP_LT = 0b1000,
|
||||
TSTOP_LE = 0b1001,
|
||||
};
|
||||
|
||||
typedef struct rogue_alu_mov_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned movw0 : 2;
|
||||
unsigned movw1 : 2;
|
||||
unsigned ext : 1;
|
||||
unsigned : 3;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 1 */
|
||||
struct {
|
||||
unsigned p2end : 1;
|
||||
unsigned aw : 1;
|
||||
unsigned maskw0 : 4;
|
||||
unsigned : 2;
|
||||
} PACKED;
|
||||
} PACKED rogue_alu_mov_encoding;
|
||||
static_assert(sizeof(rogue_alu_mov_encoding) == 2,
|
||||
"sizeof(rogue_alu_mov_encoding) != 2");
|
||||
|
||||
typedef struct rogue_alu_instr_encoding {
|
||||
union {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned : 5;
|
||||
unsigned op : 3;
|
||||
} PACKED;
|
||||
|
||||
/* Bytes 1+ */
|
||||
rogue_alu_single_encoding sngl;
|
||||
rogue_alu_fdual_encoding fadd;
|
||||
rogue_alu_fdual_encoding fmul;
|
||||
rogue_alu_fmad_encoding fmad;
|
||||
rogue_alu_tst_encoding tst;
|
||||
rogue_alu_mov_encoding mov;
|
||||
} PACKED;
|
||||
} PACKED rogue_alu_instr_encoding;
|
||||
static_assert(sizeof(rogue_alu_instr_encoding) == 2,
|
||||
"sizeof(rogue_alu_instr_encoding) != 2");
|
||||
|
||||
enum aluop {
|
||||
ALUOP_FADD = 0b000, /** Phase 0, 1. */
|
||||
ALUOP_FMUL = 0b010, /** Phase 0, 1. */
|
||||
ALUOP_SNGL = 0b100, /** Phase 0, 1, 2. */
|
||||
ALUOP_INT8_16 = 0b101, /** Phase 0. */
|
||||
ALUOP_FMAD = 0b110, /** Phase 0, 1. */
|
||||
ALUOP_MOV = 0b110, /** Phase 2. */
|
||||
ALUOP_INT32_64 = 0b111, /** Phase 0. */
|
||||
ALUOP_TST = 0b111, /** Phase 2. */
|
||||
};
|
||||
|
||||
/* Backend instructions. */
|
||||
|
||||
typedef struct rogue_backend_emitpix_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned : 1;
|
||||
unsigned freep : 1;
|
||||
unsigned : 6;
|
||||
} PACKED;
|
||||
} PACKED rogue_backend_emitpix_encoding;
|
||||
static_assert(sizeof(rogue_backend_emitpix_encoding) == 1,
|
||||
"sizeof(rogue_backend_emitpix_encoding) != 1");
|
||||
|
||||
typedef struct rogue_backend_fitr_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned mode : 2;
|
||||
unsigned : 1;
|
||||
unsigned drc : 1;
|
||||
unsigned p : 1;
|
||||
unsigned : 3;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 1 */
|
||||
struct {
|
||||
unsigned count : 4;
|
||||
unsigned sat : 1;
|
||||
unsigned : 3;
|
||||
} PACKED;
|
||||
} PACKED rogue_backend_fitr_encoding;
|
||||
static_assert(sizeof(rogue_backend_fitr_encoding) == 2,
|
||||
"sizeof(rogue_backend_fitr_encoding) != 2");
|
||||
|
||||
enum fitr_mode {
|
||||
FITR_MODE_PIXEL = 0b00,
|
||||
FITR_MODE_SAMPLE = 0b01,
|
||||
FITR_MODE_CENTROID = 0b10,
|
||||
};
|
||||
|
||||
typedef struct rogue_backend_uvsw_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned writeop : 3;
|
||||
unsigned imm : 1;
|
||||
unsigned dsel : 1;
|
||||
unsigned : 3;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 1 */
|
||||
union {
|
||||
struct {
|
||||
unsigned srcsel : 3;
|
||||
unsigned : 5;
|
||||
} PACKED src;
|
||||
|
||||
struct {
|
||||
unsigned imm_addr : 8;
|
||||
} PACKED imm_src;
|
||||
|
||||
struct {
|
||||
unsigned streamid : 2;
|
||||
unsigned : 6;
|
||||
} PACKED stream_src;
|
||||
} PACKED;
|
||||
} PACKED rogue_backend_uvsw_encoding;
|
||||
static_assert(sizeof(rogue_backend_uvsw_encoding) == 2,
|
||||
"sizeof(rogue_backend_uvsw_encoding) != 2");
|
||||
|
||||
enum uvsw_writeop {
|
||||
UVSW_WRITEOP_WRITE = 0b000,
|
||||
UVSW_WRITEOP_EMIT = 0b001,
|
||||
UVSW_WRITEOP_CUT = 0b010,
|
||||
UVSW_WRITEOP_EMIT_CUT = 0b011,
|
||||
UVSW_WRITEOP_END = 0b100,
|
||||
UVSW_WRITEOP_EMIT_END = 0b101,
|
||||
UVSW_WRITEOP_WRITE_EMIT_END = 0b110,
|
||||
};
|
||||
|
||||
typedef struct rogue_backend_instr_encoding {
|
||||
union {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned : 5;
|
||||
unsigned op : 3;
|
||||
} PACKED;
|
||||
|
||||
rogue_backend_uvsw_encoding uvsw;
|
||||
rogue_backend_fitr_encoding fitr;
|
||||
rogue_backend_emitpix_encoding emitpix;
|
||||
} PACKED;
|
||||
} PACKED rogue_backend_instr_encoding;
|
||||
static_assert(sizeof(rogue_backend_instr_encoding) == 2,
|
||||
"sizeof(rogue_backend_instr_encoding) != 2");
|
||||
|
||||
enum backendop {
|
||||
BACKENDOP_UVSW = 0b000,
|
||||
BACKENDOP_MSK = 0b001,
|
||||
BACKENDOP_PHAS = 0b010,
|
||||
BACKENDOP_SETL = 0b011,
|
||||
BACKENDOP_VISTEST = 0b100,
|
||||
BACKENDOP_FITR = 0b101,
|
||||
BACKENDOP_EMIT = 0b110,
|
||||
BACKENDOP_DMA = 0b111,
|
||||
};
|
||||
|
||||
/* Branch */
|
||||
typedef struct rogue_ctrl_ba_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned : 1;
|
||||
unsigned abs : 1;
|
||||
unsigned allp : 1;
|
||||
unsigned anyp : 1;
|
||||
unsigned link : 1;
|
||||
unsigned : 3;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 1 */
|
||||
struct {
|
||||
unsigned : 1;
|
||||
unsigned offset_7_1 : 7;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 2 */
|
||||
struct {
|
||||
unsigned offset_15_8 : 8;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 3 */
|
||||
struct {
|
||||
unsigned offset_23_16 : 8;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 4 */
|
||||
struct {
|
||||
unsigned offset_31_24 : 8;
|
||||
} PACKED;
|
||||
} PACKED rogue_ctrl_ba_encoding;
|
||||
static_assert(sizeof(rogue_ctrl_ba_encoding) == 5,
|
||||
"sizeof(rogue_ctrl_ba_encoding) != 5");
|
||||
|
||||
typedef struct rogue_offset32 {
|
||||
union {
|
||||
struct {
|
||||
struct {
|
||||
unsigned : 1;
|
||||
unsigned _7_1 : 7;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned _15_8 : 8;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned _23_16 : 8;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned _31_24 : 8;
|
||||
} PACKED;
|
||||
} PACKED;
|
||||
|
||||
uint32_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_offset32;
|
||||
static_assert(sizeof(rogue_offset32) == 4, "sizeof(rogue_offset32) != 4");
|
||||
|
||||
/* NOP */
|
||||
typedef struct rogue_ctrl_nop_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned : 8;
|
||||
} PACKED;
|
||||
} PACKED rogue_ctrl_nop_encoding;
|
||||
static_assert(sizeof(rogue_ctrl_nop_encoding) == 1,
|
||||
"sizeof(rogue_ctrl_nop_encoding) != 1");
|
||||
|
||||
/* Common for all control instructions. */
|
||||
typedef struct rogue_ctrl_instr_encoding {
|
||||
union {
|
||||
/* Bytes 0+ */
|
||||
rogue_ctrl_ba_encoding ba;
|
||||
rogue_ctrl_nop_encoding nop;
|
||||
} PACKED;
|
||||
} PACKED rogue_ctrl_instr_encoding;
|
||||
static_assert(sizeof(rogue_ctrl_instr_encoding) == 5,
|
||||
"sizeof(rogue_ctrl_instr_encoding) != 5");
|
||||
|
||||
enum ctrlop {
|
||||
CTRLOP_BA = 0b0000,
|
||||
CTRLOP_LAPC = 0b0001,
|
||||
CTRLOP_SAVL = 0b0010,
|
||||
CTRLOP_CND = 0b0011,
|
||||
CTRLOP_WOP = 0b0100,
|
||||
CTRLOP_WDF = 0b0101,
|
||||
CTRLOP_MUTEX = 0b0110,
|
||||
CTRLOP_NOP = 0b0111,
|
||||
CTRLOP_ITRSMP = 0b1000,
|
||||
CTRLOP_UNIQ = 0b1001,
|
||||
CTRLOP_FETCH = 0b1010,
|
||||
CTRLOP_SBO = 0b1011,
|
||||
};
|
||||
|
||||
typedef struct rogue_instr_group_header_encoding {
|
||||
/* Byte 0 */
|
||||
struct {
|
||||
unsigned length : 4;
|
||||
unsigned da : 4;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 1 */
|
||||
union {
|
||||
struct {
|
||||
unsigned cc : 1;
|
||||
unsigned w0p : 1;
|
||||
unsigned w1p : 1;
|
||||
unsigned olchk : 1;
|
||||
unsigned oporg : 3;
|
||||
unsigned ext : 1;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned : 4;
|
||||
unsigned opcnt : 3;
|
||||
unsigned : 1;
|
||||
} PACKED;
|
||||
} PACKED;
|
||||
|
||||
/* Byte 2 */
|
||||
union {
|
||||
struct {
|
||||
unsigned ccext : 1;
|
||||
unsigned rpt : 2;
|
||||
unsigned atom : 1;
|
||||
unsigned crel : 1;
|
||||
unsigned alutype : 2;
|
||||
unsigned end : 1;
|
||||
} PACKED;
|
||||
|
||||
struct {
|
||||
unsigned : 1;
|
||||
unsigned ctrlop : 4;
|
||||
unsigned : 2;
|
||||
unsigned miscctl : 1;
|
||||
} PACKED;
|
||||
} PACKED;
|
||||
} PACKED rogue_instr_group_header_encoding;
|
||||
static_assert(sizeof(rogue_instr_group_header_encoding) == 3,
|
||||
"sizeof(rogue_instr_group_header_encoding) != 3");
|
||||
|
||||
enum oporg {
|
||||
OPORG_P0 = 0b000,
|
||||
OPORG_P2 = 0b001,
|
||||
OPORG_BE = 0b010,
|
||||
OPORG_P0_P1 = 0b011,
|
||||
OPORG_P0_P2 = 0b100,
|
||||
OPORG_P0_P1_P2 = 0b101,
|
||||
OPORG_P0_P2_BE = 0b110,
|
||||
OPORG_P0_P1_P2_BE = 0b111,
|
||||
};
|
||||
|
||||
enum opcnt {
|
||||
OPCNT_P0 = 0b001,
|
||||
OPCNT_P1 = 0b010,
|
||||
OPCNT_P2 = 0b100,
|
||||
};
|
||||
|
||||
enum alutype {
|
||||
ALUTYPE_MAIN = 0b00,
|
||||
ALUTYPE_BITWISE = 0b10,
|
||||
ALUTYPE_CONTROL = 0b11,
|
||||
};
|
||||
|
||||
enum cc {
|
||||
CC_PE_TRUE = 0b00,
|
||||
CC_P0_TRUE = 0b01,
|
||||
CC_PE_ANY = 0b10,
|
||||
CC_P0_FALSE = 0b11,
|
||||
};
|
||||
|
||||
typedef struct rogue_cc {
|
||||
union {
|
||||
struct {
|
||||
unsigned cc : 1;
|
||||
unsigned ccext : 1;
|
||||
unsigned : 6;
|
||||
} PACKED;
|
||||
|
||||
uint8_t _;
|
||||
} PACKED;
|
||||
} PACKED rogue_cc;
|
||||
static_assert(sizeof(rogue_cc) == 1, "sizeof(rogue_cc) != 1");
|
||||
|
||||
#endif /* ROGUE_ISA_H */
|
||||
|
|
@ -23,14 +23,15 @@
|
|||
|
||||
#include "compiler/spirv/nir_spirv.h"
|
||||
#include "nir/nir.h"
|
||||
#include "nir/nir_schedule.h"
|
||||
#include "rogue_nir.h"
|
||||
#include "rogue_operand.h"
|
||||
#include "rogue.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file rogue_nir.c
|
||||
*
|
||||
* \brief Contains NIR-specific functions.
|
||||
* \brief Contains SPIR-V and NIR-specific functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -44,22 +45,9 @@ static const struct spirv_to_nir_options spirv_options = {
|
|||
};
|
||||
|
||||
static const nir_shader_compiler_options nir_options = {
|
||||
.lower_fsat = true,
|
||||
.fuse_ffma32 = true,
|
||||
};
|
||||
|
||||
const struct spirv_to_nir_options *
|
||||
rogue_get_spirv_options(const struct rogue_compiler *compiler)
|
||||
{
|
||||
return &spirv_options;
|
||||
}
|
||||
|
||||
const nir_shader_compiler_options *
|
||||
rogue_get_compiler_options(const struct rogue_compiler *compiler)
|
||||
{
|
||||
return &nir_options;
|
||||
}
|
||||
|
||||
static int rogue_glsl_type_size(const struct glsl_type *type, bool bindless)
|
||||
{
|
||||
return glsl_count_attribute_slots(type, false);
|
||||
|
|
@ -72,23 +60,24 @@ static int rogue_glsl_type_size(const struct glsl_type *type, bool bindless)
|
|||
* \param[in] ctx Shared multi-stage build context.
|
||||
* \param[in] shader Rogue shader.
|
||||
* \param[in] stage Shader stage.
|
||||
* \return true if successful, otherwise false.
|
||||
*/
|
||||
bool rogue_nir_passes(struct rogue_build_ctx *ctx,
|
||||
nir_shader *nir,
|
||||
gl_shader_stage stage)
|
||||
static void rogue_nir_passes(struct rogue_build_ctx *ctx,
|
||||
nir_shader *nir,
|
||||
gl_shader_stage stage)
|
||||
{
|
||||
bool progress;
|
||||
|
||||
#if !defined(NDEBUG)
|
||||
bool nir_debug_print_shader_prev = nir_debug_print_shader[nir->info.stage];
|
||||
nir_debug_print_shader[nir->info.stage] = ROGUE_DEBUG(NIR_PASSES);
|
||||
#endif /* !defined(NDEBUG) */
|
||||
|
||||
nir_validate_shader(nir, "after spirv_to_nir");
|
||||
|
||||
/* Splitting. */
|
||||
NIR_PASS_V(nir, nir_split_var_copies);
|
||||
NIR_PASS_V(nir, nir_split_per_member_structs);
|
||||
|
||||
/* Ensure fs outputs are in the [0.0f...1.0f] range. */
|
||||
NIR_PASS_V(nir, nir_lower_clamp_color_outputs);
|
||||
|
||||
/* Replace references to I/O variables with intrinsics. */
|
||||
NIR_PASS_V(nir,
|
||||
nir_lower_io,
|
||||
|
|
@ -97,6 +86,7 @@ bool rogue_nir_passes(struct rogue_build_ctx *ctx,
|
|||
(nir_lower_io_options)0);
|
||||
|
||||
/* Load inputs to scalars (single registers later). */
|
||||
/* TODO: Fitrp can process multiple frag inputs at once, scalarise I/O. */
|
||||
NIR_PASS_V(nir, nir_lower_io_to_scalar, nir_var_shader_in);
|
||||
|
||||
/* Optimize GL access qualifiers. */
|
||||
|
|
@ -145,13 +135,14 @@ bool rogue_nir_passes(struct rogue_build_ctx *ctx,
|
|||
NIR_PASS_V(nir, nir_opt_cse);
|
||||
} while (progress);
|
||||
|
||||
/* Replace SSA constant references with a register that loads the value. */
|
||||
NIR_PASS_V(nir, rogue_nir_constreg);
|
||||
/* Remove unused constant registers. */
|
||||
NIR_PASS_V(nir, nir_opt_dce);
|
||||
|
||||
/* Move loads to just before they're needed. */
|
||||
NIR_PASS_V(nir, nir_opt_move, nir_move_load_ubo | nir_move_load_input);
|
||||
/* Disabled for now since we want to try and keep them vectorised and group
|
||||
* them. */
|
||||
/* TODO: Investigate this further. */
|
||||
/* NIR_PASS_V(nir, nir_opt_move, nir_move_load_ubo | nir_move_load_input); */
|
||||
|
||||
/* Convert vecNs to movs so we can sequentially allocate them later. */
|
||||
NIR_PASS_V(nir, nir_lower_vec_to_movs, NULL, NULL);
|
||||
|
|
@ -185,6 +176,57 @@ bool rogue_nir_passes(struct rogue_build_ctx *ctx,
|
|||
nir_sweep(nir);
|
||||
|
||||
nir_validate_shader(nir, "after passes");
|
||||
if (ROGUE_DEBUG(NIR)) {
|
||||
fputs("after passes\n", stdout);
|
||||
nir_print_shader(nir, stdout);
|
||||
}
|
||||
|
||||
return true;
|
||||
#if !defined(NDEBUG)
|
||||
nir_debug_print_shader[nir->info.stage] = nir_debug_print_shader_prev;
|
||||
#endif /* !defined(NDEBUG) */
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Converts a SPIR-V shader to NIR.
|
||||
*
|
||||
* \param[in] ctx Shared multi-stage build context.
|
||||
* \param[in] entry Shader entry-point function name.
|
||||
* \param[in] stage Shader stage.
|
||||
* \param[in] spirv_size SPIR-V data length in DWORDs.
|
||||
* \param[in] spirv_data SPIR-V data.
|
||||
* \param[in] num_spec Number of SPIR-V specializations.
|
||||
* \param[in] spec SPIR-V specializations.
|
||||
* \return A nir_shader* if successful, or NULL if unsuccessful.
|
||||
*/
|
||||
PUBLIC
|
||||
nir_shader *rogue_spirv_to_nir(rogue_build_ctx *ctx,
|
||||
gl_shader_stage stage,
|
||||
const char *entry,
|
||||
unsigned spirv_size,
|
||||
const uint32_t *spirv_data,
|
||||
unsigned num_spec,
|
||||
struct nir_spirv_specialization *spec)
|
||||
{
|
||||
nir_shader *nir;
|
||||
|
||||
nir = spirv_to_nir(spirv_data,
|
||||
spirv_size,
|
||||
spec,
|
||||
num_spec,
|
||||
stage,
|
||||
entry,
|
||||
&spirv_options,
|
||||
&nir_options);
|
||||
if (!nir)
|
||||
return NULL;
|
||||
|
||||
ralloc_steal(ctx, nir);
|
||||
|
||||
/* Apply passes. */
|
||||
rogue_nir_passes(ctx, nir, stage);
|
||||
|
||||
/* Collect I/O data to pass back to the driver. */
|
||||
rogue_collect_io_data(ctx, nir);
|
||||
|
||||
return nir;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_NIR_H
|
||||
#define ROGUE_NIR_H
|
||||
|
||||
#include "compiler/shader_enums.h"
|
||||
#include "nir/nir.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
struct rogue_build_ctx;
|
||||
struct rogue_compiler;
|
||||
struct spirv_to_nir_options;
|
||||
|
||||
PUBLIC
|
||||
const struct spirv_to_nir_options *
|
||||
rogue_get_spirv_options(const struct rogue_compiler *compiler);
|
||||
|
||||
PUBLIC
|
||||
const nir_shader_compiler_options *
|
||||
rogue_get_compiler_options(const struct rogue_compiler *compiler);
|
||||
|
||||
bool rogue_nir_passes(struct rogue_build_ctx *ctx,
|
||||
nir_shader *nir,
|
||||
gl_shader_stage stage);
|
||||
|
||||
/* Custom passes. */
|
||||
void rogue_nir_pfo(nir_shader *shader);
|
||||
void rogue_nir_constreg(nir_shader *shader);
|
||||
bool rogue_nir_lower_io(nir_shader *shader, void *layout);
|
||||
|
||||
#endif /* ROGUE_NIR_H */
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_NIR_HELPERS_H
|
||||
#define ROGUE_NIR_HELPERS_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "nir/nir.h"
|
||||
#include "util/bitscan.h"
|
||||
|
||||
/**
|
||||
* \file rogue_nir.c
|
||||
*
|
||||
* \brief Contains various NIR helper functions.
|
||||
*/
|
||||
|
||||
static inline unsigned nir_alu_dest_regindex(const nir_alu_instr *alu)
|
||||
{
|
||||
assert(!alu->dest.dest.is_ssa);
|
||||
|
||||
return alu->dest.dest.reg.reg->index;
|
||||
}
|
||||
|
||||
static inline unsigned nir_alu_dest_comp(const nir_alu_instr *alu)
|
||||
{
|
||||
assert(!alu->dest.dest.is_ssa);
|
||||
assert(util_is_power_of_two_nonzero(alu->dest.write_mask));
|
||||
|
||||
return ffs(alu->dest.write_mask) - 1;
|
||||
}
|
||||
|
||||
static inline unsigned nir_alu_src_regindex(const nir_alu_instr *alu,
|
||||
size_t src)
|
||||
{
|
||||
assert(src < nir_op_infos[alu->op].num_inputs);
|
||||
assert(!alu->src[src].src.is_ssa);
|
||||
|
||||
return alu->src[src].src.reg.reg->index;
|
||||
}
|
||||
|
||||
static inline uint32_t nir_alu_src_const(const nir_alu_instr *alu, size_t src)
|
||||
{
|
||||
assert(src < nir_op_infos[alu->op].num_inputs);
|
||||
assert(alu->src[src].src.is_ssa);
|
||||
|
||||
nir_const_value *const_value = nir_src_as_const_value(alu->src[src].src);
|
||||
|
||||
return nir_const_value_as_uint(*const_value, 32);
|
||||
}
|
||||
|
||||
static inline bool nir_alu_src_is_const(const nir_alu_instr *alu, size_t src)
|
||||
{
|
||||
assert(src < nir_op_infos[alu->op].num_inputs);
|
||||
|
||||
if (!alu->src[src].src.is_ssa)
|
||||
return false;
|
||||
|
||||
assert(alu->src[src].src.ssa->parent_instr);
|
||||
|
||||
return (alu->src[src].src.ssa->parent_instr->type ==
|
||||
nir_instr_type_load_const);
|
||||
}
|
||||
|
||||
static inline unsigned nir_intr_dest_regindex(const nir_intrinsic_instr *intr)
|
||||
{
|
||||
assert(!intr->dest.is_ssa);
|
||||
|
||||
return intr->dest.reg.reg->index;
|
||||
}
|
||||
|
||||
static inline unsigned nir_intr_src_regindex(const nir_intrinsic_instr *intr,
|
||||
size_t src)
|
||||
{
|
||||
assert(src < nir_intrinsic_infos[intr->intrinsic].num_srcs);
|
||||
assert(!intr->src[src].is_ssa);
|
||||
|
||||
return intr->src[src].reg.reg->index;
|
||||
}
|
||||
|
||||
static inline uint32_t nir_intr_src_const(const nir_intrinsic_instr *intr,
|
||||
size_t src)
|
||||
{
|
||||
assert(src < nir_intrinsic_infos[intr->intrinsic].num_srcs);
|
||||
assert(intr->src[src].is_ssa);
|
||||
|
||||
nir_const_value *const_value = nir_src_as_const_value(intr->src[src]);
|
||||
|
||||
return nir_const_value_as_uint(*const_value, 32);
|
||||
}
|
||||
|
||||
static inline uint32_t nir_intr_src_comp_const(const nir_intrinsic_instr *intr,
|
||||
size_t src,
|
||||
size_t comp)
|
||||
{
|
||||
assert(src < nir_intrinsic_infos[intr->intrinsic].num_srcs);
|
||||
assert(intr->src[src].is_ssa);
|
||||
assert(comp < nir_src_num_components(intr->src[src]));
|
||||
|
||||
return nir_src_comp_as_uint(intr->src[src], comp);
|
||||
}
|
||||
|
||||
static inline bool nir_intr_src_is_const(const nir_intrinsic_instr *intr,
|
||||
size_t src)
|
||||
{
|
||||
assert(src < nir_intrinsic_infos[intr->intrinsic].num_srcs);
|
||||
|
||||
if (!intr->src[src].is_ssa)
|
||||
return false;
|
||||
|
||||
assert(intr->src[src].ssa->parent_instr);
|
||||
|
||||
return (intr->src[src].ssa->parent_instr->type == nir_instr_type_load_const);
|
||||
}
|
||||
|
||||
static inline size_t nir_count_variables_with_modes(const nir_shader *nir,
|
||||
nir_variable_mode mode)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
nir_foreach_variable_with_modes (var, nir, mode)
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif /* ROGUE_NIR_HELPERS_H */
|
||||
|
|
@ -1,158 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_OPERAND_H
|
||||
#define ROGUE_OPERAND_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rogue_util.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
/* Register-related defines. */
|
||||
|
||||
/* Total max number of registers per class
|
||||
* (instances > ROGUE_MAX_REG_INDEX addressable via indexing only).
|
||||
*/
|
||||
#define ROGUE_MAX_REG_TEMP 248
|
||||
#define ROGUE_MAX_REG_COEFF 4096
|
||||
#define ROGUE_MAX_REG_CONST 240
|
||||
#define ROGUE_MAX_REG_SHARED 4096
|
||||
#define ROGUE_MAX_REG_PIXEL_OUT 8
|
||||
#define ROGUE_MAX_REG_VERTEX_IN 248
|
||||
#define ROGUE_MAX_REG_INTERNAL 8
|
||||
|
||||
/* Maximum register index via offset encoding. */
|
||||
#define ROGUE_MAX_REG_INDEX 256
|
||||
|
||||
/* Pixel-out register offset. */
|
||||
#define ROGUE_PIXEL_OUT_REG_OFFSET 32
|
||||
|
||||
/* Internal register offset. */
|
||||
#define ROGUE_INTERNAL_REG_OFFSET 36
|
||||
|
||||
/* Coefficient registers are typically used in groups of 4. */
|
||||
#define ROGUE_COEFF_ALIGN 4
|
||||
|
||||
/* Defines for other operand types. */
|
||||
|
||||
/* Available dependent read counters. */
|
||||
#define ROGUE_NUM_DRCS 2
|
||||
|
||||
/* Maximum number of vertex outputs. */
|
||||
#define ROGUE_MAX_VERTEX_OUTPUTS 256
|
||||
|
||||
/* All components of an emulated vec4 register group. */
|
||||
#define ROGUE_COMPONENT_ALL (~0)
|
||||
|
||||
/**
|
||||
* \brief Operand types.
|
||||
*/
|
||||
enum rogue_operand_type {
|
||||
/* Register operands. */
|
||||
ROGUE_OPERAND_TYPE_REG_TEMP = 0, /** Temporary register. */
|
||||
ROGUE_OPERAND_TYPE_REG_COEFF, /** Coefficient register. */
|
||||
ROGUE_OPERAND_TYPE_REG_CONST, /** Constant register. */
|
||||
ROGUE_OPERAND_TYPE_REG_SHARED, /** Shared register. */
|
||||
ROGUE_OPERAND_TYPE_REG_PIXEL_OUT, /** Pixel output register. */
|
||||
ROGUE_OPERAND_TYPE_REG_VERTEX_IN, /** Vertex input register. */
|
||||
ROGUE_OPERAND_TYPE_REG_INTERNAL, /** Internal register. */
|
||||
|
||||
ROGUE_OPERAND_TYPE_REG_MAX = ROGUE_OPERAND_TYPE_REG_INTERNAL,
|
||||
|
||||
ROGUE_OPERAND_TYPE_IMMEDIATE, /** Immediate value. */
|
||||
|
||||
ROGUE_OPERAND_TYPE_DRC, /** Dependent read counter. */
|
||||
|
||||
ROGUE_OPERAND_TYPE_VREG, /** Virtual register (pre-regalloc). */
|
||||
|
||||
ROGUE_OPERAND_TYPE_COUNT,
|
||||
};
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
#define ROGUE_NUM_REG_TYPES (ROGUE_OPERAND_TYPE_REG_MAX + 1)
|
||||
|
||||
/**
|
||||
* \brief A bitmask for any register operand type.
|
||||
*/
|
||||
#define ROGUE_MASK_ANY_REG \
|
||||
ROH(ROGUE_OPERAND_TYPE_REG_TEMP) | \
|
||||
ROH(ROGUE_OPERAND_TYPE_REG_COEFF) | \
|
||||
ROH(ROGUE_OPERAND_TYPE_REG_CONST) | \
|
||||
ROH(ROGUE_OPERAND_TYPE_REG_PIXEL_OUT) | \
|
||||
ROH(ROGUE_OPERAND_TYPE_REG_VERTEX_IN) | \
|
||||
ROH(ROGUE_OPERAND_TYPE_REG_SHARED) | \
|
||||
ROH(ROGUE_OPERAND_TYPE_REG_INTERNAL)
|
||||
|
||||
/* clang-format on */
|
||||
|
||||
/**
|
||||
* \brief Operand description.
|
||||
*/
|
||||
struct rogue_operand {
|
||||
enum rogue_operand_type type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
uint64_t value;
|
||||
} immediate;
|
||||
|
||||
struct {
|
||||
size_t number;
|
||||
} drc;
|
||||
|
||||
struct {
|
||||
size_t number;
|
||||
} reg;
|
||||
|
||||
struct {
|
||||
size_t number;
|
||||
bool is_vector;
|
||||
size_t component;
|
||||
} vreg;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Register access flags.
|
||||
*/
|
||||
enum rogue_register_access {
|
||||
ROGUE_REG_ACCESS_READ = BITFIELD_BIT(0U), /** Read-only. */
|
||||
ROGUE_REG_ACCESS_WRITE = BITFIELD_BIT(1U), /* Write-only. */
|
||||
ROGUE_REG_ACCESS_RW = ROGUE_REG_ACCESS_READ |
|
||||
ROGUE_REG_ACCESS_WRITE, /** Read/write. */
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Register modifier flags.
|
||||
*/
|
||||
enum rogue_register_modifier {
|
||||
ROGUE_REG_MOD_NONE = 0U,
|
||||
ROGUE_REG_MOD_IDX = BITFIELD_BIT(0U), /** Index modifier. */
|
||||
ROGUE_REG_MOD_DIM = BITFIELD_BIT(1U), /** Dimension modifier. */
|
||||
ROGUE_REG_MOD_ALL = ROGUE_REG_MOD_IDX | ROGUE_REG_MOD_DIM,
|
||||
};
|
||||
|
||||
#endif /* ROGUE_OPERAND_H */
|
||||
751
src/imagination/rogue/rogue_print.c
Normal file
751
src/imagination/rogue/rogue_print.c
Normal file
|
|
@ -0,0 +1,751 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 "compiler/shader_enums.h"
|
||||
#include "rogue.h"
|
||||
#include "util/bitscan.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file rogue_print.c
|
||||
*
|
||||
* \brief Contains functions to print Rogue IR types and structures.
|
||||
*/
|
||||
|
||||
/* TODO NEXT: Go through and make types the same, i.e. decide on using ONLY
|
||||
* unsigned, uint32/64_t, etc., and then use inttypes if so */
|
||||
/* TODO NEXT: Make fp the last argument. */
|
||||
|
||||
enum color_esc {
|
||||
ESC_RESET = 0,
|
||||
ESC_BLACK,
|
||||
ESC_RED,
|
||||
ESC_GREEN,
|
||||
ESC_YELLOW,
|
||||
ESC_BLUE,
|
||||
ESC_PURPLE,
|
||||
ESC_CYAN,
|
||||
ESC_WHITE,
|
||||
|
||||
ESC_COUNT,
|
||||
};
|
||||
|
||||
static
|
||||
const char *color_esc[2][ESC_COUNT] = {
|
||||
[0] = {
|
||||
[ESC_RESET] = "",
|
||||
[ESC_BLACK] = "",
|
||||
[ESC_RED] = "",
|
||||
[ESC_GREEN] = "",
|
||||
[ESC_YELLOW] = "",
|
||||
[ESC_BLUE] = "",
|
||||
[ESC_PURPLE] = "",
|
||||
[ESC_CYAN] = "",
|
||||
[ESC_WHITE] = "",
|
||||
},
|
||||
[1] = {
|
||||
[ESC_RESET] = "\033[0m",
|
||||
[ESC_BLACK] = "\033[0;30m",
|
||||
[ESC_RED] = "\033[0;31m",
|
||||
[ESC_GREEN] = "\033[0;32m",
|
||||
[ESC_YELLOW] = "\033[0;33m",
|
||||
[ESC_BLUE] = "\033[0;34m",
|
||||
[ESC_PURPLE] = "\033[0;35m",
|
||||
[ESC_CYAN] = "\033[0;36m",
|
||||
[ESC_WHITE] = "\033[0;37m",
|
||||
},
|
||||
};
|
||||
|
||||
static inline void RESET(FILE *fp)
|
||||
{
|
||||
fputs(color_esc[rogue_color][ESC_RESET], fp);
|
||||
}
|
||||
|
||||
static inline void BLACK(FILE *fp)
|
||||
{
|
||||
fputs(color_esc[rogue_color][ESC_BLACK], fp);
|
||||
}
|
||||
|
||||
static inline void RED(FILE *fp)
|
||||
{
|
||||
fputs(color_esc[rogue_color][ESC_RED], fp);
|
||||
}
|
||||
|
||||
static inline void GREEN(FILE *fp)
|
||||
{
|
||||
fputs(color_esc[rogue_color][ESC_GREEN], fp);
|
||||
}
|
||||
|
||||
static inline void YELLOW(FILE *fp)
|
||||
{
|
||||
fputs(color_esc[rogue_color][ESC_YELLOW], fp);
|
||||
}
|
||||
|
||||
static inline void BLUE(FILE *fp)
|
||||
{
|
||||
fputs(color_esc[rogue_color][ESC_BLUE], fp);
|
||||
}
|
||||
|
||||
static inline void PURPLE(FILE *fp)
|
||||
{
|
||||
fputs(color_esc[rogue_color][ESC_PURPLE], fp);
|
||||
}
|
||||
|
||||
static inline void CYAN(FILE *fp)
|
||||
{
|
||||
fputs(color_esc[rogue_color][ESC_CYAN], fp);
|
||||
}
|
||||
|
||||
static inline void WHITE(FILE *fp)
|
||||
{
|
||||
fputs(color_esc[rogue_color][ESC_WHITE], fp);
|
||||
}
|
||||
|
||||
static inline void rogue_print_val(FILE *fp, unsigned val)
|
||||
{
|
||||
PURPLE(fp);
|
||||
fprintf(fp, "%u", val);
|
||||
RESET(fp);
|
||||
}
|
||||
|
||||
static inline void rogue_print_reg(FILE *fp, const rogue_reg *reg)
|
||||
{
|
||||
const rogue_reg_info *info = &rogue_reg_infos[reg->class];
|
||||
YELLOW(fp);
|
||||
fprintf(fp, "%s%" PRIu32, info->str, reg->index);
|
||||
RESET(fp);
|
||||
}
|
||||
|
||||
static inline void rogue_print_regarray(FILE *fp,
|
||||
const rogue_regarray *regarray)
|
||||
{
|
||||
const rogue_reg *reg = regarray->regs[0];
|
||||
const rogue_reg_info *info = &rogue_reg_infos[reg->class];
|
||||
YELLOW(fp);
|
||||
fprintf(fp, "%s%" PRIu32, info->str, reg->index);
|
||||
RESET(fp);
|
||||
fputs("-", fp);
|
||||
YELLOW(fp);
|
||||
fprintf(fp, "%" PRIu32, regarray->size + reg->index - 1);
|
||||
RESET(fp);
|
||||
}
|
||||
|
||||
static inline void rogue_print_imm(FILE *fp, const rogue_imm *imm)
|
||||
{
|
||||
PURPLE(fp);
|
||||
fprintf(fp, "0x%" PRIx32, imm->imm.u32);
|
||||
RESET(fp);
|
||||
}
|
||||
|
||||
static inline void rogue_print_io(FILE *fp, enum rogue_io io)
|
||||
{
|
||||
const rogue_io_info *info = &rogue_io_infos[io];
|
||||
BLUE(fp);
|
||||
fprintf(fp, "%s", info->str);
|
||||
RESET(fp);
|
||||
}
|
||||
|
||||
static inline void rogue_print_drc(FILE *fp, const rogue_drc *drc)
|
||||
{
|
||||
RED(fp);
|
||||
fprintf(fp, "drc%u", drc->index);
|
||||
RESET(fp);
|
||||
}
|
||||
|
||||
static inline void rogue_print_ref(FILE *fp, const rogue_ref *ref)
|
||||
{
|
||||
switch (ref->type) {
|
||||
case ROGUE_REF_TYPE_VAL:
|
||||
rogue_print_val(fp, ref->val);
|
||||
break;
|
||||
|
||||
case ROGUE_REF_TYPE_REG:
|
||||
rogue_print_reg(fp, ref->reg);
|
||||
break;
|
||||
|
||||
case ROGUE_REF_TYPE_REGARRAY:
|
||||
rogue_print_regarray(fp, ref->regarray);
|
||||
break;
|
||||
|
||||
case ROGUE_REF_TYPE_IMM:
|
||||
rogue_print_imm(fp, &ref->imm);
|
||||
break;
|
||||
|
||||
case ROGUE_REF_TYPE_IO:
|
||||
rogue_print_io(fp, ref->io);
|
||||
break;
|
||||
|
||||
case ROGUE_REF_TYPE_DRC:
|
||||
rogue_print_drc(fp, &ref->drc);
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Invalid ref type.");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rogue_print_alu_dst(FILE *fp, const rogue_alu_dst *dst)
|
||||
{
|
||||
rogue_print_ref(fp, &dst->ref);
|
||||
|
||||
uint64_t mod = dst->mod;
|
||||
while (mod) {
|
||||
enum rogue_alu_dst_mod dst_mod = u_bit_scan64(&mod);
|
||||
assert(dst_mod < ROGUE_ALU_DST_MOD_COUNT);
|
||||
fprintf(fp, ".%s", rogue_alu_dst_mod_infos[dst_mod].str);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rogue_print_alu_src(FILE *fp, const rogue_alu_src *src)
|
||||
{
|
||||
rogue_print_ref(fp, &src->ref);
|
||||
|
||||
uint64_t mod = src->mod;
|
||||
while (mod) {
|
||||
enum rogue_alu_src_mod src_mod = u_bit_scan64(&mod);
|
||||
assert(src_mod < ROGUE_ALU_SRC_MOD_COUNT);
|
||||
fprintf(fp, ".%s", rogue_alu_src_mod_infos[src_mod].str);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rogue_print_alu_mods(FILE *fp, const rogue_alu_instr *alu)
|
||||
{
|
||||
uint64_t mod = alu->mod;
|
||||
while (mod) {
|
||||
enum rogue_alu_op_mod op_mod = u_bit_scan64(&mod);
|
||||
assert(op_mod < ROGUE_ALU_OP_MOD_COUNT);
|
||||
fprintf(fp, ".%s", rogue_alu_op_mod_infos[op_mod].str);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rogue_print_alu_instr(FILE *fp, const rogue_alu_instr *alu)
|
||||
{
|
||||
const rogue_alu_op_info *info = &rogue_alu_op_infos[alu->op];
|
||||
|
||||
/* TODO: Print conditional info once supported. */
|
||||
|
||||
fprintf(fp, "%s", info->str);
|
||||
|
||||
if (alu->op == ROGUE_ALU_OP_TST) {
|
||||
fprintf(fp, "%s", rogue_comp_test_str[alu->comp_test]);
|
||||
fprintf(fp, ".%s", rogue_comp_type_str[alu->comp_type]);
|
||||
}
|
||||
|
||||
rogue_print_alu_mods(fp, alu);
|
||||
|
||||
fputs(" ", fp);
|
||||
|
||||
rogue_print_alu_dst(fp, &alu->dst);
|
||||
|
||||
for (unsigned i = 0; i < info->num_srcs; ++i) {
|
||||
fputs(", ", fp);
|
||||
rogue_print_alu_src(fp, &alu->src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rogue_print_block_label(FILE *fp, const rogue_block *block)
|
||||
{
|
||||
/* For debug purposes. */
|
||||
if (block->label)
|
||||
fprintf(fp, "%s", block->label);
|
||||
else
|
||||
fprintf(fp, "block%u", block->index);
|
||||
}
|
||||
|
||||
static inline void rogue_print_backend_dst(FILE *fp,
|
||||
const rogue_backend_dst *dst)
|
||||
{
|
||||
rogue_print_ref(fp, &dst->ref);
|
||||
}
|
||||
|
||||
static inline void rogue_print_backend_src(FILE *fp,
|
||||
const rogue_backend_src *src)
|
||||
{
|
||||
rogue_print_ref(fp, &src->ref);
|
||||
}
|
||||
|
||||
static inline void rogue_print_backend_mods(FILE *fp,
|
||||
const rogue_backend_instr *backend)
|
||||
{
|
||||
uint64_t mod = backend->mod;
|
||||
while (mod) {
|
||||
enum rogue_backend_op_mod op_mod = u_bit_scan64(&mod);
|
||||
assert(op_mod < ROGUE_BACKEND_OP_MOD_COUNT);
|
||||
fprintf(fp, ".%s", rogue_backend_op_mod_infos[op_mod].str);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rogue_print_backend_instr(FILE *fp,
|
||||
const rogue_backend_instr *backend)
|
||||
{
|
||||
const rogue_backend_op_info *info = &rogue_backend_op_infos[backend->op];
|
||||
|
||||
fprintf(fp, "%s", info->str);
|
||||
|
||||
rogue_print_backend_mods(fp, backend);
|
||||
|
||||
for (unsigned i = 0; i < info->num_dsts; ++i) {
|
||||
if (i > 0)
|
||||
fputs(",", fp);
|
||||
|
||||
fputs(" ", fp);
|
||||
|
||||
rogue_print_backend_dst(fp, &backend->dst[i]);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < info->num_srcs; ++i) {
|
||||
if (i == 0 && !info->num_dsts)
|
||||
fputs(" ", fp);
|
||||
else
|
||||
fputs(", ", fp);
|
||||
|
||||
rogue_print_backend_src(fp, &backend->src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rogue_print_ctrl_mods(FILE *fp, const rogue_ctrl_instr *ctrl)
|
||||
{
|
||||
uint64_t mod = ctrl->mod;
|
||||
while (mod) {
|
||||
enum rogue_ctrl_op_mod op_mod = u_bit_scan64(&mod);
|
||||
assert(op_mod < ROGUE_CTRL_OP_MOD_COUNT);
|
||||
fprintf(fp, ".%s", rogue_ctrl_op_mod_infos[op_mod].str);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void rogue_print_ctrl_src(FILE *fp, const rogue_ctrl_src *src)
|
||||
{
|
||||
rogue_print_ref(fp, &src->ref);
|
||||
}
|
||||
|
||||
static inline void rogue_print_ctrl_instr(FILE *fp,
|
||||
const rogue_ctrl_instr *ctrl)
|
||||
{
|
||||
const rogue_ctrl_op_info *info = &rogue_ctrl_op_infos[ctrl->op];
|
||||
|
||||
/* TODO: Print conditional info once supported. */
|
||||
|
||||
fprintf(fp, "%s", info->str);
|
||||
|
||||
rogue_print_ctrl_mods(fp, ctrl);
|
||||
|
||||
if (ctrl->target_block) {
|
||||
fputs(" ", fp);
|
||||
rogue_print_block_label(fp, ctrl->target_block);
|
||||
}
|
||||
|
||||
/* TODO NEXT: Dests. */
|
||||
/* TODO: Special case for the conditional ctrl instructions as they're
|
||||
* printed as source 0, then dest, then rest of the sources. */
|
||||
|
||||
for (unsigned i = 0; i < info->num_srcs; ++i) {
|
||||
if (i == 0 && !info->num_dsts)
|
||||
fputs(" ", fp);
|
||||
else
|
||||
fputs(", ", fp);
|
||||
|
||||
rogue_print_ctrl_src(fp, &ctrl->src[i]);
|
||||
}
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
void rogue_print_instr(FILE *fp, const rogue_instr *instr)
|
||||
{
|
||||
if (instr->repeat > 1)
|
||||
fprintf(fp, "(rpt%u) ", instr->repeat);
|
||||
|
||||
GREEN(fp);
|
||||
switch (instr->type) {
|
||||
case ROGUE_INSTR_TYPE_ALU:
|
||||
rogue_print_alu_instr(fp, rogue_instr_as_alu(instr));
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_BACKEND:
|
||||
rogue_print_backend_instr(fp, rogue_instr_as_backend(instr));
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_CTRL:
|
||||
rogue_print_ctrl_instr(fp, rogue_instr_as_ctrl(instr));
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Invalid instruction type.");
|
||||
}
|
||||
RESET(fp);
|
||||
|
||||
if (instr->end)
|
||||
fputs(".end", fp);
|
||||
|
||||
/* For debug purposes. */
|
||||
fputs(";", fp);
|
||||
|
||||
if (instr->comment)
|
||||
fprintf(fp, " /* %s */", instr->comment);
|
||||
}
|
||||
|
||||
/* TODO NEXT: Split this up into separate functions for printing lower srcs,
|
||||
* upper srcs, etc. since we'd want to print them in-between instructions. */
|
||||
/* TODO NEXT: Commonise with printing the ref io stuff. */
|
||||
static inline void
|
||||
rogue_print_instr_group_io_sel(FILE *fp, const rogue_instr_group_io_sel *io_sel)
|
||||
{
|
||||
bool present = false;
|
||||
|
||||
fputs(" ", fp);
|
||||
|
||||
/* TODO NEXT: Commonise this code!! */
|
||||
/* Print upper and lower sources. */
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(io_sel->srcs); ++i) {
|
||||
if (rogue_ref_is_null(&io_sel->srcs[i]))
|
||||
continue;
|
||||
|
||||
if (present && i > 0)
|
||||
fputs(", ", fp);
|
||||
|
||||
present = true;
|
||||
|
||||
rogue_print_io(fp, ROGUE_IO_S0 + i);
|
||||
fputs("=", fp);
|
||||
|
||||
if (rogue_ref_is_reg(&io_sel->srcs[i]))
|
||||
rogue_print_reg(fp, io_sel->srcs[i].reg);
|
||||
else if (rogue_ref_is_regarray(&io_sel->srcs[i]))
|
||||
rogue_print_regarray(fp, io_sel->srcs[i].regarray);
|
||||
else if (rogue_ref_is_io(&io_sel->srcs[i]))
|
||||
rogue_print_io(fp, io_sel->srcs[i].io);
|
||||
else
|
||||
unreachable("Invalid src map.");
|
||||
}
|
||||
if (present)
|
||||
fputs(" ", fp);
|
||||
|
||||
/* Print internal sources. */
|
||||
present = false;
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(io_sel->iss); ++i) {
|
||||
if (rogue_ref_is_null(&io_sel->iss[i]))
|
||||
continue;
|
||||
|
||||
if (present && i > 0)
|
||||
fputs(", ", fp);
|
||||
|
||||
present = true;
|
||||
|
||||
rogue_print_io(fp, ROGUE_IO_IS0 + i);
|
||||
fputs("=", fp);
|
||||
|
||||
if (rogue_ref_is_reg(&io_sel->iss[i]))
|
||||
rogue_print_reg(fp, io_sel->iss[i].reg);
|
||||
else if (rogue_ref_is_regarray(&io_sel->iss[i]))
|
||||
rogue_print_regarray(fp, io_sel->iss[i].regarray);
|
||||
else if (rogue_ref_is_io(&io_sel->iss[i]))
|
||||
rogue_print_io(fp, io_sel->iss[i].io);
|
||||
else
|
||||
unreachable("Invalid iss map.");
|
||||
}
|
||||
if (present)
|
||||
fputs(" ", fp);
|
||||
|
||||
/* Print destinations. */
|
||||
present = false;
|
||||
for (unsigned i = 0; i < ARRAY_SIZE(io_sel->dsts); ++i) {
|
||||
if (rogue_ref_is_null(&io_sel->dsts[i]))
|
||||
continue;
|
||||
|
||||
if (present && i > 0)
|
||||
fputs(", ", fp);
|
||||
|
||||
present = true;
|
||||
|
||||
rogue_print_io(fp, ROGUE_IO_W0 + i);
|
||||
fputs("=", fp);
|
||||
|
||||
if (rogue_ref_is_reg(&io_sel->dsts[i]))
|
||||
rogue_print_reg(fp, io_sel->dsts[i].reg);
|
||||
else if (rogue_ref_is_io(&io_sel->dsts[i]))
|
||||
rogue_print_io(fp, io_sel->dsts[i].io);
|
||||
else
|
||||
unreachable("Invalid dst map.");
|
||||
}
|
||||
if (present)
|
||||
fputs(" ", fp);
|
||||
}
|
||||
|
||||
static inline void rogue_print_instr_phase(FILE *fp,
|
||||
enum rogue_alu alu,
|
||||
enum rogue_instr_phase phase)
|
||||
{
|
||||
const char *phase_str = rogue_instr_phase_str[alu][phase];
|
||||
assert(phase_str);
|
||||
fputs(phase_str, fp);
|
||||
}
|
||||
|
||||
static inline void
|
||||
rogue_print_instr_group_header(FILE *fp, const rogue_instr_group *group)
|
||||
{
|
||||
/* ALU specific */
|
||||
switch (group->header.alu) {
|
||||
case ROGUE_ALU_MAIN:
|
||||
break;
|
||||
|
||||
case ROGUE_ALU_BITWISE:
|
||||
break;
|
||||
|
||||
case ROGUE_ALU_CONTROL:
|
||||
break;
|
||||
|
||||
default:
|
||||
unreachable("Invalid instruction group ALU.");
|
||||
}
|
||||
|
||||
if (group->header.end)
|
||||
fputs(".end", fp);
|
||||
}
|
||||
|
||||
static inline void rogue_print_instr_group(FILE *fp,
|
||||
const rogue_instr_group *group)
|
||||
{
|
||||
/* For debug purposes. */
|
||||
fprintf(fp, "%u", group->index);
|
||||
fputs(": ", fp);
|
||||
|
||||
if (group->header.repeat > 1)
|
||||
fprintf(fp, "(rpt%u) ", group->header.repeat);
|
||||
|
||||
fputs("{ ", fp);
|
||||
|
||||
CYAN(fp);
|
||||
fprintf(fp, "%s ", rogue_alu_str[group->header.alu]);
|
||||
RESET(fp);
|
||||
|
||||
/* Print each instruction. */
|
||||
rogue_foreach_phase_in_set (p, group->header.phases) {
|
||||
const rogue_instr *instr = group->instrs[p];
|
||||
assert(instr);
|
||||
|
||||
rogue_print_instr_phase(fp, group->header.alu, p);
|
||||
fputs(": ", fp);
|
||||
rogue_print_instr(fp, instr);
|
||||
}
|
||||
|
||||
/* Print source/dest mappings (if present). */
|
||||
rogue_print_instr_group_io_sel(fp, &group->io_sel);
|
||||
|
||||
fputs("}", fp);
|
||||
|
||||
/* Print group header info. */
|
||||
rogue_print_instr_group_header(fp, group);
|
||||
}
|
||||
|
||||
static inline void rogue_print_block(FILE *fp, const rogue_block *block)
|
||||
{
|
||||
rogue_print_block_label(fp, block);
|
||||
fputs(":\n", fp);
|
||||
|
||||
if (!block->shader->is_grouped) {
|
||||
rogue_foreach_instr_in_block (instr, block) {
|
||||
fputs("\t", fp);
|
||||
fprintf(fp, "%u", instr->index);
|
||||
fputs(": ", fp);
|
||||
fprintf(fp, "%s: ", rogue_instr_type_str[instr->type]);
|
||||
rogue_print_instr(fp, instr);
|
||||
fputs("\n", fp);
|
||||
}
|
||||
} else {
|
||||
rogue_foreach_instr_group_in_block (group, block) {
|
||||
fputs("\t", fp);
|
||||
rogue_print_instr_group(fp, group);
|
||||
fputs("\n", fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
void rogue_print_shader(FILE *fp, const rogue_shader *shader)
|
||||
{
|
||||
fputs("/*", fp);
|
||||
|
||||
if (shader->name)
|
||||
fprintf(fp, " \"%s\":", shader->name);
|
||||
|
||||
fprintf(fp, " %s shader */\n", _mesa_shader_stage_to_string(shader->stage));
|
||||
|
||||
rogue_foreach_block (block, shader)
|
||||
rogue_print_block(fp, block);
|
||||
}
|
||||
|
||||
static void rogue_print_instr_ref(FILE *fp,
|
||||
const rogue_instr *instr,
|
||||
bool dst,
|
||||
unsigned index,
|
||||
bool is_grouped)
|
||||
{
|
||||
if (is_grouped) {
|
||||
fprintf(fp, "%u", instr->group->index);
|
||||
fputs(": { ", fp);
|
||||
rogue_print_instr_phase(fp, instr->group->header.alu, instr->index);
|
||||
} else {
|
||||
fprintf(fp, "%u", instr->index);
|
||||
if (index != ~0)
|
||||
fputs(": ", fp);
|
||||
}
|
||||
|
||||
if (index != ~0) {
|
||||
BLUE(fp);
|
||||
fprintf(fp, "[%s%u]", dst ? "dst" : "src", index);
|
||||
RESET(fp);
|
||||
}
|
||||
|
||||
if (is_grouped)
|
||||
fputs(" }", fp);
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
void rogue_print_reg_writes(FILE *fp, const rogue_shader *shader)
|
||||
{
|
||||
fputs("/* register writes */\n", fp);
|
||||
for (enum rogue_reg_class class = 0; class < ROGUE_REG_CLASS_COUNT;
|
||||
++class) {
|
||||
rogue_foreach_reg (reg, shader, class) {
|
||||
rogue_print_reg(fp, reg);
|
||||
fputs(":", fp);
|
||||
|
||||
if (list_is_empty(®->writes)) {
|
||||
fputs(" <none>\n", fp);
|
||||
continue;
|
||||
}
|
||||
|
||||
rogue_foreach_reg_write (write, reg) {
|
||||
assert(write->instr);
|
||||
|
||||
fputs(" ", fp);
|
||||
rogue_print_instr_ref(fp,
|
||||
write->instr,
|
||||
true,
|
||||
write->dst_index,
|
||||
shader->is_grouped);
|
||||
}
|
||||
|
||||
fputs("\n", fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
void rogue_print_reg_uses(FILE *fp, const rogue_shader *shader)
|
||||
{
|
||||
fputs("/* register uses */\n", fp);
|
||||
for (enum rogue_reg_class class = 0; class < ROGUE_REG_CLASS_COUNT;
|
||||
++class) {
|
||||
rogue_foreach_reg (reg, shader, class) {
|
||||
rogue_print_reg(fp, reg);
|
||||
fputs(":", fp);
|
||||
|
||||
if (list_is_empty(®->uses)) {
|
||||
fputs(" <none>\n", fp);
|
||||
continue;
|
||||
}
|
||||
|
||||
rogue_foreach_reg_use (use, reg) {
|
||||
assert(use->instr);
|
||||
|
||||
fputs(" ", fp);
|
||||
rogue_print_instr_ref(fp,
|
||||
use->instr,
|
||||
false,
|
||||
use->src_index,
|
||||
shader->is_grouped);
|
||||
}
|
||||
|
||||
fputs("\n", fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
void rogue_print_block_uses(FILE *fp, const rogue_shader *shader)
|
||||
{
|
||||
fputs("/* block uses */\n", fp);
|
||||
rogue_foreach_block (block, shader) {
|
||||
rogue_print_block_label(fp, block);
|
||||
fputs(":", fp);
|
||||
|
||||
if (list_is_empty(&block->uses)) {
|
||||
if (list_first_entry(&shader->blocks, rogue_block, link) == block)
|
||||
fputs(" <entry>\n", fp);
|
||||
else
|
||||
fputs(" <none>\n", fp);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
rogue_foreach_block_use (use, block) {
|
||||
assert(use->instr);
|
||||
|
||||
fputs(" ", fp);
|
||||
rogue_print_instr_ref(fp, use->instr, false, ~0, shader->is_grouped);
|
||||
}
|
||||
|
||||
fputs("\n", fp);
|
||||
}
|
||||
}
|
||||
|
||||
static void rogue_print_drc_trxn(FILE *fp,
|
||||
const rogue_shader *shader,
|
||||
const rogue_drc_trxn *drc_trxn,
|
||||
unsigned index)
|
||||
{
|
||||
fprintf(fp, "drc%u: ack: ", index);
|
||||
|
||||
rogue_print_instr_ref(fp, drc_trxn->acquire, false, ~0, shader->is_grouped);
|
||||
|
||||
fputs(", rel: ", fp);
|
||||
|
||||
if (drc_trxn->release) {
|
||||
rogue_print_instr_ref(fp,
|
||||
drc_trxn->release,
|
||||
false,
|
||||
~0,
|
||||
shader->is_grouped);
|
||||
} else {
|
||||
fputs("<none>", fp);
|
||||
}
|
||||
|
||||
fputs("\n", fp);
|
||||
}
|
||||
|
||||
PUBLIC
|
||||
void rogue_print_drc_trxns(FILE *fp, const rogue_shader *shader)
|
||||
{
|
||||
fputs("/* DRC transactions */\n", fp);
|
||||
|
||||
rogue_foreach_drc_trxn (drc_trxn, shader, 0) {
|
||||
rogue_print_drc_trxn(fp, shader, drc_trxn, 0);
|
||||
}
|
||||
|
||||
rogue_foreach_drc_trxn (drc_trxn, shader, 1) {
|
||||
rogue_print_drc_trxn(fp, shader, drc_trxn, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,313 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rogue_operand.h"
|
||||
#include "rogue_regalloc.h"
|
||||
#include "rogue_shader.h"
|
||||
#include "rogue_util.h"
|
||||
#include "util/hash_table.h"
|
||||
#include "util/list.h"
|
||||
#include "util/ralloc.h"
|
||||
#include "util/register_allocate.h"
|
||||
#include "util/u_dynarray.h"
|
||||
|
||||
/**
|
||||
* \file rogue_regalloc.c
|
||||
*
|
||||
* \brief Contains register allocation helper functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Sets up the register data with the classes to be used for allocation.
|
||||
*
|
||||
* \param[in] data The register data array.
|
||||
*/
|
||||
static void
|
||||
rogue_reg_data_init(struct rogue_reg_data data[static ROGUE_REG_CLASS_COUNT])
|
||||
{
|
||||
data[ROGUE_REG_CLASS_TEMP].type = ROGUE_OPERAND_TYPE_REG_TEMP;
|
||||
data[ROGUE_REG_CLASS_TEMP].count = ROGUE_MAX_REG_TEMP;
|
||||
data[ROGUE_REG_CLASS_TEMP].stride = 1;
|
||||
|
||||
data[ROGUE_REG_CLASS_VEC4].type = ROGUE_OPERAND_TYPE_REG_INTERNAL;
|
||||
data[ROGUE_REG_CLASS_VEC4].count = ROGUE_MAX_REG_INTERNAL;
|
||||
data[ROGUE_REG_CLASS_VEC4].stride = 4;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initializes the Rogue register allocation context.
|
||||
*
|
||||
* \param[in] mem_ctx The memory context for the ra context.
|
||||
* \return A rogue_ra * if successful, or NULL if unsuccessful.
|
||||
*/
|
||||
struct rogue_ra *rogue_ra_init(void *mem_ctx)
|
||||
{
|
||||
struct rogue_ra *ra;
|
||||
size_t total_regs = 0;
|
||||
|
||||
ra = rzalloc_size(mem_ctx, sizeof(*ra));
|
||||
if (!ra)
|
||||
return NULL;
|
||||
|
||||
/* Initialize the register class data. */
|
||||
rogue_reg_data_init(ra->reg_data);
|
||||
|
||||
/* Count up the registers classes and set up their offsets.
|
||||
*
|
||||
* The physical register numbers are sequential, even if the
|
||||
* registers are from different banks, so keeping track of
|
||||
* the offset means we can get the true physical register
|
||||
* number back after allocation.
|
||||
*/
|
||||
for (size_t u = 0; u < ARRAY_SIZE(ra->reg_data); ++u) {
|
||||
ra->reg_data[u].offset = total_regs;
|
||||
total_regs += ra->reg_data[u].count;
|
||||
}
|
||||
|
||||
/* Create a register set for allocation. */
|
||||
ra->regs = ra_alloc_reg_set(ra, total_regs, true);
|
||||
if (!ra->regs) {
|
||||
ralloc_free(ra);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the register class for the temps. */
|
||||
ra->reg_data[ROGUE_REG_CLASS_TEMP].class =
|
||||
ra_alloc_contig_reg_class(ra->regs, 1);
|
||||
|
||||
/* Create the register class for vec4 registers
|
||||
* (using the internal register bank).
|
||||
*/
|
||||
ra->reg_data[ROGUE_REG_CLASS_VEC4].class =
|
||||
ra_alloc_contig_reg_class(ra->regs, 4);
|
||||
|
||||
/* Populate the register classes. */
|
||||
for (size_t u = 0; u < ARRAY_SIZE(ra->reg_data); ++u) {
|
||||
struct rogue_reg_data *reg_data = &ra->reg_data[u];
|
||||
size_t offset = reg_data->offset;
|
||||
size_t end = reg_data->offset + reg_data->count;
|
||||
size_t stride = reg_data->stride;
|
||||
|
||||
for (size_t r = offset; r < end; r += stride)
|
||||
ra_class_add_reg(reg_data->class, r);
|
||||
}
|
||||
|
||||
/* Finalize the set (no early conflicts passed along for now). */
|
||||
ra_set_finalize(ra->regs, NULL);
|
||||
|
||||
return ra;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief The range for which a (virtual) register is live, and its references.
|
||||
*/
|
||||
struct live_range {
|
||||
size_t start;
|
||||
size_t end;
|
||||
enum rogue_reg_class class;
|
||||
struct util_dynarray operand_refs;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Performs register allocation.
|
||||
*
|
||||
* \param[in] instr_list A linked list of instructions with virtual registers to
|
||||
* be allocated.
|
||||
* \param[in] ra The register allocation context.
|
||||
*/
|
||||
bool rogue_ra_alloc(struct list_head *instr_list,
|
||||
struct rogue_ra *ra,
|
||||
size_t *temps_used,
|
||||
size_t *internals_used)
|
||||
{
|
||||
/* Used for ra_alloc_interference_graph() as it doesn't
|
||||
* like having gaps (e.g. with v0, v2 count = 3 rather
|
||||
* than 2).
|
||||
*/
|
||||
size_t max_vreg = 0;
|
||||
|
||||
struct hash_table *reg_ht =
|
||||
_mesa_hash_table_create(ra, _mesa_hash_uint, _mesa_key_uint_equal);
|
||||
if (!reg_ht)
|
||||
return false;
|
||||
|
||||
/* Calculate live ranges for virtual registers. */
|
||||
size_t ip = 0U; /* "Instruction pointer". */
|
||||
foreach_instr (instr, instr_list) {
|
||||
for (size_t u = 0U; u < instr->num_operands; ++u) {
|
||||
struct hash_entry *entry;
|
||||
struct live_range *range;
|
||||
|
||||
if (instr->operands[u].type != ROGUE_OPERAND_TYPE_VREG)
|
||||
continue;
|
||||
|
||||
entry =
|
||||
_mesa_hash_table_search(reg_ht, &instr->operands[u].vreg.number);
|
||||
if (!entry) {
|
||||
/* First use of this virtual register: initialize live range. */
|
||||
/* TODO: Error handling. */
|
||||
range = rzalloc_size(reg_ht, sizeof(*range));
|
||||
|
||||
range->start = ip;
|
||||
range->end = ip;
|
||||
range->class = instr->operands[u].vreg.is_vector
|
||||
? ROGUE_REG_CLASS_VEC4
|
||||
: ROGUE_REG_CLASS_TEMP;
|
||||
|
||||
entry = _mesa_hash_table_insert(reg_ht,
|
||||
&instr->operands[u].vreg.number,
|
||||
range);
|
||||
|
||||
max_vreg = MAX2(max_vreg, instr->operands[u].vreg.number);
|
||||
|
||||
util_dynarray_init(&range->operand_refs, range);
|
||||
} else {
|
||||
/* Subsequent uses: update live range end. */
|
||||
range = entry->data;
|
||||
range->end = MAX2(range->end, ip);
|
||||
assert(range->class == (instr->operands[u].vreg.is_vector
|
||||
? ROGUE_REG_CLASS_VEC4
|
||||
: ROGUE_REG_CLASS_TEMP));
|
||||
}
|
||||
|
||||
/* Save a reference to the operand. */
|
||||
util_dynarray_append(&range->operand_refs,
|
||||
struct rogue_operand *,
|
||||
&instr->operands[u]);
|
||||
}
|
||||
++ip;
|
||||
}
|
||||
|
||||
/* Initialize the interference graph. */
|
||||
struct ra_graph *g = ra_alloc_interference_graph(ra->regs, max_vreg + 1);
|
||||
|
||||
/* Set each virtual register to the appropriate class. */
|
||||
hash_table_foreach (reg_ht, entry) {
|
||||
const uint32_t *vreg = entry->key;
|
||||
struct live_range *range = entry->data;
|
||||
struct ra_class *class = ra->reg_data[range->class].class;
|
||||
|
||||
ra_set_node_class(g, *vreg, class);
|
||||
/* TODO: ra_set_node_spill_cost(g, *vreg, cost); */
|
||||
}
|
||||
|
||||
/* Build interference graph from overlapping live ranges. */
|
||||
hash_table_foreach (reg_ht, entry_first) {
|
||||
const uint32_t *vreg_first = entry_first->key;
|
||||
struct live_range *range_first = entry_first->data;
|
||||
|
||||
hash_table_foreach (reg_ht, entry_second) {
|
||||
const uint32_t *vreg_second = entry_second->key;
|
||||
struct live_range *range_second = entry_second->data;
|
||||
|
||||
if (*vreg_first == *vreg_second)
|
||||
continue;
|
||||
|
||||
/* If the live ranges overlap, those register nodes interfere. */
|
||||
if (!(range_first->start >= range_second->end ||
|
||||
range_second->start >= range_first->end)) {
|
||||
ra_add_node_interference(g, *vreg_first, *vreg_second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Add node interferences such that the same register can't be used for
|
||||
* both an instruction's source and destination.
|
||||
*/
|
||||
foreach_instr (instr, instr_list) {
|
||||
for (size_t u = 0U; u < instr->num_operands; ++u) {
|
||||
if (instr->operands[u].type != ROGUE_OPERAND_TYPE_VREG)
|
||||
continue;
|
||||
|
||||
/* Operand 0 (if it exists and is virtual) is always
|
||||
* the destination register.
|
||||
*/
|
||||
if (u > 0 && instr->operands[0].type == ROGUE_OPERAND_TYPE_VREG)
|
||||
ra_add_node_interference(g,
|
||||
instr->operands[0].vreg.number,
|
||||
instr->operands[u].vreg.number);
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform register allocation. */
|
||||
/* TODO: Spilling support. */
|
||||
assert(ra_allocate(g));
|
||||
|
||||
/* Replace virtual registers with allocated physical registers.
|
||||
* N.B. This is a destructive process as it overwrites the hash table key!
|
||||
*/
|
||||
hash_table_foreach (reg_ht, entry) {
|
||||
uint32_t vreg = *(uint32_t *)entry->key;
|
||||
unsigned phy_reg = ra_get_node_reg(g, vreg);
|
||||
struct live_range *range = entry->data;
|
||||
|
||||
struct rogue_reg_data *reg_data = &ra->reg_data[range->class];
|
||||
enum rogue_operand_type type = reg_data->type;
|
||||
size_t reg_offset = reg_data->offset;
|
||||
size_t *num_used = ®_data->num_used;
|
||||
|
||||
util_dynarray_foreach (&range->operand_refs,
|
||||
struct rogue_operand *,
|
||||
operand_ptr) {
|
||||
size_t num = phy_reg - reg_offset;
|
||||
struct rogue_operand *operand = *operand_ptr;
|
||||
|
||||
assert(operand->type == ROGUE_OPERAND_TYPE_VREG);
|
||||
assert(operand->vreg.number == vreg);
|
||||
|
||||
/* Index the component of emulated vec4 registers. */
|
||||
if (operand->vreg.is_vector &&
|
||||
operand->vreg.component != ROGUE_COMPONENT_ALL)
|
||||
num += operand->vreg.component;
|
||||
|
||||
operand->type = type;
|
||||
operand->reg.number = num;
|
||||
|
||||
*num_used = MAX2(*num_used, operand->reg.number);
|
||||
}
|
||||
|
||||
util_dynarray_fini(&range->operand_refs);
|
||||
_mesa_hash_table_remove(reg_ht, entry);
|
||||
}
|
||||
|
||||
/* Registers used = max reg number + 1. */
|
||||
for (size_t u = 0; u < ARRAY_SIZE(ra->reg_data); ++u)
|
||||
if (ra->reg_data[u].num_used)
|
||||
++ra->reg_data[u].num_used;
|
||||
|
||||
/* Pass back the registers used. */
|
||||
if (temps_used)
|
||||
*temps_used = ra->reg_data[ROGUE_REG_CLASS_TEMP].num_used;
|
||||
|
||||
if (internals_used)
|
||||
*internals_used = ra->reg_data[ROGUE_REG_CLASS_VEC4].num_used;
|
||||
|
||||
ralloc_free(g);
|
||||
|
||||
_mesa_hash_table_destroy(reg_ht, NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rogue_shader.h"
|
||||
#include "rogue_instr.h"
|
||||
#include "rogue_regalloc.h"
|
||||
#include "rogue_util.h"
|
||||
#include "util/ralloc.h"
|
||||
|
||||
/**
|
||||
* \file rogue_shader.c
|
||||
*
|
||||
* \brief Contains functions to manipulate Rogue shaders.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Counts how many times an instruction is used in a shader.
|
||||
*
|
||||
* \param[in] shader The shader containing instructions to count.
|
||||
* \param[in] opcode The opcode of the instruction to be counted.
|
||||
* \return The number of times "opcode" is present, or 0 on error.
|
||||
*/
|
||||
size_t rogue_shader_instr_count_type(const struct rogue_shader *shader,
|
||||
enum rogue_opcode opcode)
|
||||
{
|
||||
size_t count = 0U;
|
||||
|
||||
ASSERT_OPCODE_RANGE(opcode);
|
||||
|
||||
foreach_instr (instr, &shader->instr_list)
|
||||
if (instr->opcode == opcode)
|
||||
++count;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocates and sets up a Rogue shader.
|
||||
*
|
||||
* \param[in] stage The shader stage.
|
||||
* \return A rogue_shader* if successful, or NULL if unsuccessful.
|
||||
*/
|
||||
struct rogue_shader *rogue_shader_create(struct rogue_build_ctx *ctx,
|
||||
gl_shader_stage stage)
|
||||
{
|
||||
struct rogue_shader *shader;
|
||||
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
shader = rzalloc_size(ctx, sizeof(*shader));
|
||||
if (!shader)
|
||||
return NULL;
|
||||
|
||||
shader->stage = stage;
|
||||
|
||||
list_inithead(&shader->instr_list);
|
||||
|
||||
shader->ctx = ctx;
|
||||
shader->ra = rogue_ra_init(shader);
|
||||
if (!shader->ra) {
|
||||
ralloc_free(shader);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return shader;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Creates an instruction and appends it to a Rogue shader.
|
||||
*
|
||||
* \param[in] shader The shader.
|
||||
* \param[in] opcode The instruction opcode.
|
||||
* \return A rogue_instr* if successful, or NULL if unsuccessful.
|
||||
*/
|
||||
struct rogue_instr *rogue_shader_insert(struct rogue_shader *shader,
|
||||
enum rogue_opcode opcode)
|
||||
{
|
||||
struct rogue_instr *instr = rogue_instr_create(shader, opcode);
|
||||
if (!instr)
|
||||
return NULL;
|
||||
|
||||
list_addtail(&instr->node, &shader->instr_list);
|
||||
|
||||
return instr;
|
||||
}
|
||||
|
||||
size_t rogue_acquire_drc(struct rogue_shader *shader)
|
||||
{
|
||||
size_t drc;
|
||||
|
||||
/* If both DRCs are in use, we have a problem. */
|
||||
if (shader->drc_used[0] && shader->drc_used[1])
|
||||
return SIZE_MAX;
|
||||
|
||||
drc = !shader->drc_used[0] ? 0 : 1;
|
||||
shader->drc_used[drc] = true;
|
||||
|
||||
return drc;
|
||||
}
|
||||
|
||||
void rogue_release_drc(struct rogue_shader *shader, size_t drc)
|
||||
{
|
||||
assert(drc < ROGUE_NUM_DRCS);
|
||||
assert(shader->drc_used[drc]);
|
||||
|
||||
shader->drc_used[drc] = false;
|
||||
}
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_SHADER_H
|
||||
#define ROGUE_SHADER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "compiler/shader_enums.h"
|
||||
#include "rogue_instr.h"
|
||||
#include "rogue_operand.h"
|
||||
#include "rogue_util.h"
|
||||
#include "util/list.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
struct rogue_build_ctx;
|
||||
struct rogue_ra;
|
||||
|
||||
/**
|
||||
* \brief Shader description.
|
||||
*/
|
||||
struct rogue_shader {
|
||||
gl_shader_stage stage; /** Shader stage. */
|
||||
|
||||
struct list_head instr_list; /** Instructions linked list. */
|
||||
|
||||
struct rogue_build_ctx *ctx;
|
||||
struct rogue_ra *ra;
|
||||
|
||||
bool drc_used[ROGUE_NUM_DRCS];
|
||||
};
|
||||
|
||||
/* Shader instruction list iterators and helpers. */
|
||||
#define foreach_instr(__instr, __list) \
|
||||
list_for_each_entry (struct rogue_instr, __instr, __list, node)
|
||||
#define foreach_instr_rev(__instr, __list) \
|
||||
list_for_each_entry_rev (struct rogue_instr, __instr, __list, node)
|
||||
#define foreach_instr_safe(__instr, __list) \
|
||||
list_for_each_entry_safe (struct rogue_instr, __instr, __list, node)
|
||||
|
||||
#define instr_first_entry(__list) \
|
||||
list_first_entry(__list, struct rogue_instr, node)
|
||||
#define instr_last_entry(__list) \
|
||||
list_last_entry(__list, struct rogue_instr, node)
|
||||
|
||||
size_t rogue_shader_instr_count_type(const struct rogue_shader *shader,
|
||||
enum rogue_opcode opcode);
|
||||
|
||||
PUBLIC
|
||||
struct rogue_shader *rogue_shader_create(struct rogue_build_ctx *ctx,
|
||||
gl_shader_stage stage);
|
||||
|
||||
PUBLIC
|
||||
struct rogue_instr *rogue_shader_insert(struct rogue_shader *shader,
|
||||
enum rogue_opcode opcode);
|
||||
|
||||
size_t rogue_acquire_drc(struct rogue_shader *shader);
|
||||
void rogue_release_drc(struct rogue_shader *shader, size_t drc);
|
||||
|
||||
#endif /* ROGUE_SHADER_H */
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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 <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rogue_util.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
/**
|
||||
* \file rogue_util.c
|
||||
*
|
||||
* \brief Contains compiler utility and helper functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Splits and distributes value "source" across "dest_bytes" according to
|
||||
* the ranges specified (from MSB to LSB).
|
||||
*
|
||||
* \param[in] source The source value to be distributed.
|
||||
* \param[in] rangelist The rangelist describing how to distribute "source".
|
||||
* \param[in] dest_size The size of the destination in bytes.
|
||||
* \param[in] dest_bytes The destination byte array.
|
||||
* \return false if invalid inputs were provided, else true.
|
||||
*/
|
||||
bool rogue_distribute_value(uint64_t source,
|
||||
const struct rogue_rangelist *rangelist,
|
||||
size_t dest_size,
|
||||
uint8_t dest_bytes[dest_size])
|
||||
{
|
||||
size_t total_bits_left = 0U;
|
||||
|
||||
/* Check that "value" is actually representable in "total_bits" bits. */
|
||||
total_bits_left = rogue_rangelist_bits(rangelist);
|
||||
assert(util_last_bit64(source) <= total_bits_left &&
|
||||
"Value cannot be represented.");
|
||||
|
||||
/* Iterate over each range. */
|
||||
for (size_t u = 0U; u < rangelist->num_ranges; ++u) {
|
||||
struct rogue_bitrange *range = &rangelist->ranges[u];
|
||||
|
||||
size_t dest_bit = range->start;
|
||||
size_t bits_left = range->num;
|
||||
size_t bytes_covered = rogue_bytes_spilled(range) + 1;
|
||||
size_t base_byte = rogue_byte_index(range, dest_size);
|
||||
|
||||
/* Iterate over each byte covered by the current range. */
|
||||
for (size_t b = 0U; b < bytes_covered; ++b) {
|
||||
size_t max_bits = rogue_max_bits(dest_bit);
|
||||
size_t bits_to_place = MIN2(bits_left, max_bits);
|
||||
size_t dest_byte_bit = dest_bit % 8;
|
||||
size_t source_bit = total_bits_left - 1;
|
||||
|
||||
/* Mask and shuffle the source value so that it'll fit into the
|
||||
* correct place in the destination byte:
|
||||
*/
|
||||
|
||||
/* Extract bits. */
|
||||
uint64_t value_masked =
|
||||
(source & BITMASK64_N(source_bit, bits_to_place));
|
||||
/* Shift all the way right. */
|
||||
value_masked >>= (1 + source_bit - bits_to_place);
|
||||
/* Shift left to the correct position. */
|
||||
value_masked <<= (1 + dest_byte_bit - bits_to_place);
|
||||
/* Place value into byte. */
|
||||
dest_bytes[base_byte + b] |= (value_masked & 0xff);
|
||||
|
||||
dest_bit -= max_bits;
|
||||
bits_left -= bits_to_place;
|
||||
total_bits_left -= bits_to_place;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1,320 +0,0 @@
|
|||
/*
|
||||
* Copyright © 2022 Imagination Technologies Ltd.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ROGUE_UTIL_H
|
||||
#define ROGUE_UTIL_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util/bitscan.h"
|
||||
#include "util/log.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
/* Input validation helpers. */
|
||||
|
||||
/**
|
||||
* \brief Returns false if "expr" is not asserted.
|
||||
*
|
||||
* \param[in] expr The expression to check.
|
||||
*/
|
||||
#define CHECK(expr) \
|
||||
do { \
|
||||
if (!(expr)) \
|
||||
return false; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \brief Returns false if "expr" is not asserted,
|
||||
* and logs the provided error message.
|
||||
*
|
||||
* \param[in] expr The expression to check.
|
||||
* \param[in] fmt The error message to print.
|
||||
* \param[in] ... The printf-style varable arguments.
|
||||
*/
|
||||
#define CHECKF(expr, fmt, ...) \
|
||||
do { \
|
||||
if (!(expr)) { \
|
||||
mesa_log(MESA_LOG_ERROR, "ROGUE", fmt, ##__VA_ARGS__); \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* \brief Asserts if "opcode" is invalid.
|
||||
*
|
||||
* \param[in] opcode The opcode to check.
|
||||
*/
|
||||
#define ASSERT_OPCODE_RANGE(opcode) assert((opcode) < ROGUE_OP_COUNT)
|
||||
|
||||
/**
|
||||
* \brief Asserts if "operand" is invalid.
|
||||
*
|
||||
* \param[in] operand The operand to check.
|
||||
*/
|
||||
#define ASSERT_OPERAND_RANGE(operand) \
|
||||
assert((operand) < ROGUE_OPERAND_TYPE_COUNT)
|
||||
|
||||
/**
|
||||
* \brief Asserts if "operand" is not a register.
|
||||
*
|
||||
* \param[in] operand The operand to check.
|
||||
*/
|
||||
#define ASSERT_OPERAND_REG(operand) \
|
||||
assert((operand) <= ROGUE_OPERAND_TYPE_REG_MAX)
|
||||
|
||||
/**
|
||||
* \brief Asserts if "flag" is invalid.
|
||||
*
|
||||
* \param[in] flag The flag to check.
|
||||
*/
|
||||
#define ASSERT_INSTR_FLAG_RANGE(flag) assert((flag) < ROGUE_INSTR_FLAG_COUNT)
|
||||
|
||||
/**
|
||||
* \brief Asserts if operand index "index" is out of range.
|
||||
*
|
||||
* \param[in] instr The target instruction.
|
||||
* \param[in] index The operand index to check.
|
||||
*/
|
||||
#define ASSERT_INSTR_OPERAND_INDEX(instr, index) \
|
||||
assert((index) < (instr)->num_operands)
|
||||
|
||||
/**
|
||||
* \brief Asserts if "stage" is invalid.
|
||||
*
|
||||
* \param[in] stage The stage to check.
|
||||
*/
|
||||
#define ASSERT_SHADER_STAGE_RANGE(stage) assert((stage) < MESA_SHADER_STAGES)
|
||||
|
||||
/**
|
||||
* \brief Creates a "n"-bit mask starting from bit "b".
|
||||
*
|
||||
* \param[in] b The starting bit.
|
||||
* \param[in] n The number of bits in the mask.
|
||||
*/
|
||||
#define BITMASK64_N(b, n) (((~0ULL) << (64 - (n))) >> (63 - (b)))
|
||||
|
||||
/**
|
||||
* \brief Compile-time rogue_onehot.
|
||||
*
|
||||
* \sa #rogue_onehot()
|
||||
*/
|
||||
#define ROH(OFFSET) BITFIELD64_BIT(OFFSET)
|
||||
|
||||
/* TODO: Consider integrating the following into src/util/{macros,bitscan}.h */
|
||||
|
||||
/**
|
||||
* \brief Converts a one-hot encoding to an offset encoding.
|
||||
*
|
||||
* E.g. 0b10000 -> 4
|
||||
*
|
||||
* \param[in] onehot The one-hot encoding.
|
||||
* \return The offset encoding.
|
||||
*/
|
||||
static inline uint64_t rogue_offset(uint64_t onehot)
|
||||
{
|
||||
assert(util_bitcount64(onehot) == 1);
|
||||
return ffsll(onehot) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Converts an offset encoding to a one-hot encoding.
|
||||
*
|
||||
* E.g. 0 -> 0b1
|
||||
*
|
||||
* \param[in] offset The offset encoding.
|
||||
* \return The one-hot encoding.
|
||||
*/
|
||||
static inline uint64_t rogue_onehot(uint64_t offset)
|
||||
{
|
||||
assert(offset < 64ULL);
|
||||
return (1ULL << offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Checks whether an input bitfield contains only a valid bitset.
|
||||
*
|
||||
* E.g. rogue_check_bitset(0b00001100, 0b00001111) -> true
|
||||
* rogue_check_bitset(0b00001100, 0b00000111) -> false
|
||||
*
|
||||
* \param[in] input The input bitfield.
|
||||
* \param[in] valid_bits The valid bitset.
|
||||
* \return true if "input" contains only "valid_bits", false otherwise.
|
||||
*/
|
||||
static inline bool rogue_check_bitset(uint64_t input, uint64_t valid_bits)
|
||||
{
|
||||
input &= ~valid_bits;
|
||||
return !input;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Describes a downward range of bits within an arbitrarily-sized
|
||||
* sequence.
|
||||
*
|
||||
* E.g. for start = 7 and num = 3:
|
||||
*
|
||||
* 76543210
|
||||
* abcdefgh
|
||||
*
|
||||
* the bit range would be: abc.
|
||||
*/
|
||||
struct rogue_bitrange {
|
||||
size_t start;
|
||||
size_t num;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Describes a collection of bit-ranges within an arbitrarily-sized
|
||||
* sequence that are meaningful together.
|
||||
*
|
||||
* E.g. an 8-bit value that is encoded within a larger value:
|
||||
* 8-bit value: abcdefgh
|
||||
* Parent value: 010ab0cdef0010gh
|
||||
*
|
||||
*/
|
||||
struct rogue_rangelist {
|
||||
size_t num_ranges;
|
||||
struct rogue_bitrange *ranges;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Counts the total number of bits described in a rangelist.
|
||||
*
|
||||
* \param[in] rangelist The input rangelist.
|
||||
* \return The total number of bits.
|
||||
*/
|
||||
static inline size_t
|
||||
rogue_rangelist_bits(const struct rogue_rangelist *rangelist)
|
||||
{
|
||||
size_t total_bits = 0U;
|
||||
|
||||
for (size_t u = 0U; u < rangelist->num_ranges; ++u)
|
||||
total_bits += rangelist->ranges[u].num;
|
||||
|
||||
return total_bits;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the byte offset of the bitrange moving left from the LSB.
|
||||
*
|
||||
* \param[in] bitrange The input bit-range.
|
||||
* \return The byte offset.
|
||||
*/
|
||||
static inline size_t rogue_byte_num(const struct rogue_bitrange *bitrange)
|
||||
{
|
||||
/* Make sure there are enough bits. */
|
||||
assert(bitrange->num <= (bitrange->start + 1));
|
||||
|
||||
return bitrange->start / 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the array-indexable byte offset of a bit-range if the sequence
|
||||
* it represents were to be stored in an byte-array containing "num_bytes"
|
||||
* bytes.
|
||||
*
|
||||
* E.g. uint8_t array[2] is a sequence of 16 bits:
|
||||
* bit(0) is located in array[1].
|
||||
* bit(15) is located in array[0].
|
||||
*
|
||||
* For uint8_t array[4]:
|
||||
* bit(0) is located in array[3].
|
||||
* bit(15) is located in array[2].
|
||||
*
|
||||
* \param[in] bitrange The input bit-range.
|
||||
* \param[in] num_bytes The number of bytes that are used to contain the
|
||||
* bit-range. \return The byte offset.
|
||||
*/
|
||||
static inline size_t rogue_byte_index(const struct rogue_bitrange *bitrange,
|
||||
size_t num_bytes)
|
||||
{
|
||||
/* Make sure there are enough bits. */
|
||||
assert(bitrange->num <= (bitrange->start + 1));
|
||||
|
||||
return num_bytes - rogue_byte_num(bitrange) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the bit offset of a bit-range if the sequence it represents is
|
||||
* being accessed in a byte-wise manner.
|
||||
*
|
||||
* E.g. bit 17 has a bit offset of 1.
|
||||
*
|
||||
* \param[in] bitrange The input bit-range.
|
||||
* \return The bit offset.
|
||||
*/
|
||||
static inline size_t rogue_bit_offset(const struct rogue_bitrange *bitrange)
|
||||
{
|
||||
/* Make sure there are enough bits. */
|
||||
assert(bitrange->num <= (bitrange->start + 1));
|
||||
|
||||
return bitrange->start % 8;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns the number of additional bytes that the bit-range spills into
|
||||
* (excluding its "starting" byte).
|
||||
*
|
||||
* \param[in] bitrange The input bit-range.
|
||||
* \return The number of bytes spilled.
|
||||
*/
|
||||
static inline size_t rogue_bytes_spilled(const struct rogue_bitrange *bitrange)
|
||||
{
|
||||
/* Make sure there are enough bits. */
|
||||
assert(bitrange->num <= (bitrange->start + 1));
|
||||
|
||||
return ((bitrange->num - 1) / 8) +
|
||||
((bitrange->num % 8) > (rogue_bit_offset(bitrange) + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief For a given bit offset, returns the maximum number of bits (including
|
||||
* itself) that are accessible before spilling into the following byte.
|
||||
*
|
||||
* E.g. When trying to insert an 8-bit value offset of 13, a maximum of 6 bits
|
||||
* can be placed; the last 2 bits will need to go into the next byte.
|
||||
*
|
||||
* 8-bit value: abcdefgh
|
||||
*
|
||||
* array[0] array[1]
|
||||
* 15 8 7 0
|
||||
* iiiiiiii jjjjjjjj
|
||||
* ^
|
||||
* abcdef gh
|
||||
*
|
||||
* \param[in] The bit offset.
|
||||
* \return The maximum number of accessible bits.
|
||||
*/
|
||||
static inline size_t rogue_max_bits(size_t offset)
|
||||
{
|
||||
return (offset % 8) + 1;
|
||||
}
|
||||
|
||||
bool rogue_distribute_value(uint64_t source,
|
||||
const struct rogue_rangelist *rangelist,
|
||||
size_t dest_size,
|
||||
uint8_t dest_bytes[dest_size]);
|
||||
|
||||
#endif /* ROGUE_UTIL_H */
|
||||
|
|
@ -21,268 +21,491 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \file rogue_validate.c
|
||||
*
|
||||
* \brief Contains rules and functions for validating Rogue data structures.
|
||||
*/
|
||||
#include "rogue.h"
|
||||
#include "util/bitscan.h"
|
||||
#include "util/macros.h"
|
||||
#include "util/u_dynarray.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "rogue_operand.h"
|
||||
#include "rogue_shader.h"
|
||||
#include "rogue_util.h"
|
||||
#include "rogue_validate.h"
|
||||
#include "util/list.h"
|
||||
#include "util/macros.h"
|
||||
|
||||
/**
|
||||
* \brief Register operand rules.
|
||||
*/
|
||||
#define REG_RULE(OPERAND, ACCESS, MAX, MODIFIERS) \
|
||||
[ROGUE_OPERAND_TYPE_REG_##OPERAND] = { \
|
||||
.access = ROGUE_REG_ACCESS_##ACCESS, \
|
||||
.max = MAX, \
|
||||
.modifiers = ROGUE_REG_MOD_##MODIFIERS, \
|
||||
}
|
||||
|
||||
/* TODO: Support register indexing > ROGUE_MAX_REG_TEMP. */
|
||||
static const struct rogue_register_rule reg_rules[ROGUE_NUM_REG_TYPES] = {
|
||||
REG_RULE(TEMP, RW, MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_TEMP), ALL),
|
||||
REG_RULE(COEFF, RW, MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_COEFF), ALL),
|
||||
REG_RULE(CONST, RW, MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_CONST), NONE),
|
||||
REG_RULE(SHARED, RW, MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_SHARED), ALL),
|
||||
REG_RULE(PIXEL_OUT,
|
||||
RW,
|
||||
MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_PIXEL_OUT),
|
||||
NONE),
|
||||
REG_RULE(VERTEX_IN,
|
||||
RW,
|
||||
MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_VERTEX_IN),
|
||||
ALL),
|
||||
REG_RULE(INTERNAL,
|
||||
RW,
|
||||
MIN2(ROGUE_MAX_REG_INDEX, ROGUE_MAX_REG_INTERNAL),
|
||||
NONE),
|
||||
};
|
||||
#undef REG_RULE
|
||||
|
||||
/**
|
||||
* \brief Instruction rules.
|
||||
*/
|
||||
/* TODO: Common up register classes to prevent long lines. */
|
||||
static const struct rogue_instr_rule instr_rules[ROGUE_OP_COUNT] = {
|
||||
[ROGUE_OP_NOP] = { .flags = 0, .num_operands = 0, .operand_rules = NULL, },
|
||||
[ROGUE_OP_END_FRAG] = { .flags = 0, .num_operands = 0, .operand_rules = NULL, },
|
||||
[ROGUE_OP_END_VERT] = { .flags = 0, .num_operands = 0, .operand_rules = NULL, },
|
||||
[ROGUE_OP_WDF] = { .flags = 0,
|
||||
.num_operands = 1, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_DRC), .min = -1, .max = -1, .align = -1, },
|
||||
},
|
||||
},
|
||||
[ROGUE_OP_PIX_ITER_W] = { .flags = ROH(ROGUE_INSTR_FLAG_SAT),
|
||||
.num_operands = 5, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[1] = { .mask = ROH(ROGUE_OPERAND_TYPE_DRC), .min = -1, .max = -1, .align = -1, },
|
||||
[2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_COEFF), .min = -1, .max = -1, .align = ROGUE_COEFF_ALIGN, },
|
||||
[3] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_COEFF), .min = -1, .max = -1, .align = ROGUE_COEFF_ALIGN, },
|
||||
[4] = { .mask = ROH(ROGUE_OPERAND_TYPE_IMMEDIATE), .min = 1, .max = 16, .align = -1, },
|
||||
},
|
||||
},
|
||||
[ROGUE_OP_MAX] = { .flags = 0,
|
||||
.num_operands = 3, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_CONST) | ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
},
|
||||
},
|
||||
[ROGUE_OP_MIN] = { .flags = 0,
|
||||
.num_operands = 3, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP) | ROH(ROGUE_OPERAND_TYPE_REG_INTERNAL), .min = -1, .max = -1, .align = -1, },
|
||||
[1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_CONST) | ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
},
|
||||
},
|
||||
/* TODO: Add representation for 4 sequential registers. */
|
||||
[ROGUE_OP_PACK_U8888] = { .flags = 0,
|
||||
.num_operands = 2, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_INTERNAL), .min = -1, .max = -1, .align = -1, },
|
||||
},
|
||||
},
|
||||
[ROGUE_OP_MOV] = { .flags = ROH(ROGUE_INSTR_FLAG_OLCHK),
|
||||
.num_operands = 2, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP) | ROH(ROGUE_OPERAND_TYPE_REG_INTERNAL) | ROH(ROGUE_OPERAND_TYPE_REG_PIXEL_OUT), .min = -1, .max = -1, .align = -1, },
|
||||
[1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_CONST) | ROH(ROGUE_OPERAND_TYPE_REG_TEMP) | ROH(ROGUE_OPERAND_TYPE_REG_SHARED) | ROH(ROGUE_OPERAND_TYPE_REG_VERTEX_IN), .min = -1, .max = -1, .align = -1, },
|
||||
},
|
||||
},
|
||||
[ROGUE_OP_MOV_IMM] = { .flags = 0,
|
||||
.num_operands = 2, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[1] = { .mask = ROH(ROGUE_OPERAND_TYPE_IMMEDIATE), .min = 0, .max = UINT32_MAX, .align = -1, },
|
||||
},
|
||||
},
|
||||
[ROGUE_OP_FMA] = { .flags = ROH(ROGUE_INSTR_FLAG_SAT) | ROH(ROGUE_INSTR_FLAG_LP),
|
||||
.num_operands = 4, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[3] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
},
|
||||
},
|
||||
[ROGUE_OP_MUL] = { .flags = ROH(ROGUE_INSTR_FLAG_SAT) | ROH(ROGUE_INSTR_FLAG_LP),
|
||||
.num_operands = 3, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
[2] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
},
|
||||
},
|
||||
[ROGUE_OP_VTXOUT] = { .flags = 0,
|
||||
.num_operands = 2, .operand_rules = (struct rogue_instr_operand_rule[]){
|
||||
[0] = { .mask = ROH(ROGUE_OPERAND_TYPE_IMMEDIATE), .min = 0, .max = ROGUE_MAX_VERTEX_OUTPUTS, .align = -1, },
|
||||
[1] = { .mask = ROH(ROGUE_OPERAND_TYPE_REG_TEMP), .min = -1, .max = -1, .align = -1, },
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Validates an operand.
|
||||
* \file rogue_validate.c
|
||||
*
|
||||
* \param[in] operand The operand.
|
||||
* \return true if valid, otherwise false.
|
||||
* \brief Contains functions to validate Rogue IR.
|
||||
*/
|
||||
bool rogue_validate_operand(const struct rogue_operand *operand)
|
||||
|
||||
/* TODO: Rogue_validate should make sure that immediate (sources) don't have any
|
||||
* modifiers set... */
|
||||
|
||||
/* TODO NEXT: Make sure that Register Usage Restrictions are followed (and go
|
||||
* through ISR and add any other restrictions). */
|
||||
/* TODO: Remember that some instructions have the DESTINATION as a source
|
||||
* (register pointers), e.g. fitrp using S3 */
|
||||
/* TODO NEXT: Add field to instr_info that specifies which source/destination
|
||||
* should be affected by instruction repeating. */
|
||||
/* TODO NEXT: Validate backend and control sources/dests. */
|
||||
/* TODO: Go through and make sure that validation state is being properly
|
||||
* updated as so to allow for validation_log to print enough info. */
|
||||
|
||||
/* TODO NEXT: Check for emit/end/etc. as last instruction in vertex shader, and
|
||||
* nop.end, or end flag set (or just pseudo-end) otherwise. */
|
||||
|
||||
typedef struct rogue_validation_state {
|
||||
const rogue_shader *shader; /** The shader being validated. */
|
||||
const char *when; /** Description of the validation being done. */
|
||||
bool nonfatal; /** Don't stop at the first error.*/
|
||||
const rogue_instr *instr; /** Current instruction being validated. */
|
||||
const rogue_instr_group *group; /** Current instruction group being
|
||||
validated. */
|
||||
const rogue_ref *ref; /** Current reference being validated. */
|
||||
struct util_dynarray *error_msgs; /** Error message list. */
|
||||
} rogue_validation_state;
|
||||
|
||||
/* Returns true if errors are present. */
|
||||
static bool validate_print_errors(rogue_validation_state *state)
|
||||
{
|
||||
ASSERT_OPERAND_RANGE(operand->type);
|
||||
|
||||
switch (operand->type) {
|
||||
case ROGUE_OPERAND_TYPE_IMMEDIATE:
|
||||
return true;
|
||||
|
||||
case ROGUE_OPERAND_TYPE_DRC:
|
||||
CHECKF(operand->drc.number < ROGUE_NUM_DRCS,
|
||||
"Invalid DRC number '%zu'.",
|
||||
operand->drc.number);
|
||||
return true;
|
||||
|
||||
case ROGUE_OPERAND_TYPE_REG_TEMP:
|
||||
case ROGUE_OPERAND_TYPE_REG_COEFF:
|
||||
case ROGUE_OPERAND_TYPE_REG_CONST:
|
||||
case ROGUE_OPERAND_TYPE_REG_SHARED:
|
||||
case ROGUE_OPERAND_TYPE_REG_PIXEL_OUT:
|
||||
case ROGUE_OPERAND_TYPE_REG_VERTEX_IN:
|
||||
case ROGUE_OPERAND_TYPE_REG_INTERNAL:
|
||||
CHECKF(operand->reg.number < reg_rules[operand->type].max,
|
||||
"Register number '%zu' out of range.",
|
||||
operand->reg.number);
|
||||
return true;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Validates an instruction.
|
||||
*
|
||||
* \param[in] instr The instruction.
|
||||
* \return true if valid, otherwise false.
|
||||
*/
|
||||
bool rogue_validate_instr(const struct rogue_instr *instr)
|
||||
{
|
||||
const struct rogue_instr_rule *rule;
|
||||
|
||||
ASSERT_OPCODE_RANGE(instr->opcode);
|
||||
|
||||
rule = &instr_rules[instr->opcode];
|
||||
|
||||
/* Validate flags. */
|
||||
CHECKF(rogue_check_bitset(instr->flags, rule->flags),
|
||||
"Invalid instruction flags specified.");
|
||||
|
||||
/* Validate number of operands. */
|
||||
CHECKF(instr->num_operands == rule->num_operands,
|
||||
"Invalid number of operands specified.");
|
||||
|
||||
CHECK(!rule->num_operands || instr->operands);
|
||||
for (size_t u = 0U; u < instr->num_operands; ++u) {
|
||||
/* Validate operand types. */
|
||||
CHECKF(rogue_check_bitset(rogue_onehot(instr->operands[u].type),
|
||||
rule->operand_rules[u].mask),
|
||||
"Invalid type for operand %zu.",
|
||||
u);
|
||||
|
||||
/* Validate immediate ranges. */
|
||||
if (rogue_check_bitset(rogue_onehot(instr->operands[u].type),
|
||||
ROH(ROGUE_OPERAND_TYPE_IMMEDIATE)) &&
|
||||
rule->operand_rules[u].min != -1 &&
|
||||
rule->operand_rules[u].max != -1) {
|
||||
CHECKF(
|
||||
instr->operands[u].immediate.value >= rule->operand_rules[u].min &&
|
||||
instr->operands[u].immediate.value <= rule->operand_rules[u].max,
|
||||
"Immediate value out of range for operand %zu.",
|
||||
u);
|
||||
}
|
||||
|
||||
/* Validate register alignment. */
|
||||
if (rogue_check_bitset(rogue_onehot(instr->operands[u].type),
|
||||
ROGUE_MASK_ANY_REG) &&
|
||||
rule->operand_rules[u].align != -1) {
|
||||
CHECKF(!(instr->operands[u].reg.number % rule->operand_rules[u].align),
|
||||
"Invalid register alignment in operand %zu.",
|
||||
u);
|
||||
}
|
||||
|
||||
/* Validate each operand. */
|
||||
CHECKF(rogue_validate_operand(&instr->operands[u]),
|
||||
"Failed to validate operand.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Validates a shader.
|
||||
*
|
||||
* \param[in] shader The shader.
|
||||
* \return true if valid, otherwise false.
|
||||
*/
|
||||
bool rogue_validate_shader(const struct rogue_shader *shader)
|
||||
{
|
||||
CHECK(!list_is_empty(&shader->instr_list));
|
||||
ASSERT_SHADER_STAGE_RANGE(shader->stage);
|
||||
|
||||
/* Shader stage-specific validation. */
|
||||
switch (shader->stage) {
|
||||
case MESA_SHADER_VERTEX:
|
||||
/* Make sure there is (only) one end vertex shader instruction. */
|
||||
CHECKF(rogue_shader_instr_count_type(shader, ROGUE_OP_END_VERT) == 1,
|
||||
"Shader must contain a single end.vert instruction.");
|
||||
|
||||
/* Make sure the end vertex shader instruction is the last one. */
|
||||
CHECKF(instr_last_entry(&shader->instr_list)->opcode == ROGUE_OP_END_VERT,
|
||||
"end.vert not last instruction.");
|
||||
break;
|
||||
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
/* Make sure there is (only) one end fragment shader instruction. */
|
||||
CHECKF(rogue_shader_instr_count_type(shader, ROGUE_OP_END_FRAG) == 1,
|
||||
"Shader must contain a single end.frag instruction.");
|
||||
|
||||
/* Make sure the end fragment shader instruction is the last one. */
|
||||
CHECKF(instr_last_entry(&shader->instr_list)->opcode == ROGUE_OP_END_FRAG,
|
||||
"end.frag not last instruction.");
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!util_dynarray_num_elements(state->error_msgs, const char *))
|
||||
return false;
|
||||
|
||||
util_dynarray_foreach (state->error_msgs, const char *, msg) {
|
||||
fprintf(stderr, "%s\n", *msg);
|
||||
}
|
||||
|
||||
/* Validate each instruction. */
|
||||
foreach_instr (instr, &shader->instr_list)
|
||||
CHECKF(rogue_validate_instr(instr), "Failed to validate instruction.");
|
||||
fputs("\n", stderr);
|
||||
|
||||
/* TODO: Figure out if/when to print this. */
|
||||
rogue_print_shader(stderr, state->shader);
|
||||
fputs("\n", stderr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void PRINTFLIKE(2, 3)
|
||||
validate_log(rogue_validation_state *state, const char *fmt, ...)
|
||||
{
|
||||
char *msg = ralloc_asprintf(state->error_msgs, "Validation error");
|
||||
|
||||
/* Add info about the item that was being validated. */
|
||||
if (state->instr) {
|
||||
ralloc_asprintf_append(&msg, " instr %u", state->instr->index);
|
||||
}
|
||||
|
||||
if (state->ref) {
|
||||
/* TODO: Find a way to get an index. */
|
||||
}
|
||||
|
||||
ralloc_asprintf_append(&msg, ": ");
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
ralloc_vasprintf_append(&msg, fmt, args);
|
||||
util_dynarray_append(state->error_msgs, const char *, msg);
|
||||
va_end(args);
|
||||
|
||||
if (!state->nonfatal) {
|
||||
validate_print_errors(state);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static rogue_validation_state *
|
||||
create_validation_state(const rogue_shader *shader, const char *when)
|
||||
{
|
||||
rogue_validation_state *state = rzalloc_size(shader, sizeof(*state));
|
||||
|
||||
state->shader = shader;
|
||||
state->when = when;
|
||||
state->nonfatal = ROGUE_DEBUG(VLD_NONFATAL);
|
||||
|
||||
state->error_msgs = rzalloc_size(state, sizeof(*state->error_msgs));
|
||||
util_dynarray_init(state->error_msgs, state);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static void validate_regarray(rogue_validation_state *state,
|
||||
rogue_regarray *regarray)
|
||||
{
|
||||
if (!regarray->size) {
|
||||
validate_log(state, "Register array is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
enum rogue_reg_class class = regarray->regs[0]->class;
|
||||
unsigned base_index = regarray->regs[0]->index;
|
||||
|
||||
for (unsigned u = 0; u < regarray->size; ++u) {
|
||||
if (regarray->regs[u]->class != class)
|
||||
validate_log(state, "Register class mismatch in register array.");
|
||||
|
||||
if (regarray->regs[u]->index != (base_index + u))
|
||||
validate_log(state, "Non-contiguous registers in register array.");
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_alu_dst(rogue_validation_state *state,
|
||||
const rogue_alu_dst *dst,
|
||||
uint64_t supported_dst_types)
|
||||
{
|
||||
state->ref = &dst->ref;
|
||||
|
||||
if (rogue_ref_is_null(&dst->ref))
|
||||
validate_log(state, "ALU destination has not been set.");
|
||||
|
||||
if (!state->shader->is_grouped)
|
||||
if (!rogue_ref_type_supported(dst->ref.type, supported_dst_types))
|
||||
validate_log(state, "Unsupported ALU destination type.");
|
||||
|
||||
state->ref = NULL;
|
||||
}
|
||||
|
||||
static void validate_alu_src(rogue_validation_state *state,
|
||||
const rogue_alu_src *src,
|
||||
uint64_t supported_src_types)
|
||||
{
|
||||
state->ref = &src->ref;
|
||||
|
||||
if (rogue_ref_is_null(&src->ref))
|
||||
validate_log(state, "ALU source has not been set.");
|
||||
|
||||
if (!state->shader->is_grouped) {
|
||||
if (!rogue_ref_type_supported(src->ref.type, supported_src_types))
|
||||
validate_log(state, "Unsupported ALU source type.");
|
||||
}
|
||||
|
||||
state->ref = NULL;
|
||||
}
|
||||
|
||||
static void validate_alu_instr(rogue_validation_state *state,
|
||||
const rogue_alu_instr *alu)
|
||||
{
|
||||
if (alu->op == ROGUE_ALU_OP_INVALID || alu->op >= ROGUE_ALU_OP_COUNT)
|
||||
validate_log(state, "Unknown ALU op 0x%x encountered.", alu->op);
|
||||
|
||||
const rogue_alu_op_info *info = &rogue_alu_op_infos[alu->op];
|
||||
|
||||
if (!rogue_alu_comp_is_none(alu) && alu->op != ROGUE_ALU_OP_TST)
|
||||
validate_log(state, "ALU comparison set for non-test op.");
|
||||
|
||||
if (rogue_alu_comp_is_none(alu) && alu->op == ROGUE_ALU_OP_TST)
|
||||
validate_log(state, "ALU comparison not set for test op.");
|
||||
|
||||
/* Initial check if instruction modifiers are valid. */
|
||||
if (!rogue_mods_supported(alu->mod, info->supported_op_mods))
|
||||
validate_log(state, "Unsupported ALU op modifiers.");
|
||||
|
||||
/* Validate destination and sources. */
|
||||
validate_alu_dst(state, &alu->dst, info->supported_dst_types);
|
||||
|
||||
for (unsigned i = 0; i < info->num_srcs; ++i)
|
||||
validate_alu_src(state, &alu->src[i], info->supported_src_types[i]);
|
||||
|
||||
/* TODO: Check that the src_use and dst_write fields are correct? */
|
||||
}
|
||||
|
||||
static void validate_backend_instr(rogue_validation_state *state,
|
||||
const rogue_backend_instr *backend)
|
||||
{
|
||||
if (backend->op == ROGUE_BACKEND_OP_INVALID ||
|
||||
backend->op >= ROGUE_BACKEND_OP_COUNT)
|
||||
validate_log(state, "Unknown backend op 0x%x encountered.", backend->op);
|
||||
|
||||
const rogue_backend_op_info *info = &rogue_backend_op_infos[backend->op];
|
||||
|
||||
/* Initial check if instruction modifiers are valid. */
|
||||
if (!rogue_mods_supported(backend->mod, info->supported_op_mods))
|
||||
validate_log(state, "Unsupported backend op modifiers.");
|
||||
|
||||
/* TODO: Validate dests and srcs? */
|
||||
/* TODO: Check that the src_use and dst_write fields are correct? */
|
||||
}
|
||||
|
||||
/* Returns true if instruction can end block. */
|
||||
static bool validate_ctrl_instr(rogue_validation_state *state,
|
||||
const rogue_ctrl_instr *ctrl)
|
||||
{
|
||||
if (ctrl->op == ROGUE_CTRL_OP_INVALID || ctrl->op >= ROGUE_CTRL_OP_COUNT)
|
||||
validate_log(state, "Unknown ctrl op 0x%x encountered.", ctrl->op);
|
||||
|
||||
/* TODO: Validate rest, check blocks, etc. */
|
||||
const rogue_ctrl_op_info *info = &rogue_ctrl_op_infos[ctrl->op];
|
||||
|
||||
if (info->has_target && !ctrl->target_block)
|
||||
validate_log(state, "Ctrl op expected target block, but none provided.");
|
||||
else if (!info->has_target && ctrl->target_block)
|
||||
validate_log(state,
|
||||
"Ctrl op did not expect target block, but one provided.");
|
||||
|
||||
/* Initial check if instruction modifiers are valid. */
|
||||
if (!rogue_mods_supported(ctrl->mod, info->supported_op_mods))
|
||||
validate_log(state, "Unsupported CTRL op modifiers.");
|
||||
|
||||
/* TODO: Validate dests and srcs? */
|
||||
/* TODO: Check that the src_use and dst_write fields are correct? */
|
||||
|
||||
/* nop.end counts as a end-of-block instruction. */
|
||||
if (rogue_instr_is_nop_end(&ctrl->instr))
|
||||
return true;
|
||||
|
||||
/* Control instructions have no end flag to set. */
|
||||
if (ctrl->instr.end)
|
||||
validate_log(state, "CTRL ops have no end flag.");
|
||||
|
||||
return info->ends_block;
|
||||
}
|
||||
|
||||
/* Returns true if instruction can end block. */
|
||||
static bool validate_instr(rogue_validation_state *state,
|
||||
const rogue_instr *instr)
|
||||
{
|
||||
state->instr = instr;
|
||||
|
||||
bool ends_block = false;
|
||||
|
||||
switch (instr->type) {
|
||||
case ROGUE_INSTR_TYPE_ALU:
|
||||
validate_alu_instr(state, rogue_instr_as_alu(instr));
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_BACKEND:
|
||||
validate_backend_instr(state, rogue_instr_as_backend(instr));
|
||||
break;
|
||||
|
||||
case ROGUE_INSTR_TYPE_CTRL:
|
||||
ends_block = validate_ctrl_instr(state, rogue_instr_as_ctrl(instr));
|
||||
break;
|
||||
|
||||
default:
|
||||
validate_log(state,
|
||||
"Unknown instruction type 0x%x encountered.",
|
||||
instr->type);
|
||||
}
|
||||
|
||||
/* If the last instruction isn't control flow but has the end flag set, it
|
||||
* can end a block. */
|
||||
if (!ends_block)
|
||||
ends_block = instr->end;
|
||||
|
||||
state->instr = NULL;
|
||||
|
||||
return ends_block;
|
||||
}
|
||||
|
||||
/* Returns true if instruction can end block. */
|
||||
static bool validate_instr_group(rogue_validation_state *state,
|
||||
const rogue_instr_group *group)
|
||||
{
|
||||
state->group = group;
|
||||
/* TODO: Validate group properties. */
|
||||
/* TODO: Check for pseudo-instructions. */
|
||||
|
||||
bool ends_block = false;
|
||||
|
||||
/* Validate instructions in group. */
|
||||
/* TODO: Check util_last_bit group_phases < bla bla */
|
||||
rogue_foreach_phase_in_set (p, group->header.phases) {
|
||||
const rogue_instr *instr = group->instrs[p];
|
||||
|
||||
if (!instr)
|
||||
validate_log(state, "Missing instruction where phase was set.");
|
||||
|
||||
/* TODO NEXT: Groups that have control instructions should only have a
|
||||
* single instruction. */
|
||||
ends_block = validate_instr(state, instr);
|
||||
}
|
||||
|
||||
state->group = NULL;
|
||||
|
||||
if (group->header.alu != ROGUE_ALU_CONTROL)
|
||||
return group->header.end;
|
||||
|
||||
return ends_block;
|
||||
}
|
||||
|
||||
static void validate_block(rogue_validation_state *state,
|
||||
const rogue_block *block)
|
||||
{
|
||||
/* TODO: Set/reset state->block */
|
||||
/* TODO: Validate block properties. */
|
||||
|
||||
if (list_is_empty(&block->instrs)) {
|
||||
validate_log(state, "Block is empty.");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned block_ends = 0;
|
||||
struct list_head *block_end = NULL;
|
||||
struct list_head *last = block->instrs.prev;
|
||||
|
||||
/* Validate instructions/groups in block. */
|
||||
if (!block->shader->is_grouped) {
|
||||
rogue_foreach_instr_in_block (instr, block) {
|
||||
bool ends_block = validate_instr(state, instr);
|
||||
block_ends += ends_block;
|
||||
block_end = ends_block ? &instr->link : block_end;
|
||||
}
|
||||
} else {
|
||||
rogue_foreach_instr_group_in_block (group, block) {
|
||||
bool ends_block = validate_instr_group(state, group);
|
||||
block_ends += ends_block;
|
||||
block_end = ends_block ? &group->link : block_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (!block_ends || block_ends > 1)
|
||||
validate_log(state,
|
||||
"Block must end with a single control flow instruction.");
|
||||
else if (block_end != last)
|
||||
validate_log(
|
||||
state,
|
||||
"Control flow instruction is present prior to the end of the block.");
|
||||
}
|
||||
|
||||
static void validate_reg_use(rogue_validation_state *state,
|
||||
const rogue_reg_use *use,
|
||||
uint64_t supported_io_srcs)
|
||||
{
|
||||
/* No restrictions. */
|
||||
if (!supported_io_srcs)
|
||||
return;
|
||||
|
||||
const rogue_instr *instr = use->instr;
|
||||
|
||||
rogue_foreach_phase_in_set (p, rogue_instr_supported_phases(instr)) {
|
||||
enum rogue_io io_src = rogue_instr_src_io_src(instr, p, use->src_index);
|
||||
if (io_src == ROGUE_IO_INVALID)
|
||||
validate_log(state, "Register used where no source is present.");
|
||||
|
||||
if (!rogue_io_supported(io_src, supported_io_srcs))
|
||||
validate_log(state,
|
||||
"Register class unsupported in S%u.",
|
||||
io_src - ROGUE_IO_S0); /* TODO: Either add info here to
|
||||
get register class and print as
|
||||
string, or add info to
|
||||
rogue_validation_state. */
|
||||
}
|
||||
}
|
||||
|
||||
static void validate_reg_state(rogue_validation_state *state,
|
||||
rogue_shader *shader)
|
||||
{
|
||||
BITSET_WORD *regs_used = NULL;
|
||||
|
||||
for (enum rogue_reg_class class = 0; class < ROGUE_REG_CLASS_COUNT;
|
||||
++class) {
|
||||
const rogue_reg_info *info = &rogue_reg_infos[class];
|
||||
if (info->num)
|
||||
regs_used =
|
||||
rzalloc_size(state, sizeof(*regs_used) * BITSET_WORDS(info->num));
|
||||
|
||||
rogue_foreach_reg (reg, shader, class) {
|
||||
/* Ensure that the range restrictions are satisfied. */
|
||||
if (info->num && reg->index >= info->num)
|
||||
validate_log(state, "%s register index out of range.", info->name);
|
||||
|
||||
/* Ensure that only registers of this class are in the regs list. */
|
||||
if (reg->class != class)
|
||||
validate_log(state,
|
||||
"%s register found in %s register list.",
|
||||
rogue_reg_infos[reg->class].name,
|
||||
info->name);
|
||||
|
||||
/* Track the registers used in the class. */
|
||||
if (info->num)
|
||||
BITSET_SET(regs_used, reg->index);
|
||||
|
||||
/* Check register cache entry. */
|
||||
rogue_reg **reg_cached =
|
||||
util_sparse_array_get(&shader->reg_cache[class], reg->index);
|
||||
if (!reg_cached || !*reg_cached)
|
||||
validate_log(state,
|
||||
"Missing %s register %u cache entry.",
|
||||
info->name,
|
||||
reg->index);
|
||||
else if (*reg_cached != reg || (*reg_cached)->index != reg->index ||
|
||||
(*reg_cached)->class != reg->class)
|
||||
validate_log(state,
|
||||
"Mismatching %s register %u cache entry.",
|
||||
info->name,
|
||||
reg->index);
|
||||
else if (reg_cached != reg->cached)
|
||||
validate_log(state,
|
||||
"Mismatching %s register %u cache entry pointer.",
|
||||
info->name,
|
||||
reg->index);
|
||||
|
||||
/* Validate register uses. */
|
||||
const rogue_reg_info *reg_info = &rogue_reg_infos[class];
|
||||
rogue_foreach_reg_use (use, reg)
|
||||
validate_reg_use(state, use, reg_info->supported_io_srcs);
|
||||
}
|
||||
|
||||
/* Check that the registers used matches the usage list. */
|
||||
if (info->num && memcmp(shader->regs_used[class],
|
||||
regs_used,
|
||||
sizeof(*regs_used) * BITSET_WORDS(info->num)))
|
||||
validate_log(state, "Incorrect %s register usage list.", info->name);
|
||||
|
||||
ralloc_free(regs_used);
|
||||
}
|
||||
|
||||
/* Check that SSA registers aren't being written to more than once. */
|
||||
rogue_foreach_reg (reg, shader, ROGUE_REG_CLASS_SSA)
|
||||
if (list_length(®->writes) > 1)
|
||||
validate_log(state,
|
||||
"SSA register %u is written to more than once.",
|
||||
reg->index);
|
||||
|
||||
rogue_foreach_regarray (regarray, shader) {
|
||||
/* Validate regarray contents. */
|
||||
validate_regarray(state, regarray);
|
||||
|
||||
/* Check regarray cache entry. */
|
||||
uint64_t key = rogue_regarray_cache_key(regarray->size,
|
||||
regarray->regs[0]->class,
|
||||
regarray->regs[0]->index,
|
||||
false,
|
||||
0);
|
||||
rogue_regarray **regarray_cached =
|
||||
util_sparse_array_get(&shader->regarray_cache, key);
|
||||
if (!regarray_cached || !*regarray_cached)
|
||||
validate_log(state, "Missing regarray cache entry.");
|
||||
else if (*regarray_cached != regarray ||
|
||||
(*regarray_cached)->size != regarray->size ||
|
||||
(*regarray_cached)->parent != regarray->parent ||
|
||||
(*regarray_cached)->regs != regarray->regs)
|
||||
validate_log(state, "Mismatching regarray cache entry.");
|
||||
else if (regarray_cached != regarray->cached)
|
||||
validate_log(state, "Mismatching regarray cache entry pointer.");
|
||||
|
||||
if (regarray->parent && (regarray->parent->size <= regarray->size ||
|
||||
regarray->parent->parent))
|
||||
validate_log(state, "Invalid sub-regarray.");
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: To properly test this and see what needs validating, try and write some
|
||||
* failing tests and then filling them from there. */
|
||||
PUBLIC
|
||||
bool rogue_validate_shader(rogue_shader *shader, const char *when)
|
||||
{
|
||||
if (ROGUE_DEBUG(VLD_SKIP))
|
||||
return true;
|
||||
|
||||
bool errors_present;
|
||||
|
||||
rogue_validation_state *state = create_validation_state(shader, when);
|
||||
|
||||
validate_reg_state(state, shader);
|
||||
|
||||
/* TODO: Ensure there is at least one block (with at least an end
|
||||
* instruction!) */
|
||||
rogue_foreach_block (block, shader)
|
||||
validate_block(state, block);
|
||||
|
||||
errors_present = validate_print_errors(state);
|
||||
|
||||
ralloc_free(state);
|
||||
|
||||
return !errors_present;
|
||||
}
|
||||
|
|
|
|||
39
src/imagination/rogue/tools/meson.build
Normal file
39
src/imagination/rogue/tools/meson.build
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
# Copyright © 2022 Imagination Technologies Ltd.
|
||||
|
||||
# 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.
|
||||
|
||||
rogue_compiler = executable(
|
||||
'rogue_vk_compiler',
|
||||
'vk_compiler.c',
|
||||
link_with : [libpowervr_rogue],
|
||||
dependencies : [idep_mesautil, idep_nir],
|
||||
include_directories : [
|
||||
inc_mesa,
|
||||
inc_include,
|
||||
inc_src,
|
||||
inc_mapi,
|
||||
inc_gallium,
|
||||
inc_gallium_aux,
|
||||
inc_compiler,
|
||||
inc_rogue,
|
||||
],
|
||||
build_by_default : with_imagination_tools,
|
||||
install : false,
|
||||
)
|
||||
|
|
@ -24,26 +24,23 @@
|
|||
#include "compiler/shader_enums.h"
|
||||
#include "nir/nir.h"
|
||||
#include "rogue.h"
|
||||
#include "rogue_build_data.h"
|
||||
#include "rogue_compiler.h"
|
||||
#include "rogue_dump.h"
|
||||
#include "util/macros.h"
|
||||
#include "util/os_file.h"
|
||||
#include "util/ralloc.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Number of hex columns to dump before starting a new line. */
|
||||
#define ARRAY_DUMP_COLS 16
|
||||
/* Number of hex columns to print before starting a new line. */
|
||||
#define ARRAY_PRINT_COLS 16
|
||||
|
||||
/**
|
||||
* \file compiler.c
|
||||
* \file vk_compiler.c
|
||||
*
|
||||
* \brief Rogue offline compiler.
|
||||
* \brief Rogue offline Vulkan shader compiler.
|
||||
*/
|
||||
|
||||
static const struct option cmdline_opts[] = {
|
||||
|
|
@ -56,28 +53,21 @@ static const struct option cmdline_opts[] = {
|
|||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "out", required_argument, NULL, 'o' },
|
||||
|
||||
{ "dump-c-array", no_argument, NULL, 'c' },
|
||||
{ "dump-rogue", no_argument, NULL, 'r' },
|
||||
{ "dump-nir", no_argument, NULL, 'n' },
|
||||
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
struct compiler_opts {
|
||||
typedef struct compiler_opts {
|
||||
gl_shader_stage stage;
|
||||
char *file;
|
||||
char *entry;
|
||||
char *out_file;
|
||||
bool dump_c_array;
|
||||
bool dump_rogue;
|
||||
bool dump_nir;
|
||||
};
|
||||
} compiler_opts;
|
||||
|
||||
static void usage(const char *argv0)
|
||||
{
|
||||
/* clang-format off */
|
||||
printf("Rogue offline compiler.\n");
|
||||
printf("Usage: %s -s <stage> -f <file> [-e <entry>] [-o <file>] [-c] [-r] [-n] [-h]\n", argv0);
|
||||
printf("Rogue offline Vulkan shader compiler.\n");
|
||||
printf("Usage: %s -s <stage> -f <file> [-e <entry>] [-o <file>] [-h]\n", argv0);
|
||||
printf("\n");
|
||||
|
||||
printf("Required arguments:\n");
|
||||
|
|
@ -90,11 +80,6 @@ static void usage(const char *argv0)
|
|||
printf("\t-e, --entry <entry> Overrides the shader entry-point name (default: 'main').\n");
|
||||
printf("\t-o, --out <file> Overrides the output filename (default: 'out.bin').\n");
|
||||
printf("\n");
|
||||
|
||||
printf("\t-c, --dump-c-array Print the shader binary as a C byte array.\n");
|
||||
printf("\t-r, --dump-rogue Prints the shader Rogue assembly.\n");
|
||||
printf("\t-n, --dump-nir Prints the shader NIR.\n");
|
||||
printf("\n");
|
||||
/* clang-format on */
|
||||
}
|
||||
|
||||
|
|
@ -104,14 +89,9 @@ static bool parse_cmdline(int argc, char *argv[], struct compiler_opts *opts)
|
|||
int longindex;
|
||||
|
||||
while (
|
||||
(opt =
|
||||
getopt_long(argc, argv, "crnhs:f:e:o:", cmdline_opts, &longindex)) !=
|
||||
(opt = getopt_long(argc, argv, "hs:f:e:o:", cmdline_opts, &longindex)) !=
|
||||
-1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
opts->dump_c_array = true;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
if (opts->entry)
|
||||
continue;
|
||||
|
|
@ -126,10 +106,6 @@ static bool parse_cmdline(int argc, char *argv[], struct compiler_opts *opts)
|
|||
opts->file = optarg;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
opts->dump_nir = true;
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (opts->out_file)
|
||||
continue;
|
||||
|
|
@ -137,17 +113,13 @@ static bool parse_cmdline(int argc, char *argv[], struct compiler_opts *opts)
|
|||
opts->out_file = optarg;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
opts->dump_rogue = true;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (opts->stage != MESA_SHADER_NONE)
|
||||
continue;
|
||||
|
||||
if (!strcmp(optarg, "frag"))
|
||||
if (!strcmp(optarg, "frag") || !strcmp(optarg, "f"))
|
||||
opts->stage = MESA_SHADER_FRAGMENT;
|
||||
else if (!strcmp(optarg, "vert"))
|
||||
else if (!strcmp(optarg, "vert") || !strcmp(optarg, "v"))
|
||||
opts->stage = MESA_SHADER_VERTEX;
|
||||
else {
|
||||
fprintf(stderr, "Invalid stage \"%s\".\n", optarg);
|
||||
|
|
@ -185,7 +157,7 @@ int main(int argc, char *argv[])
|
|||
{
|
||||
/* Command-line options. */
|
||||
/* N.B. MESA_SHADER_NONE != 0 */
|
||||
struct compiler_opts opts = { .stage = MESA_SHADER_NONE, 0 };
|
||||
compiler_opts opts = { .stage = MESA_SHADER_NONE, 0 };
|
||||
|
||||
/* Input file data. */
|
||||
char *input_data;
|
||||
|
|
@ -219,7 +191,8 @@ int main(int argc, char *argv[])
|
|||
goto err_free_input;
|
||||
}
|
||||
|
||||
ctx = rogue_create_build_context(compiler);
|
||||
/* Create build context. */
|
||||
ctx = rogue_build_context_create(compiler);
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "Failed to set up build context.\n");
|
||||
goto err_destroy_compiler;
|
||||
|
|
@ -238,10 +211,6 @@ int main(int argc, char *argv[])
|
|||
goto err_free_build_context;
|
||||
}
|
||||
|
||||
/* Dump NIR shader. */
|
||||
if (opts.dump_nir)
|
||||
nir_print_shader(ctx->nir[opts.stage], stdout);
|
||||
|
||||
/* NIR -> Rogue. */
|
||||
ctx->rogue[opts.stage] = rogue_nir_to_rogue(ctx, ctx->nir[opts.stage]);
|
||||
if (!ctx->rogue[opts.stage]) {
|
||||
|
|
@ -249,28 +218,7 @@ int main(int argc, char *argv[])
|
|||
goto err_free_build_context;
|
||||
}
|
||||
|
||||
/* Dump Rogue shader. */
|
||||
if (opts.dump_rogue)
|
||||
rogue_dump_shader(ctx->rogue[opts.stage], stdout);
|
||||
|
||||
/* Rogue -> Binary. */
|
||||
ctx->binary[opts.stage] = rogue_to_binary(ctx, ctx->rogue[opts.stage]);
|
||||
if (!ctx->binary[opts.stage]) {
|
||||
fprintf(stderr, "Failed to translate Rogue to binary.\n");
|
||||
goto err_free_build_context;
|
||||
}
|
||||
|
||||
/* Dump binary as a C array. */
|
||||
if (opts.dump_c_array) {
|
||||
printf("uint8_t shader_bytes[%zu] = {", ctx->binary[opts.stage]->size);
|
||||
for (size_t u = 0U; u < ctx->binary[opts.stage]->size; ++u) {
|
||||
if (!(u % ARRAY_DUMP_COLS))
|
||||
printf("\n\t");
|
||||
|
||||
printf("0x%02x, ", ctx->binary[opts.stage]->data[u]);
|
||||
}
|
||||
printf("\n};\n");
|
||||
}
|
||||
rogue_encode_shader(ctx, ctx->rogue[opts.stage], &ctx->binary[opts.stage]);
|
||||
|
||||
/* Write shader binary to disk. */
|
||||
fp = fopen(opts.out_file, "wb");
|
||||
|
|
@ -279,24 +227,22 @@ int main(int argc, char *argv[])
|
|||
goto err_free_build_context;
|
||||
}
|
||||
|
||||
bytes_written = fwrite(ctx->binary[opts.stage]->data,
|
||||
1,
|
||||
ctx->binary[opts.stage]->size,
|
||||
fp);
|
||||
if (bytes_written != ctx->binary[opts.stage]->size) {
|
||||
bytes_written =
|
||||
fwrite(ctx->binary[opts.stage].data, 1, ctx->binary[opts.stage].size, fp);
|
||||
if (bytes_written != ctx->binary[opts.stage].size) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to write to output file \"%s\" (%zu bytes of %zu written).\n",
|
||||
"Failed to write to output file \"%s\" (%zu bytes of %u written).\n",
|
||||
opts.out_file,
|
||||
bytes_written,
|
||||
ctx->binary[opts.stage]->size);
|
||||
ctx->binary[opts.stage].size);
|
||||
goto err_close_outfile;
|
||||
}
|
||||
|
||||
/* Clean up. */
|
||||
fclose(fp);
|
||||
ralloc_free(ctx);
|
||||
rogue_compiler_destroy(compiler);
|
||||
ralloc_free(compiler);
|
||||
free(input_data);
|
||||
|
||||
return 0;
|
||||
|
|
@ -306,7 +252,7 @@ err_close_outfile:
|
|||
err_free_build_context:
|
||||
ralloc_free(ctx);
|
||||
err_destroy_compiler:
|
||||
rogue_compiler_destroy(compiler);
|
||||
ralloc_free(compiler);
|
||||
err_free_input:
|
||||
free(input_data);
|
||||
|
||||
|
|
@ -487,7 +487,7 @@ VkResult pvr_device_init_graphics_static_clear_state(struct pvr_device *device)
|
|||
|
||||
struct pvr_device_static_clear_state *state = &device->static_clear_state;
|
||||
const uint32_t cache_line_size = rogue_get_slc_cache_line_size(dev_info);
|
||||
const struct rogue_shader_binary *passthrough_vert_shader;
|
||||
struct util_dynarray passthrough_vert_shader;
|
||||
struct pvr_pds_vertex_shader_program pds_program;
|
||||
VkResult result;
|
||||
|
||||
|
|
@ -514,14 +514,16 @@ VkResult pvr_device_init_graphics_static_clear_state(struct pvr_device *device)
|
|||
state->usc_multi_layer_vertex_shader_bo = NULL;
|
||||
}
|
||||
|
||||
util_dynarray_init(&passthrough_vert_shader, NULL);
|
||||
pvr_hard_code_get_passthrough_vertex_shader(dev_info,
|
||||
&passthrough_vert_shader);
|
||||
|
||||
result = pvr_gpu_upload_usc(device,
|
||||
passthrough_vert_shader->data,
|
||||
passthrough_vert_shader->size,
|
||||
passthrough_vert_shader.data,
|
||||
passthrough_vert_shader.size,
|
||||
cache_line_size,
|
||||
&state->usc_vertex_shader_bo);
|
||||
util_dynarray_fini(&passthrough_vert_shader);
|
||||
if (result != VK_SUCCESS)
|
||||
goto err_free_usc_multi_layer_shader;
|
||||
|
||||
|
|
|
|||
|
|
@ -55,12 +55,13 @@
|
|||
#include "pvr_tex_state.h"
|
||||
#include "pvr_types.h"
|
||||
#include "pvr_winsys.h"
|
||||
#include "rogue/rogue_compiler.h"
|
||||
#include "rogue/rogue.h"
|
||||
#include "util/build_id.h"
|
||||
#include "util/log.h"
|
||||
#include "util/macros.h"
|
||||
#include "util/mesa-sha1.h"
|
||||
#include "util/os_misc.h"
|
||||
#include "util/u_dynarray.h"
|
||||
#include "util/u_math.h"
|
||||
#include "vk_alloc.h"
|
||||
#include "vk_log.h"
|
||||
|
|
@ -218,7 +219,7 @@ static void pvr_physical_device_finish(struct pvr_physical_device *pdevice)
|
|||
*/
|
||||
|
||||
if (pdevice->compiler)
|
||||
rogue_compiler_destroy(pdevice->compiler);
|
||||
ralloc_free(pdevice->compiler);
|
||||
|
||||
pvr_wsi_finish(pdevice);
|
||||
|
||||
|
|
@ -1349,13 +1350,14 @@ static VkResult pvr_device_init_compute_idfwdf_state(struct pvr_device *device)
|
|||
{
|
||||
uint64_t sampler_state[ROGUE_NUM_TEXSTATE_SAMPLER_WORDS];
|
||||
uint64_t image_state[ROGUE_NUM_TEXSTATE_IMAGE_WORDS];
|
||||
const struct rogue_shader_binary *usc_program;
|
||||
struct util_dynarray usc_program;
|
||||
struct pvr_texture_state_info tex_info;
|
||||
uint32_t *dword_ptr;
|
||||
uint32_t usc_shareds;
|
||||
uint32_t usc_temps;
|
||||
VkResult result;
|
||||
|
||||
util_dynarray_init(&usc_program, NULL);
|
||||
pvr_hard_code_get_idfwdf_program(&device->pdevice->dev_info,
|
||||
&usc_program,
|
||||
&usc_shareds,
|
||||
|
|
@ -1365,10 +1367,12 @@ static VkResult pvr_device_init_compute_idfwdf_state(struct pvr_device *device)
|
|||
|
||||
/* FIXME: Figure out the define for alignment of 16. */
|
||||
result = pvr_gpu_upload_usc(device,
|
||||
usc_program->data,
|
||||
usc_program->size,
|
||||
usc_program.data,
|
||||
usc_program.size,
|
||||
16,
|
||||
&device->idfwdf_state.usc);
|
||||
util_dynarray_fini(&usc_program);
|
||||
|
||||
if (result != VK_SUCCESS)
|
||||
return result;
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@ enum pvr_hard_code_shader_type {
|
|||
PVR_HARD_CODE_SHADER_TYPE_GRAPHICS,
|
||||
};
|
||||
|
||||
#define util_dynarray_append_mem(buf, size, mem) \
|
||||
memcpy(util_dynarray_grow_bytes((buf), 1, size), mem, size)
|
||||
|
||||
/* Table indicating which demo and for which device the compiler is capable of
|
||||
* generating valid shaders.
|
||||
*/
|
||||
|
|
@ -65,7 +68,7 @@ static struct {
|
|||
} compatiblity_table[] = {
|
||||
{
|
||||
.name = "triangle",
|
||||
.bvncs = { PVR_GX6250_BVNC, },
|
||||
.bvncs = { PVR_GX6250_BVNC, PVR_AXE_1_16M_BVNC, },
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -89,8 +92,10 @@ static const struct pvr_hard_coding_data {
|
|||
/* Mask of MESA_SHADER_* (gl_shader_stage). */
|
||||
uint32_t flags;
|
||||
|
||||
struct rogue_shader_binary *const *const vert_shaders;
|
||||
struct rogue_shader_binary *const *const frag_shaders;
|
||||
uint8_t *const *const vert_shaders;
|
||||
unsigned *vert_shader_sizes;
|
||||
uint8_t *const *const frag_shaders;
|
||||
unsigned *frag_shader_sizes;
|
||||
|
||||
const struct pvr_vertex_shader_state *const *const vert_shader_states;
|
||||
const struct pvr_fragment_shader_state *const *const frag_shader_states;
|
||||
|
|
@ -225,7 +230,7 @@ pvr_hard_code_graphics_get_flags(const struct pvr_device_info *const dev_info)
|
|||
void pvr_hard_code_graphics_shader(const struct pvr_device_info *const dev_info,
|
||||
uint32_t pipeline_n,
|
||||
gl_shader_stage stage,
|
||||
struct rogue_shader_binary **const shader_out)
|
||||
struct util_dynarray *shader_out)
|
||||
{
|
||||
const struct pvr_hard_coding_data *const data =
|
||||
pvr_get_hard_coding_data(dev_info);
|
||||
|
|
@ -240,11 +245,15 @@ void pvr_hard_code_graphics_shader(const struct pvr_device_info *const dev_info,
|
|||
|
||||
switch (stage) {
|
||||
case MESA_SHADER_VERTEX:
|
||||
*shader_out = data->graphics.vert_shaders[pipeline_n];
|
||||
util_dynarray_append_mem(shader_out,
|
||||
data->graphics.vert_shader_sizes[pipeline_n],
|
||||
data->graphics.vert_shaders[pipeline_n]);
|
||||
break;
|
||||
|
||||
case MESA_SHADER_FRAGMENT:
|
||||
*shader_out = data->graphics.frag_shaders[pipeline_n];
|
||||
util_dynarray_append_mem(shader_out,
|
||||
data->graphics.frag_shader_sizes[pipeline_n],
|
||||
data->graphics.frag_shaders[pipeline_n]);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
@ -339,33 +348,30 @@ void pvr_hard_code_graphics_get_build_info(
|
|||
|
||||
void pvr_hard_code_get_idfwdf_program(
|
||||
const struct pvr_device_info *const dev_info,
|
||||
const struct rogue_shader_binary **const program_out,
|
||||
struct util_dynarray *program_out,
|
||||
uint32_t *usc_shareds_out,
|
||||
uint32_t *usc_temps_out)
|
||||
{
|
||||
static const struct rogue_shader_binary shader = {
|
||||
.size = 8U,
|
||||
.data = { 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
static const uint8_t shader[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
mesa_loge("No hard coded idfwdf program. Returning empty program.");
|
||||
*program_out = &shader;
|
||||
|
||||
util_dynarray_append_mem(program_out, ARRAY_SIZE(shader), &shader[0]);
|
||||
|
||||
*usc_shareds_out = 12U;
|
||||
*usc_temps_out = 4U;
|
||||
}
|
||||
|
||||
void pvr_hard_code_get_passthrough_vertex_shader(
|
||||
const struct pvr_device_info *const dev_info,
|
||||
const struct rogue_shader_binary **const program_out)
|
||||
struct util_dynarray *program_out)
|
||||
{
|
||||
static const struct rogue_shader_binary shader = {
|
||||
.size = 8U,
|
||||
.data = { 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||
};
|
||||
static const uint8_t shader[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
mesa_loge(
|
||||
"No hard coded passthrough vertex shader. Returning empty shader.");
|
||||
*program_out = &shader;
|
||||
|
||||
util_dynarray_append_mem(program_out, ARRAY_SIZE(shader), &shader[0]);
|
||||
};
|
||||
|
||||
/* Render target array (RTA). */
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "compiler/shader_enums.h"
|
||||
#include "rogue/rogue_build_data.h"
|
||||
#include "rogue/rogue.h"
|
||||
#include "util/u_dynarray.h"
|
||||
|
||||
/**
|
||||
|
|
@ -53,8 +53,8 @@ struct pvr_explicit_constant_usage {
|
|||
};
|
||||
|
||||
struct pvr_hard_code_compute_build_info {
|
||||
struct rogue_ubo_data ubo_data;
|
||||
struct rogue_compile_time_consts_data compile_time_consts_data;
|
||||
rogue_ubo_data ubo_data;
|
||||
rogue_compile_time_consts_data compile_time_consts_data;
|
||||
|
||||
uint32_t local_invocation_regs[2];
|
||||
uint32_t work_group_regs[3];
|
||||
|
|
@ -65,10 +65,10 @@ struct pvr_hard_code_compute_build_info {
|
|||
};
|
||||
|
||||
struct pvr_hard_code_graphics_build_info {
|
||||
struct rogue_build_data stage_data;
|
||||
rogue_build_data stage_data;
|
||||
|
||||
struct rogue_common_build_data vert_common_data;
|
||||
struct rogue_common_build_data frag_common_data;
|
||||
rogue_common_build_data vert_common_data;
|
||||
rogue_common_build_data frag_common_data;
|
||||
|
||||
struct pvr_explicit_constant_usage vert_explicit_conts_usage;
|
||||
struct pvr_explicit_constant_usage frag_explicit_conts_usage;
|
||||
|
|
@ -96,11 +96,10 @@ pvr_hard_code_graphics_get_flags(const struct pvr_device_info *const dev_info);
|
|||
* This pipeline number to request data for the first pipeline to be created
|
||||
* is 0 and should be incremented for each subsequent pipeline.
|
||||
*/
|
||||
void pvr_hard_code_graphics_shader(
|
||||
const struct pvr_device_info *const dev_info,
|
||||
uint32_t pipeline_n,
|
||||
gl_shader_stage stage,
|
||||
struct rogue_shader_binary **const shader_out);
|
||||
void pvr_hard_code_graphics_shader(const struct pvr_device_info *const dev_info,
|
||||
uint32_t pipeline_n,
|
||||
gl_shader_stage stage,
|
||||
struct util_dynarray *shader_out);
|
||||
|
||||
void pvr_hard_code_graphics_vertex_state(
|
||||
const struct pvr_device_info *const dev_info,
|
||||
|
|
@ -116,19 +115,19 @@ void pvr_hard_code_graphics_get_build_info(
|
|||
const struct pvr_device_info *const dev_info,
|
||||
uint32_t pipeline_n,
|
||||
gl_shader_stage stage,
|
||||
struct rogue_common_build_data *const common_build_data,
|
||||
struct rogue_build_data *const build_data,
|
||||
rogue_common_build_data *const common_build_data,
|
||||
rogue_build_data *const build_data,
|
||||
struct pvr_explicit_constant_usage *const explicit_const_usage);
|
||||
|
||||
void pvr_hard_code_get_idfwdf_program(
|
||||
const struct pvr_device_info *const dev_info,
|
||||
const struct rogue_shader_binary **const program_out,
|
||||
struct util_dynarray *program_out,
|
||||
uint32_t *usc_shareds_out,
|
||||
uint32_t *usc_temps_out);
|
||||
|
||||
void pvr_hard_code_get_passthrough_vertex_shader(
|
||||
const struct pvr_device_info *const dev_info,
|
||||
const struct rogue_shader_binary **const program_out);
|
||||
struct util_dynarray *program_out);
|
||||
void pvr_hard_code_get_passthrough_rta_vertex_shader(
|
||||
const struct pvr_device_info *const dev_info,
|
||||
struct util_dynarray *program_out);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
#include "pvr_shader.h"
|
||||
#include "pvr_types.h"
|
||||
#include "rogue/rogue.h"
|
||||
#include "rogue/rogue_build_data.h"
|
||||
#include "util/log.h"
|
||||
#include "util/macros.h"
|
||||
#include "util/ralloc.h"
|
||||
|
|
@ -1423,7 +1422,7 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device,
|
|||
VkResult result;
|
||||
|
||||
/* Setup shared build context. */
|
||||
ctx = rogue_create_build_context(compiler);
|
||||
ctx = rogue_build_context_create(compiler);
|
||||
if (!ctx)
|
||||
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
|
||||
|
|
@ -1507,8 +1506,8 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device,
|
|||
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
}
|
||||
|
||||
ctx->binary[stage] = pvr_rogue_to_binary(ctx, ctx->rogue[stage]);
|
||||
if (!ctx->binary[stage]) {
|
||||
pvr_rogue_to_binary(ctx, ctx->rogue[stage], &ctx->binary[stage]);
|
||||
if (!ctx->binary[stage].size) {
|
||||
ralloc_free(ctx);
|
||||
return vk_error(device, VK_ERROR_OUT_OF_HOST_MEMORY);
|
||||
}
|
||||
|
|
@ -1527,8 +1526,8 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device,
|
|||
}
|
||||
|
||||
result = pvr_gpu_upload_usc(device,
|
||||
ctx->binary[MESA_SHADER_VERTEX]->data,
|
||||
ctx->binary[MESA_SHADER_VERTEX]->size,
|
||||
ctx->binary[MESA_SHADER_VERTEX].data,
|
||||
ctx->binary[MESA_SHADER_VERTEX].size,
|
||||
cache_line_size,
|
||||
&gfx_pipeline->shader_state.vertex.bo);
|
||||
if (result != VK_SUCCESS)
|
||||
|
|
@ -1547,8 +1546,8 @@ pvr_graphics_pipeline_compile(struct pvr_device *const device,
|
|||
}
|
||||
|
||||
result = pvr_gpu_upload_usc(device,
|
||||
ctx->binary[MESA_SHADER_FRAGMENT]->data,
|
||||
ctx->binary[MESA_SHADER_FRAGMENT]->size,
|
||||
ctx->binary[MESA_SHADER_FRAGMENT].data,
|
||||
ctx->binary[MESA_SHADER_FRAGMENT].size,
|
||||
cache_line_size,
|
||||
&gfx_pipeline->shader_state.fragment.bo);
|
||||
if (result != VK_SUCCESS)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@
|
|||
#include "pvr_private.h"
|
||||
#include "pvr_shader.h"
|
||||
#include "rogue/rogue.h"
|
||||
#include "rogue/rogue_shader.h"
|
||||
#include "spirv/nir_spirv.h"
|
||||
#include "vk_format.h"
|
||||
#include "vk_shader_module.h"
|
||||
|
|
@ -52,7 +51,7 @@
|
|||
* \param[in] create_info Shader creation info from Vulkan pipeline.
|
||||
* \return A nir_shader* if successful, or NULL if unsuccessful.
|
||||
*/
|
||||
nir_shader *pvr_spirv_to_nir(struct rogue_build_ctx *ctx,
|
||||
nir_shader *pvr_spirv_to_nir(rogue_build_ctx *ctx,
|
||||
gl_shader_stage stage,
|
||||
const VkPipelineShaderStageCreateInfo *create_info)
|
||||
{
|
||||
|
|
@ -84,8 +83,7 @@ nir_shader *pvr_spirv_to_nir(struct rogue_build_ctx *ctx,
|
|||
* \param[in] nir NIR shader.
|
||||
* \return A rogue_shader* if successful, or NULL if unsuccessful.
|
||||
*/
|
||||
struct rogue_shader *pvr_nir_to_rogue(struct rogue_build_ctx *ctx,
|
||||
nir_shader *nir)
|
||||
rogue_shader *pvr_nir_to_rogue(rogue_build_ctx *ctx, nir_shader *nir)
|
||||
{
|
||||
return rogue_nir_to_rogue(ctx, nir);
|
||||
}
|
||||
|
|
@ -95,10 +93,11 @@ struct rogue_shader *pvr_nir_to_rogue(struct rogue_build_ctx *ctx,
|
|||
*
|
||||
* \param[in] ctx Shared multi-stage build context.
|
||||
* \param[in] shader Rogue shader.
|
||||
* \return A rogue_shader_binary* if successful, or NULL if unsuccessful.
|
||||
* \param[out] binary Array containing shader binary.
|
||||
*/
|
||||
struct rogue_shader_binary *pvr_rogue_to_binary(struct rogue_build_ctx *ctx,
|
||||
struct rogue_shader *shader)
|
||||
void pvr_rogue_to_binary(rogue_build_ctx *ctx,
|
||||
rogue_shader *shader,
|
||||
struct util_dynarray *binary)
|
||||
{
|
||||
return rogue_to_binary(ctx, shader);
|
||||
rogue_encode_shader(ctx, shader, binary);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,21 +28,19 @@
|
|||
|
||||
#include "compiler/shader_enums.h"
|
||||
#include "nir/nir.h"
|
||||
#include "rogue/rogue.h"
|
||||
#include "util/u_dynarray.h"
|
||||
#include "vulkan/vulkan.h"
|
||||
|
||||
struct rogue_build_ctx;
|
||||
struct rogue_compiler;
|
||||
struct rogue_shader;
|
||||
|
||||
nir_shader *
|
||||
pvr_spirv_to_nir(struct rogue_build_ctx *ctx,
|
||||
pvr_spirv_to_nir(rogue_build_ctx *ctx,
|
||||
gl_shader_stage stage,
|
||||
const VkPipelineShaderStageCreateInfo *create_info);
|
||||
|
||||
struct rogue_shader *pvr_nir_to_rogue(struct rogue_build_ctx *ctx,
|
||||
nir_shader *nir);
|
||||
rogue_shader *pvr_nir_to_rogue(rogue_build_ctx *ctx, nir_shader *nir);
|
||||
|
||||
struct rogue_shader_binary *pvr_rogue_to_binary(struct rogue_build_ctx *ctx,
|
||||
struct rogue_shader *rogue);
|
||||
void pvr_rogue_to_binary(rogue_build_ctx *ctx,
|
||||
rogue_shader *shader,
|
||||
struct util_dynarray *binary);
|
||||
|
||||
#endif /* PVR_SHADER_H */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue