[optimizing compiler] Add div-int and exception handling.
- for backends: arm, x86, x86_64
- fixed a register allocator bug: the request for a fixed register for
the first input was ignored if the output was kSameAsFirstInput
- added divide by zero exception
- more tests
- shuffle around some code in the builder to reduce the number of lines
of code for a single function.
Change-Id: Id3a515e02bfbc66cd9d16cb9746f7551bdab3d42
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 8132e81..b2d9187 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -85,6 +85,36 @@
DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
};
+class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 {
+ public:
+ explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ __ Bind(GetEntryLabel());
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero)));
+ codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+ }
+
+ private:
+ HDivZeroCheck* const instruction_;
+ DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
+};
+
+class DivMinusOneSlowPathX86 : public SlowPathCodeX86 {
+ public:
+ explicit DivMinusOneSlowPathX86(Register reg) : reg_(reg) {}
+
+ virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+ __ Bind(GetEntryLabel());
+ __ negl(reg_);
+ __ jmp(GetExitLabel());
+ }
+
+ private:
+ Register reg_;
+ DISALLOW_COPY_AND_ASSIGN(DivMinusOneSlowPathX86);
+};
+
class StackOverflowCheckSlowPathX86 : public SlowPathCodeX86 {
public:
StackOverflowCheckSlowPathX86() {}
@@ -1471,7 +1501,14 @@
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
switch (div->GetResultType()) {
- case Primitive::kPrimInt:
+ case Primitive::kPrimInt: {
+ locations->SetInAt(0, Location::RegisterLocation(EAX));
+ locations->SetInAt(1, Location::RequiresRegister());
+ locations->SetOut(Location::SameAsFirstInput());
+ // Intel uses edx:eax as the dividend.
+ locations->AddTemp(Location::RegisterLocation(EDX));
+ break;
+ }
case Primitive::kPrimLong: {
LOG(FATAL) << "Not implemented div type" << div->GetResultType();
break;
@@ -1496,7 +1533,32 @@
DCHECK(first.Equals(locations->Out()));
switch (div->GetResultType()) {
- case Primitive::kPrimInt:
+ case Primitive::kPrimInt: {
+ 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::kPrimLong: {
LOG(FATAL) << "Not implemented div type" << div->GetResultType();
break;
@@ -1517,6 +1579,36 @@
}
}
+void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ LocationSummary* locations =
+ new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
+ locations->SetInAt(0, Location::Any());
+ if (instruction->HasUses()) {
+ locations->SetOut(Location::SameAsFirstInput());
+ }
+}
+
+void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
+ SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
+ codegen_->AddSlowPath(slow_path);
+
+ LocationSummary* locations = instruction->GetLocations();
+ Location value = locations->InAt(0);
+
+ if (value.IsRegister()) {
+ __ testl(value.As<Register>(), value.As<Register>());
+ } else if (value.IsStackSlot()) {
+ __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
+ } else {
+ DCHECK(value.IsConstant()) << value;
+ if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
+ __ jmp(slow_path->GetEntryLabel());
+ }
+ return;
+ }
+ __ j(kEqual, slow_path->GetEntryLabel());
+}
+
void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
LocationSummary* locations =
new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);