2014-11-13 21:19:28 -08:00
|
|
|
/*
|
|
|
|
|
* Copyright © 2014 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.
|
|
|
|
|
*
|
|
|
|
|
* Authors:
|
|
|
|
|
* Jason Ekstrand (jason@jlekstrand.net)
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2016-04-03 19:51:22 -07:00
|
|
|
#include <inttypes.h>
|
2014-11-13 21:19:28 -08:00
|
|
|
#include "nir_search.h"
|
2018-10-22 14:08:13 -05:00
|
|
|
#include "nir_builder.h"
|
2018-02-28 13:15:04 -08:00
|
|
|
#include "util/half_float.h"
|
2014-11-13 21:19:28 -08:00
|
|
|
|
|
|
|
|
struct match_state {
|
2016-03-28 11:12:33 -07:00
|
|
|
bool inexact_match;
|
|
|
|
|
bool has_exact_alu;
|
2014-11-13 21:19:28 -08:00
|
|
|
unsigned variables_seen;
|
|
|
|
|
nir_alu_src variables[NIR_SEARCH_MAX_VARIABLES];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
match_expression(const nir_search_expression *expr, nir_alu_instr *instr,
|
|
|
|
|
unsigned num_components, const uint8_t *swizzle,
|
|
|
|
|
struct match_state *state);
|
|
|
|
|
|
2018-07-12 03:40:23 +02:00
|
|
|
static const uint8_t identity_swizzle[NIR_MAX_VEC_COMPONENTS] = { 0, 1, 2, 3 };
|
2014-11-13 21:19:28 -08:00
|
|
|
|
2016-08-17 15:02:58 -07:00
|
|
|
/**
|
|
|
|
|
* Check if a source produces a value of the given type.
|
|
|
|
|
*
|
|
|
|
|
* Used for satisfying 'a@type' constraints.
|
|
|
|
|
*/
|
|
|
|
|
static bool
|
|
|
|
|
src_is_type(nir_src src, nir_alu_type type)
|
|
|
|
|
{
|
|
|
|
|
assert(type != nir_type_invalid);
|
|
|
|
|
|
|
|
|
|
if (!src.is_ssa)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (src.ssa->parent_instr->type == nir_instr_type_alu) {
|
|
|
|
|
nir_alu_instr *src_alu = nir_instr_as_alu(src.ssa->parent_instr);
|
|
|
|
|
nir_alu_type output_type = nir_op_infos[src_alu->op].output_type;
|
|
|
|
|
|
2016-08-17 15:02:59 -07:00
|
|
|
if (type == nir_type_bool) {
|
|
|
|
|
switch (src_alu->op) {
|
|
|
|
|
case nir_op_iand:
|
|
|
|
|
case nir_op_ior:
|
|
|
|
|
case nir_op_ixor:
|
|
|
|
|
return src_is_type(src_alu->src[0].src, nir_type_bool) &&
|
|
|
|
|
src_is_type(src_alu->src[1].src, nir_type_bool);
|
|
|
|
|
case nir_op_inot:
|
|
|
|
|
return src_is_type(src_alu->src[0].src, nir_type_bool);
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nir_alu_type_get_base_type(output_type) == type;
|
2016-08-17 15:03:00 -07:00
|
|
|
} else if (src.ssa->parent_instr->type == nir_instr_type_intrinsic) {
|
|
|
|
|
nir_intrinsic_instr *intr = nir_instr_as_intrinsic(src.ssa->parent_instr);
|
|
|
|
|
|
|
|
|
|
if (type == nir_type_bool) {
|
|
|
|
|
return intr->intrinsic == nir_intrinsic_load_front_face ||
|
|
|
|
|
intr->intrinsic == nir_intrinsic_load_helper_invocation;
|
|
|
|
|
}
|
2016-08-17 15:02:58 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* don't know */
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
static bool
|
|
|
|
|
match_value(const nir_search_value *value, nir_alu_instr *instr, unsigned src,
|
|
|
|
|
unsigned num_components, const uint8_t *swizzle,
|
|
|
|
|
struct match_state *state)
|
|
|
|
|
{
|
2018-07-12 03:40:23 +02:00
|
|
|
uint8_t new_swizzle[NIR_MAX_VEC_COMPONENTS];
|
2014-11-13 21:19:28 -08:00
|
|
|
|
2017-01-10 10:24:55 -08:00
|
|
|
/* Searching only works on SSA values because, if it's not SSA, we can't
|
|
|
|
|
* know if the value changed between one instance of that value in the
|
|
|
|
|
* expression and another. Also, the replace operation will place reads of
|
|
|
|
|
* that value right before the last instruction in the expression we're
|
|
|
|
|
* replacing so those reads will happen after the original reads and may
|
|
|
|
|
* not be valid if they're register reads.
|
|
|
|
|
*/
|
|
|
|
|
if (!instr->src[src].src.is_ssa)
|
|
|
|
|
return false;
|
|
|
|
|
|
2015-05-08 08:33:01 -07:00
|
|
|
/* If the source is an explicitly sized source, then we need to reset
|
|
|
|
|
* both the number of components and the swizzle.
|
|
|
|
|
*/
|
|
|
|
|
if (nir_op_infos[instr->op].input_sizes[src] != 0) {
|
|
|
|
|
num_components = nir_op_infos[instr->op].input_sizes[src];
|
|
|
|
|
swizzle = identity_swizzle;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-08 23:52:48 +08:00
|
|
|
for (unsigned i = 0; i < num_components; ++i)
|
2014-11-13 21:19:28 -08:00
|
|
|
new_swizzle[i] = instr->src[src].swizzle[swizzle[i]];
|
|
|
|
|
|
2016-04-25 12:41:44 -07:00
|
|
|
/* If the value has a specific bit size and it doesn't match, bail */
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
if (value->bit_size > 0 &&
|
2016-04-25 12:41:44 -07:00
|
|
|
nir_src_bit_size(instr->src[src].src) != value->bit_size)
|
|
|
|
|
return false;
|
|
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
switch (value->type) {
|
|
|
|
|
case nir_search_value_expression:
|
|
|
|
|
if (instr->src[src].src.ssa->parent_instr->type != nir_instr_type_alu)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return match_expression(nir_search_value_as_expression(value),
|
|
|
|
|
nir_instr_as_alu(instr->src[src].src.ssa->parent_instr),
|
|
|
|
|
num_components, new_swizzle, state);
|
|
|
|
|
|
|
|
|
|
case nir_search_value_variable: {
|
|
|
|
|
nir_search_variable *var = nir_search_value_as_variable(value);
|
2015-05-08 09:42:05 -07:00
|
|
|
assert(var->variable < NIR_SEARCH_MAX_VARIABLES);
|
2014-11-13 21:19:28 -08:00
|
|
|
|
|
|
|
|
if (state->variables_seen & (1 << var->variable)) {
|
2017-01-10 10:24:55 -08:00
|
|
|
if (state->variables[var->variable].src.ssa != instr->src[src].src.ssa)
|
2014-11-13 21:19:28 -08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
assert(!instr->src[src].abs && !instr->src[src].negate);
|
|
|
|
|
|
2015-09-08 23:52:48 +08:00
|
|
|
for (unsigned i = 0; i < num_components; ++i) {
|
2014-11-13 21:19:28 -08:00
|
|
|
if (state->variables[var->variable].swizzle[i] != new_swizzle[i])
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
2015-01-22 14:15:27 -08:00
|
|
|
if (var->is_constant &&
|
|
|
|
|
instr->src[src].src.ssa->parent_instr->type != nir_instr_type_load_const)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-05-07 13:01:24 -04:00
|
|
|
if (var->cond && !var->cond(instr, src, num_components, new_swizzle))
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-08-17 15:02:58 -07:00
|
|
|
if (var->type != nir_type_invalid &&
|
|
|
|
|
!src_is_type(instr->src[src].src, var->type))
|
|
|
|
|
return false;
|
2015-01-28 16:29:21 -08:00
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
state->variables_seen |= (1 << var->variable);
|
|
|
|
|
state->variables[var->variable].src = instr->src[src].src;
|
|
|
|
|
state->variables[var->variable].abs = false;
|
|
|
|
|
state->variables[var->variable].negate = false;
|
|
|
|
|
|
2018-07-12 03:40:23 +02:00
|
|
|
for (unsigned i = 0; i < NIR_MAX_VEC_COMPONENTS; ++i) {
|
2014-11-13 21:19:28 -08:00
|
|
|
if (i < num_components)
|
|
|
|
|
state->variables[var->variable].swizzle[i] = new_swizzle[i];
|
|
|
|
|
else
|
|
|
|
|
state->variables[var->variable].swizzle[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case nir_search_value_constant: {
|
|
|
|
|
nir_search_constant *const_val = nir_search_value_as_constant(value);
|
|
|
|
|
|
2018-10-20 12:17:30 -05:00
|
|
|
if (!nir_src_is_const(instr->src[src].src))
|
2014-11-13 21:19:28 -08:00
|
|
|
return false;
|
|
|
|
|
|
2015-08-14 11:45:30 -07:00
|
|
|
switch (const_val->type) {
|
2014-11-13 21:19:28 -08:00
|
|
|
case nir_type_float:
|
|
|
|
|
for (unsigned i = 0; i < num_components; ++i) {
|
2018-10-20 12:17:30 -05:00
|
|
|
double val = nir_src_comp_as_float(instr->src[src].src,
|
|
|
|
|
new_swizzle[i]);
|
2015-08-14 11:45:30 -07:00
|
|
|
if (val != const_val->data.d)
|
2014-11-13 21:19:28 -08:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2015-08-14 11:45:30 -07:00
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
case nir_type_int:
|
2015-05-15 09:14:47 -07:00
|
|
|
case nir_type_uint:
|
2018-10-18 22:31:08 -05:00
|
|
|
case nir_type_bool: {
|
2018-10-20 12:17:30 -05:00
|
|
|
unsigned bit_size = nir_src_bit_size(instr->src[src].src);
|
|
|
|
|
uint64_t mask = bit_size == 64 ? UINT64_MAX : (1ull << bit_size) - 1;
|
|
|
|
|
for (unsigned i = 0; i < num_components; ++i) {
|
|
|
|
|
uint64_t val = nir_src_comp_as_uint(instr->src[src].src,
|
|
|
|
|
new_swizzle[i]);
|
|
|
|
|
if ((val & mask) != (const_val->data.u & mask))
|
|
|
|
|
return false;
|
2014-11-13 21:19:28 -08:00
|
|
|
}
|
2018-10-20 12:17:30 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
2015-08-14 11:45:30 -07:00
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
default:
|
|
|
|
|
unreachable("Invalid alu source type");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Invalid search value type");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
match_expression(const nir_search_expression *expr, nir_alu_instr *instr,
|
|
|
|
|
unsigned num_components, const uint8_t *swizzle,
|
|
|
|
|
struct match_state *state)
|
|
|
|
|
{
|
2017-01-10 15:47:31 +11:00
|
|
|
if (expr->cond && !expr->cond(instr))
|
|
|
|
|
return false;
|
|
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
if (instr->op != expr->opcode)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-03-17 11:04:49 -07:00
|
|
|
assert(instr->dest.dest.is_ssa);
|
2016-03-28 11:12:33 -07:00
|
|
|
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
if (expr->value.bit_size > 0 &&
|
2016-04-25 12:41:44 -07:00
|
|
|
instr->dest.dest.ssa.bit_size != expr->value.bit_size)
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-03-28 11:12:33 -07:00
|
|
|
state->inexact_match = expr->inexact || state->inexact_match;
|
|
|
|
|
state->has_exact_alu = instr->exact || state->has_exact_alu;
|
|
|
|
|
if (state->inexact_match && state->has_exact_alu)
|
2016-03-17 11:04:49 -07:00
|
|
|
return false;
|
|
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
assert(!instr->dest.saturate);
|
|
|
|
|
assert(nir_op_infos[instr->op].num_inputs > 0);
|
|
|
|
|
|
|
|
|
|
/* If we have an explicitly sized destination, we can only handle the
|
|
|
|
|
* identity swizzle. While dot(vec3(a, b, c).zxy) is a valid
|
|
|
|
|
* expression, we don't have the information right now to propagate that
|
|
|
|
|
* swizzle through. We can only properly propagate swizzles if the
|
|
|
|
|
* instruction is vectorized.
|
|
|
|
|
*/
|
|
|
|
|
if (nir_op_infos[instr->op].output_size != 0) {
|
|
|
|
|
for (unsigned i = 0; i < num_components; i++) {
|
|
|
|
|
if (swizzle[i] != i)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-08 09:48:33 -07:00
|
|
|
/* Stash off the current variables_seen bitmask. This way we can
|
|
|
|
|
* restore it prior to matching in the commutative case below.
|
|
|
|
|
*/
|
|
|
|
|
unsigned variables_seen_stash = state->variables_seen;
|
|
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
bool matched = true;
|
|
|
|
|
for (unsigned i = 0; i < nir_op_infos[instr->op].num_inputs; i++) {
|
|
|
|
|
if (!match_value(expr->srcs[i], instr, i, num_components,
|
|
|
|
|
swizzle, state)) {
|
|
|
|
|
matched = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (matched)
|
|
|
|
|
return true;
|
|
|
|
|
|
2015-04-15 15:20:57 -07:00
|
|
|
if (nir_op_infos[instr->op].algebraic_properties & NIR_OP_IS_COMMUTATIVE) {
|
|
|
|
|
assert(nir_op_infos[instr->op].num_inputs == 2);
|
2015-05-08 09:48:33 -07:00
|
|
|
|
|
|
|
|
/* Restore the variables_seen bitmask. If we don't do this, then we
|
|
|
|
|
* could end up with an erroneous failure due to variables found in the
|
|
|
|
|
* first match attempt above not matching those in the second.
|
|
|
|
|
*/
|
|
|
|
|
state->variables_seen = variables_seen_stash;
|
|
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
if (!match_value(expr->srcs[0], instr, 1, num_components,
|
|
|
|
|
swizzle, state))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return match_value(expr->srcs[1], instr, 0, num_components,
|
|
|
|
|
swizzle, state);
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-14 11:45:30 -07:00
|
|
|
static unsigned
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
replace_bitsize(const nir_search_value *value, unsigned search_bitsize,
|
|
|
|
|
struct match_state *state)
|
2015-08-14 11:45:30 -07:00
|
|
|
{
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
if (value->bit_size > 0)
|
|
|
|
|
return value->bit_size;
|
|
|
|
|
if (value->bit_size < 0)
|
|
|
|
|
return nir_src_bit_size(state->variables[-value->bit_size - 1].src);
|
|
|
|
|
return search_bitsize;
|
2015-08-14 11:45:30 -07:00
|
|
|
}
|
|
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
static nir_alu_src
|
2018-10-22 14:08:13 -05:00
|
|
|
construct_value(nir_builder *build,
|
|
|
|
|
const nir_search_value *value,
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
unsigned num_components, unsigned search_bitsize,
|
2015-08-14 11:45:30 -07:00
|
|
|
struct match_state *state,
|
2018-10-22 14:08:13 -05:00
|
|
|
nir_instr *instr)
|
2014-11-13 21:19:28 -08:00
|
|
|
{
|
|
|
|
|
switch (value->type) {
|
|
|
|
|
case nir_search_value_expression: {
|
|
|
|
|
const nir_search_expression *expr = nir_search_value_as_expression(value);
|
|
|
|
|
|
|
|
|
|
if (nir_op_infos[expr->opcode].output_size != 0)
|
|
|
|
|
num_components = nir_op_infos[expr->opcode].output_size;
|
|
|
|
|
|
2018-10-22 14:08:13 -05:00
|
|
|
nir_alu_instr *alu = nir_alu_instr_create(build->shader, expr->opcode);
|
2015-08-14 11:45:30 -07:00
|
|
|
nir_ssa_dest_init(&alu->instr, &alu->dest.dest, num_components,
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
replace_bitsize(value, search_bitsize, state), NULL);
|
2014-11-13 21:19:28 -08:00
|
|
|
alu->dest.write_mask = (1 << num_components) - 1;
|
|
|
|
|
alu->dest.saturate = false;
|
|
|
|
|
|
2016-03-28 11:12:33 -07:00
|
|
|
/* We have no way of knowing what values in a given search expression
|
|
|
|
|
* map to a particular replacement value. Therefore, if the
|
|
|
|
|
* expression we are replacing has any exact values, the entire
|
|
|
|
|
* replacement should be exact.
|
|
|
|
|
*/
|
|
|
|
|
alu->exact = state->has_exact_alu;
|
|
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
for (unsigned i = 0; i < nir_op_infos[expr->opcode].num_inputs; i++) {
|
|
|
|
|
/* If the source is an explicitly sized source, then we need to reset
|
|
|
|
|
* the number of components to match.
|
|
|
|
|
*/
|
|
|
|
|
if (nir_op_infos[alu->op].input_sizes[i] != 0)
|
|
|
|
|
num_components = nir_op_infos[alu->op].input_sizes[i];
|
|
|
|
|
|
2018-10-22 14:08:13 -05:00
|
|
|
alu->src[i] = construct_value(build, expr->srcs[i],
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
num_components, search_bitsize,
|
2018-10-22 14:08:13 -05:00
|
|
|
state, instr);
|
2014-11-13 21:19:28 -08:00
|
|
|
}
|
|
|
|
|
|
2018-10-22 14:08:13 -05:00
|
|
|
nir_builder_instr_insert(build, &alu->instr);
|
2014-11-13 21:19:28 -08:00
|
|
|
|
2015-01-21 11:11:03 -08:00
|
|
|
nir_alu_src val;
|
|
|
|
|
val.src = nir_src_for_ssa(&alu->dest.dest.ssa);
|
|
|
|
|
val.negate = false;
|
|
|
|
|
val.abs = false,
|
|
|
|
|
memcpy(val.swizzle, identity_swizzle, sizeof val.swizzle);
|
2014-11-13 21:19:28 -08:00
|
|
|
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case nir_search_value_variable: {
|
|
|
|
|
const nir_search_variable *var = nir_search_value_as_variable(value);
|
|
|
|
|
assert(state->variables_seen & (1 << var->variable));
|
|
|
|
|
|
2015-04-21 18:00:21 -07:00
|
|
|
nir_alu_src val = { NIR_SRC_INIT };
|
2018-10-22 14:08:13 -05:00
|
|
|
nir_alu_src_copy(&val, &state->variables[var->variable],
|
|
|
|
|
(void *)build->shader);
|
2015-01-22 14:15:27 -08:00
|
|
|
assert(!var->is_constant);
|
|
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case nir_search_value_constant: {
|
|
|
|
|
const nir_search_constant *c = nir_search_value_as_constant(value);
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
unsigned bit_size = replace_bitsize(value, search_bitsize, state);
|
2014-11-13 21:19:28 -08:00
|
|
|
|
2018-10-22 14:08:13 -05:00
|
|
|
nir_ssa_def *cval;
|
2015-08-14 11:45:30 -07:00
|
|
|
switch (c->type) {
|
2014-11-13 21:19:28 -08:00
|
|
|
case nir_type_float:
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
cval = nir_imm_floatN_t(build, c->data.d, bit_size);
|
2014-11-13 21:19:28 -08:00
|
|
|
break;
|
2015-08-14 11:45:30 -07:00
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
case nir_type_int:
|
2015-05-15 09:14:47 -07:00
|
|
|
case nir_type_uint:
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
cval = nir_imm_intN_t(build, c->data.i, bit_size);
|
2016-04-22 09:45:10 +03:00
|
|
|
break;
|
2015-08-14 11:45:30 -07:00
|
|
|
|
2018-10-18 22:31:08 -05:00
|
|
|
case nir_type_bool:
|
2018-10-22 14:08:13 -05:00
|
|
|
cval = nir_imm_bool(build, c->data.u);
|
2014-11-13 21:19:28 -08:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Invalid alu source type");
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-21 11:11:03 -08:00
|
|
|
nir_alu_src val;
|
2018-10-22 14:08:13 -05:00
|
|
|
val.src = nir_src_for_ssa(cval);
|
2015-01-21 11:11:03 -08:00
|
|
|
val.negate = false;
|
|
|
|
|
val.abs = false,
|
|
|
|
|
memset(val.swizzle, 0, sizeof val.swizzle);
|
2014-11-13 21:19:28 -08:00
|
|
|
|
|
|
|
|
return val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
unreachable("Invalid search value type");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-22 14:08:13 -05:00
|
|
|
nir_ssa_def *
|
|
|
|
|
nir_replace_instr(nir_builder *build, nir_alu_instr *instr,
|
|
|
|
|
const nir_search_expression *search,
|
|
|
|
|
const nir_search_value *replace)
|
2014-11-13 21:19:28 -08:00
|
|
|
{
|
2018-07-12 03:40:23 +02:00
|
|
|
uint8_t swizzle[NIR_MAX_VEC_COMPONENTS] = { 0 };
|
2014-11-13 21:19:28 -08:00
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < instr->dest.dest.ssa.num_components; ++i)
|
|
|
|
|
swizzle[i] = i;
|
|
|
|
|
|
|
|
|
|
assert(instr->dest.dest.is_ssa);
|
|
|
|
|
|
|
|
|
|
struct match_state state;
|
2016-03-28 11:12:33 -07:00
|
|
|
state.inexact_match = false;
|
|
|
|
|
state.has_exact_alu = false;
|
2014-11-13 21:19:28 -08:00
|
|
|
state.variables_seen = 0;
|
|
|
|
|
|
|
|
|
|
if (!match_expression(search, instr, instr->dest.dest.ssa.num_components,
|
|
|
|
|
swizzle, &state))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2018-10-22 14:08:13 -05:00
|
|
|
build->cursor = nir_before_instr(&instr->instr);
|
|
|
|
|
|
|
|
|
|
nir_alu_src val = construct_value(build, replace,
|
|
|
|
|
instr->dest.dest.ssa.num_components,
|
nir/algebraic: Rewrite bit-size inference
Before this commit, there were two copies of the algorithm: one in C,
that we would use to figure out what bit-size to give the replacement
expression, and one in Python, that emulated the C one and tried to
prove that the C algorithm would never fail to correctly assign
bit-sizes. That seemed pretty fragile, and likely to fall over if we
make any changes. Furthermore, the C code was really just recomputing
more-or-less the same thing as the Python code every time. Instead, we
can just store the results of the Python algorithm in the C
datastructure, and consult it to compute the bitsize of each value,
moving the "brains" entirely into Python. Since the Python algorithm no
longer has to match C, it's also a lot easier to change it to something
more closely approximating an actual type-inference algorithm. The
algorithm used is based on Hindley-Milner, although deliberately
weakened a little. It's a few more lines than the old one, judging by
the diffstat, but I think it's easier to verify that it's correct while
being as general as possible.
We could split this up into two changes, first making the C code use the
results of the Python code and then rewriting the Python algorithm, but
since the old algorithm never tracked which variable each equivalence
class, it would mean we'd have to add some non-trivial code which would
then get thrown away. I think it's better to see the final state all at
once, although I could also try splitting it up.
v2:
- Replace instances of "== None" and "!= None" with "is None" and
"is not None".
- Rename first_src to first_unsized_src
- Only merge the destination with the first unsized source, since the
sources have already been merged.
- Add a comment explaining what nir_search_value::bit_size now means.
v3:
- Fix one last instance to use "is not" instead of !=
- Don't try to be so clever when choosing which error message to print
based on whether we're in the search or replace expression.
- Fix trailing whitespace.
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Dylan Baker <dylan@pnwbakers.com>
2018-11-23 17:34:19 +01:00
|
|
|
instr->dest.dest.ssa.bit_size,
|
|
|
|
|
&state, &instr->instr);
|
2018-10-22 14:08:13 -05:00
|
|
|
|
2014-11-13 21:19:28 -08:00
|
|
|
/* Inserting a mov may be unnecessary. However, it's much easier to
|
|
|
|
|
* simply let copy propagation clean this up than to try to go through
|
|
|
|
|
* and rewrite swizzles ourselves.
|
|
|
|
|
*/
|
2018-10-22 14:08:13 -05:00
|
|
|
nir_ssa_def *ssa_val =
|
|
|
|
|
nir_imov_alu(build, val, instr->dest.dest.ssa.num_components);
|
|
|
|
|
nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, nir_src_for_ssa(ssa_val));
|
2014-11-13 21:19:28 -08:00
|
|
|
|
|
|
|
|
/* We know this one has no more uses because we just rewrote them all,
|
|
|
|
|
* so we can remove it. The rest of the matched expression, however, we
|
|
|
|
|
* don't know so much about. We'll just let dead code clean them up.
|
|
|
|
|
*/
|
|
|
|
|
nir_instr_remove(&instr->instr);
|
|
|
|
|
|
2018-10-22 14:08:13 -05:00
|
|
|
return ssa_val;
|
2014-11-13 21:19:28 -08:00
|
|
|
}
|