summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/code_generator_arm.cc18
-rw-r--r--compiler/optimizing/code_generator_mips64.cc28
-rw-r--r--compiler/optimizing/code_generator_x86.cc50
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc28
-rw-r--r--compiler/optimizing/instruction_simplifier.cc74
5 files changed, 175 insertions, 23 deletions
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 005b6c189e..87f52c6f21 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -2079,6 +2079,8 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
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:
@@ -2097,6 +2099,8 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
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:
@@ -2181,6 +2185,8 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
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:
@@ -2280,6 +2286,10 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio
switch (result_type) {
case Primitive::kPrimByte:
switch (input_type) {
+ case Primitive::kPrimLong:
+ // Type conversion from long to byte is a result of code transformations.
+ __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
+ break;
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimShort:
@@ -2297,6 +2307,10 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio
case Primitive::kPrimShort:
switch (input_type) {
+ case Primitive::kPrimLong:
+ // Type conversion from long to short is a result of code transformations.
+ __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
+ break;
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimByte:
@@ -2398,6 +2412,10 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio
case Primitive::kPrimChar:
switch (input_type) {
+ case Primitive::kPrimLong:
+ // Type conversion from long to char is a result of code transformations.
+ __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
+ break;
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimByte:
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 71d65e84a6..119084e026 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3943,18 +3943,26 @@ void InstructionCodeGeneratorMIPS64::VisitTypeConversion(HTypeConversion* conver
__ Andi(dst, src, 0xFFFF);
break;
case Primitive::kPrimByte:
- // long is never converted into types narrower than int directly,
- // so SEB and SEH can be used without ever causing unpredictable results
- // on 64-bit inputs
- DCHECK(input_type != Primitive::kPrimLong);
- __ Seb(dst, src);
+ if (input_type == Primitive::kPrimLong) {
+ // Type conversion from long to types narrower than int is a result of code
+ // transformations. To avoid unpredictable results for SEB and SEH, we first
+ // need to sign-extend the low 32-bit value into bits 32 through 63.
+ __ Sll(dst, src, 0);
+ __ Seb(dst, dst);
+ } else {
+ __ Seb(dst, src);
+ }
break;
case Primitive::kPrimShort:
- // long is never converted into types narrower than int directly,
- // so SEB and SEH can be used without ever causing unpredictable results
- // on 64-bit inputs
- DCHECK(input_type != Primitive::kPrimLong);
- __ Seh(dst, src);
+ if (input_type == Primitive::kPrimLong) {
+ // Type conversion from long to types narrower than int is a result of code
+ // transformations. To avoid unpredictable results for SEB and SEH, we first
+ // need to sign-extend the low 32-bit value into bits 32 through 63.
+ __ Sll(dst, src, 0);
+ __ Seh(dst, dst);
+ } else {
+ __ Seh(dst, src);
+ }
break;
case Primitive::kPrimInt:
case Primitive::kPrimLong:
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 3713690335..07edd97c1f 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -2145,6 +2145,18 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
switch (result_type) {
case Primitive::kPrimByte:
switch (input_type) {
+ case Primitive::kPrimLong: {
+ // Type conversion from long to byte is a result of code transformations.
+ HInstruction* input = conversion->InputAt(0);
+ Location input_location = input->IsConstant()
+ ? Location::ConstantLocation(input->AsConstant())
+ : Location::RegisterPairLocation(EAX, EDX);
+ locations->SetInAt(0, input_location);
+ // Make the output overlap to please the register allocator. This greatly simplifies
+ // the validation of the linear scan implementation
+ locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
+ break;
+ }
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimShort:
@@ -2165,6 +2177,8 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
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:
@@ -2242,6 +2256,8 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
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:
@@ -2336,6 +2352,16 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
switch (result_type) {
case Primitive::kPrimByte:
switch (input_type) {
+ case Primitive::kPrimLong:
+ // Type conversion from long to byte is a result of code transformations.
+ if (in.IsRegisterPair()) {
+ __ movsxb(out.AsRegister<Register>(), in.AsRegisterPairLow<ByteRegister>());
+ } else {
+ DCHECK(in.GetConstant()->IsLongConstant());
+ int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+ __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
+ }
+ break;
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimShort:
@@ -2359,6 +2385,18 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
case Primitive::kPrimShort:
switch (input_type) {
+ case Primitive::kPrimLong:
+ // Type conversion from long to short is a result of code transformations.
+ if (in.IsRegisterPair()) {
+ __ movsxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
+ } else if (in.IsDoubleStackSlot()) {
+ __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+ } else {
+ DCHECK(in.GetConstant()->IsLongConstant());
+ int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+ __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
+ }
+ break;
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimByte:
@@ -2495,6 +2533,18 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
case Primitive::kPrimChar:
switch (input_type) {
+ case Primitive::kPrimLong:
+ // Type conversion from long to short is a result of code transformations.
+ if (in.IsRegisterPair()) {
+ __ movzxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
+ } else if (in.IsDoubleStackSlot()) {
+ __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+ } else {
+ DCHECK(in.GetConstant()->IsLongConstant());
+ int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+ __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
+ }
+ break;
case Primitive::kPrimBoolean:
// Boolean input is a result of code transformations.
case Primitive::kPrimByte:
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 35603aa030..a5c386d327 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -2363,6 +2363,8 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
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:
@@ -2381,6 +2383,8 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
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:
@@ -2458,6 +2462,8 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
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:
@@ -2552,6 +2558,8 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
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:
@@ -2560,13 +2568,12 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
// Processing a Dex `int-to-byte' instruction.
if (in.IsRegister()) {
__ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
- } else if (in.IsStackSlot()) {
+ } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
__ movsxb(out.AsRegister<CpuRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()));
} else {
- DCHECK(in.GetConstant()->IsIntConstant());
__ movl(out.AsRegister<CpuRegister>(),
- Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
+ Immediate(static_cast<int8_t>(Int64FromConstant(in.GetConstant()))));
}
break;
@@ -2578,6 +2585,8 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
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:
@@ -2586,13 +2595,12 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
// Processing a Dex `int-to-short' instruction.
if (in.IsRegister()) {
__ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
- } else if (in.IsStackSlot()) {
+ } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
__ movsxw(out.AsRegister<CpuRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()));
} else {
- DCHECK(in.GetConstant()->IsIntConstant());
__ movl(out.AsRegister<CpuRegister>(),
- Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
+ Immediate(static_cast<int16_t>(Int64FromConstant(in.GetConstant()))));
}
break;
@@ -2735,6 +2743,8 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
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:
@@ -2743,14 +2753,12 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
// Processing a Dex `int-to-char' instruction.
if (in.IsRegister()) {
__ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
- } else if (in.IsStackSlot()) {
+ } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
__ movzxw(out.AsRegister<CpuRegister>(),
Address(CpuRegister(RSP), in.GetStackIndex()));
} else {
- DCHECK(in.GetConstant()->IsIntConstant());
__ movl(out.AsRegister<CpuRegister>(),
- Immediate(static_cast<uint16_t>(
- in.GetConstant()->AsIntConstant()->GetValue())));
+ Immediate(static_cast<uint16_t>(Int64FromConstant(in.GetConstant()))));
}
break;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 0029cc3650..98f8009846 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -757,11 +757,79 @@ void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
}
}
+static bool IsTypeConversionImplicit(Primitive::Type input_type, Primitive::Type result_type) {
+ // Besides conversion to the same type, widening integral conversions are implicit,
+ // excluding conversions to long and the byte->char conversion where we need to
+ // clear the high 16 bits of the 32-bit sign-extended representation of byte.
+ return result_type == input_type ||
+ (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimByte) ||
+ (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimShort) ||
+ (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimChar) ||
+ (result_type == Primitive::kPrimShort && input_type == Primitive::kPrimByte);
+}
+
+static bool IsTypeConversionLossless(Primitive::Type input_type, Primitive::Type result_type) {
+ // The conversion to a larger type is loss-less with the exception of two cases,
+ // - conversion to char, the only unsigned type, where we may lose some bits, and
+ // - conversion from float to long, the only FP to integral conversion with smaller FP type.
+ // For integral to FP conversions this holds because the FP mantissa is large enough.
+ DCHECK_NE(input_type, result_type);
+ return Primitive::ComponentSize(result_type) > Primitive::ComponentSize(input_type) &&
+ result_type != Primitive::kPrimChar &&
+ !(result_type == Primitive::kPrimLong && input_type == Primitive::kPrimFloat);
+}
+
void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
- if (instruction->GetResultType() == instruction->GetInputType()) {
- // Remove the instruction if it's converting to the same type.
- instruction->ReplaceWith(instruction->GetInput());
+ HInstruction* input = instruction->GetInput();
+ Primitive::Type input_type = input->GetType();
+ Primitive::Type result_type = instruction->GetResultType();
+ if (IsTypeConversionImplicit(input_type, result_type)) {
+ // Remove the implicit conversion; this includes conversion to the same type.
+ instruction->ReplaceWith(input);
instruction->GetBlock()->RemoveInstruction(instruction);
+ RecordSimplification();
+ return;
+ }
+
+ if (input->IsTypeConversion()) {
+ HTypeConversion* input_conversion = input->AsTypeConversion();
+ HInstruction* original_input = input_conversion->GetInput();
+ Primitive::Type original_type = original_input->GetType();
+
+ // When the first conversion is lossless, a direct conversion from the original type
+ // to the final type yields the same result, even for a lossy second conversion, for
+ // example float->double->int or int->double->float.
+ bool is_first_conversion_lossless = IsTypeConversionLossless(original_type, input_type);
+
+ // For integral conversions, see if the first conversion loses only bits that the second
+ // doesn't need, i.e. the final type is no wider than the intermediate. If so, direct
+ // conversion yields the same result, for example long->int->short or int->char->short.
+ bool integral_conversions_with_non_widening_second =
+ Primitive::IsIntegralType(input_type) &&
+ Primitive::IsIntegralType(original_type) &&
+ Primitive::IsIntegralType(result_type) &&
+ Primitive::ComponentSize(result_type) <= Primitive::ComponentSize(input_type);
+
+ if (is_first_conversion_lossless || integral_conversions_with_non_widening_second) {
+ // If the merged conversion is implicit, do the simplification unconditionally.
+ if (IsTypeConversionImplicit(original_type, result_type)) {
+ instruction->ReplaceWith(original_input);
+ instruction->GetBlock()->RemoveInstruction(instruction);
+ if (!input_conversion->HasUses()) {
+ // Don't wait for DCE.
+ input_conversion->GetBlock()->RemoveInstruction(input_conversion);
+ }
+ RecordSimplification();
+ return;
+ }
+ // Otherwise simplify only if the first conversion has no other use.
+ if (input_conversion->HasOnlyOneNonEnvironmentUse()) {
+ input_conversion->ReplaceWith(original_input);
+ input_conversion->GetBlock()->RemoveInstruction(input_conversion);
+ RecordSimplification();
+ return;
+ }
+ }
}
}