mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-21 22:20:14 +01:00
185 lines
6.3 KiB
C
185 lines
6.3 KiB
C
|
|
/*
|
||
|
|
* Copyright © 2022 Intel Corporation
|
||
|
|
*
|
||
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
|
* copy of this software and associated documentation files (the "Software"),
|
||
|
|
* to deal in the Software without restriction, including without limitation
|
||
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||
|
|
* Software is furnished to do so, subject to the following conditions:
|
||
|
|
*
|
||
|
|
* The above copyright notice and this permission notice (including the next
|
||
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
||
|
|
* Software.
|
||
|
|
*
|
||
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||
|
|
* IN THE SOFTWARE.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "nir.h"
|
||
|
|
|
||
|
|
static nir_alu_type
|
||
|
|
nir_alu_src_type(const nir_alu_instr *instr, unsigned src)
|
||
|
|
{
|
||
|
|
return nir_alu_type_get_base_type(nir_op_infos[instr->op].input_types[src]) |
|
||
|
|
nir_src_bit_size(instr->src[src].src);
|
||
|
|
}
|
||
|
|
|
||
|
|
static nir_ssa_scalar
|
||
|
|
nir_alu_arg(const nir_alu_instr *alu, unsigned arg, unsigned comp)
|
||
|
|
{
|
||
|
|
const nir_alu_src *src = &alu->src[arg];
|
||
|
|
return nir_get_ssa_scalar(src->src.ssa, src->swizzle[comp]);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Tries to determine the value of expression "val % div", assuming that val
|
||
|
|
* is interpreted as value of type "val_type". "div" must be a power of two.
|
||
|
|
* Returns true if it can statically tell the value of "val % div", false if not.
|
||
|
|
* Value of *mod is undefined if this function returned false.
|
||
|
|
*
|
||
|
|
* Tests are in mod_analysis_tests.cpp.
|
||
|
|
*/
|
||
|
|
bool
|
||
|
|
nir_mod_analysis(nir_ssa_scalar val, nir_alu_type val_type, unsigned div, unsigned *mod)
|
||
|
|
{
|
||
|
|
if (div == 1) {
|
||
|
|
*mod = 0;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
assert(util_is_power_of_two_nonzero(div));
|
||
|
|
|
||
|
|
switch (val.def->parent_instr->type) {
|
||
|
|
case nir_instr_type_load_const: {
|
||
|
|
nir_load_const_instr *load =
|
||
|
|
nir_instr_as_load_const(val.def->parent_instr);
|
||
|
|
nir_alu_type base_type = nir_alu_type_get_base_type(val_type);
|
||
|
|
|
||
|
|
if (base_type == nir_type_uint) {
|
||
|
|
assert(val.comp < load->def.num_components);
|
||
|
|
uint64_t ival = nir_const_value_as_uint(load->value[val.comp],
|
||
|
|
load->def.bit_size);
|
||
|
|
*mod = ival % div;
|
||
|
|
return true;
|
||
|
|
} else if (base_type == nir_type_int) {
|
||
|
|
assert(val.comp < load->def.num_components);
|
||
|
|
int64_t ival = nir_const_value_as_int(load->value[val.comp],
|
||
|
|
load->def.bit_size);
|
||
|
|
|
||
|
|
/* whole analysis collapses the moment we allow negative values */
|
||
|
|
if (ival < 0)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
*mod = ((uint64_t)ival) % div;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case nir_instr_type_alu: {
|
||
|
|
nir_alu_instr *alu = nir_instr_as_alu(val.def->parent_instr);
|
||
|
|
|
||
|
|
if (alu->dest.dest.ssa.num_components != 1)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
switch (alu->op) {
|
||
|
|
case nir_op_ishr: {
|
||
|
|
if (nir_src_is_const(alu->src[1].src)) {
|
||
|
|
assert(alu->src[1].src.ssa->num_components == 1);
|
||
|
|
uint64_t shift = nir_src_as_uint(alu->src[1].src);
|
||
|
|
|
||
|
|
if (util_last_bit(div) + shift > 32)
|
||
|
|
break;
|
||
|
|
|
||
|
|
nir_alu_type type0 = nir_alu_src_type(alu, 0);
|
||
|
|
if (!nir_mod_analysis(nir_alu_arg(alu, 0, val.comp), type0, div << shift, mod))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
*mod >>= shift;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case nir_op_iadd: {
|
||
|
|
unsigned mod0;
|
||
|
|
nir_alu_type type0 = nir_alu_src_type(alu, 0);
|
||
|
|
if (!nir_mod_analysis(nir_alu_arg(alu, 0, val.comp), type0, div, &mod0))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
unsigned mod1;
|
||
|
|
nir_alu_type type1 = nir_alu_src_type(alu, 1);
|
||
|
|
if (!nir_mod_analysis(nir_alu_arg(alu, 1, val.comp), type1, div, &mod1))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
*mod = (mod0 + mod1) % div;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
case nir_op_ishl: {
|
||
|
|
if (nir_src_is_const(alu->src[1].src)) {
|
||
|
|
assert(alu->src[1].src.ssa->num_components == 1);
|
||
|
|
uint64_t shift = nir_src_as_uint(alu->src[1].src);
|
||
|
|
|
||
|
|
if ((div >> shift) == 0) {
|
||
|
|
*mod = 0;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
nir_alu_type type0 = nir_alu_src_type(alu, 0);
|
||
|
|
return nir_mod_analysis(nir_alu_arg(alu, 0, val.comp), type0, div >> shift, mod);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
case nir_op_imul_32x16: /* multiply 32-bits with low 16-bits */
|
||
|
|
case nir_op_imul: {
|
||
|
|
unsigned mod0;
|
||
|
|
nir_alu_type type0 = nir_alu_src_type(alu, 0);
|
||
|
|
bool s1 = nir_mod_analysis(nir_alu_arg(alu, 0, val.comp), type0, div, &mod0);
|
||
|
|
|
||
|
|
if (s1 && (mod0 == 0)) {
|
||
|
|
*mod = 0;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* if divider is larger than 2nd source max (interpreted) value
|
||
|
|
* then modulo of multiplication is unknown
|
||
|
|
*/
|
||
|
|
if (alu->op == nir_op_imul_32x16 && div > (1u << 16))
|
||
|
|
return false;
|
||
|
|
|
||
|
|
unsigned mod1;
|
||
|
|
nir_alu_type type1 = nir_alu_src_type(alu, 1);
|
||
|
|
bool s2 = nir_mod_analysis(nir_alu_arg(alu, 1, val.comp), type1, div, &mod1);
|
||
|
|
|
||
|
|
if (s2 && (mod1 == 0)) {
|
||
|
|
*mod = 0;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!s1 || !s2)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
*mod = (mod0 * mod1) % div;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|