Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(507)

Unified Diff: src/x64/codegen-x64.cc

Issue 1687014: Port improved ia32 CompareStub to x64. Add framework for inlined floating po... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 10 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/x64/codegen-x64.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/x64/codegen-x64.cc
===================================================================
--- src/x64/codegen-x64.cc (revision 4514)
+++ src/x64/codegen-x64.cc (working copy)
@@ -202,11 +202,21 @@
// Code pattern for loading a floating point value. Input value must
// be either a smi or a heap number object (fp value). Requirements:
// operand in src register. Returns operand as floating point number
- // in XMM register
+ // in XMM register. May destroy src register.
static void LoadFloatOperand(MacroAssembler* masm,
Register src,
XMMRegister dst);
+ // Code pattern for loading a possible number into a XMM register.
+ // If the contents of src is not a number, control branches to
+ // the Label not_number. If contents of src is a smi or a heap number
+ // object (fp value), it is loaded into the XMM register as a double.
+ // The register src is not changed, and src may not be kScratchRegister.
+ static void LoadFloatOperand(MacroAssembler* masm,
+ Register src,
+ XMMRegister dst,
+ Label *not_number);
+
// Code pattern for loading floating point values. Input values must
// be either smi or heap number objects (fp values). Requirements:
// operand_1 in rdx, operand_2 in rax; Returns operands as
@@ -5320,6 +5330,22 @@
}
+// Convert from signed to unsigned comparison to match the way EFLAGS are set
+// by FPU and XMM compare instructions.
+static Condition DoubleCondition(Condition cc) {
+ switch (cc) {
+ case less: return below;
+ case equal: return equal;
+ case less_equal: return below_equal;
+ case greater: return above;
+ case greater_equal: return above_equal;
+ default: UNREACHABLE();
+ }
+ UNREACHABLE();
+ return equal;
+}
+
+
void CodeGenerator::Comparison(AstNode* node,
Condition cc,
bool strict,
@@ -5391,7 +5417,7 @@
left_side = right_side;
right_side = temp;
cc = ReverseCondition(cc);
- // This may reintroduce greater or less_equal as the value of cc.
+ // This may re-introduce greater or less_equal as the value of cc.
// CompareStub and the inline code both support all values of cc.
}
// Implement comparison against a constant Smi, inlining the case
@@ -5434,22 +5460,13 @@
// Jump to builtin for NaN.
not_number.Branch(parity_even, &left_side);
left_side.Unuse();
- Condition double_cc = cc;
- switch (cc) {
- case less: double_cc = below; break;
- case equal: double_cc = equal; break;
- case less_equal: double_cc = below_equal; break;
- case greater: double_cc = above; break;
- case greater_equal: double_cc = above_equal; break;
- default: UNREACHABLE();
- }
- dest->true_target()->Branch(double_cc);
+ dest->true_target()->Branch(DoubleCondition(cc));
dest->false_target()->Jump();
not_number.Bind(&left_side);
}
// Setup and call the compare stub.
- CompareStub stub(cc, strict);
+ CompareStub stub(cc, strict, kCantBothBeNaN);
Result result = frame_->CallStub(&stub, &left_side, &right_side);
result.ToRegister();
__ testq(result.reg(), result.reg());
@@ -5642,17 +5659,34 @@
// If either side is a non-smi constant, skip the smi check.
bool known_non_smi =
(left_side.is_constant() && !left_side.handle()->IsSmi()) ||
- (right_side.is_constant() && !right_side.handle()->IsSmi());
+ (right_side.is_constant() && !right_side.handle()->IsSmi()) ||
+ left_side.type_info().IsDouble() ||
+ right_side.type_info().IsDouble();
NaNInformation nan_info =
(CouldBeNaN(left_side) && CouldBeNaN(right_side)) ?
kBothCouldBeNaN :
kCantBothBeNaN;
+ // Inline number comparison handling any combination of smi's and heap
+ // numbers if:
+ // code is in a loop
+ // the compare operation is different from equal
+ // compare is not a for-loop comparison
+ // The reason for excluding equal is that it will most likely be done
+ // with smi's (not heap numbers) and the code to comparing smi's is inlined
+ // separately. The same reason applies for for-loop comparison which will
+ // also most likely be smi comparisons.
+ bool is_loop_condition = (node->AsExpression() != NULL)
+ && node->AsExpression()->is_loop_condition();
+ bool inline_number_compare =
+ loop_nesting() > 0 && cc != equal && !is_loop_condition;
+
left_side.ToRegister();
right_side.ToRegister();
if (known_non_smi) {
+ // Inlined equality check:
// If at least one of the objects is not NaN, then if the objects
// are identical, they are equal.
if (nan_info == kCantBothBeNaN && cc == equal) {
@@ -5660,8 +5694,15 @@
dest->true_target()->Branch(equal);
}
- // When non-smi, call out to the compare stub.
- CompareStub stub(cc, strict);
+ // Inlined number comparison:
+ if (inline_number_compare) {
+ GenerateInlineNumberComparison(&left_side, &right_side, cc, dest);
+ }
+
+ // Call the compare stub.
+ // TODO(whesse@chromium.org): Enable the inlining flag once
+ // GenerateInlineNumberComparison is implemented.
+ CompareStub stub(cc, strict, nan_info, true || !inline_number_compare);
Result answer = frame_->CallStub(&stub, &left_side, &right_side);
// The result is a Smi, which is negative, zero, or positive.
__ SmiTest(answer.reg()); // Sets both zero and sign flag.
@@ -5679,15 +5720,23 @@
Condition both_smi = masm_->CheckBothSmi(left_reg, right_reg);
is_smi.Branch(both_smi);
- // When non-smi, call out to the compare stub, after inlined checks.
- // If at least one of the objects is not NaN, then if the objects
- // are identical, they are equal.
+
+ // Inline the equality check if both operands can't be a NaN. If both
+ // objects are the same they are equal.
if (nan_info == kCantBothBeNaN && cc == equal) {
__ cmpq(left_side.reg(), right_side.reg());
dest->true_target()->Branch(equal);
}
- CompareStub stub(cc, strict);
+ // Inlined number comparison:
+ if (inline_number_compare) {
+ GenerateInlineNumberComparison(&left_side, &right_side, cc, dest);
+ }
+
+ // Call the compare stub.
+ // TODO(whesse@chromium.org): Enable the inlining flag once
+ // GenerateInlineNumberComparison is implemented.
+ CompareStub stub(cc, strict, nan_info, true || !inline_number_compare);
Result answer = frame_->CallStub(&stub, &left_side, &right_side);
__ SmiTest(answer.reg()); // Sets both zero and sign flags.
answer.Unuse();
@@ -5706,6 +5755,17 @@
}
+void CodeGenerator::GenerateInlineNumberComparison(Result* left_side,
+ Result* right_side,
+ Condition cc,
+ ControlDestination* dest) {
+ ASSERT(left_side->is_register());
+ ASSERT(right_side->is_register());
+ // TODO(whesse@chromium.org): Implement this function, and enable the
+ // corresponding flags in the CompareStub.
+}
+
+
class DeferredInlineBinaryOperation: public DeferredCode {
public:
DeferredInlineBinaryOperation(Token::Value op,
@@ -7781,60 +7841,90 @@
}
+static int NegativeComparisonResult(Condition cc) {
+ ASSERT(cc != equal);
+ ASSERT((cc == less) || (cc == less_equal)
+ || (cc == greater) || (cc == greater_equal));
+ return (cc == greater || cc == greater_equal) ? LESS : GREATER;
+}
+
void CompareStub::Generate(MacroAssembler* masm) {
Label call_builtin, done;
// NOTICE! This code is only reached after a smi-fast-case check, so
// it is certain that at least one operand isn't a smi.
- if (cc_ == equal) { // Both strict and non-strict.
- Label slow; // Fallthrough label.
- // Equality is almost reflexive (everything but NaN), so start by testing
- // for "identity and not NaN".
- {
- Label not_identical;
- __ cmpq(rax, rdx);
- __ j(not_equal, &not_identical);
- // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
- // so we do the second best thing - test it ourselves.
+ // Identical objects can be compared fast, but there are some tricky cases
+ // for NaN and undefined.
+ {
+ Label not_identical;
+ __ cmpq(rax, rdx);
+ __ j(not_equal, &not_identical);
- if (never_nan_nan_) {
- __ xor_(rax, rax);
- __ ret(0);
- } else {
- Label return_equal;
- Label heap_number;
- // If it's not a heap number, then return equal.
- __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
- Factory::heap_number_map());
- __ j(equal, &heap_number);
- __ bind(&return_equal);
- __ xor_(rax, rax);
- __ ret(0);
+ if (cc_ != equal) {
+ // Check for undefined. undefined OP undefined is false even though
+ // undefined == undefined.
+ Label check_for_nan;
+ __ CompareRoot(rdx, Heap::kUndefinedValueRootIndex);
+ __ j(not_equal, &check_for_nan);
+ __ Set(rax, NegativeComparisonResult(cc_));
+ __ ret(0);
+ __ bind(&check_for_nan);
+ }
- __ bind(&heap_number);
- // It is a heap number, so return non-equal if it's NaN and equal if
- // it's not NaN.
- // The representation of NaN values has all exponent bits (52..62) set,
- // and not all mantissa bits (0..51) clear.
- // We only allow QNaNs, which have bit 51 set (which also rules out
- // the value being Infinity).
+ // Test for NaN. Sadly, we can't just compare to Factory::nan_value(),
+ // so we do the second best thing - test it ourselves.
+ // Note: if cc_ != equal, never_nan_nan_ is not used.
+ if (never_nan_nan_ && (cc_ == equal)) {
+ __ Set(rax, EQUAL);
+ __ ret(0);
+ } else {
+ Label return_equal;
+ Label heap_number;
+ // If it's not a heap number, then return equal.
+ __ Cmp(FieldOperand(rdx, HeapObject::kMapOffset),
+ Factory::heap_number_map());
+ __ j(equal, &heap_number);
+ __ bind(&return_equal);
+ __ Set(rax, EQUAL);
+ __ ret(0);
- // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
- // all bits in the mask are set. We only need to check the word
- // that contains the exponent and high bit of the mantissa.
- ASSERT_NE(0, (kQuietNaNHighBitsMask << 1) & 0x80000000u);
- __ movl(rdx, FieldOperand(rdx, HeapNumber::kExponentOffset));
- __ xorl(rax, rax);
- __ addl(rdx, rdx); // Shift value and mask so mask applies to top bits.
- __ cmpl(rdx, Immediate(kQuietNaNHighBitsMask << 1));
+ __ bind(&heap_number);
+ // It is a heap number, so return non-equal if it's NaN and equal if
+ // it's not NaN.
+ // The representation of NaN values has all exponent bits (52..62) set,
+ // and not all mantissa bits (0..51) clear.
+ // We only allow QNaNs, which have bit 51 set (which also rules out
+ // the value being Infinity).
+
+ // Value is a QNaN if value & kQuietNaNMask == kQuietNaNMask, i.e.,
+ // all bits in the mask are set. We only need to check the word
+ // that contains the exponent and high bit of the mantissa.
+ ASSERT_NE(0, (kQuietNaNHighBitsMask << 1) & 0x80000000u);
+ __ movl(rdx, FieldOperand(rdx, HeapNumber::kExponentOffset));
+ __ xorl(rax, rax);
+ __ addl(rdx, rdx); // Shift value and mask so mask applies to top bits.
+ __ cmpl(rdx, Immediate(kQuietNaNHighBitsMask << 1));
+ if (cc_ == equal) {
__ setcc(above_equal, rax);
__ ret(0);
+ } else {
+ Label nan;
+ __ j(above_equal, &nan);
+ __ Set(rax, EQUAL);
+ __ ret(0);
+ __ bind(&nan);
+ __ Set(rax, NegativeComparisonResult(cc_));
+ __ ret(0);
}
-
- __ bind(&not_identical);
}
+ __ bind(&not_identical);
+ }
+
+ if (cc_ == equal) { // Both strict and non-strict.
+ Label slow; // Fallthrough label.
+
// If we're doing a strict equality comparison, we don't have to do
// type conversion, so we generate code to do fast comparison for objects
// and oddballs. Non-smi numbers and strings still go through the usual
@@ -7896,36 +7986,43 @@
__ push(rdx);
__ push(rcx);
- // Inlined floating point compare.
- // Call builtin if operands are not floating point or smi.
- Label check_for_symbols;
- // Push arguments on stack, for helper functions.
- FloatingPointHelper::CheckNumberOperands(masm, &check_for_symbols);
- FloatingPointHelper::LoadFloatOperands(masm, rax, rdx);
- __ FCmp();
+ // Generate the number comparison code.
+ if (include_number_compare_) {
+ Label non_number_comparison;
+ Label unordered;
+ FloatingPointHelper::LoadFloatOperand(masm, rdx, xmm0,
+ &non_number_comparison);
+ FloatingPointHelper::LoadFloatOperand(masm, rax, xmm1,
+ &non_number_comparison);
- // Jump to builtin for NaN.
- __ j(parity_even, &call_builtin);
+ __ comisd(xmm0, xmm1);
- // TODO(1243847): Use cmov below once CpuFeatures are properly hooked up.
- Label below_lbl, above_lbl;
- // use rdx, rax to convert unsigned to signed comparison
- __ j(below, &below_lbl);
- __ j(above, &above_lbl);
+ // Don't base result on EFLAGS when a NaN is involved.
+ __ j(parity_even, &unordered);
+ // Return a result of -1, 0, or 1, based on EFLAGS.
+ __ movq(rax, Immediate(0)); // equal
+ __ movq(rcx, Immediate(1));
+ __ cmovq(above, rax, rcx);
+ __ movq(rcx, Immediate(-1));
+ __ cmovq(below, rax, rcx);
+ __ ret(2 * kPointerSize); // rax, rdx were pushed
- __ xor_(rax, rax); // equal
- __ ret(2 * kPointerSize);
+ // If one of the numbers was NaN, then the result is always false.
+ // The cc is never not-equal.
+ __ bind(&unordered);
+ ASSERT(cc_ != not_equal);
+ if (cc_ == less || cc_ == less_equal) {
+ __ Set(rax, 1);
+ } else {
+ __ Set(rax, -1);
+ }
+ __ ret(2 * kPointerSize); // rax, rdx were pushed
- __ bind(&below_lbl);
- __ movq(rax, Immediate(-1));
- __ ret(2 * kPointerSize);
+ // The number comparison code did not provide a valid result.
+ __ bind(&non_number_comparison);
+ }
- __ bind(&above_lbl);
- __ movq(rax, Immediate(1));
- __ ret(2 * kPointerSize); // rax, rdx were pushed
-
// Fast negative check for symbol-to-symbol equality.
- __ bind(&check_for_symbols);
Label check_for_strings;
if (cc_ == equal) {
BranchIfNonSymbol(masm, &check_for_strings, rax, kScratchRegister);
@@ -7968,14 +8065,7 @@
builtin = strict_ ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
} else {
builtin = Builtins::COMPARE;
- int ncr; // NaN compare result
- if (cc_ == less || cc_ == less_equal) {
- ncr = GREATER;
- } else {
- ASSERT(cc_ == greater || cc_ == greater_equal); // remaining cases
- ncr = LESS;
- }
- __ Push(Smi::FromInt(ncr));
+ __ push(Immediate(NegativeComparisonResult(cc_)));
}
// Restore return address on the stack.
@@ -8764,6 +8854,27 @@
}
+void FloatingPointHelper::LoadFloatOperand(MacroAssembler* masm,
+ Register src,
+ XMMRegister dst,
+ Label* not_number) {
+ Label load_smi, done;
+ ASSERT(!src.is(kScratchRegister));
+ __ JumpIfSmi(src, &load_smi);
+ __ LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex);
+ __ cmpq(FieldOperand(src, HeapObject::kMapOffset), kScratchRegister);
+ __ j(not_equal, not_number);
+ __ movsd(dst, FieldOperand(src, HeapNumber::kValueOffset));
+ __ jmp(&done);
+
+ __ bind(&load_smi);
+ __ SmiToInteger32(kScratchRegister, src);
+ __ cvtlsi2sd(dst, kScratchRegister);
+
+ __ bind(&done);
+}
+
+
void FloatingPointHelper::LoadFloatOperands(MacroAssembler* masm,
XMMRegister dst1,
XMMRegister dst2) {
« no previous file with comments | « src/x64/codegen-x64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698