Commit a453a3ce authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

ARM: Add multiplication and modulus to the type recording binary operation stub.

For now the smi part only handles power of two right hand side operands.

Fixed a bug when loading floating point value into core registers with VFP supported.
Review URL: http://codereview.chromium.org/6312059

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6560 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 72b1d0c7
...@@ -389,7 +389,7 @@ class FloatingPointHelper : public AllStatic { ...@@ -389,7 +389,7 @@ class FloatingPointHelper : public AllStatic {
// floating point registers VFP3 must be supported. If core registers are // floating point registers VFP3 must be supported. If core registers are
// requested when VFP3 is supported d6 and d7 will still be scratched. If // requested when VFP3 is supported d6 and d7 will still be scratched. If
// either r0 or r1 is not a number (not smi and not heap number object) the // either r0 or r1 is not a number (not smi and not heap number object) the
// not_number label is jumped to. // not_number label is jumped to with r0 and r1 intact.
static void LoadOperands(MacroAssembler* masm, static void LoadOperands(MacroAssembler* masm,
FloatingPointHelper::Destination destination, FloatingPointHelper::Destination destination,
Register heap_number_map, Register heap_number_map,
...@@ -417,11 +417,11 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm, ...@@ -417,11 +417,11 @@ void FloatingPointHelper::LoadSmis(MacroAssembler* masm,
if (CpuFeatures::IsSupported(VFP3)) { if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3); CpuFeatures::Scope scope(VFP3);
__ mov(scratch1, Operand(r0, ASR, kSmiTagSize)); __ mov(scratch1, Operand(r0, ASR, kSmiTagSize));
__ vmov(s15, scratch1); __ vmov(d7.high(), scratch1);
__ vcvt_f64_s32(d7, s15); __ vcvt_f64_s32(d7, d7.high());
__ mov(scratch1, Operand(r1, ASR, kSmiTagSize)); __ mov(scratch1, Operand(r1, ASR, kSmiTagSize));
__ vmov(s13, scratch1); __ vmov(d6.high(), scratch1);
__ vcvt_f64_s32(d6, s13); __ vcvt_f64_s32(d6, d6.high());
if (destination == kCoreRegisters) { if (destination == kCoreRegisters) {
__ vmov(r2, r3, d7); __ vmov(r2, r3, d7);
__ vmov(r0, r1, d6); __ vmov(r0, r1, d6);
...@@ -476,7 +476,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm, ...@@ -476,7 +476,7 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
__ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number); __ JumpIfNotHeapNumber(object, heap_number_map, scratch1, not_number);
// Handle loading a double from a heap number. // Handle loading a double from a heap number.
if (CpuFeatures::IsSupported(VFP3)) { if (CpuFeatures::IsSupported(VFP3) && destination == kVFPRegisters) {
CpuFeatures::Scope scope(VFP3); CpuFeatures::Scope scope(VFP3);
// Load the double from tagged HeapNumber to double register. // Load the double from tagged HeapNumber to double register.
__ sub(scratch1, object, Operand(kHeapObjectTag)); __ sub(scratch1, object, Operand(kHeapObjectTag));
...@@ -492,16 +492,17 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm, ...@@ -492,16 +492,17 @@ void FloatingPointHelper::LoadNumber(MacroAssembler* masm,
__ bind(&is_smi); __ bind(&is_smi);
if (CpuFeatures::IsSupported(VFP3)) { if (CpuFeatures::IsSupported(VFP3)) {
CpuFeatures::Scope scope(VFP3); CpuFeatures::Scope scope(VFP3);
// Convert smi to double. // Convert smi to double using VFP instructions.
__ SmiUntag(scratch1, object); __ SmiUntag(scratch1, object);
__ vmov(dst.high(), scratch1); __ vmov(dst.high(), scratch1);
__ vcvt_f64_s32(dst, dst.high()); __ vcvt_f64_s32(dst, dst.high());
if (destination == kCoreRegisters) { if (destination == kCoreRegisters) {
// Load the converted smi to dst1 and dst2 in double format.
__ vmov(dst1, dst2, dst); __ vmov(dst1, dst2, dst);
} }
} else { } else {
ASSERT(destination == kCoreRegisters); ASSERT(destination == kCoreRegisters);
// Write Smi to dst1 and dst2 double format. // Write smi to dst1 and dst2 double format.
__ mov(scratch1, Operand(object)); __ mov(scratch1, Operand(object));
ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2); ConvertToDoubleStub stub(dst2, dst1, scratch1, scratch2);
__ push(lr); __ push(lr);
...@@ -2501,6 +2502,33 @@ void TypeRecordingBinaryOpStub::GenerateSmiSmiOperation( ...@@ -2501,6 +2502,33 @@ void TypeRecordingBinaryOpStub::GenerateSmiSmiOperation(
// We fall through here if we multiplied a negative number with 0, because // We fall through here if we multiplied a negative number with 0, because
// that would mean we should produce -0. // that would mean we should produce -0.
break; break;
case Token::DIV:
// Check for power of two on the right hand side.
__ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result);
// Check for positive and no remainder (scratch1 contains right - 1).
__ orr(scratch2, scratch1, Operand(0x80000000u));
__ tst(left, scratch2);
__ b(ne, &not_smi_result);
// Perform division by shifting.
__ CountLeadingZeros(scratch1, scratch1, scratch2);
__ rsb(scratch1, scratch1, Operand(31));
__ mov(right, Operand(left, LSR, scratch1));
__ Ret();
break;
case Token::MOD:
// Check for two positive smis.
__ orr(scratch1, left, Operand(right));
__ tst(scratch1, Operand(0x80000000u | kSmiTagMask));
__ b(ne, &not_smi_result);
// Check for power of two on the right hand side.
__ JumpIfNotPowerOfTwoOrZero(right, scratch1, &not_smi_result);
// Perform modulus by masking.
__ and_(right, left, Operand(scratch1));
__ Ret();
break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -2520,6 +2548,9 @@ void TypeRecordingBinaryOpStub::GenerateVFPOperation( ...@@ -2520,6 +2548,9 @@ void TypeRecordingBinaryOpStub::GenerateVFPOperation(
case Token::MUL: case Token::MUL:
__ vmul(d5, d6, d7); __ vmul(d5, d6, d7);
break; break;
case Token::DIV:
__ vdiv(d5, d6, d7);
break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
...@@ -2535,7 +2566,11 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, ...@@ -2535,7 +2566,11 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
SmiCodeGenerateHeapNumberResults allow_heapnumber_results) { SmiCodeGenerateHeapNumberResults allow_heapnumber_results) {
Label not_smis; Label not_smis;
ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); ASSERT(op_ == Token::ADD ||
op_ == Token::SUB ||
op_ == Token::MUL ||
op_ == Token::DIV ||
op_ == Token::MOD);
Register left = r1; Register left = r1;
Register right = r0; Register right = r0;
...@@ -2548,13 +2583,14 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, ...@@ -2548,13 +2583,14 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
__ tst(scratch1, Operand(kSmiTagMask)); __ tst(scratch1, Operand(kSmiTagMask));
__ b(ne, &not_smis); __ b(ne, &not_smis);
// If the smi-smi operation results in a smi return is generated.
GenerateSmiSmiOperation(masm); GenerateSmiSmiOperation(masm);
// If heap number results are possible generate the result in an allocated // If heap number results are possible generate the result in an allocated
// heap number. // heap number.
if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) { if (allow_heapnumber_results == ALLOW_HEAPNUMBER_RESULTS) {
FloatingPointHelper::Destination destination = FloatingPointHelper::Destination destination =
CpuFeatures::IsSupported(VFP3) && Token::MOD != op_ ? CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ?
FloatingPointHelper::kVFPRegisters : FloatingPointHelper::kVFPRegisters :
FloatingPointHelper::kCoreRegisters; FloatingPointHelper::kCoreRegisters;
...@@ -2562,9 +2598,9 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, ...@@ -2562,9 +2598,9 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
// Allocate new heap number for result. // Allocate new heap number for result.
Register heap_number = r5; Register result = r5;
__ AllocateHeapNumber( __ AllocateHeapNumber(
heap_number, scratch1, scratch2, heap_number_map, gc_required); result, scratch1, scratch2, heap_number_map, gc_required);
// Load the smis. // Load the smis.
FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2); FloatingPointHelper::LoadSmis(masm, destination, scratch1, scratch2);
...@@ -2577,7 +2613,7 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, ...@@ -2577,7 +2613,7 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
CpuFeatures::Scope scope(VFP3); CpuFeatures::Scope scope(VFP3);
GenerateVFPOperation(masm); GenerateVFPOperation(masm);
__ sub(r0, heap_number, Operand(kHeapObjectTag)); __ sub(r0, result, Operand(kHeapObjectTag));
__ vstr(d5, r0, HeapNumber::kValueOffset); __ vstr(d5, r0, HeapNumber::kValueOffset);
__ add(r0, r0, Operand(kHeapObjectTag)); __ add(r0, r0, Operand(kHeapObjectTag));
__ Ret(); __ Ret();
...@@ -2598,13 +2634,13 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, ...@@ -2598,13 +2634,13 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
// Double returned in fp coprocessor register 0 and 1, encoded as // Double returned in fp coprocessor register 0 and 1, encoded as
// register cr8. Offsets must be divisible by 4 for coprocessor so we // register cr8. Offsets must be divisible by 4 for coprocessor so we
// need to substract the tag from r5. // need to substract the tag from r5.
__ sub(scratch1, heap_number, Operand(kHeapObjectTag)); __ sub(scratch1, result, Operand(kHeapObjectTag));
__ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset));
#else #else
// Double returned in registers 0 and 1. // Double returned in registers 0 and 1.
__ Strd(r0, r1, FieldMemOperand(heap_number, HeapNumber::kValueOffset)); __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset));
#endif #endif
__ mov(r0, Operand(heap_number)); __ mov(r0, Operand(result));
// And we are done. // And we are done.
__ pop(pc); __ pop(pc);
} }
...@@ -2616,7 +2652,11 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm, ...@@ -2616,7 +2652,11 @@ void TypeRecordingBinaryOpStub::GenerateSmiCode(MacroAssembler* masm,
void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateSmiStub(MacroAssembler* masm) {
Label not_smis, call_runtime; Label not_smis, call_runtime;
ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); ASSERT(op_ == Token::ADD ||
op_ == Token::SUB ||
op_ == Token::MUL ||
op_ == Token::DIV ||
op_ == Token::MOD);
if (result_type_ == TRBinaryOpIC::UNINITIALIZED || if (result_type_ == TRBinaryOpIC::UNINITIALIZED ||
result_type_ == TRBinaryOpIC::SMI) { result_type_ == TRBinaryOpIC::SMI) {
...@@ -2648,7 +2688,11 @@ void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) { ...@@ -2648,7 +2688,11 @@ void TypeRecordingBinaryOpStub::GenerateStringStub(MacroAssembler* masm) {
void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); ASSERT(op_ == Token::ADD ||
op_ == Token::SUB ||
op_ == Token::MUL ||
op_ == Token::DIV ||
op_ == Token::MOD);
ASSERT(operands_type_ == TRBinaryOpIC::INT32); ASSERT(operands_type_ == TRBinaryOpIC::INT32);
...@@ -2657,7 +2701,11 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) { ...@@ -2657,7 +2701,11 @@ void TypeRecordingBinaryOpStub::GenerateInt32Stub(MacroAssembler* masm) {
void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); ASSERT(op_ == Token::ADD ||
op_ == Token::SUB ||
op_ == Token::MUL ||
op_ == Token::DIV ||
op_ == Token::MOD);
Register scratch1 = r7; Register scratch1 = r7;
Register scratch2 = r9; Register scratch2 = r9;
...@@ -2668,10 +2716,17 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { ...@@ -2668,10 +2716,17 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
Register heap_number_map = r6; Register heap_number_map = r6;
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex); __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
// Get a heap number object for the result - might be left or right if one
// of these are overwritable. Uses a callee-save register to keep the value
// across the C call which we might use below.
Register result = r5;
GenerateHeapResultAllocation(
masm, result, heap_number_map, scratch1, scratch2, &call_runtime);
// Load left and right operands into d6 and d7 or r0/r1 and r2/r3 depending on // Load left and right operands into d6 and d7 or r0/r1 and r2/r3 depending on
// whether VFP3 is available. // whether VFP3 is available.
FloatingPointHelper::Destination destination = FloatingPointHelper::Destination destination =
CpuFeatures::IsSupported(VFP3) ? CpuFeatures::IsSupported(VFP3) && op_ != Token::MOD ?
FloatingPointHelper::kVFPRegisters : FloatingPointHelper::kVFPRegisters :
FloatingPointHelper::kCoreRegisters; FloatingPointHelper::kCoreRegisters;
FloatingPointHelper::LoadOperands(masm, FloatingPointHelper::LoadOperands(masm,
...@@ -2685,13 +2740,8 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { ...@@ -2685,13 +2740,8 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
CpuFeatures::Scope scope(VFP3); CpuFeatures::Scope scope(VFP3);
GenerateVFPOperation(masm); GenerateVFPOperation(masm);
// Get a heap number object for the result - might be left or right if one
// of these are overwritable.
GenerateHeapResultAllocation(
masm, r4, heap_number_map, scratch1, scratch2, &call_runtime);
// Fill the result into the allocated heap number and return. // Fill the result into the allocated heap number and return.
__ sub(r0, r4, Operand(kHeapObjectTag)); __ sub(r0, result, Operand(kHeapObjectTag));
__ vstr(d5, r0, HeapNumber::kValueOffset); __ vstr(d5, r0, HeapNumber::kValueOffset);
__ add(r0, r0, Operand(kHeapObjectTag)); __ add(r0, r0, Operand(kHeapObjectTag));
__ Ret(); __ Ret();
...@@ -2701,30 +2751,23 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { ...@@ -2701,30 +2751,23 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
// r0/r1: Left operand // r0/r1: Left operand
// r2/r3: Right operand // r2/r3: Right operand
// Get a heap number object for the result - might be left or right if one
// of these are overwritable. Uses a callee-save register to keep the value
// across the c call.
GenerateHeapResultAllocation(
masm, r4, heap_number_map, scratch1, scratch2, &call_runtime);
__ push(lr); // For returning later (no GC after this point). __ push(lr); // For returning later (no GC after this point).
__ PrepareCallCFunction(4, scratch1); // Two doubles count as 4 arguments. __ PrepareCallCFunction(4, scratch1); // Two doubles count as 4 arguments.
// Call C routine that may not cause GC or other trouble. r4 is callee // Call C routine that may not cause GC or other trouble. result (r5) is
// saved. // callee saved.
__ CallCFunction(ExternalReference::double_fp_operation(op_), 4); __ CallCFunction(ExternalReference::double_fp_operation(op_), 4);
// Fill the result into the allocated heap number. // Fill the result into the allocated heap number.
#if !defined(USE_ARM_EABI) #if !defined(USE_ARM_EABI)
// Double returned in fp coprocessor register 0 and 1, encoded as // Double returned in fp coprocessor register 0 and 1, encoded as
// register cr8. Offsets must be divisible by 4 for coprocessor so we // register cr8. Offsets must be divisible by 4 for coprocessor so we
// need to substract the tag from r5. // need to substract the tag from r5.
__ sub(scratch1, r4, Operand(kHeapObjectTag)); __ sub(scratch1, result, Operand(kHeapObjectTag));
__ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset)); __ stc(p1, cr8, MemOperand(scratch1, HeapNumber::kValueOffset));
#else #else
// Double returned in registers 0 and 1. // Double returned in registers 0 and 1.
__ Strd(r0, r1, FieldMemOperand(r4, HeapNumber::kValueOffset)); __ Strd(r0, r1, FieldMemOperand(result, HeapNumber::kValueOffset));
#endif #endif
__ mov(r0, Operand(r4)); __ mov(r0, Operand(result));
__ pop(pc); // Return to the pushed lr. __ pop(pc); // Return to the pushed lr.
} }
...@@ -2737,7 +2780,11 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) { ...@@ -2737,7 +2780,11 @@ void TypeRecordingBinaryOpStub::GenerateHeapNumberStub(MacroAssembler* masm) {
void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) { void TypeRecordingBinaryOpStub::GenerateGeneric(MacroAssembler* masm) {
ASSERT(op_ == Token::ADD || op_ == Token::SUB || op_ == Token::MUL); ASSERT(op_ == Token::ADD ||
op_ == Token::SUB ||
op_ == Token::MUL ||
op_ == Token::DIV ||
op_ == Token::MOD);
Label call_runtime; Label call_runtime;
...@@ -2796,6 +2843,12 @@ void TypeRecordingBinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) { ...@@ -2796,6 +2843,12 @@ void TypeRecordingBinaryOpStub::GenerateCallRuntime(MacroAssembler* masm) {
case Token::MUL: case Token::MUL:
__ InvokeBuiltin(Builtins::MUL, JUMP_JS); __ InvokeBuiltin(Builtins::MUL, JUMP_JS);
break; break;
case Token::DIV:
__ InvokeBuiltin(Builtins::DIV, JUMP_JS);
break;
case Token::MOD:
__ InvokeBuiltin(Builtins::MOD, JUMP_JS);
break;
default: default:
UNREACHABLE(); UNREACHABLE();
} }
......
...@@ -1550,7 +1550,11 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, ...@@ -1550,7 +1550,11 @@ void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
void FullCodeGenerator::EmitBinaryOp(Token::Value op, void FullCodeGenerator::EmitBinaryOp(Token::Value op,
OverwriteMode mode) { OverwriteMode mode) {
__ pop(r1); __ pop(r1);
if (op == Token::ADD || op == Token::SUB || op == Token::MUL) { if (op == Token::ADD ||
op == Token::SUB ||
op == Token::MUL ||
op == Token::DIV ||
op == Token::MOD) {
TypeRecordingBinaryOpStub stub(op, mode); TypeRecordingBinaryOpStub stub(op, mode);
__ CallStub(&stub); __ CallStub(&stub);
} else { } else {
......
...@@ -1053,11 +1053,8 @@ void LCodeGen::DoModI(LModI* instr) { ...@@ -1053,11 +1053,8 @@ void LCodeGen::DoModI(LModI* instr) {
} }
// Check for power of two on the right hand side. // Check for power of two on the right hand side.
__ sub(scratch, right, Operand(1), SetCC); __ JumpIfNotPowerOfTwoOrZero(right, scratch, &call_stub);
__ b(mi, &call_stub); // Perform modulo operation (scratch contains right - 1).
__ tst(scratch, right);
__ b(ne, &call_stub);
// Perform modulo operation.
__ and_(result, scratch, Operand(left)); __ and_(result, scratch, Operand(left));
__ bind(&call_stub); __ bind(&call_stub);
......
...@@ -1954,6 +1954,17 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function, ...@@ -1954,6 +1954,17 @@ void MacroAssembler::LoadGlobalFunctionInitialMap(Register function,
} }
void MacroAssembler::JumpIfNotPowerOfTwoOrZero(
Register reg,
Register scratch,
Label* not_power_of_two_or_zero) {
sub(scratch, reg, Operand(1), SetCC);
b(mi, not_power_of_two_or_zero);
tst(scratch, reg);
b(ne, not_power_of_two_or_zero);
}
void MacroAssembler::JumpIfNotBothSmi(Register reg1, void MacroAssembler::JumpIfNotBothSmi(Register reg1,
Register reg2, Register reg2,
Label* on_not_both_smi) { Label* on_not_both_smi) {
...@@ -2102,7 +2113,7 @@ void MacroAssembler::CopyFields(Register dst, ...@@ -2102,7 +2113,7 @@ void MacroAssembler::CopyFields(Register dst,
void MacroAssembler::CountLeadingZeros(Register zeros, // Answer. void MacroAssembler::CountLeadingZeros(Register zeros, // Answer.
Register source, // Input. Register source, // Input.
Register scratch) { Register scratch) {
ASSERT(!zeros.is(source) || !source.is(zeros)); ASSERT(!zeros.is(source) || !source.is(scratch));
ASSERT(!zeros.is(scratch)); ASSERT(!zeros.is(scratch));
ASSERT(!scratch.is(ip)); ASSERT(!scratch.is(ip));
ASSERT(!source.is(ip)); ASSERT(!source.is(ip));
......
...@@ -706,6 +706,17 @@ class MacroAssembler: public Assembler { ...@@ -706,6 +706,17 @@ class MacroAssembler: public Assembler {
void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; } void set_allow_stub_calls(bool value) { allow_stub_calls_ = value; }
bool allow_stub_calls() { return allow_stub_calls_; } bool allow_stub_calls() { return allow_stub_calls_; }
// ---------------------------------------------------------------------------
// Number utilities
// Check whether the value of reg is a power of two and not zero. If not
// control continues at the label not_power_of_two. If reg is a power of two
// the register scratch contains the value of (reg - 1) when control falls
// through.
void JumpIfNotPowerOfTwoOrZero(Register reg,
Register scratch,
Label* not_power_of_two_or_zero);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Smi utilities // Smi utilities
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment