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

Unified Diff: src/x64/macro-assembler-x64.cc

Issue 196077: X64: Extract all smi operations into MacroAssembler macros. (Closed)
Patch Set: Created 11 years, 3 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
Index: src/x64/macro-assembler-x64.cc
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 104ccb8c155f5e36c04bb550d603fcfcf1c5a6fa..608f49405b5ecf973d64b53800a9699f457907c2 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -412,6 +412,686 @@ void MacroAssembler::Set(const Operand& dst, int64_t x) {
}
+// ----------------------------------------------------------------------------
+// Smi tagging, untagging and tag detection.
+
+
+void MacroAssembler::Integer32ToSmi(Register dst, Register src) {
+ ASSERT_EQ(1, kSmiTagSize);
+ ASSERT_EQ(0, kSmiTag);
+#ifdef DEBUG
+ cmpq(src, Immediate(0xC0000000u));
+ Check(positive, "Smi conversion overflow");
+#endif
+ if (dst.is(src)) {
+ addl(dst, src);
+ } else {
+ lea(dst, Operand(src, src, times_1, 0));
+ }
+}
+
+
+void MacroAssembler::Integer32ToSmi(Register dst,
+ Register src,
+ Label* on_overflow) {
+ ASSERT_EQ(1, kSmiTagSize);
+ ASSERT_EQ(0, kSmiTag);
+ if (!dst.is(src)) {
+ movl(dst, src);
+ }
+ addl(dst, src);
+ j(overflow, on_overflow);
+}
+
+
+void MacroAssembler::Integer64AddToSmi(Register dst,
+ Register src,
+ int constant) {
+#ifdef DEBUG
+ movl(kScratchRegister, src);
+ addl(kScratchRegister, Immediate(constant));
+ Check(no_overflow, "Add-and-smi-convert overflow");
+ Condition valid = CheckInteger32ValidSmiValue(kScratchRegister);
+ Check(valid, "Add-and-smi-convert overflow");
+#endif
+ lea(dst, Operand(src, src, times_1, constant << kSmiTagSize));
+}
+
+
+void MacroAssembler::SmiToInteger32(Register dst, Register src) {
+ ASSERT_EQ(1, kSmiTagSize);
+ ASSERT_EQ(0, kSmiTag);
+ if (!dst.is(src)) {
+ movl(dst, src);
+ }
+ sarl(dst, Immediate(kSmiTagSize));
+}
+
+
+void MacroAssembler::SmiToInteger64(Register dst, Register src) {
+ ASSERT_EQ(1, kSmiTagSize);
+ ASSERT_EQ(0, kSmiTag);
+ movsxlq(dst, src);
+ sar(dst, Immediate(kSmiTagSize));
+}
+
+
+void MacroAssembler::PositiveSmiTimesPowerOfTwoToInteger64(Register dst,
+ Register src,
+ int power) {
+ ASSERT(power >= 0);
+ ASSERT(power < 64);
+ if (power == 0) {
+ SmiToInteger64(dst, src);
+ return;
+ }
+ shl(dst, Immediate(power - 1));
+}
+
+void MacroAssembler::JumpIfSmi(Register src, Label* on_smi) {
+ ASSERT_EQ(0, kSmiTag);
+ testl(src, Immediate(kSmiTagMask));
+ j(zero, on_smi);
+}
+
+
+void MacroAssembler::JumpIfNotSmi(Register src, Label* on_not_smi) {
+ Condition not_smi = CheckNotSmi(src);
+ j(not_smi, on_not_smi);
+}
+
+
+void MacroAssembler::JumpIfNotPositiveSmi(Register src,
+ Label* on_not_positive_smi) {
+ Condition not_positive_smi = CheckNotPositiveSmi(src);
+ j(not_positive_smi, on_not_positive_smi);
+}
+
+
+void MacroAssembler::JumpIfSmiEqualsConstant(Register src,
+ int constant,
+ Label* on_equals) {
+ if (Smi::IsValid(constant)) {
+ Condition are_equal = CheckSmiEqualsConstant(src, constant);
+ j(are_equal, on_equals);
+ }
+}
+
+
+void MacroAssembler::JumpIfNotValidSmiValue(Register src, Label* on_invalid) {
+ Condition is_valid = CheckInteger32ValidSmiValue(src);
+ j(ReverseCondition(is_valid), on_invalid);
+}
+
+
+
+void MacroAssembler::JumpIfNotBothSmi(Register src1,
+ Register src2,
+ Label* on_not_both_smi) {
+ Condition not_both_smi = CheckNotBothSmi(src1, src2);
+ j(not_both_smi, on_not_both_smi);
+}
+
+Condition MacroAssembler::CheckSmi(Register src) {
+ testb(src, Immediate(kSmiTagMask));
+ return zero;
+}
+
+
+Condition MacroAssembler::CheckNotSmi(Register src) {
+ ASSERT_EQ(0, kSmiTag);
+ testb(src, Immediate(kSmiTagMask));
+ return not_zero;
+}
+
+
+Condition MacroAssembler::CheckPositiveSmi(Register src) {
+ ASSERT_EQ(0, kSmiTag);
+ testl(src, Immediate(static_cast<uint32_t>(0x80000000u | kSmiTagMask)));
+ return zero;
+}
+
+
+Condition MacroAssembler::CheckNotPositiveSmi(Register src) {
+ ASSERT_EQ(0, kSmiTag);
+ testl(src, Immediate(static_cast<uint32_t>(0x80000000u | kSmiTagMask)));
+ return not_zero;
+}
+
+
+Condition MacroAssembler::CheckBothSmi(Register first, Register second) {
+ if (first.is(second)) {
+ return CheckSmi(first);
+ }
+ movl(kScratchRegister, first);
+ orl(kScratchRegister, second);
+ return CheckSmi(kScratchRegister);
+}
+
+
+Condition MacroAssembler::CheckNotBothSmi(Register first, Register second) {
+ ASSERT_EQ(0, kSmiTag);
+ if (first.is(second)) {
+ return CheckNotSmi(first);
+ }
+ movl(kScratchRegister, first);
+ or_(kScratchRegister, second);
+ return CheckNotSmi(kScratchRegister);
+}
+
+
+Condition MacroAssembler::CheckIsMinSmi(Register src) {
+ ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
+ cmpl(src, Immediate(0x40000000));
+ return equal;
+}
+
+Condition MacroAssembler::CheckSmiEqualsConstant(Register src, int constant) {
+ if (constant == 0) {
+ testl(src, src);
+ return zero;
+ }
+ if (Smi::IsValid(constant)) {
+ cmpl(src, Immediate(Smi::FromInt(constant)));
+ return zero;
+ }
+ // Can't be equal.
+ UNREACHABLE();
+ return no_condition;
+}
+
+
+Condition MacroAssembler::CheckInteger32ValidSmiValue(Register src) {
+ // A 32-bit integer value can be converted to a smi if it is in the
+ // range [-2^30 .. 2^30-1]. That is equivalent to having its 32-bit
+ // representation have bits 30 and 31 be equal.
+ cmpl(src, Immediate(0xC0000000u));
+ return positive;
+}
+
+
+void MacroAssembler::SmiNeg(Register dst,
+ Register src,
+ Label* on_not_smi_result) {
+ if (!dst.is(src)) {
+ movl(dst, src);
+ }
+ negl(dst);
+ testl(dst, Immediate(0x7fffffff));
+ // If the result is zero or 0x80000000, negation failed to create a smi.
+ j(equal, on_not_smi_result);
+}
+
+
+void MacroAssembler::SmiAdd(Register dst,
+ Register src1,
+ Register src2,
+ Label* on_not_smi_result) {
+ ASSERT(!dst.is(src2));
+ if (!dst.is(src1)) {
+ movl(dst, src1);
+ }
+ addl(dst, src2);
+ if (!dst.is(src1)) {
+ j(overflow, on_not_smi_result);
+ } else {
+ Label smi_result;
+ j(no_overflow, &smi_result);
+ // Restore src1.
+ subl(src1, src2);
+ jmp(on_not_smi_result);
+ bind(&smi_result);
+ }
+}
+
+
+
+void MacroAssembler::SmiSub(Register dst,
+ Register src1,
+ Register src2,
+ Label* on_not_smi_result) {
+ ASSERT(!dst.is(src2));
+ if (!dst.is(src1)) {
+ movl(dst, src1);
+ }
+ subl(dst, src2);
+ if (!dst.is(src1)) {
+ j(overflow, on_not_smi_result);
+ } else {
+ Label smi_result;
+ j(no_overflow, &smi_result);
+ // Restore src1.
+ addl(src1, src2);
+ jmp(on_not_smi_result);
+ bind(&smi_result);
+ }
+}
+
+
+void MacroAssembler::SmiMul(Register dst,
+ Register src1,
+ Register src2,
+ Label* on_not_smi_result) {
+ ASSERT(!dst.is(src2));
+
+ if (dst.is(src1)) {
+ movq(kScratchRegister, src1);
+ }
+ SmiToInteger32(dst, src1);
+
+ imull(dst, src2);
+ j(overflow, on_not_smi_result);
+
+ // Check for negative zero result. If product is zero, and one
+ // argument is negative, go to slow case. The frame is unchanged
+ // in this block, so local control flow can use a Label rather
+ // than a JumpTarget.
+ Label non_zero_result;
+ testl(dst, dst);
+ j(not_zero, &non_zero_result);
+
+ // Test whether either operand is negative (the other must be zero).
+ orl(kScratchRegister, src2);
+ j(negative, on_not_smi_result);
+ bind(&non_zero_result);
+}
+
+
+void MacroAssembler::SmiTryAddConstant(Register dst,
+ Register src,
+ int32_t constant,
+ Label* on_not_smi_result) {
+ // Does not assume that src is a smi.
+ ASSERT_EQ(1, kSmiTagMask);
+ ASSERT_EQ(0, kSmiTag);
+ ASSERT(Smi::IsValid(constant));
+
+ Register tmp = (src.is(dst) ? kScratchRegister : dst);
+ movl(tmp, src);
+ addl(tmp, Immediate(Smi::FromInt(constant)));
+ if (tmp.is(kScratchRegister)) {
+ j(overflow, on_not_smi_result);
+ testl(tmp, Immediate(kSmiTagMask));
+ j(not_zero, on_not_smi_result);
+ movl(dst, tmp);
+ } else {
+ movl(kScratchRegister, Immediate(kSmiTagMask));
+ cmovl(overflow, dst, kScratchRegister);
+ testl(dst, kScratchRegister);
+ j(not_zero, on_not_smi_result);
+ }
+}
+
+
+void MacroAssembler::SmiAddConstant(Register dst,
+ Register src,
+ int32_t constant,
+ Label* on_not_smi_result) {
+ ASSERT(Smi::IsValid(constant));
+ if (on_not_smi_result == NULL) {
+ if (dst.is(src)) {
+ movl(dst, src);
+ } else {
+ lea(dst, Operand(src, constant << kSmiTagSize));
+ }
+ } else {
+ if (!dst.is(src)) {
+ movl(dst, src);
+ }
+ addl(dst, Immediate(Smi::FromInt(constant)));
+ if (!dst.is(src)) {
+ j(overflow, on_not_smi_result);
+ } else {
+ Label result_ok;
+ j(no_overflow, &result_ok);
+ subl(dst, Immediate(Smi::FromInt(constant)));
+ jmp(on_not_smi_result);
+ bind(&result_ok);
+ }
+ }
+}
+
+
+void MacroAssembler::SmiSubConstant(Register dst,
+ Register src,
+ int32_t constant,
+ Label* on_not_smi_result) {
+ ASSERT(Smi::IsValid(constant));
+ Smi* smi_value = Smi::FromInt(constant);
+ if (dst.is(src)) {
+ // Optimistic subtract - may change value of dst register,
+ // if it has garbage bits in the higher half, but will not change
+ // the value as a tagged smi.
+ subl(dst, Immediate(smi_value));
+ if (on_not_smi_result != NULL) {
+ Label add_success;
+ j(no_overflow, &add_success);
+ addl(dst, Immediate(smi_value));
+ jmp(on_not_smi_result);
+ bind(&add_success);
+ }
+ } else {
+ UNIMPLEMENTED(); // Not used yet.
+ }
+}
+
+
+void MacroAssembler::SmiDiv(Register dst,
+ Register src1,
+ Register src2,
+ Label* on_not_smi_result) {
+ ASSERT(!src2.is(rax));
+ ASSERT(!src2.is(rdx));
+ ASSERT(!src1.is(rdx));
+
+ // Check for 0 divisor (result is +/-Infinity).
+ Label positive_divisor;
+ testl(src2, src2);
+ j(zero, on_not_smi_result);
+ j(positive, &positive_divisor);
+ // Check for negative zero result. If the dividend is zero, and the
+ // divisor is negative, return a floating point negative zero.
+ testl(src1, src1);
+ j(zero, on_not_smi_result);
+ bind (&positive_divisor);
+
+ // Sign extend src1 into edx:eax.
+ if (!src1.is(rax)) {
+ movl(rax, src1);
+ }
+ cdq();
+
+ idivl(src2);
+ // Check for the corner case of dividing the most negative smi by
+ // -1. We cannot use the overflow flag, since it is not set by
+ // idiv instruction.
+ ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
+ cmpl(rax, Immediate(0x40000000));
+ j(equal, on_not_smi_result);
+ // Check that the remainder is zero.
+ testl(rdx, rdx);
+ j(not_zero, on_not_smi_result);
+ // Tag the result and store it in the destination register.
+ Integer32ToSmi(dst, rax);
+}
+
+
+void MacroAssembler::SmiMod(Register dst,
+ Register src1,
+ Register src2,
+ Label* on_not_smi_result) {
+ ASSERT(!dst.is(kScratchRegister));
+ ASSERT(!src1.is(kScratchRegister));
+ ASSERT(!src2.is(kScratchRegister));
+ ASSERT(!src2.is(rax));
+ ASSERT(!src2.is(rdx));
+ ASSERT(!src1.is(rdx));
+
+ testl(src2, src2);
+ j(zero, on_not_smi_result);
+
+ if (src1.is(rax)) {
+ // Mist remember the value to see if a zero result should
+ // be a negative zero.
+ movl(kScratchRegister, rax);
+ } else {
+ movl(rax, src1);
+ }
+ // Sign extend eax into edx:eax.
+ cdq();
+ idivl(src2);
+ // Check for a negative zero result. If the result is zero, and the
+ // dividend is negative, return a floating point negative zero.
+ Label non_zero_result;
+ testl(rdx, rdx);
+ j(not_zero, &non_zero_result);
+ if (src1.is(rax)) {
+ testl(kScratchRegister, kScratchRegister);
+ } else {
+ testl(src1, src1);
+ }
+ j(negative, on_not_smi_result);
+ bind(&non_zero_result);
+ if (!dst.is(rdx)) {
+ movl(dst, rdx);
+ }
+}
+
+
+void MacroAssembler::SmiNot(Register dst, Register src) {
+ if (dst.is(src)) {
+ not_(dst);
+ // Remove inverted smi-tag. The mask is sign-extended to 64 bits.
+ xor_(src, Immediate(kSmiTagMask));
+ } else {
+ ASSERT_EQ(0, kSmiTag);
+ lea(dst, Operand(src, kSmiTagMask));
+ not_(dst);
+ }
+}
+
+
+void MacroAssembler::SmiAnd(Register dst, Register src1, Register src2) {
+ if (!dst.is(src1)) {
+ movl(dst, src1);
+ }
+ and_(dst, src2);
+}
+
+
+void MacroAssembler::SmiAndConstant(Register dst, Register src, int constant) {
+ ASSERT(Smi::IsValid(constant));
+ if (!dst.is(src)) {
+ movl(dst, src);
+ }
+ and_(dst, Immediate(Smi::FromInt(constant)));
+}
+
+
+void MacroAssembler::SmiOr(Register dst, Register src1, Register src2) {
+ if (!dst.is(src1)) {
+ movl(dst, src1);
+ }
+ or_(dst, src2);
+}
+
+
+void MacroAssembler::SmiOrConstant(Register dst, Register src, int constant) {
+ ASSERT(Smi::IsValid(constant));
+ if (!dst.is(src)) {
+ movl(dst, src);
+ }
+ or_(dst, Immediate(Smi::FromInt(constant)));
+}
+
+void MacroAssembler::SmiXor(Register dst, Register src1, Register src2) {
+ if (!dst.is(src1)) {
+ movl(dst, src1);
+ }
+ xor_(dst, src2);
+}
+
+
+void MacroAssembler::SmiXorConstant(Register dst, Register src, int constant) {
+ ASSERT(Smi::IsValid(constant));
+ if (!dst.is(src)) {
+ movl(dst, src);
+ }
+ xor_(dst, Immediate(Smi::FromInt(constant)));
+}
+
+
+
+void MacroAssembler::SmiShiftArithmeticRightConstant(Register dst,
+ Register src,
+ int shift_value) {
+ if (shift_value > 0) {
+ if (dst.is(src)) {
+ sarl(dst, Immediate(shift_value));
+ and_(dst, Immediate(~kSmiTagMask));
+ } else {
+ UNIMPLEMENTED(); // Not used.
+ }
+ }
+}
+
+
+void MacroAssembler::SmiShiftLogicRightConstant(Register dst,
+ Register src,
+ int shift_value,
+ Label* on_not_smi_result) {
+ // Logic right shift interprets its result as an *unsigned* number.
+ if (dst.is(src)) {
+ UNIMPLEMENTED(); // Not used.
+ } else {
+ movl(dst, src);
+ // Untag the smi.
+ sarl(dst, Immediate(kSmiTagSize));
+ if (shift_value < 2) {
+ // A negative Smi shifted right two is in the positive Smi range,
+ // but if shifted only by zero or one, it never is.
+ j(negative, on_not_smi_result);
+ }
+ if (shift_value > 0) {
+ // Do the right shift on the integer value.
+ shrl(dst, Immediate(shift_value));
+ }
+ // Re-tag the result.
+ addl(dst, dst);
+ }
+}
+
+
+void MacroAssembler::SmiShiftLeftConstant(Register dst,
+ Register src,
+ int shift_value,
+ Label* on_not_smi_result) {
+ if (dst.is(src)) {
+ UNIMPLEMENTED(); // Not used.
+ } else {
+ movl(dst, src);
+ if (shift_value > 0) {
+ // Treat dst as an untagged integer value equal to two times the
+ // smi value of src, i.e., already shifted left by one.
+ if (shift_value > 1) {
+ shll(dst, Immediate(shift_value - 1));
+ }
+ // Convert int result to Smi, checking that it is in smi range.
+ ASSERT(kSmiTagSize == 1); // adjust code if not the case
+ Integer32ToSmi(dst, dst, on_not_smi_result);
+ }
+ }
+}
+
+
+void MacroAssembler::SmiShiftLeft(Register dst,
+ Register src1,
+ Register src2,
+ Label* on_not_smi_result) {
+ ASSERT(!dst.is(rcx));
+ Label result_ok;
+ // Untag both operands.
+ SmiToInteger32(dst, src1);
+ SmiToInteger32(rcx, src2);
+ shll(dst);
+ // Check that the *signed* result fits in a smi.
+ Condition is_valid = CheckInteger32ValidSmiValue(dst);
+ j(is_valid, &result_ok);
+ // Restore the relevant bits of the source registers
+ // and call the slow version.
+ if (dst.is(src1)) {
+ shrl(dst);
+ Integer32ToSmi(dst, dst);
+ }
+ Integer32ToSmi(rcx, rcx);
+ jmp(on_not_smi_result);
+ bind(&result_ok);
+ Integer32ToSmi(dst, dst);
+}
+
+
+void MacroAssembler::SmiShiftLogicRight(Register dst,
+ Register src1,
+ Register src2,
+ Label* on_not_smi_result) {
+ ASSERT(!dst.is(rcx));
+ Label result_ok;
+ // Untag both operands.
+ SmiToInteger32(dst, src1);
+ SmiToInteger32(rcx, src2);
+
+ shrl(dst);
+ // Check that the *unsigned* result fits in a smi.
+ // I.e., that it is a valid positive smi value. The positive smi
+ // values are 0..0x3fffffff, i.e., neither of the top-most two
+ // bits can be set.
+ //
+ // These two cases can only happen with shifts by 0 or 1 when
+ // handed a valid smi. If the answer cannot be represented by a
+ // smi, restore the left and right arguments, and jump to slow
+ // case. The low bit of the left argument may be lost, but only
+ // in a case where it is dropped anyway.
+ testl(dst, Immediate(0xc0000000));
+ j(zero, &result_ok);
+ if (dst.is(src1)) {
+ shll(dst);
+ Integer32ToSmi(dst, dst);
+ }
+ Integer32ToSmi(rcx, rcx);
+ jmp(on_not_smi_result);
+ bind(&result_ok);
+ // Smi-tag the result in answer.
+ Integer32ToSmi(dst, dst);
+}
+
+
+void MacroAssembler::SmiShiftArithmeticRight(Register dst,
+ Register src1,
+ Register src2) {
+ ASSERT(!dst.is(rcx));
+ // Untag both operands.
+ SmiToInteger32(dst, src1);
+ SmiToInteger32(rcx, src2);
+ // Shift as integer.
+ sarl(dst);
+ // Retag result.
+ Integer32ToSmi(dst, dst);
+}
+
+
+void MacroAssembler::SelectNonSmi(Register dst,
+ Register src1,
+ Register src2,
+ Label* on_not_smis) {
+ ASSERT(!dst.is(src1));
+ ASSERT(!dst.is(src2));
+ // Both operands must not be smis.
+#ifdef DEBUG
+ Condition not_both_smis = CheckNotBothSmi(src1, src2);
+ Check(not_both_smis, "Both registers were smis.");
+#endif
+ ASSERT_EQ(0, kSmiTag);
+ ASSERT_EQ(0, Smi::FromInt(0));
+ movq(kScratchRegister, Immediate(kSmiTagMask));
+ and_(kScratchRegister, src1);
+ testl(kScratchRegister, src2);
+ j(not_zero, on_not_smis);
+ // One operand is a smi.
+
+ ASSERT_EQ(1, static_cast<int>(kSmiTagMask));
+ // kScratchRegister still holds src1 & kSmiTag, which is either zero or one.
+ subq(kScratchRegister, Immediate(1));
+ // If src1 is a smi, then scratch register all 1s, else it is all 0s.
+ movq(dst, src1);
+ xor_(dst, src2);
+ and_(dst, kScratchRegister);
+ // If src1 is a smi, dst holds src1 ^ src2, else it is zero.
+ xor_(dst, src1);
+ // If src1 is a smi, dst is src2, else it is src1, i.e., a non-smi.
+}
+
+
+
bool MacroAssembler::IsUnsafeSmi(Smi* value) {
return false;
}

Powered by Google App Engine
This is Rietveld 408576698