summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Ekstrand <jason.ekstrand@intel.com>2021-02-04 11:38:40 -0600
committerMarge Bot <eric+marge@anholt.net>2021-02-16 16:36:31 +0000
commit96303a59eaeb2a38ab04330fb6ad9bc75f9d7b36 (patch)
treee2ddf6d35ffdc61563f569a67f1d4281216a0b08
parentd670afa27a42bd86730815e8246110292de95cc1 (diff)
nir: Add some range analysis for used bits
This isn't 100% accurate, of course, but it should be good enough for what we're about to do with it. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8872>
-rw-r--r--src/compiler/nir/nir_range_analysis.c166
-rw-r--r--src/compiler/nir/nir_range_analysis.h2
2 files changed, 168 insertions, 0 deletions
diff --git a/src/compiler/nir/nir_range_analysis.c b/src/compiler/nir/nir_range_analysis.c
index f2b7211a5f6..4c250206594 100644
--- a/src/compiler/nir/nir_range_analysis.c
+++ b/src/compiler/nir/nir_range_analysis.c
@@ -1496,3 +1496,169 @@ nir_addition_might_overflow(nir_shader *shader, struct hash_table *range_ht,
return const_val + ub < const_val;
}
+static uint64_t
+ssa_def_bits_used(nir_ssa_def *def, int recur)
+{
+ uint64_t bits_used = 0;
+ uint64_t all_bits = BITFIELD64_MASK(def->bit_size);
+
+ /* Limit recursion */
+ if (recur-- <= 0)
+ return all_bits;
+
+ nir_foreach_use(src, def) {
+ switch (src->parent_instr->type) {
+ case nir_instr_type_alu: {
+ nir_alu_instr *use_alu = nir_instr_as_alu(src->parent_instr);
+ unsigned src_idx = container_of(src, nir_alu_src, src) - use_alu->src;
+
+ switch (use_alu->op) {
+ case nir_op_u2u8:
+ case nir_op_i2i8:
+ bits_used |= 0xff;
+ break;
+
+ case nir_op_u2u16:
+ case nir_op_i2i16:
+ bits_used |= all_bits & 0xffff;
+ break;
+
+ case nir_op_u2u32:
+ case nir_op_i2i32:
+ bits_used |= all_bits & 0xffffffff;
+ break;
+
+ case nir_op_extract_u8:
+ case nir_op_extract_i8:
+ if (src_idx == 0 && nir_src_is_const(use_alu->src[1].src)) {
+ unsigned chunk = nir_src_as_uint(use_alu->src[1].src);
+ bits_used |= 0xffull << (chunk * 8);
+ break;
+ } else {
+ return all_bits;
+ }
+
+ case nir_op_extract_u16:
+ case nir_op_extract_i16:
+ if (src_idx == 0 && nir_src_is_const(use_alu->src[1].src)) {
+ unsigned chunk = nir_src_as_uint(use_alu->src[1].src);
+ bits_used |= 0xffffull << (chunk * 16);
+ break;
+ } else {
+ return all_bits;
+ }
+
+ case nir_op_ishl:
+ case nir_op_ishr:
+ case nir_op_ushr:
+ if (src_idx == 1) {
+ bits_used |= (nir_src_bit_size(use_alu->src[0].src) - 1);
+ break;
+ } else {
+ return all_bits;
+ }
+
+ case nir_op_iand:
+ assert(src_idx < 2);
+ if (nir_src_is_const(use_alu->src[1 - src_idx].src)) {
+ uint64_t u64 = nir_src_as_uint(use_alu->src[1 - src_idx].src);
+ bits_used |= u64;
+ break;
+ } else {
+ return all_bits;
+ }
+
+ case nir_op_ior:
+ assert(src_idx < 2);
+ if (nir_src_is_const(use_alu->src[1 - src_idx].src)) {
+ uint64_t u64 = nir_src_as_uint(use_alu->src[1 - src_idx].src);
+ bits_used |= all_bits & ~u64;
+ break;
+ } else {
+ return all_bits;
+ }
+
+ default:
+ /* We don't know what this op does */
+ return all_bits;
+ }
+ break;
+ }
+
+ case nir_instr_type_intrinsic: {
+ nir_intrinsic_instr *use_intrin =
+ nir_instr_as_intrinsic(src->parent_instr);
+ unsigned src_idx = src - use_intrin->src;
+
+ switch (use_intrin->intrinsic) {
+ case nir_intrinsic_read_invocation:
+ case nir_intrinsic_shuffle:
+ case nir_intrinsic_shuffle_up:
+ case nir_intrinsic_shuffle_down:
+ case nir_intrinsic_shuffle_xor:
+ case nir_intrinsic_quad_broadcast:
+ case nir_intrinsic_quad_swap_horizontal:
+ case nir_intrinsic_quad_swap_vertical:
+ case nir_intrinsic_quad_swap_diagonal:
+ if (src_idx == 0) {
+ assert(use_intrin->dest.is_ssa);
+ bits_used |= ssa_def_bits_used(&use_intrin->dest.ssa, recur);
+ } else {
+ if (use_intrin->intrinsic == nir_intrinsic_quad_broadcast) {
+ bits_used |= 3;
+ } else {
+ /* Subgroups larger than 128 are not a thing */
+ bits_used |= 127;
+ }
+ }
+ break;
+
+ case nir_intrinsic_reduce:
+ case nir_intrinsic_inclusive_scan:
+ case nir_intrinsic_exclusive_scan:
+ assert(src_idx == 0);
+ switch (nir_intrinsic_reduction_op(use_intrin)) {
+ case nir_op_iadd:
+ case nir_op_imul:
+ case nir_op_ior:
+ case nir_op_iand:
+ case nir_op_ixor:
+ bits_used |= ssa_def_bits_used(&use_intrin->dest.ssa, recur);
+ break;
+
+ default:
+ return all_bits;
+ }
+ break;
+
+ default:
+ /* We don't know what this op does */
+ return all_bits;
+ }
+ break;
+ }
+
+ case nir_instr_type_phi: {
+ nir_phi_instr *use_phi = nir_instr_as_phi(src->parent_instr);
+ bits_used |= ssa_def_bits_used(&use_phi->dest.ssa, recur);
+ break;
+ }
+
+ default:
+ return all_bits;
+ }
+
+ /* If we've somehow shown that all our bits are used, we're done */
+ assert((bits_used & ~all_bits) == 0);
+ if (bits_used == all_bits)
+ return all_bits;
+ }
+
+ return bits_used;
+}
+
+uint64_t
+nir_ssa_def_bits_used(nir_ssa_def *def)
+{
+ return ssa_def_bits_used(def, 2);
+}
diff --git a/src/compiler/nir/nir_range_analysis.h b/src/compiler/nir/nir_range_analysis.h
index f5d12bfbf9f..a607a4b5799 100644
--- a/src/compiler/nir/nir_range_analysis.h
+++ b/src/compiler/nir/nir_range_analysis.h
@@ -45,4 +45,6 @@ extern struct ssa_result_range
nir_analyze_range(struct hash_table *range_ht,
const nir_alu_instr *instr, unsigned src);
+uint64_t nir_ssa_def_bits_used(nir_ssa_def *def);
+
#endif /* _NIR_RANGE_ANALYSIS_H_ */