#include "msl_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 1
 * transforms:
 *    ('f2f16_rtz', 'a@32') => ('bcsel', ('flt', ('fabs', 'a'), ('fabs', ('f2f32', ('f2f16_rtne', 'a')))), ('isub', ('f2f16_rtne', 'a'), 1), ('f2f16_rtne', 'a'))
 */


static const nir_search_value_union msl_nir_lower_algebraic_late_values[] = {
   /* ('f2f16_rtz', 'a@32') => ('bcsel', ('flt', ('fabs', 'a'), ('fabs', ('f2f32', ('f2f16_rtne', 'a')))), ('isub', ('f2f16_rtne', 'a'), 1), ('f2f16_rtne', 'a')) */
   { .variable = {
      { nir_search_value_variable, 32 },
      0, /* a */
      false,
      nir_type_invalid,
      -1,
      {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      -1,
      nir_op_f2f16_rtz,
      -1, 0,
      { 0 },
      -1,
   } },

   /* replace0_0_0_0 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, 32 },
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      -1,
      nir_op_fabs,
      -1, 0,
      { 0 },
      -1,
   } },
   /* replace0_0_1_0_0_0 -> 0 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      -1,
      nir_op_f2f16_rtne,
      -1, 0,
      { 0 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      -1,
      nir_op_f2f32,
      -1, 0,
      { 3 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 32 },
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      -1,
      nir_op_fabs,
      -1, 0,
      { 4 },
      -1,
   } },
   { .expression = {
      { nir_search_value_expression, 1 },
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      -1,
      nir_op_flt,
      -1, 0,
      { 2, 5 },
      -1,
   } },
   /* replace0_1_0_0 -> 0 in the cache */
   /* replace0_1_0 -> 3 in the cache */
   { .constant = {
      { nir_search_value_constant, 16 },
      nir_type_int, { 0x1ull /* 1 */ },
   } },
   { .expression = {
      { nir_search_value_expression, 16 },
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      true,
      -1,
      nir_op_isub,
      -1, 0,
      { 3, 7 },
      -1,
   } },
   /* replace0_2_0 -> 0 in the cache */
   /* replace0_2 -> 3 in the cache */
   { .expression = {
      { nir_search_value_expression, 16 },
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      false,
      -1,
      nir_op_bcsel,
      -1, 0,
      { 6, 8, 3 },
      -1,
   } },

};



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

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

};

static const struct per_op_table msl_nir_lower_algebraic_late_pass_op_table[nir_num_search_ops] = {
   [nir_op_f2f16_rtz] = {
      .filter = NULL,
      
      .num_filtered_states = 1,
      .table = (const uint16_t []) {
      
         2,
      },
   },
};

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

static const nir_algebraic_table msl_nir_lower_algebraic_late_table = {
   .transforms = msl_nir_lower_algebraic_late_transforms,
   .transform_offsets = msl_nir_lower_algebraic_late_transform_offsets,
   .pass_op_table = msl_nir_lower_algebraic_late_pass_op_table,
   .values = msl_nir_lower_algebraic_late_values,
   .expression_cond = NULL,
   .variable_cond = NULL,
};

bool
msl_nir_lower_algebraic_late(
   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(10 == ARRAY_SIZE(msl_nir_lower_algebraic_late_values));
   condition_flags[0] = true;

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

   return progress;
}

