void InstructionCodeGeneratorMIPS::HandleBinaryOp()

in compiler/optimizing/code_generator_mips.cc [1184:1399]


void InstructionCodeGeneratorMIPS::HandleBinaryOp(HBinaryOperation* instruction) {
  Primitive::Type type = instruction->GetType();
  LocationSummary* locations = instruction->GetLocations();

  switch (type) {
    case Primitive::kPrimInt: {
      Register dst = locations->Out().AsRegister<Register>();
      Register lhs = locations->InAt(0).AsRegister<Register>();
      Location rhs_location = locations->InAt(1);

      Register rhs_reg = ZERO;
      int32_t rhs_imm = 0;
      bool use_imm = rhs_location.IsConstant();
      if (use_imm) {
        rhs_imm = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant());
      } else {
        rhs_reg = rhs_location.AsRegister<Register>();
      }

      if (instruction->IsAnd()) {
        if (use_imm)
          __ Andi(dst, lhs, rhs_imm);
        else
          __ And(dst, lhs, rhs_reg);
      } else if (instruction->IsOr()) {
        if (use_imm)
          __ Ori(dst, lhs, rhs_imm);
        else
          __ Or(dst, lhs, rhs_reg);
      } else if (instruction->IsXor()) {
        if (use_imm)
          __ Xori(dst, lhs, rhs_imm);
        else
          __ Xor(dst, lhs, rhs_reg);
      } else if (instruction->IsAdd()) {
        if (use_imm)
          __ Addiu(dst, lhs, rhs_imm);
        else
          __ Addu(dst, lhs, rhs_reg);
      } else {
        DCHECK(instruction->IsSub());
        if (use_imm)
          __ Addiu(dst, lhs, -rhs_imm);
        else
          __ Subu(dst, lhs, rhs_reg);
      }
      break;
    }

    case Primitive::kPrimLong: {
      Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
      Register dst_low = locations->Out().AsRegisterPairLow<Register>();
      Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
      Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
      Location rhs_location = locations->InAt(1);
      bool use_imm = rhs_location.IsConstant();
      if (!use_imm) {
        Register rhs_high = rhs_location.AsRegisterPairHigh<Register>();
        Register rhs_low = rhs_location.AsRegisterPairLow<Register>();
        if (instruction->IsAnd()) {
          __ And(dst_low, lhs_low, rhs_low);
          __ And(dst_high, lhs_high, rhs_high);
        } else if (instruction->IsOr()) {
          __ Or(dst_low, lhs_low, rhs_low);
          __ Or(dst_high, lhs_high, rhs_high);
        } else if (instruction->IsXor()) {
          __ Xor(dst_low, lhs_low, rhs_low);
          __ Xor(dst_high, lhs_high, rhs_high);
        } else if (instruction->IsAdd()) {
          if (lhs_low == rhs_low) {
            // Special case for lhs = rhs and the sum potentially overwriting both lhs and rhs.
            __ Slt(TMP, lhs_low, ZERO);
            __ Addu(dst_low, lhs_low, rhs_low);
          } else {
            __ Addu(dst_low, lhs_low, rhs_low);
            // If the sum overwrites rhs, lhs remains unchanged, otherwise rhs remains unchanged.
            __ Sltu(TMP, dst_low, (dst_low == rhs_low) ? lhs_low : rhs_low);
          }
          __ Addu(dst_high, lhs_high, rhs_high);
          __ Addu(dst_high, dst_high, TMP);
        } else {
          DCHECK(instruction->IsSub());
          __ Sltu(TMP, lhs_low, rhs_low);
          __ Subu(dst_low, lhs_low, rhs_low);
          __ Subu(dst_high, lhs_high, rhs_high);
          __ Subu(dst_high, dst_high, TMP);
        }
      } else {
        int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
        if (instruction->IsOr()) {
          uint32_t low = Low32Bits(value);
          uint32_t high = High32Bits(value);
          if (IsUint<16>(low)) {
            if (dst_low != lhs_low || low != 0) {
              __ Ori(dst_low, lhs_low, low);
            }
          } else {
            __ LoadConst32(TMP, low);
            __ Or(dst_low, lhs_low, TMP);
          }
          if (IsUint<16>(high)) {
            if (dst_high != lhs_high || high != 0) {
              __ Ori(dst_high, lhs_high, high);
            }
          } else {
            if (high != low) {
              __ LoadConst32(TMP, high);
            }
            __ Or(dst_high, lhs_high, TMP);
          }
        } else if (instruction->IsXor()) {
          uint32_t low = Low32Bits(value);
          uint32_t high = High32Bits(value);
          if (IsUint<16>(low)) {
            if (dst_low != lhs_low || low != 0) {
              __ Xori(dst_low, lhs_low, low);
            }
          } else {
            __ LoadConst32(TMP, low);
            __ Xor(dst_low, lhs_low, TMP);
          }
          if (IsUint<16>(high)) {
            if (dst_high != lhs_high || high != 0) {
              __ Xori(dst_high, lhs_high, high);
            }
          } else {
            if (high != low) {
              __ LoadConst32(TMP, high);
            }
            __ Xor(dst_high, lhs_high, TMP);
          }
        } else if (instruction->IsAnd()) {
          uint32_t low = Low32Bits(value);
          uint32_t high = High32Bits(value);
          if (IsUint<16>(low)) {
            __ Andi(dst_low, lhs_low, low);
          } else if (low != 0xFFFFFFFF) {
            __ LoadConst32(TMP, low);
            __ And(dst_low, lhs_low, TMP);
          } else if (dst_low != lhs_low) {
            __ Move(dst_low, lhs_low);
          }
          if (IsUint<16>(high)) {
            __ Andi(dst_high, lhs_high, high);
          } else if (high != 0xFFFFFFFF) {
            if (high != low) {
              __ LoadConst32(TMP, high);
            }
            __ And(dst_high, lhs_high, TMP);
          } else if (dst_high != lhs_high) {
            __ Move(dst_high, lhs_high);
          }
        } else {
          if (instruction->IsSub()) {
            value = -value;
          } else {
            DCHECK(instruction->IsAdd());
          }
          int32_t low = Low32Bits(value);
          int32_t high = High32Bits(value);
          if (IsInt<16>(low)) {
            if (dst_low != lhs_low || low != 0) {
              __ Addiu(dst_low, lhs_low, low);
            }
            if (low != 0) {
              __ Sltiu(AT, dst_low, low);
            }
          } else {
            __ LoadConst32(TMP, low);
            __ Addu(dst_low, lhs_low, TMP);
            __ Sltu(AT, dst_low, TMP);
          }
          if (IsInt<16>(high)) {
            if (dst_high != lhs_high || high != 0) {
              __ Addiu(dst_high, lhs_high, high);
            }
          } else {
            if (high != low) {
              __ LoadConst32(TMP, high);
            }
            __ Addu(dst_high, lhs_high, TMP);
          }
          if (low != 0) {
            __ Addu(dst_high, dst_high, AT);
          }
        }
      }
      break;
    }

    case Primitive::kPrimFloat:
    case Primitive::kPrimDouble: {
      FRegister dst = locations->Out().AsFpuRegister<FRegister>();
      FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
      FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
      if (instruction->IsAdd()) {
        if (type == Primitive::kPrimFloat) {
          __ AddS(dst, lhs, rhs);
        } else {
          __ AddD(dst, lhs, rhs);
        }
      } else {
        DCHECK(instruction->IsSub());
        if (type == Primitive::kPrimFloat) {
          __ SubS(dst, lhs, rhs);
        } else {
          __ SubD(dst, lhs, rhs);
        }
      }
      break;
    }

    default:
      LOG(FATAL) << "Unexpected binary operation type " << type;
  }
}