in compiler/optimizing/code_generator_mips64.cc [631:792]
void CodeGeneratorMIPS64::MoveLocation(Location destination,
Location source,
Primitive::Type dst_type) {
if (source.Equals(destination)) {
return;
}
// A valid move can always be inferred from the destination and source
// locations. When moving from and to a register, the argument type can be
// used to generate 32bit instead of 64bit moves.
bool unspecified_type = (dst_type == Primitive::kPrimVoid);
DCHECK_EQ(unspecified_type, false);
if (destination.IsRegister() || destination.IsFpuRegister()) {
if (unspecified_type) {
HConstant* src_cst = source.IsConstant() ? source.GetConstant() : nullptr;
if (source.IsStackSlot() ||
(src_cst != nullptr && (src_cst->IsIntConstant()
|| src_cst->IsFloatConstant()
|| src_cst->IsNullConstant()))) {
// For stack slots and 32bit constants, a 64bit type is appropriate.
dst_type = destination.IsRegister() ? Primitive::kPrimInt : Primitive::kPrimFloat;
} else {
// If the source is a double stack slot or a 64bit constant, a 64bit
// type is appropriate. Else the source is a register, and since the
// type has not been specified, we chose a 64bit type to force a 64bit
// move.
dst_type = destination.IsRegister() ? Primitive::kPrimLong : Primitive::kPrimDouble;
}
}
DCHECK((destination.IsFpuRegister() && Primitive::IsFloatingPointType(dst_type)) ||
(destination.IsRegister() && !Primitive::IsFloatingPointType(dst_type)));
if (source.IsStackSlot() || source.IsDoubleStackSlot()) {
// Move to GPR/FPR from stack
LoadOperandType load_type = source.IsStackSlot() ? kLoadWord : kLoadDoubleword;
if (Primitive::IsFloatingPointType(dst_type)) {
__ LoadFpuFromOffset(load_type,
destination.AsFpuRegister<FpuRegister>(),
SP,
source.GetStackIndex());
} else {
// TODO: use load_type = kLoadUnsignedWord when type == Primitive::kPrimNot.
__ LoadFromOffset(load_type,
destination.AsRegister<GpuRegister>(),
SP,
source.GetStackIndex());
}
} else if (source.IsConstant()) {
// Move to GPR/FPR from constant
GpuRegister gpr = AT;
if (!Primitive::IsFloatingPointType(dst_type)) {
gpr = destination.AsRegister<GpuRegister>();
}
if (dst_type == Primitive::kPrimInt || dst_type == Primitive::kPrimFloat) {
int32_t value = GetInt32ValueOf(source.GetConstant()->AsConstant());
if (Primitive::IsFloatingPointType(dst_type) && value == 0) {
gpr = ZERO;
} else {
__ LoadConst32(gpr, value);
}
} else {
int64_t value = GetInt64ValueOf(source.GetConstant()->AsConstant());
if (Primitive::IsFloatingPointType(dst_type) && value == 0) {
gpr = ZERO;
} else {
__ LoadConst64(gpr, value);
}
}
if (dst_type == Primitive::kPrimFloat) {
__ Mtc1(gpr, destination.AsFpuRegister<FpuRegister>());
} else if (dst_type == Primitive::kPrimDouble) {
__ Dmtc1(gpr, destination.AsFpuRegister<FpuRegister>());
}
} else if (source.IsRegister()) {
if (destination.IsRegister()) {
// Move to GPR from GPR
__ Move(destination.AsRegister<GpuRegister>(), source.AsRegister<GpuRegister>());
} else {
DCHECK(destination.IsFpuRegister());
if (Primitive::Is64BitType(dst_type)) {
__ Dmtc1(source.AsRegister<GpuRegister>(), destination.AsFpuRegister<FpuRegister>());
} else {
__ Mtc1(source.AsRegister<GpuRegister>(), destination.AsFpuRegister<FpuRegister>());
}
}
} else if (source.IsFpuRegister()) {
if (destination.IsFpuRegister()) {
// Move to FPR from FPR
if (dst_type == Primitive::kPrimFloat) {
__ MovS(destination.AsFpuRegister<FpuRegister>(), source.AsFpuRegister<FpuRegister>());
} else {
DCHECK_EQ(dst_type, Primitive::kPrimDouble);
__ MovD(destination.AsFpuRegister<FpuRegister>(), source.AsFpuRegister<FpuRegister>());
}
} else {
DCHECK(destination.IsRegister());
if (Primitive::Is64BitType(dst_type)) {
__ Dmfc1(destination.AsRegister<GpuRegister>(), source.AsFpuRegister<FpuRegister>());
} else {
__ Mfc1(destination.AsRegister<GpuRegister>(), source.AsFpuRegister<FpuRegister>());
}
}
}
} else { // The destination is not a register. It must be a stack slot.
DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot());
if (source.IsRegister() || source.IsFpuRegister()) {
if (unspecified_type) {
if (source.IsRegister()) {
dst_type = destination.IsStackSlot() ? Primitive::kPrimInt : Primitive::kPrimLong;
} else {
dst_type = destination.IsStackSlot() ? Primitive::kPrimFloat : Primitive::kPrimDouble;
}
}
DCHECK((destination.IsDoubleStackSlot() == Primitive::Is64BitType(dst_type)) &&
(source.IsFpuRegister() == Primitive::IsFloatingPointType(dst_type)));
// Move to stack from GPR/FPR
StoreOperandType store_type = destination.IsStackSlot() ? kStoreWord : kStoreDoubleword;
if (source.IsRegister()) {
__ StoreToOffset(store_type,
source.AsRegister<GpuRegister>(),
SP,
destination.GetStackIndex());
} else {
__ StoreFpuToOffset(store_type,
source.AsFpuRegister<FpuRegister>(),
SP,
destination.GetStackIndex());
}
} else if (source.IsConstant()) {
// Move to stack from constant
HConstant* src_cst = source.GetConstant();
StoreOperandType store_type = destination.IsStackSlot() ? kStoreWord : kStoreDoubleword;
GpuRegister gpr = ZERO;
if (destination.IsStackSlot()) {
int32_t value = GetInt32ValueOf(src_cst->AsConstant());
if (value != 0) {
gpr = TMP;
__ LoadConst32(gpr, value);
}
} else {
DCHECK(destination.IsDoubleStackSlot());
int64_t value = GetInt64ValueOf(src_cst->AsConstant());
if (value != 0) {
gpr = TMP;
__ LoadConst64(gpr, value);
}
}
__ StoreToOffset(store_type, gpr, SP, destination.GetStackIndex());
} else {
DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot());
DCHECK_EQ(source.IsDoubleStackSlot(), destination.IsDoubleStackSlot());
// Move to stack from stack
if (destination.IsStackSlot()) {
__ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
__ StoreToOffset(kStoreWord, TMP, SP, destination.GetStackIndex());
} else {
__ LoadFromOffset(kLoadDoubleword, TMP, SP, source.GetStackIndex());
__ StoreToOffset(kStoreDoubleword, TMP, SP, destination.GetStackIndex());
}
}
}
}