Files
third_party_mesa3d/src/gallium/drivers/lima/ir/gp/nir.c
Connor Abbott 11a49f289d lima/gp: Support exp2 and log2
log2 is tricky because there cannot be a move between complex1 and
postlog2. We can't guarantee that scheduling complex1 will succeed when
we schedule postlog2, so we try to schedule complex1 and if it fails we
back out by rewriting the postlog2 as a move and introducing a new
postlog2 so that we can try again later.

Signed-off-by: Connor Abbott <cwabbott0@gmail.com>
Acked-by: Qiang Yu <yuq825@gmail.com>
2019-07-30 23:01:15 +02:00

457 lines
13 KiB
C

/*
* Copyright (c) 2017 Lima Project
*
* 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, sub license,
* 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 NON-INFRINGEMENT. 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 "util/ralloc.h"
#include "compiler/nir/nir.h"
#include "gpir.h"
#include "lima_context.h"
static inline void *gpir_node_create_ssa(gpir_block *block, gpir_op op, nir_ssa_def *ssa)
{
int index = ssa->index;
gpir_node *node = gpir_node_create(block, op);
block->comp->var_nodes[index] = node;
snprintf(node->name, sizeof(node->name), "ssa%d", index);
list_addtail(&node->list, &block->node_list);
return node;
}
static inline void *gpir_node_create_reg(gpir_block *block, gpir_op op, nir_reg_dest *reg)
{
int index = reg->reg->index;
gpir_node *node = gpir_node_create(block, op);
gpir_store_node *store = gpir_node_create(block, gpir_op_store_reg);
snprintf(node->name, sizeof(node->name), "reg%d", index);
store->child = node;
gpir_node_add_dep(&store->node, node, GPIR_DEP_INPUT);
list_for_each_entry(gpir_reg, reg, &block->comp->reg_list, list) {
if (reg->index == index) {
store->reg = reg;
list_addtail(&store->reg_link, &reg->defs_list);
break;
}
}
list_addtail(&node->list, &block->node_list);
list_addtail(&store->node.list, &block->node_list);
return node;
}
static void *gpir_node_create_dest(gpir_block *block, gpir_op op, nir_dest *dest)
{
if (dest->is_ssa)
return gpir_node_create_ssa(block, op, &dest->ssa);
else
return gpir_node_create_reg(block, op, &dest->reg);
}
static gpir_node *gpir_node_find(gpir_block *block, gpir_node *succ, nir_src *src,
int channel)
{
gpir_node *pred = NULL;
if (src->is_ssa) {
if (src->ssa->num_components > 1) {
for (int i = 0; i < GPIR_VECTOR_SSA_NUM; i++) {
if (block->comp->vector_ssa[i].ssa == src->ssa->index) {
pred = block->comp->vector_ssa[i].nodes[channel];
break;
}
}
} else
pred = block->comp->var_nodes[src->ssa->index];
assert(pred);
}
else {
pred = gpir_node_create(block, gpir_op_load_reg);
list_addtail(&pred->list, &succ->list);
gpir_load_node *load = gpir_node_to_load(pred);
list_for_each_entry(gpir_reg, reg, &block->comp->reg_list, list) {
if (reg->index == src->reg.reg->index) {
load->reg = reg;
list_addtail(&load->reg_link, &reg->uses_list);
break;
}
}
}
return pred;
}
static int nir_to_gpir_opcodes[nir_num_opcodes] = {
/* not supported */
[0 ... nir_last_opcode] = -1,
[nir_op_fmul] = gpir_op_mul,
[nir_op_fadd] = gpir_op_add,
[nir_op_fneg] = gpir_op_neg,
[nir_op_fmin] = gpir_op_min,
[nir_op_fmax] = gpir_op_max,
[nir_op_frcp] = gpir_op_rcp,
[nir_op_frsq] = gpir_op_rsqrt,
[nir_op_fexp2] = gpir_op_exp2,
[nir_op_flog2] = gpir_op_log2,
[nir_op_slt] = gpir_op_lt,
[nir_op_sge] = gpir_op_ge,
[nir_op_fcsel] = gpir_op_select,
[nir_op_ffloor] = gpir_op_floor,
[nir_op_fsign] = gpir_op_sign,
[nir_op_seq] = gpir_op_eq,
[nir_op_sne] = gpir_op_ne,
[nir_op_fabs] = gpir_op_abs,
[nir_op_mov] = gpir_op_mov,
};
static bool gpir_emit_alu(gpir_block *block, nir_instr *ni)
{
nir_alu_instr *instr = nir_instr_as_alu(ni);
int op = nir_to_gpir_opcodes[instr->op];
if (op < 0) {
gpir_error("unsupported nir_op: %s\n", nir_op_infos[instr->op].name);
return false;
}
gpir_alu_node *node = gpir_node_create_dest(block, op, &instr->dest.dest);
if (unlikely(!node))
return false;
unsigned num_child = nir_op_infos[instr->op].num_inputs;
assert(num_child <= ARRAY_SIZE(node->children));
node->num_child = num_child;
for (int i = 0; i < num_child; i++) {
nir_alu_src *src = instr->src + i;
node->children_negate[i] = src->negate;
gpir_node *child = gpir_node_find(block, &node->node, &src->src, src->swizzle[0]);
node->children[i] = child;
gpir_node_add_dep(&node->node, child, GPIR_DEP_INPUT);
}
return true;
}
static gpir_node *gpir_create_load(gpir_block *block, nir_dest *dest,
int op, int index, int component)
{
gpir_load_node *load = gpir_node_create_dest(block, op, dest);
if (unlikely(!load))
return NULL;
load->index = index;
load->component = component;
return &load->node;
}
static bool gpir_create_vector_load(gpir_block *block, nir_dest *dest, int index)
{
assert(dest->is_ssa);
assert(index < GPIR_VECTOR_SSA_NUM);
block->comp->vector_ssa[index].ssa = dest->ssa.index;
for (int i = 0; i < dest->ssa.num_components; i++) {
gpir_node *node = gpir_create_load(block, dest, gpir_op_load_uniform,
block->comp->constant_base + index, i);
if (!node)
return false;
block->comp->vector_ssa[index].nodes[i] = node;
snprintf(node->name, sizeof(node->name), "ssa%d.%c", dest->ssa.index, "xyzw"[i]);
}
return true;
}
static bool gpir_emit_intrinsic(gpir_block *block, nir_instr *ni)
{
nir_intrinsic_instr *instr = nir_instr_as_intrinsic(ni);
switch (instr->intrinsic) {
case nir_intrinsic_load_input:
return gpir_create_load(block, &instr->dest,
gpir_op_load_attribute,
nir_intrinsic_base(instr),
nir_intrinsic_component(instr)) != NULL;
case nir_intrinsic_load_uniform:
{
int offset = nir_intrinsic_base(instr);
offset += (int)nir_src_as_float(instr->src[0]);
return gpir_create_load(block, &instr->dest,
gpir_op_load_uniform,
offset / 4, offset % 4) != NULL;
}
case nir_intrinsic_load_viewport_scale:
return gpir_create_vector_load(block, &instr->dest, GPIR_VECTOR_SSA_VIEWPORT_SCALE);
case nir_intrinsic_load_viewport_offset:
return gpir_create_vector_load(block, &instr->dest, GPIR_VECTOR_SSA_VIEWPORT_OFFSET);
case nir_intrinsic_store_output:
{
gpir_store_node *store = gpir_node_create(block, gpir_op_store_varying);
if (unlikely(!store))
return false;
list_addtail(&store->node.list, &block->node_list);
store->index = nir_intrinsic_base(instr);
store->component = nir_intrinsic_component(instr);
gpir_node *child = gpir_node_find(block, &store->node, instr->src, 0);
store->child = child;
gpir_node_add_dep(&store->node, child, GPIR_DEP_INPUT);
return true;
}
default:
gpir_error("unsupported nir_intrinsic_instr %s\n",
nir_intrinsic_infos[instr->intrinsic].name);
return false;
}
}
static bool gpir_emit_load_const(gpir_block *block, nir_instr *ni)
{
nir_load_const_instr *instr = nir_instr_as_load_const(ni);
gpir_const_node *node =
gpir_node_create_ssa(block, gpir_op_const, &instr->def);
if (unlikely(!node))
return false;
assert(instr->def.bit_size == 32);
assert(instr->def.num_components == 1);
node->value.i = instr->value[0].i32;
return true;
}
static bool gpir_emit_ssa_undef(gpir_block *block, nir_instr *ni)
{
gpir_error("nir_ssa_undef_instr not support\n");
return false;
}
static bool gpir_emit_tex(gpir_block *block, nir_instr *ni)
{
gpir_error("nir_jump_instr not support\n");
return false;
}
static bool gpir_emit_jump(gpir_block *block, nir_instr *ni)
{
gpir_error("nir_jump_instr not support\n");
return false;
}
static bool (*gpir_emit_instr[nir_instr_type_phi])(gpir_block *, nir_instr *) = {
[nir_instr_type_alu] = gpir_emit_alu,
[nir_instr_type_intrinsic] = gpir_emit_intrinsic,
[nir_instr_type_load_const] = gpir_emit_load_const,
[nir_instr_type_ssa_undef] = gpir_emit_ssa_undef,
[nir_instr_type_tex] = gpir_emit_tex,
[nir_instr_type_jump] = gpir_emit_jump,
};
static gpir_block *gpir_block_create(gpir_compiler *comp)
{
gpir_block *block = ralloc(comp, gpir_block);
if (!block)
return NULL;
list_inithead(&block->node_list);
list_inithead(&block->instr_list);
return block;
}
static bool gpir_emit_block(gpir_compiler *comp, nir_block *nblock)
{
gpir_block *block = gpir_block_create(comp);
if (!block)
return false;
list_addtail(&block->list, &comp->block_list);
block->comp = comp;
nir_foreach_instr(instr, nblock) {
assert(instr->type < nir_instr_type_phi);
if (!gpir_emit_instr[instr->type](block, instr))
return false;
}
return true;
}
static bool gpir_emit_if(gpir_compiler *comp, nir_if *nif)
{
gpir_error("if nir_cf_node not support\n");
return false;
}
static bool gpir_emit_loop(gpir_compiler *comp, nir_loop *nloop)
{
gpir_error("loop nir_cf_node not support\n");
return false;
}
static bool gpir_emit_function(gpir_compiler *comp, nir_function_impl *nfunc)
{
gpir_error("function nir_cf_node not support\n");
return false;
}
static bool gpir_emit_cf_list(gpir_compiler *comp, struct exec_list *list)
{
foreach_list_typed(nir_cf_node, node, node, list) {
bool ret;
switch (node->type) {
case nir_cf_node_block:
ret = gpir_emit_block(comp, nir_cf_node_as_block(node));
break;
case nir_cf_node_if:
ret = gpir_emit_if(comp, nir_cf_node_as_if(node));
break;
case nir_cf_node_loop:
ret = gpir_emit_loop(comp, nir_cf_node_as_loop(node));
break;
case nir_cf_node_function:
ret = gpir_emit_function(comp, nir_cf_node_as_function(node));
break;
default:
gpir_error("unknown NIR node type %d\n", node->type);
return false;
}
if (!ret)
return false;
}
return true;
}
gpir_reg *gpir_create_reg(gpir_compiler *comp)
{
gpir_reg *reg = ralloc(comp, gpir_reg);
reg->index = comp->cur_reg++;
list_addtail(&reg->list, &comp->reg_list);
list_inithead(&reg->defs_list);
list_inithead(&reg->uses_list);
return reg;
}
static gpir_compiler *gpir_compiler_create(void *prog, unsigned num_reg, unsigned num_ssa)
{
gpir_compiler *comp = rzalloc(prog, gpir_compiler);
list_inithead(&comp->block_list);
list_inithead(&comp->reg_list);
for (int i = 0; i < num_reg; i++)
gpir_create_reg(comp);
for (int i = 0; i < GPIR_VECTOR_SSA_NUM; i++)
comp->vector_ssa[i].ssa = -1;
comp->var_nodes = rzalloc_array(comp, gpir_node *, num_ssa);
comp->prog = prog;
return comp;
}
static int gpir_glsl_type_size(enum glsl_base_type type)
{
/* only support GLSL_TYPE_FLOAT */
assert(type == GLSL_TYPE_FLOAT);
return 4;
}
bool gpir_compile_nir(struct lima_vs_shader_state *prog, struct nir_shader *nir)
{
nir_function_impl *func = nir_shader_get_entrypoint(nir);
gpir_compiler *comp = gpir_compiler_create(prog, func->reg_alloc, func->ssa_alloc);
if (!comp)
return false;
comp->constant_base = nir->num_uniforms;
prog->uniform_pending_offset = nir->num_uniforms * 16;
if (!gpir_emit_cf_list(comp, &func->body))
goto err_out0;
gpir_node_print_prog_seq(comp);
gpir_node_print_prog_dep(comp);
/* increase for viewport uniforms */
comp->constant_base += GPIR_VECTOR_SSA_NUM;
if (!gpir_pre_rsched_lower_prog(comp))
goto err_out0;
if (!gpir_reduce_reg_pressure_schedule_prog(comp))
goto err_out0;
if (!gpir_post_rsched_lower_prog(comp))
goto err_out0;
if (!gpir_regalloc_prog(comp))
goto err_out0;
if (!gpir_schedule_prog(comp))
goto err_out0;
if (!gpir_codegen_prog(comp))
goto err_out0;
nir_foreach_variable(var, &nir->outputs) {
if (var->data.location == VARYING_SLOT_POS)
assert(var->data.driver_location == 0);
struct lima_varying_info *v = prog->varying + var->data.driver_location;
if (!v->components) {
v->component_size = gpir_glsl_type_size(glsl_get_base_type(var->type));
prog->num_varying++;
}
v->components += glsl_get_components(var->type);
}
ralloc_free(comp);
return true;
err_out0:
ralloc_free(comp);
return false;
}