/*
 * Copyright 2023 Intel Corporation
 * SPDX-License-Identifier: MIT
 */

#include "nir.h"
#include "nir_instr_set.h"

bool
nir_opt_reuse_constants(nir_shader *shader)
{
   bool progress = false;

   struct set *consts = nir_instr_set_create(NULL);
   nir_foreach_function_impl(impl, shader) {
      _mesa_set_clear(consts, NULL);

      nir_block *start_block = nir_start_block(impl);
      bool func_progress = false;

      nir_foreach_block_safe(block, impl) {
         const bool in_start_block = start_block == block;
         nir_foreach_instr_safe(instr, block) {
            if (instr->type != nir_instr_type_load_const)
               continue;

            struct set_entry *entry = _mesa_set_search(consts, instr);
            if (!entry) {
               if (!in_start_block)
                  nir_instr_move(nir_after_block_before_jump(start_block), instr);
               _mesa_set_add(consts, instr);
            }

            if (nir_instr_set_add_or_rewrite(consts, instr, nir_instrs_equal)) {
               func_progress = true;
               nir_instr_remove(instr);
            }
         }
      }

      if (func_progress) {
         nir_metadata_preserve(impl, nir_metadata_control_flow);
         progress = true;
      } else {
         nir_metadata_preserve(impl, nir_metadata_all);
      }
   }

   nir_instr_set_destroy(consts);
   return progress;
}
