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