// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void SimpleDeadCodeElimination::AddIndexes(Operand* op, LoadStoreInfo& info, 
                                           Variable* variable, bool isStore) {
    if(auto variableRef = op->As<VariableReference>()) {
        if(variableRef->GetVariable() == variable) {
            // Found the base variable.
            info.Valid = true;
        }
        return;
    }
    else if(auto indexInstr = op->DefiningInstrAs<IndexInstr>()) {
        // Check if we have a constant index.
        if(auto intConst = indexInstr->IndexOp()->As<IntConstant>()) {
            info.IndexList.Add(intConst->Value());
        }
        else info.HasVariableIndex = true;

        AddIndexes(indexInstr->BaseOp(), info, variable, isStore);
        return;
    }
    else if(auto elemInstr = op->DefiningInstrAs<ElementInstr>()) {
        info.IndexList.Add(elemInstr->GetFieldIndex());
        AddIndexes(elemInstr->BaseOp(), info, variable, isStore);
        return;
    }
    else if(isStore == false) {
        // Keep track of 'addr' and 'ptop' that lead to the variable,
        // because they keep alive any store.
        if(auto addrInstr = op->DefiningInstrAs<AddressInstr>()) {
            info.HasVariableIndex = true;
            AddIndexes(addrInstr->BaseOp(), info, variable, isStore);
        }
        else if(auto ptopInstr = op->DefiningInstrAs<PtopInstr>()) {
            info.HasVariableIndex = true;
            AddIndexes(ptopInstr->TargetOp(), info, variable, isStore);
        }
        return;
    }

    // Any other instruction renders the 'store' invalid.
    info.Valid = false;
}
void IndexTuner::Analyze(storage::DataTable* table) {

  // Process all samples in table
  auto& samples = table->GetIndexSamples();
  auto sample_count = samples.size();

  // Check if we have sufficient number of samples
  if (sample_count < sample_count_threshold) {
    return;
  }

  // Check write ratio
  auto average_write_ratio = ComputeWorkloadWriteRatio(samples);

  // Determine frequent samples
  auto sample_frequency_entry_list = GetFrequentSamples(samples);

  // Compute suggested indices
  auto suggested_indices = GetSuggestedIndices(sample_frequency_entry_list);

  // Check index storage footprint
  auto max_indexes_allowed = CheckIndexStorageFootprint(table);

  // Drop indexes if needed
  auto index_creation_constraint = (max_indexes_allowed <= 0);
  auto write_intensive_workload = (average_write_ratio > write_ratio_threshold);
  if (index_creation_constraint == true || write_intensive_workload == true) {
    DropIndexes(table);
  }

  // Add indexes if needed
  AddIndexes(table, suggested_indices, max_indexes_allowed);

  // Clear all current samples in table
  table->ClearIndexSamples();

  // Update index utility
  UpdateIndexUtility(table, sample_frequency_entry_list);

  // Display index information
  PrintIndexInformation(table);
}