[Mesa-dev] [PATCH 2/3] nir/algebraic: support for power-of-two optimizations
Rob Clark
robdclark at gmail.com
Mon May 9 16:52:14 UTC 2016
From: Rob Clark <robclark at freedesktop.org>
It was kinda sad that we couldn't optimize imul/idiv by power-of-two.
So I bashed my head against python for a while and this is what I came
up with. In the search expression, you can use "#a^2" to only match
constants which are a power of two. The rest is taken care of w/ normal
replacement expression.
Signed-off-by: Rob Clark <robclark at freedesktop.org>
---
src/compiler/nir/nir_algebraic.py | 9 +++++++--
src/compiler/nir/nir_opt_algebraic.py | 5 +++++
src/compiler/nir/nir_search.c | 26 ++++++++++++++++++++++++++
src/compiler/nir/nir_search.h | 7 +++++++
4 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/src/compiler/nir/nir_algebraic.py b/src/compiler/nir/nir_algebraic.py
index 285f853..9bfd3f2 100644
--- a/src/compiler/nir/nir_algebraic.py
+++ b/src/compiler/nir/nir_algebraic.py
@@ -83,6 +83,7 @@ static const ${val.c_type} ${val.name} = {
% elif isinstance(val, Variable):
${val.index}, /* ${val.var_name} */
${'true' if val.is_constant else 'false'},
+ ${'true' if val.is_power_of_two else 'false'},
${val.type() or 'nir_type_invalid' },
% elif isinstance(val, Expression):
${'true' if val.inexact else 'false'},
@@ -113,7 +114,7 @@ static const ${val.c_type} ${val.name} = {
Variable=Variable,
Expression=Expression)
-_constant_re = re.compile(r"(?P<value>[^@]+)(?:@(?P<bits>\d+))?")
+_constant_re = re.compile(r"(?P<value>[^@\^]+)(?P<PoT>\^2)?(?:@(?P<bits>\d+))?")
class Constant(Value):
def __init__(self, val, name):
@@ -123,6 +124,7 @@ class Constant(Value):
m = _constant_re.match(val)
self.value = ast.literal_eval(m.group('value'))
self.bit_size = int(m.group('bits')) if m.group('bits') else 0
+ self.power_of_two = m.group('PoT') is not None
else:
self.value = val
self.bit_size = 0
@@ -149,7 +151,7 @@ class Constant(Value):
elif isinstance(self.value, float):
return "nir_type_float"
-_var_name_re = re.compile(r"(?P<const>#)?(?P<name>\w+)"
+_var_name_re = re.compile(r"(?P<const>#)?(?P<name>\w+)(?P<PoT>\^2)?"
r"(?:@(?P<type>int|uint|bool|float)?(?P<bits>\d+)?)?")
class Variable(Value):
@@ -161,6 +163,9 @@ class Variable(Value):
self.var_name = m.group('name')
self.is_constant = m.group('const') is not None
+ self.is_power_of_two = m.group('PoT') is not None
+ if self.is_power_of_two:
+ assert self.is_constant
self.required_type = m.group('type')
self.bit_size = int(m.group('bits')) if m.group('bits') else 0
diff --git a/src/compiler/nir/nir_opt_algebraic.py b/src/compiler/nir/nir_opt_algebraic.py
index 0a95725..c92e76d 100644
--- a/src/compiler/nir/nir_opt_algebraic.py
+++ b/src/compiler/nir/nir_opt_algebraic.py
@@ -62,6 +62,11 @@ d = 'd'
# constructed value should have that bit-size.
optimizations = [
+
+ (('imul', a, '#b^2 at 32'), ('ishl', a, ('find_lsb', b))),
+ (('udiv', a, '#b^2 at 32'), ('ishr', a, ('find_lsb', b))),
+ (('umod', a, '#b^2'), ('iand', a, ('isub', b, 1))),
+
(('fneg', ('fneg', a)), a),
(('ineg', ('ineg', a)), a),
(('fabs', ('fabs', a)), ('fabs', a)),
diff --git a/src/compiler/nir/nir_search.c b/src/compiler/nir/nir_search.c
index 2c2fd92..6578088 100644
--- a/src/compiler/nir/nir_search.c
+++ b/src/compiler/nir/nir_search.c
@@ -70,6 +70,13 @@ alu_instr_is_bool(nir_alu_instr *instr)
}
}
+/* helper for this somewhere? */
+static bool
+is_power_of_two(unsigned int x)
+{
+ return ((x != 0) && !(x & (x - 1)));
+}
+
static bool
match_value(const nir_search_value *value, nir_alu_instr *instr, unsigned src,
unsigned num_components, const uint8_t *swizzle,
@@ -127,6 +134,25 @@ match_value(const nir_search_value *value, nir_alu_instr *instr, unsigned src,
instr->src[src].src.ssa->parent_instr->type != nir_instr_type_load_const)
return false;
+ if (var->is_power_of_two) {
+ assert(var->is_constant);
+ nir_const_value *val = nir_src_as_const_value(instr->src[src].src);
+ for (unsigned i = 0; i < num_components; i++) {
+ switch (nir_op_infos[instr->op].input_types[src]) {
+ case nir_type_int:
+ if (!is_power_of_two(val->i32[new_swizzle[i]]))
+ return false;
+ break;
+ case nir_type_uint:
+ if (!is_power_of_two(val->u32[new_swizzle[i]]))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+
if (var->type != nir_type_invalid) {
if (instr->src[src].src.ssa->parent_instr->type != nir_instr_type_alu)
return false;
diff --git a/src/compiler/nir/nir_search.h b/src/compiler/nir/nir_search.h
index a500feb..32ed538 100644
--- a/src/compiler/nir/nir_search.h
+++ b/src/compiler/nir/nir_search.h
@@ -57,6 +57,13 @@ typedef struct {
*/
bool is_constant;
+ /** Indicates that the given constant is a power of two
+ *
+ * This is only allowed in search expressions, and only for constant
+ * variables.
+ */
+ bool is_power_of_two;
+
/** Indicates that the given variable must have a certain type
*
* This is only allowed in search expressions and indicates that the
--
2.5.5
More information about the mesa-dev
mailing list