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

Unified Diff: runtime/vm/intrinsifier_x64.cc

Issue 10704192: Implement the remaining methods in intrinsifier_x64.cc (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 5 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 | « runtime/vm/intrinsifier_ia32.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/intrinsifier_x64.cc
===================================================================
--- runtime/vm/intrinsifier_x64.cc (revision 9596)
+++ runtime/vm/intrinsifier_x64.cc (working copy)
@@ -677,6 +677,34 @@
bool Intrinsifier::Integer_shl(Assembler* assembler) {
+ ASSERT(kSmiTagShift == 1);
+ ASSERT(kSmiTag == 0);
+ Label fall_through, overflow;
+ TestBothArgumentsSmis(assembler, &fall_through);
+ // Shift value is in RAX. Compare with tagged Smi.
+ __ cmpq(RAX, Immediate(Smi::RawValue(Smi::kBits)));
+ __ j(ABOVE_EQUAL, &fall_through, Assembler::kNearJump);
+
+ __ SmiUntag(RAX);
+ __ movq(RCX, RAX); // Shift amount must be in RCX.
+ __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Value.
+
+ // Overflow test - all the shifted-out bits must be same as the sign bit.
+ __ movq(RDI, RAX);
+ __ shlq(RAX, RCX);
+ __ sarq(RAX, RCX);
+ __ cmpq(RAX, RDI);
+ __ j(NOT_EQUAL, &overflow, Assembler::kNearJump);
+
+ __ shlq(RAX, RCX); // Shift for result now we know there is no overflow.
+
+ // RAX is a correctly tagged Smi.
+ __ ret();
+
+ __ Bind(&overflow);
+ // Mint is rarely used on x64 (only for integers requiring 64 bit instead of
+ // 63 bits as represented by Smi).
+ __ Bind(&fall_through);
return false;
}
@@ -725,7 +753,56 @@
}
+// This is called for Smi, Mint and Bigint receivers. The right argument
+// can be Smi, Mint, Bigint or double.
bool Intrinsifier::Integer_equalToInteger(Assembler* assembler) {
+ Label fall_through, true_label, check_for_mint;
+ const Bool& bool_true = Bool::ZoneHandle(Bool::True());
+ const Bool& bool_false = Bool::ZoneHandle(Bool::False());
+ // For integer receiver '===' check first.
+ __ movq(RAX, Address(RSP, + 1 * kWordSize));
+ __ movq(RCX, Address(RSP, + 2 * kWordSize));
+ __ cmpq(RAX, RCX);
+ __ j(EQUAL, &true_label, Assembler::kNearJump);
+ __ orq(RAX, RCX);
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &check_for_mint, Assembler::kNearJump);
+ // Both arguments are smi, '===' is good enough.
+ __ LoadObject(RAX, bool_false);
+ __ ret();
+ __ Bind(&true_label);
+ __ LoadObject(RAX, bool_true);
+ __ ret();
+
+ // At least one of the arguments was not Smi.
+ Label receiver_not_smi;
+ __ Bind(&check_for_mint);
+ __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Receiver.
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &receiver_not_smi);
+
+ // Left (receiver) is Smi, return false if right is not Double.
+ // Note that an instance of Mint or Bigint never contains a value that can be
+ // represented by Smi.
+ __ movq(RAX, Address(RSP, + 1 * kWordSize));
+ __ CompareClassId(RAX, kDouble);
+ __ j(EQUAL, &fall_through);
+ __ LoadObject(RAX, bool_false);
+ __ ret();
+
+ __ Bind(&receiver_not_smi);
+ // RAX:: receiver.
+ __ CompareClassId(RAX, kMint);
+ __ j(NOT_EQUAL, &fall_through);
+ // Receiver is Mint, return false if right is Smi.
+ __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Right argument.
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &fall_through);
+ __ LoadObject(RAX, bool_false); // Smi == Mint -> false.
+ __ ret();
+ // TODO(srdjan): Implement Mint == Mint comparison.
+
+ __ Bind(&fall_through);
return false;
}
@@ -736,37 +813,111 @@
bool Intrinsifier::Integer_sar(Assembler* assembler) {
+ Label fall_through, shift_count_ok;
+ TestBothArgumentsSmis(assembler, &fall_through);
+ Immediate count_limit = Immediate(0x3F);
+ // Check that the count is not larger than what the hardware can handle.
+ // For shifting right a Smi the result is the same for all numbers
+ // >= count_limit.
+ __ SmiUntag(RAX);
+ // Negative counts throw exception.
+ __ cmpq(RAX, Immediate(0));
+ __ j(LESS, &fall_through, Assembler::kNearJump);
+ __ cmpq(RAX, count_limit);
+ __ j(LESS_EQUAL, &shift_count_ok, Assembler::kNearJump);
+ __ movq(RAX, count_limit);
+ __ Bind(&shift_count_ok);
+ __ movq(RCX, RAX); // Shift amount must be in RCX.
+ __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Value.
+ __ SmiUntag(RAX); // Value.
+ __ sarq(RAX, RCX);
+ __ SmiTag(RAX);
+ __ ret();
+ __ Bind(&fall_through);
return false;
}
+// Argument is Smi (receiver).
bool Intrinsifier::Smi_bitNegate(Assembler* assembler) {
+ __ movq(RAX, Address(RSP, + 1 * kWordSize)); // Index.
+ __ notq(RAX);
+ __ andq(RAX, Immediate(~kSmiTagMask)); // Remove inverted smi-tag.
+ __ ret();
+ return true;
+}
+
+
+// Check if the last argument is a double, jump to label 'is_smi' if smi
+// (easy to convert to double), otherwise jump to label 'not_double_smi',
+// Returns the last argument in RAX.
+static void TestLastArgumentIsDouble(Assembler* assembler,
+ Label* is_smi,
+ Label* not_double_smi) {
+ __ movq(RAX, Address(RSP, + 1 * kWordSize));
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi.
+ __ CompareClassId(RAX, kDouble);
+ __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump);
+ // Fall through if double.
+}
+
+
+// Both arguments on stack, left argument is a double, right argument is of
+// unknown type. Return true or false object in RAX. Any NaN argument
+// returns false. Any non-double argument causes control flow to fall through
+// to the slow case (compiled method body).
+static bool CompareDoubles(Assembler* assembler, Condition true_condition) {
+ const Bool& bool_true = Bool::ZoneHandle(Bool::True());
+ const Bool& bool_false = Bool::ZoneHandle(Bool::False());
+ Label fall_through, is_false, is_true, is_smi, double_op;
+ TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
+ // Both arguments are double, right operand is in RAX.
+ __ movsd(XMM1, FieldAddress(RAX, Double::value_offset()));
+ __ Bind(&double_op);
+ __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument.
+ __ movsd(XMM0, FieldAddress(RAX, Double::value_offset()));
+ __ comisd(XMM0, XMM1);
+ __ j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN -> false;
+ __ j(true_condition, &is_true, Assembler::kNearJump);
+ // Fall through false.
+ __ Bind(&is_false);
+ __ LoadObject(RAX, bool_false);
+ __ ret();
+ __ Bind(&is_true);
+ __ LoadObject(RAX, bool_true);
+ __ ret();
+ __ Bind(&is_smi);
+ __ SmiUntag(RAX);
+ __ cvtsi2sd(XMM1, RAX);
+ __ jmp(&double_op);
+ __ Bind(&fall_through);
return false;
}
bool Intrinsifier::Double_greaterThan(Assembler* assembler) {
- return false;
+ return CompareDoubles(assembler, ABOVE);
}
bool Intrinsifier::Double_greaterEqualThan(Assembler* assembler) {
- return false;
+ return CompareDoubles(assembler, ABOVE_EQUAL);
}
bool Intrinsifier::Double_lessThan(Assembler* assembler) {
- return false;
+ return CompareDoubles(assembler, BELOW);
}
bool Intrinsifier::Double_equal(Assembler* assembler) {
- return false;
+ return CompareDoubles(assembler, EQUAL);
}
bool Intrinsifier::Double_lessEqualThan(Assembler* assembler) {
- return false;
+ return CompareDoubles(assembler, BELOW_EQUAL);
}
@@ -779,32 +930,99 @@
return true;
}
-bool Intrinsifier::Double_add(Assembler* assembler) {
+
+// Expects left argument to be double (receiver). Right argument is unknown.
+// Both arguments are on stack.
+static bool DoubleArithmeticOperations(Assembler* assembler, Token::Kind kind) {
+ Label fall_through;
+ TestLastArgumentIsDouble(assembler, &fall_through, &fall_through);
+ // Both arguments are double, right operand is in RAX.
+ __ movsd(XMM1, FieldAddress(RAX, Double::value_offset()));
+ __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left argument.
+ __ movsd(XMM0, FieldAddress(RAX, Double::value_offset()));
+ switch (kind) {
+ case Token::kADD: __ addsd(XMM0, XMM1); break;
+ case Token::kSUB: __ subsd(XMM0, XMM1); break;
+ case Token::kMUL: __ mulsd(XMM0, XMM1); break;
+ case Token::kDIV: __ divsd(XMM0, XMM1); break;
+ default: UNREACHABLE();
+ }
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ AssemblerMacros::TryAllocate(assembler,
+ double_class,
+ &fall_through,
+ RAX); // Result register.
+ __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
+ __ ret();
+ __ Bind(&fall_through);
return false;
}
+bool Intrinsifier::Double_add(Assembler* assembler) {
+ return DoubleArithmeticOperations(assembler, Token::kADD);
+}
+
+
bool Intrinsifier::Double_mul(Assembler* assembler) {
- return false;
+ return DoubleArithmeticOperations(assembler, Token::kMUL);
}
bool Intrinsifier::Double_sub(Assembler* assembler) {
- return false;
+ return DoubleArithmeticOperations(assembler, Token::kSUB);
}
bool Intrinsifier::Double_div(Assembler* assembler) {
- return false;
+ return DoubleArithmeticOperations(assembler, Token::kDIV);
}
bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) {
+ Label fall_through;
+ // Only Smi-s allowed.
+ __ movq(RAX, Address(RSP, + 1 * kWordSize));
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
+ // Is Smi.
+ __ SmiUntag(RAX);
+ __ cvtsi2sd(XMM1, RAX);
+ __ movq(RAX, Address(RSP, + 2 * kWordSize));
+ __ movsd(XMM0, FieldAddress(RAX, Double::value_offset()));
+ __ mulsd(XMM0, XMM1);
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ AssemblerMacros::TryAllocate(assembler,
+ double_class,
+ &fall_through,
+ RAX); // Result register.
+ __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
+ __ ret();
+ __ Bind(&fall_through);
return false;
}
+// Left is double right is integer (Bigint, Mint or Smi)
bool Intrinsifier::Double_fromInteger(Assembler* assembler) {
+ Label fall_through;
+ __ movq(RAX, Address(RSP, +1 * kWordSize));
+ __ testq(RAX, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &fall_through, Assembler::kNearJump);
+ // Is Smi.
+ __ SmiUntag(RAX);
+ __ cvtsi2sd(XMM0, RAX);
+ const Class& double_class = Class::Handle(
+ Isolate::Current()->object_store()->double_class());
+ AssemblerMacros::TryAllocate(assembler,
+ double_class,
+ &fall_through,
+ RAX); // Result register.
+ __ movsd(FieldAddress(RAX, Double::value_offset()), XMM0);
+ __ ret();
+ __ Bind(&fall_through);
return false;
}
@@ -853,26 +1071,12 @@
}
-// Check if the last argument is a double, jump to label 'is_smi' if smi
-// (easy to convert to double), otherwise jump to label 'not_double_smi',
-// Returns the last argument in RAX.
-static void TestLastArgumentIsDouble(Assembler* assembler,
- Label* is_smi,
- Label* not_double_smi) {
- __ movq(RAX, Address(RSP, + 1 * kWordSize));
- __ testq(RAX, Immediate(kSmiTagMask));
- __ j(ZERO, is_smi, Assembler::kNearJump); // Jump if Smi.
- __ CompareClassId(RAX, kDouble);
- __ j(NOT_EQUAL, not_double_smi, Assembler::kNearJump);
- // Fall through if double.
-}
-
-
enum TrigonometricFunctions {
kSine,
kCosine,
};
+
static void EmitTrigonometric(Assembler* assembler,
TrigonometricFunctions kind) {
Label fall_through, is_smi, double_op;
« no previous file with comments | « runtime/vm/intrinsifier_ia32.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698