diff --git a/src/compiler/nir/nir_opt_algebraic.py b/src/compiler/nir/nir_opt_algebraic.py index 611fc10ab65..55c052ace7f 100644 --- a/src/compiler/nir/nir_opt_algebraic.py +++ b/src/compiler/nir/nir_opt_algebraic.py @@ -1386,6 +1386,27 @@ optimizations.extend([ (('uror@32', a, b), ('ior', ('ushr', a, b), ('ishl', a, ('isub', 32, b))), 'options->lower_rotate'), (('uror@64', a, b), ('ior', ('ushr', a, b), ('ishl', a, ('isub', 64, b))), 'options->lower_rotate'), + # bfi(X, a, b) = (b & ~X) | (a & X) + # If X = ~0: (b & 0) | (a & 0xffffffff) = a + # If X = 0: (b & 0xffffffff) | (a & 0) = b + (('bfi', 0xffffffff, a, b), a), + (('bfi', 0x00000000, a, b), b), + + # The result of -int(some_bool) is 0 or 0xffffffff, so the result of the + # bfi is either b or c. + (('bfi', ('ineg', ('b2i', 'a@1')), b, c), ('bcsel', a, b, c)), + + # bfi(a, a, b) = ((a << find_lsb(a)) & a) | (b & ~a) + # = (a & a) | (b & ~a) If a is odd, find_lsb(a) == 0 + # = a | (b & ~a) + # = a | b + (('bfi', '#a(is_odd)', a, b), ('ior', a, b)), + + # bfi(a, b, 0) = ((b << find_lsb(a)) & a) | (0 & ~a) + # = ((b << find_lsb(a)) & a) + # = (b & a) If a is odd, find_lsb(a) == 0 + (('bfi', '#a(is_odd)', b, 0), ('iand', a, b)), + # Because 'a' is a positive power of two, the result of the bfi is either 0 # or 'a' depending on whether or not 'b' is odd. Use 'b&1' for the zero # value to help platforms that can't have two constants in a bcsel. diff --git a/src/compiler/nir/nir_search_helpers.h b/src/compiler/nir/nir_search_helpers.h index 06abe924391..a9d19963a7a 100644 --- a/src/compiler/nir/nir_search_helpers.h +++ b/src/compiler/nir/nir_search_helpers.h @@ -196,6 +196,35 @@ is_gt_0_and_lt_1(UNUSED struct hash_table *ht, const nir_alu_instr *instr, return true; } +/** + * x & 1 != 0 + */ +static inline bool +is_odd(UNUSED struct hash_table *ht, const nir_alu_instr *instr, + unsigned src, unsigned num_components, + const uint8_t *swizzle) +{ + /* only constant srcs: */ + if (!nir_src_is_const(instr->src[src].src)) + return false; + + for (unsigned i = 0; i < num_components; i++) { + nir_alu_type type = nir_op_infos[instr->op].input_types[src]; + switch (nir_alu_type_get_base_type(type)) { + case nir_type_int: + case nir_type_uint: { + if ((nir_src_comp_as_uint(instr->src[src].src, swizzle[i]) & 1) == 0) + return false; + break; + } + default: + return false; + } + } + + return true; +} + static inline bool is_not_const_zero(UNUSED struct hash_table *ht, const nir_alu_instr *instr, unsigned src, unsigned num_components,