/*
 * 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 HIDDEN {
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() {
    MaybeRecordStat(stats_, MethodCompilationStat::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* allocator = graph->GetAllocator();
  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 (allocator) 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();
  }
}

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

}  // namespace mips
}  // namespace art
