/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "instruction_simplifier_mips.h"

#include "arch/mips/instruction_set_features_mips.h"
#include "mirror/array-inl.h"

namespace art {
namespace mips {

class InstructionSimplifierMipsVisitor : public HGraphVisitor {
 public:
  InstructionSimplifierMipsVisitor(HGraph* graph,
                                   CodeGenerator* codegen,
                                   OptimizingCompilerStats* stats)
      : HGraphVisitor(graph),
        stats_(stats),
        codegen_(down_cast<CodeGeneratorMIPS*>(codegen)) {}

 private:
  void RecordSimplification() {
    if (stats_ != nullptr) {
      stats_->RecordStat(kInstructionSimplificationsArch);
    }
  }

  bool TryExtractArrayAccessIndex(HInstruction* access,
                                  HInstruction* index,
                                  DataType::Type packed_type);
  void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
  void VisitArraySet(HArraySet* instruction) OVERRIDE;

  OptimizingCompilerStats* stats_;
  CodeGeneratorMIPS* codegen_;
};

bool InstructionSimplifierMipsVisitor::TryExtractArrayAccessIndex(HInstruction* access,
                                                                  HInstruction* index,
                                                                  DataType::Type packed_type) {
  if (codegen_->GetInstructionSetFeatures().IsR6() ||
      codegen_->GetInstructionSetFeatures().HasMsa()) {
    return false;
  }
  if (index->IsConstant() ||
      (index->IsBoundsCheck() && index->AsBoundsCheck()->GetIndex()->IsConstant())) {
    // If index is constant the whole address calculation often can be done by load/store
    // instructions themselves.
    // TODO: Treat the case with non-embeddable constants.
    return false;
  }

  if (packed_type != DataType::Type::kInt16 && packed_type != DataType::Type::kUint16 &&
      packed_type != DataType::Type::kInt32 && packed_type != DataType::Type::kInt64 &&
      packed_type != DataType::Type::kFloat32 && packed_type != DataType::Type::kFloat64) {
    return false;
  }

  if (access->IsArrayGet() && access->AsArrayGet()->IsStringCharAt()) {
    return false;
  }

  HGraph* graph = access->GetBlock()->GetGraph();
  ArenaAllocator* arena = graph->GetArena();
  size_t component_shift = DataType::SizeShift(packed_type);

  bool is_extracting_beneficial = false;
  // It is beneficial to extract index intermediate address only if there are at least 2 users.
  for (const HUseListNode<HInstruction*>& use : index->GetUses()) {
    HInstruction* user = use.GetUser();
    if (user->IsArrayGet() && user != access && !user->AsArrayGet()->IsStringCharAt()) {
      HArrayGet* another_access = user->AsArrayGet();
      DataType::Type another_packed_type = another_access->GetType();
      size_t another_component_shift = DataType::SizeShift(another_packed_type);
      if (another_component_shift == component_shift) {
        is_extracting_beneficial = true;
        break;
      }
    } else if (user->IsArraySet() && user != access) {
      HArraySet* another_access = user->AsArraySet();
      DataType::Type another_packed_type = another_access->GetType();
      size_t another_component_shift = DataType::SizeShift(another_packed_type);
      if (another_component_shift == component_shift) {
        is_extracting_beneficial = true;
        break;
      }
    } else if (user->IsIntermediateArrayAddressIndex()) {
      HIntermediateArrayAddressIndex* another_access = user->AsIntermediateArrayAddressIndex();
      size_t another_component_shift = another_access->GetShift()->AsIntConstant()->GetValue();
      if (another_component_shift == component_shift) {
        is_extracting_beneficial = true;
        break;
      }
    }
  }

  if (!is_extracting_beneficial) {
    return false;
  }

  HIntConstant* shift = graph->GetIntConstant(component_shift);
  HIntermediateArrayAddressIndex* address =
      new (arena) HIntermediateArrayAddressIndex(index, shift, kNoDexPc);
  access->GetBlock()->InsertInstructionBefore(address, access);
  access->ReplaceInput(address, 1);
  return true;
}

void InstructionSimplifierMipsVisitor::VisitArrayGet(HArrayGet* instruction) {
  DataType::Type packed_type = instruction->GetType();
  if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) {
    RecordSimplification();
  }
}

void InstructionSimplifierMipsVisitor::VisitArraySet(HArraySet* instruction) {
  DataType::Type packed_type = instruction->GetComponentType();
  if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) {
    RecordSimplification();
  }
}

void InstructionSimplifierMips::Run() {
  InstructionSimplifierMipsVisitor visitor(graph_, codegen_, stats_);
  visitor.VisitReversePostOrder();
}

}  // namespace mips
}  // namespace art
