#include "jay_private.h"
#include "nir.h"
#include "nir_builder.h"
#include "nir_search.h"
#include "nir_search_helpers.h"

/* What follows is NIR algebraic transform code for the following 14
 * transforms:
 *    ('fsign', 'a') => ('bcsel', ('!flt', 0, 'a'), 1.0, ('bcsel', ('!flt', 'a', 0), -1.0, 0.0))
 *    ('fceil', 'a') => ('fneg', ('ffloor', ('fneg', 'a')))
 *    ('inot', ('iand(is_used_once)', ('inot', 'a'), 'b')) => ('ior', 'a', ('inot', 'b'))
 *    ('inot', ('ior(is_used_once)', ('inot', 'a'), 'b')) => ('iand', 'a', ('inot', 'b'))
 *    ('inot', ('ixor(is_used_once)', ('inot', 'a'), 'b')) => ('ixor', 'a', 'b')
 *    ('inot', ('iand(is_used_once)', 'a', 'b')) => ('ior', ('inot', 'a'), ('inot', 'b'))
 *    ('inot', ('ior(is_used_once)', 'a', 'b')) => ('iand', ('inot', 'a'), ('inot', 'b'))
 *    ('inot', ('ixor(is_used_once)', 'a', 'b')) => ('ixor', ('inot', 'a'), 'b')
 *    ('u2f32', ('extract_u8', 'a', 0)) => ('u2f32', ('u2u8', 'a'))
 *    ('u2f32', ('extract_u16', 'a', 0)) => ('u2f32', ('u2u16', 'a'))
 *    ('i2f32', ('extract_i8', 'a', 0)) => ('i2f32', ('i2i8', 'a'))
 *    ('i2f32', ('extract_i16', 'a', 0)) => ('i2f32', ('i2i16', 'a'))
 *    ('pack_half_2x16_split', 'a', 'b') => ('pack_32_2x16_split', ('f2f16', 'a'), ('f2f16', 'b'))
 *    ('bcsel', 'a', ('iadd(is_used_once)', 'b', 'c'), 'b') => ('iadd', ('bcsel', 'a', 'c', 0), 'b')
 */


static const nir_search_value_union jay_nir_lower_fsign_values[] = {
   /* ('fsign', 'a') => ('bcsel', ('!flt', 0, 'a'), 1.0, ('bcsel', ('!flt', 'a', 0), -1.0, 0.0)) */
   { .variable = {
      { nir_search_value_variable, -1 },
      0, /* a */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_fsign,
      -1, 0,
      { 0 },
      -1,
   } },

   { .constant = {
      { nir_search_value_constant, -1 },
      nir_type_int, { 0x0ull /* 0 */ },
   } },
   /* replace0_0_1 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, 1 },
      nir_fp_fast_math,
      nir_fp_exact,
      false,
      -1,
      nir_op_flt,
      -1, 0,
      { 2, 0 },
      -1,
   } },
   { .constant = {
      { nir_search_value_constant, -1 },
      nir_type_float, { 0x3ff0000000000000ull /* 1.0 */ },
   } },
   /* replace0_2_0_0 -> 0 in the cache */
   /* replace0_2_0_1 -> 2 in the cache */
   { .expression = {
      { nir_search_value_expression, 1 },
      nir_fp_fast_math,
      nir_fp_exact,
      true,
      -1,
      nir_op_flt,
      -1, 0,
      { 0, 2 },
      -1,
   } },
   { .constant = {
      { nir_search_value_constant, -1 },
      nir_type_float, { 0xbff0000000000000ull /* -1.0 */ },
   } },
   { .constant = {
      { nir_search_value_constant, -1 },
      nir_type_float, { 0x0ull /* 0.0 */ },
   } },
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 5, 6, 7 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 3, 4, 8 },
      -1,
   } },

   /* ('fceil', 'a') => ('fneg', ('ffloor', ('fneg', 'a'))) */
   /* search1_0 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_fceil,
      -1, 0,
      { 0 },
      -1,
   } },

   /* replace1_0_0_0 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_fneg,
      -1, 0,
      { 0 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ffloor,
      -1, 0,
      { 11 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_fneg,
      -1, 0,
      { 12 },
      -1,
   } },

   /* ('inot', ('iand(is_used_once)', ('inot', 'a'), 'b')) => ('ior', 'a', ('inot', 'b')) */
   { .variable = {
      { nir_search_value_variable, -2 },
      0, /* a */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 0,
      { 14 },
      -1,
   } },
   { .variable = {
      { nir_search_value_variable, -2 },
      1, /* b */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_iand,
      0, 1,
      { 15, 16 },
      0,
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 1,
      { 17 },
      -1,
   } },

   /* replace2_0 -> 14 in the cache */
   /* replace2_1_0 -> 16 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 0,
      { 16 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ior,
      0, 1,
      { 14, 19 },
      -1,
   } },

   /* ('inot', ('ior(is_used_once)', ('inot', 'a'), 'b')) => ('iand', 'a', ('inot', 'b')) */
   /* search3_0_0_0 -> 14 in the cache */
   /* search3_0_0 -> 15 in the cache */
   /* search3_0_1 -> 16 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ior,
      0, 1,
      { 15, 16 },
      0,
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 1,
      { 21 },
      -1,
   } },

   /* replace3_0 -> 14 in the cache */
   /* replace3_1_0 -> 16 in the cache */
   /* replace3_1 -> 19 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_iand,
      0, 1,
      { 14, 19 },
      -1,
   } },

   /* ('inot', ('ixor(is_used_once)', ('inot', 'a'), 'b')) => ('ixor', 'a', 'b') */
   /* search4_0_0_0 -> 14 in the cache */
   /* search4_0_0 -> 15 in the cache */
   /* search4_0_1 -> 16 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ixor,
      0, 1,
      { 15, 16 },
      0,
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 1,
      { 24 },
      -1,
   } },

   /* replace4_0 -> 14 in the cache */
   /* replace4_1 -> 16 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ixor,
      0, 1,
      { 14, 16 },
      -1,
   } },

   /* ('inot', ('iand(is_used_once)', 'a', 'b')) => ('ior', ('inot', 'a'), ('inot', 'b')) */
   /* search5_0_0 -> 14 in the cache */
   /* search5_0_1 -> 16 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_iand,
      0, 1,
      { 14, 16 },
      0,
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 1,
      { 27 },
      -1,
   } },

   /* replace5_0_0 -> 14 in the cache */
   /* replace5_0 -> 15 in the cache */
   /* replace5_1_0 -> 16 in the cache */
   /* replace5_1 -> 19 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ior,
      0, 1,
      { 15, 19 },
      -1,
   } },

   /* ('inot', ('ior(is_used_once)', 'a', 'b')) => ('iand', ('inot', 'a'), ('inot', 'b')) */
   /* search6_0_0 -> 14 in the cache */
   /* search6_0_1 -> 16 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ior,
      0, 1,
      { 14, 16 },
      0,
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 1,
      { 30 },
      -1,
   } },

   /* replace6_0_0 -> 14 in the cache */
   /* replace6_0 -> 15 in the cache */
   /* replace6_1_0 -> 16 in the cache */
   /* replace6_1 -> 19 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_iand,
      0, 1,
      { 15, 19 },
      -1,
   } },

   /* ('inot', ('ixor(is_used_once)', 'a', 'b')) => ('ixor', ('inot', 'a'), 'b') */
   /* search7_0_0 -> 14 in the cache */
   /* search7_0_1 -> 16 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ixor,
      0, 1,
      { 14, 16 },
      0,
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 1,
      { 33 },
      -1,
   } },

   /* replace7_0_0 -> 14 in the cache */
   /* replace7_0 -> 15 in the cache */
   /* replace7_1 -> 16 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ixor,
      0, 1,
      { 15, 16 },
      -1,
   } },

   /* ('u2f32', ('extract_u8', 'a', 0)) => ('u2f32', ('u2u8', 'a')) */
   /* search8_0_0 -> 0 in the cache */
   /* search8_0_1 -> 2 in the cache */
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_extract_u8,
      -1, 0,
      { 0, 2 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_u2f32,
      -1, 0,
      { 36 },
      -1,
   } },

   /* replace8_0_0 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_u2u8,
      -1, 0,
      { 0 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_u2f32,
      -1, 0,
      { 38 },
      -1,
   } },

   /* ('u2f32', ('extract_u16', 'a', 0)) => ('u2f32', ('u2u16', 'a')) */
   /* search9_0_0 -> 0 in the cache */
   /* search9_0_1 -> 2 in the cache */
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_extract_u16,
      -1, 0,
      { 0, 2 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_u2f32,
      -1, 0,
      { 40 },
      -1,
   } },

   /* replace9_0_0 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_u2u16,
      -1, 0,
      { 0 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_u2f32,
      -1, 0,
      { 42 },
      -1,
   } },

   /* ('i2f32', ('extract_i8', 'a', 0)) => ('i2f32', ('i2i8', 'a')) */
   /* search10_0_0 -> 0 in the cache */
   /* search10_0_1 -> 2 in the cache */
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_extract_i8,
      -1, 0,
      { 0, 2 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_i2f32,
      -1, 0,
      { 44 },
      -1,
   } },

   /* replace10_0_0 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_i2i8,
      -1, 0,
      { 0 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_i2f32,
      -1, 0,
      { 46 },
      -1,
   } },

   /* ('i2f32', ('extract_i16', 'a', 0)) => ('i2f32', ('i2i16', 'a')) */
   /* search11_0_0 -> 0 in the cache */
   /* search11_0_1 -> 2 in the cache */
   { .expression = {
      { nir_search_value_expression, -1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_extract_i16,
      -1, 0,
      { 0, 2 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_i2f32,
      -1, 0,
      { 48 },
      -1,
   } },

   /* replace11_0_0 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_i2i16,
      -1, 0,
      { 0 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_i2f32,
      -1, 0,
      { 50 },
      -1,
   } },

   /* ('pack_half_2x16_split', 'a', 'b') => ('pack_32_2x16_split', ('f2f16', 'a'), ('f2f16', 'b')) */
   { .variable = {
      { nir_search_value_variable, 32 },
      0, /* a */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .variable = {
      { nir_search_value_variable, 32 },
      1, /* b */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_pack_half_2x16_split,
      -1, 0,
      { 52, 53 },
      -1,
   } },

   /* replace12_0_0 -> 52 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_f2f16,
      -1, 0,
      { 52 },
      -1,
   } },
   /* replace12_1_0 -> 53 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_f2f16,
      -1, 0,
      { 53 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_pack_32_2x16_split,
      -1, 0,
      { 55, 56 },
      -1,
   } },

   /* ('bcsel', 'a', ('iadd(is_used_once)', 'b', 'c'), 'b') => ('iadd', ('bcsel', 'a', 'c', 0), 'b') */
   { .variable = {
      { nir_search_value_variable, 1 },
      0, /* a */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .variable = {
      { nir_search_value_variable, -3 },
      1, /* b */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .variable = {
      { nir_search_value_variable, -3 },
      2, /* c */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .expression = {
      { nir_search_value_expression, -3 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_iadd,
      0, 1,
      { 59, 60 },
      0,
   } },
   /* search13_2 -> 59 in the cache */
   { .expression = {
      { nir_search_value_expression, -3 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_bcsel,
      -1, 1,
      { 58, 61, 59 },
      -1,
   } },

   /* replace13_0_0 -> 58 in the cache */
   /* replace13_0_1 -> 60 in the cache */
   { .constant = {
      { nir_search_value_constant, -3 },
      nir_type_int, { 0x0ull /* 0 */ },
   } },
   { .expression = {
      { nir_search_value_expression, -3 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 58, 60, 63 },
      -1,
   } },
   /* replace13_1 -> 59 in the cache */
   { .expression = {
      { nir_search_value_expression, -3 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_iadd,
      0, 1,
      { 64, 59 },
      -1,
   } },

};

UNUSED static const nir_search_expression_cond jay_nir_lower_fsign_expression_cond[] = {
   is_used_once,
};


static const struct transform jay_nir_lower_fsign_transforms[] = {
   { ~0, ~0, ~0 }, /* Sentinel */

   { 1, 9, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 10, 13, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 54, 57, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 28, 29, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 31, 32, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 34, 35, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 37, 39, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 41, 43, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 45, 47, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 49, 51, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 62, 65, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 18, 20, 0 },
   { 28, 29, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 22, 23, 0 },
   { 31, 32, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 25, 26, 0 },
   { 34, 35, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

};

static const struct per_op_table jay_nir_lower_fsign_pass_op_table[nir_num_search_ops] = {
   [nir_op_fsign] = {
      .filter = NULL,
      
      .num_filtered_states = 1,
      .table = (const uint16_t []) {
      
         2,
      },
   },
   [nir_op_fceil] = {
      .filter = NULL,
      
      .num_filtered_states = 1,
      .table = (const uint16_t []) {
      
         3,
      },
   },
   [nir_op_inot] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         0,
         1,
         2,
         3,
         0,
         0,
         0,
         0,
         0,
         0,
         4,
         5,
         6,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 7,
      .table = (const uint16_t []) {
      
         4,
         17,
         18,
         19,
         25,
         26,
         27,
      },
   },
   [nir_op_iand] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         1,
         1,
         1,
         0,
         0,
         0,
         0,
         0,
         1,
         1,
         1,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         5,
         14,
         14,
         14,
      },
   },
   [nir_op_ior] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         1,
         1,
         1,
         0,
         0,
         0,
         0,
         0,
         1,
         1,
         1,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         6,
         15,
         15,
         15,
      },
   },
   [nir_op_ixor] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         1,
         1,
         1,
         0,
         0,
         0,
         0,
         0,
         1,
         1,
         1,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         7,
         16,
         16,
         16,
      },
   },
   [nir_search_op_u2f] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         1,
         2,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 3,
      .table = (const uint16_t []) {
      
         0,
         20,
         21,
      },
   },
   [nir_op_extract_u8] = {
      .filter = (const uint16_t []) {
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         0,
         8,
         0,
         8,
      },
   },
   [nir_op_extract_u16] = {
      .filter = (const uint16_t []) {
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         0,
         9,
         0,
         9,
      },
   },
   [nir_search_op_i2f] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         1,
         2,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 3,
      .table = (const uint16_t []) {
      
         0,
         22,
         23,
      },
   },
   [nir_op_extract_i8] = {
      .filter = (const uint16_t []) {
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         0,
         10,
         0,
         10,
      },
   },
   [nir_op_extract_i16] = {
      .filter = (const uint16_t []) {
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         0,
         11,
         0,
         11,
      },
   },
   [nir_op_pack_half_2x16_split] = {
      .filter = NULL,
      
      .num_filtered_states = 1,
      .table = (const uint16_t []) {
      
         12,
      },
   },
   [nir_op_bcsel] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         0,
         0,
         24,
         24,
         0,
         0,
         24,
         24,
      },
   },
   [nir_op_iadd] = {
      .filter = NULL,
      
      .num_filtered_states = 1,
      .table = (const uint16_t []) {
      
         13,
      },
   },
};

/* Mapping from state index to offset in transforms (0 being no transforms) */
static const uint16_t jay_nir_lower_fsign_transform_offsets[] = {
   0,
   0,
   1,
   3,
   0,
   0,
   0,
   0,
   0,
   0,
   0,
   0,
   5,
   0,
   0,
   0,
   0,
   7,
   9,
   11,
   13,
   15,
   17,
   19,
   21,
   23,
   26,
   29,
};

static const nir_algebraic_table jay_nir_lower_fsign_table = {
   .transforms = jay_nir_lower_fsign_transforms,
   .transform_offsets = jay_nir_lower_fsign_transform_offsets,
   .pass_op_table = jay_nir_lower_fsign_pass_op_table,
   .values = jay_nir_lower_fsign_values,
   .expression_cond = jay_nir_lower_fsign_expression_cond,
   .variable_cond = NULL,
};

bool
jay_nir_lower_fsign(
   nir_shader *shader
) {
   bool progress = false;
   bool condition_flags[1];
   const nir_shader_compiler_options *options = shader->options;
   const shader_info *info = &shader->info;
   (void) options;
   (void) info;

   STATIC_ASSERT(66 == ARRAY_SIZE(jay_nir_lower_fsign_values));
   condition_flags[0] = true;

   nir_foreach_function_impl(impl, shader) {
     progress |= nir_algebraic_impl(impl, condition_flags, &jay_nir_lower_fsign_table);
   }

   return progress;
}

#include "nir.h"
#include "nir_builder.h"
#include "nir_search.h"
#include "nir_search_helpers.h"

/* What follows is NIR algebraic transform code for the following 29
 * transforms:
 *    ('ieq', ('iand(is_used_once)', 'a', 'b'), 'b') => ('ieq', ('iand', ('inot', 'a'), 'b'), 0)
 *    ('ine', ('iand(is_used_once)', 'a', 'b'), 'b') => ('ine', ('iand', ('inot', 'a'), 'b'), 0)
 *    ('fneg', ('b2f16', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1.0)
 *    ('fneg', ('b2f16', 'a@1')) => ('bcsel', 'a', -1.0, 0)
 *    ('b2f16', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1.0)
 *    ('b2f16', 'a@1') => ('bcsel', 'a', 1.0, 0)
 *    ('fneg', ('b2f32', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1.0)
 *    ('fneg', ('b2f32', 'a@1')) => ('bcsel', 'a', -1.0, 0)
 *    ('b2f32', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1.0)
 *    ('b2f32', 'a@1') => ('bcsel', 'a', 1.0, 0)
 *    ('ineg', ('b2i8', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1)
 *    ('ineg', ('b2i8', 'a@1')) => ('bcsel', 'a', -1, 0)
 *    ('b2i8', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1)
 *    ('b2i8', 'a@1') => ('bcsel', 'a', 1, 0)
 *    ('ineg', ('b2i16', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1)
 *    ('ineg', ('b2i16', 'a@1')) => ('bcsel', 'a', -1, 0)
 *    ('b2i16', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1)
 *    ('b2i16', 'a@1') => ('bcsel', 'a', 1, 0)
 *    ('ineg', ('b2i32', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1)
 *    ('ineg', ('b2i32', 'a@1')) => ('bcsel', 'a', -1, 0)
 *    ('b2i32', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1)
 *    ('b2i32', 'a@1') => ('bcsel', 'a', 1, 0)
 *    ('b2b8', ('inot', 'a@1')) => ('bcsel', 'a', 0, -1)
 *    ('b2b8', 'a@1') => ('bcsel', 'a', -1, 0)
 *    ('b2b16', ('inot', 'a@1')) => ('bcsel', 'a', 0, -1)
 *    ('b2b16', 'a@1') => ('bcsel', 'a', -1, 0)
 *    ('b2b32', ('inot', 'a@1')) => ('bcsel', 'a', 0, -1)
 *    ('b2b32', 'a@1') => ('bcsel', 'a', -1, 0)
 *    ('b2i64', 'a@1') => ('pack_64_2x32_split', ('bcsel', 'a', 1, 0), 0)
 */


static const nir_search_value_union jay_nir_lower_bool_values[] = {
   /* ('ieq', ('iand(is_used_once)', 'a', 'b'), 'b') => ('ieq', ('iand', ('inot', 'a'), 'b'), 0) */
   { .variable = {
      { nir_search_value_variable, -2 },
      0, /* a */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .variable = {
      { nir_search_value_variable, -2 },
      1, /* b */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_iand,
      1, 1,
      { 0, 1 },
      0,
   } },
   /* search14_1 -> 1 in the cache */
   { .expression = {
      { nir_search_value_expression, 1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ieq,
      0, 2,
      { 2, 1 },
      -1,
   } },

   /* replace14_0_0_0 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 0,
      { 0 },
      -1,
   } },
   /* replace14_0_1 -> 1 in the cache */
   { .expression = {
      { nir_search_value_expression, -2 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_iand,
      1, 1,
      { 4, 1 },
      -1,
   } },
   { .constant = {
      { nir_search_value_constant, -2 },
      nir_type_int, { 0x0ull /* 0 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_ieq,
      0, 2,
      { 5, 6 },
      -1,
   } },

   /* ('ine', ('iand(is_used_once)', 'a', 'b'), 'b') => ('ine', ('iand', ('inot', 'a'), 'b'), 0) */
   /* search15_0_0 -> 0 in the cache */
   /* search15_0_1 -> 1 in the cache */
   /* search15_0 -> 2 in the cache */
   /* search15_1 -> 1 in the cache */
   { .expression = {
      { nir_search_value_expression, 1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ine,
      0, 2,
      { 2, 1 },
      -1,
   } },

   /* replace15_0_0_0 -> 0 in the cache */
   /* replace15_0_0 -> 4 in the cache */
   /* replace15_0_1 -> 1 in the cache */
   /* replace15_0 -> 5 in the cache */
   /* replace15_1 -> 6 in the cache */
   { .expression = {
      { nir_search_value_expression, 1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_ine,
      0, 2,
      { 5, 6 },
      -1,
   } },

   /* ('fneg', ('b2f16', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1.0) */
   { .variable = {
      { nir_search_value_variable, 1 },
      0, /* a */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .expression = {
      { nir_search_value_expression, 1 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_inot,
      -1, 0,
      { 10 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2f16,
      -1, 0,
      { 11 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_fneg,
      -1, 0,
      { 12 },
      -1,
   } },

   /* replace16_0 -> 10 in the cache */
   { .constant = {
      { nir_search_value_constant, 16 },
      nir_type_int, { 0x0ull /* 0 */ },
   } },
   { .constant = {
      { nir_search_value_constant, 16 },
      nir_type_float, { 0xbff0000000000000ull /* -1.0 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 14, 15 },
      -1,
   } },

   /* ('fneg', ('b2f16', 'a@1')) => ('bcsel', 'a', -1.0, 0) */
   /* search17_0_0 -> 10 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2f16,
      -1, 0,
      { 10 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_fneg,
      -1, 0,
      { 17 },
      -1,
   } },

   /* replace17_0 -> 10 in the cache */
   /* replace17_1 -> 15 in the cache */
   /* replace17_2 -> 14 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 15, 14 },
      -1,
   } },

   /* ('b2f16', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1.0) */
   /* search18_0_0 -> 10 in the cache */
   /* search18_0 -> 11 in the cache */
   /* search18 -> 12 in the cache */

   /* replace18_0 -> 10 in the cache */
   /* replace18_1 -> 14 in the cache */
   { .constant = {
      { nir_search_value_constant, 16 },
      nir_type_float, { 0x3ff0000000000000ull /* 1.0 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 14, 20 },
      -1,
   } },

   /* ('b2f16', 'a@1') => ('bcsel', 'a', 1.0, 0) */
   /* search19_0 -> 10 in the cache */
   /* search19 -> 17 in the cache */

   /* replace19_0 -> 10 in the cache */
   /* replace19_1 -> 20 in the cache */
   /* replace19_2 -> 14 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 20, 14 },
      -1,
   } },

   /* ('fneg', ('b2f32', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1.0) */
   /* search20_0_0_0 -> 10 in the cache */
   /* search20_0_0 -> 11 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2f32,
      -1, 0,
      { 11 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_fneg,
      -1, 0,
      { 23 },
      -1,
   } },

   /* replace20_0 -> 10 in the cache */
   { .constant = {
      { nir_search_value_constant, 32 },
      nir_type_int, { 0x0ull /* 0 */ },
   } },
   { .constant = {
      { nir_search_value_constant, 32 },
      nir_type_float, { 0xbff0000000000000ull /* -1.0 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 25, 26 },
      -1,
   } },

   /* ('fneg', ('b2f32', 'a@1')) => ('bcsel', 'a', -1.0, 0) */
   /* search21_0_0 -> 10 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2f32,
      -1, 0,
      { 10 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_fneg,
      -1, 0,
      { 28 },
      -1,
   } },

   /* replace21_0 -> 10 in the cache */
   /* replace21_1 -> 26 in the cache */
   /* replace21_2 -> 25 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 26, 25 },
      -1,
   } },

   /* ('b2f32', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1.0) */
   /* search22_0_0 -> 10 in the cache */
   /* search22_0 -> 11 in the cache */
   /* search22 -> 23 in the cache */

   /* replace22_0 -> 10 in the cache */
   /* replace22_1 -> 25 in the cache */
   { .constant = {
      { nir_search_value_constant, 32 },
      nir_type_float, { 0x3ff0000000000000ull /* 1.0 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 25, 31 },
      -1,
   } },

   /* ('b2f32', 'a@1') => ('bcsel', 'a', 1.0, 0) */
   /* search23_0 -> 10 in the cache */
   /* search23 -> 28 in the cache */

   /* replace23_0 -> 10 in the cache */
   /* replace23_1 -> 31 in the cache */
   /* replace23_2 -> 25 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 31, 25 },
      -1,
   } },

   /* ('ineg', ('b2i8', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1) */
   /* search24_0_0_0 -> 10 in the cache */
   /* search24_0_0 -> 11 in the cache */
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2i8,
      -1, 0,
      { 11 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ineg,
      -1, 0,
      { 34 },
      -1,
   } },

   /* replace24_0 -> 10 in the cache */
   { .constant = {
      { nir_search_value_constant, 8 },
      nir_type_int, { 0x0ull /* 0 */ },
   } },
   { .constant = {
      { nir_search_value_constant, 8 },
      nir_type_int, { 0xffffffffffffffffull /* -1 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 36, 37 },
      -1,
   } },

   /* ('ineg', ('b2i8', 'a@1')) => ('bcsel', 'a', -1, 0) */
   /* search25_0_0 -> 10 in the cache */
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2i8,
      -1, 0,
      { 10 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ineg,
      -1, 0,
      { 39 },
      -1,
   } },

   /* replace25_0 -> 10 in the cache */
   /* replace25_1 -> 37 in the cache */
   /* replace25_2 -> 36 in the cache */
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 37, 36 },
      -1,
   } },

   /* ('b2i8', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1) */
   /* search26_0_0 -> 10 in the cache */
   /* search26_0 -> 11 in the cache */
   /* search26 -> 34 in the cache */

   /* replace26_0 -> 10 in the cache */
   /* replace26_1 -> 36 in the cache */
   { .constant = {
      { nir_search_value_constant, 8 },
      nir_type_int, { 0x1ull /* 1 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 36, 42 },
      -1,
   } },

   /* ('b2i8', 'a@1') => ('bcsel', 'a', 1, 0) */
   /* search27_0 -> 10 in the cache */
   /* search27 -> 39 in the cache */

   /* replace27_0 -> 10 in the cache */
   /* replace27_1 -> 42 in the cache */
   /* replace27_2 -> 36 in the cache */
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 42, 36 },
      -1,
   } },

   /* ('ineg', ('b2i16', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1) */
   /* search28_0_0_0 -> 10 in the cache */
   /* search28_0_0 -> 11 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2i16,
      -1, 0,
      { 11 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ineg,
      -1, 0,
      { 45 },
      -1,
   } },

   /* replace28_0 -> 10 in the cache */
   /* replace28_1 -> 14 in the cache */
   { .constant = {
      { nir_search_value_constant, 16 },
      nir_type_int, { 0xffffffffffffffffull /* -1 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 14, 47 },
      -1,
   } },

   /* ('ineg', ('b2i16', 'a@1')) => ('bcsel', 'a', -1, 0) */
   /* search29_0_0 -> 10 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2i16,
      -1, 0,
      { 10 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ineg,
      -1, 0,
      { 49 },
      -1,
   } },

   /* replace29_0 -> 10 in the cache */
   /* replace29_1 -> 47 in the cache */
   /* replace29_2 -> 14 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 47, 14 },
      -1,
   } },

   /* ('b2i16', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1) */
   /* search30_0_0 -> 10 in the cache */
   /* search30_0 -> 11 in the cache */
   /* search30 -> 45 in the cache */

   /* replace30_0 -> 10 in the cache */
   /* replace30_1 -> 14 in the cache */
   { .constant = {
      { nir_search_value_constant, 16 },
      nir_type_int, { 0x1ull /* 1 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 14, 52 },
      -1,
   } },

   /* ('b2i16', 'a@1') => ('bcsel', 'a', 1, 0) */
   /* search31_0 -> 10 in the cache */
   /* search31 -> 49 in the cache */

   /* replace31_0 -> 10 in the cache */
   /* replace31_1 -> 52 in the cache */
   /* replace31_2 -> 14 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 52, 14 },
      -1,
   } },

   /* ('ineg', ('b2i32', ('inot', 'a@1'))) => ('bcsel', 'a', 0, -1) */
   /* search32_0_0_0 -> 10 in the cache */
   /* search32_0_0 -> 11 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2i32,
      -1, 0,
      { 11 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ineg,
      -1, 0,
      { 55 },
      -1,
   } },

   /* replace32_0 -> 10 in the cache */
   /* replace32_1 -> 25 in the cache */
   { .constant = {
      { nir_search_value_constant, 32 },
      nir_type_int, { 0xffffffffffffffffull /* -1 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 25, 57 },
      -1,
   } },

   /* ('ineg', ('b2i32', 'a@1')) => ('bcsel', 'a', -1, 0) */
   /* search33_0_0 -> 10 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2i32,
      -1, 0,
      { 10 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ineg,
      -1, 0,
      { 59 },
      -1,
   } },

   /* replace33_0 -> 10 in the cache */
   /* replace33_1 -> 57 in the cache */
   /* replace33_2 -> 25 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 57, 25 },
      -1,
   } },

   /* ('b2i32', ('inot', 'a@1')) => ('bcsel', 'a', 0, 1) */
   /* search34_0_0 -> 10 in the cache */
   /* search34_0 -> 11 in the cache */
   /* search34 -> 55 in the cache */

   /* replace34_0 -> 10 in the cache */
   /* replace34_1 -> 25 in the cache */
   { .constant = {
      { nir_search_value_constant, 32 },
      nir_type_int, { 0x1ull /* 1 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 25, 62 },
      -1,
   } },

   /* ('b2i32', 'a@1') => ('bcsel', 'a', 1, 0) */
   /* search35_0 -> 10 in the cache */
   /* search35 -> 59 in the cache */

   /* replace35_0 -> 10 in the cache */
   /* replace35_1 -> 62 in the cache */
   /* replace35_2 -> 25 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 10, 62, 25 },
      -1,
   } },

   /* ('b2b8', ('inot', 'a@1')) => ('bcsel', 'a', 0, -1) */
   /* search36_0_0 -> 10 in the cache */
   /* search36_0 -> 11 in the cache */
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2b8,
      -1, 0,
      { 11 },
      -1,
   } },

   /* replace36_0 -> 10 in the cache */
   /* replace36_1 -> 36 in the cache */
   /* replace36_2 -> 37 in the cache */
   /* replace36 -> 38 in the cache */

   /* ('b2b8', 'a@1') => ('bcsel', 'a', -1, 0) */
   /* search37_0 -> 10 in the cache */
   { .expression = {
      { nir_search_value_expression, 8 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2b8,
      -1, 0,
      { 10 },
      -1,
   } },

   /* replace37_0 -> 10 in the cache */
   /* replace37_1 -> 37 in the cache */
   /* replace37_2 -> 36 in the cache */
   /* replace37 -> 41 in the cache */

   /* ('b2b16', ('inot', 'a@1')) => ('bcsel', 'a', 0, -1) */
   /* search38_0_0 -> 10 in the cache */
   /* search38_0 -> 11 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2b16,
      -1, 0,
      { 11 },
      -1,
   } },

   /* replace38_0 -> 10 in the cache */
   /* replace38_1 -> 14 in the cache */
   /* replace38_2 -> 47 in the cache */
   /* replace38 -> 48 in the cache */

   /* ('b2b16', 'a@1') => ('bcsel', 'a', -1, 0) */
   /* search39_0 -> 10 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2b16,
      -1, 0,
      { 10 },
      -1,
   } },

   /* replace39_0 -> 10 in the cache */
   /* replace39_1 -> 47 in the cache */
   /* replace39_2 -> 14 in the cache */
   /* replace39 -> 51 in the cache */

   /* ('b2b32', ('inot', 'a@1')) => ('bcsel', 'a', 0, -1) */
   /* search40_0_0 -> 10 in the cache */
   /* search40_0 -> 11 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2b32,
      -1, 0,
      { 11 },
      -1,
   } },

   /* replace40_0 -> 10 in the cache */
   /* replace40_1 -> 25 in the cache */
   /* replace40_2 -> 57 in the cache */
   /* replace40 -> 58 in the cache */

   /* ('b2b32', 'a@1') => ('bcsel', 'a', -1, 0) */
   /* search41_0 -> 10 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2b32,
      -1, 0,
      { 10 },
      -1,
   } },

   /* replace41_0 -> 10 in the cache */
   /* replace41_1 -> 57 in the cache */
   /* replace41_2 -> 25 in the cache */
   /* replace41 -> 61 in the cache */

   /* ('b2i64', 'a@1') => ('pack_64_2x32_split', ('bcsel', 'a', 1, 0), 0) */
   /* search42_0 -> 10 in the cache */
   { .expression = {
      { nir_search_value_expression, 64 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_b2i64,
      -1, 0,
      { 10 },
      -1,
   } },

   /* replace42_0_0 -> 10 in the cache */
   /* replace42_0_1 -> 62 in the cache */
   /* replace42_0_2 -> 25 in the cache */
   /* replace42_0 -> 64 in the cache */
   /* replace42_1 -> 25 in the cache */
   { .expression = {
      { nir_search_value_expression, 64 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_pack_64_2x32_split,
      -1, 0,
      { 64, 25 },
      -1,
   } },

};

UNUSED static const nir_search_expression_cond jay_nir_lower_bool_expression_cond[] = {
   is_used_once,
};


static const struct transform jay_nir_lower_bool_transforms[] = {
   { ~0, ~0, ~0 }, /* Sentinel */

   { 17, 22, 0 },
   { 28, 33, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 39, 44, 0 },
   { 49, 54, 0 },
   { 59, 64, 0 },
   { 71, 72, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 66, 41, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 68, 51, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 70, 61, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 3, 7, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 8, 9, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 18, 19, 0 },
   { 29, 30, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 12, 21, 0 },
   { 17, 22, 0 },
   { 23, 32, 0 },
   { 28, 33, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 34, 43, 0 },
   { 39, 44, 0 },
   { 45, 53, 0 },
   { 49, 54, 0 },
   { 55, 63, 0 },
   { 59, 64, 0 },
   { 71, 72, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 65, 38, 0 },
   { 66, 41, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 67, 48, 0 },
   { 68, 51, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 69, 58, 0 },
   { 70, 61, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 40, 41, 0 },
   { 50, 51, 0 },
   { 60, 61, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 13, 16, 0 },
   { 18, 19, 0 },
   { 24, 27, 0 },
   { 29, 30, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

   { 35, 38, 0 },
   { 40, 41, 0 },
   { 46, 48, 0 },
   { 50, 51, 0 },
   { 56, 58, 0 },
   { 60, 61, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

};

static const struct per_op_table jay_nir_lower_bool_pass_op_table[nir_num_search_ops] = {
   [nir_op_ieq] = {
      .filter = (const uint16_t []) {
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         0,
         9,
         9,
         9,
      },
   },
   [nir_op_iand] = {
      .filter = NULL,
      
      .num_filtered_states = 1,
      .table = (const uint16_t []) {
      
         2,
      },
   },
   [nir_op_ine] = {
      .filter = (const uint16_t []) {
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         0,
         10,
         10,
         10,
      },
   },
   [nir_op_fneg] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         2,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 3,
      .table = (const uint16_t []) {
      
         0,
         11,
         18,
      },
   },
   [nir_search_op_b2f] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         3,
         12,
      },
   },
   [nir_op_inot] = {
      .filter = NULL,
      
      .num_filtered_states = 1,
      .table = (const uint16_t []) {
      
         4,
      },
   },
   [nir_op_ineg] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         2,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 3,
      .table = (const uint16_t []) {
      
         0,
         17,
         19,
      },
   },
   [nir_search_op_b2i] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         5,
         13,
      },
   },
   [nir_op_b2b8] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         6,
         14,
      },
   },
   [nir_op_b2b16] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         7,
         15,
      },
   },
   [nir_op_b2b32] = {
      .filter = (const uint16_t []) {
         0,
         0,
         0,
         0,
         1,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         8,
         16,
      },
   },
};

/* Mapping from state index to offset in transforms (0 being no transforms) */
static const uint16_t jay_nir_lower_bool_transform_offsets[] = {
   0,
   0,
   0,
   1,
   0,
   4,
   9,
   11,
   13,
   15,
   17,
   19,
   22,
   27,
   35,
   38,
   41,
   44,
   48,
   53,
};

static const nir_algebraic_table jay_nir_lower_bool_table = {
   .transforms = jay_nir_lower_bool_transforms,
   .transform_offsets = jay_nir_lower_bool_transform_offsets,
   .pass_op_table = jay_nir_lower_bool_pass_op_table,
   .values = jay_nir_lower_bool_values,
   .expression_cond = jay_nir_lower_bool_expression_cond,
   .variable_cond = NULL,
};

bool
jay_nir_lower_bool(
   nir_shader *shader
) {
   bool progress = false;
   bool condition_flags[1];
   const nir_shader_compiler_options *options = shader->options;
   const shader_info *info = &shader->info;
   (void) options;
   (void) info;

   STATIC_ASSERT(73 == ARRAY_SIZE(jay_nir_lower_bool_values));
   condition_flags[0] = true;

   nir_foreach_function_impl(impl, shader) {
     progress |= nir_algebraic_impl(impl, condition_flags, &jay_nir_lower_bool_table);
   }

   return progress;
}

#include "nir.h"
#include "nir_builder.h"
#include "nir_search.h"
#include "nir_search_helpers.h"

/* What follows is NIR algebraic transform code for the following 2
 * transforms:
 *    ('bcsel@32', 'a', 0, 1) => ('iadd', ('bcsel', 'a', 4294967295, 0), 1)
 *    ('bcsel@32', 'a', 1, 0) => ('ineg', ('bcsel', 'a', 4294967295, 0))
 */


static const nir_search_value_union jay_nir_opt_sel_zero_values[] = {
   /* ('bcsel@32', 'a', 0, 1) => ('iadd', ('bcsel', 'a', 4294967295, 0), 1) */
   { .variable = {
      { nir_search_value_variable, 1 },
      0, /* a */
      false,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .constant = {
      { nir_search_value_constant, 32 },
      nir_type_int, { 0x0ull /* 0 */ },
   } },
   { .constant = {
      { nir_search_value_constant, 32 },
      nir_type_int, { 0x1ull /* 1 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 0, 1, 2 },
      -1,
   } },

   /* replace43_0_0 -> 0 in the cache */
   { .constant = {
      { nir_search_value_constant, 32 },
      nir_type_int, { 0xffffffffull /* 4294967295 */ },
   } },
   /* replace43_0_2 -> 1 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 0, 4, 1 },
      -1,
   } },
   /* replace43_1 -> 2 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_iadd,
      0, 1,
      { 5, 2 },
      -1,
   } },

   /* ('bcsel@32', 'a', 1, 0) => ('ineg', ('bcsel', 'a', 4294967295, 0)) */
   /* search44_0 -> 0 in the cache */
   /* search44_1 -> 2 in the cache */
   /* search44_2 -> 1 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      true,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 0, 2, 1 },
      -1,
   } },

   /* replace44_0_0 -> 0 in the cache */
   /* replace44_0_1 -> 4 in the cache */
   /* replace44_0_2 -> 1 in the cache */
   /* replace44_0 -> 5 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      nir_fp_fast_math,
      nir_fp_fast_math,
      false,
      -1,
      nir_op_ineg,
      -1, 0,
      { 5 },
      -1,
   } },

};



static const struct transform jay_nir_opt_sel_zero_transforms[] = {
   { ~0, ~0, ~0 }, /* Sentinel */

   { 3, 6, 0 },
   { 7, 8, 0 },
   { ~0, ~0, ~0 }, /* Sentinel */

};

static const struct per_op_table jay_nir_opt_sel_zero_pass_op_table[nir_num_search_ops] = {
   [nir_op_bcsel] = {
      .filter = (const uint16_t []) {
         0,
         1,
         0,
      },
      
      .num_filtered_states = 2,
      .table = (const uint16_t []) {
      
         0,
         0,
         0,
         2,
         0,
         0,
         0,
         2,
      },
   },
};

/* Mapping from state index to offset in transforms (0 being no transforms) */
static const uint16_t jay_nir_opt_sel_zero_transform_offsets[] = {
   0,
   0,
   1,
};

static const nir_algebraic_table jay_nir_opt_sel_zero_table = {
   .transforms = jay_nir_opt_sel_zero_transforms,
   .transform_offsets = jay_nir_opt_sel_zero_transform_offsets,
   .pass_op_table = jay_nir_opt_sel_zero_pass_op_table,
   .values = jay_nir_opt_sel_zero_values,
   .expression_cond = NULL,
   .variable_cond = NULL,
};

bool
jay_nir_opt_sel_zero(
   nir_shader *shader
) {
   bool progress = false;
   bool condition_flags[1];
   const nir_shader_compiler_options *options = shader->options;
   const shader_info *info = &shader->info;
   (void) options;
   (void) info;

   STATIC_ASSERT(9 == ARRAY_SIZE(jay_nir_opt_sel_zero_values));
   condition_flags[0] = true;

   nir_foreach_function_impl(impl, shader) {
     progress |= nir_algebraic_impl(impl, condition_flags, &jay_nir_opt_sel_zero_table);
   }

   return progress;
}
