diff options
author | 2015-12-16 15:45:29 +0000 | |
---|---|---|
committer | 2015-12-16 15:45:29 +0000 | |
commit | cbf8af898e758cef27687c20c8cf9ac75280026d (patch) | |
tree | 982a30df208013b0b3107dc5cadb169a4d76b3ab | |
parent | 1329b15f47751b764ba3162674b2bb997c2ddb90 (diff) | |
parent | cd7b0ee296b0462961c63e51d99c9c323e2690df (diff) |
Merge "MIPS32: Fuse long and FP compare & condition in Optimizing."
-rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 1015 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips.h | 12 | ||||
-rw-r--r-- | compiler/optimizing/instruction_simplifier.cc | 4 | ||||
-rw-r--r-- | compiler/utils/assembler_test.h | 75 | ||||
-rw-r--r-- | compiler/utils/mips/assembler_mips.cc | 274 | ||||
-rw-r--r-- | compiler/utils/mips/assembler_mips.h | 170 | ||||
-rw-r--r-- | compiler/utils/mips/assembler_mips_test.cc | 321 | ||||
-rw-r--r-- | disassembler/disassembler_mips.cc | 40 |
8 files changed, 1462 insertions, 449 deletions
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index a23e5ef332..99a0982fe2 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -1956,11 +1956,8 @@ void InstructionCodeGeneratorMIPS::VisitClinitCheck(HClinitCheck* check) { void LocationsBuilderMIPS::VisitCompare(HCompare* compare) { Primitive::Type in_type = compare->InputAt(0)->GetType(); - LocationSummary::CallKind call_kind = Primitive::IsFloatingPointType(in_type) - ? LocationSummary::kCall - : LocationSummary::kNoCall; - - LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare, call_kind); + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); switch (in_type) { case Primitive::kPrimLong: @@ -1971,13 +1968,11 @@ void LocationsBuilderMIPS::VisitCompare(HCompare* compare) { break; case Primitive::kPrimFloat: - case Primitive::kPrimDouble: { - InvokeRuntimeCallingConvention calling_convention; - locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0))); - locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1))); - locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimInt)); + case Primitive::kPrimDouble: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); break; - } default: LOG(FATAL) << "Unexpected type for compare operation " << in_type; @@ -1986,7 +1981,10 @@ void LocationsBuilderMIPS::VisitCompare(HCompare* compare) { void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) { LocationSummary* locations = instruction->GetLocations(); + Register res = locations->Out().AsRegister<Register>(); Primitive::Type in_type = instruction->InputAt(0)->GetType(); + bool gt_bias = instruction->IsGtBias(); + bool isR6 = codegen_->GetInstructionSetFeatures().IsR6(); // 0 if: left == right // 1 if: left > right @@ -1994,7 +1992,6 @@ void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) { switch (in_type) { case Primitive::kPrimLong: { MipsLabel done; - Register res = locations->Out().AsRegister<Register>(); Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>(); Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>(); Register rhs_high = locations->InAt(1).AsRegisterPairHigh<Register>(); @@ -2011,45 +2008,82 @@ void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) { break; } - case Primitive::kPrimFloat: - case Primitive::kPrimDouble: { - int32_t entry_point_offset; - bool direct; - if (in_type == Primitive::kPrimFloat) { - if (instruction->IsGtBias()) { - entry_point_offset = QUICK_ENTRY_POINT(pCmpgFloat); - direct = IsDirectEntrypoint(kQuickCmpgFloat); + case Primitive::kPrimFloat: { + FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>(); + FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>(); + MipsLabel done; + if (isR6) { + __ CmpEqS(FTMP, lhs, rhs); + __ LoadConst32(res, 0); + __ Bc1nez(FTMP, &done); + if (gt_bias) { + __ CmpLtS(FTMP, lhs, rhs); + __ LoadConst32(res, -1); + __ Bc1nez(FTMP, &done); + __ LoadConst32(res, 1); } else { - entry_point_offset = QUICK_ENTRY_POINT(pCmplFloat); - direct = IsDirectEntrypoint(kQuickCmplFloat); + __ CmpLtS(FTMP, rhs, lhs); + __ LoadConst32(res, 1); + __ Bc1nez(FTMP, &done); + __ LoadConst32(res, -1); } } else { - if (instruction->IsGtBias()) { - entry_point_offset = QUICK_ENTRY_POINT(pCmpgDouble); - direct = IsDirectEntrypoint(kQuickCmpgDouble); + if (gt_bias) { + __ ColtS(0, lhs, rhs); + __ LoadConst32(res, -1); + __ Bc1t(0, &done); + __ CeqS(0, lhs, rhs); + __ LoadConst32(res, 1); + __ Movt(res, ZERO, 0); } else { - entry_point_offset = QUICK_ENTRY_POINT(pCmplDouble); - direct = IsDirectEntrypoint(kQuickCmplDouble); + __ ColtS(0, rhs, lhs); + __ LoadConst32(res, 1); + __ Bc1t(0, &done); + __ CeqS(0, lhs, rhs); + __ LoadConst32(res, -1); + __ Movt(res, ZERO, 0); } } - codegen_->InvokeRuntime(entry_point_offset, - instruction, - instruction->GetDexPc(), - nullptr, - direct); - if (in_type == Primitive::kPrimFloat) { - if (instruction->IsGtBias()) { - CheckEntrypointTypes<kQuickCmpgFloat, int32_t, float, float>(); + __ Bind(&done); + break; + } + case Primitive::kPrimDouble: { + FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>(); + FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>(); + MipsLabel done; + if (isR6) { + __ CmpEqD(FTMP, lhs, rhs); + __ LoadConst32(res, 0); + __ Bc1nez(FTMP, &done); + if (gt_bias) { + __ CmpLtD(FTMP, lhs, rhs); + __ LoadConst32(res, -1); + __ Bc1nez(FTMP, &done); + __ LoadConst32(res, 1); } else { - CheckEntrypointTypes<kQuickCmplFloat, int32_t, float, float>(); + __ CmpLtD(FTMP, rhs, lhs); + __ LoadConst32(res, 1); + __ Bc1nez(FTMP, &done); + __ LoadConst32(res, -1); } } else { - if (instruction->IsGtBias()) { - CheckEntrypointTypes<kQuickCmpgDouble, int32_t, double, double>(); + if (gt_bias) { + __ ColtD(0, lhs, rhs); + __ LoadConst32(res, -1); + __ Bc1t(0, &done); + __ CeqD(0, lhs, rhs); + __ LoadConst32(res, 1); + __ Movt(res, ZERO, 0); } else { - CheckEntrypointTypes<kQuickCmplDouble, int32_t, double, double>(); + __ ColtD(0, rhs, lhs); + __ LoadConst32(res, 1); + __ Bc1t(0, &done); + __ CeqD(0, lhs, rhs); + __ LoadConst32(res, -1); + __ Movt(res, ZERO, 0); } } + __ Bind(&done); break; } @@ -2060,8 +2094,19 @@ void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) { void LocationsBuilderMIPS::VisitCondition(HCondition* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); + switch (instruction->InputAt(0)->GetType()) { + default: + case Primitive::kPrimLong: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); + break; + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + break; + } if (instruction->NeedsMaterialization()) { locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); } @@ -2071,151 +2116,45 @@ void InstructionCodeGeneratorMIPS::VisitCondition(HCondition* instruction) { if (!instruction->NeedsMaterialization()) { return; } - // TODO: generalize to long - DCHECK_NE(instruction->InputAt(0)->GetType(), Primitive::kPrimLong); + Primitive::Type type = instruction->InputAt(0)->GetType(); LocationSummary* locations = instruction->GetLocations(); Register dst = locations->Out().AsRegister<Register>(); + MipsLabel true_label; - Register lhs = locations->InAt(0).AsRegister<Register>(); - Location rhs_location = locations->InAt(1); - - Register rhs_reg = ZERO; - int64_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>(); - } - - IfCondition if_cond = instruction->GetCondition(); + switch (type) { + default: + // Integer case. + GenerateIntCompare(instruction->GetCondition(), locations); + return; - switch (if_cond) { - case kCondEQ: - case kCondNE: - if (use_imm && IsUint<16>(rhs_imm)) { - __ Xori(dst, lhs, rhs_imm); - } else { - if (use_imm) { - rhs_reg = TMP; - __ LoadConst32(rhs_reg, rhs_imm); - } - __ Xor(dst, lhs, rhs_reg); - } - if (if_cond == kCondEQ) { - __ Sltiu(dst, dst, 1); - } else { - __ Sltu(dst, ZERO, dst); - } + case Primitive::kPrimLong: + // TODO: don't use branches. + GenerateLongCompareAndBranch(instruction->GetCondition(), locations, &true_label); break; - case kCondLT: - case kCondGE: - if (use_imm && IsInt<16>(rhs_imm)) { - __ Slti(dst, lhs, rhs_imm); - } else { - if (use_imm) { - rhs_reg = TMP; - __ LoadConst32(rhs_reg, rhs_imm); - } - __ Slt(dst, lhs, rhs_reg); - } - if (if_cond == kCondGE) { - // Simulate lhs >= rhs via !(lhs < rhs) since there's - // only the slt instruction but no sge. - __ Xori(dst, dst, 1); - } + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + // TODO: don't use branches. + GenerateFpCompareAndBranch(instruction->GetCondition(), + instruction->IsGtBias(), + type, + locations, + &true_label); break; + } - case kCondLE: - case kCondGT: - if (use_imm && IsInt<16>(rhs_imm + 1)) { - // Simulate lhs <= rhs via lhs < rhs + 1. - __ Slti(dst, lhs, rhs_imm + 1); - if (if_cond == kCondGT) { - // Simulate lhs > rhs via !(lhs <= rhs) since there's - // only the slti instruction but no sgti. - __ Xori(dst, dst, 1); - } - } else { - if (use_imm) { - rhs_reg = TMP; - __ LoadConst32(rhs_reg, rhs_imm); - } - __ Slt(dst, rhs_reg, lhs); - if (if_cond == kCondLE) { - // Simulate lhs <= rhs via !(rhs < lhs) since there's - // only the slt instruction but no sle. - __ Xori(dst, dst, 1); - } - } - break; + // Convert the branches into the result. + MipsLabel done; - case kCondB: - case kCondAE: - // Use sltiu instruction if rhs_imm is in range [0, 32767] or in - // [max_unsigned - 32767 = 0xffff8000, max_unsigned = 0xffffffff]. - if (use_imm && - (IsUint<15>(rhs_imm) || - IsUint<15>(rhs_imm - (MaxInt<uint64_t>(32) - MaxInt<uint64_t>(15))))) { - if (IsUint<15>(rhs_imm)) { - __ Sltiu(dst, lhs, rhs_imm); - } else { - // 16-bit value (in range [0x8000, 0xffff]) passed to sltiu is sign-extended - // and then used as unsigned integer (range [0xffff8000, 0xffffffff]). - __ Sltiu(dst, lhs, rhs_imm - (MaxInt<uint64_t>(32) - MaxInt<uint64_t>(16))); - } - } else { - if (use_imm) { - rhs_reg = TMP; - __ LoadConst32(rhs_reg, rhs_imm); - } - __ Sltu(dst, lhs, rhs_reg); - } - if (if_cond == kCondAE) { - // Simulate lhs >= rhs via !(lhs < rhs) since there's - // only the sltu instruction but no sgeu. - __ Xori(dst, dst, 1); - } - break; + // False case: result = 0. + __ LoadConst32(dst, 0); + __ B(&done); - case kCondBE: - case kCondA: - // Use sltiu instruction if rhs_imm is in range [0, 32766] or in - // [max_unsigned - 32767 - 1 = 0xffff7fff, max_unsigned - 1 = 0xfffffffe]. - // lhs <= rhs is simulated via lhs < rhs + 1. - if (use_imm && (rhs_imm != -1) && - (IsUint<15>(rhs_imm + 1) || - IsUint<15>(rhs_imm + 1 - (MaxInt<uint64_t>(32) - MaxInt<uint64_t>(15))))) { - if (IsUint<15>(rhs_imm + 1)) { - // Simulate lhs <= rhs via lhs < rhs + 1. - __ Sltiu(dst, lhs, rhs_imm + 1); - } else { - // 16-bit value (in range [0x8000, 0xffff]) passed to sltiu is sign-extended - // and then used as unsigned integer (range [0xffff8000, 0xffffffff] where rhs_imm - // is in range [0xffff7fff, 0xfffffffe] since lhs <= rhs is simulated via lhs < rhs + 1). - __ Sltiu(dst, lhs, rhs_imm + 1 - (MaxInt<uint64_t>(32) - MaxInt<uint64_t>(16))); - } - if (if_cond == kCondA) { - // Simulate lhs > rhs via !(lhs <= rhs) since there's - // only the sltiu instruction but no sgtiu. - __ Xori(dst, dst, 1); - } - } else { - if (use_imm) { - rhs_reg = TMP; - __ LoadConst32(rhs_reg, rhs_imm); - } - __ Sltu(dst, rhs_reg, lhs); - if (if_cond == kCondBE) { - // Simulate lhs <= rhs via !(rhs < lhs) since there's - // only the sltu instruction but no sleu. - __ Xori(dst, dst, 1); - } - } - break; - } + // True case: result = 1. + __ Bind(&true_label); + __ LoadConst32(dst, 1); + __ Bind(&done); } void InstructionCodeGeneratorMIPS::DivRemOneOrMinusOne(HBinaryOperation* instruction) { @@ -2574,6 +2513,627 @@ void InstructionCodeGeneratorMIPS::VisitTryBoundary(HTryBoundary* try_boundary) } } +void InstructionCodeGeneratorMIPS::GenerateIntCompare(IfCondition cond, + LocationSummary* locations) { + Register dst = locations->Out().AsRegister<Register>(); + Register lhs = locations->InAt(0).AsRegister<Register>(); + Location rhs_location = locations->InAt(1); + Register rhs_reg = ZERO; + int64_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>(); + } + + switch (cond) { + case kCondEQ: + case kCondNE: + if (use_imm && IsUint<16>(rhs_imm)) { + __ Xori(dst, lhs, rhs_imm); + } else { + if (use_imm) { + rhs_reg = TMP; + __ LoadConst32(rhs_reg, rhs_imm); + } + __ Xor(dst, lhs, rhs_reg); + } + if (cond == kCondEQ) { + __ Sltiu(dst, dst, 1); + } else { + __ Sltu(dst, ZERO, dst); + } + break; + + case kCondLT: + case kCondGE: + if (use_imm && IsInt<16>(rhs_imm)) { + __ Slti(dst, lhs, rhs_imm); + } else { + if (use_imm) { + rhs_reg = TMP; + __ LoadConst32(rhs_reg, rhs_imm); + } + __ Slt(dst, lhs, rhs_reg); + } + if (cond == kCondGE) { + // Simulate lhs >= rhs via !(lhs < rhs) since there's + // only the slt instruction but no sge. + __ Xori(dst, dst, 1); + } + break; + + case kCondLE: + case kCondGT: + if (use_imm && IsInt<16>(rhs_imm + 1)) { + // Simulate lhs <= rhs via lhs < rhs + 1. + __ Slti(dst, lhs, rhs_imm + 1); + if (cond == kCondGT) { + // Simulate lhs > rhs via !(lhs <= rhs) since there's + // only the slti instruction but no sgti. + __ Xori(dst, dst, 1); + } + } else { + if (use_imm) { + rhs_reg = TMP; + __ LoadConst32(rhs_reg, rhs_imm); + } + __ Slt(dst, rhs_reg, lhs); + if (cond == kCondLE) { + // Simulate lhs <= rhs via !(rhs < lhs) since there's + // only the slt instruction but no sle. + __ Xori(dst, dst, 1); + } + } + break; + + case kCondB: + case kCondAE: + if (use_imm && IsInt<16>(rhs_imm)) { + // Sltiu sign-extends its 16-bit immediate operand before + // the comparison and thus lets us compare directly with + // unsigned values in the ranges [0, 0x7fff] and + // [0xffff8000, 0xffffffff]. + __ Sltiu(dst, lhs, rhs_imm); + } else { + if (use_imm) { + rhs_reg = TMP; + __ LoadConst32(rhs_reg, rhs_imm); + } + __ Sltu(dst, lhs, rhs_reg); + } + if (cond == kCondAE) { + // Simulate lhs >= rhs via !(lhs < rhs) since there's + // only the sltu instruction but no sgeu. + __ Xori(dst, dst, 1); + } + break; + + case kCondBE: + case kCondA: + if (use_imm && (rhs_imm != -1) && IsInt<16>(rhs_imm + 1)) { + // Simulate lhs <= rhs via lhs < rhs + 1. + // Note that this only works if rhs + 1 does not overflow + // to 0, hence the check above. + // Sltiu sign-extends its 16-bit immediate operand before + // the comparison and thus lets us compare directly with + // unsigned values in the ranges [0, 0x7fff] and + // [0xffff8000, 0xffffffff]. + __ Sltiu(dst, lhs, rhs_imm + 1); + if (cond == kCondA) { + // Simulate lhs > rhs via !(lhs <= rhs) since there's + // only the sltiu instruction but no sgtiu. + __ Xori(dst, dst, 1); + } + } else { + if (use_imm) { + rhs_reg = TMP; + __ LoadConst32(rhs_reg, rhs_imm); + } + __ Sltu(dst, rhs_reg, lhs); + if (cond == kCondBE) { + // Simulate lhs <= rhs via !(rhs < lhs) since there's + // only the sltu instruction but no sleu. + __ Xori(dst, dst, 1); + } + } + break; + } +} + +void InstructionCodeGeneratorMIPS::GenerateIntCompareAndBranch(IfCondition cond, + LocationSummary* locations, + MipsLabel* label) { + 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 (use_imm && rhs_imm == 0) { + switch (cond) { + case kCondEQ: + case kCondBE: // <= 0 if zero + __ Beqz(lhs, label); + break; + case kCondNE: + case kCondA: // > 0 if non-zero + __ Bnez(lhs, label); + break; + case kCondLT: + __ Bltz(lhs, label); + break; + case kCondGE: + __ Bgez(lhs, label); + break; + case kCondLE: + __ Blez(lhs, label); + break; + case kCondGT: + __ Bgtz(lhs, label); + break; + case kCondB: // always false + break; + case kCondAE: // always true + __ B(label); + break; + } + } else { + if (use_imm) { + // TODO: more efficient comparison with 16-bit constants without loading them into TMP. + rhs_reg = TMP; + __ LoadConst32(rhs_reg, rhs_imm); + } + switch (cond) { + case kCondEQ: + __ Beq(lhs, rhs_reg, label); + break; + case kCondNE: + __ Bne(lhs, rhs_reg, label); + break; + case kCondLT: + __ Blt(lhs, rhs_reg, label); + break; + case kCondGE: + __ Bge(lhs, rhs_reg, label); + break; + case kCondLE: + __ Bge(rhs_reg, lhs, label); + break; + case kCondGT: + __ Blt(rhs_reg, lhs, label); + break; + case kCondB: + __ Bltu(lhs, rhs_reg, label); + break; + case kCondAE: + __ Bgeu(lhs, rhs_reg, label); + break; + case kCondBE: + __ Bgeu(rhs_reg, lhs, label); + break; + case kCondA: + __ Bltu(rhs_reg, lhs, label); + break; + } + } +} + +void InstructionCodeGeneratorMIPS::GenerateLongCompareAndBranch(IfCondition cond, + LocationSummary* locations, + MipsLabel* label) { + Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>(); + Location rhs_location = locations->InAt(1); + Register rhs_high = ZERO; + Register rhs_low = ZERO; + int64_t imm = 0; + uint32_t imm_high = 0; + uint32_t imm_low = 0; + bool use_imm = rhs_location.IsConstant(); + if (use_imm) { + imm = rhs_location.GetConstant()->AsLongConstant()->GetValue(); + imm_high = High32Bits(imm); + imm_low = Low32Bits(imm); + } else { + rhs_high = rhs_location.AsRegisterPairHigh<Register>(); + rhs_low = rhs_location.AsRegisterPairLow<Register>(); + } + + if (use_imm && imm == 0) { + switch (cond) { + case kCondEQ: + case kCondBE: // <= 0 if zero + __ Or(TMP, lhs_high, lhs_low); + __ Beqz(TMP, label); + break; + case kCondNE: + case kCondA: // > 0 if non-zero + __ Or(TMP, lhs_high, lhs_low); + __ Bnez(TMP, label); + break; + case kCondLT: + __ Bltz(lhs_high, label); + break; + case kCondGE: + __ Bgez(lhs_high, label); + break; + case kCondLE: + __ Or(TMP, lhs_high, lhs_low); + __ Sra(AT, lhs_high, 31); + __ Bgeu(AT, TMP, label); + break; + case kCondGT: + __ Or(TMP, lhs_high, lhs_low); + __ Sra(AT, lhs_high, 31); + __ Bltu(AT, TMP, label); + break; + case kCondB: // always false + break; + case kCondAE: // always true + __ B(label); + break; + } + } else if (use_imm) { + // TODO: more efficient comparison with constants without loading them into TMP/AT. + switch (cond) { + case kCondEQ: + __ LoadConst32(TMP, imm_high); + __ Xor(TMP, TMP, lhs_high); + __ LoadConst32(AT, imm_low); + __ Xor(AT, AT, lhs_low); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondNE: + __ LoadConst32(TMP, imm_high); + __ Xor(TMP, TMP, lhs_high); + __ LoadConst32(AT, imm_low); + __ Xor(AT, AT, lhs_low); + __ Or(TMP, TMP, AT); + __ Bnez(TMP, label); + break; + case kCondLT: + __ LoadConst32(TMP, imm_high); + __ Blt(lhs_high, TMP, label); + __ Slt(TMP, TMP, lhs_high); + __ LoadConst32(AT, imm_low); + __ Sltu(AT, lhs_low, AT); + __ Blt(TMP, AT, label); + break; + case kCondGE: + __ LoadConst32(TMP, imm_high); + __ Blt(TMP, lhs_high, label); + __ Slt(TMP, lhs_high, TMP); + __ LoadConst32(AT, imm_low); + __ Sltu(AT, lhs_low, AT); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondLE: + __ LoadConst32(TMP, imm_high); + __ Blt(lhs_high, TMP, label); + __ Slt(TMP, TMP, lhs_high); + __ LoadConst32(AT, imm_low); + __ Sltu(AT, AT, lhs_low); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondGT: + __ LoadConst32(TMP, imm_high); + __ Blt(TMP, lhs_high, label); + __ Slt(TMP, lhs_high, TMP); + __ LoadConst32(AT, imm_low); + __ Sltu(AT, AT, lhs_low); + __ Blt(TMP, AT, label); + break; + case kCondB: + __ LoadConst32(TMP, imm_high); + __ Bltu(lhs_high, TMP, label); + __ Sltu(TMP, TMP, lhs_high); + __ LoadConst32(AT, imm_low); + __ Sltu(AT, lhs_low, AT); + __ Blt(TMP, AT, label); + break; + case kCondAE: + __ LoadConst32(TMP, imm_high); + __ Bltu(TMP, lhs_high, label); + __ Sltu(TMP, lhs_high, TMP); + __ LoadConst32(AT, imm_low); + __ Sltu(AT, lhs_low, AT); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondBE: + __ LoadConst32(TMP, imm_high); + __ Bltu(lhs_high, TMP, label); + __ Sltu(TMP, TMP, lhs_high); + __ LoadConst32(AT, imm_low); + __ Sltu(AT, AT, lhs_low); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondA: + __ LoadConst32(TMP, imm_high); + __ Bltu(TMP, lhs_high, label); + __ Sltu(TMP, lhs_high, TMP); + __ LoadConst32(AT, imm_low); + __ Sltu(AT, AT, lhs_low); + __ Blt(TMP, AT, label); + break; + } + } else { + switch (cond) { + case kCondEQ: + __ Xor(TMP, lhs_high, rhs_high); + __ Xor(AT, lhs_low, rhs_low); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondNE: + __ Xor(TMP, lhs_high, rhs_high); + __ Xor(AT, lhs_low, rhs_low); + __ Or(TMP, TMP, AT); + __ Bnez(TMP, label); + break; + case kCondLT: + __ Blt(lhs_high, rhs_high, label); + __ Slt(TMP, rhs_high, lhs_high); + __ Sltu(AT, lhs_low, rhs_low); + __ Blt(TMP, AT, label); + break; + case kCondGE: + __ Blt(rhs_high, lhs_high, label); + __ Slt(TMP, lhs_high, rhs_high); + __ Sltu(AT, lhs_low, rhs_low); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondLE: + __ Blt(lhs_high, rhs_high, label); + __ Slt(TMP, rhs_high, lhs_high); + __ Sltu(AT, rhs_low, lhs_low); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondGT: + __ Blt(rhs_high, lhs_high, label); + __ Slt(TMP, lhs_high, rhs_high); + __ Sltu(AT, rhs_low, lhs_low); + __ Blt(TMP, AT, label); + break; + case kCondB: + __ Bltu(lhs_high, rhs_high, label); + __ Sltu(TMP, rhs_high, lhs_high); + __ Sltu(AT, lhs_low, rhs_low); + __ Blt(TMP, AT, label); + break; + case kCondAE: + __ Bltu(rhs_high, lhs_high, label); + __ Sltu(TMP, lhs_high, rhs_high); + __ Sltu(AT, lhs_low, rhs_low); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondBE: + __ Bltu(lhs_high, rhs_high, label); + __ Sltu(TMP, rhs_high, lhs_high); + __ Sltu(AT, rhs_low, lhs_low); + __ Or(TMP, TMP, AT); + __ Beqz(TMP, label); + break; + case kCondA: + __ Bltu(rhs_high, lhs_high, label); + __ Sltu(TMP, lhs_high, rhs_high); + __ Sltu(AT, rhs_low, lhs_low); + __ Blt(TMP, AT, label); + break; + } + } +} + +void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond, + bool gt_bias, + Primitive::Type type, + LocationSummary* locations, + MipsLabel* label) { + FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>(); + FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>(); + bool isR6 = codegen_->GetInstructionSetFeatures().IsR6(); + if (type == Primitive::kPrimFloat) { + if (isR6) { + switch (cond) { + case kCondEQ: + __ CmpEqS(FTMP, lhs, rhs); + __ Bc1nez(FTMP, label); + break; + case kCondNE: + __ CmpEqS(FTMP, lhs, rhs); + __ Bc1eqz(FTMP, label); + break; + case kCondLT: + if (gt_bias) { + __ CmpLtS(FTMP, lhs, rhs); + } else { + __ CmpUltS(FTMP, lhs, rhs); + } + __ Bc1nez(FTMP, label); + break; + case kCondLE: + if (gt_bias) { + __ CmpLeS(FTMP, lhs, rhs); + } else { + __ CmpUleS(FTMP, lhs, rhs); + } + __ Bc1nez(FTMP, label); + break; + case kCondGT: + if (gt_bias) { + __ CmpUltS(FTMP, rhs, lhs); + } else { + __ CmpLtS(FTMP, rhs, lhs); + } + __ Bc1nez(FTMP, label); + break; + case kCondGE: + if (gt_bias) { + __ CmpUleS(FTMP, rhs, lhs); + } else { + __ CmpLeS(FTMP, rhs, lhs); + } + __ Bc1nez(FTMP, label); + break; + default: + LOG(FATAL) << "Unexpected non-floating-point condition"; + } + } else { + switch (cond) { + case kCondEQ: + __ CeqS(0, lhs, rhs); + __ Bc1t(0, label); + break; + case kCondNE: + __ CeqS(0, lhs, rhs); + __ Bc1f(0, label); + break; + case kCondLT: + if (gt_bias) { + __ ColtS(0, lhs, rhs); + } else { + __ CultS(0, lhs, rhs); + } + __ Bc1t(0, label); + break; + case kCondLE: + if (gt_bias) { + __ ColeS(0, lhs, rhs); + } else { + __ CuleS(0, lhs, rhs); + } + __ Bc1t(0, label); + break; + case kCondGT: + if (gt_bias) { + __ CultS(0, rhs, lhs); + } else { + __ ColtS(0, rhs, lhs); + } + __ Bc1t(0, label); + break; + case kCondGE: + if (gt_bias) { + __ CuleS(0, rhs, lhs); + } else { + __ ColeS(0, rhs, lhs); + } + __ Bc1t(0, label); + break; + default: + LOG(FATAL) << "Unexpected non-floating-point condition"; + } + } + } else { + DCHECK_EQ(type, Primitive::kPrimDouble); + if (isR6) { + switch (cond) { + case kCondEQ: + __ CmpEqD(FTMP, lhs, rhs); + __ Bc1nez(FTMP, label); + break; + case kCondNE: + __ CmpEqD(FTMP, lhs, rhs); + __ Bc1eqz(FTMP, label); + break; + case kCondLT: + if (gt_bias) { + __ CmpLtD(FTMP, lhs, rhs); + } else { + __ CmpUltD(FTMP, lhs, rhs); + } + __ Bc1nez(FTMP, label); + break; + case kCondLE: + if (gt_bias) { + __ CmpLeD(FTMP, lhs, rhs); + } else { + __ CmpUleD(FTMP, lhs, rhs); + } + __ Bc1nez(FTMP, label); + break; + case kCondGT: + if (gt_bias) { + __ CmpUltD(FTMP, rhs, lhs); + } else { + __ CmpLtD(FTMP, rhs, lhs); + } + __ Bc1nez(FTMP, label); + break; + case kCondGE: + if (gt_bias) { + __ CmpUleD(FTMP, rhs, lhs); + } else { + __ CmpLeD(FTMP, rhs, lhs); + } + __ Bc1nez(FTMP, label); + break; + default: + LOG(FATAL) << "Unexpected non-floating-point condition"; + } + } else { + switch (cond) { + case kCondEQ: + __ CeqD(0, lhs, rhs); + __ Bc1t(0, label); + break; + case kCondNE: + __ CeqD(0, lhs, rhs); + __ Bc1f(0, label); + break; + case kCondLT: + if (gt_bias) { + __ ColtD(0, lhs, rhs); + } else { + __ CultD(0, lhs, rhs); + } + __ Bc1t(0, label); + break; + case kCondLE: + if (gt_bias) { + __ ColeD(0, lhs, rhs); + } else { + __ CuleD(0, lhs, rhs); + } + __ Bc1t(0, label); + break; + case kCondGT: + if (gt_bias) { + __ CultD(0, rhs, lhs); + } else { + __ ColtD(0, rhs, lhs); + } + __ Bc1t(0, label); + break; + case kCondGE: + if (gt_bias) { + __ CuleD(0, rhs, lhs); + } else { + __ ColeD(0, rhs, lhs); + } + __ Bc1t(0, label); + break; + default: + LOG(FATAL) << "Unexpected non-floating-point condition"; + } + } + } +} + void InstructionCodeGeneratorMIPS::GenerateTestAndBranch(HInstruction* instruction, size_t condition_input_index, MipsLabel* true_target, @@ -2610,7 +3170,7 @@ void InstructionCodeGeneratorMIPS::GenerateTestAndBranch(HInstruction* instructi // The condition instruction has been materialized, compare the output to 0. Location cond_val = instruction->GetLocations()->InAt(condition_input_index); DCHECK(cond_val.IsRegister()); - if (true_target == nullptr) { + if (true_target == nullptr) { __ Beqz(cond_val.AsRegister<Register>(), false_target); } else { __ Bnez(cond_val.AsRegister<Register>(), true_target); @@ -2619,98 +3179,27 @@ void InstructionCodeGeneratorMIPS::GenerateTestAndBranch(HInstruction* instructi // The condition instruction has not been materialized, use its inputs as // the comparison and its condition as the branch condition. HCondition* condition = cond->AsCondition(); + Primitive::Type type = condition->InputAt(0)->GetType(); + LocationSummary* locations = cond->GetLocations(); + IfCondition if_cond = condition->GetCondition(); + MipsLabel* branch_target = true_target; - Register lhs = condition->GetLocations()->InAt(0).AsRegister<Register>(); - Location rhs_location = condition->GetLocations()->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>(); - } - - IfCondition if_cond; - MipsLabel* non_fallthrough_target; if (true_target == nullptr) { if_cond = condition->GetOppositeCondition(); - non_fallthrough_target = false_target; - } else { - if_cond = condition->GetCondition(); - non_fallthrough_target = true_target; + branch_target = false_target; } - if (use_imm && rhs_imm == 0) { - switch (if_cond) { - case kCondEQ: - __ Beqz(lhs, non_fallthrough_target); - break; - case kCondNE: - __ Bnez(lhs, non_fallthrough_target); - break; - case kCondLT: - __ Bltz(lhs, non_fallthrough_target); - break; - case kCondGE: - __ Bgez(lhs, non_fallthrough_target); - break; - case kCondLE: - __ Blez(lhs, non_fallthrough_target); - break; - case kCondGT: - __ Bgtz(lhs, non_fallthrough_target); - break; - case kCondB: - break; // always false - case kCondBE: - __ Beqz(lhs, non_fallthrough_target); // <= 0 if zero - break; - case kCondA: - __ Bnez(lhs, non_fallthrough_target); // > 0 if non-zero - break; - case kCondAE: - __ B(non_fallthrough_target); // always true - break; - } - } else { - if (use_imm) { - // TODO: more efficient comparison with 16-bit constants without loading them into TMP. - rhs_reg = TMP; - __ LoadConst32(rhs_reg, rhs_imm); - } - switch (if_cond) { - case kCondEQ: - __ Beq(lhs, rhs_reg, non_fallthrough_target); - break; - case kCondNE: - __ Bne(lhs, rhs_reg, non_fallthrough_target); - break; - case kCondLT: - __ Blt(lhs, rhs_reg, non_fallthrough_target); - break; - case kCondGE: - __ Bge(lhs, rhs_reg, non_fallthrough_target); - break; - case kCondLE: - __ Bge(rhs_reg, lhs, non_fallthrough_target); - break; - case kCondGT: - __ Blt(rhs_reg, lhs, non_fallthrough_target); - break; - case kCondB: - __ Bltu(lhs, rhs_reg, non_fallthrough_target); - break; - case kCondAE: - __ Bgeu(lhs, rhs_reg, non_fallthrough_target); - break; - case kCondBE: - __ Bgeu(rhs_reg, lhs, non_fallthrough_target); - break; - case kCondA: - __ Bltu(rhs_reg, lhs, non_fallthrough_target); - break; - } + switch (type) { + default: + GenerateIntCompareAndBranch(if_cond, locations, branch_target); + break; + case Primitive::kPrimLong: + GenerateLongCompareAndBranch(if_cond, locations, branch_target); + break; + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: + GenerateFpCompareAndBranch(if_cond, condition->IsGtBias(), type, locations, branch_target); + break; } } diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index caf3174455..1ee6bdef8e 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -225,6 +225,18 @@ class InstructionCodeGeneratorMIPS : public HGraphVisitor { void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc); void GenerateImplicitNullCheck(HNullCheck* instruction); void GenerateExplicitNullCheck(HNullCheck* instruction); + void GenerateIntCompare(IfCondition cond, LocationSummary* locations); + void GenerateIntCompareAndBranch(IfCondition cond, + LocationSummary* locations, + MipsLabel* label); + void GenerateLongCompareAndBranch(IfCondition cond, + LocationSummary* locations, + MipsLabel* label); + void GenerateFpCompareAndBranch(IfCondition cond, + bool gt_bias, + Primitive::Type type, + LocationSummary* locations, + MipsLabel* label); void GenerateTestAndBranch(HInstruction* instruction, size_t condition_input_index, MipsLabel* true_target, diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index e1b13c5087..67097deaeb 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -778,9 +778,9 @@ void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) { // Try to fold an HCompare into this HCondition. // This simplification is currently supported on x86, x86_64, ARM and ARM64. - // TODO: Implement it for MIPS and MIPS64. + // TODO: Implement it for MIPS64. InstructionSet instruction_set = GetGraph()->GetInstructionSet(); - if (instruction_set == kMips || instruction_set == kMips64) { + if (instruction_set == kMips64) { return; } diff --git a/compiler/utils/assembler_test.h b/compiler/utils/assembler_test.h index 9457da1c36..2579ddb52e 100644 --- a/compiler/utils/assembler_test.h +++ b/compiler/utils/assembler_test.h @@ -147,7 +147,7 @@ class AssemblerTest : public testing::Test { std::string (AssemblerTest::*GetName2)(const Reg2&), std::string fmt) { std::string str; - std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), imm_bits > 0); + std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); for (auto reg1 : reg1_registers) { for (auto reg2 : reg2_registers) { @@ -188,14 +188,66 @@ class AssemblerTest : public testing::Test { return str; } - template <typename RegType, typename ImmType> - std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType), + template <typename ImmType, typename Reg1, typename Reg2> + std::string RepeatTemplatedImmBitsRegisters(void (Ass::*f)(ImmType, Reg1, Reg2), + const std::vector<Reg1*> reg1_registers, + const std::vector<Reg2*> reg2_registers, + std::string (AssemblerTest::*GetName1)(const Reg1&), + std::string (AssemblerTest::*GetName2)(const Reg2&), int imm_bits, - const std::vector<Reg*> registers, - std::string (AssemblerTest::*GetName)(const RegType&), std::string fmt) { + std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); + + WarnOnCombinations(reg1_registers.size() * reg2_registers.size() * imms.size()); + std::string str; - std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), imm_bits > 0); + for (auto reg1 : reg1_registers) { + for (auto reg2 : reg2_registers) { + for (int64_t imm : imms) { + ImmType new_imm = CreateImmediate(imm); + (assembler_.get()->*f)(new_imm, *reg1, *reg2); + std::string base = fmt; + + std::string reg1_string = (this->*GetName1)(*reg1); + size_t reg1_index; + while ((reg1_index = base.find(REG1_TOKEN)) != std::string::npos) { + base.replace(reg1_index, ConstexprStrLen(REG1_TOKEN), reg1_string); + } + + std::string reg2_string = (this->*GetName2)(*reg2); + size_t reg2_index; + while ((reg2_index = base.find(REG2_TOKEN)) != std::string::npos) { + base.replace(reg2_index, ConstexprStrLen(REG2_TOKEN), reg2_string); + } + + size_t imm_index = base.find(IMM_TOKEN); + if (imm_index != std::string::npos) { + std::ostringstream sreg; + sreg << imm; + std::string imm_string = sreg.str(); + base.replace(imm_index, ConstexprStrLen(IMM_TOKEN), imm_string); + } + + if (str.size() > 0) { + str += "\n"; + } + str += base; + } + } + } + // Add a newline at the end. + str += "\n"; + return str; + } + + template <typename RegType, typename ImmType> + std::string RepeatTemplatedRegisterImmBits(void (Ass::*f)(RegType, ImmType), + int imm_bits, + const std::vector<Reg*> registers, + std::string (AssemblerTest::*GetName)(const RegType&), + std::string fmt) { + std::string str; + std::vector<int64_t> imms = CreateImmediateValuesBits(abs(imm_bits), (imm_bits > 0)); for (auto reg : registers) { for (int64_t imm : imms) { @@ -291,6 +343,17 @@ class AssemblerTest : public testing::Test { fmt); } + template <typename ImmType> + std::string RepeatIbFF(void (Ass::*f)(ImmType, FPReg, FPReg), int imm_bits, std::string fmt) { + return RepeatTemplatedImmBitsRegisters<ImmType, FPReg, FPReg>(f, + GetFPRegisters(), + GetFPRegisters(), + &AssemblerTest::GetFPRegName, + &AssemblerTest::GetFPRegName, + imm_bits, + fmt); + } + std::string RepeatFR(void (Ass::*f)(FPReg, Reg), std::string fmt) { return RepeatTemplatedRegisters<FPReg, Reg>(f, GetFPRegisters(), diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index 733ad2cc38..afca8adcbb 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -503,6 +503,18 @@ void MipsAssembler::Bgtz(Register rt, uint16_t imm16) { EmitI(0x7, rt, static_cast<Register>(0), imm16); } +void MipsAssembler::Bc1f(int cc, uint16_t imm16) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>(cc << 2), imm16); +} + +void MipsAssembler::Bc1t(int cc, uint16_t imm16) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitI(0x11, static_cast<Register>(0x8), static_cast<Register>((cc << 2) | 1), imm16); +} + void MipsAssembler::J(uint32_t addr26) { EmitI26(0x2, addr26); } @@ -637,7 +649,17 @@ void MipsAssembler::Bnezc(Register rs, uint32_t imm21) { EmitI21(0x3E, rs, imm21); } -void MipsAssembler::EmitBcond(BranchCondition cond, Register rs, Register rt, uint16_t imm16) { +void MipsAssembler::Bc1eqz(FRegister ft, uint16_t imm16) { + CHECK(IsR6()); + EmitFI(0x11, 0x9, ft, imm16); +} + +void MipsAssembler::Bc1nez(FRegister ft, uint16_t imm16) { + CHECK(IsR6()); + EmitFI(0x11, 0xD, ft, imm16); +} + +void MipsAssembler::EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16) { switch (cond) { case kCondLTZ: CHECK_EQ(rt, ZERO); @@ -669,6 +691,14 @@ void MipsAssembler::EmitBcond(BranchCondition cond, Register rs, Register rt, ui CHECK_EQ(rt, ZERO); Bnez(rs, imm16); break; + case kCondF: + CHECK_EQ(rt, ZERO); + Bc1f(static_cast<int>(rs), imm16); + break; + case kCondT: + CHECK_EQ(rt, ZERO); + Bc1t(static_cast<int>(rs), imm16); + break; case kCondLT: case kCondGE: case kCondLE: @@ -683,7 +713,7 @@ void MipsAssembler::EmitBcond(BranchCondition cond, Register rs, Register rt, ui } } -void MipsAssembler::EmitBcondc(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) { +void MipsAssembler::EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21) { switch (cond) { case kCondLT: Bltc(rs, rt, imm16_21); @@ -733,6 +763,14 @@ void MipsAssembler::EmitBcondc(BranchCondition cond, Register rs, Register rt, u case kCondGEU: Bgeuc(rs, rt, imm16_21); break; + case kCondF: + CHECK_EQ(rt, ZERO); + Bc1eqz(static_cast<FRegister>(rs), imm16_21); + break; + case kCondT: + CHECK_EQ(rt, ZERO); + Bc1nez(static_cast<FRegister>(rs), imm16_21); + break; case kUncond: LOG(FATAL) << "Unexpected branch condition " << cond; UNREACHABLE(); @@ -787,6 +825,202 @@ void MipsAssembler::NegD(FRegister fd, FRegister fs) { EmitFR(0x11, 0x11, static_cast<FRegister>(0), fs, fd, 0x7); } +void MipsAssembler::CunS(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x31); +} + +void MipsAssembler::CeqS(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x32); +} + +void MipsAssembler::CueqS(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x33); +} + +void MipsAssembler::ColtS(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x34); +} + +void MipsAssembler::CultS(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x35); +} + +void MipsAssembler::ColeS(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x36); +} + +void MipsAssembler::CuleS(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x10, ft, fs, static_cast<FRegister>(cc << 2), 0x37); +} + +void MipsAssembler::CunD(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x31); +} + +void MipsAssembler::CeqD(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x32); +} + +void MipsAssembler::CueqD(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x33); +} + +void MipsAssembler::ColtD(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x34); +} + +void MipsAssembler::CultD(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x35); +} + +void MipsAssembler::ColeD(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x36); +} + +void MipsAssembler::CuleD(int cc, FRegister fs, FRegister ft) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitFR(0x11, 0x11, ft, fs, static_cast<FRegister>(cc << 2), 0x37); +} + +void MipsAssembler::CmpUnS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x01); +} + +void MipsAssembler::CmpEqS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x02); +} + +void MipsAssembler::CmpUeqS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x03); +} + +void MipsAssembler::CmpLtS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x04); +} + +void MipsAssembler::CmpUltS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x05); +} + +void MipsAssembler::CmpLeS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x06); +} + +void MipsAssembler::CmpUleS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x07); +} + +void MipsAssembler::CmpOrS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x11); +} + +void MipsAssembler::CmpUneS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x12); +} + +void MipsAssembler::CmpNeS(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x14, ft, fs, fd, 0x13); +} + +void MipsAssembler::CmpUnD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x01); +} + +void MipsAssembler::CmpEqD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x02); +} + +void MipsAssembler::CmpUeqD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x03); +} + +void MipsAssembler::CmpLtD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x04); +} + +void MipsAssembler::CmpUltD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x05); +} + +void MipsAssembler::CmpLeD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x06); +} + +void MipsAssembler::CmpUleD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x07); +} + +void MipsAssembler::CmpOrD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x11); +} + +void MipsAssembler::CmpUneD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x12); +} + +void MipsAssembler::CmpNeD(FRegister fd, FRegister fs, FRegister ft) { + CHECK(IsR6()); + EmitFR(0x11, 0x15, ft, fs, fd, 0x13); +} + +void MipsAssembler::Movf(Register rd, Register rs, int cc) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitR(0, rs, static_cast<Register>(cc << 2), rd, 0, 0x01); +} + +void MipsAssembler::Movt(Register rd, Register rs, int cc) { + CHECK(!IsR6()); + CHECK(IsUint<3>(cc)) << cc; + EmitR(0, rs, static_cast<Register>((cc << 2) | 1), rd, 0, 0x01); +} + void MipsAssembler::Cvtsw(FRegister fd, FRegister fs) { EmitFR(0x11, 0x14, static_cast<FRegister>(0), fs, fd, 0x20); } @@ -1058,6 +1292,10 @@ MipsAssembler::Branch::Branch(bool is_r6, CHECK_NE(lhs_reg, ZERO); CHECK_EQ(rhs_reg, ZERO); break; + case kCondF: + case kCondT: + CHECK_EQ(rhs_reg, ZERO); + break; case kUncond: UNREACHABLE(); } @@ -1112,6 +1350,10 @@ MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition( return kCondGEU; case kCondGEU: return kCondLTU; + case kCondF: + return kCondT; + case kCondT: + return kCondF; case kUncond: LOG(FATAL) << "Unexpected branch condition " << cond; } @@ -1514,7 +1756,7 @@ void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) { break; case Branch::kCondBranch: CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - EmitBcond(condition, lhs, rhs, offset); + EmitBcondR2(condition, lhs, rhs, offset); Nop(); // TODO: improve by filling the delay slot. break; case Branch::kCall: @@ -1561,7 +1803,7 @@ void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) { // Note: the opposite condition branch encodes 8 as the distance, which is equal to the // number of instructions skipped: // (PUSH(IncreaseFrameSize(ADDIU) + SW) + NAL + LUI + ORI + ADDU + LW + JR). - EmitBcond(Branch::OppositeCondition(condition), lhs, rhs, 8); + EmitBcondR2(Branch::OppositeCondition(condition), lhs, rhs, 8); Push(RA); Nal(); CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); @@ -1589,8 +1831,8 @@ void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) { break; case Branch::kR6CondBranch: CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); - EmitBcondc(condition, lhs, rhs, offset); - Nop(); // TODO: improve by filling the forbidden slot. + EmitBcondR6(condition, lhs, rhs, offset); + Nop(); // TODO: improve by filling the forbidden/delay slot. break; case Branch::kR6Call: CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); @@ -1606,7 +1848,7 @@ void MipsAssembler::EmitBranch(MipsAssembler::Branch* branch) { Jic(AT, Low16Bits(offset)); break; case Branch::kR6LongCondBranch: - EmitBcondc(Branch::OppositeCondition(condition), lhs, rhs, 2); + EmitBcondR6(Branch::OppositeCondition(condition), lhs, rhs, 2); offset += (offset & 0x8000) << 1; // Account for sign extension in jic. CHECK_EQ(overwrite_location_, branch->GetOffsetLocation()); Auipc(AT, High16Bits(offset)); @@ -1708,6 +1950,24 @@ void MipsAssembler::Bgeu(Register rs, Register rt, MipsLabel* label) { } } +void MipsAssembler::Bc1f(int cc, MipsLabel* label) { + CHECK(IsUint<3>(cc)) << cc; + Bcond(label, kCondF, static_cast<Register>(cc), ZERO); +} + +void MipsAssembler::Bc1t(int cc, MipsLabel* label) { + CHECK(IsUint<3>(cc)) << cc; + Bcond(label, kCondT, static_cast<Register>(cc), ZERO); +} + +void MipsAssembler::Bc1eqz(FRegister ft, MipsLabel* label) { + Bcond(label, kCondF, static_cast<Register>(ft), ZERO); +} + +void MipsAssembler::Bc1nez(FRegister ft, MipsLabel* label) { + Bcond(label, kCondT, static_cast<Register>(ft), ZERO); +} + void MipsAssembler::LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset) { // IsInt<16> must be passed a signed value. diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index 62366f6a8b..f569aa858c 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -72,8 +72,8 @@ class MipsExceptionSlowPath { : scratch_(scratch), stack_adjust_(stack_adjust) {} MipsExceptionSlowPath(MipsExceptionSlowPath&& src) - : scratch_(std::move(src.scratch_)), - stack_adjust_(std::move(src.stack_adjust_)), + : scratch_(src.scratch_), + stack_adjust_(src.stack_adjust_), exception_entry_(std::move(src.exception_entry_)) {} private: @@ -185,6 +185,8 @@ class MipsAssembler FINAL : public Assembler { void Bgez(Register rt, uint16_t imm16); void Blez(Register rt, uint16_t imm16); void Bgtz(Register rt, uint16_t imm16); + void Bc1f(int cc, uint16_t imm16); // R2 + void Bc1t(int cc, uint16_t imm16); // R2 void J(uint32_t addr26); void Jal(uint32_t addr26); void Jalr(Register rd, Register rs); @@ -208,6 +210,8 @@ class MipsAssembler FINAL : public Assembler { void Bnec(Register rs, Register rt, uint16_t imm16); // R6 void Beqzc(Register rs, uint32_t imm21); // R6 void Bnezc(Register rs, uint32_t imm21); // R6 + void Bc1eqz(FRegister ft, uint16_t imm16); // R6 + void Bc1nez(FRegister ft, uint16_t imm16); // R6 void AddS(FRegister fd, FRegister fs, FRegister ft); void SubS(FRegister fd, FRegister fs, FRegister ft); @@ -222,6 +226,43 @@ class MipsAssembler FINAL : public Assembler { void NegS(FRegister fd, FRegister fs); void NegD(FRegister fd, FRegister fs); + void CunS(int cc, FRegister fs, FRegister ft); // R2 + void CeqS(int cc, FRegister fs, FRegister ft); // R2 + void CueqS(int cc, FRegister fs, FRegister ft); // R2 + void ColtS(int cc, FRegister fs, FRegister ft); // R2 + void CultS(int cc, FRegister fs, FRegister ft); // R2 + void ColeS(int cc, FRegister fs, FRegister ft); // R2 + void CuleS(int cc, FRegister fs, FRegister ft); // R2 + void CunD(int cc, FRegister fs, FRegister ft); // R2 + void CeqD(int cc, FRegister fs, FRegister ft); // R2 + void CueqD(int cc, FRegister fs, FRegister ft); // R2 + void ColtD(int cc, FRegister fs, FRegister ft); // R2 + void CultD(int cc, FRegister fs, FRegister ft); // R2 + void ColeD(int cc, FRegister fs, FRegister ft); // R2 + void CuleD(int cc, FRegister fs, FRegister ft); // R2 + void CmpUnS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpEqS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpUeqS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpLtS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpUltS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpLeS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpUleS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpOrS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpUneS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpNeS(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpUnD(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpEqD(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpUeqD(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpLtD(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpUltD(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpLeD(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpUleD(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpOrD(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpUneD(FRegister fd, FRegister fs, FRegister ft); // R6 + void CmpNeD(FRegister fd, FRegister fs, FRegister ft); // R6 + void Movf(Register rd, Register rs, int cc); // R2 + void Movt(Register rd, Register rs, int cc); // R2 + void Cvtsw(FRegister fd, FRegister fs); void Cvtdw(FRegister fd, FRegister fs); void Cvtsd(FRegister fd, FRegister fs); @@ -267,6 +308,10 @@ class MipsAssembler FINAL : public Assembler { void Bge(Register rs, Register rt, MipsLabel* label); void Bltu(Register rs, Register rt, MipsLabel* label); void Bgeu(Register rs, Register rt, MipsLabel* label); + void Bc1f(int cc, MipsLabel* label); // R2 + void Bc1t(int cc, MipsLabel* label); // R2 + void Bc1eqz(FRegister ft, MipsLabel* label); // R6 + void Bc1nez(FRegister ft, MipsLabel* label); // R6 void EmitLoad(ManagedRegister m_dst, Register src_register, int32_t src_offset, size_t size); void LoadFromOffset(LoadOperandType type, Register reg, Register base, int32_t offset); @@ -296,7 +341,8 @@ class MipsAssembler FINAL : public Assembler { // // Emit code that will create an activation on the stack. - void BuildFrame(size_t frame_size, ManagedRegister method_reg, + void BuildFrame(size_t frame_size, + ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, const ManagedRegisterEntrySpills& entry_spills) OVERRIDE; @@ -314,58 +360,85 @@ class MipsAssembler FINAL : public Assembler { void StoreImmediateToFrame(FrameOffset dest, uint32_t imm, ManagedRegister mscratch) OVERRIDE; - void StoreImmediateToThread32(ThreadOffset<4> dest, uint32_t imm, ManagedRegister mscratch) - OVERRIDE; + void StoreImmediateToThread32(ThreadOffset<kMipsWordSize> dest, + uint32_t imm, + ManagedRegister mscratch) OVERRIDE; - void StoreStackOffsetToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, + void StoreStackOffsetToThread32(ThreadOffset<kMipsWordSize> thr_offs, + FrameOffset fr_offs, ManagedRegister mscratch) OVERRIDE; - void StoreStackPointerToThread32(ThreadOffset<4> thr_offs) OVERRIDE; + void StoreStackPointerToThread32(ThreadOffset<kMipsWordSize> thr_offs) OVERRIDE; - void StoreSpanning(FrameOffset dest, ManagedRegister msrc, FrameOffset in_off, + void StoreSpanning(FrameOffset dest, + ManagedRegister msrc, + FrameOffset in_off, ManagedRegister mscratch) OVERRIDE; // Load routines. void Load(ManagedRegister mdest, FrameOffset src, size_t size) OVERRIDE; - void LoadFromThread32(ManagedRegister mdest, ThreadOffset<4> src, size_t size) OVERRIDE; + void LoadFromThread32(ManagedRegister mdest, + ThreadOffset<kMipsWordSize> src, + size_t size) OVERRIDE; void LoadRef(ManagedRegister dest, FrameOffset src) OVERRIDE; - void LoadRef(ManagedRegister mdest, ManagedRegister base, MemberOffset offs, + void LoadRef(ManagedRegister mdest, + ManagedRegister base, + MemberOffset offs, bool unpoison_reference) OVERRIDE; void LoadRawPtr(ManagedRegister mdest, ManagedRegister base, Offset offs) OVERRIDE; - void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset<4> offs) OVERRIDE; + void LoadRawPtrFromThread32(ManagedRegister mdest, ThreadOffset<kMipsWordSize> offs) OVERRIDE; // Copying routines. void Move(ManagedRegister mdest, ManagedRegister msrc, size_t size) OVERRIDE; - void CopyRawPtrFromThread32(FrameOffset fr_offs, ThreadOffset<4> thr_offs, + void CopyRawPtrFromThread32(FrameOffset fr_offs, + ThreadOffset<kMipsWordSize> thr_offs, ManagedRegister mscratch) OVERRIDE; - void CopyRawPtrToThread32(ThreadOffset<4> thr_offs, FrameOffset fr_offs, + void CopyRawPtrToThread32(ThreadOffset<kMipsWordSize> thr_offs, + FrameOffset fr_offs, ManagedRegister mscratch) OVERRIDE; void CopyRef(FrameOffset dest, FrameOffset src, ManagedRegister mscratch) OVERRIDE; void Copy(FrameOffset dest, FrameOffset src, ManagedRegister mscratch, size_t size) OVERRIDE; - void Copy(FrameOffset dest, ManagedRegister src_base, Offset src_offset, ManagedRegister mscratch, + void Copy(FrameOffset dest, + ManagedRegister src_base, + Offset src_offset, + ManagedRegister mscratch, size_t size) OVERRIDE; - void Copy(ManagedRegister dest_base, Offset dest_offset, FrameOffset src, - ManagedRegister mscratch, size_t size) OVERRIDE; + void Copy(ManagedRegister dest_base, + Offset dest_offset, + FrameOffset src, + ManagedRegister mscratch, + size_t size) OVERRIDE; - void Copy(FrameOffset dest, FrameOffset src_base, Offset src_offset, ManagedRegister mscratch, + void Copy(FrameOffset dest, + FrameOffset src_base, + Offset src_offset, + ManagedRegister mscratch, size_t size) OVERRIDE; - void Copy(ManagedRegister dest, Offset dest_offset, ManagedRegister src, Offset src_offset, - ManagedRegister mscratch, size_t size) OVERRIDE; + void Copy(ManagedRegister dest, + Offset dest_offset, + ManagedRegister src, + Offset src_offset, + ManagedRegister mscratch, + size_t size) OVERRIDE; - void Copy(FrameOffset dest, Offset dest_offset, FrameOffset src, Offset src_offset, - ManagedRegister mscratch, size_t size) OVERRIDE; + void Copy(FrameOffset dest, + Offset dest_offset, + FrameOffset src, + Offset src_offset, + ManagedRegister mscratch, + size_t size) OVERRIDE; void MemoryBarrier(ManagedRegister) OVERRIDE; @@ -383,13 +456,17 @@ class MipsAssembler FINAL : public Assembler { // value is null and null_allowed. in_reg holds a possibly stale reference // that can be used to avoid loading the handle scope entry to see if the value is // null. - void CreateHandleScopeEntry(ManagedRegister out_reg, FrameOffset handlescope_offset, - ManagedRegister in_reg, bool null_allowed) OVERRIDE; + void CreateHandleScopeEntry(ManagedRegister out_reg, + FrameOffset handlescope_offset, + ManagedRegister in_reg, + bool null_allowed) OVERRIDE; // Set up out_off to hold a Object** into the handle scope, or to be null if the // value is null and null_allowed. - void CreateHandleScopeEntry(FrameOffset out_off, FrameOffset handlescope_offset, - ManagedRegister mscratch, bool null_allowed) OVERRIDE; + void CreateHandleScopeEntry(FrameOffset out_off, + FrameOffset handlescope_offset, + ManagedRegister mscratch, + bool null_allowed) OVERRIDE; // src holds a handle scope entry (Object**) load this into dst. void LoadReferenceFromHandleScope(ManagedRegister dst, ManagedRegister src) OVERRIDE; @@ -402,7 +479,7 @@ class MipsAssembler FINAL : public Assembler { // Call to address held at [base+offset]. void Call(ManagedRegister base, Offset offset, ManagedRegister mscratch) OVERRIDE; void Call(FrameOffset base, Offset offset, ManagedRegister mscratch) OVERRIDE; - void CallFromThread32(ThreadOffset<4> offset, ManagedRegister mscratch) OVERRIDE; + void CallFromThread32(ThreadOffset<kMipsWordSize> offset, ManagedRegister mscratch) OVERRIDE; // Generate code to check if Thread::Current()->exception_ is non-null // and branch to a ExceptionSlowPath if it is. @@ -437,6 +514,8 @@ class MipsAssembler FINAL : public Assembler { kCondNEZ, kCondLTU, kCondGEU, + kCondF, // Floating-point predicate false. + kCondT, // Floating-point predicate true. kUncond, }; friend std::ostream& operator<<(std::ostream& os, const BranchCondition& rhs); @@ -543,7 +622,22 @@ class MipsAssembler FINAL : public Assembler { // // Composite branches (made of several instructions) with longer reach have 32-bit // offsets encoded as 2 16-bit "halves" in two instructions (high half goes first). - // The composite branches cover the range of PC + +/-2GB. + // The composite branches cover the range of PC + +/-2GB on MIPS32 CPUs. However, + // the range is not end-to-end on MIPS64 (unless addresses are forced to zero- or + // sign-extend from 32 to 64 bits by the appropriate CPU configuration). + // Consider the following implementation of a long unconditional branch, for + // example: + // + // auipc at, offset_31_16 // at = pc + sign_extend(offset_31_16) << 16 + // jic at, offset_15_0 // pc = at + sign_extend(offset_15_0) + // + // Both of the above instructions take 16-bit signed offsets as immediate operands. + // When bit 15 of offset_15_0 is 1, it effectively causes subtraction of 0x10000 + // due to sign extension. This must be compensated for by incrementing offset_31_16 + // by 1. offset_31_16 can only be incremented by 1 if it's not 0x7FFF. If it is + // 0x7FFF, adding 1 will overflow the positive offset into the negative range. + // Therefore, the long branch range is something like from PC - 0x80000000 to + // PC + 0x7FFF7FFF, IOW, shorter by 32KB on one side. // // The returned values are therefore: 18, 21, 23, 28 and 32. There's also a special // case with the addiu instruction and a 16 bit offset. @@ -580,17 +674,17 @@ class MipsAssembler FINAL : public Assembler { // Helper for the above. void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type); - uint32_t old_location_; // Offset into assembler buffer in bytes. - uint32_t location_; // Offset into assembler buffer in bytes. - uint32_t target_; // Offset into assembler buffer in bytes. + uint32_t old_location_; // Offset into assembler buffer in bytes. + uint32_t location_; // Offset into assembler buffer in bytes. + uint32_t target_; // Offset into assembler buffer in bytes. - uint32_t lhs_reg_ : 5; // Left-hand side register in conditional branches or - // indirect call register. - uint32_t rhs_reg_ : 5; // Right-hand side register in conditional branches. - BranchCondition condition_ : 5; // Condition for conditional branches. + uint32_t lhs_reg_; // Left-hand side register in conditional branches or + // indirect call register. + uint32_t rhs_reg_; // Right-hand side register in conditional branches. + BranchCondition condition_; // Condition for conditional branches. - Type type_ : 5; // Current type of the branch. - Type old_type_ : 5; // Initial type of the branch. + Type type_; // Current type of the branch. + Type old_type_; // Initial type of the branch. }; friend std::ostream& operator<<(std::ostream& os, const Branch::Type& rhs); friend std::ostream& operator<<(std::ostream& os, const Branch::OffsetBits& rhs); @@ -601,8 +695,8 @@ class MipsAssembler FINAL : public Assembler { void EmitI26(int opcode, uint32_t imm26); void EmitFR(int opcode, int fmt, FRegister ft, FRegister fs, FRegister fd, int funct); void EmitFI(int opcode, int fmt, FRegister rt, uint16_t imm); - void EmitBcond(BranchCondition cond, Register rs, Register rt, uint16_t imm16); - void EmitBcondc(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21); // R6 + void EmitBcondR2(BranchCondition cond, Register rs, Register rt, uint16_t imm16); + void EmitBcondR6(BranchCondition cond, Register rs, Register rt, uint32_t imm16_21); void Buncond(MipsLabel* label); void Bcond(MipsLabel* label, BranchCondition condition, Register lhs, Register rhs = ZERO); diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc index 063d8bd825..6f8b3e8c57 100644 --- a/compiler/utils/mips/assembler_mips_test.cc +++ b/compiler/utils/mips/assembler_mips_test.cc @@ -21,6 +21,8 @@ #include "base/stl_util.h" #include "utils/assembler_test.h" +#define __ GetAssembler()-> + namespace art { struct MIPSCpuRegisterCompare { @@ -184,6 +186,63 @@ class AssemblerMIPSTest : public AssemblerTest<mips::MipsAssembler, return result; } + void BranchCondOneRegHelper(void (mips::MipsAssembler::*f)(mips::Register, + mips::MipsLabel*), + std::string instr_name) { + mips::MipsLabel label; + (Base::GetAssembler()->*f)(mips::A0, &label); + constexpr size_t kAdduCount1 = 63; + for (size_t i = 0; i != kAdduCount1; ++i) { + __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); + } + __ Bind(&label); + constexpr size_t kAdduCount2 = 64; + for (size_t i = 0; i != kAdduCount2; ++i) { + __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); + } + (Base::GetAssembler()->*f)(mips::A1, &label); + + std::string expected = + ".set noreorder\n" + + instr_name + " $a0, 1f\n" + "nop\n" + + RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + + "1:\n" + + RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + + instr_name + " $a1, 1b\n" + "nop\n"; + DriverStr(expected, instr_name); + } + + void BranchCondTwoRegsHelper(void (mips::MipsAssembler::*f)(mips::Register, + mips::Register, + mips::MipsLabel*), + std::string instr_name) { + mips::MipsLabel label; + (Base::GetAssembler()->*f)(mips::A0, mips::A1, &label); + constexpr size_t kAdduCount1 = 63; + for (size_t i = 0; i != kAdduCount1; ++i) { + __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); + } + __ Bind(&label); + constexpr size_t kAdduCount2 = 64; + for (size_t i = 0; i != kAdduCount2; ++i) { + __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); + } + (Base::GetAssembler()->*f)(mips::A2, mips::A3, &label); + + std::string expected = + ".set noreorder\n" + + instr_name + " $a0, $a1, 1f\n" + "nop\n" + + RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + + "1:\n" + + RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + + instr_name + " $a2, $a3, 1b\n" + "nop\n"; + DriverStr(expected, instr_name); + } + private: std::vector<mips::Register*> registers_; std::map<mips::Register, std::string, MIPSCpuRegisterCompare> secondary_register_names_; @@ -196,8 +255,6 @@ TEST_F(AssemblerMIPSTest, Toolchain) { EXPECT_TRUE(CheckTools()); } -#define __ GetAssembler()-> - TEST_F(AssemblerMIPSTest, Addu) { DriverStr(RepeatRRR(&mips::MipsAssembler::Addu, "addu ${reg1}, ${reg2}, ${reg3}"), "Addu"); } @@ -418,6 +475,84 @@ TEST_F(AssemblerMIPSTest, NegD) { DriverStr(RepeatFF(&mips::MipsAssembler::NegD, "neg.d ${reg1}, ${reg2}"), "NegD"); } +TEST_F(AssemblerMIPSTest, CunS) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CunS, 3, "c.un.s $fcc{imm}, ${reg1}, ${reg2}"), + "CunS"); +} + +TEST_F(AssemblerMIPSTest, CeqS) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CeqS, 3, "c.eq.s $fcc{imm}, ${reg1}, ${reg2}"), + "CeqS"); +} + +TEST_F(AssemblerMIPSTest, CueqS) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CueqS, 3, "c.ueq.s $fcc{imm}, ${reg1}, ${reg2}"), + "CueqS"); +} + +TEST_F(AssemblerMIPSTest, ColtS) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::ColtS, 3, "c.olt.s $fcc{imm}, ${reg1}, ${reg2}"), + "ColtS"); +} + +TEST_F(AssemblerMIPSTest, CultS) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CultS, 3, "c.ult.s $fcc{imm}, ${reg1}, ${reg2}"), + "CultS"); +} + +TEST_F(AssemblerMIPSTest, ColeS) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::ColeS, 3, "c.ole.s $fcc{imm}, ${reg1}, ${reg2}"), + "ColeS"); +} + +TEST_F(AssemblerMIPSTest, CuleS) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CuleS, 3, "c.ule.s $fcc{imm}, ${reg1}, ${reg2}"), + "CuleS"); +} + +TEST_F(AssemblerMIPSTest, CunD) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CunD, 3, "c.un.d $fcc{imm}, ${reg1}, ${reg2}"), + "CunD"); +} + +TEST_F(AssemblerMIPSTest, CeqD) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CeqD, 3, "c.eq.d $fcc{imm}, ${reg1}, ${reg2}"), + "CeqD"); +} + +TEST_F(AssemblerMIPSTest, CueqD) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CueqD, 3, "c.ueq.d $fcc{imm}, ${reg1}, ${reg2}"), + "CueqD"); +} + +TEST_F(AssemblerMIPSTest, ColtD) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::ColtD, 3, "c.olt.d $fcc{imm}, ${reg1}, ${reg2}"), + "ColtD"); +} + +TEST_F(AssemblerMIPSTest, CultD) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CultD, 3, "c.ult.d $fcc{imm}, ${reg1}, ${reg2}"), + "CultD"); +} + +TEST_F(AssemblerMIPSTest, ColeD) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::ColeD, 3, "c.ole.d $fcc{imm}, ${reg1}, ${reg2}"), + "ColeD"); +} + +TEST_F(AssemblerMIPSTest, CuleD) { + DriverStr(RepeatIbFF(&mips::MipsAssembler::CuleD, 3, "c.ule.d $fcc{imm}, ${reg1}, ${reg2}"), + "CuleD"); +} + +TEST_F(AssemblerMIPSTest, Movf) { + DriverStr(RepeatRRIb(&mips::MipsAssembler::Movf, 3, "movf ${reg1}, ${reg2}, $fcc{imm}"), "Movf"); +} + +TEST_F(AssemblerMIPSTest, Movt) { + DriverStr(RepeatRRIb(&mips::MipsAssembler::Movt, 3, "movt ${reg1}, ${reg2}, $fcc{imm}"), "Movt"); +} + TEST_F(AssemblerMIPSTest, CvtSW) { DriverStr(RepeatFF(&mips::MipsAssembler::Cvtsw, "cvt.s.w ${reg1}, ${reg2}"), "CvtSW"); } @@ -1000,55 +1135,11 @@ TEST_F(AssemblerMIPSTest, B) { } TEST_F(AssemblerMIPSTest, Beq) { - mips::MipsLabel label; - __ Beq(mips::A0, mips::A1, &label); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Beq(mips::A2, mips::A3, &label); - - std::string expected = - ".set noreorder\n" - "beq $a0, $a1, 1f\n" - "nop\n" + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "beq $a2, $a3, 1b\n" - "nop\n"; - DriverStr(expected, "Beq"); + BranchCondTwoRegsHelper(&mips::MipsAssembler::Beq, "Beq"); } TEST_F(AssemblerMIPSTest, Bne) { - mips::MipsLabel label; - __ Bne(mips::A0, mips::A1, &label); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bne(mips::A2, mips::A3, &label); - - std::string expected = - ".set noreorder\n" - "bne $a0, $a1, 1f\n" - "nop\n" + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "bne $a2, $a3, 1b\n" - "nop\n"; - DriverStr(expected, "Bne"); + BranchCondTwoRegsHelper(&mips::MipsAssembler::Bne, "Bne"); } TEST_F(AssemblerMIPSTest, Beqz) { @@ -1104,60 +1195,24 @@ TEST_F(AssemblerMIPSTest, Bnez) { } TEST_F(AssemblerMIPSTest, Bltz) { - mips::MipsLabel label; - __ Bltz(mips::A0, &label); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bltz(mips::A1, &label); - - std::string expected = - ".set noreorder\n" - "bltz $a0, 1f\n" - "nop\n" + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "bltz $a1, 1b\n" - "nop\n"; - DriverStr(expected, "Bltz"); + BranchCondOneRegHelper(&mips::MipsAssembler::Bltz, "Bltz"); } TEST_F(AssemblerMIPSTest, Bgez) { - mips::MipsLabel label; - __ Bgez(mips::A0, &label); - constexpr size_t kAdduCount1 = 63; - for (size_t i = 0; i != kAdduCount1; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bind(&label); - constexpr size_t kAdduCount2 = 64; - for (size_t i = 0; i != kAdduCount2; ++i) { - __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); - } - __ Bgez(mips::A1, &label); - - std::string expected = - ".set noreorder\n" - "bgez $a0, 1f\n" - "nop\n" + - RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + - "1:\n" + - RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "bgez $a1, 1b\n" - "nop\n"; - DriverStr(expected, "Bgez"); + BranchCondOneRegHelper(&mips::MipsAssembler::Bgez, "Bgez"); } TEST_F(AssemblerMIPSTest, Blez) { + BranchCondOneRegHelper(&mips::MipsAssembler::Blez, "Blez"); +} + +TEST_F(AssemblerMIPSTest, Bgtz) { + BranchCondOneRegHelper(&mips::MipsAssembler::Bgtz, "Bgtz"); +} + +TEST_F(AssemblerMIPSTest, Blt) { mips::MipsLabel label; - __ Blez(mips::A0, &label); + __ Blt(mips::A0, mips::A1, &label); constexpr size_t kAdduCount1 = 63; for (size_t i = 0; i != kAdduCount1; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); @@ -1167,23 +1222,25 @@ TEST_F(AssemblerMIPSTest, Blez) { for (size_t i = 0; i != kAdduCount2; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); } - __ Blez(mips::A1, &label); + __ Blt(mips::A2, mips::A3, &label); std::string expected = ".set noreorder\n" - "blez $a0, 1f\n" + "slt $at, $a0, $a1\n" + "bne $zero, $at, 1f\n" "nop\n" + RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + "1:\n" + RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "blez $a1, 1b\n" + "slt $at, $a2, $a3\n" + "bne $zero, $at, 1b\n" "nop\n"; - DriverStr(expected, "Blez"); + DriverStr(expected, "Blt"); } -TEST_F(AssemblerMIPSTest, Bgtz) { +TEST_F(AssemblerMIPSTest, Bge) { mips::MipsLabel label; - __ Bgtz(mips::A0, &label); + __ Bge(mips::A0, mips::A1, &label); constexpr size_t kAdduCount1 = 63; for (size_t i = 0; i != kAdduCount1; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); @@ -1193,23 +1250,25 @@ TEST_F(AssemblerMIPSTest, Bgtz) { for (size_t i = 0; i != kAdduCount2; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); } - __ Bgtz(mips::A1, &label); + __ Bge(mips::A2, mips::A3, &label); std::string expected = ".set noreorder\n" - "bgtz $a0, 1f\n" + "slt $at, $a0, $a1\n" + "beq $zero, $at, 1f\n" "nop\n" + RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + "1:\n" + RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "bgtz $a1, 1b\n" + "slt $at, $a2, $a3\n" + "beq $zero, $at, 1b\n" "nop\n"; - DriverStr(expected, "Bgtz"); + DriverStr(expected, "Bge"); } -TEST_F(AssemblerMIPSTest, Blt) { +TEST_F(AssemblerMIPSTest, Bltu) { mips::MipsLabel label; - __ Blt(mips::A0, mips::A1, &label); + __ Bltu(mips::A0, mips::A1, &label); constexpr size_t kAdduCount1 = 63; for (size_t i = 0; i != kAdduCount1; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); @@ -1219,25 +1278,25 @@ TEST_F(AssemblerMIPSTest, Blt) { for (size_t i = 0; i != kAdduCount2; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); } - __ Blt(mips::A2, mips::A3, &label); + __ Bltu(mips::A2, mips::A3, &label); std::string expected = ".set noreorder\n" - "slt $at, $a0, $a1\n" + "sltu $at, $a0, $a1\n" "bne $zero, $at, 1f\n" "nop\n" + RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + "1:\n" + RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "slt $at, $a2, $a3\n" + "sltu $at, $a2, $a3\n" "bne $zero, $at, 1b\n" "nop\n"; - DriverStr(expected, "Blt"); + DriverStr(expected, "Bltu"); } -TEST_F(AssemblerMIPSTest, Bge) { +TEST_F(AssemblerMIPSTest, Bgeu) { mips::MipsLabel label; - __ Bge(mips::A0, mips::A1, &label); + __ Bgeu(mips::A0, mips::A1, &label); constexpr size_t kAdduCount1 = 63; for (size_t i = 0; i != kAdduCount1; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); @@ -1247,25 +1306,25 @@ TEST_F(AssemblerMIPSTest, Bge) { for (size_t i = 0; i != kAdduCount2; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); } - __ Bge(mips::A2, mips::A3, &label); + __ Bgeu(mips::A2, mips::A3, &label); std::string expected = ".set noreorder\n" - "slt $at, $a0, $a1\n" + "sltu $at, $a0, $a1\n" "beq $zero, $at, 1f\n" "nop\n" + RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + "1:\n" + RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "slt $at, $a2, $a3\n" + "sltu $at, $a2, $a3\n" "beq $zero, $at, 1b\n" "nop\n"; - DriverStr(expected, "Bge"); + DriverStr(expected, "Bgeu"); } -TEST_F(AssemblerMIPSTest, Bltu) { +TEST_F(AssemblerMIPSTest, Bc1f) { mips::MipsLabel label; - __ Bltu(mips::A0, mips::A1, &label); + __ Bc1f(0, &label); constexpr size_t kAdduCount1 = 63; for (size_t i = 0; i != kAdduCount1; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); @@ -1275,25 +1334,23 @@ TEST_F(AssemblerMIPSTest, Bltu) { for (size_t i = 0; i != kAdduCount2; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); } - __ Bltu(mips::A2, mips::A3, &label); + __ Bc1f(7, &label); std::string expected = ".set noreorder\n" - "sltu $at, $a0, $a1\n" - "bne $zero, $at, 1f\n" + "bc1f $fcc0, 1f\n" "nop\n" + RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + "1:\n" + RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "sltu $at, $a2, $a3\n" - "bne $zero, $at, 1b\n" + "bc1f $fcc7, 1b\n" "nop\n"; - DriverStr(expected, "Bltu"); + DriverStr(expected, "Bc1f"); } -TEST_F(AssemblerMIPSTest, Bgeu) { +TEST_F(AssemblerMIPSTest, Bc1t) { mips::MipsLabel label; - __ Bgeu(mips::A0, mips::A1, &label); + __ Bc1t(0, &label); constexpr size_t kAdduCount1 = 63; for (size_t i = 0; i != kAdduCount1; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); @@ -1303,20 +1360,18 @@ TEST_F(AssemblerMIPSTest, Bgeu) { for (size_t i = 0; i != kAdduCount2; ++i) { __ Addu(mips::ZERO, mips::ZERO, mips::ZERO); } - __ Bgeu(mips::A2, mips::A3, &label); + __ Bc1t(7, &label); std::string expected = ".set noreorder\n" - "sltu $at, $a0, $a1\n" - "beq $zero, $at, 1f\n" + "bc1t $fcc0, 1f\n" "nop\n" + RepeatInsn(kAdduCount1, "addu $zero, $zero, $zero\n") + "1:\n" + RepeatInsn(kAdduCount2, "addu $zero, $zero, $zero\n") + - "sltu $at, $a2, $a3\n" - "beq $zero, $at, 1b\n" + "bc1t $fcc7, 1b\n" "nop\n"; - DriverStr(expected, "Bgeu"); + DriverStr(expected, "Bc1t"); } #undef __ diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc index 2d15f6f41e..cd64a4f926 100644 --- a/disassembler/disassembler_mips.cc +++ b/disassembler/disassembler_mips.cc @@ -111,6 +111,8 @@ static const MipsInstruction gMipsInstructions[] = { { kRTypeMask | (0x1f << 21), 63, "dsra32", "DTA", }, // SPECIAL0 + { kSpecial0Mask | 0x307ff, 1, "movf", "DSc" }, + { kSpecial0Mask | 0x307ff, 0x10001, "movt", "DSc" }, { kSpecial0Mask | 0x7ff, (2 << 6) | 24, "mul", "DST" }, { kSpecial0Mask | 0x7ff, (3 << 6) | 24, "muh", "DST" }, { kSpecial0Mask | 0x7ff, (2 << 6) | 25, "mulu", "DST" }, @@ -216,6 +218,11 @@ static const MipsInstruction gMipsInstructions[] = { { kITypeMask | (0x1f << 21), 15 << kOpcodeShift, "lui", "TI", }, { kITypeMask, 15 << kOpcodeShift, "aui", "TSI", }, + { kITypeMask | (0x3e3 << 16), (17 << kOpcodeShift) | (8 << 21), "bc1f", "cB" }, + { kITypeMask | (0x3e3 << 16), (17 << kOpcodeShift) | (8 << 21) | (1 << 16), "bc1t", "cB" }, + { kITypeMask | (0x1f << 21), (17 << kOpcodeShift) | (9 << 21), "bc1eqz", "tB" }, + { kITypeMask | (0x1f << 21), (17 << kOpcodeShift) | (13 << 21), "bc1nez", "tB" }, + { kITypeMask | (0x1f << 21), 22 << kOpcodeShift, "blezc", "TB" }, // TODO: de-dup @@ -333,6 +340,26 @@ static const MipsInstruction gMipsInstructions[] = { { kFpMask | (0x1f << 21), kCop1 | (0x04 << 21), "mtc1", "Td" }, { kFpMask | (0x1f << 21), kCop1 | (0x05 << 21), "dmtc1", "Td" }, { kFpMask | (0x1f << 21), kCop1 | (0x07 << 21), "mthc1", "Td" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 1, "cmp.un.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 2, "cmp.eq.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 3, "cmp.ueq.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 4, "cmp.lt.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 5, "cmp.ult.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 6, "cmp.le.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 7, "cmp.ule.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 17, "cmp.or.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 18, "cmp.une.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 19, "cmp.ne.s", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 1, "cmp.un.d", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 2, "cmp.eq.d", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 3, "cmp.ueq.d", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 4, "cmp.lt.d", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 5, "cmp.ult.d", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 6, "cmp.le.d", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 7, "cmp.ule.d", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 17, "cmp.or.d", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 18, "cmp.une.d", "adt" }, + { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 19, "cmp.ne.d", "adt" }, { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 0, "add", "fadt" }, { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 1, "sub", "fadt" }, { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 2, "mul", "fadt" }, @@ -356,6 +383,13 @@ static const MipsInstruction gMipsInstructions[] = { { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 36, "cvt.w", "fad" }, { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 37, "cvt.l", "fad" }, { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 38, "cvt.ps", "fad" }, + { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 49, "c.un", "fCdt" }, + { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 50, "c.eq", "fCdt" }, + { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 51, "c.ueq", "fCdt" }, + { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 52, "c.olt", "fCdt" }, + { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 53, "c.ult", "fCdt" }, + { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 54, "c.ole", "fCdt" }, + { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 55, "c.ule", "fCdt" }, { kFpMask, kCop1 | 0x10, "sel", "fadt" }, { kFpMask, kCop1 | 0x1e, "max", "fadt" }, { kFpMask, kCop1 | 0x1c, "min", "fadt" }, @@ -408,6 +442,12 @@ size_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* instr_ptr) { << StringPrintf(" ; %+d", offset); } break; + case 'C': // Floating-point condition code flag in c.<cond>.fmt. + args << "cc" << (sa >> 2); + break; + case 'c': // Floating-point condition code flag in bc1f/bc1t and movf/movt. + args << "cc" << (rt >> 2); + break; case 'D': args << 'r' << rd; break; case 'd': args << 'f' << rd; break; case 'a': args << 'f' << sa; break; |