diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/optimizing/builder.cc | 70 | ||||
-rw-r--r-- | compiler/optimizing/builder.h | 13 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 80 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 167 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.h | 1 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 139 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 1 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 37 |
9 files changed, 407 insertions, 104 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index b51b6e7d2..855730eb5 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -568,12 +568,13 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, return true; } -void HGraphBuilder::BuildCheckedDiv(uint16_t out_vreg, - uint16_t first_vreg, - int64_t second_vreg_or_constant, - uint32_t dex_pc, - Primitive::Type type, - bool second_is_constant) { +void HGraphBuilder::BuildCheckedDivRem(uint16_t out_vreg, + uint16_t first_vreg, + int64_t second_vreg_or_constant, + uint32_t dex_pc, + Primitive::Type type, + bool second_is_constant, + bool isDiv) { DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong); HInstruction* first = LoadLocal(first_vreg, type); @@ -597,7 +598,11 @@ void HGraphBuilder::BuildCheckedDiv(uint16_t out_vreg, temps.Add(current_block_->GetLastInstruction()); } - current_block_->AddInstruction(new (arena_) HDiv(type, first, second, dex_pc)); + if (isDiv) { + current_block_->AddInstruction(new (arena_) HDiv(type, first, second, dex_pc)); + } else { + current_block_->AddInstruction(new (arena_) HRem(type, first, second, dex_pc)); + } UpdateLocal(out_vreg, current_block_->GetLastInstruction()); } @@ -1078,14 +1083,14 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::DIV_INT: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), - dex_pc, Primitive::kPrimInt, false); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimInt, false, true); break; } case Instruction::DIV_LONG: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), - dex_pc, Primitive::kPrimLong, false); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimLong, false, true); break; } @@ -1099,6 +1104,18 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 break; } + case Instruction::REM_INT: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimInt, false, false); + break; + } + + case Instruction::REM_LONG: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimLong, false, false); + break; + } + case Instruction::AND_INT: { Binop_23x<HAnd>(instruction, Primitive::kPrimInt); break; @@ -1185,14 +1202,26 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 } case Instruction::DIV_INT_2ADDR: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), - dex_pc, Primitive::kPrimInt, false); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), + dex_pc, Primitive::kPrimInt, false, true); break; } case Instruction::DIV_LONG_2ADDR: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), - dex_pc, Primitive::kPrimLong, false); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), + dex_pc, Primitive::kPrimLong, false, true); + break; + } + + case Instruction::REM_INT_2ADDR: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), + dex_pc, Primitive::kPrimInt, false, false); + break; + } + + case Instruction::REM_LONG_2ADDR: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegA(), instruction.VRegB(), + dex_pc, Primitive::kPrimLong, false, false); break; } @@ -1298,8 +1327,15 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 case Instruction::DIV_INT_LIT16: case Instruction::DIV_INT_LIT8: { - BuildCheckedDiv(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), - dex_pc, Primitive::kPrimInt, true); + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimInt, true, true); + break; + } + + case Instruction::REM_INT_LIT16: + case Instruction::REM_INT_LIT8: { + BuildCheckedDivRem(instruction.VRegA(), instruction.VRegB(), instruction.VRegC(), + dex_pc, Primitive::kPrimInt, true, false); break; } diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index 799e628a7..897bcece7 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -123,12 +123,13 @@ class HGraphBuilder : public ValueObject { Primitive::Type input_type, Primitive::Type result_type); - void BuildCheckedDiv(uint16_t out_reg, - uint16_t first_reg, - int64_t second_reg_or_constant, - uint32_t dex_pc, - Primitive::Type type, - bool second_is_lit); + void BuildCheckedDivRem(uint16_t out_reg, + uint16_t first_reg, + int64_t second_reg_or_constant, + uint32_t dex_pc, + Primitive::Type type, + bool second_is_lit, + bool is_div); void BuildReturn(const Instruction& instruction, Primitive::Type type); diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 09e1b9757..1c23170d1 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -1842,6 +1842,86 @@ void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) { } } +void LocationsBuilderARM::VisitRem(HRem* rem) { + LocationSummary::CallKind call_kind = rem->GetResultType() == Primitive::kPrimLong + ? LocationSummary::kCall + : LocationSummary::kNoCall; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); + + switch (rem->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + locations->AddTemp(Location::RequiresRegister()); + break; + } + case Primitive::kPrimLong: { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); + locations->SetInAt(1, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); + // The runtime helper puts the output in R2,R3. + locations->SetOut(Location::RegisterPairLocation(R2, R3)); + break; + } + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + +void InstructionCodeGeneratorARM::VisitRem(HRem* rem) { + LocationSummary* locations = rem->GetLocations(); + Location out = locations->Out(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + + switch (rem->GetResultType()) { + case Primitive::kPrimInt: { + Register reg1 = first.As<Register>(); + Register reg2 = second.As<Register>(); + Register temp = locations->GetTemp(0).As<Register>(); + + // temp = reg1 / reg2 (integer division) + // temp = temp * reg2 + // dest = reg1 - temp + __ sdiv(temp, reg1, reg2); + __ mul(temp, temp, reg2); + __ sub(out.As<Register>(), reg1, ShifterOperand(temp)); + break; + } + + case Primitive::kPrimLong: { + InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); + DCHECK_EQ(R2, out.AsRegisterPairLow<Register>()); + DCHECK_EQ(R3, out.AsRegisterPairHigh<Register>()); + + codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc()); + break; + } + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 887a4efa1..543288296 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -643,11 +643,12 @@ InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, M(MonitorOperation) \ M(Or) \ M(ParallelMove) \ + M(Rem) \ M(StaticFieldGet) \ M(StaticFieldSet) \ M(Throw) \ M(TypeConversion) \ - M(Xor) \ + M(Xor) \ #define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 8a8fec260..f20ca0168 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -100,19 +100,24 @@ class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 { DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86); }; -class DivMinusOneSlowPathX86 : public SlowPathCodeX86 { +class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 { public: - explicit DivMinusOneSlowPathX86(Register reg) : reg_(reg) {} + explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {} virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { __ Bind(GetEntryLabel()); - __ negl(reg_); + if (is_div_) { + __ negl(reg_); + } else { + __ movl(reg_, Immediate(0)); + } __ jmp(GetExitLabel()); } private: Register reg_; - DISALLOW_COPY_AND_ASSIGN(DivMinusOneSlowPathX86); + bool is_div_; + DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86); }; class StackOverflowCheckSlowPathX86 : public SlowPathCodeX86 { @@ -1753,6 +1758,68 @@ void InstructionCodeGeneratorX86::VisitMul(HMul* mul) { } } +void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + + LocationSummary* locations = instruction->GetLocations(); + Location out = locations->Out(); + Location first = locations->InAt(0); + Location second = locations->InAt(1); + bool is_div = instruction->IsDiv(); + + switch (instruction->GetResultType()) { + case Primitive::kPrimInt: { + Register second_reg = second.As<Register>(); + DCHECK_EQ(EAX, first.As<Register>()); + DCHECK_EQ(is_div ? EAX : EDX, out.As<Register>()); + + SlowPathCodeX86* slow_path = + new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.As<Register>(), is_div); + codegen_->AddSlowPath(slow_path); + + // 0x80000000/-1 triggers an arithmetic exception! + // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so + // it's safe to just use negl instead of more complex comparisons. + + __ cmpl(second_reg, Immediate(-1)); + __ j(kEqual, slow_path->GetEntryLabel()); + + // edx:eax <- sign-extended of eax + __ cdq(); + // eax = quotient, edx = remainder + __ idivl(second_reg); + + __ Bind(slow_path->GetExitLabel()); + break; + } + + case Primitive::kPrimLong: { + InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); + DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); + DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>()); + DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>()); + + if (is_div) { + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv))); + } else { + __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod))); + } + uint32_t dex_pc = is_div + ? instruction->AsDiv()->GetDexPc() + : instruction->AsRem()->GetDexPc(); + codegen_->RecordPcInfo(instruction, dex_pc); + + break; + } + + default: + LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType(); + } +} + void LocationsBuilderX86::VisitDiv(HDiv* div) { LocationSummary::CallKind call_kind = div->GetResultType() == Primitive::kPrimLong ? LocationSummary::kCall @@ -1798,45 +1865,9 @@ void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) { Location second = locations->InAt(1); switch (div->GetResultType()) { - case Primitive::kPrimInt: { - DCHECK(first.Equals(out)); - Register first_reg = first.As<Register>(); - Register second_reg = second.As<Register>(); - DCHECK_EQ(EAX, first_reg); - DCHECK_EQ(EDX, locations->GetTemp(0).As<Register>()); - - SlowPathCodeX86* slow_path = - new (GetGraph()->GetArena()) DivMinusOneSlowPathX86(first_reg); - codegen_->AddSlowPath(slow_path); - - // 0x80000000/-1 triggers an arithmetic exception! - // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so - // it's safe to just use negl instead of more complex comparisons. - - __ cmpl(second_reg, Immediate(-1)); - __ j(kEqual, slow_path->GetEntryLabel()); - - // edx:eax <- sign-extended of eax - __ cdq(); - // eax = quotient, edx = remainder - __ idivl(second_reg); - - __ Bind(slow_path->GetExitLabel()); - break; - } - + case Primitive::kPrimInt: case Primitive::kPrimLong: { - InvokeRuntimeCallingConvention calling_convention; - DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); - DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); - DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); - DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); - DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>()); - DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>()); - - __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv))); - codegen_->RecordPcInfo(div, div->GetDexPc()); - + GenerateDivRemIntegral(div); break; } @@ -1857,6 +1888,58 @@ void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) { } } +void LocationsBuilderX86::VisitRem(HRem* rem) { + LocationSummary::CallKind call_kind = rem->GetResultType() == Primitive::kPrimLong + ? LocationSummary::kCall + : LocationSummary::kNoCall; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); + + switch (rem->GetResultType()) { + case Primitive::kPrimInt: { + locations->SetInAt(0, Location::RegisterLocation(EAX)); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RegisterLocation(EDX)); + break; + } + case Primitive::kPrimLong: { + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); + locations->SetInAt(1, Location::RegisterPairLocation( + calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); + // Runtime helper puts the result in EAX, EDX. + locations->SetOut(Location::RegisterPairLocation(EAX, EDX)); + break; + } + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + +void InstructionCodeGeneratorX86::VisitRem(HRem* rem) { + Primitive::Type type = rem->GetResultType(); + switch (type) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + GenerateDivRemIntegral(rem); + break; + } + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << type; + break; + } + default: + LOG(FATAL) << "Unexpected rem type " << type; + } +} + void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 841b28b15..8252f81c7 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -130,6 +130,7 @@ class InstructionCodeGeneratorX86 : public HGraphVisitor { void GenerateSuspendCheck(HSuspendCheck* check, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeX86* slow_path, Register class_reg); void HandleBitwiseOperation(HBinaryOperation* instruction); + void GenerateDivRemIntegral(HBinaryOperation* instruction); X86Assembler* const assembler_; CodeGeneratorX86* const codegen_; diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 5aa1c4a6c..910e73db2 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -106,26 +106,36 @@ class DivZeroCheckSlowPathX86_64 : public SlowPathCodeX86_64 { DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86_64); }; -class DivMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 { +class DivRemMinusOneSlowPathX86_64 : public SlowPathCodeX86_64 { public: - explicit DivMinusOneSlowPathX86_64(Register reg, Primitive::Type type) - : reg_(reg), type_(type) {} + explicit DivRemMinusOneSlowPathX86_64(Register reg, Primitive::Type type, bool is_div) + : cpu_reg_(CpuRegister(reg)), type_(type), is_div_(is_div) {} virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { __ Bind(GetEntryLabel()); if (type_ == Primitive::kPrimInt) { - __ negl(CpuRegister(reg_)); + if (is_div_) { + __ negl(cpu_reg_); + } else { + __ movl(cpu_reg_, Immediate(0)); + } + } else { DCHECK_EQ(Primitive::kPrimLong, type_); - __ negq(CpuRegister(reg_)); + if (is_div_) { + __ negq(cpu_reg_); + } else { + __ movq(cpu_reg_, Immediate(0)); + } } __ jmp(GetExitLabel()); } private: - const Register reg_; + const CpuRegister cpu_reg_; const Primitive::Type type_; - DISALLOW_COPY_AND_ASSIGN(DivMinusOneSlowPathX86_64); + const bool is_div_; + DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86_64); }; class StackOverflowCheckSlowPathX86_64 : public SlowPathCodeX86_64 { @@ -1701,6 +1711,47 @@ void InstructionCodeGeneratorX86_64::VisitMul(HMul* mul) { } } +void InstructionCodeGeneratorX86_64::GenerateDivRemIntegral(HBinaryOperation* instruction) { + DCHECK(instruction->IsDiv() || instruction->IsRem()); + Primitive::Type type = instruction->GetResultType(); + DCHECK(type == Primitive::kPrimInt || Primitive::kPrimLong); + + bool is_div = instruction->IsDiv(); + LocationSummary* locations = instruction->GetLocations(); + + CpuRegister out_reg = locations->Out().As<CpuRegister>(); + CpuRegister second_reg = locations->InAt(1).As<CpuRegister>(); + + DCHECK_EQ(RAX, locations->InAt(0).As<CpuRegister>().AsRegister()); + DCHECK_EQ(is_div ? RAX : RDX, out_reg.AsRegister()); + + SlowPathCodeX86_64* slow_path = + new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86_64( + out_reg.AsRegister(), type, is_div); + codegen_->AddSlowPath(slow_path); + + // 0x80000000(00000000)/-1 triggers an arithmetic exception! + // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000) + // so it's safe to just use negl instead of more complex comparisons. + + __ cmpl(second_reg, Immediate(-1)); + __ j(kEqual, slow_path->GetEntryLabel()); + + if (type == Primitive::kPrimInt) { + // edx:eax <- sign-extended of eax + __ cdq(); + // eax = quotient, edx = remainder + __ idivl(second_reg); + } else { + // rdx:rax <- sign-extended of rax + __ cqo(); + // rax = quotient, rdx = remainder + __ idivq(second_reg); + } + + __ Bind(slow_path->GetExitLabel()); +} + void LocationsBuilderX86_64::VisitDiv(HDiv* div) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall); @@ -1738,35 +1789,7 @@ void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) { switch (type) { case Primitive::kPrimInt: case Primitive::kPrimLong: { - CpuRegister first_reg = first.As<CpuRegister>(); - CpuRegister second_reg = second.As<CpuRegister>(); - DCHECK_EQ(RAX, first_reg.AsRegister()); - DCHECK_EQ(RDX, locations->GetTemp(0).As<CpuRegister>().AsRegister()); - - SlowPathCodeX86_64* slow_path = - new (GetGraph()->GetArena()) DivMinusOneSlowPathX86_64(first_reg.AsRegister(), type); - codegen_->AddSlowPath(slow_path); - - // 0x80000000(00000000)/-1 triggers an arithmetic exception! - // Dividing by -1 is actually negation and -0x800000000(00000000) = 0x80000000(00000000) - // so it's safe to just use negl instead of more complex comparisons. - - __ cmpl(second_reg, Immediate(-1)); - __ j(kEqual, slow_path->GetEntryLabel()); - - if (type == Primitive::kPrimInt) { - // edx:eax <- sign-extended of eax - __ cdq(); - // eax = quotient, edx = remainder - __ idivl(second_reg); - } else { - // rdx:rax <- sign-extended of rax - __ cqo(); - // rax = quotient, rdx = remainder - __ idivq(second_reg); - } - - __ Bind(slow_path->GetExitLabel()); + GenerateDivRemIntegral(div); break; } @@ -1785,6 +1808,50 @@ void InstructionCodeGeneratorX86_64::VisitDiv(HDiv* div) { } } +void LocationsBuilderX86_64::VisitRem(HRem* rem) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall); + switch (rem->GetResultType()) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + locations->SetInAt(0, Location::RegisterLocation(RAX)); + locations->SetInAt(1, Location::RequiresRegister()); + // Intel uses rdx:rax as the dividend and puts the remainder in rdx + locations->SetOut(Location::RegisterLocation(RDX)); + break; + } + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + +void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) { + Primitive::Type type = rem->GetResultType(); + switch (type) { + case Primitive::kPrimInt: + case Primitive::kPrimLong: { + GenerateDivRemIntegral(rem); + break; + } + + case Primitive::kPrimFloat: + case Primitive::kPrimDouble: { + LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); + break; + } + + default: + LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); + } +} + void LocationsBuilderX86_64::VisitDivZeroCheck(HDivZeroCheck* instruction) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 4c6e4750d..86f3b4ebf 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -134,6 +134,7 @@ class InstructionCodeGeneratorX86_64 : public HGraphVisitor { void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg); void HandleBitwiseOperation(HBinaryOperation* operation); + void GenerateDivRemIntegral(HBinaryOperation* instruction); X86_64Assembler* const assembler_; CodeGeneratorX86_64* const codegen_; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 5af3cdd2d..383d8bc09 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -521,6 +521,7 @@ class HBasicBlock : public ArenaObject<kArenaAllocMisc> { M(ParallelMove, Instruction) \ M(ParameterValue, Instruction) \ M(Phi, Instruction) \ + M(Rem, BinaryOperation) \ M(Return, Instruction) \ M(ReturnVoid, Instruction) \ M(StaticFieldGet, Instruction) \ @@ -1756,10 +1757,15 @@ class HDiv : public HBinaryOperation { virtual int32_t Evaluate(int32_t x, int32_t y) const { // Our graph structure ensures we never have 0 for `y` during constant folding. DCHECK_NE(y, 0); - // Special case -1 to avoid getting a SIGFPE on x86. + // Special case -1 to avoid getting a SIGFPE on x86(_64). + return (y == -1) ? -x : x / y; + } + + virtual int64_t Evaluate(int64_t x, int64_t y) const { + DCHECK_NE(y, 0); + // Special case -1 to avoid getting a SIGFPE on x86(_64). return (y == -1) ? -x : x / y; } - virtual int64_t Evaluate(int64_t x, int64_t y) const { return x / y; } uint32_t GetDexPc() const { return dex_pc_; } @@ -1771,6 +1777,33 @@ class HDiv : public HBinaryOperation { DISALLOW_COPY_AND_ASSIGN(HDiv); }; +class HRem : public HBinaryOperation { + public: + HRem(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc) + : HBinaryOperation(result_type, left, right), dex_pc_(dex_pc) {} + + virtual int32_t Evaluate(int32_t x, int32_t y) const { + DCHECK_NE(y, 0); + // Special case -1 to avoid getting a SIGFPE on x86(_64). + return (y == -1) ? 0 : x % y; + } + + virtual int64_t Evaluate(int64_t x, int64_t y) const { + DCHECK_NE(y, 0); + // Special case -1 to avoid getting a SIGFPE on x86(_64). + return (y == -1) ? 0 : x % y; + } + + uint32_t GetDexPc() const { return dex_pc_; } + + DECLARE_INSTRUCTION(Rem); + + private: + const uint32_t dex_pc_; + + DISALLOW_COPY_AND_ASSIGN(HRem); +}; + class HDivZeroCheck : public HExpression<1> { public: HDivZeroCheck(HInstruction* value, uint32_t dex_pc) |