diff options
author | 2017-09-26 12:37:26 +0100 | |
---|---|---|
committer | 2017-10-03 10:40:51 +0100 | |
commit | d5d2f2ce627aa0f6920d7ae05197abd1a396e035 (patch) | |
tree | e8e780780c832e3614a22438a23fb60ee4960ca3 /compiler/optimizing | |
parent | efac0df8c738764823c637deeca1f3be33912064 (diff) |
ART: Introduce Uint8 compiler data type.
This CL adds all the necessary codegen for the Uint8 type
but does not add code transformations that use that code.
Vectorization codegens are modified to use Uint8 as the
packed type when appropriate. The side effects are now
disconnected from the instruction's type after the graph has
been built to allow changing HArrayGet/H*FieldGet/HVecLoad
to use a type different from the underlying field or array.
Note: HArrayGet for String.charAt() is modified to have
no side effects whatsoever; Strings are immutable.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing --jit
Test: testrunner.py --target --optimizing on Nexus 6P
Test: Nexus 6P boots.
Bug: 23964345
Change-Id: If2dfffedcfb1f50db24570a1e9bd517b3f17bfd0
Diffstat (limited to 'compiler/optimizing')
32 files changed, 1347 insertions, 1075 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..70c8a5b523 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) { @@ -2683,6 +2673,19 @@ 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::kInt32: { DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t)); Register out = out_loc.AsRegister<Register>(); @@ -2880,6 +2883,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,8 +2901,8 @@ 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; @@ -3390,9 +3394,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 +3434,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 +3839,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 +6166,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 +6320,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 +8610,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 +8662,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 +8681,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 +8692,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..5a023ad69b 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,27 @@ class DataType { return type == Type::kInt64 || type == Type::kFloat64; } + static bool IsUnsignedType(Type type) { + return type == Type::kUint8 || type == Type::kUint16; + } + + static Type ToSignedType(Type type) { + switch (type) { + case Type::kUint8: + return Type::kInt8; + case Type::kUint16: + return Type::kInt16; + default: + DCHECK(type != Type::kVoid && type != Type::kReference); + return type; + } + } + // 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 +157,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 +179,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 +197,8 @@ class DataType { return 0; } + static bool IsTypeConversionImplicit(Type input_type, Type result_type); + static const char* PrettyDescriptor(Type type); private: @@ -179,6 +206,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 cf1cbd578c..f739d7b4f6 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 || @@ -876,10 +878,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); } @@ -1036,30 +1039,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); @@ -1069,7 +1055,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); @@ -1098,7 +1084,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()) { @@ -1127,7 +1113,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(); @@ -2167,8 +2153,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); 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 fec64e2adf..2090a12929 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; @@ -87,6 +127,7 @@ static bool IsSignExtensionAndGet(HInstruction* instruction, 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; @@ -151,6 +192,7 @@ static bool IsZeroExtensionAndGet(HInstruction* instruction, 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; @@ -170,9 +212,13 @@ static bool IsZeroExtensionAndGet(HInstruction* instruction, } // An implicit widening conversion of any unsigned expression zero-extends. if (instruction->GetType() == type) { - if (type == DataType::Type::kUint16) { - *operand = instruction; - return true; + 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 @@ -190,6 +236,7 @@ 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: @@ -257,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. @@ -1105,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 (DataType::ToSignedType(type) == DataType::ToSignedType(instruction->GetType()) && node->loop_info->IsDefinedOutOfTheLoop(base) && induction_range_.IsUnitStride(instruction, index, graph_, &offset)) { if (generate_code) { @@ -1281,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; @@ -1340,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); @@ -1359,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); @@ -1387,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; @@ -1416,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); @@ -1444,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); @@ -1540,11 +1552,16 @@ void HLoopOptimization::GenerateVecMem(HInstruction* org, 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_); } 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); } // Known dynamically enforced alignment? if (vector_peeling_candidate_ != nullptr && @@ -1556,11 +1573,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(), kNoDexPc); } 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(), kNoDexPc, is_string_char_at); } } vector_map_->Put(org, vector); @@ -1737,6 +1755,7 @@ void HLoopOptimization::GenerateVecOp(HInstruction* org, 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); break; @@ -1745,6 +1764,7 @@ void HLoopOptimization::GenerateVecOp(HInstruction* org, 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); break; @@ -1857,14 +1877,15 @@ 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_unsigned, - is_rounded)); + is_rounded, + is_unsigned)); MaybeRecordStat(stats_, MethodCompilationStat::kLoopVectorizedIdiom); } else { GenerateVecOp(instruction, vector_map_->Get(r), vector_map_->Get(s), type); @@ -1952,6 +1973,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_, 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..c75a5124f3 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1760,14 +1760,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. @@ -5382,9 +5394,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 +5477,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 +5499,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 +5537,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_vector.h b/compiler/optimizing/nodes_vector.h index 0aac260839..d01f8c0289 100644 --- a/compiler/optimizing/nodes_vector.h +++ b/compiler/optimizing/nodes_vector.h @@ -232,8 +232,10 @@ inline static bool HasConsistentPackedTypes(HInstruction* input, DataType::Type DataType::Type input_type = input->AsVecOperation()->GetPackedType(); switch (input_type) { case DataType::Type::kBool: + case DataType::Type::kUint8: case DataType::Type::kInt8: return type == DataType::Type::kBool || + type == DataType::Type::kUint8 || type == DataType::Type::kInt8; case DataType::Type::kUint16: case DataType::Type::kInt16: @@ -471,10 +473,14 @@ 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) - : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { + bool is_unsigned = false) + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, kNoDexPc) { + // 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); @@ -584,9 +590,13 @@ class HVecMin FINAL : public HVecBinaryOperation { HInstruction* right, DataType::Type packed_type, size_t vector_length, - bool is_unsigned, - uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { + bool is_unsigned = false) + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, kNoDexPc) { + // 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); @@ -622,9 +632,13 @@ class HVecMax FINAL : public HVecBinaryOperation { HInstruction* right, DataType::Type packed_type, size_t vector_length, - bool is_unsigned, - uint32_t dex_pc = kNoDexPc) - : HVecBinaryOperation(arena, left, right, packed_type, vector_length, dex_pc) { + bool is_unsigned = false) + : HVecBinaryOperation(arena, left, right, packed_type, vector_length, kNoDexPc) { + // 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); @@ -933,12 +947,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) : HVecMemoryOperation(arena, packed_type, - SideEffects::ArrayReadOfType(packed_type), + side_effects, /* number_of_inputs */ 2, vector_length, dex_pc) { @@ -977,11 +992,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) : 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..7dbfcda736 100644 --- a/compiler/optimizing/nodes_vector_test.cc +++ b/compiler/optimizing/nodes_vector_test.cc @@ -47,6 +47,16 @@ class NodesVectorTest : public CommonCompilerTest { 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_); } // General building fields. @@ -58,6 +68,8 @@ class NodesVectorTest : public CommonCompilerTest { HBasicBlock* exit_block_; HInstruction* parameter_; + HInstruction* int8_parameter_; + HInstruction* int16_parameter_; }; // @@ -126,8 +138,14 @@ TEST_F(NodesVectorTest, VectorOperationProperties) { HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 2); HVecOperation* v3 = new (&allocator_) HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt16, 4); - HVecOperation* v4 = new (&allocator_) - HVecStore(&allocator_, parameter_, parameter_, v0, DataType::Type::kInt32, 4); + HVecOperation* v4 = new (&allocator_) HVecStore( + &allocator_, + parameter_, + parameter_, + v0, + DataType::Type::kInt32, + SideEffects::ArrayWriteOfType(DataType::Type::kInt32), + 4); EXPECT_TRUE(v0->Equals(v0)); EXPECT_TRUE(v1->Equals(v1)); @@ -175,12 +193,27 @@ 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_, + parameter_, + parameter_, + DataType::Type::kInt32, + SideEffects::ArrayReadOfType(DataType::Type::kInt32), + 4, + /*is_string_char_at*/ false); + HVecLoad* v1 = new (&allocator_) HVecLoad(&allocator_, + parameter_, + parameter_, + DataType::Type::kInt32, + SideEffects::ArrayReadOfType(DataType::Type::kInt32), + 4, + /*is_string_char_at*/ false); + HVecLoad* v2 = new (&allocator_) HVecLoad(&allocator_, + parameter_, + parameter_, + DataType::Type::kInt32, + SideEffects::ArrayReadOfType(DataType::Type::kInt32), + 4, + /*is_string_char_at*/ true); EXPECT_TRUE(v0->CanBeMoved()); EXPECT_TRUE(v1->CanBeMoved()); @@ -209,99 +242,155 @@ TEST_F(NodesVectorTest, VectorAlignmentAndStringCharAtMatterOnLoad) { } TEST_F(NodesVectorTest, VectorSignMattersOnMin) { - HVecOperation* v0 = new (&allocator_) + HVecOperation* p0 = new (&allocator_) HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4); + HVecOperation* p1 = new (&allocator_) + HVecReplicateScalar(&allocator_, int8_parameter_, DataType::Type::kInt8, 4); + HVecOperation* p2 = new (&allocator_) + HVecReplicateScalar(&allocator_, int16_parameter_, DataType::Type::kInt16, 4); + + HVecMin* v0 = new (&allocator_) HVecMin( + &allocator_, p0, p0, DataType::Type::kInt32, 4, /*is_unsigned*/ true); + HVecMin* v1 = new (&allocator_) HVecMin( + &allocator_, p0, p0, DataType::Type::kInt32, 4, /*is_unsigned*/ false); + HVecMin* v2 = new (&allocator_) HVecMin( + &allocator_, p0, p0, DataType::Type::kInt32, 2, /*is_unsigned*/ true); + HVecMin* v3 = new (&allocator_) HVecMin(&allocator_, p1, p1, DataType::Type::kUint8, 16); + HVecMin* v4 = new (&allocator_) HVecMin(&allocator_, p1, p1, DataType::Type::kInt8, 16); + HVecMin* v5 = new (&allocator_) HVecMin(&allocator_, p2, p2, DataType::Type::kUint16, 8); + HVecMin* v6 = new (&allocator_) HVecMin(&allocator_, p2, p2, DataType::Type::kInt16, 8); + 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()); + } - 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); - - EXPECT_FALSE(v0->CanBeMoved()); - EXPECT_TRUE(v1->CanBeMoved()); - EXPECT_TRUE(v2->CanBeMoved()); - EXPECT_TRUE(v3->CanBeMoved()); - - EXPECT_TRUE(v1->IsUnsigned()); - EXPECT_FALSE(v2->IsUnsigned()); - EXPECT_TRUE(v3->IsUnsigned()); - - 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 (HVecMin* min_insn1 : min_insns) { + for (HVecMin* min_insn2 : min_insns) { + EXPECT_EQ(min_insn1 == min_insn2, min_insn1->Equals(min_insn2)); + } + } } TEST_F(NodesVectorTest, VectorSignMattersOnMax) { - HVecOperation* v0 = new (&allocator_) + HVecOperation* p0 = new (&allocator_) HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4); + HVecOperation* p1 = new (&allocator_) + HVecReplicateScalar(&allocator_, int8_parameter_, DataType::Type::kInt8, 4); + HVecOperation* p2 = new (&allocator_) + HVecReplicateScalar(&allocator_, int16_parameter_, DataType::Type::kInt16, 4); + + HVecMax* v0 = new (&allocator_) HVecMax( + &allocator_, p0, p0, DataType::Type::kInt32, 4, /*is_unsigned*/ true); + HVecMax* v1 = new (&allocator_) HVecMax( + &allocator_, p0, p0, DataType::Type::kInt32, 4, /*is_unsigned*/ false); + HVecMax* v2 = new (&allocator_) HVecMax( + &allocator_, p0, p0, DataType::Type::kInt32, 2, /*is_unsigned*/ true); + HVecMax* v3 = new (&allocator_) HVecMax(&allocator_, p1, p1, DataType::Type::kUint8, 16); + HVecMax* v4 = new (&allocator_) HVecMax(&allocator_, p1, p1, DataType::Type::kInt8, 16); + HVecMax* v5 = new (&allocator_) HVecMax(&allocator_, p2, p2, DataType::Type::kUint16, 8); + HVecMax* v6 = new (&allocator_) HVecMax(&allocator_, p2, p2, DataType::Type::kInt16, 8); + 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()); + } - 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); - - EXPECT_FALSE(v0->CanBeMoved()); - EXPECT_TRUE(v1->CanBeMoved()); - EXPECT_TRUE(v2->CanBeMoved()); - EXPECT_TRUE(v3->CanBeMoved()); - - EXPECT_TRUE(v1->IsUnsigned()); - EXPECT_FALSE(v2->IsUnsigned()); - EXPECT_TRUE(v3->IsUnsigned()); - - 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_) + HVecOperation* p0 = new (&allocator_) HVecReplicateScalar(&allocator_, parameter_, DataType::Type::kInt32, 4); + HVecOperation* p1 = new (&allocator_) + HVecReplicateScalar(&allocator_, int8_parameter_, DataType::Type::kInt8, 4); + HVecOperation* p2 = new (&allocator_) + HVecReplicateScalar(&allocator_, int16_parameter_, DataType::Type::kInt16, 4); + HVecHalvingAdd* v0 = new (&allocator_) HVecHalvingAdd( + &allocator_, p0, p0, DataType::Type::kInt32, 4, /*is_rounded*/ true, /*is_unsigned*/ true); 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); 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); 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); 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); 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); + HVecHalvingAdd* v6 = new (&allocator_) HVecHalvingAdd( + &allocator_, p1, p1, DataType::Type::kUint8, 16, /*is_rounded*/ false); + HVecHalvingAdd* v7 = new (&allocator_) HVecHalvingAdd( + &allocator_, p1, p1, DataType::Type::kInt8, 16, /*is_rounded*/ true); + HVecHalvingAdd* v8 = new (&allocator_) HVecHalvingAdd( + &allocator_, p1, p1, DataType::Type::kInt8, 16, /*is_rounded*/ false); + HVecHalvingAdd* v9 = new (&allocator_) HVecHalvingAdd( + &allocator_, p2, p2, DataType::Type::kUint16, 8, /*is_rounded*/ true); + HVecHalvingAdd* v10 = new (&allocator_) HVecHalvingAdd( + &allocator_, p2, p2, DataType::Type::kUint16, 8, /*is_rounded*/ false); + HVecHalvingAdd* v11 = new (&allocator_) HVecHalvingAdd( + &allocator_, p2, p2, DataType::Type::kInt16, 2, /*is_rounded*/ true); + HVecHalvingAdd* v12 = new (&allocator_) HVecHalvingAdd( + &allocator_, p2, p2, DataType::Type::kInt16, 2, /*is_rounded*/ false); + 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) { 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. |