in compiler/optimizing/code_generator_x86_64.cc [2536:2870]
void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conversion) {
LocationSummary* locations = conversion->GetLocations();
Location out = locations->Out();
Location in = locations->InAt(0);
Primitive::Type result_type = conversion->GetResultType();
Primitive::Type input_type = conversion->GetInputType();
DCHECK_NE(result_type, input_type);
switch (result_type) {
case Primitive::kPrimByte:
switch (input_type) {
case Primitive::kPrimLong:
// Type conversion from long to byte is a result of code transformations.
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimShort:
case Primitive::kPrimInt:
case Primitive::kPrimChar:
// Processing a Dex `int-to-byte' instruction.
if (in.IsRegister()) {
__ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
} else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
__ movsxb(out.AsRegister<CpuRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()));
} else {
__ movl(out.AsRegister<CpuRegister>(),
Immediate(static_cast<int8_t>(Int64FromConstant(in.GetConstant()))));
}
break;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
<< " to " << result_type;
}
break;
case Primitive::kPrimShort:
switch (input_type) {
case Primitive::kPrimLong:
// Type conversion from long to short is a result of code transformations.
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimByte:
case Primitive::kPrimInt:
case Primitive::kPrimChar:
// Processing a Dex `int-to-short' instruction.
if (in.IsRegister()) {
__ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
} else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
__ movsxw(out.AsRegister<CpuRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()));
} else {
__ movl(out.AsRegister<CpuRegister>(),
Immediate(static_cast<int16_t>(Int64FromConstant(in.GetConstant()))));
}
break;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
<< " to " << result_type;
}
break;
case Primitive::kPrimInt:
switch (input_type) {
case Primitive::kPrimLong:
// Processing a Dex `long-to-int' instruction.
if (in.IsRegister()) {
__ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
} else if (in.IsDoubleStackSlot()) {
__ movl(out.AsRegister<CpuRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()));
} else {
DCHECK(in.IsConstant());
DCHECK(in.GetConstant()->IsLongConstant());
int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
__ movl(out.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
}
break;
case Primitive::kPrimFloat: {
// Processing a Dex `float-to-int' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
CpuRegister output = out.AsRegister<CpuRegister>();
NearLabel done, nan;
__ movl(output, Immediate(kPrimIntMax));
// if input >= (float)INT_MAX goto done
__ comiss(input, codegen_->LiteralFloatAddress(kPrimIntMax));
__ j(kAboveEqual, &done);
// if input == NaN goto nan
__ j(kUnordered, &nan);
// output = float-to-int-truncate(input)
__ cvttss2si(output, input, false);
__ jmp(&done);
__ Bind(&nan);
// output = 0
__ xorl(output, output);
__ Bind(&done);
break;
}
case Primitive::kPrimDouble: {
// Processing a Dex `double-to-int' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
CpuRegister output = out.AsRegister<CpuRegister>();
NearLabel done, nan;
__ movl(output, Immediate(kPrimIntMax));
// if input >= (double)INT_MAX goto done
__ comisd(input, codegen_->LiteralDoubleAddress(kPrimIntMax));
__ j(kAboveEqual, &done);
// if input == NaN goto nan
__ j(kUnordered, &nan);
// output = double-to-int-truncate(input)
__ cvttsd2si(output, input);
__ jmp(&done);
__ Bind(&nan);
// output = 0
__ xorl(output, output);
__ Bind(&done);
break;
}
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
<< " to " << result_type;
}
break;
case Primitive::kPrimLong:
switch (input_type) {
DCHECK(out.IsRegister());
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimByte:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
case Primitive::kPrimChar:
// Processing a Dex `int-to-long' instruction.
DCHECK(in.IsRegister());
__ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
break;
case Primitive::kPrimFloat: {
// Processing a Dex `float-to-long' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
CpuRegister output = out.AsRegister<CpuRegister>();
NearLabel done, nan;
codegen_->Load64BitValue(output, kPrimLongMax);
// if input >= (float)LONG_MAX goto done
__ comiss(input, codegen_->LiteralFloatAddress(kPrimLongMax));
__ j(kAboveEqual, &done);
// if input == NaN goto nan
__ j(kUnordered, &nan);
// output = float-to-long-truncate(input)
__ cvttss2si(output, input, true);
__ jmp(&done);
__ Bind(&nan);
// output = 0
__ xorl(output, output);
__ Bind(&done);
break;
}
case Primitive::kPrimDouble: {
// Processing a Dex `double-to-long' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
CpuRegister output = out.AsRegister<CpuRegister>();
NearLabel done, nan;
codegen_->Load64BitValue(output, kPrimLongMax);
// if input >= (double)LONG_MAX goto done
__ comisd(input, codegen_->LiteralDoubleAddress(kPrimLongMax));
__ j(kAboveEqual, &done);
// if input == NaN goto nan
__ j(kUnordered, &nan);
// output = double-to-long-truncate(input)
__ cvttsd2si(output, input, true);
__ jmp(&done);
__ Bind(&nan);
// output = 0
__ xorl(output, output);
__ Bind(&done);
break;
}
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
<< " to " << result_type;
}
break;
case Primitive::kPrimChar:
switch (input_type) {
case Primitive::kPrimLong:
// Type conversion from long to char is a result of code transformations.
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimByte:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
// Processing a Dex `int-to-char' instruction.
if (in.IsRegister()) {
__ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
} else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
__ movzxw(out.AsRegister<CpuRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()));
} else {
__ movl(out.AsRegister<CpuRegister>(),
Immediate(static_cast<uint16_t>(Int64FromConstant(in.GetConstant()))));
}
break;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
<< " to " << result_type;
}
break;
case Primitive::kPrimFloat:
switch (input_type) {
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimByte:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
case Primitive::kPrimChar:
// Processing a Dex `int-to-float' instruction.
if (in.IsRegister()) {
__ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
} else if (in.IsConstant()) {
int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
XmmRegister dest = out.AsFpuRegister<XmmRegister>();
codegen_->Load32BitValue(dest, static_cast<float>(v));
} else {
__ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()), false);
}
break;
case Primitive::kPrimLong:
// Processing a Dex `long-to-float' instruction.
if (in.IsRegister()) {
__ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
} else if (in.IsConstant()) {
int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
XmmRegister dest = out.AsFpuRegister<XmmRegister>();
codegen_->Load32BitValue(dest, static_cast<float>(v));
} else {
__ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()), true);
}
break;
case Primitive::kPrimDouble:
// Processing a Dex `double-to-float' instruction.
if (in.IsFpuRegister()) {
__ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
} else if (in.IsConstant()) {
double v = in.GetConstant()->AsDoubleConstant()->GetValue();
XmmRegister dest = out.AsFpuRegister<XmmRegister>();
codegen_->Load32BitValue(dest, static_cast<float>(v));
} else {
__ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()));
}
break;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
<< " to " << result_type;
};
break;
case Primitive::kPrimDouble:
switch (input_type) {
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimByte:
case Primitive::kPrimShort:
case Primitive::kPrimInt:
case Primitive::kPrimChar:
// Processing a Dex `int-to-double' instruction.
if (in.IsRegister()) {
__ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
} else if (in.IsConstant()) {
int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
XmmRegister dest = out.AsFpuRegister<XmmRegister>();
codegen_->Load64BitValue(dest, static_cast<double>(v));
} else {
__ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()), false);
}
break;
case Primitive::kPrimLong:
// Processing a Dex `long-to-double' instruction.
if (in.IsRegister()) {
__ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
} else if (in.IsConstant()) {
int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
XmmRegister dest = out.AsFpuRegister<XmmRegister>();
codegen_->Load64BitValue(dest, static_cast<double>(v));
} else {
__ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()), true);
}
break;
case Primitive::kPrimFloat:
// Processing a Dex `float-to-double' instruction.
if (in.IsFpuRegister()) {
__ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
} else if (in.IsConstant()) {
float v = in.GetConstant()->AsFloatConstant()->GetValue();
XmmRegister dest = out.AsFpuRegister<XmmRegister>();
codegen_->Load64BitValue(dest, static_cast<double>(v));
} else {
__ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()));
}
break;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
<< " to " << result_type;
};
break;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
<< " to " << result_type;
}
}