summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/code_generator_arm64.cc54
-rw-r--r--compiler/optimizing/code_generator_arm_vixl.cc370
-rw-r--r--compiler/optimizing/code_generator_mips.cc122
-rw-r--r--compiler/optimizing/code_generator_mips64.cc64
-rw-r--r--compiler/optimizing/code_generator_vector_arm64.cc103
-rw-r--r--compiler/optimizing/code_generator_vector_arm_vixl.cc95
-rw-r--r--compiler/optimizing/code_generator_vector_mips.cc95
-rw-r--r--compiler/optimizing/code_generator_vector_mips64.cc95
-rw-r--r--compiler/optimizing/code_generator_vector_x86.cc62
-rw-r--r--compiler/optimizing/code_generator_vector_x86_64.cc62
-rw-r--r--compiler/optimizing/code_generator_x86.cc312
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc266
-rw-r--r--compiler/optimizing/data_type-inl.h22
-rw-r--r--compiler/optimizing/data_type.cc1
-rw-r--r--compiler/optimizing/data_type.h34
-rw-r--r--compiler/optimizing/data_type_test.cc56
-rw-r--r--compiler/optimizing/graph_visualizer.cc8
-rw-r--r--compiler/optimizing/induction_var_analysis.cc27
-rw-r--r--compiler/optimizing/induction_var_range.cc12
-rw-r--r--compiler/optimizing/instruction_simplifier.cc135
-rw-r--r--compiler/optimizing/instruction_simplifier_arm.cc56
-rw-r--r--compiler/optimizing/instruction_simplifier_arm.h57
-rw-r--r--compiler/optimizing/instruction_simplifier_arm64.cc62
-rw-r--r--compiler/optimizing/instruction_simplifier_arm64.h63
-rw-r--r--compiler/optimizing/instruction_simplifier_mips.cc142
-rw-r--r--compiler/optimizing/instruction_simplifier_mips.h47
-rw-r--r--compiler/optimizing/intrinsics.cc11
-rw-r--r--compiler/optimizing/intrinsics.h43
-rw-r--r--compiler/optimizing/load_store_elimination.cc1
-rw-r--r--compiler/optimizing/loop_optimization.cc353
-rw-r--r--compiler/optimizing/nodes.cc1
-rw-r--r--compiler/optimizing/nodes.h77
-rw-r--r--compiler/optimizing/nodes_mips.h40
-rw-r--r--compiler/optimizing/nodes_vector.h128
-rw-r--r--compiler/optimizing/nodes_vector_test.cc355
-rw-r--r--compiler/optimizing/optimizing_compiler.cc6
-rw-r--r--compiler/optimizing/register_allocation_resolver.cc1
-rw-r--r--compiler/optimizing/register_allocator_graph_color.cc1
-rw-r--r--compiler/optimizing/register_allocator_linear_scan.cc1
-rw-r--r--compiler/optimizing/scheduler_arm.cc19
-rw-r--r--compiler/optimizing/side_effects_test.cc21
-rw-r--r--compiler/optimizing/ssa_builder.cc2
42 files changed, 2103 insertions, 1379 deletions
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 42e9f68a76..468e93a8c0 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1929,17 +1929,18 @@ void CodeGeneratorARM64::Load(DataType::Type type,
const MemOperand& src) {
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
__ Ldrb(Register(dst), src);
break;
case DataType::Type::kInt8:
__ Ldrsb(Register(dst), src);
break;
- case DataType::Type::kInt16:
- __ Ldrsh(Register(dst), src);
- break;
case DataType::Type::kUint16:
__ Ldrh(Register(dst), src);
break;
+ case DataType::Type::kInt16:
+ __ Ldrsh(Register(dst), src);
+ break;
case DataType::Type::kInt32:
case DataType::Type::kReference:
case DataType::Type::kInt64:
@@ -1972,14 +1973,7 @@ void CodeGeneratorARM64::LoadAcquire(HInstruction* instruction,
MemOperand base = MemOperand(temp_base);
switch (type) {
case DataType::Type::kBool:
- {
- ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
- __ ldarb(Register(dst), base);
- if (needs_null_check) {
- MaybeRecordImplicitNullCheck(instruction);
- }
- }
- break;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
{
ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
@@ -1988,17 +1982,11 @@ void CodeGeneratorARM64::LoadAcquire(HInstruction* instruction,
MaybeRecordImplicitNullCheck(instruction);
}
}
- __ Sbfx(Register(dst), Register(dst), 0, DataType::Size(type) * kBitsPerByte);
- break;
- case DataType::Type::kUint16:
- {
- ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
- __ ldarh(Register(dst), base);
- if (needs_null_check) {
- MaybeRecordImplicitNullCheck(instruction);
- }
+ if (type == DataType::Type::kInt8) {
+ __ Sbfx(Register(dst), Register(dst), 0, DataType::Size(type) * kBitsPerByte);
}
break;
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
{
ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
@@ -2007,7 +1995,9 @@ void CodeGeneratorARM64::LoadAcquire(HInstruction* instruction,
MaybeRecordImplicitNullCheck(instruction);
}
}
- __ Sbfx(Register(dst), Register(dst), 0, DataType::Size(type) * kBitsPerByte);
+ if (type == DataType::Type::kInt16) {
+ __ Sbfx(Register(dst), Register(dst), 0, DataType::Size(type) * kBitsPerByte);
+ }
break;
case DataType::Type::kInt32:
case DataType::Type::kReference:
@@ -2048,6 +2038,7 @@ void CodeGeneratorARM64::Store(DataType::Type type,
const MemOperand& dst) {
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
__ Strb(Register(src), dst);
break;
@@ -2087,6 +2078,7 @@ void CodeGeneratorARM64::StoreRelease(HInstruction* instruction,
// Ensure that between store and MaybeRecordImplicitNullCheck there are no pools emitted.
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
{
ExactAssemblyScope eas(masm, kInstructionSize, CodeBufferCheckScope::kExactSize);
@@ -3222,9 +3214,10 @@ void LocationsBuilderARM64::VisitCompare(HCompare* compare) {
DataType::Type in_type = compare->InputAt(0)->GetType();
switch (in_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
case DataType::Type::kInt64: {
locations->SetInAt(0, Location::RequiresRegister());
@@ -3255,9 +3248,10 @@ void InstructionCodeGeneratorARM64::VisitCompare(HCompare* compare) {
// -1 if: left < right
switch (in_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
case DataType::Type::kInt64: {
Register result = OutputRegister(compare);
@@ -5744,7 +5738,8 @@ void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) {
new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
DataType::Type input_type = conversion->GetInputType();
DataType::Type result_type = conversion->GetResultType();
- DCHECK_NE(input_type, result_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
if ((input_type == DataType::Type::kReference) || (input_type == DataType::Type::kVoid) ||
(result_type == DataType::Type::kReference) || (result_type == DataType::Type::kVoid)) {
LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type;
@@ -5767,7 +5762,8 @@ void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* convers
DataType::Type result_type = conversion->GetResultType();
DataType::Type input_type = conversion->GetInputType();
- DCHECK_NE(input_type, result_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
int result_size = DataType::Size(result_type);
@@ -5784,11 +5780,9 @@ void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* convers
// 32bit input value as a 64bit value assuming that the top 32 bits are
// zero.
__ Mov(output.W(), source.W());
- } else if (result_type == DataType::Type::kUint16 ||
- (input_type == DataType::Type::kUint16 && input_size < result_size)) {
- __ Ubfx(output,
- output.IsX() ? source.X() : source.W(),
- 0, DataType::Size(DataType::Type::kUint16) * kBitsPerByte);
+ } else if (DataType::IsUnsignedType(result_type) ||
+ (DataType::IsUnsignedType(input_type) && input_size < result_size)) {
+ __ Ubfx(output, output.IsX() ? source.X() : source.W(), 0, result_size * kBitsPerByte);
} else {
__ Sbfx(output, output.IsX() ? source.X() : source.W(), 0, min_size * kBitsPerByte);
}
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 2b9e0febe8..d4fb064107 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -282,6 +282,58 @@ static size_t RestoreContiguousSRegisterList(size_t first,
return stack_offset;
}
+static LoadOperandType GetLoadOperandType(DataType::Type type) {
+ switch (type) {
+ case DataType::Type::kReference:
+ return kLoadWord;
+ case DataType::Type::kBool:
+ case DataType::Type::kUint8:
+ return kLoadUnsignedByte;
+ case DataType::Type::kInt8:
+ return kLoadSignedByte;
+ case DataType::Type::kUint16:
+ return kLoadUnsignedHalfword;
+ case DataType::Type::kInt16:
+ return kLoadSignedHalfword;
+ case DataType::Type::kInt32:
+ return kLoadWord;
+ case DataType::Type::kInt64:
+ return kLoadWordPair;
+ case DataType::Type::kFloat32:
+ return kLoadSWord;
+ case DataType::Type::kFloat64:
+ return kLoadDWord;
+ default:
+ LOG(FATAL) << "Unreachable type " << type;
+ UNREACHABLE();
+ }
+}
+
+static StoreOperandType GetStoreOperandType(DataType::Type type) {
+ switch (type) {
+ case DataType::Type::kReference:
+ return kStoreWord;
+ case DataType::Type::kBool:
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
+ return kStoreByte;
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ return kStoreHalfword;
+ case DataType::Type::kInt32:
+ return kStoreWord;
+ case DataType::Type::kInt64:
+ return kStoreWordPair;
+ case DataType::Type::kFloat32:
+ return kStoreSWord;
+ case DataType::Type::kFloat64:
+ return kStoreDWord;
+ default:
+ LOG(FATAL) << "Unreachable type " << type;
+ UNREACHABLE();
+ }
+}
+
void SlowPathCodeARMVIXL::SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) {
size_t stack_offset = codegen->GetFirstRegisterSlotInSlowPath();
size_t orig_offset = stack_offset;
@@ -2598,12 +2650,13 @@ void CodeGeneratorARMVIXL::Bind(HBasicBlock* block) {
Location InvokeDexCallingConventionVisitorARMVIXL::GetNextLocation(DataType::Type type) {
switch (type) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- case DataType::Type::kReference: {
+ case DataType::Type::kInt32: {
uint32_t index = gp_index_++;
uint32_t stack_index = stack_index_++;
if (index < calling_convention.GetNumberOfRegisters()) {
@@ -2674,12 +2727,13 @@ Location InvokeDexCallingConventionVisitorARMVIXL::GetNextLocation(DataType::Typ
Location InvokeDexCallingConventionVisitorARMVIXL::GetReturnLocation(DataType::Type type) const {
switch (type) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- case DataType::Type::kReference: {
+ case DataType::Type::kInt32: {
return LocationFrom(r0);
}
@@ -3728,7 +3782,8 @@ void InstructionCodeGeneratorARMVIXL::VisitNeg(HNeg* neg) {
void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
DataType::Type result_type = conversion->GetResultType();
DataType::Type input_type = conversion->GetInputType();
- DCHECK_NE(result_type, input_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
// The float-to-long, double-to-long and long-to-float type conversions
// rely on a call to the runtime.
@@ -3741,67 +3796,30 @@ void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
- // The Java language does not allow treating boolean as an integral type but
- // our bit representation makes it safe.
-
switch (result_type) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to byte is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-byte' instruction.
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
- break;
-
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to short is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-short' instruction.
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
+ DCHECK(DataType::IsIntegralType(input_type)) << input_type;
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
case DataType::Type::kInt32:
switch (input_type) {
case DataType::Type::kInt64:
- // Processing a Dex `long-to-int' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-int' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresRegister());
locations->AddTemp(Location::RequiresFpuRegister());
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-int' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresRegister());
locations->AddTemp(Location::RequiresFpuRegister());
@@ -3816,18 +3834,16 @@ void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
case DataType::Type::kInt64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-long' instruction.
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
case DataType::Type::kFloat32: {
- // Processing a Dex `float-to-long' instruction.
InvokeRuntimeCallingConventionARMVIXL calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0)));
locations->SetOut(LocationFrom(r0, r1));
@@ -3835,7 +3851,6 @@ void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
}
case DataType::Type::kFloat64: {
- // Processing a Dex `double-to-long' instruction.
InvokeRuntimeCallingConventionARMVIXL calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetFpuRegisterAt(0),
calling_convention.GetFpuRegisterAt(1)));
@@ -3849,41 +3864,19 @@ void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
}
break;
- case DataType::Type::kUint16:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to char is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- // Processing a Dex `int-to-char' instruction.
- locations->SetInAt(0, Location::RequiresRegister());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
- break;
-
case DataType::Type::kFloat32:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-float' instruction.
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresFpuRegister());
break;
case DataType::Type::kInt64: {
- // Processing a Dex `long-to-float' instruction.
InvokeRuntimeCallingConventionARMVIXL calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0),
calling_convention.GetRegisterAt(1)));
@@ -3892,7 +3885,6 @@ void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
}
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-float' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -3906,18 +3898,16 @@ void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
case DataType::Type::kFloat64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-double' instruction.
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresFpuRegister());
break;
case DataType::Type::kInt64:
- // Processing a Dex `long-to-double' instruction.
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresFpuRegister());
locations->AddTemp(Location::RequiresFpuRegister());
@@ -3925,7 +3915,6 @@ void LocationsBuilderARMVIXL::VisitTypeConversion(HTypeConversion* conversion) {
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-double' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -3948,22 +3937,38 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
Location in = locations->InAt(0);
DataType::Type result_type = conversion->GetResultType();
DataType::Type input_type = conversion->GetInputType();
- DCHECK_NE(result_type, input_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
switch (result_type) {
- case DataType::Type::kInt8:
+ case DataType::Type::kUint8:
switch (input_type) {
+ case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ case DataType::Type::kInt32:
+ __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 8);
+ break;
case DataType::Type::kInt64:
- // Type conversion from long to byte is a result of code transformations.
- __ Sbfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 8);
+ __ Ubfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 8);
break;
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case DataType::Type::kInt8:
+ switch (input_type) {
+ case DataType::Type::kUint8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-byte' instruction.
__ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 8);
break;
+ case DataType::Type::kInt64:
+ __ Sbfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 8);
+ break;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
@@ -3971,20 +3976,32 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
}
break;
- case DataType::Type::kInt16:
+ case DataType::Type::kUint16:
switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to short is a result of code transformations.
- __ Sbfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 16);
- break;
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
case DataType::Type::kInt8:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
+ __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 16);
+ break;
+ case DataType::Type::kInt64:
+ __ Ubfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 16);
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case DataType::Type::kInt16:
+ switch (input_type) {
case DataType::Type::kUint16:
- // Processing a Dex `int-to-short' instruction.
+ case DataType::Type::kInt32:
__ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 16);
break;
+ case DataType::Type::kInt64:
+ __ Sbfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 16);
+ break;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
@@ -3995,7 +4012,6 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
case DataType::Type::kInt32:
switch (input_type) {
case DataType::Type::kInt64:
- // Processing a Dex `long-to-int' instruction.
DCHECK(out.IsRegister());
if (in.IsRegisterPair()) {
__ Mov(OutputRegister(conversion), LowRegisterFrom(in));
@@ -4013,7 +4029,6 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
break;
case DataType::Type::kFloat32: {
- // Processing a Dex `float-to-int' instruction.
vixl32::SRegister temp = LowSRegisterFrom(locations->GetTemp(0));
__ Vcvt(S32, F32, temp, InputSRegisterAt(conversion, 0));
__ Vmov(OutputRegister(conversion), temp);
@@ -4021,7 +4036,6 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
}
case DataType::Type::kFloat64: {
- // Processing a Dex `double-to-int' instruction.
vixl32::SRegister temp_s = LowSRegisterFrom(locations->GetTemp(0));
__ Vcvt(S32, F64, temp_s, DRegisterFrom(in));
__ Vmov(OutputRegister(conversion), temp_s);
@@ -4037,12 +4051,11 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
case DataType::Type::kInt64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-long' instruction.
DCHECK(out.IsRegisterPair());
DCHECK(in.IsRegister());
__ Mov(LowRegisterFrom(out), InputRegisterAt(conversion, 0));
@@ -4051,13 +4064,11 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-long' instruction.
codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
CheckEntrypointTypes<kQuickF2l, int64_t, float>();
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-long' instruction.
codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
CheckEntrypointTypes<kQuickD2l, int64_t, double>();
break;
@@ -4068,49 +4079,24 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
}
break;
- case DataType::Type::kUint16:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to char is a result of code transformations.
- __ Ubfx(OutputRegister(conversion), LowRegisterFrom(in), 0, 16);
- break;
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- // Processing a Dex `int-to-char' instruction.
- __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, 16);
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
- break;
-
case DataType::Type::kFloat32:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16: {
- // Processing a Dex `int-to-float' instruction.
__ Vmov(OutputSRegister(conversion), InputRegisterAt(conversion, 0));
__ Vcvt(F32, S32, OutputSRegister(conversion), OutputSRegister(conversion));
break;
- }
case DataType::Type::kInt64:
- // Processing a Dex `long-to-float' instruction.
codegen_->InvokeRuntime(kQuickL2f, conversion, conversion->GetDexPc());
CheckEntrypointTypes<kQuickL2f, float, int64_t>();
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-float' instruction.
__ Vcvt(F32, F64, OutputSRegister(conversion), DRegisterFrom(in));
break;
@@ -4123,19 +4109,16 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
case DataType::Type::kFloat64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16: {
- // Processing a Dex `int-to-double' instruction.
__ Vmov(LowSRegisterFrom(out), InputRegisterAt(conversion, 0));
__ Vcvt(F64, S32, DRegisterFrom(out), LowSRegisterFrom(out));
break;
- }
case DataType::Type::kInt64: {
- // Processing a Dex `long-to-double' instruction.
vixl32::Register low = LowRegisterFrom(in);
vixl32::Register high = HighRegisterFrom(in);
vixl32::SRegister out_s = LowSRegisterFrom(out);
@@ -4158,7 +4141,6 @@ void InstructionCodeGeneratorARMVIXL::VisitTypeConversion(HTypeConversion* conve
}
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-double' instruction.
__ Vcvt(F64, F32, DRegisterFrom(out), InputSRegisterAt(conversion, 0));
break;
@@ -4760,6 +4742,7 @@ void InstructionCodeGeneratorARMVIXL::VisitDivZeroCheck(HDivZeroCheck* instructi
switch (instruction->GetType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -5288,9 +5271,10 @@ void LocationsBuilderARMVIXL::VisitCompare(HCompare* compare) {
new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
switch (compare->InputAt(0)->GetType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
case DataType::Type::kInt64: {
locations->SetInAt(0, Location::RequiresRegister());
@@ -5323,9 +5307,10 @@ void InstructionCodeGeneratorARMVIXL::VisitCompare(HCompare* compare) {
vixl32::Condition less_cond = vixl32::Condition(kNone);
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32: {
// Emit move to `out` before the `Cmp`, as `Mov` might affect the status flags.
__ Mov(out, 0);
@@ -5513,18 +5498,16 @@ void InstructionCodeGeneratorARMVIXL::HandleFieldSet(HInstruction* instruction,
switch (field_type) {
case DataType::Type::kBool:
- case DataType::Type::kInt8: {
- GetAssembler()->StoreToOffset(kStoreByte, RegisterFrom(value), base, offset);
- break;
- }
-
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
- case DataType::Type::kUint16: {
- GetAssembler()->StoreToOffset(kStoreHalfword, RegisterFrom(value), base, offset);
+ case DataType::Type::kInt32: {
+ StoreOperandType operand_type = GetStoreOperandType(field_type);
+ GetAssembler()->StoreToOffset(operand_type, RegisterFrom(value), base, offset);
break;
}
- case DataType::Type::kInt32:
case DataType::Type::kReference: {
if (kPoisonHeapReferences && needs_write_barrier) {
// Note that in the case where `value` is a null reference,
@@ -5764,24 +5747,15 @@ void InstructionCodeGeneratorARMVIXL::HandleFieldGet(HInstruction* instruction,
switch (field_type) {
case DataType::Type::kBool:
- GetAssembler()->LoadFromOffset(kLoadUnsignedByte, RegisterFrom(out), base, offset);
- break;
-
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- GetAssembler()->LoadFromOffset(kLoadSignedByte, RegisterFrom(out), base, offset);
- break;
-
- case DataType::Type::kInt16:
- GetAssembler()->LoadFromOffset(kLoadSignedHalfword, RegisterFrom(out), base, offset);
- break;
-
case DataType::Type::kUint16:
- GetAssembler()->LoadFromOffset(kLoadUnsignedHalfword, RegisterFrom(out), base, offset);
- break;
-
- case DataType::Type::kInt32:
- GetAssembler()->LoadFromOffset(kLoadWord, RegisterFrom(out), base, offset);
+ case DataType::Type::kInt16:
+ case DataType::Type::kInt32: {
+ LoadOperandType operand_type = GetLoadOperandType(field_type);
+ GetAssembler()->LoadFromOffset(operand_type, RegisterFrom(out), base, offset);
break;
+ }
case DataType::Type::kReference: {
// /* HeapReference<Object> */ out = *(base + offset)
@@ -5995,56 +5969,6 @@ void InstructionCodeGeneratorARMVIXL::VisitNullCheck(HNullCheck* instruction) {
codegen_->GenerateNullCheck(instruction);
}
-static LoadOperandType GetLoadOperandType(DataType::Type type) {
- switch (type) {
- case DataType::Type::kReference:
- return kLoadWord;
- case DataType::Type::kBool:
- return kLoadUnsignedByte;
- case DataType::Type::kInt8:
- return kLoadSignedByte;
- case DataType::Type::kUint16:
- return kLoadUnsignedHalfword;
- case DataType::Type::kInt16:
- return kLoadSignedHalfword;
- case DataType::Type::kInt32:
- return kLoadWord;
- case DataType::Type::kInt64:
- return kLoadWordPair;
- case DataType::Type::kFloat32:
- return kLoadSWord;
- case DataType::Type::kFloat64:
- return kLoadDWord;
- default:
- LOG(FATAL) << "Unreachable type " << type;
- UNREACHABLE();
- }
-}
-
-static StoreOperandType GetStoreOperandType(DataType::Type type) {
- switch (type) {
- case DataType::Type::kReference:
- return kStoreWord;
- case DataType::Type::kBool:
- case DataType::Type::kInt8:
- return kStoreByte;
- case DataType::Type::kUint16:
- case DataType::Type::kInt16:
- return kStoreHalfword;
- case DataType::Type::kInt32:
- return kStoreWord;
- case DataType::Type::kInt64:
- return kStoreWordPair;
- case DataType::Type::kFloat32:
- return kStoreSWord;
- case DataType::Type::kFloat64:
- return kStoreDWord;
- default:
- LOG(FATAL) << "Unreachable type " << type;
- UNREACHABLE();
- }
-}
-
void CodeGeneratorARMVIXL::LoadFromShiftedRegOffset(DataType::Type type,
Location out_loc,
vixl32::Register base,
@@ -6054,18 +5978,19 @@ void CodeGeneratorARMVIXL::LoadFromShiftedRegOffset(DataType::Type type,
MemOperand mem_address(base, reg_index, vixl32::LSL, shift_count);
switch (type) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
__ Ldrsb(cond, RegisterFrom(out_loc), mem_address);
break;
case DataType::Type::kBool:
__ Ldrb(cond, RegisterFrom(out_loc), mem_address);
break;
- case DataType::Type::kInt16:
- __ Ldrsh(cond, RegisterFrom(out_loc), mem_address);
- break;
case DataType::Type::kUint16:
__ Ldrh(cond, RegisterFrom(out_loc), mem_address);
break;
+ case DataType::Type::kInt16:
+ __ Ldrsh(cond, RegisterFrom(out_loc), mem_address);
+ break;
case DataType::Type::kReference:
case DataType::Type::kInt32:
__ Ldr(cond, RegisterFrom(out_loc), mem_address);
@@ -6089,12 +6014,13 @@ void CodeGeneratorARMVIXL::StoreToShiftedRegOffset(DataType::Type type,
MemOperand mem_address(base, reg_index, vixl32::LSL, shift_count);
switch (type) {
- case DataType::Type::kInt8:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
__ Strb(cond, RegisterFrom(loc), mem_address);
break;
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
__ Strh(cond, RegisterFrom(loc), mem_address);
break;
case DataType::Type::kReference:
@@ -6182,9 +6108,10 @@ void InstructionCodeGeneratorARMVIXL::VisitArrayGet(HArrayGet* instruction) {
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32: {
vixl32::Register length;
if (maybe_compressed_char_at) {
@@ -6434,9 +6361,10 @@ void InstructionCodeGeneratorARMVIXL::VisitArraySet(HArraySet* instruction) {
switch (value_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32: {
if (index.IsConstant()) {
int32_t const_index = Int32ConstantFrom(index);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index a7c85574ee..3c592e7e37 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -51,12 +51,13 @@ constexpr bool kBakerReadBarrierThunksEnableForGcRoots = true;
Location MipsReturnLocation(DataType::Type return_type) {
switch (return_type) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kReference:
return Location::RegisterLocation(V0);
case DataType::Type::kInt64:
@@ -84,12 +85,13 @@ Location InvokeDexCallingConventionVisitorMIPS::GetNextLocation(DataType::Type t
Location next_location;
switch (type) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- case DataType::Type::kReference: {
+ case DataType::Type::kInt32: {
uint32_t gp_index = gp_index_++;
if (gp_index < calling_convention.GetNumberOfRegisters()) {
next_location = Location::RegisterLocation(calling_convention.GetRegisterAt(gp_index));
@@ -2592,7 +2594,8 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
instruction->IsStringCharAt();
switch (type) {
- case DataType::Type::kBool: {
+ case DataType::Type::kBool:
+ case DataType::Type::kUint8: {
Register out = out_loc.AsRegister<Register>();
if (index.IsConstant()) {
size_t offset =
@@ -2618,19 +2621,6 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
break;
}
- case DataType::Type::kInt16: {
- Register out = out_loc.AsRegister<Register>();
- if (index.IsConstant()) {
- size_t offset =
- (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
- __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
- } else {
- __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_2, TMP);
- __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
- }
- break;
- }
-
case DataType::Type::kUint16: {
Register out = out_loc.AsRegister<Register>();
if (maybe_compressed_char_at) {
@@ -2675,6 +2665,9 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
__ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
__ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset);
__ Bind(&done);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index_reg, obj);
+ __ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index_reg, obj, TIMES_2, TMP);
__ LoadFromOffset(kLoadUnsignedHalfword, out, TMP, data_offset, null_checker);
@@ -2683,6 +2676,22 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
break;
}
+ case DataType::Type::kInt16: {
+ Register out = out_loc.AsRegister<Register>();
+ if (index.IsConstant()) {
+ size_t offset =
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+ __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
+ } else {
+ __ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_2, TMP);
+ __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
+ }
+ break;
+ }
+
case DataType::Type::kInt32: {
DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
Register out = out_loc.AsRegister<Register>();
@@ -2690,6 +2699,9 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
__ LoadFromOffset(kLoadWord, out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
__ LoadFromOffset(kLoadWord, out, TMP, data_offset, null_checker);
@@ -2763,6 +2775,9 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
__ LoadFromOffset(kLoadDoubleword, out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
__ LoadFromOffset(kLoadDoubleword, out, TMP, data_offset, null_checker);
@@ -2776,6 +2791,9 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
__ LoadSFromOffset(out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadSFromOffset(out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_4, TMP);
__ LoadSFromOffset(out, TMP, data_offset, null_checker);
@@ -2789,6 +2807,9 @@ void InstructionCodeGeneratorMIPS::VisitArrayGet(HArrayGet* instruction) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
__ LoadDFromOffset(out, obj, offset, null_checker);
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(TMP, index.AsRegister<Register>(), obj);
+ __ LoadDFromOffset(out, TMP, data_offset, null_checker);
} else {
__ ShiftAndAdd(TMP, index.AsRegister<Register>(), obj, TIMES_8, TMP);
__ LoadDFromOffset(out, TMP, data_offset, null_checker);
@@ -2880,6 +2901,7 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
switch (value_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8: {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
if (index.IsConstant()) {
@@ -2897,11 +2919,13 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
break;
}
- case DataType::Type::kInt16:
- case DataType::Type::kUint16: {
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16: {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_2, base_reg);
}
@@ -2919,6 +2943,8 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
@@ -2968,6 +2994,8 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
@@ -3051,6 +3079,8 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
}
@@ -3068,6 +3098,8 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_4, base_reg);
}
@@ -3085,6 +3117,8 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8;
+ } else if (instruction->InputAt(1)->IsIntermediateArrayAddressIndex()) {
+ __ Addu(base_reg, index.AsRegister<Register>(), obj);
} else {
__ ShiftAndAdd(base_reg, index.AsRegister<Register>(), obj, TIMES_8, base_reg);
}
@@ -3104,6 +3138,26 @@ void InstructionCodeGeneratorMIPS::VisitArraySet(HArraySet* instruction) {
}
}
+void LocationsBuilderMIPS::VisitIntermediateArrayAddressIndex(
+ HIntermediateArrayAddressIndex* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+
+ HIntConstant* shift = instruction->GetShift()->AsIntConstant();
+
+ locations->SetInAt(0, Location::RequiresRegister());
+ locations->SetInAt(1, Location::ConstantLocation(shift));
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
+}
+
+void InstructionCodeGeneratorMIPS::VisitIntermediateArrayAddressIndex(
+ HIntermediateArrayAddressIndex* instruction) {
+ LocationSummary* locations = instruction->GetLocations();
+ Register index_reg = locations->InAt(0).AsRegister<Register>();
+ uint32_t shift = instruction->GetShift()->AsIntConstant()->GetValue();
+ __ Sll(locations->Out().AsRegister<Register>(), index_reg, shift);
+}
+
void LocationsBuilderMIPS::VisitBoundsCheck(HBoundsCheck* instruction) {
RegisterSet caller_saves = RegisterSet::Empty();
InvokeRuntimeCallingConvention calling_convention;
@@ -3390,9 +3444,10 @@ void LocationsBuilderMIPS::VisitCompare(HCompare* compare) {
switch (in_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
locations->SetInAt(0, Location::RequiresRegister());
locations->SetInAt(1, Location::RequiresRegister());
@@ -3429,9 +3484,10 @@ void InstructionCodeGeneratorMIPS::VisitCompare(HCompare* instruction) {
// -1 if: left < right
switch (in_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32: {
Register lhs = locations->InAt(0).AsRegister<Register>();
Register rhs = locations->InAt(1).AsRegister<Register>();
@@ -3833,6 +3889,7 @@ void InstructionCodeGeneratorMIPS::VisitDivZeroCheck(HDivZeroCheck* instruction)
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -6159,17 +6216,18 @@ void InstructionCodeGeneratorMIPS::HandleFieldGet(HInstruction* instruction,
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
load_type = kLoadUnsignedByte;
break;
case DataType::Type::kInt8:
load_type = kLoadSignedByte;
break;
- case DataType::Type::kInt16:
- load_type = kLoadSignedHalfword;
- break;
case DataType::Type::kUint16:
load_type = kLoadUnsignedHalfword;
break;
+ case DataType::Type::kInt16:
+ load_type = kLoadSignedHalfword;
+ break;
case DataType::Type::kInt32:
case DataType::Type::kFloat32:
case DataType::Type::kReference:
@@ -6312,11 +6370,12 @@ void InstructionCodeGeneratorMIPS::HandleFieldSet(HInstruction* instruction,
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
store_type = kStoreByte;
break;
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
store_type = kStoreHalfword;
break;
case DataType::Type::kInt32:
@@ -8601,7 +8660,8 @@ void InstructionCodeGeneratorMIPS::VisitThrow(HThrow* instruction) {
void LocationsBuilderMIPS::VisitTypeConversion(HTypeConversion* conversion) {
DataType::Type input_type = conversion->GetInputType();
DataType::Type result_type = conversion->GetResultType();
- DCHECK_NE(input_type, result_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
if ((input_type == DataType::Type::kReference) || (input_type == DataType::Type::kVoid) ||
@@ -8652,7 +8712,8 @@ void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversi
bool has_sign_extension = codegen_->GetInstructionSetFeatures().IsMipsIsaRevGreaterThanEqual2();
bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
- DCHECK_NE(input_type, result_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
if (result_type == DataType::Type::kInt64 && DataType::IsIntegralType(input_type)) {
Register dst_high = locations->Out().AsRegisterPairHigh<Register>();
@@ -8670,8 +8731,8 @@ void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversi
: locations->InAt(0).AsRegister<Register>();
switch (result_type) {
- case DataType::Type::kUint16:
- __ Andi(dst, src, 0xFFFF);
+ case DataType::Type::kUint8:
+ __ Andi(dst, src, 0xFF);
break;
case DataType::Type::kInt8:
if (has_sign_extension) {
@@ -8681,6 +8742,9 @@ void InstructionCodeGeneratorMIPS::VisitTypeConversion(HTypeConversion* conversi
__ Sra(dst, dst, 24);
}
break;
+ case DataType::Type::kUint16:
+ __ Andi(dst, src, 0xFFFF);
+ break;
case DataType::Type::kInt16:
if (has_sign_extension) {
__ Seh(dst, src);
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 7051ccefdc..687700380b 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -50,6 +50,7 @@ constexpr bool kBakerReadBarrierThunksEnableForGcRoots = true;
Location Mips64ReturnLocation(DataType::Type return_type) {
switch (return_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -2170,7 +2171,8 @@ void InstructionCodeGeneratorMIPS64::VisitArrayGet(HArrayGet* instruction) {
const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
instruction->IsStringCharAt();
switch (type) {
- case DataType::Type::kBool: {
+ case DataType::Type::kBool:
+ case DataType::Type::kUint8: {
GpuRegister out = out_loc.AsRegister<GpuRegister>();
if (index.IsConstant()) {
size_t offset =
@@ -2196,19 +2198,6 @@ void InstructionCodeGeneratorMIPS64::VisitArrayGet(HArrayGet* instruction) {
break;
}
- case DataType::Type::kInt16: {
- GpuRegister out = out_loc.AsRegister<GpuRegister>();
- if (index.IsConstant()) {
- size_t offset =
- (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
- __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
- } else {
- __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_2);
- __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
- }
- break;
- }
-
case DataType::Type::kUint16: {
GpuRegister out = out_loc.AsRegister<GpuRegister>();
if (maybe_compressed_char_at) {
@@ -2261,6 +2250,19 @@ void InstructionCodeGeneratorMIPS64::VisitArrayGet(HArrayGet* instruction) {
break;
}
+ case DataType::Type::kInt16: {
+ GpuRegister out = out_loc.AsRegister<GpuRegister>();
+ if (index.IsConstant()) {
+ size_t offset =
+ (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
+ __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset, null_checker);
+ } else {
+ __ Dlsa(TMP, index.AsRegister<GpuRegister>(), obj, TIMES_2);
+ __ LoadFromOffset(kLoadSignedHalfword, out, TMP, data_offset, null_checker);
+ }
+ break;
+ }
+
case DataType::Type::kInt32: {
DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
GpuRegister out = out_loc.AsRegister<GpuRegister>();
@@ -2460,6 +2462,7 @@ void InstructionCodeGeneratorMIPS64::VisitArraySet(HArraySet* instruction) {
switch (value_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8: {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
if (index.IsConstant()) {
@@ -2477,8 +2480,8 @@ void InstructionCodeGeneratorMIPS64::VisitArraySet(HArraySet* instruction) {
break;
}
- case DataType::Type::kInt16:
- case DataType::Type::kUint16: {
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16: {
uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
if (index.IsConstant()) {
data_offset += index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2;
@@ -2969,9 +2972,10 @@ void LocationsBuilderMIPS64::VisitCompare(HCompare* compare) {
switch (in_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
case DataType::Type::kInt64:
locations->SetInAt(0, Location::RequiresRegister());
@@ -3001,9 +3005,10 @@ void InstructionCodeGeneratorMIPS64::VisitCompare(HCompare* instruction) {
// -1 if: left < right
switch (in_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
case DataType::Type::kInt64: {
GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
@@ -4681,17 +4686,18 @@ void InstructionCodeGeneratorMIPS64::HandleFieldGet(HInstruction* instruction,
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
load_type = kLoadUnsignedByte;
break;
case DataType::Type::kInt8:
load_type = kLoadSignedByte;
break;
- case DataType::Type::kInt16:
- load_type = kLoadSignedHalfword;
- break;
case DataType::Type::kUint16:
load_type = kLoadUnsignedHalfword;
break;
+ case DataType::Type::kInt16:
+ load_type = kLoadSignedHalfword;
+ break;
case DataType::Type::kInt32:
case DataType::Type::kFloat32:
load_type = kLoadWord;
@@ -4779,11 +4785,12 @@ void InstructionCodeGeneratorMIPS64::HandleFieldSet(HInstruction* instruction,
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
store_type = kStoreByte;
break;
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
store_type = kStoreHalfword;
break;
case DataType::Type::kInt32:
@@ -6767,7 +6774,8 @@ void InstructionCodeGeneratorMIPS64::VisitThrow(HThrow* instruction) {
void LocationsBuilderMIPS64::VisitTypeConversion(HTypeConversion* conversion) {
DataType::Type input_type = conversion->GetInputType();
DataType::Type result_type = conversion->GetResultType();
- DCHECK_NE(input_type, result_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
if ((input_type == DataType::Type::kReference) || (input_type == DataType::Type::kVoid) ||
(result_type == DataType::Type::kReference) || (result_type == DataType::Type::kVoid)) {
@@ -6794,15 +6802,16 @@ void InstructionCodeGeneratorMIPS64::VisitTypeConversion(HTypeConversion* conver
DataType::Type result_type = conversion->GetResultType();
DataType::Type input_type = conversion->GetInputType();
- DCHECK_NE(input_type, result_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
if (DataType::IsIntegralType(result_type) && DataType::IsIntegralType(input_type)) {
GpuRegister dst = locations->Out().AsRegister<GpuRegister>();
GpuRegister src = locations->InAt(0).AsRegister<GpuRegister>();
switch (result_type) {
- case DataType::Type::kUint16:
- __ Andi(dst, src, 0xFFFF);
+ case DataType::Type::kUint8:
+ __ Andi(dst, src, 0xFF);
break;
case DataType::Type::kInt8:
if (input_type == DataType::Type::kInt64) {
@@ -6815,6 +6824,9 @@ void InstructionCodeGeneratorMIPS64::VisitTypeConversion(HTypeConversion* conver
__ Seb(dst, src);
}
break;
+ case DataType::Type::kUint16:
+ __ Andi(dst, src, 0xFFFF);
+ break;
case DataType::Type::kInt16:
if (input_type == DataType::Type::kInt64) {
// Type conversion from long to types narrower than int is a result of code
diff --git a/compiler/optimizing/code_generator_vector_arm64.cc b/compiler/optimizing/code_generator_vector_arm64.cc
index 5d5623bbe7..b2aec1e66d 100644
--- a/compiler/optimizing/code_generator_vector_arm64.cc
+++ b/compiler/optimizing/code_generator_vector_arm64.cc
@@ -42,6 +42,7 @@ void LocationsBuilderARM64::VisitVecReplicateScalar(HVecReplicateScalar* instruc
HInstruction* input = instruction->InputAt(0);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -73,6 +74,7 @@ void InstructionCodeGeneratorARM64::VisitVecReplicateScalar(HVecReplicateScalar*
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
if (src_loc.IsConstant()) {
@@ -132,6 +134,7 @@ void LocationsBuilderARM64::VisitVecExtractScalar(HVecExtractScalar* instruction
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -185,6 +188,7 @@ static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* in
instruction->IsVecNot() ? Location::kOutputOverlap
: Location::kNoOutputOverlap);
break;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -268,6 +272,7 @@ void InstructionCodeGeneratorARM64::VisitVecNeg(HVecNeg* instruction) {
VRegister src = VRegisterFrom(locations->InAt(0));
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ Neg(dst.V16B(), src.V16B());
@@ -312,7 +317,6 @@ void InstructionCodeGeneratorARM64::VisitVecAbs(HVecAbs* instruction) {
DCHECK_EQ(16u, instruction->GetVectorLength());
__ Abs(dst.V16B(), src.V16B());
break;
- case DataType::Type::kUint16:
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Abs(dst.V8H(), src.V8H());
@@ -353,6 +357,7 @@ void InstructionCodeGeneratorARM64::VisitVecNot(HVecNot* instruction) {
__ Movi(dst.V16B(), 1);
__ Eor(dst.V16B(), dst.V16B(), src.V16B());
break;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -371,6 +376,7 @@ static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation*
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -398,6 +404,7 @@ void InstructionCodeGeneratorARM64::VisitVecAdd(HVecAdd* instruction) {
VRegister rhs = VRegisterFrom(locations->InAt(1));
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ Add(dst.V16B(), lhs.V16B(), rhs.V16B());
@@ -439,30 +446,29 @@ void InstructionCodeGeneratorARM64::VisitVecHalvingAdd(HVecHalvingAdd* instructi
VRegister rhs = VRegisterFrom(locations->InAt(1));
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ instruction->IsRounded()
+ ? __ Urhadd(dst.V16B(), lhs.V16B(), rhs.V16B())
+ : __ Uhadd(dst.V16B(), lhs.V16B(), rhs.V16B());
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- instruction->IsRounded()
- ? __ Urhadd(dst.V16B(), lhs.V16B(), rhs.V16B())
- : __ Uhadd(dst.V16B(), lhs.V16B(), rhs.V16B());
- } else {
- instruction->IsRounded()
- ? __ Srhadd(dst.V16B(), lhs.V16B(), rhs.V16B())
- : __ Shadd(dst.V16B(), lhs.V16B(), rhs.V16B());
- }
+ instruction->IsRounded()
+ ? __ Srhadd(dst.V16B(), lhs.V16B(), rhs.V16B())
+ : __ Shadd(dst.V16B(), lhs.V16B(), rhs.V16B());
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ instruction->IsRounded()
+ ? __ Urhadd(dst.V8H(), lhs.V8H(), rhs.V8H())
+ : __ Uhadd(dst.V8H(), lhs.V8H(), rhs.V8H());
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- instruction->IsRounded()
- ? __ Urhadd(dst.V8H(), lhs.V8H(), rhs.V8H())
- : __ Uhadd(dst.V8H(), lhs.V8H(), rhs.V8H());
- } else {
- instruction->IsRounded()
- ? __ Srhadd(dst.V8H(), lhs.V8H(), rhs.V8H())
- : __ Shadd(dst.V8H(), lhs.V8H(), rhs.V8H());
- }
+ instruction->IsRounded()
+ ? __ Srhadd(dst.V8H(), lhs.V8H(), rhs.V8H())
+ : __ Shadd(dst.V8H(), lhs.V8H(), rhs.V8H());
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -480,6 +486,7 @@ void InstructionCodeGeneratorARM64::VisitVecSub(HVecSub* instruction) {
VRegister rhs = VRegisterFrom(locations->InAt(1));
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ Sub(dst.V16B(), lhs.V16B(), rhs.V16B());
@@ -521,6 +528,7 @@ void InstructionCodeGeneratorARM64::VisitVecMul(HVecMul* instruction) {
VRegister rhs = VRegisterFrom(locations->InAt(1));
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ Mul(dst.V16B(), lhs.V16B(), rhs.V16B());
@@ -582,22 +590,21 @@ void InstructionCodeGeneratorARM64::VisitVecMin(HVecMin* instruction) {
VRegister rhs = VRegisterFrom(locations->InAt(1));
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Umin(dst.V16B(), lhs.V16B(), rhs.V16B());
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Umin(dst.V16B(), lhs.V16B(), rhs.V16B());
- } else {
- __ Smin(dst.V16B(), lhs.V16B(), rhs.V16B());
- }
+ __ Smin(dst.V16B(), lhs.V16B(), rhs.V16B());
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Umin(dst.V8H(), lhs.V8H(), rhs.V8H());
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Umin(dst.V8H(), lhs.V8H(), rhs.V8H());
- } else {
- __ Smin(dst.V8H(), lhs.V8H(), rhs.V8H());
- }
+ __ Smin(dst.V8H(), lhs.V8H(), rhs.V8H());
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -633,22 +640,21 @@ void InstructionCodeGeneratorARM64::VisitVecMax(HVecMax* instruction) {
VRegister rhs = VRegisterFrom(locations->InAt(1));
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Umax(dst.V16B(), lhs.V16B(), rhs.V16B());
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Umax(dst.V16B(), lhs.V16B(), rhs.V16B());
- } else {
- __ Smax(dst.V16B(), lhs.V16B(), rhs.V16B());
- }
+ __ Smax(dst.V16B(), lhs.V16B(), rhs.V16B());
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Umax(dst.V8H(), lhs.V8H(), rhs.V8H());
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Umax(dst.V8H(), lhs.V8H(), rhs.V8H());
- } else {
- __ Smax(dst.V8H(), lhs.V8H(), rhs.V8H());
- }
+ __ Smax(dst.V8H(), lhs.V8H(), rhs.V8H());
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -675,6 +681,7 @@ void InstructionCodeGeneratorARM64::VisitVecMax(HVecMax* instruction) {
}
void LocationsBuilderARM64::VisitVecAnd(HVecAnd* instruction) {
+ // TODO: Allow constants supported by BIC (vector, immediate).
CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
}
@@ -685,6 +692,7 @@ void InstructionCodeGeneratorARM64::VisitVecAnd(HVecAnd* instruction) {
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -705,6 +713,7 @@ void LocationsBuilderARM64::VisitVecAndNot(HVecAndNot* instruction) {
}
void InstructionCodeGeneratorARM64::VisitVecAndNot(HVecAndNot* instruction) {
+ // TODO: Use BIC (vector, register).
LOG(FATAL) << "Unsupported SIMD instruction " << instruction->GetId();
}
@@ -719,6 +728,7 @@ void InstructionCodeGeneratorARM64::VisitVecOr(HVecOr* instruction) {
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -745,6 +755,7 @@ void InstructionCodeGeneratorARM64::VisitVecXor(HVecXor* instruction) {
VRegister dst = VRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -764,6 +775,7 @@ void InstructionCodeGeneratorARM64::VisitVecXor(HVecXor* instruction) {
static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -789,6 +801,7 @@ void InstructionCodeGeneratorARM64::VisitVecShl(HVecShl* instruction) {
VRegister dst = VRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ Shl(dst.V16B(), lhs.V16B(), value);
@@ -822,6 +835,7 @@ void InstructionCodeGeneratorARM64::VisitVecShr(HVecShr* instruction) {
VRegister dst = VRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ Sshr(dst.V16B(), lhs.V16B(), value);
@@ -855,6 +869,7 @@ void InstructionCodeGeneratorARM64::VisitVecUShr(HVecUShr* instruction) {
VRegister dst = VRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ Ushr(dst.V16B(), lhs.V16B(), value);
@@ -888,6 +903,7 @@ void LocationsBuilderARM64::VisitVecSetScalars(HVecSetScalars* instruction) {
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -926,6 +942,7 @@ void InstructionCodeGeneratorARM64::VisitVecSetScalars(HVecSetScalars* instructi
// Set required elements.
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ Mov(dst.V16B(), 0, InputRegisterAt(instruction, 0));
@@ -953,6 +970,7 @@ void InstructionCodeGeneratorARM64::VisitVecSetScalars(HVecSetScalars* instructi
static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -985,6 +1003,7 @@ void InstructionCodeGeneratorARM64::VisitVecMultiplyAccumulate(HVecMultiplyAccum
DCHECK(locations->InAt(0).Equals(locations->Out()));
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
if (instruction->GetOpKind() == HInstruction::kAdd) {
@@ -1024,6 +1043,7 @@ void LocationsBuilderARM64::VisitVecSADAccumulate(HVecSADAccumulate* instruction
HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
DCHECK_EQ(a->GetPackedType(), b->GetPackedType());
switch (a->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
switch (instruction->GetPackedType()) {
case DataType::Type::kInt64:
@@ -1069,10 +1089,10 @@ void InstructionCodeGeneratorARM64::VisitVecSADAccumulate(HVecSADAccumulate* ins
HVecOperation* b = instruction->InputAt(2)->AsVecOperation();
DCHECK_EQ(a->GetPackedType(), b->GetPackedType());
switch (a->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, a->GetVectorLength());
switch (instruction->GetPackedType()) {
- case DataType::Type::kUint16:
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Sabal(acc.V8H(), left.V8B(), right.V8B());
@@ -1202,6 +1222,7 @@ static void CreateVecMemLocations(ArenaAllocator* arena,
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -1300,6 +1321,7 @@ void InstructionCodeGeneratorARM64::VisitVecLoad(HVecLoad* instruction) {
}
FALLTHROUGH_INTENDED;
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
@@ -1329,6 +1351,7 @@ void InstructionCodeGeneratorARM64::VisitVecStore(HVecStore* instruction) {
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
diff --git a/compiler/optimizing/code_generator_vector_arm_vixl.cc b/compiler/optimizing/code_generator_vector_arm_vixl.cc
index 333d108f2c..df757524a1 100644
--- a/compiler/optimizing/code_generator_vector_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_vector_arm_vixl.cc
@@ -36,6 +36,7 @@ void LocationsBuilderARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instr
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -54,6 +55,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecReplicateScalar(HVecReplicateScala
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Vdup(Untyped8, dst, InputRegisterAt(instruction, 0));
@@ -91,6 +93,7 @@ static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* in
instruction->IsVecNot() ? Location::kOutputOverlap
: Location::kNoOutputOverlap);
break;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -129,6 +132,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecNeg(HVecNeg* instruction) {
vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Vneg(DataTypeValue::S8, dst, src);
@@ -161,7 +165,6 @@ void InstructionCodeGeneratorARMVIXL::VisitVecAbs(HVecAbs* instruction) {
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Vabs(DataTypeValue::S8, dst, src);
break;
- case DataType::Type::kUint16:
case DataType::Type::kInt16:
DCHECK_EQ(4u, instruction->GetVectorLength());
__ Vabs(DataTypeValue::S16, dst, src);
@@ -190,6 +193,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecNot(HVecNot* instruction) {
__ Vmov(I8, dst, 1);
__ Veor(dst, dst, src);
break;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -207,6 +211,7 @@ static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation*
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -231,6 +236,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecAdd(HVecAdd* instruction) {
vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Vadd(I8, dst, lhs, rhs);
@@ -260,30 +266,29 @@ void InstructionCodeGeneratorARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruc
vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ instruction->IsRounded()
+ ? __ Vrhadd(DataTypeValue::U8, dst, lhs, rhs)
+ : __ Vhadd(DataTypeValue::U8, dst, lhs, rhs);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- instruction->IsRounded()
- ? __ Vrhadd(DataTypeValue::U8, dst, lhs, rhs)
- : __ Vhadd(DataTypeValue::U8, dst, lhs, rhs);
- } else {
- instruction->IsRounded()
- ? __ Vrhadd(DataTypeValue::S8, dst, lhs, rhs)
- : __ Vhadd(DataTypeValue::S8, dst, lhs, rhs);
- }
+ instruction->IsRounded()
+ ? __ Vrhadd(DataTypeValue::S8, dst, lhs, rhs)
+ : __ Vhadd(DataTypeValue::S8, dst, lhs, rhs);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ instruction->IsRounded()
+ ? __ Vrhadd(DataTypeValue::U16, dst, lhs, rhs)
+ : __ Vhadd(DataTypeValue::U16, dst, lhs, rhs);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(4u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- instruction->IsRounded()
- ? __ Vrhadd(DataTypeValue::U16, dst, lhs, rhs)
- : __ Vhadd(DataTypeValue::U16, dst, lhs, rhs);
- } else {
- instruction->IsRounded()
- ? __ Vrhadd(DataTypeValue::S16, dst, lhs, rhs)
- : __ Vhadd(DataTypeValue::S16, dst, lhs, rhs);
- }
+ instruction->IsRounded()
+ ? __ Vrhadd(DataTypeValue::S16, dst, lhs, rhs)
+ : __ Vhadd(DataTypeValue::S16, dst, lhs, rhs);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -301,6 +306,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecSub(HVecSub* instruction) {
vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Vsub(I8, dst, lhs, rhs);
@@ -330,6 +336,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecMul(HVecMul* instruction) {
vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Vmul(I8, dst, lhs, rhs);
@@ -367,22 +374,21 @@ void InstructionCodeGeneratorARMVIXL::VisitVecMin(HVecMin* instruction) {
vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Vmin(DataTypeValue::U8, dst, lhs, rhs);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Vmin(DataTypeValue::U8, dst, lhs, rhs);
- } else {
- __ Vmin(DataTypeValue::S8, dst, lhs, rhs);
- }
+ __ Vmin(DataTypeValue::S8, dst, lhs, rhs);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Vmin(DataTypeValue::U16, dst, lhs, rhs);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(4u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Vmin(DataTypeValue::U16, dst, lhs, rhs);
- } else {
- __ Vmin(DataTypeValue::S16, dst, lhs, rhs);
- }
+ __ Vmin(DataTypeValue::S16, dst, lhs, rhs);
break;
case DataType::Type::kInt32:
DCHECK_EQ(2u, instruction->GetVectorLength());
@@ -408,22 +414,21 @@ void InstructionCodeGeneratorARMVIXL::VisitVecMax(HVecMax* instruction) {
vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Vmax(DataTypeValue::U8, dst, lhs, rhs);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Vmax(DataTypeValue::U8, dst, lhs, rhs);
- } else {
- __ Vmax(DataTypeValue::S8, dst, lhs, rhs);
- }
+ __ Vmax(DataTypeValue::S8, dst, lhs, rhs);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(4u, instruction->GetVectorLength());
+ __ Vmax(DataTypeValue::U16, dst, lhs, rhs);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(4u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Vmax(DataTypeValue::U16, dst, lhs, rhs);
- } else {
- __ Vmax(DataTypeValue::S16, dst, lhs, rhs);
- }
+ __ Vmax(DataTypeValue::S16, dst, lhs, rhs);
break;
case DataType::Type::kInt32:
DCHECK_EQ(2u, instruction->GetVectorLength());
@@ -440,6 +445,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecMax(HVecMax* instruction) {
}
void LocationsBuilderARMVIXL::VisitVecAnd(HVecAnd* instruction) {
+ // TODO: Allow constants supported by VAND (immediate).
CreateVecBinOpLocations(GetGraph()->GetArena(), instruction);
}
@@ -450,6 +456,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecAnd(HVecAnd* instruction) {
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -481,6 +488,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecOr(HVecOr* instruction) {
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -504,6 +512,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecXor(HVecXor* instruction) {
vixl32::DRegister dst = DRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -520,6 +529,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecXor(HVecXor* instruction) {
static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -544,6 +554,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecShl(HVecShl* instruction) {
vixl32::DRegister dst = DRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Vshl(I8, dst, lhs, value);
@@ -573,6 +584,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecShr(HVecShr* instruction) {
vixl32::DRegister dst = DRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Vshr(DataTypeValue::S8, dst, lhs, value);
@@ -602,6 +614,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecUShr(HVecUShr* instruction) {
vixl32::DRegister dst = DRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ Vshr(DataTypeValue::U8, dst, lhs, value);
@@ -633,6 +646,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecSetScalars(HVecSetScalars* instruc
static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -678,6 +692,7 @@ static void CreateVecMemLocations(ArenaAllocator* arena,
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -764,6 +779,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecLoad(HVecLoad* instruction) {
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
if (IsWordAligned(instruction)) {
@@ -811,6 +827,7 @@ void InstructionCodeGeneratorARMVIXL::VisitVecStore(HVecStore* instruction) {
vixl32::Register scratch;
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(8u, instruction->GetVectorLength());
if (IsWordAligned(instruction)) {
diff --git a/compiler/optimizing/code_generator_vector_mips.cc b/compiler/optimizing/code_generator_vector_mips.cc
index c25f5acb7e..e8c515761c 100644
--- a/compiler/optimizing/code_generator_vector_mips.cc
+++ b/compiler/optimizing/code_generator_vector_mips.cc
@@ -27,6 +27,7 @@ void LocationsBuilderMIPS::VisitVecReplicateScalar(HVecReplicateScalar* instruct
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -51,6 +52,7 @@ void InstructionCodeGeneratorMIPS::VisitVecReplicateScalar(HVecReplicateScalar*
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ FillB(dst, locations->InAt(0).AsRegister<Register>());
@@ -106,6 +108,7 @@ static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* in
instruction->IsVecNot() ? Location::kOutputOverlap
: Location::kNoOutputOverlap);
break;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -160,6 +163,7 @@ void InstructionCodeGeneratorMIPS::VisitVecNeg(HVecNeg* instruction) {
VectorRegister src = VectorRegisterFrom(locations->InAt(0));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ FillB(dst, ZERO);
@@ -211,7 +215,6 @@ void InstructionCodeGeneratorMIPS::VisitVecAbs(HVecAbs* instruction) {
__ FillB(dst, ZERO); // all zeroes
__ Add_aB(dst, dst, src); // dst = abs(0) + abs(src)
break;
- case DataType::Type::kUint16:
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ FillH(dst, ZERO); // all zeroes
@@ -259,6 +262,7 @@ void InstructionCodeGeneratorMIPS::VisitVecNot(HVecNot* instruction) {
__ LdiB(dst, 1);
__ XorV(dst, dst, src);
break;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -281,6 +285,7 @@ static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation*
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -308,6 +313,7 @@ void InstructionCodeGeneratorMIPS::VisitVecAdd(HVecAdd* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ AddvB(dst, lhs, rhs);
@@ -349,30 +355,29 @@ void InstructionCodeGeneratorMIPS::VisitVecHalvingAdd(HVecHalvingAdd* instructio
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ instruction->IsRounded()
+ ? __ Aver_uB(dst, lhs, rhs)
+ : __ Ave_uB(dst, lhs, rhs);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- instruction->IsRounded()
- ? __ Aver_uB(dst, lhs, rhs)
- : __ Ave_uB(dst, lhs, rhs);
- } else {
- instruction->IsRounded()
- ? __ Aver_sB(dst, lhs, rhs)
- : __ Ave_sB(dst, lhs, rhs);
- }
+ instruction->IsRounded()
+ ? __ Aver_sB(dst, lhs, rhs)
+ : __ Ave_sB(dst, lhs, rhs);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ instruction->IsRounded()
+ ? __ Aver_uH(dst, lhs, rhs)
+ : __ Ave_uH(dst, lhs, rhs);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- instruction->IsRounded()
- ? __ Aver_uH(dst, lhs, rhs)
- : __ Ave_uH(dst, lhs, rhs);
- } else {
- instruction->IsRounded()
- ? __ Aver_sH(dst, lhs, rhs)
- : __ Ave_sH(dst, lhs, rhs);
- }
+ instruction->IsRounded()
+ ? __ Aver_sH(dst, lhs, rhs)
+ : __ Ave_sH(dst, lhs, rhs);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -390,6 +395,7 @@ void InstructionCodeGeneratorMIPS::VisitVecSub(HVecSub* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ SubvB(dst, lhs, rhs);
@@ -431,6 +437,7 @@ void InstructionCodeGeneratorMIPS::VisitVecMul(HVecMul* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ MulvB(dst, lhs, rhs);
@@ -496,22 +503,21 @@ void InstructionCodeGeneratorMIPS::VisitVecMin(HVecMin* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Min_uB(dst, lhs, rhs);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Min_uB(dst, lhs, rhs);
- } else {
- __ Min_sB(dst, lhs, rhs);
- }
+ __ Min_sB(dst, lhs, rhs);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Min_uH(dst, lhs, rhs);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Min_uH(dst, lhs, rhs);
- } else {
- __ Min_sH(dst, lhs, rhs);
- }
+ __ Min_sH(dst, lhs, rhs);
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -557,22 +563,21 @@ void InstructionCodeGeneratorMIPS::VisitVecMax(HVecMax* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Max_uB(dst, lhs, rhs);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Max_uB(dst, lhs, rhs);
- } else {
- __ Max_sB(dst, lhs, rhs);
- }
+ __ Max_sB(dst, lhs, rhs);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Max_uH(dst, lhs, rhs);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Max_uH(dst, lhs, rhs);
- } else {
- __ Max_sH(dst, lhs, rhs);
- }
+ __ Max_sH(dst, lhs, rhs);
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -619,6 +624,7 @@ void InstructionCodeGeneratorMIPS::VisitVecAnd(HVecAnd* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -655,6 +661,7 @@ void InstructionCodeGeneratorMIPS::VisitVecOr(HVecOr* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -683,6 +690,7 @@ void InstructionCodeGeneratorMIPS::VisitVecXor(HVecXor* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -704,6 +712,7 @@ void InstructionCodeGeneratorMIPS::VisitVecXor(HVecXor* instruction) {
static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -729,6 +738,7 @@ void InstructionCodeGeneratorMIPS::VisitVecShl(HVecShl* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ SlliB(dst, lhs, value);
@@ -762,6 +772,7 @@ void InstructionCodeGeneratorMIPS::VisitVecShr(HVecShr* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ SraiB(dst, lhs, value);
@@ -795,6 +806,7 @@ void InstructionCodeGeneratorMIPS::VisitVecUShr(HVecUShr* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ SrliB(dst, lhs, value);
@@ -830,6 +842,7 @@ void InstructionCodeGeneratorMIPS::VisitVecSetScalars(HVecSetScalars* instructio
static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -856,6 +869,7 @@ void InstructionCodeGeneratorMIPS::VisitVecMultiplyAccumulate(HVecMultiplyAccumu
VectorRegister left = VectorRegisterFrom(locations->InAt(1));
VectorRegister right = VectorRegisterFrom(locations->InAt(2));
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
if (instruction->GetOpKind() == HInstruction::kAdd) {
@@ -911,6 +925,7 @@ static void CreateVecMemLocations(ArenaAllocator* arena,
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -976,6 +991,7 @@ void InstructionCodeGeneratorMIPS::VisitVecLoad(HVecLoad* instruction) {
int32_t offset = VecAddress(locations, size, &base);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ LdB(reg, base, offset);
@@ -1018,6 +1034,7 @@ void InstructionCodeGeneratorMIPS::VisitVecStore(HVecStore* instruction) {
int32_t offset = VecAddress(locations, size, &base);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ StB(reg, base, offset);
diff --git a/compiler/optimizing/code_generator_vector_mips64.cc b/compiler/optimizing/code_generator_vector_mips64.cc
index f60f708976..7d69773ae6 100644
--- a/compiler/optimizing/code_generator_vector_mips64.cc
+++ b/compiler/optimizing/code_generator_vector_mips64.cc
@@ -32,6 +32,7 @@ void LocationsBuilderMIPS64::VisitVecReplicateScalar(HVecReplicateScalar* instru
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -56,6 +57,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecReplicateScalar(HVecReplicateScalar
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ FillB(dst, locations->InAt(0).AsRegister<GpuRegister>());
@@ -109,6 +111,7 @@ static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* in
instruction->IsVecNot() ? Location::kOutputOverlap
: Location::kNoOutputOverlap);
break;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -164,6 +167,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecNeg(HVecNeg* instruction) {
VectorRegister src = VectorRegisterFrom(locations->InAt(0));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ FillB(dst, ZERO);
@@ -215,7 +219,6 @@ void InstructionCodeGeneratorMIPS64::VisitVecAbs(HVecAbs* instruction) {
__ FillB(dst, ZERO); // all zeroes
__ Add_aB(dst, dst, src); // dst = abs(0) + abs(src)
break;
- case DataType::Type::kUint16:
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ FillH(dst, ZERO); // all zeroes
@@ -263,6 +266,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecNot(HVecNot* instruction) {
__ LdiB(dst, 1);
__ XorV(dst, dst, src);
break;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -285,6 +289,7 @@ static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation*
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -312,6 +317,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecAdd(HVecAdd* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ AddvB(dst, lhs, rhs);
@@ -353,30 +359,29 @@ void InstructionCodeGeneratorMIPS64::VisitVecHalvingAdd(HVecHalvingAdd* instruct
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ instruction->IsRounded()
+ ? __ Aver_uB(dst, lhs, rhs)
+ : __ Ave_uB(dst, lhs, rhs);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- instruction->IsRounded()
- ? __ Aver_uB(dst, lhs, rhs)
- : __ Ave_uB(dst, lhs, rhs);
- } else {
- instruction->IsRounded()
- ? __ Aver_sB(dst, lhs, rhs)
- : __ Ave_sB(dst, lhs, rhs);
- }
+ instruction->IsRounded()
+ ? __ Aver_sB(dst, lhs, rhs)
+ : __ Ave_sB(dst, lhs, rhs);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ instruction->IsRounded()
+ ? __ Aver_uH(dst, lhs, rhs)
+ : __ Ave_uH(dst, lhs, rhs);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- instruction->IsRounded()
- ? __ Aver_uH(dst, lhs, rhs)
- : __ Ave_uH(dst, lhs, rhs);
- } else {
- instruction->IsRounded()
- ? __ Aver_sH(dst, lhs, rhs)
- : __ Ave_sH(dst, lhs, rhs);
- }
+ instruction->IsRounded()
+ ? __ Aver_sH(dst, lhs, rhs)
+ : __ Ave_sH(dst, lhs, rhs);
break;
default:
LOG(FATAL) << "Unsupported SIMD type";
@@ -394,6 +399,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecSub(HVecSub* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ SubvB(dst, lhs, rhs);
@@ -435,6 +441,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecMul(HVecMul* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ MulvB(dst, lhs, rhs);
@@ -500,22 +507,21 @@ void InstructionCodeGeneratorMIPS64::VisitVecMin(HVecMin* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Min_uB(dst, lhs, rhs);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Min_uB(dst, lhs, rhs);
- } else {
- __ Min_sB(dst, lhs, rhs);
- }
+ __ Min_sB(dst, lhs, rhs);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Min_uH(dst, lhs, rhs);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Min_uH(dst, lhs, rhs);
- } else {
- __ Min_sH(dst, lhs, rhs);
- }
+ __ Min_sH(dst, lhs, rhs);
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -561,22 +567,21 @@ void InstructionCodeGeneratorMIPS64::VisitVecMax(HVecMax* instruction) {
VectorRegister rhs = VectorRegisterFrom(locations->InAt(1));
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ Max_uB(dst, lhs, rhs);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Max_uB(dst, lhs, rhs);
- } else {
- __ Max_sB(dst, lhs, rhs);
- }
+ __ Max_sB(dst, lhs, rhs);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ Max_uH(dst, lhs, rhs);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ Max_uH(dst, lhs, rhs);
- } else {
- __ Max_sH(dst, lhs, rhs);
- }
+ __ Max_sH(dst, lhs, rhs);
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -623,6 +628,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecAnd(HVecAnd* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -659,6 +665,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecOr(HVecOr* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -687,6 +694,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecXor(HVecXor* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -708,6 +716,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecXor(HVecXor* instruction) {
static void CreateVecShiftLocations(ArenaAllocator* arena, HVecBinaryOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -733,6 +742,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecShl(HVecShl* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ SlliB(dst, lhs, value);
@@ -766,6 +776,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecShr(HVecShr* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ SraiB(dst, lhs, value);
@@ -799,6 +810,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecUShr(HVecUShr* instruction) {
VectorRegister dst = VectorRegisterFrom(locations->Out());
int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ SrliB(dst, lhs, value);
@@ -834,6 +846,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecSetScalars(HVecSetScalars* instruct
static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -860,6 +873,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecMultiplyAccumulate(HVecMultiplyAccu
VectorRegister left = VectorRegisterFrom(locations->InAt(1));
VectorRegister right = VectorRegisterFrom(locations->InAt(2));
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
if (instruction->GetOpKind() == HInstruction::kAdd) {
@@ -915,6 +929,7 @@ static void CreateVecMemLocations(ArenaAllocator* arena,
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -980,6 +995,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecLoad(HVecLoad* instruction) {
int32_t offset = VecAddress(locations, size, &base);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ LdB(reg, base, offset);
@@ -1022,6 +1038,7 @@ void InstructionCodeGeneratorMIPS64::VisitVecStore(HVecStore* instruction) {
int32_t offset = VecAddress(locations, size, &base);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ StB(reg, base, offset);
diff --git a/compiler/optimizing/code_generator_vector_x86.cc b/compiler/optimizing/code_generator_vector_x86.cc
index 6515dbe7b7..a2ef1b1be9 100644
--- a/compiler/optimizing/code_generator_vector_x86.cc
+++ b/compiler/optimizing/code_generator_vector_x86.cc
@@ -37,6 +37,7 @@ void LocationsBuilderX86::VisitVecReplicateScalar(HVecReplicateScalar* instructi
}
FALLTHROUGH_INTENDED;
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -70,6 +71,7 @@ void InstructionCodeGeneratorX86::VisitVecReplicateScalar(HVecReplicateScalar* i
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ movd(dst, locations->InAt(0).AsRegister<Register>());
@@ -122,6 +124,7 @@ void LocationsBuilderX86::VisitVecExtractScalar(HVecExtractScalar* instruction)
locations->AddTemp(Location::RequiresFpuRegister());
FALLTHROUGH_INTENDED;
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -145,6 +148,7 @@ void InstructionCodeGeneratorX86::VisitVecExtractScalar(HVecExtractScalar* instr
XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16: // TODO: up to here, and?
@@ -180,6 +184,7 @@ static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* in
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -290,6 +295,7 @@ void InstructionCodeGeneratorX86::VisitVecNeg(HVecNeg* instruction) {
XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ pxor(dst, dst);
@@ -390,6 +396,7 @@ void InstructionCodeGeneratorX86::VisitVecNot(HVecNot* instruction) {
__ pxor(dst, src);
break;
}
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -421,6 +428,7 @@ static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation*
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -448,6 +456,7 @@ void InstructionCodeGeneratorX86::VisitVecAdd(HVecAdd* instruction) {
XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ paddb(dst, src);
@@ -490,15 +499,13 @@ void InstructionCodeGeneratorX86::VisitVecHalvingAdd(HVecHalvingAdd* instruction
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
DCHECK(instruction->IsRounded());
- DCHECK(instruction->IsUnsigned());
switch (instruction->GetPackedType()) {
- case DataType::Type::kInt8:
+ case DataType::Type::kUint8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ pavgb(dst, src);
return;
case DataType::Type::kUint16:
- case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ pavgw(dst, src);
return;
@@ -518,6 +525,7 @@ void InstructionCodeGeneratorX86::VisitVecSub(HVecSub* instruction) {
XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ psubb(dst, src);
@@ -616,22 +624,21 @@ void InstructionCodeGeneratorX86::VisitVecMin(HVecMin* instruction) {
XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ pminub(dst, src);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ pminub(dst, src);
- } else {
- __ pminsb(dst, src);
- }
+ __ pminsb(dst, src);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ pminuw(dst, src);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ pminuw(dst, src);
- } else {
- __ pminsw(dst, src);
- }
+ __ pminsw(dst, src);
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -668,22 +675,21 @@ void InstructionCodeGeneratorX86::VisitVecMax(HVecMax* instruction) {
XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ pmaxub(dst, src);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ pmaxub(dst, src);
- } else {
- __ pmaxsb(dst, src);
- }
+ __ pmaxsb(dst, src);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ pmaxuw(dst, src);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ pmaxuw(dst, src);
- } else {
- __ pmaxsw(dst, src);
- }
+ __ pmaxsw(dst, src);
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -721,6 +727,7 @@ void InstructionCodeGeneratorX86::VisitVecAnd(HVecAnd* instruction) {
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -755,6 +762,7 @@ void InstructionCodeGeneratorX86::VisitVecAndNot(HVecAndNot* instruction) {
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -789,6 +797,7 @@ void InstructionCodeGeneratorX86::VisitVecOr(HVecOr* instruction) {
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -823,6 +832,7 @@ void InstructionCodeGeneratorX86::VisitVecXor(HVecXor* instruction) {
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -963,6 +973,7 @@ void LocationsBuilderX86::VisitVecSetScalars(HVecSetScalars* instruction) {
}
FALLTHROUGH_INTENDED;
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -1000,6 +1011,7 @@ void InstructionCodeGeneratorX86::VisitVecSetScalars(HVecSetScalars* instruction
// Set required elements.
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16: // TODO: up to here, and?
@@ -1036,6 +1048,7 @@ void InstructionCodeGeneratorX86::VisitVecSetScalars(HVecSetScalars* instruction
static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -1077,6 +1090,7 @@ static void CreateVecMemLocations(ArenaAllocator* arena,
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -1156,6 +1170,7 @@ void InstructionCodeGeneratorX86::VisitVecLoad(HVecLoad* instruction) {
}
FALLTHROUGH_INTENDED;
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
@@ -1190,6 +1205,7 @@ void InstructionCodeGeneratorX86::VisitVecStore(HVecStore* instruction) {
bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
diff --git a/compiler/optimizing/code_generator_vector_x86_64.cc b/compiler/optimizing/code_generator_vector_x86_64.cc
index 4241042574..2270f6b9c8 100644
--- a/compiler/optimizing/code_generator_vector_x86_64.cc
+++ b/compiler/optimizing/code_generator_vector_x86_64.cc
@@ -31,6 +31,7 @@ void LocationsBuilderX86_64::VisitVecReplicateScalar(HVecReplicateScalar* instru
bool is_zero = IsZeroBitPattern(input);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -65,6 +66,7 @@ void InstructionCodeGeneratorX86_64::VisitVecReplicateScalar(HVecReplicateScalar
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ movd(dst, locations->InAt(0).AsRegister<CpuRegister>(), /*64-bit*/ false);
@@ -109,6 +111,7 @@ void LocationsBuilderX86_64::VisitVecExtractScalar(HVecExtractScalar* instructio
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -133,6 +136,7 @@ void InstructionCodeGeneratorX86_64::VisitVecExtractScalar(HVecExtractScalar* in
XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16: // TODO: up to here, and?
@@ -163,6 +167,7 @@ static void CreateVecUnOpLocations(ArenaAllocator* arena, HVecUnaryOperation* in
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -273,6 +278,7 @@ void InstructionCodeGeneratorX86_64::VisitVecNeg(HVecNeg* instruction) {
XmmRegister src = locations->InAt(0).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ pxor(dst, dst);
@@ -373,6 +379,7 @@ void InstructionCodeGeneratorX86_64::VisitVecNot(HVecNot* instruction) {
__ pxor(dst, src);
break;
}
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -404,6 +411,7 @@ static void CreateVecBinOpLocations(ArenaAllocator* arena, HVecBinaryOperation*
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -431,6 +439,7 @@ void InstructionCodeGeneratorX86_64::VisitVecAdd(HVecAdd* instruction) {
XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ paddb(dst, src);
@@ -473,15 +482,13 @@ void InstructionCodeGeneratorX86_64::VisitVecHalvingAdd(HVecHalvingAdd* instruct
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
DCHECK(instruction->IsRounded());
- DCHECK(instruction->IsUnsigned());
switch (instruction->GetPackedType()) {
- case DataType::Type::kInt8:
+ case DataType::Type::kUint8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ pavgb(dst, src);
return;
case DataType::Type::kUint16:
- case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
__ pavgw(dst, src);
return;
@@ -501,6 +508,7 @@ void InstructionCodeGeneratorX86_64::VisitVecSub(HVecSub* instruction) {
XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
__ psubb(dst, src);
@@ -599,22 +607,21 @@ void InstructionCodeGeneratorX86_64::VisitVecMin(HVecMin* instruction) {
XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ pminub(dst, src);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ pminub(dst, src);
- } else {
- __ pminsb(dst, src);
- }
+ __ pminsb(dst, src);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ pminuw(dst, src);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ pminuw(dst, src);
- } else {
- __ pminsw(dst, src);
- }
+ __ pminsw(dst, src);
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -651,22 +658,21 @@ void InstructionCodeGeneratorX86_64::VisitVecMax(HVecMax* instruction) {
XmmRegister src = locations->InAt(1).AsFpuRegister<XmmRegister>();
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
+ DCHECK_EQ(16u, instruction->GetVectorLength());
+ __ pmaxub(dst, src);
+ break;
case DataType::Type::kInt8:
DCHECK_EQ(16u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ pmaxub(dst, src);
- } else {
- __ pmaxsb(dst, src);
- }
+ __ pmaxsb(dst, src);
break;
case DataType::Type::kUint16:
+ DCHECK_EQ(8u, instruction->GetVectorLength());
+ __ pmaxuw(dst, src);
+ break;
case DataType::Type::kInt16:
DCHECK_EQ(8u, instruction->GetVectorLength());
- if (instruction->IsUnsigned()) {
- __ pmaxuw(dst, src);
- } else {
- __ pmaxsw(dst, src);
- }
+ __ pmaxsw(dst, src);
break;
case DataType::Type::kInt32:
DCHECK_EQ(4u, instruction->GetVectorLength());
@@ -704,6 +710,7 @@ void InstructionCodeGeneratorX86_64::VisitVecAnd(HVecAnd* instruction) {
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -738,6 +745,7 @@ void InstructionCodeGeneratorX86_64::VisitVecAndNot(HVecAndNot* instruction) {
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -772,6 +780,7 @@ void InstructionCodeGeneratorX86_64::VisitVecOr(HVecOr* instruction) {
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -806,6 +815,7 @@ void InstructionCodeGeneratorX86_64::VisitVecXor(HVecXor* instruction) {
XmmRegister dst = locations->Out().AsFpuRegister<XmmRegister>();
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -940,6 +950,7 @@ void LocationsBuilderX86_64::VisitVecSetScalars(HVecSetScalars* instruction) {
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -978,6 +989,7 @@ void InstructionCodeGeneratorX86_64::VisitVecSetScalars(HVecSetScalars* instruct
// Set required elements.
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16: // TODO: up to here, and?
@@ -1009,6 +1021,7 @@ void InstructionCodeGeneratorX86_64::VisitVecSetScalars(HVecSetScalars* instruct
static void CreateVecAccumLocations(ArenaAllocator* arena, HVecOperation* instruction) {
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -1050,6 +1063,7 @@ static void CreateVecMemLocations(ArenaAllocator* arena,
LocationSummary* locations = new (arena) LocationSummary(instruction);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -1129,6 +1143,7 @@ void InstructionCodeGeneratorX86_64::VisitVecLoad(HVecLoad* instruction) {
}
FALLTHROUGH_INTENDED;
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
@@ -1163,6 +1178,7 @@ void InstructionCodeGeneratorX86_64::VisitVecStore(HVecStore* instruction) {
bool is_aligned16 = instruction->GetAlignment().IsAlignedAt(16);
switch (instruction->GetPackedType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 70e270e74d..35156491e8 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1131,12 +1131,13 @@ void CodeGeneratorX86::Bind(HBasicBlock* block) {
Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(DataType::Type type) const {
switch (type) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kReference:
return Location::RegisterLocation(EAX);
case DataType::Type::kInt64:
@@ -1159,12 +1160,13 @@ Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const {
Location InvokeDexCallingConventionVisitorX86::GetNextLocation(DataType::Type type) {
switch (type) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- case DataType::Type::kReference: {
+ case DataType::Type::kInt32: {
uint32_t index = gp_index_++;
stack_index_++;
if (index < calling_convention.GetNumberOfRegisters()) {
@@ -2099,12 +2101,13 @@ void LocationsBuilderX86::VisitReturn(HReturn* ret) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
switch (ret->InputAt(0)->GetType()) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kReference:
locations->SetInAt(0, Location::RegisterLocation(EAX));
break;
@@ -2127,12 +2130,13 @@ void LocationsBuilderX86::VisitReturn(HReturn* ret) {
void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
if (kIsDebugBuild) {
switch (ret->InputAt(0)->GetType()) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kReference:
DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
break;
@@ -2408,7 +2412,8 @@ void InstructionCodeGeneratorX86::VisitX86FPNeg(HX86FPNeg* neg) {
void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
DataType::Type result_type = conversion->GetResultType();
DataType::Type input_type = conversion->GetInputType();
- DCHECK_NE(result_type, input_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
// The float-to-long and double-to-long type conversions rely on a
// call to the runtime.
@@ -2420,14 +2425,21 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
- // The Java language does not allow treating boolean as an integral type but
- // our bit representation makes it safe.
-
switch (result_type) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
switch (input_type) {
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ case DataType::Type::kInt32:
+ locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
+ // 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 DataType::Type::kInt64: {
- // 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())
@@ -2438,17 +2450,6 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
break;
}
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-byte' instruction.
- locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
- // 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;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
@@ -2456,43 +2457,27 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
}
break;
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to short is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-short' instruction.
- locations->SetInAt(0, Location::Any());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
+ DCHECK(DataType::IsIntegralType(input_type)) << input_type;
+ locations->SetInAt(0, Location::Any());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
case DataType::Type::kInt32:
switch (input_type) {
case DataType::Type::kInt64:
- // Processing a Dex `long-to-int' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-int' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresRegister());
locations->AddTemp(Location::RequiresFpuRegister());
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-int' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresRegister());
locations->AddTemp(Location::RequiresFpuRegister());
@@ -2507,19 +2492,17 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
case DataType::Type::kInt64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-long' instruction.
locations->SetInAt(0, Location::RegisterLocation(EAX));
locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
break;
case DataType::Type::kFloat32:
case DataType::Type::kFloat64: {
- // Processing a Dex `float-to-long' or 'double-to-long' instruction.
InvokeRuntimeCallingConvention calling_convention;
XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
@@ -2535,47 +2518,24 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
}
break;
- case DataType::Type::kUint16:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to char is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- // Processing a Dex `int-to-char' instruction.
- locations->SetInAt(0, Location::Any());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
- break;
-
case DataType::Type::kFloat32:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-float' instruction.
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresFpuRegister());
break;
case DataType::Type::kInt64:
- // Processing a Dex `long-to-float' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::Any());
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-float' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -2589,24 +2549,21 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
case DataType::Type::kFloat64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-double' instruction.
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RequiresFpuRegister());
break;
case DataType::Type::kInt64:
- // Processing a Dex `long-to-double' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::Any());
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-double' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -2629,26 +2586,45 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
Location in = locations->InAt(0);
DataType::Type result_type = conversion->GetResultType();
DataType::Type input_type = conversion->GetInputType();
- DCHECK_NE(result_type, input_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
switch (result_type) {
- case DataType::Type::kInt8:
+ case DataType::Type::kUint8:
switch (input_type) {
+ case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ case DataType::Type::kInt32:
+ if (in.IsRegister()) {
+ __ movzxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
+ } else {
+ DCHECK(in.GetConstant()->IsIntConstant());
+ int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
+ __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint8_t>(value)));
+ }
+ break;
case DataType::Type::kInt64:
- // Type conversion from long to byte is a result of code transformations.
if (in.IsRegisterPair()) {
- __ movsxb(out.AsRegister<Register>(), in.AsRegisterPairLow<ByteRegister>());
+ __ movzxb(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)));
+ __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint8_t>(value)));
}
break;
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case DataType::Type::kInt8:
+ switch (input_type) {
+ case DataType::Type::kUint8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-byte' instruction.
if (in.IsRegister()) {
__ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
} else {
@@ -2657,6 +2633,15 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
__ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
}
break;
+ case DataType::Type::kInt64:
+ 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;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
@@ -2664,26 +2649,43 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
}
break;
- case DataType::Type::kInt16:
+ case DataType::Type::kUint16:
switch (input_type) {
+ case DataType::Type::kInt8:
+ case DataType::Type::kInt16:
+ case DataType::Type::kInt32:
+ if (in.IsRegister()) {
+ __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
+ } else if (in.IsStackSlot()) {
+ __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+ } else {
+ DCHECK(in.GetConstant()->IsIntConstant());
+ int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
+ __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
+ }
+ break;
case DataType::Type::kInt64:
- // Type conversion from long to short is a result of code transformations.
if (in.IsRegisterPair()) {
- __ movsxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
+ __ movzxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
} else if (in.IsDoubleStackSlot()) {
- __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+ __ 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<int16_t>(value)));
+ __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
}
break;
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt32:
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case DataType::Type::kInt16:
+ switch (input_type) {
case DataType::Type::kUint16:
- // Processing a Dex `int-to-short' instruction.
+ case DataType::Type::kInt32:
if (in.IsRegister()) {
__ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
} else if (in.IsStackSlot()) {
@@ -2694,6 +2696,17 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
__ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
}
break;
+ case DataType::Type::kInt64:
+ 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;
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
@@ -2704,7 +2717,6 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
case DataType::Type::kInt32:
switch (input_type) {
case DataType::Type::kInt64:
- // Processing a Dex `long-to-int' instruction.
if (in.IsRegisterPair()) {
__ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
} else if (in.IsDoubleStackSlot()) {
@@ -2718,7 +2730,6 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
break;
case DataType::Type::kFloat32: {
- // Processing a Dex `float-to-int' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
Register output = out.AsRegister<Register>();
XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
@@ -2743,7 +2754,6 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
}
case DataType::Type::kFloat64: {
- // Processing a Dex `double-to-int' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
Register output = out.AsRegister<Register>();
XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
@@ -2776,12 +2786,11 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
case DataType::Type::kInt64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-long' instruction.
DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
DCHECK_EQ(in.AsRegister<Register>(), EAX);
@@ -2789,13 +2798,11 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-long' instruction.
codegen_->InvokeRuntime(kQuickF2l, conversion, conversion->GetDexPc());
CheckEntrypointTypes<kQuickF2l, int64_t, float>();
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-long' instruction.
codegen_->InvokeRuntime(kQuickD2l, conversion, conversion->GetDexPc());
CheckEntrypointTypes<kQuickD2l, int64_t, double>();
break;
@@ -2806,57 +2813,18 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
}
break;
- case DataType::Type::kUint16:
- switch (input_type) {
- case DataType::Type::kInt64:
- // 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 DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- // Processing a Dex `Process a Dex `int-to-char'' instruction.
- if (in.IsRegister()) {
- __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
- } else if (in.IsStackSlot()) {
- __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
- } else {
- DCHECK(in.GetConstant()->IsIntConstant());
- int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
- __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
- }
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
- break;
-
case DataType::Type::kFloat32:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-float' instruction.
__ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
break;
case DataType::Type::kInt64: {
- // Processing a Dex `long-to-float' instruction.
size_t adjustment = 0;
// Create stack space for the call to
@@ -2886,7 +2854,6 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
}
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-float' instruction.
__ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
break;
@@ -2899,17 +2866,15 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
case DataType::Type::kFloat64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-double' instruction.
__ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
break;
case DataType::Type::kInt64: {
- // Processing a Dex `long-to-double' instruction.
size_t adjustment = 0;
// Create stack space for the call to
@@ -2939,7 +2904,6 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
}
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-double' instruction.
__ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
break;
@@ -3832,6 +3796,7 @@ void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
LocationSummary* locations = codegen_->CreateThrowingSlowPathLocations(instruction);
switch (instruction->GetType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -3860,6 +3825,7 @@ void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction)
switch (instruction->GetType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -4349,9 +4315,10 @@ void LocationsBuilderX86::VisitCompare(HCompare* compare) {
new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
switch (compare->InputAt(0)->GetType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
case DataType::Type::kInt64: {
locations->SetInAt(0, Location::RequiresRegister());
@@ -4388,9 +4355,10 @@ void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
switch (compare->InputAt(0)->GetType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32: {
codegen_->GenerateIntCompare(left, right);
break;
@@ -4792,7 +4760,8 @@ void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
uint32_t offset = field_info.GetFieldOffset().Uint32Value();
switch (field_type) {
- case DataType::Type::kBool: {
+ case DataType::Type::kBool:
+ case DataType::Type::kUint8: {
__ movzxb(out.AsRegister<Register>(), Address(base, offset));
break;
}
@@ -4802,13 +4771,13 @@ void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
break;
}
- case DataType::Type::kInt16: {
- __ movsxw(out.AsRegister<Register>(), Address(base, offset));
+ case DataType::Type::kUint16: {
+ __ movzxw(out.AsRegister<Register>(), Address(base, offset));
break;
}
- case DataType::Type::kUint16: {
- __ movzxw(out.AsRegister<Register>(), Address(base, offset));
+ case DataType::Type::kInt16: {
+ __ movsxw(out.AsRegister<Register>(), Address(base, offset));
break;
}
@@ -4897,8 +4866,7 @@ void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldI
locations->SetInAt(0, Location::RequiresRegister());
bool is_volatile = field_info.IsVolatile();
DataType::Type field_type = field_info.GetFieldType();
- bool is_byte_type = (field_type == DataType::Type::kBool)
- || (field_type == DataType::Type::kInt8);
+ bool is_byte_type = DataType::Size(field_type) == 1u;
// The register allocator does not support multiple
// inputs that die at entry with one in a specific register.
@@ -4957,13 +4925,14 @@ void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
switch (field_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8: {
__ movb(Address(base, offset), value.AsRegister<ByteRegister>());
break;
}
- case DataType::Type::kInt16:
- case DataType::Type::kUint16: {
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16: {
if (value.IsConstant()) {
__ movw(Address(base, offset),
Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
@@ -5242,7 +5211,8 @@ void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
DataType::Type type = instruction->GetType();
switch (type) {
- case DataType::Type::kBool: {
+ case DataType::Type::kBool:
+ case DataType::Type::kUint8: {
Register out = out_loc.AsRegister<Register>();
__ movzxb(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_1, data_offset));
break;
@@ -5254,12 +5224,6 @@ void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
break;
}
- case DataType::Type::kInt16: {
- Register out = out_loc.AsRegister<Register>();
- __ movsxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
- break;
- }
-
case DataType::Type::kUint16: {
Register out = out_loc.AsRegister<Register>();
if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
@@ -5284,6 +5248,12 @@ void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
break;
}
+ case DataType::Type::kInt16: {
+ Register out = out_loc.AsRegister<Register>();
+ __ movsxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+ break;
+ }
+
case DataType::Type::kInt32: {
Register out = out_loc.AsRegister<Register>();
__ movl(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_4, data_offset));
@@ -5368,8 +5338,7 @@ void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
LocationSummary::kCallOnSlowPath :
LocationSummary::kNoCall);
- bool is_byte_type = (value_type == DataType::Type::kBool)
- || (value_type == DataType::Type::kInt8);
+ bool is_byte_type = DataType::Size(value_type) == 1u;
// We need the inputs to be different than the output in case of long operation.
// In case of a byte operation, the register allocator does not support multiple
// inputs that die at entry with one in a specific register.
@@ -5407,6 +5376,7 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
switch (value_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8: {
uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_1, offset);
@@ -5419,8 +5389,8 @@ void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
break;
}
- case DataType::Type::kInt16:
- case DataType::Type::kUint16: {
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16: {
uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Address address = CodeGeneratorX86::ArrayAddress(array, index, TIMES_2, offset);
if (value.IsRegister()) {
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 42704e9fe1..e8bfa66a58 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1521,6 +1521,7 @@ void InstructionCodeGeneratorX86_64::GenerateCompareTest(HCondition* condition)
DataType::Type type = condition->InputAt(0)->GetType();
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -2036,9 +2037,10 @@ void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
switch (compare->InputAt(0)->GetType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
case DataType::Type::kInt64: {
locations->SetInAt(0, Location::RequiresRegister());
@@ -2070,9 +2072,10 @@ void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32: {
codegen_->GenerateIntCompare(left, right);
break;
@@ -2207,12 +2210,13 @@ void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
switch (ret->InputAt(0)->GetType()) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kReference:
case DataType::Type::kInt64:
locations->SetInAt(0, Location::RegisterLocation(RAX));
break;
@@ -2230,12 +2234,13 @@ void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
if (kIsDebugBuild) {
switch (ret->InputAt(0)->GetType()) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kReference:
case DataType::Type::kInt64:
DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<CpuRegister>().AsRegister(), RAX);
break;
@@ -2255,12 +2260,13 @@ void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
Location InvokeDexCallingConventionVisitorX86_64::GetReturnLocation(DataType::Type type) const {
switch (type) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kReference:
case DataType::Type::kInt64:
return Location::RegisterLocation(RAX);
@@ -2281,12 +2287,13 @@ Location InvokeDexCallingConventionVisitorX86_64::GetMethodLocation() const {
Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(DataType::Type type) {
switch (type) {
+ case DataType::Type::kReference:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- case DataType::Type::kReference: {
+ case DataType::Type::kInt32: {
uint32_t index = gp_index_++;
stack_index_++;
if (index < calling_convention.GetNumberOfRegisters()) {
@@ -2536,68 +2543,32 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall);
DataType::Type result_type = conversion->GetResultType();
DataType::Type input_type = conversion->GetInputType();
- DCHECK_NE(result_type, input_type);
-
- // The Java language does not allow treating boolean as an integral type but
- // our bit representation makes it safe.
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
switch (result_type) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to byte is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-byte' instruction.
- locations->SetInAt(0, Location::Any());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
- break;
-
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to short is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-short' instruction.
- locations->SetInAt(0, Location::Any());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
+ DCHECK(DataType::IsIntegralType(input_type)) << input_type;
+ locations->SetInAt(0, Location::Any());
+ locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
case DataType::Type::kInt32:
switch (input_type) {
case DataType::Type::kInt64:
- // Processing a Dex `long-to-int' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-int' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresRegister());
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-int' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresRegister());
break;
@@ -2611,12 +2582,11 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
case DataType::Type::kInt64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-long' instruction.
// TODO: We would benefit from a (to-be-implemented)
// Location::RegisterOrStackSlot requirement for this input.
locations->SetInAt(0, Location::RequiresRegister());
@@ -2624,13 +2594,11 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-long' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresRegister());
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-long' instruction.
locations->SetInAt(0, Location::RequiresFpuRegister());
locations->SetOut(Location::RequiresRegister());
break;
@@ -2641,47 +2609,24 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
}
break;
- case DataType::Type::kUint16:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to char is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- // Processing a Dex `int-to-char' instruction.
- locations->SetInAt(0, Location::Any());
- locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
- break;
-
- default:
- LOG(FATAL) << "Unexpected type conversion from " << input_type
- << " to " << result_type;
- }
- break;
-
case DataType::Type::kFloat32:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-float' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister());
break;
case DataType::Type::kInt64:
- // Processing a Dex `long-to-float' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister());
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-float' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -2695,24 +2640,21 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
case DataType::Type::kFloat64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-double' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister());
break;
case DataType::Type::kInt64:
- // Processing a Dex `long-to-double' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister());
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-double' instruction.
locations->SetInAt(0, Location::Any());
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
break;
@@ -2735,18 +2677,40 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
Location in = locations->InAt(0);
DataType::Type result_type = conversion->GetResultType();
DataType::Type input_type = conversion->GetInputType();
- DCHECK_NE(result_type, input_type);
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " -> " << result_type;
switch (result_type) {
- case DataType::Type::kInt8:
+ case DataType::Type::kUint8:
switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to byte is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
+ case DataType::Type::kInt64:
+ if (in.IsRegister()) {
+ __ movzxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
+ } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
+ __ movzxb(out.AsRegister<CpuRegister>(),
+ Address(CpuRegister(RSP), in.GetStackIndex()));
+ } else {
+ __ movl(out.AsRegister<CpuRegister>(),
+ Immediate(static_cast<uint8_t>(Int64FromConstant(in.GetConstant()))));
+ }
+ break;
+
+ default:
+ LOG(FATAL) << "Unexpected type conversion from " << input_type
+ << " to " << result_type;
+ }
+ break;
+
+ case DataType::Type::kInt8:
+ switch (input_type) {
+ case DataType::Type::kUint8:
case DataType::Type::kUint16:
- // Processing a Dex `int-to-byte' instruction.
+ case DataType::Type::kInt16:
+ case DataType::Type::kInt32:
+ case DataType::Type::kInt64:
if (in.IsRegister()) {
__ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
} else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
@@ -2764,16 +2728,34 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
}
break;
- case DataType::Type::kInt16:
+ case DataType::Type::kUint16:
switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to short is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
case DataType::Type::kInt8:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
+ case DataType::Type::kInt64:
+ 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 DataType::Type::kInt16:
+ switch (input_type) {
case DataType::Type::kUint16:
- // Processing a Dex `int-to-short' instruction.
+ case DataType::Type::kInt32:
+ case DataType::Type::kInt64:
if (in.IsRegister()) {
__ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
} else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
@@ -2794,7 +2776,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
case DataType::Type::kInt32:
switch (input_type) {
case DataType::Type::kInt64:
- // Processing a Dex `long-to-int' instruction.
if (in.IsRegister()) {
__ movl(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
} else if (in.IsDoubleStackSlot()) {
@@ -2809,7 +2790,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
break;
case DataType::Type::kFloat32: {
- // Processing a Dex `float-to-int' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
CpuRegister output = out.AsRegister<CpuRegister>();
NearLabel done, nan;
@@ -2831,7 +2811,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
}
case DataType::Type::kFloat64: {
- // Processing a Dex `double-to-int' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
CpuRegister output = out.AsRegister<CpuRegister>();
NearLabel done, nan;
@@ -2862,18 +2841,16 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
switch (input_type) {
DCHECK(out.IsRegister());
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-long' instruction.
DCHECK(in.IsRegister());
__ movsxd(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
break;
case DataType::Type::kFloat32: {
- // Processing a Dex `float-to-long' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
CpuRegister output = out.AsRegister<CpuRegister>();
NearLabel done, nan;
@@ -2895,7 +2872,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
}
case DataType::Type::kFloat64: {
- // Processing a Dex `double-to-long' instruction.
XmmRegister input = in.AsFpuRegister<XmmRegister>();
CpuRegister output = out.AsRegister<CpuRegister>();
NearLabel done, nan;
@@ -2922,42 +2898,14 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
}
break;
- case DataType::Type::kUint16:
- switch (input_type) {
- case DataType::Type::kInt64:
- // Type conversion from long to char is a result of code transformations.
- case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
- case DataType::Type::kInt8:
- case DataType::Type::kInt16:
- case DataType::Type::kInt32:
- // 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 DataType::Type::kFloat32:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-float' instruction.
if (in.IsRegister()) {
__ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
} else if (in.IsConstant()) {
@@ -2971,7 +2919,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
break;
case DataType::Type::kInt64:
- // Processing a Dex `long-to-float' instruction.
if (in.IsRegister()) {
__ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
} else if (in.IsConstant()) {
@@ -2985,7 +2932,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
break;
case DataType::Type::kFloat64:
- // Processing a Dex `double-to-float' instruction.
if (in.IsFpuRegister()) {
__ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
} else if (in.IsConstant()) {
@@ -3007,12 +2953,11 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
case DataType::Type::kFloat64:
switch (input_type) {
case DataType::Type::kBool:
- // Boolean input is a result of code transformations.
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
case DataType::Type::kInt16:
case DataType::Type::kInt32:
- case DataType::Type::kUint16:
- // Processing a Dex `int-to-double' instruction.
if (in.IsRegister()) {
__ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), false);
} else if (in.IsConstant()) {
@@ -3026,7 +2971,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
break;
case DataType::Type::kInt64:
- // Processing a Dex `long-to-double' instruction.
if (in.IsRegister()) {
__ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<CpuRegister>(), true);
} else if (in.IsConstant()) {
@@ -3040,7 +2984,6 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
break;
case DataType::Type::kFloat32:
- // Processing a Dex `float-to-double' instruction.
if (in.IsFpuRegister()) {
__ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
} else if (in.IsConstant()) {
@@ -3883,6 +3826,7 @@ void InstructionCodeGeneratorX86_64::VisitDivZeroCheck(HDivZeroCheck* instructio
switch (instruction->GetType()) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -4290,7 +4234,8 @@ void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
uint32_t offset = field_info.GetFieldOffset().Uint32Value();
switch (field_type) {
- case DataType::Type::kBool: {
+ case DataType::Type::kBool:
+ case DataType::Type::kUint8: {
__ movzxb(out.AsRegister<CpuRegister>(), Address(base, offset));
break;
}
@@ -4300,13 +4245,13 @@ void InstructionCodeGeneratorX86_64::HandleFieldGet(HInstruction* instruction,
break;
}
- case DataType::Type::kInt16: {
- __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
+ case DataType::Type::kUint16: {
+ __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
break;
}
- case DataType::Type::kUint16: {
- __ movzxw(out.AsRegister<CpuRegister>(), Address(base, offset));
+ case DataType::Type::kInt16: {
+ __ movsxw(out.AsRegister<CpuRegister>(), Address(base, offset));
break;
}
@@ -4433,6 +4378,7 @@ void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
switch (field_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8: {
if (value.IsConstant()) {
__ movb(Address(base, offset),
@@ -4443,8 +4389,8 @@ void InstructionCodeGeneratorX86_64::HandleFieldSet(HInstruction* instruction,
break;
}
- case DataType::Type::kInt16:
- case DataType::Type::kUint16: {
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16: {
if (value.IsConstant()) {
__ movw(Address(base, offset),
Immediate(CodeGenerator::GetInt16ValueOf(value.GetConstant())));
@@ -4714,7 +4660,8 @@ void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
DataType::Type type = instruction->GetType();
switch (type) {
- case DataType::Type::kBool: {
+ case DataType::Type::kBool:
+ case DataType::Type::kUint8: {
CpuRegister out = out_loc.AsRegister<CpuRegister>();
__ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
break;
@@ -4726,12 +4673,6 @@ void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
break;
}
- case DataType::Type::kInt16: {
- CpuRegister out = out_loc.AsRegister<CpuRegister>();
- __ movsxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
- break;
- }
-
case DataType::Type::kUint16: {
CpuRegister out = out_loc.AsRegister<CpuRegister>();
if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
@@ -4754,6 +4695,12 @@ void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
break;
}
+ case DataType::Type::kInt16: {
+ CpuRegister out = out_loc.AsRegister<CpuRegister>();
+ __ movsxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+ break;
+ }
+
case DataType::Type::kInt32: {
CpuRegister out = out_loc.AsRegister<CpuRegister>();
__ movl(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_4, data_offset));
@@ -4865,6 +4812,7 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
switch (value_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8: {
uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_1, offset);
@@ -4877,8 +4825,8 @@ void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
break;
}
- case DataType::Type::kInt16:
- case DataType::Type::kUint16: {
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16: {
uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Address address = CodeGeneratorX86_64::ArrayAddress(array, index, TIMES_2, offset);
if (value.IsRegister()) {
diff --git a/compiler/optimizing/data_type-inl.h b/compiler/optimizing/data_type-inl.h
index fbc0c1215d..e389bad3ad 100644
--- a/compiler/optimizing/data_type-inl.h
+++ b/compiler/optimizing/data_type-inl.h
@@ -46,17 +46,19 @@ constexpr DataType::Type DataType::FromShorty(char type) {
constexpr char DataType::TypeId(DataType::Type type) {
// Type id for visualizer.
+ // Types corresponding to Java types are given a lower-case version of their shorty character.
switch (type) {
- case DataType::Type::kBool: return 'z';
- case DataType::Type::kInt8: return 'b';
- case DataType::Type::kUint16: return 'c';
- case DataType::Type::kInt16: return 's';
- case DataType::Type::kInt32: return 'i';
- case DataType::Type::kInt64: return 'j';
- case DataType::Type::kFloat32: return 'f';
- case DataType::Type::kFloat64: return 'd';
- case DataType::Type::kReference: return 'l';
- case DataType::Type::kVoid: return 'v';
+ case DataType::Type::kBool: return 'z'; // Java boolean (Z).
+ case DataType::Type::kUint8: return 'a'; // The character before Java byte's 'b'.
+ case DataType::Type::kInt8: return 'b'; // Java byte (B).
+ case DataType::Type::kUint16: return 'c'; // Java char (C).
+ case DataType::Type::kInt16: return 's'; // Java short (S).
+ case DataType::Type::kInt32: return 'i'; // Java int (I).
+ case DataType::Type::kInt64: return 'j'; // Java long (J).
+ case DataType::Type::kFloat32: return 'f'; // Java float (F).
+ case DataType::Type::kFloat64: return 'd'; // Java double (D).
+ case DataType::Type::kReference: return 'l'; // Java reference (L).
+ case DataType::Type::kVoid: return 'v'; // Java void (V).
}
LOG(FATAL) << "Unreachable";
UNREACHABLE();
diff --git a/compiler/optimizing/data_type.cc b/compiler/optimizing/data_type.cc
index 689061722e..3c99a76c17 100644
--- a/compiler/optimizing/data_type.cc
+++ b/compiler/optimizing/data_type.cc
@@ -21,6 +21,7 @@ namespace art {
static const char* kTypeNames[] = {
"Reference",
"Bool",
+ "Uint8",
"Int8",
"Uint16",
"Int16",
diff --git a/compiler/optimizing/data_type.h b/compiler/optimizing/data_type.h
index 08f9263127..3b67efe100 100644
--- a/compiler/optimizing/data_type.h
+++ b/compiler/optimizing/data_type.h
@@ -29,6 +29,7 @@ class DataType {
enum class Type : uint8_t {
kReference = 0,
kBool,
+ kUint8,
kInt8,
kUint16,
kInt16,
@@ -47,6 +48,7 @@ class DataType {
switch (type) {
case Type::kVoid:
case Type::kBool:
+ case Type::kUint8:
case Type::kInt8:
return 0;
case Type::kUint16:
@@ -71,6 +73,7 @@ class DataType {
case Type::kVoid:
return 0;
case Type::kBool:
+ case Type::kUint8:
case Type::kInt8:
return 1;
case Type::kUint16:
@@ -99,6 +102,7 @@ class DataType {
// our bit representation makes it safe.
switch (type) {
case Type::kBool:
+ case Type::kUint8:
case Type::kInt8:
case Type::kUint16:
case Type::kInt16:
@@ -118,10 +122,15 @@ class DataType {
return type == Type::kInt64 || type == Type::kFloat64;
}
+ static bool IsUnsignedType(Type type) {
+ return type == Type::kUint8 || type == Type::kUint16;
+ }
+
// Return the general kind of `type`, fusing integer-like types as Type::kInt.
static Type Kind(Type type) {
switch (type) {
case Type::kBool:
+ case Type::kUint8:
case Type::kInt8:
case Type::kInt16:
case Type::kUint16:
@@ -136,6 +145,8 @@ class DataType {
switch (type) {
case Type::kBool:
return std::numeric_limits<bool>::min();
+ case Type::kUint8:
+ return std::numeric_limits<uint8_t>::min();
case Type::kInt8:
return std::numeric_limits<int8_t>::min();
case Type::kUint16:
@@ -156,6 +167,8 @@ class DataType {
switch (type) {
case Type::kBool:
return std::numeric_limits<bool>::max();
+ case Type::kUint8:
+ return std::numeric_limits<uint8_t>::max();
case Type::kInt8:
return std::numeric_limits<int8_t>::max();
case Type::kUint16:
@@ -172,6 +185,8 @@ class DataType {
return 0;
}
+ static bool IsTypeConversionImplicit(Type input_type, Type result_type);
+
static const char* PrettyDescriptor(Type type);
private:
@@ -179,6 +194,25 @@ class DataType {
};
std::ostream& operator<<(std::ostream& os, DataType::Type data_type);
+// Defined outside DataType to have the operator<< available for DCHECK_NE().
+inline bool DataType::IsTypeConversionImplicit(Type input_type, Type result_type) {
+ DCHECK_NE(DataType::Type::kVoid, result_type);
+ DCHECK_NE(DataType::Type::kVoid, input_type);
+
+ // Invariant: We should never generate a conversion to a Boolean value.
+ DCHECK_NE(DataType::Type::kBool, result_type);
+
+ // Besides conversion to the same type, integral conversions to non-Int64 types
+ // are implicit if the result value range covers the input value range, i.e.
+ // widening conversions that do not need to trim the sign bits.
+ return result_type == input_type ||
+ (result_type != Type::kInt64 &&
+ IsIntegralType(input_type) &&
+ IsIntegralType(result_type) &&
+ MinValueOfIntegralType(input_type) >= MinValueOfIntegralType(result_type) &&
+ MaxValueOfIntegralType(input_type) <= MaxValueOfIntegralType(result_type));
+}
+
} // namespace art
#endif // ART_COMPILER_OPTIMIZING_DATA_TYPE_H_
diff --git a/compiler/optimizing/data_type_test.cc b/compiler/optimizing/data_type_test.cc
index 927291a54a..3ce683ac4d 100644
--- a/compiler/optimizing/data_type_test.cc
+++ b/compiler/optimizing/data_type_test.cc
@@ -18,6 +18,8 @@
#include "data_type-inl.h"
+#include "base/array_ref.h"
+#include "base/macros.h"
#include "primitive.h"
namespace art {
@@ -57,4 +59,58 @@ TEST(DataType, Names) {
#undef CHECK_NAME
}
+TEST(DataType, IsTypeConversionImplicit) {
+ static const DataType::Type kIntegralTypes[] = {
+ DataType::Type::kBool,
+ DataType::Type::kUint8,
+ DataType::Type::kInt8,
+ DataType::Type::kUint16,
+ DataType::Type::kInt16,
+ DataType::Type::kInt32,
+ DataType::Type::kInt64,
+ };
+ const ArrayRef<const DataType::Type> kIntegralInputTypes(kIntegralTypes);
+ // Note: kBool cannot be used as a result type.
+ DCHECK_EQ(kIntegralTypes[0], DataType::Type::kBool);
+ const ArrayRef<const DataType::Type> kIntegralResultTypes = kIntegralInputTypes.SubArray(1u);
+
+ static const bool kImplicitIntegralConversions[][arraysize(kIntegralTypes)] = {
+ // Bool Uint8 Int8 Uint16 Int16 Int32 Int64
+ { /* Bool N/A */ true, true, true, true, true, false },
+ { /* Uint8 N/A */ true, false, true, true, true, false },
+ { /* Int8 N/A */ false, true, false, true, true, false },
+ { /* Uint16 N/A */ false, false, true, false, true, false },
+ { /* Int16 N/A */ false, false, false, true, true, false },
+ { /* Int32 N/A */ false, false, false, false, true, false },
+ { /* Int64 N/A */ false, false, false, false, false, true },
+ };
+ static_assert(arraysize(kIntegralTypes) == arraysize(kImplicitIntegralConversions), "size check");
+
+ for (size_t input_index = 0; input_index != kIntegralInputTypes.size(); ++input_index) {
+ DataType::Type input_type = kIntegralInputTypes[input_index];
+ for (size_t result_index = 1u; result_index != kIntegralResultTypes.size(); ++result_index) {
+ DataType::Type result_type = kIntegralResultTypes[result_index];
+ EXPECT_EQ(kImplicitIntegralConversions[input_index][result_index],
+ DataType::IsTypeConversionImplicit(input_type, result_type))
+ << input_type << " " << result_type;
+ }
+ }
+ for (DataType::Type input_type : kIntegralInputTypes) {
+ EXPECT_FALSE(DataType::IsTypeConversionImplicit(input_type, DataType::Type::kFloat32));
+ EXPECT_FALSE(DataType::IsTypeConversionImplicit(input_type, DataType::Type::kFloat64));
+ }
+ for (DataType::Type result_type : kIntegralResultTypes) {
+ EXPECT_FALSE(DataType::IsTypeConversionImplicit(DataType::Type::kFloat32, result_type));
+ EXPECT_FALSE(DataType::IsTypeConversionImplicit(DataType::Type::kFloat64, result_type));
+ }
+ EXPECT_TRUE(
+ DataType::IsTypeConversionImplicit(DataType::Type::kFloat32, DataType::Type::kFloat32));
+ EXPECT_FALSE(
+ DataType::IsTypeConversionImplicit(DataType::Type::kFloat32, DataType::Type::kFloat64));
+ EXPECT_FALSE(
+ DataType::IsTypeConversionImplicit(DataType::Type::kFloat64, DataType::Type::kFloat32));
+ EXPECT_TRUE(
+ DataType::IsTypeConversionImplicit(DataType::Type::kFloat64, DataType::Type::kFloat64));
+}
+
} // namespace art
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 194f063d48..eccdccf186 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -521,20 +521,28 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor {
StartAttributeStream("kind") << deoptimize->GetKind();
}
+ void VisitVecOperation(HVecOperation* vec_operation) OVERRIDE {
+ StartAttributeStream("packed_type") << vec_operation->GetPackedType();
+ }
+
void VisitVecHalvingAdd(HVecHalvingAdd* hadd) OVERRIDE {
+ VisitVecBinaryOperation(hadd);
StartAttributeStream("unsigned") << std::boolalpha << hadd->IsUnsigned() << std::noboolalpha;
StartAttributeStream("rounded") << std::boolalpha << hadd->IsRounded() << std::noboolalpha;
}
void VisitVecMin(HVecMin* min) OVERRIDE {
+ VisitVecBinaryOperation(min);
StartAttributeStream("unsigned") << std::boolalpha << min->IsUnsigned() << std::noboolalpha;
}
void VisitVecMax(HVecMax* max) OVERRIDE {
+ VisitVecBinaryOperation(max);
StartAttributeStream("unsigned") << std::boolalpha << max->IsUnsigned() << std::noboolalpha;
}
void VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instruction) OVERRIDE {
+ VisitVecOperation(instruction);
StartAttributeStream("kind") << instruction->GetOpKind();
}
diff --git a/compiler/optimizing/induction_var_analysis.cc b/compiler/optimizing/induction_var_analysis.cc
index fe286ab88a..eab17aad31 100644
--- a/compiler/optimizing/induction_var_analysis.cc
+++ b/compiler/optimizing/induction_var_analysis.cc
@@ -59,14 +59,19 @@ static void RotateEntryPhiFirst(HLoopInformation* loop,
static bool IsNarrowingIntegralConversion(DataType::Type from, DataType::Type to) {
switch (from) {
case DataType::Type::kInt64:
- return to == DataType::Type::kInt8 || to == DataType::Type::kInt16
- || to == DataType::Type::kUint16 || to == DataType::Type::kInt32;
+ return to == DataType::Type::kUint8 ||
+ to == DataType::Type::kInt8 ||
+ to == DataType::Type::kUint16 ||
+ to == DataType::Type::kInt16 ||
+ to == DataType::Type::kInt32;
case DataType::Type::kInt32:
- return to == DataType::Type::kInt8 || to == DataType::Type::kInt16
- || to == DataType::Type::kUint16;
+ return to == DataType::Type::kUint8 ||
+ to == DataType::Type::kInt8 ||
+ to == DataType::Type::kUint16 ||
+ to == DataType::Type::kInt16;
case DataType::Type::kUint16:
case DataType::Type::kInt16:
- return to == DataType::Type::kInt8;
+ return to == DataType::Type::kUint8 || to == DataType::Type::kInt8;
default:
return false;
}
@@ -77,10 +82,11 @@ static bool IsNarrowingIntegralConversion(DataType::Type from, DataType::Type to
*/
static DataType::Type ImplicitConversion(DataType::Type type) {
switch (type) {
- case DataType::Type::kInt16:
- case DataType::Type::kUint16:
- case DataType::Type::kInt8:
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
return DataType::Type::kInt32;
default:
return type;
@@ -1142,9 +1148,10 @@ bool HInductionVarAnalysis::IsAtLeast(InductionInfo* info, int64_t* value) {
bool HInductionVarAnalysis::IsNarrowingLinear(InductionInfo* info) {
return info != nullptr &&
info->induction_class == kLinear &&
- (info->type == DataType::Type::kInt8 ||
- info->type == DataType::Type::kInt16 ||
+ (info->type == DataType::Type::kUint8 ||
+ info->type == DataType::Type::kInt8 ||
info->type == DataType::Type::kUint16 ||
+ info->type == DataType::Type::kInt16 ||
(info->type == DataType::Type::kInt32 && (info->op_a->type == DataType::Type::kInt64 ||
info->op_b->type == DataType::Type::kInt64)));
}
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index 92b584cc3b..ab6fbae248 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -159,9 +159,10 @@ static bool IsConstantValue(InductionVarRange::Value v) {
/** Corrects a value for type to account for arithmetic wrap-around in lower precision. */
static InductionVarRange::Value CorrectForType(InductionVarRange::Value v, DataType::Type type) {
switch (type) {
- case DataType::Type::kInt16:
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
case DataType::Type::kUint16:
- case DataType::Type::kInt8: {
+ case DataType::Type::kInt16: {
// Constants within range only.
// TODO: maybe some room for improvement, like allowing widening conversions
int32_t min = DataType::MinValueOfIntegralType(type);
@@ -216,10 +217,11 @@ bool InductionVarRange::GetInductionRange(HInstruction* context,
// bounds check elimination, will have truncated higher precision induction
// at their use point already).
switch (info->type) {
- case DataType::Type::kInt32:
- case DataType::Type::kInt16:
- case DataType::Type::kUint16:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ case DataType::Type::kInt32:
break;
default:
return false;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 1a2494a992..6610bcc713 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -251,7 +251,8 @@ bool InstructionSimplifierVisitor::TryCombineVecMultiplyAccumulate(HVecMul* mul)
InstructionSet isa = codegen_->GetInstructionSet();
switch (isa) {
case kArm64:
- if (!(type == DataType::Type::kInt8 ||
+ if (!(type == DataType::Type::kUint8 ||
+ type == DataType::Type::kInt8 ||
type == DataType::Type::kUint16 ||
type == DataType::Type::kInt16 ||
type == DataType::Type::kInt32)) {
@@ -260,7 +261,8 @@ bool InstructionSimplifierVisitor::TryCombineVecMultiplyAccumulate(HVecMul* mul)
break;
case kMips:
case kMips64:
- if (!(type == DataType::Type::kInt8 ||
+ if (!(type == DataType::Type::kUint8 ||
+ type == DataType::Type::kInt8 ||
type == DataType::Type::kUint16 ||
type == DataType::Type::kInt16 ||
type == DataType::Type::kInt32 ||
@@ -311,7 +313,8 @@ bool InstructionSimplifierVisitor::TryCombineVecMultiplyAccumulate(HVecMul* mul)
mul->GetLeft(),
mul->GetRight(),
binop->GetPackedType(),
- binop->GetVectorLength());
+ binop->GetVectorLength(),
+ binop->GetDexPc());
binop->GetBlock()->ReplaceAndRemoveInstructionWith(binop, mulacc);
DCHECK(!mul->HasUses());
@@ -360,18 +363,36 @@ void InstructionSimplifierVisitor::VisitShift(HBinaryOperation* instruction) {
}
// Shift operations implicitly mask the shift amount according to the type width. Get rid of
- // unnecessary explicit masking operations on the shift amount.
+ // unnecessary And/Or/Xor/Add/Sub/TypeConversion operations on the shift amount that do not
+ // affect the relevant bits.
// Replace code looking like
- // AND masked_shift, shift, <superset of implicit mask>
- // SHL dst, value, masked_shift
+ // AND adjusted_shift, shift, <superset of implicit mask>
+ // [OR/XOR/ADD/SUB adjusted_shift, shift, <value not overlapping with implicit mask>]
+ // [<conversion-from-integral-non-64-bit-type> adjusted_shift, shift]
+ // SHL dst, value, adjusted_shift
// with
// SHL dst, value, shift
- if (shift_amount->IsAnd()) {
- HAnd* and_insn = shift_amount->AsAnd();
- HConstant* mask = and_insn->GetConstantRight();
- if ((mask != nullptr) && ((Int64FromConstant(mask) & implicit_mask) == implicit_mask)) {
- instruction->ReplaceInput(and_insn->GetLeastConstantLeft(), 1);
+ if (shift_amount->IsAnd() ||
+ shift_amount->IsOr() ||
+ shift_amount->IsXor() ||
+ shift_amount->IsAdd() ||
+ shift_amount->IsSub()) {
+ int64_t required_result = shift_amount->IsAnd() ? implicit_mask : 0;
+ HBinaryOperation* bin_op = shift_amount->AsBinaryOperation();
+ HConstant* mask = bin_op->GetConstantRight();
+ if (mask != nullptr && (Int64FromConstant(mask) & implicit_mask) == required_result) {
+ instruction->ReplaceInput(bin_op->GetLeastConstantLeft(), 1);
RecordSimplification();
+ return;
+ }
+ } else if (shift_amount->IsTypeConversion()) {
+ DCHECK_NE(shift_amount->GetType(), DataType::Type::kBool); // We never convert to bool.
+ DataType::Type source_type = shift_amount->InputAt(0)->GetType();
+ // Non-integral and 64-bit source types require an explicit type conversion.
+ if (DataType::IsIntegralType(source_type) && !DataType::Is64BitType(source_type)) {
+ instruction->ReplaceInput(shift_amount->AsTypeConversion()->GetInput(), 1);
+ RecordSimplification();
+ return;
}
}
}
@@ -858,10 +879,11 @@ static bool AreLowerPrecisionArgs(DataType::Type to_type, HInstruction* a, HInst
}
DataType::Type type1 = a->GetType();
DataType::Type type2 = b->GetType();
- return (type1 == DataType::Type::kInt8 && type2 == DataType::Type::kInt8) ||
- (type1 == DataType::Type::kInt16 && type2 == DataType::Type::kInt16) ||
- (type1 == DataType::Type::kUint16 && type2 == DataType::Type::kUint16) ||
- (type1 == DataType::Type::kInt32 && type2 == DataType::Type::kInt32 &&
+ return (type1 == DataType::Type::kUint8 && type2 == DataType::Type::kUint8) ||
+ (type1 == DataType::Type::kInt8 && type2 == DataType::Type::kInt8) ||
+ (type1 == DataType::Type::kInt16 && type2 == DataType::Type::kInt16) ||
+ (type1 == DataType::Type::kUint16 && type2 == DataType::Type::kUint16) ||
+ (type1 == DataType::Type::kInt32 && type2 == DataType::Type::kInt32 &&
to_type == DataType::Type::kInt64);
}
@@ -1018,30 +1040,13 @@ void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
}
}
-static bool IsTypeConversionImplicit(DataType::Type input_type, DataType::Type result_type) {
- // Invariant: We should never generate a conversion to a Boolean value.
- DCHECK_NE(DataType::Type::kBool, 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 == DataType::Type::kInt32 && (input_type == DataType::Type::kBool ||
- input_type == DataType::Type::kInt8 ||
- input_type == DataType::Type::kInt16 ||
- input_type == DataType::Type::kUint16)) ||
- (result_type == DataType::Type::kUint16 && input_type == DataType::Type::kBool) ||
- (result_type == DataType::Type::kInt16 && (input_type == DataType::Type::kBool ||
- input_type == DataType::Type::kInt8)) ||
- (result_type == DataType::Type::kInt8 && input_type == DataType::Type::kBool);
-}
-
static bool IsTypeConversionLossless(DataType::Type input_type, DataType::Type result_type) {
// The conversion to a larger type is loss-less with the exception of two cases,
- // - conversion to Uint16, the only unsigned type, where we may lose some bits, and
+ // - conversion to the unsigned type Uint16, 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);
+ // Note: The size check excludes Uint8 as the result type.
+ DCHECK(!DataType::IsTypeConversionImplicit(input_type, result_type));
return DataType::Size(result_type) > DataType::Size(input_type) &&
result_type != DataType::Type::kUint16 &&
!(result_type == DataType::Type::kInt64 && input_type == DataType::Type::kFloat32);
@@ -1051,7 +1056,7 @@ void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruct
HInstruction* input = instruction->GetInput();
DataType::Type input_type = input->GetType();
DataType::Type result_type = instruction->GetResultType();
- if (IsTypeConversionImplicit(input_type, result_type)) {
+ if (DataType::IsTypeConversionImplicit(input_type, result_type)) {
// Remove the implicit conversion; this includes conversion to the same type.
instruction->ReplaceWith(input);
instruction->GetBlock()->RemoveInstruction(instruction);
@@ -1080,7 +1085,7 @@ void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruct
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)) {
+ if (DataType::IsTypeConversionImplicit(original_type, result_type)) {
instruction->ReplaceWith(original_input);
instruction->GetBlock()->RemoveInstruction(instruction);
if (!input_conversion->HasUses()) {
@@ -1109,7 +1114,7 @@ void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruct
if (trailing_ones >= kBitsPerByte * DataType::Size(result_type)) {
// The `HAnd` is useless, for example in `(byte) (x & 0xff)`, get rid of it.
HInstruction* original_input = input_and->GetLeastConstantLeft();
- if (IsTypeConversionImplicit(original_input->GetType(), result_type)) {
+ if (DataType::IsTypeConversionImplicit(original_input->GetType(), result_type)) {
instruction->ReplaceWith(original_input);
instruction->GetBlock()->RemoveInstruction(instruction);
RecordSimplification();
@@ -1226,6 +1231,37 @@ void InstructionSimplifierVisitor::VisitAnd(HAnd* instruction) {
RecordSimplification();
return;
}
+ if (input_other->IsTypeConversion() &&
+ input_other->GetType() == DataType::Type::kInt64 &&
+ DataType::IsIntegralType(input_other->InputAt(0)->GetType()) &&
+ IsInt<32>(value) &&
+ input_other->HasOnlyOneNonEnvironmentUse()) {
+ // The AND can be reordered before the TypeConversion. Replace
+ // LongConstant cst, <32-bit-constant-sign-extended-to-64-bits>
+ // TypeConversion<Int64> tmp, src
+ // AND dst, tmp, cst
+ // with
+ // IntConstant cst, <32-bit-constant>
+ // AND tmp, src, cst
+ // TypeConversion<Int64> dst, tmp
+ // This helps 32-bit targets and does not hurt 64-bit targets.
+ // This also simplifies detection of other patterns, such as Uint8 loads.
+ HInstruction* new_and_input = input_other->InputAt(0);
+ // Implicit conversion Int64->Int64 would have been removed previously.
+ DCHECK_NE(new_and_input->GetType(), DataType::Type::kInt64);
+ HConstant* new_const = GetGraph()->GetConstant(DataType::Type::kInt32, value);
+ HAnd* new_and =
+ new (GetGraph()->GetArena()) HAnd(DataType::Type::kInt32, new_and_input, new_const);
+ instruction->GetBlock()->InsertInstructionBefore(new_and, instruction);
+ HTypeConversion* new_conversion =
+ new (GetGraph()->GetArena()) HTypeConversion(DataType::Type::kInt64, new_and);
+ instruction->GetBlock()->ReplaceAndRemoveInstructionWith(instruction, new_conversion);
+ input_other->GetBlock()->RemoveInstruction(input_other);
+ RecordSimplification();
+ // Try to process the new And now, do not wait for the next round of simplifications.
+ instruction = new_and;
+ input_other = new_and_input;
+ }
// Eliminate And from UShr+And if the And-mask contains all the bits that
// can be non-zero after UShr. Transform Shr+And to UShr if the And-mask
// precisely clears the shifted-in sign bits.
@@ -2149,8 +2185,12 @@ void InstructionSimplifierVisitor::SimplifyStringCharAt(HInvoke* invoke) {
HBoundsCheck* bounds_check = new (arena) HBoundsCheck(
index, length, dex_pc, invoke->GetDexMethodIndex());
invoke->GetBlock()->InsertInstructionBefore(bounds_check, invoke);
- HArrayGet* array_get = new (arena) HArrayGet(
- str, bounds_check, DataType::Type::kUint16, dex_pc, /* is_string_char_at */ true);
+ HArrayGet* array_get = new (arena) HArrayGet(str,
+ bounds_check,
+ DataType::Type::kUint16,
+ SideEffects::None(), // Strings are immutable.
+ dex_pc,
+ /* is_string_char_at */ true);
invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, array_get);
bounds_check->CopyEnvironmentFrom(invoke->GetEnvironment());
GetGraph()->SetHasBoundsChecks(true);
@@ -2312,6 +2352,21 @@ void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) {
case Intrinsics::kUnsafeFullFence:
SimplifyMemBarrier(instruction, MemBarrierKind::kAnyAny);
break;
+ case Intrinsics::kVarHandleFullFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kAnyAny);
+ break;
+ case Intrinsics::kVarHandleAcquireFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny);
+ break;
+ case Intrinsics::kVarHandleReleaseFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kAnyStore);
+ break;
+ case Intrinsics::kVarHandleLoadLoadFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kLoadAny);
+ break;
+ case Intrinsics::kVarHandleStoreStoreFence:
+ SimplifyMemBarrier(instruction, MemBarrierKind::kStoreStore);
+ break;
default:
break;
}
diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc
index efd7cb47fe..7439893787 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -30,6 +30,57 @@ using helpers::HasShifterOperand;
namespace arm {
+class InstructionSimplifierArmVisitor : public HGraphVisitor {
+ public:
+ InstructionSimplifierArmVisitor(HGraph* graph, OptimizingCompilerStats* stats)
+ : HGraphVisitor(graph), stats_(stats) {}
+
+ private:
+ void RecordSimplification() {
+ if (stats_ != nullptr) {
+ stats_->RecordStat(kInstructionSimplificationsArch);
+ }
+ }
+
+ bool TryMergeIntoUsersShifterOperand(HInstruction* instruction);
+ bool TryMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op, bool do_merge);
+ bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
+ return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false);
+ }
+ bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
+ DCHECK(CanMergeIntoShifterOperand(use, bitfield_op));
+ return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true);
+ }
+
+ /**
+ * This simplifier uses a special-purpose BB visitor.
+ * (1) No need to visit Phi nodes.
+ * (2) Since statements can be removed in a "forward" fashion,
+ * the visitor should test if each statement is still there.
+ */
+ void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
+ // TODO: fragile iteration, provide more robust iterators?
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ HInstruction* instruction = it.Current();
+ if (instruction->IsInBlock()) {
+ instruction->Accept(this);
+ }
+ }
+ }
+
+ void VisitAnd(HAnd* instruction) OVERRIDE;
+ void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
+ void VisitArraySet(HArraySet* instruction) OVERRIDE;
+ void VisitMul(HMul* instruction) OVERRIDE;
+ void VisitOr(HOr* instruction) OVERRIDE;
+ void VisitShl(HShl* instruction) OVERRIDE;
+ void VisitShr(HShr* instruction) OVERRIDE;
+ void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
+ void VisitUShr(HUShr* instruction) OVERRIDE;
+
+ OptimizingCompilerStats* stats_;
+};
+
bool InstructionSimplifierArmVisitor::TryMergeIntoShifterOperand(HInstruction* use,
HInstruction* bitfield_op,
bool do_merge) {
@@ -234,5 +285,10 @@ void InstructionSimplifierArmVisitor::VisitUShr(HUShr* instruction) {
}
}
+void InstructionSimplifierArm::Run() {
+ InstructionSimplifierArmVisitor visitor(graph_, stats_);
+ visitor.VisitReversePostOrder();
+}
+
} // namespace arm
} // namespace art
diff --git a/compiler/optimizing/instruction_simplifier_arm.h b/compiler/optimizing/instruction_simplifier_arm.h
index e2ed257777..2f6572931f 100644
--- a/compiler/optimizing/instruction_simplifier_arm.h
+++ b/compiler/optimizing/instruction_simplifier_arm.h
@@ -23,58 +23,6 @@
namespace art {
namespace arm {
-class InstructionSimplifierArmVisitor : public HGraphVisitor {
- public:
- InstructionSimplifierArmVisitor(HGraph* graph, OptimizingCompilerStats* stats)
- : HGraphVisitor(graph), stats_(stats) {}
-
- private:
- void RecordSimplification() {
- if (stats_ != nullptr) {
- stats_->RecordStat(kInstructionSimplificationsArch);
- }
- }
-
- bool TryMergeIntoUsersShifterOperand(HInstruction* instruction);
- bool TryMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op, bool do_merge);
- bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
- return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false);
- }
- bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
- DCHECK(CanMergeIntoShifterOperand(use, bitfield_op));
- return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true);
- }
-
- /**
- * This simplifier uses a special-purpose BB visitor.
- * (1) No need to visit Phi nodes.
- * (2) Since statements can be removed in a "forward" fashion,
- * the visitor should test if each statement is still there.
- */
- void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
- // TODO: fragile iteration, provide more robust iterators?
- for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
- HInstruction* instruction = it.Current();
- if (instruction->IsInBlock()) {
- instruction->Accept(this);
- }
- }
- }
-
- void VisitAnd(HAnd* instruction) OVERRIDE;
- void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
- void VisitArraySet(HArraySet* instruction) OVERRIDE;
- void VisitMul(HMul* instruction) OVERRIDE;
- void VisitOr(HOr* instruction) OVERRIDE;
- void VisitShl(HShl* instruction) OVERRIDE;
- void VisitShr(HShr* instruction) OVERRIDE;
- void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
- void VisitUShr(HUShr* instruction) OVERRIDE;
-
- OptimizingCompilerStats* stats_;
-};
-
-
class InstructionSimplifierArm : public HOptimization {
public:
InstructionSimplifierArm(HGraph* graph, OptimizingCompilerStats* stats)
@@ -82,10 +30,7 @@ class InstructionSimplifierArm : public HOptimization {
static constexpr const char* kInstructionSimplifierArmPassName = "instruction_simplifier_arm";
- void Run() OVERRIDE {
- InstructionSimplifierArmVisitor visitor(graph_, stats_);
- visitor.VisitReversePostOrder();
- }
+ void Run() OVERRIDE;
};
} // namespace arm
diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc
index 1c3b79dc03..c639953536 100644
--- a/compiler/optimizing/instruction_simplifier_arm64.cc
+++ b/compiler/optimizing/instruction_simplifier_arm64.cc
@@ -30,6 +30,63 @@ namespace arm64 {
using helpers::ShifterOperandSupportsExtension;
+class InstructionSimplifierArm64Visitor : public HGraphVisitor {
+ public:
+ InstructionSimplifierArm64Visitor(HGraph* graph, OptimizingCompilerStats* stats)
+ : HGraphVisitor(graph), stats_(stats) {}
+
+ private:
+ void RecordSimplification() {
+ if (stats_ != nullptr) {
+ stats_->RecordStat(kInstructionSimplificationsArch);
+ }
+ }
+
+ bool TryMergeIntoUsersShifterOperand(HInstruction* instruction);
+ bool TryMergeIntoShifterOperand(HInstruction* use,
+ HInstruction* bitfield_op,
+ bool do_merge);
+ bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
+ return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false);
+ }
+ bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
+ DCHECK(CanMergeIntoShifterOperand(use, bitfield_op));
+ return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true);
+ }
+
+ /**
+ * This simplifier uses a special-purpose BB visitor.
+ * (1) No need to visit Phi nodes.
+ * (2) Since statements can be removed in a "forward" fashion,
+ * the visitor should test if each statement is still there.
+ */
+ void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
+ // TODO: fragile iteration, provide more robust iterators?
+ for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+ HInstruction* instruction = it.Current();
+ if (instruction->IsInBlock()) {
+ instruction->Accept(this);
+ }
+ }
+ }
+
+ // HInstruction visitors, sorted alphabetically.
+ void VisitAnd(HAnd* instruction) OVERRIDE;
+ void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
+ void VisitArraySet(HArraySet* instruction) OVERRIDE;
+ void VisitMul(HMul* instruction) OVERRIDE;
+ void VisitOr(HOr* instruction) OVERRIDE;
+ void VisitShl(HShl* instruction) OVERRIDE;
+ void VisitShr(HShr* instruction) OVERRIDE;
+ void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
+ void VisitUShr(HUShr* instruction) OVERRIDE;
+ void VisitXor(HXor* instruction) OVERRIDE;
+ void VisitVecLoad(HVecLoad* instruction) OVERRIDE;
+ void VisitVecStore(HVecStore* instruction) OVERRIDE;
+
+ OptimizingCompilerStats* stats_;
+};
+
bool InstructionSimplifierArm64Visitor::TryMergeIntoShifterOperand(HInstruction* use,
HInstruction* bitfield_op,
bool do_merge) {
@@ -223,5 +280,10 @@ void InstructionSimplifierArm64Visitor::VisitVecStore(HVecStore* instruction) {
}
}
+void InstructionSimplifierArm64::Run() {
+ InstructionSimplifierArm64Visitor visitor(graph_, stats_);
+ visitor.VisitReversePostOrder();
+}
+
} // namespace arm64
} // namespace art
diff --git a/compiler/optimizing/instruction_simplifier_arm64.h b/compiler/optimizing/instruction_simplifier_arm64.h
index 4f16fc383d..d180a8dc46 100644
--- a/compiler/optimizing/instruction_simplifier_arm64.h
+++ b/compiler/optimizing/instruction_simplifier_arm64.h
@@ -23,64 +23,6 @@
namespace art {
namespace arm64 {
-class InstructionSimplifierArm64Visitor : public HGraphVisitor {
- public:
- InstructionSimplifierArm64Visitor(HGraph* graph, OptimizingCompilerStats* stats)
- : HGraphVisitor(graph), stats_(stats) {}
-
- private:
- void RecordSimplification() {
- if (stats_ != nullptr) {
- stats_->RecordStat(kInstructionSimplificationsArch);
- }
- }
-
- bool TryMergeIntoUsersShifterOperand(HInstruction* instruction);
- bool TryMergeIntoShifterOperand(HInstruction* use,
- HInstruction* bitfield_op,
- bool do_merge);
- bool CanMergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
- return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ false);
- }
- bool MergeIntoShifterOperand(HInstruction* use, HInstruction* bitfield_op) {
- DCHECK(CanMergeIntoShifterOperand(use, bitfield_op));
- return TryMergeIntoShifterOperand(use, bitfield_op, /* do_merge */ true);
- }
-
- /**
- * This simplifier uses a special-purpose BB visitor.
- * (1) No need to visit Phi nodes.
- * (2) Since statements can be removed in a "forward" fashion,
- * the visitor should test if each statement is still there.
- */
- void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
- // TODO: fragile iteration, provide more robust iterators?
- for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
- HInstruction* instruction = it.Current();
- if (instruction->IsInBlock()) {
- instruction->Accept(this);
- }
- }
- }
-
- // HInstruction visitors, sorted alphabetically.
- void VisitAnd(HAnd* instruction) OVERRIDE;
- void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
- void VisitArraySet(HArraySet* instruction) OVERRIDE;
- void VisitMul(HMul* instruction) OVERRIDE;
- void VisitOr(HOr* instruction) OVERRIDE;
- void VisitShl(HShl* instruction) OVERRIDE;
- void VisitShr(HShr* instruction) OVERRIDE;
- void VisitTypeConversion(HTypeConversion* instruction) OVERRIDE;
- void VisitUShr(HUShr* instruction) OVERRIDE;
- void VisitXor(HXor* instruction) OVERRIDE;
- void VisitVecLoad(HVecLoad* instruction) OVERRIDE;
- void VisitVecStore(HVecStore* instruction) OVERRIDE;
-
- OptimizingCompilerStats* stats_;
-};
-
-
class InstructionSimplifierArm64 : public HOptimization {
public:
InstructionSimplifierArm64(HGraph* graph, OptimizingCompilerStats* stats)
@@ -88,10 +30,7 @@ class InstructionSimplifierArm64 : public HOptimization {
static constexpr const char* kInstructionSimplifierArm64PassName = "instruction_simplifier_arm64";
- void Run() OVERRIDE {
- InstructionSimplifierArm64Visitor visitor(graph_, stats_);
- visitor.VisitReversePostOrder();
- }
+ void Run() OVERRIDE;
};
} // namespace arm64
diff --git a/compiler/optimizing/instruction_simplifier_mips.cc b/compiler/optimizing/instruction_simplifier_mips.cc
new file mode 100644
index 0000000000..4bf1bfb9f3
--- /dev/null
+++ b/compiler/optimizing/instruction_simplifier_mips.cc
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_simplifier_mips.h"
+
+#include "arch/mips/instruction_set_features_mips.h"
+#include "mirror/array-inl.h"
+
+namespace art {
+namespace mips {
+
+class InstructionSimplifierMipsVisitor : public HGraphVisitor {
+ public:
+ InstructionSimplifierMipsVisitor(HGraph* graph,
+ CodeGenerator* codegen,
+ OptimizingCompilerStats* stats)
+ : HGraphVisitor(graph),
+ stats_(stats),
+ codegen_(down_cast<CodeGeneratorMIPS*>(codegen)) {}
+
+ private:
+ void RecordSimplification() {
+ if (stats_ != nullptr) {
+ stats_->RecordStat(kInstructionSimplificationsArch);
+ }
+ }
+
+ bool TryExtractArrayAccessIndex(HInstruction* access,
+ HInstruction* index,
+ DataType::Type packed_type);
+ void VisitArrayGet(HArrayGet* instruction) OVERRIDE;
+ void VisitArraySet(HArraySet* instruction) OVERRIDE;
+
+ OptimizingCompilerStats* stats_;
+ CodeGeneratorMIPS* codegen_;
+};
+
+bool InstructionSimplifierMipsVisitor::TryExtractArrayAccessIndex(HInstruction* access,
+ HInstruction* index,
+ DataType::Type packed_type) {
+ if (codegen_->GetInstructionSetFeatures().IsR6() ||
+ codegen_->GetInstructionSetFeatures().HasMsa()) {
+ return false;
+ }
+ if (index->IsConstant() ||
+ (index->IsBoundsCheck() && index->AsBoundsCheck()->GetIndex()->IsConstant())) {
+ // If index is constant the whole address calculation often can be done by load/store
+ // instructions themselves.
+ // TODO: Treat the case with non-embeddable constants.
+ return false;
+ }
+
+ if (packed_type != DataType::Type::kInt16 && packed_type != DataType::Type::kUint16 &&
+ packed_type != DataType::Type::kInt32 && packed_type != DataType::Type::kInt64 &&
+ packed_type != DataType::Type::kFloat32 && packed_type != DataType::Type::kFloat64) {
+ return false;
+ }
+
+ if (access->IsArrayGet() && access->AsArrayGet()->IsStringCharAt()) {
+ return false;
+ }
+
+ HGraph* graph = access->GetBlock()->GetGraph();
+ ArenaAllocator* arena = graph->GetArena();
+ size_t component_shift = DataType::SizeShift(packed_type);
+
+ bool is_extracting_beneficial = false;
+ // It is beneficial to extract index intermediate address only if there are at least 2 users.
+ for (const HUseListNode<HInstruction*>& use : index->GetUses()) {
+ HInstruction* user = use.GetUser();
+ if (user->IsArrayGet() && user != access && !user->AsArrayGet()->IsStringCharAt()) {
+ HArrayGet* another_access = user->AsArrayGet();
+ DataType::Type another_packed_type = another_access->GetType();
+ size_t another_component_shift = DataType::SizeShift(another_packed_type);
+ if (another_component_shift == component_shift) {
+ is_extracting_beneficial = true;
+ break;
+ }
+ } else if (user->IsArraySet() && user != access) {
+ HArraySet* another_access = user->AsArraySet();
+ DataType::Type another_packed_type = another_access->GetType();
+ size_t another_component_shift = DataType::SizeShift(another_packed_type);
+ if (another_component_shift == component_shift) {
+ is_extracting_beneficial = true;
+ break;
+ }
+ } else if (user->IsIntermediateArrayAddressIndex()) {
+ HIntermediateArrayAddressIndex* another_access = user->AsIntermediateArrayAddressIndex();
+ size_t another_component_shift = another_access->GetShift()->AsIntConstant()->GetValue();
+ if (another_component_shift == component_shift) {
+ is_extracting_beneficial = true;
+ break;
+ }
+ }
+ }
+
+ if (!is_extracting_beneficial) {
+ return false;
+ }
+
+ HIntConstant* shift = graph->GetIntConstant(component_shift);
+ HIntermediateArrayAddressIndex* address =
+ new (arena) HIntermediateArrayAddressIndex(index, shift, kNoDexPc);
+ access->GetBlock()->InsertInstructionBefore(address, access);
+ access->ReplaceInput(address, 1);
+ return true;
+}
+
+void InstructionSimplifierMipsVisitor::VisitArrayGet(HArrayGet* instruction) {
+ DataType::Type packed_type = instruction->GetType();
+ if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) {
+ RecordSimplification();
+ }
+}
+
+void InstructionSimplifierMipsVisitor::VisitArraySet(HArraySet* instruction) {
+ DataType::Type packed_type = instruction->GetComponentType();
+ if (TryExtractArrayAccessIndex(instruction, instruction->GetIndex(), packed_type)) {
+ RecordSimplification();
+ }
+}
+
+void InstructionSimplifierMips::Run() {
+ InstructionSimplifierMipsVisitor visitor(graph_, codegen_, stats_);
+ visitor.VisitReversePostOrder();
+}
+
+} // namespace mips
+} // namespace art
diff --git a/compiler/optimizing/instruction_simplifier_mips.h b/compiler/optimizing/instruction_simplifier_mips.h
new file mode 100644
index 0000000000..22cc2efc1a
--- /dev/null
+++ b/compiler/optimizing/instruction_simplifier_mips.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_MIPS_H_
+#define ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_MIPS_H_
+
+#include "nodes.h"
+#include "optimization.h"
+#include "code_generator_mips.h"
+
+namespace art {
+
+class CodeGenerator;
+
+namespace mips {
+
+class InstructionSimplifierMips : public HOptimization {
+ public:
+ InstructionSimplifierMips(HGraph* graph, CodeGenerator* codegen, OptimizingCompilerStats* stats)
+ : HOptimization(graph, "instruction_simplifier_mips", stats),
+ codegen_(down_cast<CodeGeneratorMIPS*>(codegen)) {}
+
+ static constexpr const char* kInstructionSimplifierMipsPassName = "instruction_simplifier_mips";
+
+ void Run() OVERRIDE;
+
+ private:
+ CodeGeneratorMIPS* codegen_;
+};
+
+} // namespace mips
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_MIPS_H_
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 11725f43c3..0f14d2728b 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -30,6 +30,16 @@
namespace art {
+// Check that intrinsic enum values fit within space set aside in ArtMethod modifier flags.
+#define CHECK_INTRINSICS_ENUM_VALUES(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
+ static_assert( \
+ static_cast<uint32_t>(Intrinsics::k ## Name) <= (kAccIntrinsicBits >> CTZ(kAccIntrinsicBits)), \
+ "Instrinsics enumeration space overflow.");
+#include "intrinsics_list.h"
+ INTRINSICS_LIST(CHECK_INTRINSICS_ENUM_VALUES)
+#undef INTRINSICS_LIST
+#undef CHECK_INTRINSICS_ENUM_VALUES
+
// Function that returns whether an intrinsic is static/direct or virtual.
static inline InvokeType GetIntrinsicInvokeType(Intrinsics i) {
switch (i) {
@@ -109,6 +119,7 @@ static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
// InvokeStaticOrDirect.
InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
InvokeType invoke_type = invoke->GetInvokeType();
+
switch (intrinsic_type) {
case kStatic:
return (invoke_type == kStatic);
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 6411e82f92..7abfd5b74e 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -256,25 +256,30 @@ void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke) { \
LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic() \
<< " should have been converted to HIR"; \
}
-#define UNREACHABLE_INTRINSICS(Arch) \
-UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits) \
-UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits) \
-UNREACHABLE_INTRINSIC(Arch, FloatIsNaN) \
-UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN) \
-UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft) \
-UNREACHABLE_INTRINSIC(Arch, LongRotateLeft) \
-UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight) \
-UNREACHABLE_INTRINSIC(Arch, LongRotateRight) \
-UNREACHABLE_INTRINSIC(Arch, IntegerCompare) \
-UNREACHABLE_INTRINSIC(Arch, LongCompare) \
-UNREACHABLE_INTRINSIC(Arch, IntegerSignum) \
-UNREACHABLE_INTRINSIC(Arch, LongSignum) \
-UNREACHABLE_INTRINSIC(Arch, StringCharAt) \
-UNREACHABLE_INTRINSIC(Arch, StringIsEmpty) \
-UNREACHABLE_INTRINSIC(Arch, StringLength) \
-UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence) \
-UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence) \
-UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence)
+#define UNREACHABLE_INTRINSICS(Arch) \
+UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits) \
+UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits) \
+UNREACHABLE_INTRINSIC(Arch, FloatIsNaN) \
+UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN) \
+UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft) \
+UNREACHABLE_INTRINSIC(Arch, LongRotateLeft) \
+UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight) \
+UNREACHABLE_INTRINSIC(Arch, LongRotateRight) \
+UNREACHABLE_INTRINSIC(Arch, IntegerCompare) \
+UNREACHABLE_INTRINSIC(Arch, LongCompare) \
+UNREACHABLE_INTRINSIC(Arch, IntegerSignum) \
+UNREACHABLE_INTRINSIC(Arch, LongSignum) \
+UNREACHABLE_INTRINSIC(Arch, StringCharAt) \
+UNREACHABLE_INTRINSIC(Arch, StringIsEmpty) \
+UNREACHABLE_INTRINSIC(Arch, StringLength) \
+UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence) \
+UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence) \
+UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleFullFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleAcquireFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleReleaseFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleLoadLoadFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleStoreStoreFence)
template <typename IntrinsicLocationsBuilder, typename Codegenerator>
bool IsCallFreeIntrinsic(HInvoke* invoke, Codegenerator* codegen) {
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index bd14f2b142..54c2d43e9c 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -276,6 +276,7 @@ class LSEVisitor : public HGraphVisitor {
case DataType::Type::kReference:
return GetGraph()->GetNullConstant();
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index 7e37018229..c51fafa695 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -28,6 +28,46 @@
namespace art {
+// TODO: Clean up the packed type detection so that we have the right type straight away
+// and do not need to go through this normalization.
+static inline void NormalizePackedType(/* inout */ DataType::Type* type,
+ /* inout */ bool* is_unsigned) {
+ switch (*type) {
+ case DataType::Type::kBool:
+ DCHECK(!*is_unsigned);
+ break;
+ case DataType::Type::kUint8:
+ case DataType::Type::kInt8:
+ if (*is_unsigned) {
+ *is_unsigned = false;
+ *type = DataType::Type::kUint8;
+ } else {
+ *type = DataType::Type::kInt8;
+ }
+ break;
+ case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
+ if (*is_unsigned) {
+ *is_unsigned = false;
+ *type = DataType::Type::kUint16;
+ } else {
+ *type = DataType::Type::kInt16;
+ }
+ break;
+ case DataType::Type::kInt32:
+ case DataType::Type::kInt64:
+ // We do not have kUint32 and kUint64 at the moment.
+ break;
+ case DataType::Type::kFloat32:
+ case DataType::Type::kFloat64:
+ DCHECK(!*is_unsigned);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected type " << *type;
+ UNREACHABLE();
+ }
+}
+
// Enables vectorization (SIMDization) in the loop optimizer.
static constexpr bool kEnableVectorization = true;
@@ -74,22 +114,20 @@ static bool IsEarlyExit(HLoopInformation* loop_info) {
// Forward declaration.
static bool IsZeroExtensionAndGet(HInstruction* instruction,
DataType::Type type,
- /*out*/ HInstruction** operand,
- bool to64 = false);
+ /*out*/ HInstruction** operand);
-// Detect a sign extension in instruction from the given type. The to64 parameter
-// denotes if result is long, and thus sign extension from int can be included.
+// Detect a sign extension in instruction from the given type.
// Returns the promoted operand on success.
static bool IsSignExtensionAndGet(HInstruction* instruction,
DataType::Type type,
- /*out*/ HInstruction** operand,
- bool to64 = false) {
+ /*out*/ HInstruction** operand) {
// Accept any already wider constant that would be handled properly by sign
// extension when represented in the *width* of the given narrower data type
- // (the fact that char normally zero extends does not matter here).
+ // (the fact that Uint16 normally zero extends does not matter here).
int64_t value = 0;
if (IsInt64AndGet(instruction, /*out*/ &value)) {
switch (type) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
if (IsInt<8>(value)) {
*operand = instruction;
@@ -103,43 +141,39 @@ static bool IsSignExtensionAndGet(HInstruction* instruction,
return true;
}
return false;
- case DataType::Type::kInt32:
- if (IsInt<32>(value)) {
- *operand = instruction;
- return to64;
- }
- return false;
default:
return false;
}
}
- // An implicit widening conversion of a signed integer to an integral type sign-extends
- // the two's-complement representation of the integer value to fill the wider format.
- if (instruction->GetType() == type && (instruction->IsArrayGet() ||
- instruction->IsStaticFieldGet() ||
- instruction->IsInstanceFieldGet())) {
+ // An implicit widening conversion of any signed expression sign-extends.
+ if (instruction->GetType() == type) {
switch (type) {
case DataType::Type::kInt8:
case DataType::Type::kInt16:
*operand = instruction;
return true;
- case DataType::Type::kInt32:
- *operand = instruction;
- return to64;
default:
return false;
}
}
- // Explicit type conversions.
+ // An explicit widening conversion of a signed expression sign-extends.
if (instruction->IsTypeConversion()) {
- DataType::Type from = instruction->InputAt(0)->GetType();
+ HInstruction* conv = instruction->InputAt(0);
+ DataType::Type from = conv->GetType();
switch (instruction->GetType()) {
+ case DataType::Type::kInt32:
case DataType::Type::kInt64:
- return IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+ if (type == from && (from == DataType::Type::kInt8 ||
+ from == DataType::Type::kInt16 ||
+ from == DataType::Type::kInt32)) {
+ *operand = conv;
+ return true;
+ }
+ return false;
case DataType::Type::kInt16:
return type == DataType::Type::kUint16 &&
from == DataType::Type::kUint16 &&
- IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, to64);
+ IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand);
default:
return false;
}
@@ -147,19 +181,18 @@ static bool IsSignExtensionAndGet(HInstruction* instruction,
return false;
}
-// Detect a zero extension in instruction from the given type. The to64 parameter
-// denotes if result is long, and thus zero extension from int can be included.
+// Detect a zero extension in instruction from the given type.
// Returns the promoted operand on success.
static bool IsZeroExtensionAndGet(HInstruction* instruction,
DataType::Type type,
- /*out*/ HInstruction** operand,
- bool to64) {
+ /*out*/ HInstruction** operand) {
// Accept any already wider constant that would be handled properly by zero
// extension when represented in the *width* of the given narrower data type
- // (the fact that byte/short/int normally sign extend does not matter here).
+ // (the fact that Int8/Int16 normally sign extend does not matter here).
int64_t value = 0;
if (IsInt64AndGet(instruction, /*out*/ &value)) {
switch (type) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
if (IsUint<8>(value)) {
*operand = instruction;
@@ -173,28 +206,26 @@ static bool IsZeroExtensionAndGet(HInstruction* instruction,
return true;
}
return false;
- case DataType::Type::kInt32:
- if (IsUint<32>(value)) {
- *operand = instruction;
- return to64;
- }
- return false;
default:
return false;
}
}
- // An implicit widening conversion of a char to an integral type zero-extends
- // the representation of the char value to fill the wider format.
- if (instruction->GetType() == type && (instruction->IsArrayGet() ||
- instruction->IsStaticFieldGet() ||
- instruction->IsInstanceFieldGet())) {
- if (type == DataType::Type::kUint16) {
- *operand = instruction;
- return true;
+ // An implicit widening conversion of any unsigned expression zero-extends.
+ if (instruction->GetType() == type) {
+ switch (type) {
+ case DataType::Type::kUint8:
+ case DataType::Type::kUint16:
+ *operand = instruction;
+ return true;
+ default:
+ return false;
}
}
// A sign (or zero) extension followed by an explicit removal of just the
// higher sign bits is equivalent to a zero extension of the underlying operand.
+ //
+ // TODO: move this into simplifier and use new type system instead.
+ //
if (instruction->IsAnd()) {
int64_t mask = 0;
HInstruction* a = instruction->InputAt(0);
@@ -205,27 +236,32 @@ static bool IsZeroExtensionAndGet(HInstruction* instruction,
(IsInt64AndGet(b, /*out*/ &mask) && (IsSignExtensionAndGet(a, type, /*out*/ operand) ||
IsZeroExtensionAndGet(a, type, /*out*/ operand)))) {
switch ((*operand)->GetType()) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
return mask == std::numeric_limits<uint8_t>::max();
case DataType::Type::kUint16:
case DataType::Type::kInt16:
return mask == std::numeric_limits<uint16_t>::max();
- case DataType::Type::kInt32:
- return mask == std::numeric_limits<uint32_t>::max() && to64;
default: return false;
}
}
}
- // Explicit type conversions.
+ // An explicit widening conversion of an unsigned expression zero-extends.
if (instruction->IsTypeConversion()) {
- DataType::Type from = instruction->InputAt(0)->GetType();
+ HInstruction* conv = instruction->InputAt(0);
+ DataType::Type from = conv->GetType();
switch (instruction->GetType()) {
+ case DataType::Type::kInt32:
case DataType::Type::kInt64:
- return IsZeroExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, /*to64*/ true);
+ if (type == from && from == DataType::Type::kUint16) {
+ *operand = conv;
+ return true;
+ }
+ return false;
case DataType::Type::kUint16:
return type == DataType::Type::kInt16 &&
from == DataType::Type::kInt16 &&
- IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand, to64);
+ IsSignExtensionAndGet(instruction->InputAt(0), type, /*out*/ operand);
default:
return false;
}
@@ -268,51 +304,10 @@ static bool IsNarrowerOperand(HInstruction* a,
// Compute relative vector length based on type difference.
static size_t GetOtherVL(DataType::Type other_type, DataType::Type vector_type, size_t vl) {
- switch (other_type) {
- case DataType::Type::kBool:
- case DataType::Type::kInt8:
- switch (vector_type) {
- case DataType::Type::kBool:
- case DataType::Type::kInt8: return vl;
- default: break;
- }
- return vl;
- case DataType::Type::kUint16:
- case DataType::Type::kInt16:
- switch (vector_type) {
- case DataType::Type::kBool:
- case DataType::Type::kInt8: return vl >> 1;
- case DataType::Type::kUint16:
- case DataType::Type::kInt16: return vl;
- default: break;
- }
- break;
- case DataType::Type::kInt32:
- switch (vector_type) {
- case DataType::Type::kBool:
- case DataType::Type::kInt8: return vl >> 2;
- case DataType::Type::kUint16:
- case DataType::Type::kInt16: return vl >> 1;
- case DataType::Type::kInt32: return vl;
- default: break;
- }
- break;
- case DataType::Type::kInt64:
- switch (vector_type) {
- case DataType::Type::kBool:
- case DataType::Type::kInt8: return vl >> 3;
- case DataType::Type::kUint16:
- case DataType::Type::kInt16: return vl >> 2;
- case DataType::Type::kInt32: return vl >> 1;
- case DataType::Type::kInt64: return vl;
- default: break;
- }
- break;
- default:
- break;
- }
- LOG(FATAL) << "Unsupported idiom conversion";
- UNREACHABLE();
+ DCHECK(DataType::IsIntegralType(other_type));
+ DCHECK(DataType::IsIntegralType(vector_type));
+ DCHECK_GE(DataType::SizeShift(other_type), DataType::SizeShift(vector_type));
+ return vl >> (DataType::SizeShift(other_type) - DataType::SizeShift(vector_type));
}
// Detect up to two instructions a and b, and an acccumulated constant c.
@@ -360,6 +355,22 @@ static bool IsAddConst(HInstruction* instruction,
return false;
}
+// Detect a + c for constant c.
+static bool IsAddConst(HInstruction* instruction,
+ /*out*/ HInstruction** a,
+ /*out*/ int64_t* c) {
+ if (instruction->IsAdd()) {
+ if (IsInt64AndGet(instruction->InputAt(0), c)) {
+ *a = instruction->InputAt(1);
+ return true;
+ } else if (IsInt64AndGet(instruction->InputAt(1), c)) {
+ *a = instruction->InputAt(0);
+ return true;
+ }
+ }
+ return false;
+}
+
// Detect reductions of the following forms,
// x = x_phi + ..
// x = x_phi - ..
@@ -1100,19 +1111,19 @@ bool HLoopOptimization::VectorizeUse(LoopNode* node,
return true;
} else if (instruction->IsArrayGet()) {
// Deal with vector restrictions.
- if (instruction->AsArrayGet()->IsStringCharAt() &&
- HasVectorRestrictions(restrictions, kNoStringCharAt)) {
+ bool is_string_char_at = instruction->AsArrayGet()->IsStringCharAt();
+ if (is_string_char_at && HasVectorRestrictions(restrictions, kNoStringCharAt)) {
return false;
}
// Accept a right-hand-side array base[index] for
- // (1) exact matching vector type,
+ // (1) matching vector type (exact match or signed/unsigned integral type of the same size),
// (2) loop-invariant base,
// (3) unit stride index,
// (4) vectorizable right-hand-side value.
HInstruction* base = instruction->InputAt(0);
HInstruction* index = instruction->InputAt(1);
HInstruction* offset = nullptr;
- if (type == instruction->GetType() &&
+ if (HVecOperation::ToSignedType(type) == HVecOperation::ToSignedType(instruction->GetType()) &&
node->loop_info->IsDefinedOutOfTheLoop(base) &&
induction_range_.IsUnitStride(instruction, index, graph_, &offset)) {
if (generate_code) {
@@ -1148,6 +1159,7 @@ bool HLoopOptimization::VectorizeUse(LoopNode* node,
size_t size_vec = DataType::Size(type);
size_t size_from = DataType::Size(from);
size_t size_to = DataType::Size(to);
+ DataType::Type ctype = size_from == size_vec ? from : type;
// Accept an integral conversion
// (1a) narrowing into vector type, "wider" operations cannot bring in higher order bits, or
// (1b) widening from at least vector type, and
@@ -1157,7 +1169,7 @@ bool HLoopOptimization::VectorizeUse(LoopNode* node,
VectorizeUse(node, opa, generate_code, type, restrictions | kNoHiBits)) ||
(size_to >= size_from &&
size_from >= size_vec &&
- VectorizeUse(node, opa, generate_code, type, restrictions))) {
+ VectorizeUse(node, opa, generate_code, ctype, restrictions))) {
if (generate_code) {
if (vector_mode_ == kVector) {
vector_map_->Put(instruction, vector_map_->Get(opa)); // operand pass-through
@@ -1275,6 +1287,7 @@ bool HLoopOptimization::VectorizeUse(LoopNode* node,
}
if (VectorizeUse(node, r, generate_code, type, restrictions)) {
if (generate_code) {
+ NormalizePackedType(&type, &is_unsigned);
GenerateVecOp(instruction, vector_map_->Get(r), nullptr, type);
}
return true;
@@ -1334,6 +1347,7 @@ bool HLoopOptimization::TrySetVectorType(DataType::Type type, uint64_t* restrict
// ARM 32-bit always supports advanced SIMD (64-bit SIMD).
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
*restrictions |= kNoDiv | kNoReduction;
return TrySetVectorLength(8);
@@ -1353,6 +1367,7 @@ bool HLoopOptimization::TrySetVectorType(DataType::Type type, uint64_t* restrict
// ARMv8 AArch64 always supports advanced SIMD (128-bit SIMD).
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
*restrictions |= kNoDiv;
return TrySetVectorLength(16);
@@ -1381,6 +1396,7 @@ bool HLoopOptimization::TrySetVectorType(DataType::Type type, uint64_t* restrict
if (features->AsX86InstructionSetFeatures()->HasSSE4_1()) {
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
*restrictions |=
kNoMul | kNoDiv | kNoShift | kNoAbs | kNoSignedHAdd | kNoUnroundedHAdd | kNoSAD;
@@ -1410,6 +1426,7 @@ bool HLoopOptimization::TrySetVectorType(DataType::Type type, uint64_t* restrict
if (features->AsMipsInstructionSetFeatures()->HasMsa()) {
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
*restrictions |= kNoDiv | kNoReduction | kNoSAD;
return TrySetVectorLength(16);
@@ -1438,6 +1455,7 @@ bool HLoopOptimization::TrySetVectorType(DataType::Type type, uint64_t* restrict
if (features->AsMips64InstructionSetFeatures()->HasMsa()) {
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
*restrictions |= kNoDiv | kNoReduction | kNoSAD;
return TrySetVectorLength(16);
@@ -1502,7 +1520,7 @@ void HLoopOptimization::GenerateVecInv(HInstruction* org, DataType::Type type) {
new (global_allocator_) HTypeConversion(type, input, kNoDexPc));
}
vector = new (global_allocator_)
- HVecReplicateScalar(global_allocator_, input, type, vector_length_);
+ HVecReplicateScalar(global_allocator_, input, type, vector_length_, kNoDexPc);
vector_permanent_map_->Put(org, Insert(vector_preheader_, vector));
}
vector_map_->Put(org, vector);
@@ -1528,17 +1546,24 @@ void HLoopOptimization::GenerateVecMem(HInstruction* org,
HInstruction* opb,
HInstruction* offset,
DataType::Type type) {
+ uint32_t dex_pc = org->GetDexPc();
HInstruction* vector = nullptr;
if (vector_mode_ == kVector) {
// Vector store or load.
HInstruction* base = org->InputAt(0);
if (opb != nullptr) {
vector = new (global_allocator_) HVecStore(
- global_allocator_, base, opa, opb, type, vector_length_);
+ global_allocator_, base, opa, opb, type, org->GetSideEffects(), vector_length_, dex_pc);
} else {
bool is_string_char_at = org->AsArrayGet()->IsStringCharAt();
- vector = new (global_allocator_) HVecLoad(
- global_allocator_, base, opa, type, vector_length_, is_string_char_at);
+ vector = new (global_allocator_) HVecLoad(global_allocator_,
+ base,
+ opa,
+ type,
+ org->GetSideEffects(),
+ vector_length_,
+ is_string_char_at,
+ dex_pc);
}
// Known dynamically enforced alignment?
if (vector_peeling_candidate_ != nullptr &&
@@ -1550,11 +1575,12 @@ void HLoopOptimization::GenerateVecMem(HInstruction* org,
// Scalar store or load.
DCHECK(vector_mode_ == kSequential);
if (opb != nullptr) {
- vector = new (global_allocator_) HArraySet(org->InputAt(0), opa, opb, type, kNoDexPc);
+ vector = new (global_allocator_) HArraySet(
+ org->InputAt(0), opa, opb, type, org->GetSideEffects(), dex_pc);
} else {
bool is_string_char_at = org->AsArrayGet()->IsStringCharAt();
vector = new (global_allocator_) HArrayGet(
- org->InputAt(0), opa, type, kNoDexPc, is_string_char_at);
+ org->InputAt(0), opa, type, org->GetSideEffects(), dex_pc, is_string_char_at);
}
}
vector_map_->Put(org, vector);
@@ -1603,7 +1629,8 @@ void HLoopOptimization::GenerateVecReductionPhiInputs(HPhi* phi, HInstruction* r
&new_init,
type,
vector_length,
- 1));
+ 1,
+ kNoDexPc));
} else {
new_init = ReduceAndExtractIfNeeded(new_init);
}
@@ -1629,10 +1656,10 @@ HInstruction* HLoopOptimization::ReduceAndExtractIfNeeded(HInstruction* instruct
// y = x_1
// along the exit of the defining loop.
HInstruction* reduce = new (global_allocator_) HVecReduce(
- global_allocator_, instruction, type, vector_length, kind);
+ global_allocator_, instruction, type, vector_length, kind, kNoDexPc);
exit->InsertInstructionBefore(reduce, exit->GetFirstInstruction());
instruction = new (global_allocator_) HVecExtractScalar(
- global_allocator_, reduce, type, vector_length, 0);
+ global_allocator_, reduce, type, vector_length, 0, kNoDexPc);
exit->InsertInstructionAfter(instruction, reduce);
}
}
@@ -1653,69 +1680,70 @@ void HLoopOptimization::GenerateVecOp(HInstruction* org,
HInstruction* opb,
DataType::Type type,
bool is_unsigned) {
+ uint32_t dex_pc = org->GetDexPc();
HInstruction* vector = nullptr;
DataType::Type org_type = org->GetType();
switch (org->GetKind()) {
case HInstruction::kNeg:
DCHECK(opb == nullptr);
GENERATE_VEC(
- new (global_allocator_) HVecNeg(global_allocator_, opa, type, vector_length_),
- new (global_allocator_) HNeg(org_type, opa));
+ new (global_allocator_) HVecNeg(global_allocator_, opa, type, vector_length_, dex_pc),
+ new (global_allocator_) HNeg(org_type, opa, dex_pc));
case HInstruction::kNot:
DCHECK(opb == nullptr);
GENERATE_VEC(
- new (global_allocator_) HVecNot(global_allocator_, opa, type, vector_length_),
- new (global_allocator_) HNot(org_type, opa));
+ new (global_allocator_) HVecNot(global_allocator_, opa, type, vector_length_, dex_pc),
+ new (global_allocator_) HNot(org_type, opa, dex_pc));
case HInstruction::kBooleanNot:
DCHECK(opb == nullptr);
GENERATE_VEC(
- new (global_allocator_) HVecNot(global_allocator_, opa, type, vector_length_),
- new (global_allocator_) HBooleanNot(opa));
+ new (global_allocator_) HVecNot(global_allocator_, opa, type, vector_length_, dex_pc),
+ new (global_allocator_) HBooleanNot(opa, dex_pc));
case HInstruction::kTypeConversion:
DCHECK(opb == nullptr);
GENERATE_VEC(
- new (global_allocator_) HVecCnv(global_allocator_, opa, type, vector_length_),
- new (global_allocator_) HTypeConversion(org_type, opa, kNoDexPc));
+ new (global_allocator_) HVecCnv(global_allocator_, opa, type, vector_length_, dex_pc),
+ new (global_allocator_) HTypeConversion(org_type, opa, dex_pc));
case HInstruction::kAdd:
GENERATE_VEC(
- new (global_allocator_) HVecAdd(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HAdd(org_type, opa, opb));
+ new (global_allocator_) HVecAdd(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HAdd(org_type, opa, opb, dex_pc));
case HInstruction::kSub:
GENERATE_VEC(
- new (global_allocator_) HVecSub(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HSub(org_type, opa, opb));
+ new (global_allocator_) HVecSub(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HSub(org_type, opa, opb, dex_pc));
case HInstruction::kMul:
GENERATE_VEC(
- new (global_allocator_) HVecMul(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HMul(org_type, opa, opb));
+ new (global_allocator_) HVecMul(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HMul(org_type, opa, opb, dex_pc));
case HInstruction::kDiv:
GENERATE_VEC(
- new (global_allocator_) HVecDiv(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HDiv(org_type, opa, opb, kNoDexPc));
+ new (global_allocator_) HVecDiv(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HDiv(org_type, opa, opb, dex_pc));
case HInstruction::kAnd:
GENERATE_VEC(
- new (global_allocator_) HVecAnd(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HAnd(org_type, opa, opb));
+ new (global_allocator_) HVecAnd(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HAnd(org_type, opa, opb, dex_pc));
case HInstruction::kOr:
GENERATE_VEC(
- new (global_allocator_) HVecOr(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HOr(org_type, opa, opb));
+ new (global_allocator_) HVecOr(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HOr(org_type, opa, opb, dex_pc));
case HInstruction::kXor:
GENERATE_VEC(
- new (global_allocator_) HVecXor(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HXor(org_type, opa, opb));
+ new (global_allocator_) HVecXor(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HXor(org_type, opa, opb, dex_pc));
case HInstruction::kShl:
GENERATE_VEC(
- new (global_allocator_) HVecShl(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HShl(org_type, opa, opb));
+ new (global_allocator_) HVecShl(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HShl(org_type, opa, opb, dex_pc));
case HInstruction::kShr:
GENERATE_VEC(
- new (global_allocator_) HVecShr(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HShr(org_type, opa, opb));
+ new (global_allocator_) HVecShr(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HShr(org_type, opa, opb, dex_pc));
case HInstruction::kUShr:
GENERATE_VEC(
- new (global_allocator_) HVecUShr(global_allocator_, opa, opb, type, vector_length_),
- new (global_allocator_) HUShr(org_type, opa, opb));
+ new (global_allocator_) HVecUShr(global_allocator_, opa, opb, type, vector_length_, dex_pc),
+ new (global_allocator_) HUShr(org_type, opa, opb, dex_pc));
case HInstruction::kInvokeStaticOrDirect: {
HInvokeStaticOrDirect* invoke = org->AsInvokeStaticOrDirect();
if (vector_mode_ == kVector) {
@@ -1725,22 +1753,25 @@ void HLoopOptimization::GenerateVecOp(HInstruction* org,
case Intrinsics::kMathAbsFloat:
case Intrinsics::kMathAbsDouble:
DCHECK(opb == nullptr);
- vector = new (global_allocator_) HVecAbs(global_allocator_, opa, type, vector_length_);
+ vector = new (global_allocator_)
+ HVecAbs(global_allocator_, opa, type, vector_length_, dex_pc);
break;
case Intrinsics::kMathMinIntInt:
case Intrinsics::kMathMinLongLong:
case Intrinsics::kMathMinFloatFloat:
case Intrinsics::kMathMinDoubleDouble: {
+ NormalizePackedType(&type, &is_unsigned);
vector = new (global_allocator_)
- HVecMin(global_allocator_, opa, opb, type, vector_length_, is_unsigned);
+ HVecMin(global_allocator_, opa, opb, type, vector_length_, is_unsigned, dex_pc);
break;
}
case Intrinsics::kMathMaxIntInt:
case Intrinsics::kMathMaxLongLong:
case Intrinsics::kMathMaxFloatFloat:
case Intrinsics::kMathMaxDoubleDouble: {
+ NormalizePackedType(&type, &is_unsigned);
vector = new (global_allocator_)
- HVecMax(global_allocator_, opa, opb, type, vector_length_, is_unsigned);
+ HVecMax(global_allocator_, opa, opb, type, vector_length_, is_unsigned, dex_pc);
break;
}
default:
@@ -1851,14 +1882,16 @@ bool HLoopOptimization::VectorizeHalvingAddIdiom(LoopNode* node,
VectorizeUse(node, s, generate_code, type, restrictions)) {
if (generate_code) {
if (vector_mode_ == kVector) {
+ NormalizePackedType(&type, &is_unsigned);
vector_map_->Put(instruction, new (global_allocator_) HVecHalvingAdd(
global_allocator_,
vector_map_->Get(r),
vector_map_->Get(s),
type,
vector_length_,
+ is_rounded,
is_unsigned,
- is_rounded));
+ kNoDexPc));
MaybeRecordStat(stats_, MethodCompilationStat::kLoopVectorizedIdiom);
} else {
GenerateVecOp(instruction, vector_map_->Get(r), vector_map_->Get(s), type);
@@ -1896,9 +1929,14 @@ bool HLoopOptimization::VectorizeSADIdiom(LoopNode* node,
(v->AsInvokeStaticOrDirect()->GetIntrinsic() == Intrinsics::kMathAbsInt ||
v->AsInvokeStaticOrDirect()->GetIntrinsic() == Intrinsics::kMathAbsLong)) {
HInstruction* x = v->InputAt(0);
- if (x->IsSub() && x->GetType() == reduction_type) {
- a = x->InputAt(0);
- b = x->InputAt(1);
+ if (x->GetType() == reduction_type) {
+ int64_t c = 0;
+ if (x->IsSub()) {
+ a = x->InputAt(0);
+ b = x->InputAt(1);
+ } else if (IsAddConst(x, /*out*/ &a, /*out*/ &c)) {
+ b = graph_->GetConstant(reduction_type, -c); // hidden SUB!
+ }
}
}
if (a == nullptr || b == nullptr) {
@@ -1906,22 +1944,21 @@ bool HLoopOptimization::VectorizeSADIdiom(LoopNode* node,
}
// Accept same-type or consistent sign extension for narrower-type on operands a and b.
// The same-type or narrower operands are called r (a or lower) and s (b or lower).
+ // We inspect the operands carefully to pick the most suited type.
HInstruction* r = a;
HInstruction* s = b;
bool is_unsigned = false;
DataType::Type sub_type = a->GetType();
- if (a->IsTypeConversion()) {
- HInstruction* hunt = a;
- while (hunt->IsTypeConversion()) {
- hunt = hunt->InputAt(0);
- }
- sub_type = hunt->GetType();
- } else if (b->IsTypeConversion()) {
- HInstruction* hunt = a;
- while (hunt->IsTypeConversion()) {
- hunt = hunt->InputAt(0);
- }
- sub_type = hunt->GetType();
+ if (DataType::Size(b->GetType()) < DataType::Size(sub_type)) {
+ sub_type = b->GetType();
+ }
+ if (a->IsTypeConversion() &&
+ DataType::Size(a->InputAt(0)->GetType()) < DataType::Size(sub_type)) {
+ sub_type = a->InputAt(0)->GetType();
+ }
+ if (b->IsTypeConversion() &&
+ DataType::Size(b->InputAt(0)->GetType()) < DataType::Size(sub_type)) {
+ sub_type = b->InputAt(0)->GetType();
}
if (reduction_type != sub_type &&
(!IsNarrowerOperands(a, b, sub_type, &r, &s, &is_unsigned) || is_unsigned)) {
@@ -1942,6 +1979,7 @@ bool HLoopOptimization::VectorizeSADIdiom(LoopNode* node,
VectorizeUse(node, r, generate_code, sub_type, restrictions) &&
VectorizeUse(node, s, generate_code, sub_type, restrictions)) {
if (generate_code) {
+ NormalizePackedType(&reduction_type, &is_unsigned);
if (vector_mode_ == kVector) {
vector_map_->Put(instruction, new (global_allocator_) HVecSADAccumulate(
global_allocator_,
@@ -1949,7 +1987,8 @@ bool HLoopOptimization::VectorizeSADIdiom(LoopNode* node,
vector_map_->Get(r),
vector_map_->Get(s),
reduction_type,
- GetOtherVL(reduction_type, sub_type, vector_length_)));
+ GetOtherVL(reduction_type, sub_type, vector_length_),
+ kNoDexPc));
MaybeRecordStat(stats_, MethodCompilationStat::kLoopVectorizedIdiom);
} else {
GenerateVecOp(v, vector_map_->Get(r), nullptr, reduction_type);
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 41ea998a8c..cae5054ef7 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -590,6 +590,7 @@ HConstant* HGraph::GetConstant(DataType::Type type, int64_t value, uint32_t dex_
case DataType::Type::kBool:
DCHECK(IsUint<1>(value));
FALLTHROUGH_INTENDED;
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index c49cee3284..fef0c865ae 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1423,7 +1423,8 @@ class HLoopInformationOutwardIterator : public ValueObject {
#else
#define FOR_EACH_CONCRETE_INSTRUCTION_MIPS(M) \
M(MipsComputeBaseMethodAddress, Instruction) \
- M(MipsPackedSwitch, Instruction)
+ M(MipsPackedSwitch, Instruction) \
+ M(IntermediateArrayAddressIndex, Instruction)
#endif
#define FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(M)
@@ -1760,14 +1761,26 @@ class SideEffects : public ValueObject {
static constexpr uint64_t kAllReads =
((1ULL << (kLastBitForReads + 1 - kFieldReadOffset)) - 1) << kFieldReadOffset;
- // Translates type to bit flag.
+ // Translates type to bit flag. The type must correspond to a Java type.
static uint64_t TypeFlag(DataType::Type type, int offset) {
- CHECK_NE(type, DataType::Type::kVoid);
- const uint64_t one = 1;
- const int shift = static_cast<int>(type); // 0-based consecutive enum
+ int shift;
+ switch (type) {
+ case DataType::Type::kReference: shift = 0; break;
+ case DataType::Type::kBool: shift = 1; break;
+ case DataType::Type::kInt8: shift = 2; break;
+ case DataType::Type::kUint16: shift = 3; break;
+ case DataType::Type::kInt16: shift = 4; break;
+ case DataType::Type::kInt32: shift = 5; break;
+ case DataType::Type::kInt64: shift = 6; break;
+ case DataType::Type::kFloat32: shift = 7; break;
+ case DataType::Type::kFloat64: shift = 8; break;
+ default:
+ LOG(FATAL) << "Unexpected data type " << type;
+ UNREACHABLE();
+ }
DCHECK_LE(kFieldWriteOffset, shift);
DCHECK_LT(shift, kArrayWriteOffset);
- return one << (shift + offset);
+ return UINT64_C(1) << (shift + offset);
}
// Private constructor on direct flags value.
@@ -5185,7 +5198,7 @@ class HBooleanNot FINAL : public HUnaryOperation {
class HTypeConversion FINAL : public HExpression<1> {
public:
// Instantiate a type conversion of `input` to `result_type`.
- HTypeConversion(DataType::Type result_type, HInstruction* input, uint32_t dex_pc)
+ HTypeConversion(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
: HExpression(result_type, SideEffects::None(), dex_pc) {
SetRawInputAt(0, input);
// Invariant: We should never generate a conversion to a Boolean value.
@@ -5382,9 +5395,21 @@ class HArrayGet FINAL : public HExpression<2> {
HArrayGet(HInstruction* array,
HInstruction* index,
DataType::Type type,
+ uint32_t dex_pc)
+ : HArrayGet(array,
+ index,
+ type,
+ SideEffects::ArrayReadOfType(type),
+ dex_pc,
+ /* is_string_char_at */ false) {}
+
+ HArrayGet(HInstruction* array,
+ HInstruction* index,
+ DataType::Type type,
+ SideEffects side_effects,
uint32_t dex_pc,
- bool is_string_char_at = false)
- : HExpression(type, SideEffects::ArrayReadOfType(type), dex_pc) {
+ bool is_string_char_at)
+ : HExpression(type, side_effects, dex_pc) {
SetPackedFlag<kFlagIsStringCharAt>(is_string_char_at);
SetRawInputAt(0, array);
SetRawInputAt(1, index);
@@ -5453,7 +5478,21 @@ class HArraySet FINAL : public HTemplateInstruction<3> {
HInstruction* value,
DataType::Type expected_component_type,
uint32_t dex_pc)
- : HTemplateInstruction(SideEffects::None(), dex_pc) {
+ : HArraySet(array,
+ index,
+ value,
+ expected_component_type,
+ // Make a best guess for side effects now, may be refined during SSA building.
+ ComputeSideEffects(GetComponentType(value->GetType(), expected_component_type)),
+ dex_pc) {}
+
+ HArraySet(HInstruction* array,
+ HInstruction* index,
+ HInstruction* value,
+ DataType::Type expected_component_type,
+ SideEffects side_effects,
+ uint32_t dex_pc)
+ : HTemplateInstruction(side_effects, dex_pc) {
SetPackedField<ExpectedComponentTypeField>(expected_component_type);
SetPackedFlag<kFlagNeedsTypeCheck>(value->GetType() == DataType::Type::kReference);
SetPackedFlag<kFlagValueCanBeNull>(true);
@@ -5461,8 +5500,6 @@ class HArraySet FINAL : public HTemplateInstruction<3> {
SetRawInputAt(0, array);
SetRawInputAt(1, index);
SetRawInputAt(2, value);
- // Make a best guess now, may be refined during SSA building.
- ComputeSideEffects();
}
bool NeedsEnvironment() const OVERRIDE {
@@ -5501,24 +5538,26 @@ class HArraySet FINAL : public HTemplateInstruction<3> {
HInstruction* GetValue() const { return InputAt(2); }
DataType::Type GetComponentType() const {
+ return GetComponentType(GetValue()->GetType(), GetRawExpectedComponentType());
+ }
+
+ static DataType::Type GetComponentType(DataType::Type value_type,
+ DataType::Type expected_component_type) {
// The Dex format does not type floating point index operations. Since the
- // `expected_component_type_` is set during building and can therefore not
+ // `expected_component_type` comes from SSA building and can therefore not
// be correct, we also check what is the value type. If it is a floating
// point type, we must use that type.
- DataType::Type value_type = GetValue()->GetType();
return ((value_type == DataType::Type::kFloat32) || (value_type == DataType::Type::kFloat64))
? value_type
- : GetRawExpectedComponentType();
+ : expected_component_type;
}
DataType::Type GetRawExpectedComponentType() const {
return GetPackedField<ExpectedComponentTypeField>();
}
- void ComputeSideEffects() {
- DataType::Type type = GetComponentType();
- SetSideEffects(SideEffects::ArrayWriteOfType(type).Union(
- SideEffectsForArchRuntimeCalls(type)));
+ static SideEffects ComputeSideEffects(DataType::Type type) {
+ return SideEffects::ArrayWriteOfType(type).Union(SideEffectsForArchRuntimeCalls(type));
}
static SideEffects SideEffectsForArchRuntimeCalls(DataType::Type value_type) {
diff --git a/compiler/optimizing/nodes_mips.h b/compiler/optimizing/nodes_mips.h
index 80e652eaa7..ef388c30d5 100644
--- a/compiler/optimizing/nodes_mips.h
+++ b/compiler/optimizing/nodes_mips.h
@@ -69,6 +69,46 @@ class HMipsPackedSwitch FINAL : public HTemplateInstruction<2> {
DISALLOW_COPY_AND_ASSIGN(HMipsPackedSwitch);
};
+// This instruction computes part of the array access offset (index offset).
+//
+// For array accesses the element address has the following structure:
+// Address = CONST_OFFSET + base_addr + index << ELEM_SHIFT. The address part
+// (index << ELEM_SHIFT) can be shared across array accesses with
+// the same data type and index. For example, in the following loop 5 accesses can share address
+// computation:
+//
+// void foo(int[] a, int[] b, int[] c) {
+// for (i...) {
+// a[i] = a[i] + 5;
+// b[i] = b[i] + c[i];
+// }
+// }
+//
+// Note: as the instruction doesn't involve base array address into computations it has no side
+// effects.
+class HIntermediateArrayAddressIndex FINAL : public HExpression<2> {
+ public:
+ HIntermediateArrayAddressIndex(HInstruction* index, HInstruction* shift, uint32_t dex_pc)
+ : HExpression(DataType::Type::kInt32, SideEffects::None(), dex_pc) {
+ SetRawInputAt(0, index);
+ SetRawInputAt(1, shift);
+ }
+
+ bool CanBeMoved() const OVERRIDE { return true; }
+ bool InstructionDataEquals(const HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE {
+ return true;
+ }
+ bool IsActualObject() const OVERRIDE { return false; }
+
+ HInstruction* GetIndex() const { return InputAt(0); }
+ HInstruction* GetShift() const { return InputAt(1); }
+
+ DECLARE_INSTRUCTION(IntermediateArrayAddressIndex);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(HIntermediateArrayAddressIndex);
+};
+
} // namespace art
#endif // ART_COMPILER_OPTIMIZING_NODES_MIPS_H_
diff --git a/compiler/optimizing/nodes_vector.h b/compiler/optimizing/nodes_vector.h
index 0aac260839..8f3ab11d00 100644
--- a/compiler/optimizing/nodes_vector.h
+++ b/compiler/optimizing/nodes_vector.h
@@ -34,7 +34,7 @@ class Alignment {
DCHECK(IsPowerOfTwo(base));
}
- // Returns true if memory is "at least" aligned at the given boundary.
+ // Returns true if memory is at least aligned at the given boundary.
// Assumes requested base is power of two.
bool IsAlignedAt(size_t base) const {
DCHECK_NE(0u, base);
@@ -42,6 +42,10 @@ class Alignment {
return ((offset_ | base_) & (base - 1u)) == 0;
}
+ size_t Base() const { return base_; }
+
+ size_t Offset() const { return offset_; }
+
std::string ToString() const {
return "ALIGN(" + std::to_string(base_) + "," + std::to_string(offset_) + ")";
}
@@ -116,6 +120,22 @@ class HVecOperation : public HVariableInputSizeInstruction {
return GetVectorLength() == o->GetVectorLength() && GetPackedType() == o->GetPackedType();
}
+ // Maps an integral type to the same-size signed type and leaves other types alone.
+ // Can be used to test relaxed type consistency in which packed same-size integral
+ // types can co-exist, but other type mixes are an error.
+ static DataType::Type ToSignedType(DataType::Type type) {
+ switch (type) {
+ case DataType::Type::kBool: // 1-byte storage unit
+ case DataType::Type::kUint8:
+ return DataType::Type::kInt8;
+ case DataType::Type::kUint16:
+ return DataType::Type::kInt16;
+ default:
+ DCHECK(type != DataType::Type::kVoid && type != DataType::Type::kReference) << type;
+ return type;
+ }
+ }
+
DECLARE_ABSTRACT_INSTRUCTION(VecOperation);
protected:
@@ -187,8 +207,7 @@ class HVecBinaryOperation : public HVecOperation {
};
// Abstraction of a vector operation that references memory, with an alignment.
-// The Android runtime guarantees at least "component size" alignment for array
-// elements and, thus, vectors.
+// The Android runtime guarantees elements have at least natural alignment.
class HVecMemoryOperation : public HVecOperation {
public:
HVecMemoryOperation(ArenaAllocator* arena,
@@ -230,18 +249,7 @@ inline static bool HasConsistentPackedTypes(HInstruction* input, DataType::Type
}
DCHECK(input->IsVecOperation());
DataType::Type input_type = input->AsVecOperation()->GetPackedType();
- switch (input_type) {
- case DataType::Type::kBool:
- case DataType::Type::kInt8:
- return type == DataType::Type::kBool ||
- type == DataType::Type::kInt8;
- case DataType::Type::kUint16:
- case DataType::Type::kInt16:
- return type == DataType::Type::kUint16 ||
- type == DataType::Type::kInt16;
- default:
- return type == input_type;
- }
+ return HVecOperation::ToSignedType(input_type) == HVecOperation::ToSignedType(type);
}
//
@@ -256,7 +264,7 @@ class HVecReplicateScalar FINAL : public HVecUnaryOperation {
HInstruction* scalar,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecUnaryOperation(arena, scalar, packed_type, vector_length, dex_pc) {
DCHECK(!scalar->IsVecOperation());
}
@@ -282,7 +290,7 @@ class HVecExtractScalar FINAL : public HVecUnaryOperation {
DataType::Type packed_type,
size_t vector_length,
size_t index,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(input, packed_type));
DCHECK_LT(index, vector_length);
@@ -320,7 +328,7 @@ class HVecReduce FINAL : public HVecUnaryOperation {
DataType::Type packed_type,
size_t vector_length,
ReductionKind kind,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc),
kind_(kind) {
DCHECK(HasConsistentPackedTypes(input, packed_type));
@@ -352,7 +360,7 @@ class HVecCnv FINAL : public HVecUnaryOperation {
HInstruction* input,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
DCHECK(input->IsVecOperation());
DCHECK_NE(GetInputType(), GetResultType()); // actual convert
@@ -377,7 +385,7 @@ class HVecNeg FINAL : public HVecUnaryOperation {
HInstruction* input,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(input, packed_type));
}
@@ -391,14 +399,15 @@ class HVecNeg FINAL : public HVecUnaryOperation {
};
// Takes absolute value of every component in the vector,
-// viz. abs[ x1, .. , xn ] = [ |x1|, .. , |xn| ].
+// viz. abs[ x1, .. , xn ] = [ |x1|, .. , |xn| ]
+// for signed operand x.
class HVecAbs FINAL : public HVecUnaryOperation {
public:
HVecAbs(ArenaAllocator* arena,
HInstruction* input,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(input, packed_type));
}
@@ -420,7 +429,7 @@ class HVecNot FINAL : public HVecUnaryOperation {
HInstruction* input,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecUnaryOperation(arena, input, packed_type, vector_length, dex_pc) {
DCHECK(input->IsVecOperation());
}
@@ -446,7 +455,7 @@ class HVecAdd FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(left, packed_type));
DCHECK(HasConsistentPackedTypes(right, packed_type));
@@ -463,7 +472,7 @@ class HVecAdd FINAL : public HVecBinaryOperation {
// Performs halving add on every component in the two vectors, viz.
// rounded [ x1, .. , xn ] hradd [ y1, .. , yn ] = [ (x1 + y1 + 1) >> 1, .. , (xn + yn + 1) >> 1 ]
// truncated [ x1, .. , xn ] hadd [ y1, .. , yn ] = [ (x1 + y1) >> 1, .. , (xn + yn ) >> 1 ]
-// for signed operands x, y (sign extension) or unsigned operands x, y (zero extension).
+// for either both signed or both unsigned operands x, y.
class HVecHalvingAdd FINAL : public HVecBinaryOperation {
public:
HVecHalvingAdd(ArenaAllocator* arena,
@@ -471,10 +480,15 @@ class HVecHalvingAdd FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- bool is_unsigned,
bool is_rounded,
- uint32_t dex_pc = kNoDexPc)
+ bool is_unsigned,
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
+ // The `is_unsigned` flag should be used exclusively with the Int32 or Int64.
+ // This flag is a temporary measure while we do not have the Uint32 and Uint64 data types.
+ DCHECK(!is_unsigned ||
+ packed_type == DataType::Type::kInt32 ||
+ packed_type == DataType::Type::kInt64) << packed_type;
DCHECK(HasConsistentPackedTypes(left, packed_type));
DCHECK(HasConsistentPackedTypes(right, packed_type));
SetPackedFlag<kFieldHAddIsUnsigned>(is_unsigned);
@@ -515,7 +529,7 @@ class HVecSub FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(left, packed_type));
DCHECK(HasConsistentPackedTypes(right, packed_type));
@@ -538,7 +552,7 @@ class HVecMul FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(left, packed_type));
DCHECK(HasConsistentPackedTypes(right, packed_type));
@@ -561,7 +575,7 @@ class HVecDiv FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(left, packed_type));
DCHECK(HasConsistentPackedTypes(right, packed_type));
@@ -576,7 +590,8 @@ class HVecDiv FINAL : public HVecBinaryOperation {
};
// Takes minimum of every component in the two vectors,
-// viz. MIN( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ min(x1, y1), .. , min(xn, yn) ].
+// viz. MIN( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ min(x1, y1), .. , min(xn, yn) ]
+// for either both signed or both unsigned operands x, y.
class HVecMin FINAL : public HVecBinaryOperation {
public:
HVecMin(ArenaAllocator* arena,
@@ -585,8 +600,13 @@ class HVecMin FINAL : public HVecBinaryOperation {
DataType::Type packed_type,
size_t vector_length,
bool is_unsigned,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
+ // The `is_unsigned` flag should be used exclusively with the Int32 or Int64.
+ // This flag is a temporary measure while we do not have the Uint32 and Uint64 data types.
+ DCHECK(!is_unsigned ||
+ packed_type == DataType::Type::kInt32 ||
+ packed_type == DataType::Type::kInt64) << packed_type;
DCHECK(HasConsistentPackedTypes(left, packed_type));
DCHECK(HasConsistentPackedTypes(right, packed_type));
SetPackedFlag<kFieldMinOpIsUnsigned>(is_unsigned);
@@ -614,7 +634,8 @@ class HVecMin FINAL : public HVecBinaryOperation {
};
// Takes maximum of every component in the two vectors,
-// viz. MAX( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ max(x1, y1), .. , max(xn, yn) ].
+// viz. MAX( [ x1, .. , xn ] , [ y1, .. , yn ]) = [ max(x1, y1), .. , max(xn, yn) ]
+// for either both signed or both unsigned operands x, y.
class HVecMax FINAL : public HVecBinaryOperation {
public:
HVecMax(ArenaAllocator* arena,
@@ -623,8 +644,13 @@ class HVecMax FINAL : public HVecBinaryOperation {
DataType::Type packed_type,
size_t vector_length,
bool is_unsigned,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
+ // The `is_unsigned` flag should be used exclusively with the Int32 or Int64.
+ // This flag is a temporary measure while we do not have the Uint32 and Uint64 data types.
+ DCHECK(!is_unsigned ||
+ packed_type == DataType::Type::kInt32 ||
+ packed_type == DataType::Type::kInt64) << packed_type;
DCHECK(HasConsistentPackedTypes(left, packed_type));
DCHECK(HasConsistentPackedTypes(right, packed_type));
SetPackedFlag<kFieldMaxOpIsUnsigned>(is_unsigned);
@@ -660,7 +686,7 @@ class HVecAnd FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(left->IsVecOperation() && right->IsVecOperation());
}
@@ -682,7 +708,7 @@ class HVecAndNot FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(left->IsVecOperation() && right->IsVecOperation());
}
@@ -704,7 +730,7 @@ class HVecOr FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(left->IsVecOperation() && right->IsVecOperation());
}
@@ -726,7 +752,7 @@ class HVecXor FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(left->IsVecOperation() && right->IsVecOperation());
}
@@ -748,7 +774,7 @@ class HVecShl FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(left, packed_type));
}
@@ -770,7 +796,7 @@ class HVecShr FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(left, packed_type));
}
@@ -792,7 +818,7 @@ class HVecUShr FINAL : public HVecBinaryOperation {
HInstruction* right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) {
DCHECK(HasConsistentPackedTypes(left, packed_type));
}
@@ -819,7 +845,7 @@ class HVecSetScalars FINAL : public HVecOperation {
DataType::Type packed_type,
size_t vector_length,
size_t number_of_scalars,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecOperation(arena,
packed_type,
SideEffects::None(),
@@ -853,7 +879,7 @@ class HVecMultiplyAccumulate FINAL : public HVecOperation {
HInstruction* mul_right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecOperation(arena,
packed_type,
SideEffects::None(),
@@ -891,9 +917,9 @@ class HVecMultiplyAccumulate FINAL : public HVecOperation {
// Takes the absolute difference of two vectors, and adds the results to
// same-precision or wider-precision components in the accumulator,
-// viz. SAD([ a1, .. , am ], [ x1, .. , xn ], [ y1, .. , yn ] =
+// viz. SAD([ a1, .. , am ], [ x1, .. , xn ], [ y1, .. , yn ]) =
// [ a1 + sum abs(xi-yi), .. , am + sum abs(xj-yj) ],
-// for m <= n and non-overlapping sums.
+// for m <= n, non-overlapping sums, and signed operands x, y.
class HVecSADAccumulate FINAL : public HVecOperation {
public:
HVecSADAccumulate(ArenaAllocator* arena,
@@ -902,7 +928,7 @@ class HVecSADAccumulate FINAL : public HVecOperation {
HInstruction* sad_right,
DataType::Type packed_type,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecOperation(arena,
packed_type,
SideEffects::None(),
@@ -933,12 +959,13 @@ class HVecLoad FINAL : public HVecMemoryOperation {
HInstruction* base,
HInstruction* index,
DataType::Type packed_type,
+ SideEffects side_effects,
size_t vector_length,
bool is_string_char_at,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecMemoryOperation(arena,
packed_type,
- SideEffects::ArrayReadOfType(packed_type),
+ side_effects,
/* number_of_inputs */ 2,
vector_length,
dex_pc) {
@@ -977,11 +1004,12 @@ class HVecStore FINAL : public HVecMemoryOperation {
HInstruction* index,
HInstruction* value,
DataType::Type packed_type,
+ SideEffects side_effects,
size_t vector_length,
- uint32_t dex_pc = kNoDexPc)
+ uint32_t dex_pc)
: HVecMemoryOperation(arena,
packed_type,
- SideEffects::ArrayWriteOfType(packed_type),
+ side_effects,
/* number_of_inputs */ 3,
vector_length,
dex_pc) {
diff --git a/compiler/optimizing/nodes_vector_test.cc b/compiler/optimizing/nodes_vector_test.cc
index 3acdb20b32..d3a499cb31 100644
--- a/compiler/optimizing/nodes_vector_test.cc
+++ b/compiler/optimizing/nodes_vector_test.cc
@@ -42,11 +42,21 @@ class NodesVectorTest : public CommonCompilerTest {
graph_->AddBlock(exit_block_);
graph_->SetEntryBlock(entry_block_);
graph_->SetExitBlock(exit_block_);
- parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
- dex::TypeIndex(0),
- 0,
- DataType::Type::kInt32);
- entry_block_->AddInstruction(parameter_);
+ int8_parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(1),
+ 0,
+ DataType::Type::kInt8);
+ entry_block_->AddInstruction(int8_parameter_);
+ int16_parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(2),
+ 0,
+ DataType::Type::kInt16);
+ entry_block_->AddInstruction(int16_parameter_);
+ int32_parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(0),
+ 0,
+ DataType::Type::kInt32);
+ entry_block_->AddInstruction(int32_parameter_);
}
// General building fields.
@@ -57,7 +67,9 @@ class NodesVectorTest : public CommonCompilerTest {
HBasicBlock* entry_block_;
HBasicBlock* exit_block_;
- HInstruction* parameter_;
+ HInstruction* int8_parameter_;
+ HInstruction* int16_parameter_;
+ HInstruction* int32_parameter_;
};
//
@@ -92,6 +104,10 @@ TEST(NodesVector, Alignment) {
EXPECT_FALSE(Alignment(16, 1).IsAlignedAt(16));
EXPECT_FALSE(Alignment(16, 7).IsAlignedAt(16));
EXPECT_FALSE(Alignment(16, 0).IsAlignedAt(32));
+
+ EXPECT_EQ(16u, Alignment(16, 0).Base());
+ EXPECT_EQ(0u, Alignment(16, 0).Offset());
+ EXPECT_EQ(4u, Alignment(16, 4).Offset());
}
TEST(NodesVector, AlignmentEQ) {
@@ -119,15 +135,22 @@ TEST(NodesVector, AlignmentString) {
TEST_F(NodesVectorTest, VectorOperationProperties) {
HVecOperation* v0 = new (&allocator_)
- HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
HVecOperation* v1 = new (&allocator_)
- HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
HVecOperation* v2 = new (&allocator_)
- HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 2);
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt32, 2, kNoDexPc);
HVecOperation* v3 = new (&allocator_)
- HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt16, 4);
- HVecOperation* v4 = new (&allocator_)
- HVecStore(&allocator_, parameter_, parameter_, v0, DataType::Type::kInt32, 4);
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt16, 4, kNoDexPc);
+ HVecOperation* v4 = new (&allocator_) HVecStore(
+ &allocator_,
+ int32_parameter_,
+ int32_parameter_,
+ v0,
+ DataType::Type::kInt32,
+ SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
+ 4,
+ kNoDexPc);
EXPECT_TRUE(v0->Equals(v0));
EXPECT_TRUE(v1->Equals(v1));
@@ -175,12 +198,30 @@ TEST_F(NodesVectorTest, VectorOperationProperties) {
}
TEST_F(NodesVectorTest, VectorAlignmentAndStringCharAtMatterOnLoad) {
- HVecLoad* v0 = new (&allocator_) HVecLoad(
- &allocator_, parameter_, parameter_, DataType::Type::kInt32, 4, /*is_string_char_at*/ false);
- HVecLoad* v1 = new (&allocator_) HVecLoad(
- &allocator_, parameter_, parameter_, DataType::Type::kInt32, 4, /*is_string_char_at*/ false);
- HVecLoad* v2 = new (&allocator_) HVecLoad(
- &allocator_, parameter_, parameter_, DataType::Type::kInt32, 4, /*is_string_char_at*/ true);
+ HVecLoad* v0 = new (&allocator_) HVecLoad(&allocator_,
+ int32_parameter_,
+ int32_parameter_,
+ DataType::Type::kInt32,
+ SideEffects::ArrayReadOfType(DataType::Type::kInt32),
+ 4,
+ /*is_string_char_at*/ false,
+ kNoDexPc);
+ HVecLoad* v1 = new (&allocator_) HVecLoad(&allocator_,
+ int32_parameter_,
+ int32_parameter_,
+ DataType::Type::kInt32,
+ SideEffects::ArrayReadOfType(DataType::Type::kInt32),
+ 4,
+ /*is_string_char_at*/ false,
+ kNoDexPc);
+ HVecLoad* v2 = new (&allocator_) HVecLoad(&allocator_,
+ int32_parameter_,
+ int32_parameter_,
+ DataType::Type::kInt32,
+ SideEffects::ArrayReadOfType(DataType::Type::kInt32),
+ 4,
+ /*is_string_char_at*/ true,
+ kNoDexPc);
EXPECT_TRUE(v0->CanBeMoved());
EXPECT_TRUE(v1->CanBeMoved());
@@ -195,7 +236,7 @@ TEST_F(NodesVectorTest, VectorAlignmentAndStringCharAtMatterOnLoad) {
EXPECT_TRUE(v2->Equals(v2));
EXPECT_TRUE(v0->Equals(v1));
- EXPECT_FALSE(v0->Equals(v2));
+ EXPECT_FALSE(v0->Equals(v2)); // different is_string_char_at
EXPECT_TRUE(v0->GetAlignment() == Alignment(4, 0));
EXPECT_TRUE(v1->GetAlignment() == Alignment(4, 0));
@@ -208,112 +249,226 @@ TEST_F(NodesVectorTest, VectorAlignmentAndStringCharAtMatterOnLoad) {
EXPECT_FALSE(v0->Equals(v1)); // no longer equal
}
-TEST_F(NodesVectorTest, VectorSignMattersOnMin) {
- HVecOperation* v0 = new (&allocator_)
- HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
-
- HVecMin* v1 = new (&allocator_)
- HVecMin(&allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ true);
- HVecMin* v2 = new (&allocator_)
- HVecMin(&allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ false);
- HVecMin* v3 = new (&allocator_)
- HVecMin(&allocator_, v0, v0, DataType::Type::kInt32, 2, /*is_unsigned*/ true);
+TEST_F(NodesVectorTest, VectorAlignmentMattersOnStore) {
+ HVecOperation* p0 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
+ HVecStore* v0 = new (&allocator_) HVecStore(
+ &allocator_,
+ int32_parameter_,
+ int32_parameter_,
+ p0,
+ DataType::Type::kInt32,
+ SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
+ 4,
+ kNoDexPc);
+ HVecStore* v1 = new (&allocator_) HVecStore(
+ &allocator_,
+ int32_parameter_,
+ int32_parameter_,
+ p0,
+ DataType::Type::kInt32,
+ SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
+ 4,
+ kNoDexPc);
EXPECT_FALSE(v0->CanBeMoved());
- EXPECT_TRUE(v1->CanBeMoved());
- EXPECT_TRUE(v2->CanBeMoved());
- EXPECT_TRUE(v3->CanBeMoved());
+ EXPECT_FALSE(v1->CanBeMoved());
- EXPECT_TRUE(v1->IsUnsigned());
- EXPECT_FALSE(v2->IsUnsigned());
- EXPECT_TRUE(v3->IsUnsigned());
+ EXPECT_TRUE(v0->Equals(v1));
- EXPECT_TRUE(v1->Equals(v1));
- EXPECT_TRUE(v2->Equals(v2));
- EXPECT_TRUE(v3->Equals(v3));
+ EXPECT_TRUE(v0->GetAlignment() == Alignment(4, 0));
+ EXPECT_TRUE(v1->GetAlignment() == Alignment(4, 0));
- EXPECT_FALSE(v1->Equals(v2)); // different signs
- EXPECT_FALSE(v1->Equals(v3)); // different vector lengths
+ v1->SetAlignment(Alignment(8, 0));
+
+ EXPECT_TRUE(v1->GetAlignment() == Alignment(8, 0));
+
+ EXPECT_FALSE(v0->Equals(v1)); // no longer equal
}
-TEST_F(NodesVectorTest, VectorSignMattersOnMax) {
- HVecOperation* v0 = new (&allocator_)
- HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
+TEST_F(NodesVectorTest, VectorSignMattersOnMin) {
+ HVecOperation* p0 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
+ HVecOperation* p1 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int8_parameter_, DataType::Type::kInt8, 4, kNoDexPc);
+ HVecOperation* p2 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int16_parameter_, DataType::Type::kInt16, 4, kNoDexPc);
+
+ HVecMin* v0 = new (&allocator_) HVecMin(
+ &allocator_, p0, p0, DataType::Type::kInt32, 4, /*is_unsigned*/ true, kNoDexPc);
+ HVecMin* v1 = new (&allocator_) HVecMin(
+ &allocator_, p0, p0, DataType::Type::kInt32, 4, /*is_unsigned*/ false, kNoDexPc);
+ HVecMin* v2 = new (&allocator_) HVecMin(
+ &allocator_, p0, p0, DataType::Type::kInt32, 2, /*is_unsigned*/ true, kNoDexPc);
+ HVecMin* v3 = new (&allocator_) HVecMin(
+ &allocator_, p1, p1, DataType::Type::kUint8, 16, /*is_unsigned*/ false, kNoDexPc);
+ HVecMin* v4 = new (&allocator_) HVecMin(
+ &allocator_, p1, p1, DataType::Type::kInt8, 16, /*is_unsigned*/ false, kNoDexPc);
+ HVecMin* v5 = new (&allocator_) HVecMin(
+ &allocator_, p2, p2, DataType::Type::kUint16, 8, /*is_unsigned*/ false, kNoDexPc);
+ HVecMin* v6 = new (&allocator_) HVecMin(
+ &allocator_, p2, p2, DataType::Type::kInt16, 8, /*is_unsigned*/ false, kNoDexPc);
+ HVecMin* min_insns[] = { v0, v1, v2, v3, v4, v5, v6 };
+
+ EXPECT_FALSE(p0->CanBeMoved());
+ EXPECT_FALSE(p1->CanBeMoved());
+ EXPECT_FALSE(p2->CanBeMoved());
+
+ for (HVecMin* min_insn : min_insns) {
+ EXPECT_TRUE(min_insn->CanBeMoved());
+ }
- HVecMax* v1 = new (&allocator_)
- HVecMax(&allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ true);
- HVecMax* v2 = new (&allocator_)
- HVecMax(&allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ false);
- HVecMax* v3 = new (&allocator_)
- HVecMax(&allocator_, v0, v0, DataType::Type::kInt32, 2, /*is_unsigned*/ true);
+ // Deprecated; IsUnsigned() should be removed with the introduction of Uint32 and Uint64.
+ EXPECT_TRUE(v0->IsUnsigned());
+ EXPECT_FALSE(v1->IsUnsigned());
+ EXPECT_TRUE(v2->IsUnsigned());
- EXPECT_FALSE(v0->CanBeMoved());
- EXPECT_TRUE(v1->CanBeMoved());
- EXPECT_TRUE(v2->CanBeMoved());
- EXPECT_TRUE(v3->CanBeMoved());
+ for (HVecMin* min_insn1 : min_insns) {
+ for (HVecMin* min_insn2 : min_insns) {
+ EXPECT_EQ(min_insn1 == min_insn2, min_insn1->Equals(min_insn2));
+ }
+ }
+}
- EXPECT_TRUE(v1->IsUnsigned());
- EXPECT_FALSE(v2->IsUnsigned());
- EXPECT_TRUE(v3->IsUnsigned());
+TEST_F(NodesVectorTest, VectorSignMattersOnMax) {
+ HVecOperation* p0 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
+ HVecOperation* p1 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int8_parameter_, DataType::Type::kInt8, 4, kNoDexPc);
+ HVecOperation* p2 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int16_parameter_, DataType::Type::kInt16, 4, kNoDexPc);
+
+ HVecMax* v0 = new (&allocator_) HVecMax(
+ &allocator_, p0, p0, DataType::Type::kInt32, 4, /*is_unsigned*/ true, kNoDexPc);
+ HVecMax* v1 = new (&allocator_) HVecMax(
+ &allocator_, p0, p0, DataType::Type::kInt32, 4, /*is_unsigned*/ false, kNoDexPc);
+ HVecMax* v2 = new (&allocator_) HVecMax(
+ &allocator_, p0, p0, DataType::Type::kInt32, 2, /*is_unsigned*/ true, kNoDexPc);
+ HVecMax* v3 = new (&allocator_) HVecMax(
+ &allocator_, p1, p1, DataType::Type::kUint8, 16, /*is_unsigned*/ false, kNoDexPc);
+ HVecMax* v4 = new (&allocator_) HVecMax(
+ &allocator_, p1, p1, DataType::Type::kInt8, 16, /*is_unsigned*/ false, kNoDexPc);
+ HVecMax* v5 = new (&allocator_) HVecMax(
+ &allocator_, p2, p2, DataType::Type::kUint16, 8, /*is_unsigned*/ false, kNoDexPc);
+ HVecMax* v6 = new (&allocator_) HVecMax(
+ &allocator_, p2, p2, DataType::Type::kInt16, 8, /*is_unsigned*/ false, kNoDexPc);
+ HVecMax* max_insns[] = { v0, v1, v2, v3, v4, v5, v6 };
+
+ EXPECT_FALSE(p0->CanBeMoved());
+ EXPECT_FALSE(p1->CanBeMoved());
+ EXPECT_FALSE(p2->CanBeMoved());
+
+ for (HVecMax* max_insn : max_insns) {
+ EXPECT_TRUE(max_insn->CanBeMoved());
+ }
- EXPECT_TRUE(v1->Equals(v1));
- EXPECT_TRUE(v2->Equals(v2));
- EXPECT_TRUE(v3->Equals(v3));
+ // Deprecated; IsUnsigned() should be removed with the introduction of Uint32 and Uint64.
+ EXPECT_TRUE(v0->IsUnsigned());
+ EXPECT_FALSE(v1->IsUnsigned());
+ EXPECT_TRUE(v2->IsUnsigned());
- EXPECT_FALSE(v1->Equals(v2)); // different signs
- EXPECT_FALSE(v1->Equals(v3)); // different vector lengths
+ for (HVecMax* max_insn1 : max_insns) {
+ for (HVecMax* max_insn2 : max_insns) {
+ EXPECT_EQ(max_insn1 == max_insn2, max_insn1->Equals(max_insn2));
+ }
+ }
}
TEST_F(NodesVectorTest, VectorAttributesMatterOnHalvingAdd) {
- HVecOperation* v0 = new (&allocator_)
- HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
-
+ HVecOperation* p0 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
+ HVecOperation* p1 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int8_parameter_, DataType::Type::kInt8, 4, kNoDexPc);
+ HVecOperation* p2 = new (&allocator_)
+ HVecReplicateScalar(&allocator_, int16_parameter_, DataType::Type::kInt16, 4, kNoDexPc);
+
+ HVecHalvingAdd* v0 = new (&allocator_) HVecHalvingAdd(
+ &allocator_, p0, p0, DataType::Type::kInt32, 4,
+ /*is_rounded*/ true, /*is_unsigned*/ true, kNoDexPc);
HVecHalvingAdd* v1 = new (&allocator_) HVecHalvingAdd(
- &allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ true, /*is_rounded*/ true);
+ &allocator_, p0, p0, DataType::Type::kInt32, 4,
+ /*is_rounded*/ false, /*is_unsigned*/ true, kNoDexPc);
HVecHalvingAdd* v2 = new (&allocator_) HVecHalvingAdd(
- &allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ true, /*is_rounded*/ false);
+ &allocator_, p0, p0, DataType::Type::kInt32, 4,
+ /*is_rounded*/ true, /*is_unsigned*/ false, kNoDexPc);
HVecHalvingAdd* v3 = new (&allocator_) HVecHalvingAdd(
- &allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ false, /*is_rounded*/ true);
+ &allocator_, p0, p0, DataType::Type::kInt32, 4,
+ /*is_rounded*/ false, /*is_unsigned*/ false, kNoDexPc);
HVecHalvingAdd* v4 = new (&allocator_) HVecHalvingAdd(
- &allocator_, v0, v0, DataType::Type::kInt32, 4, /*is_unsigned*/ false, /*is_rounded*/ false);
+ &allocator_, p0, p0, DataType::Type::kInt32, 2,
+ /*is_rounded*/ true, /*is_unsigned*/ true, kNoDexPc);
HVecHalvingAdd* v5 = new (&allocator_) HVecHalvingAdd(
- &allocator_, v0, v0, DataType::Type::kInt32, 2, /*is_unsigned*/ true, /*is_rounded*/ true);
-
- EXPECT_FALSE(v0->CanBeMoved());
- EXPECT_TRUE(v1->CanBeMoved());
- EXPECT_TRUE(v2->CanBeMoved());
- EXPECT_TRUE(v3->CanBeMoved());
- EXPECT_TRUE(v4->CanBeMoved());
- EXPECT_TRUE(v5->CanBeMoved());
+ &allocator_, p1, p1, DataType::Type::kUint8, 16,
+ /*is_rounded*/ true, /*is_unsigned*/ false, kNoDexPc);
+ HVecHalvingAdd* v6 = new (&allocator_) HVecHalvingAdd(
+ &allocator_, p1, p1, DataType::Type::kUint8, 16,
+ /*is_rounded*/ false, /*is_unsigned*/ false, kNoDexPc);
+ HVecHalvingAdd* v7 = new (&allocator_) HVecHalvingAdd(
+ &allocator_, p1, p1, DataType::Type::kInt8, 16,
+ /*is_rounded*/ true, /*is_unsigned*/ false, kNoDexPc);
+ HVecHalvingAdd* v8 = new (&allocator_) HVecHalvingAdd(
+ &allocator_, p1, p1, DataType::Type::kInt8, 16,
+ /*is_rounded*/ false, /*is_unsigned*/ false, kNoDexPc);
+ HVecHalvingAdd* v9 = new (&allocator_) HVecHalvingAdd(
+ &allocator_, p2, p2, DataType::Type::kUint16, 8,
+ /*is_rounded*/ true, /*is_unsigned*/ false, kNoDexPc);
+ HVecHalvingAdd* v10 = new (&allocator_) HVecHalvingAdd(
+ &allocator_, p2, p2, DataType::Type::kUint16, 8,
+ /*is_rounded*/ false, /*is_unsigned*/ false, kNoDexPc);
+ HVecHalvingAdd* v11 = new (&allocator_) HVecHalvingAdd(
+ &allocator_, p2, p2, DataType::Type::kInt16, 2,
+ /*is_rounded*/ true, /*is_unsigned*/ false, kNoDexPc);
+ HVecHalvingAdd* v12 = new (&allocator_) HVecHalvingAdd(
+ &allocator_, p2, p2, DataType::Type::kInt16, 2,
+ /*is_rounded*/ false, /*is_unsigned*/ false, kNoDexPc);
+ HVecHalvingAdd* hadd_insns[] = { v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 };
+
+ EXPECT_FALSE(p0->CanBeMoved());
+ EXPECT_FALSE(p1->CanBeMoved());
+ EXPECT_FALSE(p2->CanBeMoved());
+
+ for (HVecHalvingAdd* hadd_insn : hadd_insns) {
+ EXPECT_TRUE(hadd_insn->CanBeMoved());
+ }
- EXPECT_TRUE(v1->Equals(v1));
- EXPECT_TRUE(v2->Equals(v2));
- EXPECT_TRUE(v3->Equals(v3));
- EXPECT_TRUE(v4->Equals(v4));
- EXPECT_TRUE(v5->Equals(v5));
-
- EXPECT_TRUE(v1->IsUnsigned() && v1->IsRounded());
- EXPECT_TRUE(v2->IsUnsigned() && !v2->IsRounded());
- EXPECT_TRUE(!v3->IsUnsigned() && v3->IsRounded());
- EXPECT_TRUE(!v4->IsUnsigned() && !v4->IsRounded());
- EXPECT_TRUE(v5->IsUnsigned() && v5->IsRounded());
-
- EXPECT_FALSE(v1->Equals(v2)); // different attributes
- EXPECT_FALSE(v1->Equals(v3)); // different attributes
- EXPECT_FALSE(v1->Equals(v4)); // different attributes
- EXPECT_FALSE(v1->Equals(v5)); // different vector lengths
+ // Deprecated; IsUnsigned() should be removed with the introduction of Uint32 and Uint64.
+ EXPECT_TRUE(v0->IsUnsigned());
+ EXPECT_TRUE(v1->IsUnsigned());
+ EXPECT_TRUE(!v2->IsUnsigned());
+ EXPECT_TRUE(!v3->IsUnsigned());
+ EXPECT_TRUE(v4->IsUnsigned());
+
+ EXPECT_TRUE(v0->IsRounded());
+ EXPECT_TRUE(!v1->IsRounded());
+ EXPECT_TRUE(v2->IsRounded());
+ EXPECT_TRUE(!v3->IsRounded());
+ EXPECT_TRUE(v4->IsRounded());
+ EXPECT_TRUE(v5->IsRounded());
+ EXPECT_TRUE(!v6->IsRounded());
+ EXPECT_TRUE(v7->IsRounded());
+ EXPECT_TRUE(!v8->IsRounded());
+ EXPECT_TRUE(v9->IsRounded());
+ EXPECT_TRUE(!v10->IsRounded());
+ EXPECT_TRUE(v11->IsRounded());
+ EXPECT_TRUE(!v12->IsRounded());
+
+ for (HVecHalvingAdd* hadd_insn1 : hadd_insns) {
+ for (HVecHalvingAdd* hadd_insn2 : hadd_insns) {
+ EXPECT_EQ(hadd_insn1 == hadd_insn2, hadd_insn1->Equals(hadd_insn2));
+ }
+ }
}
TEST_F(NodesVectorTest, VectorOperationMattersOnMultiplyAccumulate) {
HVecOperation* v0 = new (&allocator_)
- HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
HVecMultiplyAccumulate* v1 = new (&allocator_) HVecMultiplyAccumulate(
- &allocator_, HInstruction::kAdd, v0, v0, v0, DataType::Type::kInt32, 4);
+ &allocator_, HInstruction::kAdd, v0, v0, v0, DataType::Type::kInt32, 4, kNoDexPc);
HVecMultiplyAccumulate* v2 = new (&allocator_) HVecMultiplyAccumulate(
- &allocator_, HInstruction::kSub, v0, v0, v0, DataType::Type::kInt32, 4);
+ &allocator_, HInstruction::kSub, v0, v0, v0, DataType::Type::kInt32, 4, kNoDexPc);
HVecMultiplyAccumulate* v3 = new (&allocator_) HVecMultiplyAccumulate(
- &allocator_, HInstruction::kAdd, v0, v0, v0, DataType::Type::kInt32, 2);
+ &allocator_, HInstruction::kAdd, v0, v0, v0, DataType::Type::kInt32, 2, kNoDexPc);
EXPECT_FALSE(v0->CanBeMoved());
EXPECT_TRUE(v1->CanBeMoved());
@@ -334,14 +489,14 @@ TEST_F(NodesVectorTest, VectorOperationMattersOnMultiplyAccumulate) {
TEST_F(NodesVectorTest, VectorKindMattersOnReduce) {
HVecOperation* v0 = new (&allocator_)
- HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4);
+ HVecReplicateScalar(&allocator_, int32_parameter_, DataType::Type::kInt32, 4, kNoDexPc);
HVecReduce* v1 = new (&allocator_) HVecReduce(
- &allocator_, v0, DataType::Type::kInt32, 4, HVecReduce::kSum);
+ &allocator_, v0, DataType::Type::kInt32, 4, HVecReduce::kSum, kNoDexPc);
HVecReduce* v2 = new (&allocator_) HVecReduce(
- &allocator_, v0, DataType::Type::kInt32, 4, HVecReduce::kMin);
+ &allocator_, v0, DataType::Type::kInt32, 4, HVecReduce::kMin, kNoDexPc);
HVecReduce* v3 = new (&allocator_) HVecReduce(
- &allocator_, v0, DataType::Type::kInt32, 4, HVecReduce::kMax);
+ &allocator_, v0, DataType::Type::kInt32, 4, HVecReduce::kMax, kNoDexPc);
EXPECT_FALSE(v0->CanBeMoved());
EXPECT_TRUE(v1->CanBeMoved());
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 12185866cd..1e06ea86a2 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -27,6 +27,7 @@
#endif
#ifdef ART_ENABLE_CODEGEN_mips
+#include "instruction_simplifier_mips.h"
#include "pc_relative_fixups_mips.h"
#endif
@@ -528,6 +529,8 @@ static HOptimization* BuildOptimization(
#ifdef ART_ENABLE_CODEGEN_mips
} else if (opt_name == mips::PcRelativeFixups::kPcRelativeFixupsMipsPassName) {
return new (arena) mips::PcRelativeFixups(graph, codegen, stats);
+ } else if (opt_name == mips::InstructionSimplifierMips::kInstructionSimplifierMipsPassName) {
+ return new (arena) mips::InstructionSimplifierMips(graph, codegen, stats);
#endif
#ifdef ART_ENABLE_CODEGEN_x86
} else if (opt_name == x86::PcRelativeFixups::kPcRelativeFixupsX86PassName) {
@@ -669,11 +672,14 @@ void OptimizingCompiler::RunArchOptimizations(InstructionSet instruction_set,
#endif
#ifdef ART_ENABLE_CODEGEN_mips
case kMips: {
+ mips::InstructionSimplifierMips* simplifier =
+ new (arena) mips::InstructionSimplifierMips(graph, codegen, stats);
SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph);
GVNOptimization* gvn = new (arena) GVNOptimization(graph, *side_effects, "GVN$after_arch");
mips::PcRelativeFixups* pc_relative_fixups =
new (arena) mips::PcRelativeFixups(graph, codegen, stats);
HOptimization* mips_optimizations[] = {
+ simplifier,
side_effects,
gvn,
pc_relative_fixups,
diff --git a/compiler/optimizing/register_allocation_resolver.cc b/compiler/optimizing/register_allocation_resolver.cc
index f0057c3095..1786aa72a1 100644
--- a/compiler/optimizing/register_allocation_resolver.cc
+++ b/compiler/optimizing/register_allocation_resolver.cc
@@ -112,6 +112,7 @@ void RegisterAllocationResolver::Resolve(ArrayRef<HInstruction* const> safepoint
case DataType::Type::kReference:
case DataType::Type::kInt32:
case DataType::Type::kUint16:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kBool:
case DataType::Type::kInt16:
diff --git a/compiler/optimizing/register_allocator_graph_color.cc b/compiler/optimizing/register_allocator_graph_color.cc
index 4ff7315045..33df607831 100644
--- a/compiler/optimizing/register_allocator_graph_color.cc
+++ b/compiler/optimizing/register_allocator_graph_color.cc
@@ -1940,6 +1940,7 @@ void RegisterAllocatorGraphColor::AllocateSpillSlots(const ArenaVector<Interfere
case DataType::Type::kReference:
case DataType::Type::kInt32:
case DataType::Type::kUint16:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kBool:
case DataType::Type::kInt16:
diff --git a/compiler/optimizing/register_allocator_linear_scan.cc b/compiler/optimizing/register_allocator_linear_scan.cc
index 2012cd5847..9803a7b650 100644
--- a/compiler/optimizing/register_allocator_linear_scan.cc
+++ b/compiler/optimizing/register_allocator_linear_scan.cc
@@ -1116,6 +1116,7 @@ void RegisterAllocatorLinearScan::AllocateSpillSlotFor(LiveInterval* interval) {
case DataType::Type::kReference:
case DataType::Type::kInt32:
case DataType::Type::kUint16:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kBool:
case DataType::Type::kInt16:
diff --git a/compiler/optimizing/scheduler_arm.cc b/compiler/optimizing/scheduler_arm.cc
index 110db47eb5..b3c8f105d1 100644
--- a/compiler/optimizing/scheduler_arm.cc
+++ b/compiler/optimizing/scheduler_arm.cc
@@ -514,9 +514,10 @@ void SchedulingLatencyVisitorARM::VisitCompare(HCompare* instr) {
DataType::Type type = instr->InputAt(0)->GetType();
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
last_visited_internal_latency_ = 2 * kArmIntegerOpLatency;
break;
@@ -633,9 +634,10 @@ void SchedulingLatencyVisitorARM::VisitArrayGet(HArrayGet* instruction) {
switch (type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32: {
if (maybe_compressed_char_at) {
last_visited_internal_latency_ += kArmMemoryLoadLatency;
@@ -733,9 +735,10 @@ void SchedulingLatencyVisitorARM::VisitArraySet(HArraySet* instruction) {
switch (value_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32: {
if (index->IsConstant()) {
last_visited_latency_ = kArmMemoryStoreLatency;
@@ -916,9 +919,10 @@ void SchedulingLatencyVisitorARM::HandleFieldGetLatencies(HInstruction* instruct
switch (field_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
case DataType::Type::kInt32:
last_visited_latency_ = kArmMemoryLoadLatency;
break;
@@ -977,9 +981,10 @@ void SchedulingLatencyVisitorARM::HandleFieldSetLatencies(HInstruction* instruct
switch (field_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
- case DataType::Type::kInt16:
case DataType::Type::kUint16:
+ case DataType::Type::kInt16:
if (is_volatile) {
last_visited_internal_latency_ = kArmMemoryBarrierLatency + kArmMemoryStoreLatency;
last_visited_latency_ = kArmMemoryBarrierLatency;
@@ -1047,6 +1052,7 @@ void SchedulingLatencyVisitorARM::VisitTypeConversion(HTypeConversion* instr) {
DataType::Type input_type = instr->GetInputType();
switch (result_type) {
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -1072,6 +1078,7 @@ void SchedulingLatencyVisitorARM::VisitTypeConversion(HTypeConversion* instr) {
case DataType::Type::kInt64:
switch (input_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -1095,6 +1102,7 @@ void SchedulingLatencyVisitorARM::VisitTypeConversion(HTypeConversion* instr) {
case DataType::Type::kFloat32:
switch (input_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
@@ -1118,6 +1126,7 @@ void SchedulingLatencyVisitorARM::VisitTypeConversion(HTypeConversion* instr) {
case DataType::Type::kFloat64:
switch (input_type) {
case DataType::Type::kBool:
+ case DataType::Type::kUint8:
case DataType::Type::kInt8:
case DataType::Type::kUint16:
case DataType::Type::kInt16:
diff --git a/compiler/optimizing/side_effects_test.cc b/compiler/optimizing/side_effects_test.cc
index ac5eb15228..97317124ef 100644
--- a/compiler/optimizing/side_effects_test.cc
+++ b/compiler/optimizing/side_effects_test.cc
@@ -21,6 +21,19 @@
namespace art {
+// Only runtime types other than void are allowed.
+static const DataType::Type kTestTypes[] = {
+ DataType::Type::kReference,
+ DataType::Type::kBool,
+ DataType::Type::kInt8,
+ DataType::Type::kUint16,
+ DataType::Type::kInt16,
+ DataType::Type::kInt32,
+ DataType::Type::kInt64,
+ DataType::Type::kFloat32,
+ DataType::Type::kFloat64,
+};
+
/**
* Tests for the SideEffects class.
*/
@@ -91,9 +104,7 @@ TEST(SideEffectsTest, None) {
TEST(SideEffectsTest, DependencesAndNoDependences) {
// Apply test to each individual data type.
- for (DataType::Type type = DataType::Type::kReference;
- type < DataType::Type::kVoid;
- type = static_cast<DataType::Type>(static_cast<uint8_t>(type) + 1u)) {
+ for (DataType::Type type : kTestTypes) {
// Same data type and access type: proper write/read dep.
testWriteAndReadDependence(
SideEffects::FieldWriteOfType(type, false),
@@ -169,9 +180,7 @@ TEST(SideEffectsTest, SameWidthTypesNoAlias) {
TEST(SideEffectsTest, AllWritesAndReads) {
SideEffects s = SideEffects::None();
// Keep taking the union of different writes and reads.
- for (DataType::Type type = DataType::Type::kReference;
- type < DataType::Type::kVoid;
- type = static_cast<DataType::Type>(static_cast<uint8_t>(type) + 1u)) {
+ for (DataType::Type type : kTestTypes) {
s = s.Union(SideEffects::FieldWriteOfType(type, /* is_volatile */ false));
s = s.Union(SideEffects::ArrayWriteOfType(type));
s = s.Union(SideEffects::FieldReadOfType(type, /* is_volatile */ false));
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 77b7a228dc..23563168a0 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -393,7 +393,7 @@ bool SsaBuilder::FixAmbiguousArrayOps() {
}
// Refine the side effects of this floating point aset. Note that we do this even if
// no replacement occurs, since the right-hand-side may have been corrected already.
- aset->ComputeSideEffects();
+ aset->SetSideEffects(HArraySet::ComputeSideEffects(aset->GetComponentType()));
} else {
// Array elements are integral and the value assigned to it initially
// was integral too. Nothing to do.