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;
}
}