break;
}
case Token::ADD:
- __ AdduAndCheckForOverflow(v0, left, right, scratch1);
+ __ DadduAndCheckForOverflow(v0, left, right, scratch1);
__ BranchOnOverflow(&stub_call, scratch1);
break;
case Token::SUB:
- __ SubuAndCheckForOverflow(v0, left, right, scratch1);
+ __ DsubuAndCheckForOverflow(v0, left, right, scratch1);
__ BranchOnOverflow(&stub_call, scratch1);
break;
case Token::MUL: {
__ lbu(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
__ JumpIfInstanceTypeIsNotSequentialOneByte(scratch1, scratch2, &bailout);
__ ld(scratch1, FieldMemOperand(string, SeqOneByteString::kLengthOffset));
- __ AdduAndCheckForOverflow(string_length, string_length, scratch1, scratch3);
+ __ DadduAndCheckForOverflow(string_length, string_length, scratch1, scratch3);
__ BranchOnOverflow(&bailout, scratch3);
__ Branch(&loop, lt, element, Operand(elements_end));
Register scratch1 = a1;
Register scratch2 = a4;
__ li(scratch1, Operand(Smi::FromInt(count_value)));
- __ AdduAndCheckForOverflow(v0, v0, scratch1, scratch2);
+ __ DadduAndCheckForOverflow(v0, v0, scratch1, scratch2);
__ BranchOnNoOverflow(&done, scratch2);
// Call stub. Undo operation first.
__ Move(v0, a0);
}
-void LCodeGen::DoMulI(LMulI* instr) {
+void LCodeGen::DoMulS(LMulS* instr) {
Register scratch = scratch0();
Register result = ToRegister(instr->result());
// Note that result may alias left.
switch (constant) {
case -1:
if (overflow) {
- __ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
- DeoptimizeIf(gt, instr, Deoptimizer::kOverflow, scratch,
- Operand(kMaxInt));
+ __ DsubuAndCheckForOverflow(result, zero_reg, left, scratch);
+ DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, scratch,
+ Operand(zero_reg));
} else {
__ Dsubu(result, zero_reg, left);
}
__ dsll(scratch, left, shift);
__ Daddu(result, scratch, left);
// Correct the sign of the result if the constant is negative.
- if (constant < 0) __ Dsubu(result, zero_reg, result);
+ if (constant < 0) __ Dsubu(result, zero_reg, result);
} else if (base::bits::IsPowerOfTwo32(constant_abs + 1)) {
int32_t shift = WhichPowerOf2(constant_abs + 1);
__ dsll(scratch, left, shift);
__ Dsubu(result, scratch, left);
// Correct the sign of the result if the constant is negative.
- if (constant < 0) __ Dsubu(result, zero_reg, result);
+ if (constant < 0) __ Dsubu(result, zero_reg, result);
} else {
// Generate standard code.
__ li(at, constant);
__ Dmul(result, left, at);
}
}
+ } else {
+ DCHECK(right_op->IsRegister());
+ Register right = ToRegister(right_op);
+
+ if (overflow) {
+ // hi:lo = left * right.
+ __ Dmulh(result, left, right);
+ __ dsra32(scratch, result, 0);
+ __ sra(at, result, 31);
+ __ SmiTag(result);
+ DeoptimizeIf(ne, instr, Deoptimizer::kOverflow, scratch, Operand(at));
+ } else {
+ __ SmiUntag(result, left);
+ __ dmul(result, result, right);
+ }
+
+ if (bailout_on_minus_zero) {
+ Label done;
+ __ Xor(at, left, right);
+ __ Branch(&done, ge, at, Operand(zero_reg));
+ // Bail out if the result is minus zero.
+ DeoptimizeIf(eq, instr, Deoptimizer::kMinusZero, result,
+ Operand(zero_reg));
+ __ bind(&done);
+ }
+ }
+}
+
+
+void LCodeGen::DoMulI(LMulI* instr) {
+ Register scratch = scratch0();
+ Register result = ToRegister(instr->result());
+ // Note that result may alias left.
+ Register left = ToRegister(instr->left());
+ LOperand* right_op = instr->right();
+
+ bool bailout_on_minus_zero =
+ instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
+ bool overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+
+ if (right_op->IsConstantOperand()) {
+ int32_t constant = ToInteger32(LConstantOperand::cast(right_op));
+
+ if (bailout_on_minus_zero && (constant < 0)) {
+ // The case of a null constant will be handled separately.
+ // If constant is negative and left is null, the result should be -0.
+ DeoptimizeIf(eq, instr, Deoptimizer::kMinusZero, left, Operand(zero_reg));
+ }
+
+ switch (constant) {
+ case -1:
+ if (overflow) {
+ __ SubuAndCheckForOverflow(result, zero_reg, left, scratch);
+ DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, scratch,
+ Operand(zero_reg));
+ } else {
+ __ Subu(result, zero_reg, left);
+ }
+ break;
+ case 0:
+ if (bailout_on_minus_zero) {
+ // If left is strictly negative and the constant is null, the
+ // result is -0. Deoptimize if required, otherwise return 0.
+ DeoptimizeIf(lt, instr, Deoptimizer::kMinusZero, left,
+ Operand(zero_reg));
+ }
+ __ mov(result, zero_reg);
+ break;
+ case 1:
+ // Nothing to do.
+ __ Move(result, left);
+ break;
+ default:
+ // Multiplying by powers of two and powers of two plus or minus
+ // one can be done faster with shifted operands.
+ // For other constants we emit standard code.
+ int32_t mask = constant >> 31;
+ uint32_t constant_abs = (constant + mask) ^ mask;
+
+ if (base::bits::IsPowerOfTwo32(constant_abs)) {
+ int32_t shift = WhichPowerOf2(constant_abs);
+ __ sll(result, left, shift);
+ // Correct the sign of the result if the constant is negative.
+ if (constant < 0) __ Subu(result, zero_reg, result);
+ } else if (base::bits::IsPowerOfTwo32(constant_abs - 1)) {
+ int32_t shift = WhichPowerOf2(constant_abs - 1);
+ __ sll(scratch, left, shift);
+ __ addu(result, scratch, left);
+ // Correct the sign of the result if the constant is negative.
+ if (constant < 0) __ Subu(result, zero_reg, result);
+ } else if (base::bits::IsPowerOfTwo32(constant_abs + 1)) {
+ int32_t shift = WhichPowerOf2(constant_abs + 1);
+ __ sll(scratch, left, shift);
+ __ Subu(result, scratch, left);
+ // Correct the sign of the result if the constant is negative.
+ if (constant < 0) __ Subu(result, zero_reg, result);
+ } else {
+ // Generate standard code.
+ __ li(at, constant);
+ __ Mul(result, left, at);
+ }
+ }
} else {
DCHECK(right_op->IsRegister());
if (overflow) {
// hi:lo = left * right.
- if (instr->hydrogen()->representation().IsSmi()) {
- __ Dmulh(result, left, right);
- } else {
- __ Dmul(result, left, right);
- }
+ __ Dmul(result, left, right);
__ dsra32(scratch, result, 0);
__ sra(at, result, 31);
- if (instr->hydrogen()->representation().IsSmi()) {
- __ SmiTag(result);
- }
+
DeoptimizeIf(ne, instr, Deoptimizer::kOverflow, scratch, Operand(at));
} else {
- if (instr->hydrogen()->representation().IsSmi()) {
- __ SmiUntag(result, left);
- __ Dmul(result, result, right);
- } else {
- __ Dmul(result, left, right);
- }
+ __ mul(result, left, right);
}
if (bailout_on_minus_zero) {
}
+void LCodeGen::DoSubS(LSubS* instr) {
+ LOperand* left = instr->left();
+ LOperand* right = instr->right();
+ LOperand* result = instr->result();
+ bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+
+ if (!can_overflow) {
+ DCHECK(right->IsRegister() || right->IsConstantOperand());
+ __ Dsubu(ToRegister(result), ToRegister(left), ToOperand(right));
+ } else { // can_overflow.
+ Register overflow = scratch0();
+ Register scratch = scratch1();
+ DCHECK(right->IsRegister() || right->IsConstantOperand());
+ __ DsubuAndCheckForOverflow(ToRegister(result), ToRegister(left),
+ ToOperand(right), overflow, scratch);
+ DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, overflow,
+ Operand(zero_reg));
+ }
+}
+
+
void LCodeGen::DoSubI(LSubI* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
if (!can_overflow) {
- if (right->IsStackSlot()) {
- Register right_reg = EmitLoadRegister(right, at);
- __ Dsubu(ToRegister(result), ToRegister(left), Operand(right_reg));
- } else {
- DCHECK(right->IsRegister() || right->IsConstantOperand());
- __ Dsubu(ToRegister(result), ToRegister(left), ToOperand(right));
- }
+ DCHECK(right->IsRegister() || right->IsConstantOperand());
+ __ Subu(ToRegister(result), ToRegister(left), ToOperand(right));
} else { // can_overflow.
Register overflow = scratch0();
Register scratch = scratch1();
- if (right->IsStackSlot() || right->IsConstantOperand()) {
- Register right_reg = EmitLoadRegister(right, scratch);
- __ SubuAndCheckForOverflow(ToRegister(result),
- ToRegister(left),
- right_reg,
- overflow); // Reg at also used as scratch.
- } else {
- DCHECK(right->IsRegister());
- // Due to overflow check macros not supporting constant operands,
- // handling the IsConstantOperand case was moved to prev if clause.
- __ SubuAndCheckForOverflow(ToRegister(result),
- ToRegister(left),
- ToRegister(right),
- overflow); // Reg at also used as scratch.
- }
+ DCHECK(right->IsRegister() || right->IsConstantOperand());
+ __ SubuAndCheckForOverflow(ToRegister(result), ToRegister(left),
+ ToOperand(right), overflow, scratch);
DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, overflow,
Operand(zero_reg));
- if (!instr->hydrogen()->representation().IsSmi()) {
- DeoptimizeIf(gt, instr, Deoptimizer::kOverflow, ToRegister(result),
- Operand(kMaxInt));
- DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, ToRegister(result),
- Operand(kMinInt));
- }
}
}
}
-void LCodeGen::DoAddI(LAddI* instr) {
+void LCodeGen::DoAddS(LAddS* instr) {
LOperand* left = instr->left();
LOperand* right = instr->right();
LOperand* result = instr->result();
} else { // can_overflow.
Register overflow = scratch0();
Register scratch = scratch1();
- if (right->IsConstantOperand()) {
- Register right_reg = EmitLoadRegister(right, scratch);
- __ AdduAndCheckForOverflow(ToRegister(result),
- ToRegister(left),
- right_reg,
- overflow); // Reg at also used as scratch.
- } else {
- DCHECK(right->IsRegister());
- // Due to overflow check macros not supporting constant operands,
- // handling the IsConstantOperand case was moved to prev if clause.
- __ AdduAndCheckForOverflow(ToRegister(result),
- ToRegister(left),
- ToRegister(right),
- overflow); // Reg at also used as scratch.
- }
+ DCHECK(right->IsRegister() || right->IsConstantOperand());
+ __ DadduAndCheckForOverflow(ToRegister(result), ToRegister(left),
+ ToOperand(right), overflow, scratch);
+ DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, overflow,
+ Operand(zero_reg));
+ }
+}
+
+
+void LCodeGen::DoAddI(LAddI* instr) {
+ LOperand* left = instr->left();
+ LOperand* right = instr->right();
+ LOperand* result = instr->result();
+ bool can_overflow = instr->hydrogen()->CheckFlag(HValue::kCanOverflow);
+
+ if (!can_overflow) {
+ DCHECK(right->IsRegister() || right->IsConstantOperand());
+ __ Addu(ToRegister(result), ToRegister(left), ToOperand(right));
+ } else { // can_overflow.
+ Register overflow = scratch0();
+ Register scratch = scratch1();
+ DCHECK(right->IsRegister() || right->IsConstantOperand());
+ __ AdduAndCheckForOverflow(ToRegister(result), ToRegister(left),
+ ToOperand(right), overflow, scratch);
DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, overflow,
Operand(zero_reg));
- // if not smi, it must int32.
- if (!instr->hydrogen()->representation().IsSmi()) {
- DeoptimizeIf(gt, instr, Deoptimizer::kOverflow, ToRegister(result),
- Operand(kMaxInt));
- DeoptimizeIf(lt, instr, Deoptimizer::kOverflow, ToRegister(result),
- Operand(kMinInt));
- }
}
}
}
right_op = UseRegister(right);
}
- LMulI* mul = new(zone()) LMulI(left_op, right_op);
+ LInstruction* result =
+ instr->representation().IsSmi()
+ ? DefineAsRegister(new (zone()) LMulS(left_op, right_op))
+ : DefineAsRegister(new (zone()) LMulI(left_op, right_op));
if (right_op->IsConstantOperand()
? ((can_overflow && constant_value == -1) ||
(bailout_on_minus_zero && constant_value <= 0))
: (can_overflow || bailout_on_minus_zero)) {
- AssignEnvironment(mul);
+ AssignEnvironment(result);
}
- return DefineAsRegister(mul);
+ return result;
} else if (instr->representation().IsDouble()) {
if (kArchVariant == kMips64r2) {
DCHECK(instr->left()->representation().Equals(instr->representation()));
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->left());
- LOperand* right = UseOrConstantAtStart(instr->right());
- LSubI* sub = new(zone()) LSubI(left, right);
- LInstruction* result = DefineAsRegister(sub);
+ LOperand* right = UseRegisterOrConstantAtStart(instr->right());
+ LInstruction* result =
+ instr->representation().IsSmi()
+ ? DefineAsRegister(new (zone()) LSubS(left, right))
+ : DefineAsRegister(new (zone()) LSubI(left, right));
if (instr->CheckFlag(HValue::kCanOverflow)) {
result = AssignEnvironment(result);
}
DCHECK(instr->right()->representation().Equals(instr->representation()));
LOperand* left = UseRegisterAtStart(instr->BetterLeftOperand());
LOperand* right = UseRegisterOrConstantAtStart(instr->BetterRightOperand());
- LAddI* add = new(zone()) LAddI(left, right);
- LInstruction* result = DefineAsRegister(add);
+ LInstruction* result =
+ instr->representation().IsSmi()
+ ? DefineAsRegister(new (zone()) LAddS(left, right))
+ : DefineAsRegister(new (zone()) LAddI(left, right));
if (instr->CheckFlag(HValue::kCanOverflow)) {
result = AssignEnvironment(result);
}
#define LITHIUM_CONCRETE_INSTRUCTION_LIST(V) \
V(AccessArgumentsAt) \
- V(AddI) \
V(AddE) \
+ V(AddI) \
+ V(AddS) \
V(Allocate) \
V(AllocateBlockContext) \
V(ApplyArguments) \
V(ModByPowerOf2I) \
V(ModI) \
V(MulI) \
+ V(MulS) \
V(MultiplyAddD) \
V(NumberTagD) \
V(NumberTagU) \
V(StringCharFromCode) \
V(StringCompareAndBranch) \
V(SubI) \
+ V(SubS) \
V(TaggedToI) \
V(ThisFunction) \
V(ToFastProperties) \
};
+class LMulS final : public LTemplateInstruction<1, 2, 0> {
+ public:
+ LMulS(LOperand* left, LOperand* right) {
+ inputs_[0] = left;
+ inputs_[1] = right;
+ }
+
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MulS, "mul-s")
+ DECLARE_HYDROGEN_ACCESSOR(Mul)
+};
+
+
class LMulI final : public LTemplateInstruction<1, 2, 0> {
public:
LMulI(LOperand* left, LOperand* right) {
};
+class LSubS final : public LTemplateInstruction<1, 2, 0> {
+ public:
+ LSubS(LOperand* left, LOperand* right) {
+ inputs_[0] = left;
+ inputs_[1] = right;
+ }
+
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(SubS, "sub-s")
+ DECLARE_HYDROGEN_ACCESSOR(Sub)
+};
+
+
class LConstantI final : public LTemplateInstruction<1, 0, 0> {
public:
DECLARE_CONCRETE_INSTRUCTION(ConstantI, "constant-i")
};
+class LAddS final : public LTemplateInstruction<1, 2, 0> {
+ public:
+ LAddS(LOperand* left, LOperand* right) {
+ inputs_[0] = left;
+ inputs_[1] = right;
+ }
+
+ LOperand* left() { return inputs_[0]; }
+ LOperand* right() { return inputs_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(AddS, "add-s")
+ DECLARE_HYDROGEN_ACCESSOR(Add)
+};
+
+
class LMathMinMax final : public LTemplateInstruction<1, 2, 0> {
public:
LMathMinMax(LOperand* left, LOperand* right) {
void MacroAssembler::SmiToDoubleFPURegister(Register smi,
FPURegister value,
Register scratch1) {
- // dsra(scratch1, smi, kSmiTagSize);
dsra32(scratch1, smi, 0);
mtc1(scratch1, value);
cvt_d_w(value, value);
AdduAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
} else {
if (dst.is(left)) {
+ li(t9, right); // Load right.
mov(scratch, left); // Preserve left.
- daddiu(dst, left,
- static_cast<int32_t>(right.immediate())); // Left is overwritten.
+ addu(dst, left, t9); // Left is overwritten.
xor_(scratch, dst, scratch); // Original left.
- // Load right since xori takes uint16 as immediate.
- daddiu(t9, zero_reg, static_cast<int32_t>(right.immediate()));
xor_(overflow_dst, dst, t9);
and_(overflow_dst, overflow_dst, scratch);
} else {
- daddiu(dst, left, static_cast<int32_t>(right.immediate()));
+ li(t9, right);
+ addu(dst, left, t9);
xor_(overflow_dst, dst, left);
- // Load right since xori takes uint16 as immediate.
- daddiu(t9, zero_reg, static_cast<int32_t>(right.immediate()));
xor_(scratch, dst, t9);
and_(overflow_dst, scratch, overflow_dst);
}
}
-void MacroAssembler::AdduAndCheckForOverflow(Register dst,
- Register left,
+void MacroAssembler::AdduAndCheckForOverflow(Register dst, Register left,
Register right,
Register overflow_dst,
Register scratch) {
}
if (dst.is(left)) {
+ mov(scratch, left); // Preserve left.
+ addu(dst, left, right); // Left is overwritten.
+ xor_(scratch, dst, scratch); // Original left.
+ xor_(overflow_dst, dst, right);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else if (dst.is(right)) {
+ mov(scratch, right); // Preserve right.
+ addu(dst, left, right); // Right is overwritten.
+ xor_(scratch, dst, scratch); // Original right.
+ xor_(overflow_dst, dst, left);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else {
+ addu(dst, left, right);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, dst, right);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+}
+
+
+void MacroAssembler::DadduAndCheckForOverflow(Register dst, Register left,
+ const Operand& right,
+ Register overflow_dst,
+ Register scratch) {
+ if (right.is_reg()) {
+ DadduAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+ } else {
+ if (dst.is(left)) {
+ li(t9, right); // Load right.
+ mov(scratch, left); // Preserve left.
+ daddu(dst, left, t9); // Left is overwritten.
+ xor_(scratch, dst, scratch); // Original left.
+ xor_(overflow_dst, dst, t9);
+ and_(overflow_dst, overflow_dst, scratch);
+ } else {
+ li(t9, right); // Load right.
+ Daddu(dst, left, t9);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, dst, t9);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+ }
+}
+
+
+void MacroAssembler::DadduAndCheckForOverflow(Register dst, Register left,
+ Register right,
+ Register overflow_dst,
+ Register scratch) {
+ DCHECK(!dst.is(overflow_dst));
+ DCHECK(!dst.is(scratch));
+ DCHECK(!overflow_dst.is(scratch));
+ DCHECK(!overflow_dst.is(left));
+ DCHECK(!overflow_dst.is(right));
+
+ if (left.is(right) && dst.is(left)) {
+ DCHECK(!dst.is(t9));
+ DCHECK(!scratch.is(t9));
+ DCHECK(!left.is(t9));
+ DCHECK(!right.is(t9));
+ DCHECK(!overflow_dst.is(t9));
+ mov(t9, right);
+ right = t9;
+ }
+
+ if (dst.is(left)) {
mov(scratch, left); // Preserve left.
daddu(dst, left, right); // Left is overwritten.
xor_(scratch, dst, scratch); // Original left.
SubuAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
} else {
if (dst.is(left)) {
+ li(t9, right); // Load right.
mov(scratch, left); // Preserve left.
- daddiu(dst, left,
- static_cast<int32_t>(-right.immediate())); // Left is overwritten.
+ Subu(dst, left, t9); // Left is overwritten.
xor_(overflow_dst, dst, scratch); // scratch is original left.
- // Load right since xori takes uint16 as immediate.
- daddiu(t9, zero_reg, static_cast<int32_t>(right.immediate()));
xor_(scratch, scratch, t9); // scratch is original left.
and_(overflow_dst, scratch, overflow_dst);
} else {
- daddiu(dst, left, static_cast<int32_t>(-right.immediate()));
+ li(t9, right);
+ subu(dst, left, t9);
xor_(overflow_dst, dst, left);
- // Load right since xori takes uint16 as immediate.
- daddiu(t9, zero_reg, static_cast<int32_t>(right.immediate()));
xor_(scratch, left, t9);
and_(overflow_dst, scratch, overflow_dst);
}
}
-void MacroAssembler::SubuAndCheckForOverflow(Register dst,
- Register left,
+void MacroAssembler::SubuAndCheckForOverflow(Register dst, Register left,
Register right,
Register overflow_dst,
Register scratch) {
}
if (dst.is(left)) {
+ mov(scratch, left); // Preserve left.
+ subu(dst, left, right); // Left is overwritten.
+ xor_(overflow_dst, dst, scratch); // scratch is original left.
+ xor_(scratch, scratch, right); // scratch is original left.
+ and_(overflow_dst, scratch, overflow_dst);
+ } else if (dst.is(right)) {
+ mov(scratch, right); // Preserve right.
+ subu(dst, left, right); // Right is overwritten.
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, left, scratch); // Original right.
+ and_(overflow_dst, scratch, overflow_dst);
+ } else {
+ subu(dst, left, right);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, left, right);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+}
+
+
+void MacroAssembler::DsubuAndCheckForOverflow(Register dst, Register left,
+ const Operand& right,
+ Register overflow_dst,
+ Register scratch) {
+ if (right.is_reg()) {
+ DsubuAndCheckForOverflow(dst, left, right.rm(), overflow_dst, scratch);
+ } else {
+ if (dst.is(left)) {
+ li(t9, right); // Load right.
+ mov(scratch, left); // Preserve left.
+ dsubu(dst, left, t9); // Left is overwritten.
+ xor_(overflow_dst, dst, scratch); // scratch is original left.
+ xor_(scratch, scratch, t9); // scratch is original left.
+ and_(overflow_dst, scratch, overflow_dst);
+ } else {
+ li(t9, right);
+ dsubu(dst, left, t9);
+ xor_(overflow_dst, dst, left);
+ xor_(scratch, left, t9);
+ and_(overflow_dst, scratch, overflow_dst);
+ }
+ }
+}
+
+
+void MacroAssembler::DsubuAndCheckForOverflow(Register dst, Register left,
+ Register right,
+ Register overflow_dst,
+ Register scratch) {
+ DCHECK(!dst.is(overflow_dst));
+ DCHECK(!dst.is(scratch));
+ DCHECK(!overflow_dst.is(scratch));
+ DCHECK(!overflow_dst.is(left));
+ DCHECK(!overflow_dst.is(right));
+ DCHECK(!scratch.is(left));
+ DCHECK(!scratch.is(right));
+
+ // This happens with some crankshaft code. Since Subu works fine if
+ // left == right, let's not make that restriction here.
+ if (left.is(right)) {
+ mov(dst, zero_reg);
+ mov(overflow_dst, zero_reg);
+ return;
+ }
+
+ if (dst.is(left)) {
mov(scratch, left); // Preserve left.
dsubu(dst, left, right); // Left is overwritten.
xor_(overflow_dst, dst, scratch); // scratch is original left.
}
}
-
void MacroAssembler::CallRuntime(const Runtime::Function* f,
int num_arguments,
SaveFPRegsMode save_doubles) {
void AdduAndCheckForOverflow(Register dst, Register left,
const Operand& right, Register overflow_dst,
- Register scratch = at);
+ Register scratch);
void SubuAndCheckForOverflow(Register dst,
Register left,
void SubuAndCheckForOverflow(Register dst, Register left,
const Operand& right, Register overflow_dst,
- Register scratch = at);
+ Register scratch);
+
+ void DadduAndCheckForOverflow(Register dst, Register left, Register right,
+ Register overflow_dst, Register scratch = at);
+
+ void DadduAndCheckForOverflow(Register dst, Register left,
+ const Operand& right, Register overflow_dst,
+ Register scratch);
+
+ void DsubuAndCheckForOverflow(Register dst, Register left, Register right,
+ Register overflow_dst, Register scratch = at);
+
+ void DsubuAndCheckForOverflow(Register dst, Register left,
+ const Operand& right, Register overflow_dst,
+ Register scratch);
void BranchOnOverflow(Label* label,
Register overflow_check,