Index: runtime/vm/intermediate_language_ia32.cc |
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc |
index dd7cf89227fee0f72b81ab85a7df2297aae343d6..7699adb41eb78a550ab919e445885d0206b50f01 100644 |
--- a/runtime/vm/intermediate_language_ia32.cc |
+++ b/runtime/vm/intermediate_language_ia32.cc |
@@ -4844,8 +4844,57 @@ void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
} |
-LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const { |
- if (kind() == MergedMathInstr::kTruncDivMod) { |
+LocationSummary* ExtractNthOutputInstr::MakeLocationSummary(bool opt) const { |
+ // Only use this instruction in optimized code. |
+ ASSERT(opt); |
+ const intptr_t kNumInputs = 1; |
+ LocationSummary* summary = |
+ new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); |
+ if (representation() == kUnboxedDouble) { |
+ if (index() == 0) { |
+ summary->set_in(0, Location::Pair(Location::RequiresFpuRegister(), |
+ Location::Any())); |
+ } else { |
+ ASSERT(index() == 1); |
+ summary->set_in(0, Location::Pair(Location::Any(), |
+ Location::RequiresFpuRegister())); |
+ } |
+ summary->set_out(0, Location::RequiresFpuRegister()); |
+ } else { |
+ ASSERT(representation() == kTagged); |
+ if (index() == 0) { |
+ summary->set_in(0, Location::Pair(Location::RequiresRegister(), |
+ Location::Any())); |
+ } else { |
+ ASSERT(index() == 1); |
+ summary->set_in(0, Location::Pair(Location::Any(), |
+ Location::RequiresRegister())); |
+ } |
+ summary->set_out(0, Location::RequiresRegister()); |
+ } |
+ return summary; |
+} |
+ |
+ |
+void ExtractNthOutputInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ ASSERT(locs()->in(0).IsPairLocation()); |
+ PairLocation* pair = locs()->in(0).AsPairLocation(); |
+ Location in_loc = pair->At(index()); |
+ if (representation() == kUnboxedDouble) { |
+ XmmRegister out = locs()->out(0).fpu_reg(); |
+ XmmRegister in = in_loc.fpu_reg(); |
+ __ movaps(out, in); |
+ } else { |
+ ASSERT(representation() == kTagged); |
+ Register out = locs()->out(0).reg(); |
+ Register in = in_loc.reg(); |
+ __ movl(out, in); |
+ } |
+} |
+ |
+ |
+LocationSummary* MergedMath2Instr::MakeLocationSummary(bool opt) const { |
+ if (kind() == MergedMath2Instr::kTruncDivMod) { |
const intptr_t kNumInputs = 2; |
const intptr_t kNumTemps = 1; |
LocationSummary* summary = |
@@ -4853,18 +4902,21 @@ LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const { |
// Both inputs must be writable because they will be untagged. |
summary->set_in(0, Location::RegisterLocation(EAX)); |
summary->set_in(1, Location::WritableRegister()); |
- summary->set_out(0, Location::RequiresRegister()); |
+ // Output is a pair of registers. |
+ summary->set_out(0, Location::Pair(Location::RequiresRegister(), |
+ Location::RequiresRegister())); |
// Will be used for sign extension and division. |
summary->set_temp(0, Location::RegisterLocation(EDX)); |
return summary; |
} |
- if (kind() == MergedMathInstr::kSinCos) { |
+ if (kind() == MergedMath2Instr::kSinCos) { |
const intptr_t kNumInputs = 1; |
const intptr_t kNumTemps = 0; |
LocationSummary* summary = |
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
- summary->set_in(0, Location::FpuRegisterLocation(XMM1)); |
- summary->set_out(0, Location::RegisterLocation(EAX)); |
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
+ summary->set_in(0, Location::RequiresFpuRegister()); |
+ summary->set_out(0, Location::Pair(Location::RequiresFpuRegister(), |
+ Location::RequiresFpuRegister())); |
return summary; |
} |
UNIMPLEMENTED(); |
@@ -4879,6 +4931,132 @@ extern const RuntimeEntry kSinCosRuntimeEntry( |
static_cast<SinCosCFunction>(&SinCos)), 1, true, true); |
+void MergedMath2Instr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ Label* deopt = NULL; |
+ if (CanDeoptimize()) { |
+ deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinarySmiOp); |
+ } |
+ |
+ if (kind() == MergedMath2Instr::kTruncDivMod) { |
+ Register left = locs()->in(0).reg(); |
+ Register right = locs()->in(1).reg(); |
+ ASSERT(locs()->out(0).IsPairLocation()); |
+ PairLocation* pair = locs()->out(0).AsPairLocation(); |
+ Register result1 = pair->At(0).reg(); |
+ Register result2 = pair->At(1).reg(); |
+ Range* right_range = InputAt(1)->definition()->range(); |
+ if ((right_range == NULL) || right_range->Overlaps(0, 0)) { |
+ // Handle divide by zero in runtime. |
+ __ testl(right, right); |
+ __ j(ZERO, deopt); |
+ } |
+ ASSERT(left == EAX); |
+ ASSERT((right != EDX) && (right != EAX)); |
+ ASSERT(locs()->temp(0).reg() == EDX); |
+ ASSERT((result1 != EDX) && (result1 != EAX)); |
+ ASSERT((result2 != EDX) && (result2 != EAX)); |
+ __ SmiUntag(left); |
+ __ SmiUntag(right); |
+ __ cdq(); // Sign extend EAX -> EDX:EAX. |
+ __ idivl(right); // EAX: quotient, EDX: remainder. |
+ // Check the corner case of dividing the 'MIN_SMI' with -1, in which |
+ // case we cannot tag the result. |
+ // TODO(srdjan): We could store instead untagged intermediate results in a |
+ // typed array, but then the load indexed instructions would need to be |
+ // able to deoptimize. |
+ __ cmpl(EAX, Immediate(0x40000000)); |
+ __ j(EQUAL, deopt); |
+ // Modulo result (EDX) correction: |
+ // res = left % right; |
+ // if (res < 0) { |
+ // if (right < 0) { |
+ // res = res - right; |
+ // } else { |
+ // res = res + right; |
+ // } |
+ // } |
+ Label done; |
+ __ cmpl(EDX, Immediate(0)); |
+ __ j(GREATER_EQUAL, &done, Assembler::kNearJump); |
+ // Result is negative, adjust it. |
+ if ((right_range == NULL) || right_range->Overlaps(-1, 1)) { |
+ Label subtract; |
+ __ cmpl(right, Immediate(0)); |
+ __ j(LESS, &subtract, Assembler::kNearJump); |
+ __ addl(EDX, right); |
+ __ jmp(&done, Assembler::kNearJump); |
+ __ Bind(&subtract); |
+ __ subl(EDX, right); |
+ } else if (right_range->IsWithin(0, RangeBoundary::kPlusInfinity)) { |
+ // Right is positive. |
+ __ addl(EDX, right); |
+ } else { |
+ // Right is negative. |
+ __ subl(EDX, right); |
+ } |
+ __ Bind(&done); |
+ |
+ __ SmiTag(EAX); |
+ __ SmiTag(EDX); |
+ __ movl(result1, EAX); |
+ __ movl(result2, EDX); |
+ return; |
+ } |
+ |
+ if (kind() == MergedMath2Instr::kSinCos) { |
+ XmmRegister in = locs()->in(0).fpu_reg(); |
+ ASSERT(locs()->out(0).IsPairLocation()); |
+ PairLocation* pair = locs()->out(0).AsPairLocation(); |
+ XmmRegister out1 = pair->At(0).fpu_reg(); |
+ XmmRegister out2 = pair->At(1).fpu_reg(); |
+ |
+ // Do x87 sincos, since the ia32 compilers may not fuse sin/cos into |
+ // sincos. |
+ __ pushl(EAX); |
+ __ pushl(EAX); |
+ __ movsd(Address(ESP, 0), in); |
+ __ fldl(Address(ESP, 0)); |
+ __ fsincos(); |
+ __ fstpl(Address(ESP, 0)); |
+ __ movsd(out1, Address(ESP, 0)); |
+ __ fstpl(Address(ESP, 0)); |
+ __ movsd(out2, Address(ESP, 0)); |
+ __ addl(ESP, Immediate(2 * kWordSize)); |
+ return; |
+ } |
+ |
+ UNIMPLEMENTED(); |
+} |
+ |
+ |
+LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const { |
+ if (kind() == MergedMathInstr::kTruncDivMod) { |
+ const intptr_t kNumInputs = 2; |
+ const intptr_t kNumTemps = 1; |
+ LocationSummary* summary = |
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
+ // Both inputs must be writable because they will be untagged. |
+ summary->set_in(0, Location::RegisterLocation(EAX)); |
+ summary->set_in(1, Location::WritableRegister()); |
+ summary->set_out(0, Location::RequiresRegister()); |
+ // Will be used for sign extension and division. |
+ summary->set_temp(0, Location::RegisterLocation(EDX)); |
+ return summary; |
+ } |
+ if (kind() == MergedMathInstr::kSinCos) { |
Florian Schneider
2014/04/04 11:52:46
I wonder how much code is actually shared between
Cutch
2014/04/04 16:34:46
Note that this is a clone of MergedMathInstr that
|
+ const intptr_t kNumInputs = 1; |
+ const intptr_t kNumTemps = 0; |
+ LocationSummary* summary = |
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall); |
+ summary->set_in(0, Location::FpuRegisterLocation(XMM1)); |
+ summary->set_out(0, Location::RegisterLocation(EAX)); |
+ return summary; |
+ } |
+ UNIMPLEMENTED(); |
+ return NULL; |
+} |
+ |
+ |
void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
Label* deopt = NULL; |
if (CanDeoptimize()) { |