A64: Use a scope utility to allocate scratch registers.
This replaces Tmp0() and Tmp1() with a more flexible scratch register pool. A scope-based utility can temporarily acquire registers from this pool as needed. We no longer have to worry about whether to use Tmp0(), Tmp1() or something else; the scope can just get the next available scratch register. BUG= R=jochen@chromium.org, rmcilroy@chromium.org Review URL: https://codereview.chromium.org/164793003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19768 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
e19d2bd423
commit
19a04c3a69
@ -179,9 +179,9 @@ inline void CPURegList::Combine(const CPURegList& other) {
|
|||||||
|
|
||||||
inline void CPURegList::Remove(const CPURegList& other) {
|
inline void CPURegList::Remove(const CPURegList& other) {
|
||||||
ASSERT(IsValid());
|
ASSERT(IsValid());
|
||||||
ASSERT(other.type() == type_);
|
if (other.type() == type_) {
|
||||||
ASSERT(other.RegisterSizeInBits() == size_);
|
list_ &= ~other.list();
|
||||||
list_ &= ~other.list();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -192,10 +192,14 @@ inline void CPURegList::Combine(const CPURegister& other) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void CPURegList::Remove(const CPURegister& other) {
|
inline void CPURegList::Remove(const CPURegister& other1,
|
||||||
ASSERT(other.type() == type_);
|
const CPURegister& other2,
|
||||||
ASSERT(other.SizeInBits() == size_);
|
const CPURegister& other3,
|
||||||
Remove(other.code());
|
const CPURegister& other4) {
|
||||||
|
if (!other1.IsNone() && (other1.type() == type_)) Remove(other1.code());
|
||||||
|
if (!other2.IsNone() && (other2.type() == type_)) Remove(other2.code());
|
||||||
|
if (!other3.IsNone() && (other3.type() == type_)) Remove(other3.code());
|
||||||
|
if (!other4.IsNone() && (other4.type() == type_)) Remove(other4.code());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -461,6 +461,11 @@ class CPURegList {
|
|||||||
return list_;
|
return list_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void set_list(RegList new_list) {
|
||||||
|
ASSERT(IsValid());
|
||||||
|
list_ = new_list;
|
||||||
|
}
|
||||||
|
|
||||||
// Combine another CPURegList into this one. Registers that already exist in
|
// Combine another CPURegList into this one. Registers that already exist in
|
||||||
// this list are left unchanged. The type and size of the registers in the
|
// this list are left unchanged. The type and size of the registers in the
|
||||||
// 'other' list must match those in this list.
|
// 'other' list must match those in this list.
|
||||||
@ -471,9 +476,12 @@ class CPURegList {
|
|||||||
// in the 'other' list must match those in this list.
|
// in the 'other' list must match those in this list.
|
||||||
void Remove(const CPURegList& other);
|
void Remove(const CPURegList& other);
|
||||||
|
|
||||||
// Variants of Combine and Remove which take a single register.
|
// Variants of Combine and Remove which take CPURegisters.
|
||||||
void Combine(const CPURegister& other);
|
void Combine(const CPURegister& other);
|
||||||
void Remove(const CPURegister& other);
|
void Remove(const CPURegister& other1,
|
||||||
|
const CPURegister& other2 = NoCPUReg,
|
||||||
|
const CPURegister& other3 = NoCPUReg,
|
||||||
|
const CPURegister& other4 = NoCPUReg);
|
||||||
|
|
||||||
// Variants of Combine and Remove which take a single register by its code;
|
// Variants of Combine and Remove which take a single register by its code;
|
||||||
// the type and size of the register is inferred from this list.
|
// the type and size of the register is inferred from this list.
|
||||||
@ -503,9 +511,17 @@ class CPURegList {
|
|||||||
return list_ == 0;
|
return list_ == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IncludesAliasOf(const CPURegister& other) const {
|
bool IncludesAliasOf(const CPURegister& other1,
|
||||||
|
const CPURegister& other2 = NoCPUReg,
|
||||||
|
const CPURegister& other3 = NoCPUReg,
|
||||||
|
const CPURegister& other4 = NoCPUReg) const {
|
||||||
ASSERT(IsValid());
|
ASSERT(IsValid());
|
||||||
return (type_ == other.type()) && (other.Bit() & list_);
|
RegList list = 0;
|
||||||
|
if (!other1.IsNone() && (other1.type() == type_)) list |= other1.Bit();
|
||||||
|
if (!other2.IsNone() && (other2.type() == type_)) list |= other2.Bit();
|
||||||
|
if (!other3.IsNone() && (other3.type() == type_)) list |= other3.Bit();
|
||||||
|
if (!other4.IsNone() && (other4.type() == type_)) list |= other4.Bit();
|
||||||
|
return (list_ & list) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Count() const {
|
int Count() const {
|
||||||
|
@ -1222,7 +1222,8 @@ void MathPowStub::Generate(MacroAssembler* masm) {
|
|||||||
// A64 simulator does not currently simulate FPCR (where the rounding
|
// A64 simulator does not currently simulate FPCR (where the rounding
|
||||||
// mode is set), so test the operation with some debug code.
|
// mode is set), so test the operation with some debug code.
|
||||||
if (masm->emit_debug_code()) {
|
if (masm->emit_debug_code()) {
|
||||||
Register temp = masm->Tmp1();
|
UseScratchRegisterScope temps(masm);
|
||||||
|
Register temp = temps.AcquireX();
|
||||||
// d5 zero_double The value +0.0 as a double.
|
// d5 zero_double The value +0.0 as a double.
|
||||||
__ Fneg(scratch0_double, zero_double);
|
__ Fneg(scratch0_double, zero_double);
|
||||||
// Verify that we correctly generated +0.0 and -0.0.
|
// Verify that we correctly generated +0.0 and -0.0.
|
||||||
@ -1500,7 +1501,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
|
|||||||
if (__ emit_debug_code()) {
|
if (__ emit_debug_code()) {
|
||||||
// Verify that the slot below fp[kSPOffset]-8 points to the return location
|
// Verify that the slot below fp[kSPOffset]-8 points to the return location
|
||||||
// (currently in x12).
|
// (currently in x12).
|
||||||
Register temp = masm->Tmp1();
|
UseScratchRegisterScope temps(masm);
|
||||||
|
Register temp = temps.AcquireX();
|
||||||
__ Ldr(temp, MemOperand(fp, ExitFrameConstants::kSPOffset));
|
__ Ldr(temp, MemOperand(fp, ExitFrameConstants::kSPOffset));
|
||||||
__ Ldr(temp, MemOperand(temp, -static_cast<int64_t>(kXRegSizeInBytes)));
|
__ Ldr(temp, MemOperand(temp, -static_cast<int64_t>(kXRegSizeInBytes)));
|
||||||
__ Cmp(temp, x12);
|
__ Cmp(temp, x12);
|
||||||
@ -4720,9 +4722,10 @@ void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
|
|||||||
masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
|
masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
|
||||||
InformIncrementalMarker(masm);
|
InformIncrementalMarker(masm);
|
||||||
regs_.Restore(masm); // Restore the extra scratch registers we used.
|
regs_.Restore(masm); // Restore the extra scratch registers we used.
|
||||||
|
|
||||||
__ RememberedSetHelper(object_,
|
__ RememberedSetHelper(object_,
|
||||||
address_,
|
address_,
|
||||||
value_,
|
value_, // scratch1
|
||||||
save_fp_regs_mode_,
|
save_fp_regs_mode_,
|
||||||
MacroAssembler::kReturnAtEnd);
|
MacroAssembler::kReturnAtEnd);
|
||||||
|
|
||||||
@ -4783,7 +4786,7 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
|
|||||||
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
|
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
|
||||||
__ RememberedSetHelper(object_,
|
__ RememberedSetHelper(object_,
|
||||||
address_,
|
address_,
|
||||||
value_,
|
value_, // scratch1
|
||||||
save_fp_regs_mode_,
|
save_fp_regs_mode_,
|
||||||
MacroAssembler::kReturnAtEnd);
|
MacroAssembler::kReturnAtEnd);
|
||||||
} else {
|
} else {
|
||||||
@ -4826,7 +4829,7 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
|
|||||||
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
|
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
|
||||||
__ RememberedSetHelper(object_,
|
__ RememberedSetHelper(object_,
|
||||||
address_,
|
address_,
|
||||||
value_,
|
value_, // scratch1
|
||||||
save_fp_regs_mode_,
|
save_fp_regs_mode_,
|
||||||
MacroAssembler::kReturnAtEnd);
|
MacroAssembler::kReturnAtEnd);
|
||||||
} else {
|
} else {
|
||||||
@ -4859,7 +4862,7 @@ void RecordWriteStub::Generate(MacroAssembler* masm) {
|
|||||||
if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
|
if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
|
||||||
__ RememberedSetHelper(object_,
|
__ RememberedSetHelper(object_,
|
||||||
address_,
|
address_,
|
||||||
value_,
|
value_, // scratch1
|
||||||
save_fp_regs_mode_,
|
save_fp_regs_mode_,
|
||||||
MacroAssembler::kReturnAtEnd);
|
MacroAssembler::kReturnAtEnd);
|
||||||
}
|
}
|
||||||
@ -5090,12 +5093,11 @@ void NameDictionaryLookupStub::GeneratePositiveLookup(
|
|||||||
__ Add(scratch2, scratch2, Operand(scratch2, LSL, 1));
|
__ Add(scratch2, scratch2, Operand(scratch2, LSL, 1));
|
||||||
|
|
||||||
// Check if the key is identical to the name.
|
// Check if the key is identical to the name.
|
||||||
|
UseScratchRegisterScope temps(masm);
|
||||||
|
Register scratch3 = temps.AcquireX();
|
||||||
__ Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2));
|
__ Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2));
|
||||||
// TODO(jbramley): We need another scratch here, but some callers can't
|
__ Ldr(scratch3, FieldMemOperand(scratch2, kElementsStartOffset));
|
||||||
// provide a scratch3 so we have to use Tmp1(). We should find a clean way
|
__ Cmp(name, scratch3);
|
||||||
// to make it unavailable to the MacroAssembler for a short time.
|
|
||||||
__ Ldr(__ Tmp1(), FieldMemOperand(scratch2, kElementsStartOffset));
|
|
||||||
__ Cmp(name, __ Tmp1());
|
|
||||||
__ B(eq, done);
|
__ B(eq, done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,8 +175,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
|
|||||||
ASSERT((object_regs & non_object_regs) == 0);
|
ASSERT((object_regs & non_object_regs) == 0);
|
||||||
ASSERT((scratch.Bit() & object_regs) == 0);
|
ASSERT((scratch.Bit() & object_regs) == 0);
|
||||||
ASSERT((scratch.Bit() & non_object_regs) == 0);
|
ASSERT((scratch.Bit() & non_object_regs) == 0);
|
||||||
ASSERT((ip0.Bit() & (object_regs | non_object_regs)) == 0);
|
ASSERT((masm->TmpList()->list() & (object_regs | non_object_regs)) == 0);
|
||||||
ASSERT((ip1.Bit() & (object_regs | non_object_regs)) == 0);
|
|
||||||
STATIC_ASSERT(kSmiValueSize == 32);
|
STATIC_ASSERT(kSmiValueSize == 32);
|
||||||
|
|
||||||
CPURegList non_object_list =
|
CPURegList non_object_list =
|
||||||
|
@ -340,6 +340,9 @@ const int Deoptimizer::table_entry_size_ = 2 * kInstructionSize;
|
|||||||
|
|
||||||
|
|
||||||
void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
|
void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
|
||||||
|
UseScratchRegisterScope temps(masm());
|
||||||
|
Register entry_id = temps.AcquireX();
|
||||||
|
|
||||||
// Create a sequence of deoptimization entries.
|
// Create a sequence of deoptimization entries.
|
||||||
// Note that registers are still live when jumping to an entry.
|
// Note that registers are still live when jumping to an entry.
|
||||||
Label done;
|
Label done;
|
||||||
@ -354,15 +357,13 @@ void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
|
|||||||
for (int i = 0; i < count(); i++) {
|
for (int i = 0; i < count(); i++) {
|
||||||
int start = masm()->pc_offset();
|
int start = masm()->pc_offset();
|
||||||
USE(start);
|
USE(start);
|
||||||
__ movz(masm()->Tmp0(), i);
|
__ movz(entry_id, i);
|
||||||
__ b(&done);
|
__ b(&done);
|
||||||
ASSERT(masm()->pc_offset() - start == table_entry_size_);
|
ASSERT(masm()->pc_offset() - start == table_entry_size_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
__ Bind(&done);
|
__ Bind(&done);
|
||||||
// TODO(all): We need to add some kind of assertion to verify that Tmp0()
|
__ Push(entry_id);
|
||||||
// is not clobbered by Push.
|
|
||||||
__ Push(masm()->Tmp0());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,10 +86,10 @@ class JumpPatchSite BASE_EMBEDDED {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EmitJumpIfEitherNotSmi(Register reg1, Register reg2, Label* target) {
|
void EmitJumpIfEitherNotSmi(Register reg1, Register reg2, Label* target) {
|
||||||
// We need to use ip0, so don't allow access to the MacroAssembler.
|
UseScratchRegisterScope temps(masm_);
|
||||||
InstructionAccurateScope scope(masm_);
|
Register temp = temps.AcquireX();
|
||||||
__ orr(ip0, reg1, reg2);
|
__ Orr(temp, reg1, reg2);
|
||||||
EmitJumpIfNotSmi(ip0, target);
|
EmitJumpIfNotSmi(temp, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitPatchInfo() {
|
void EmitPatchInfo() {
|
||||||
|
@ -1074,6 +1074,7 @@ static void KeyedStoreGenerateGenericHelper(
|
|||||||
FAST_DOUBLE_ELEMENTS,
|
FAST_DOUBLE_ELEMENTS,
|
||||||
receiver_map,
|
receiver_map,
|
||||||
x10,
|
x10,
|
||||||
|
x11,
|
||||||
slow);
|
slow);
|
||||||
ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
|
ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
|
||||||
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
|
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
|
||||||
@ -1088,6 +1089,7 @@ static void KeyedStoreGenerateGenericHelper(
|
|||||||
FAST_ELEMENTS,
|
FAST_ELEMENTS,
|
||||||
receiver_map,
|
receiver_map,
|
||||||
x10,
|
x10,
|
||||||
|
x11,
|
||||||
slow);
|
slow);
|
||||||
ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
|
ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
|
||||||
mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
|
mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
|
||||||
@ -1104,6 +1106,7 @@ static void KeyedStoreGenerateGenericHelper(
|
|||||||
FAST_ELEMENTS,
|
FAST_ELEMENTS,
|
||||||
receiver_map,
|
receiver_map,
|
||||||
x10,
|
x10,
|
||||||
|
x11,
|
||||||
slow);
|
slow);
|
||||||
ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
|
ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
|
||||||
mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
|
mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);
|
||||||
|
@ -845,7 +845,13 @@ bool LCodeGen::GenerateDeoptJumpTable() {
|
|||||||
}
|
}
|
||||||
if (deopt_jump_table_[i].needs_frame) {
|
if (deopt_jump_table_[i].needs_frame) {
|
||||||
ASSERT(!info()->saves_caller_doubles());
|
ASSERT(!info()->saves_caller_doubles());
|
||||||
__ Mov(__ Tmp0(), Operand(ExternalReference::ForDeoptEntry(entry)));
|
|
||||||
|
UseScratchRegisterScope temps(masm());
|
||||||
|
Register stub_deopt_entry = temps.AcquireX();
|
||||||
|
Register stub_marker = temps.AcquireX();
|
||||||
|
|
||||||
|
__ Mov(stub_deopt_entry,
|
||||||
|
Operand(ExternalReference::ForDeoptEntry(entry)));
|
||||||
if (needs_frame.is_bound()) {
|
if (needs_frame.is_bound()) {
|
||||||
__ B(&needs_frame);
|
__ B(&needs_frame);
|
||||||
} else {
|
} else {
|
||||||
@ -853,12 +859,11 @@ bool LCodeGen::GenerateDeoptJumpTable() {
|
|||||||
// This variant of deopt can only be used with stubs. Since we don't
|
// This variant of deopt can only be used with stubs. Since we don't
|
||||||
// have a function pointer to install in the stack frame that we're
|
// have a function pointer to install in the stack frame that we're
|
||||||
// building, install a special marker there instead.
|
// building, install a special marker there instead.
|
||||||
// TODO(jochen): Revisit the use of TmpX().
|
|
||||||
ASSERT(info()->IsStub());
|
ASSERT(info()->IsStub());
|
||||||
__ Mov(__ Tmp1(), Operand(Smi::FromInt(StackFrame::STUB)));
|
__ Mov(stub_marker, Operand(Smi::FromInt(StackFrame::STUB)));
|
||||||
__ Push(lr, fp, cp, __ Tmp1());
|
__ Push(lr, fp, cp, stub_marker);
|
||||||
__ Add(fp, __ StackPointer(), 2 * kPointerSize);
|
__ Add(fp, __ StackPointer(), 2 * kPointerSize);
|
||||||
__ Call(__ Tmp0());
|
__ Call(stub_deopt_entry);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (info()->saves_caller_doubles()) {
|
if (info()->saves_caller_doubles()) {
|
||||||
|
@ -588,7 +588,8 @@ void MacroAssembler::Fcmp(const FPRegister& fn, const FPRegister& fm) {
|
|||||||
void MacroAssembler::Fcmp(const FPRegister& fn, double value) {
|
void MacroAssembler::Fcmp(const FPRegister& fn, double value) {
|
||||||
ASSERT(allow_macro_instructions_);
|
ASSERT(allow_macro_instructions_);
|
||||||
if (value != 0.0) {
|
if (value != 0.0) {
|
||||||
FPRegister tmp = AppropriateTempFor(fn);
|
UseScratchRegisterScope temps(this);
|
||||||
|
FPRegister tmp = temps.AcquireSameSizeAs(fn);
|
||||||
Fmov(tmp, value);
|
Fmov(tmp, value);
|
||||||
fcmp(fn, tmp);
|
fcmp(fn, tmp);
|
||||||
} else {
|
} else {
|
||||||
@ -742,16 +743,19 @@ void MacroAssembler::Fmov(FPRegister fd, double imm) {
|
|||||||
// These cases can be handled by the Assembler.
|
// These cases can be handled by the Assembler.
|
||||||
fmov(fd, imm);
|
fmov(fd, imm);
|
||||||
} else {
|
} else {
|
||||||
|
UseScratchRegisterScope temps(this);
|
||||||
// TODO(all): The Assembler would try to relocate the immediate with
|
// TODO(all): The Assembler would try to relocate the immediate with
|
||||||
// Assembler::ldr(const FPRegister& ft, double imm) but it is not
|
// Assembler::ldr(const FPRegister& ft, double imm) but it is not
|
||||||
// implemented yet.
|
// implemented yet.
|
||||||
if (fd.SizeInBits() == kDRegSize) {
|
if (fd.SizeInBits() == kDRegSize) {
|
||||||
Mov(Tmp0(), double_to_rawbits(imm));
|
Register tmp = temps.AcquireX();
|
||||||
Fmov(fd, Tmp0());
|
Mov(tmp, double_to_rawbits(imm));
|
||||||
|
Fmov(fd, tmp);
|
||||||
} else {
|
} else {
|
||||||
ASSERT(fd.SizeInBits() == kSRegSize);
|
ASSERT(fd.SizeInBits() == kSRegSize);
|
||||||
Mov(WTmp0(), float_to_rawbits(static_cast<float>(imm)));
|
Register tmp = temps.AcquireW();
|
||||||
Fmov(fd, WTmp0());
|
Mov(tmp, float_to_rawbits(static_cast<float>(imm)));
|
||||||
|
Fmov(fd, tmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1351,9 +1355,11 @@ void MacroAssembler::JumpIfBothSmi(Register value1,
|
|||||||
Label* both_smi_label,
|
Label* both_smi_label,
|
||||||
Label* not_smi_label) {
|
Label* not_smi_label) {
|
||||||
STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
|
STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
|
||||||
|
UseScratchRegisterScope temps(this);
|
||||||
|
Register tmp = temps.AcquireX();
|
||||||
// Check if both tag bits are clear.
|
// Check if both tag bits are clear.
|
||||||
Orr(Tmp0(), value1, value2);
|
Orr(tmp, value1, value2);
|
||||||
JumpIfSmi(Tmp0(), both_smi_label, not_smi_label);
|
JumpIfSmi(tmp, both_smi_label, not_smi_label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1362,9 +1368,11 @@ void MacroAssembler::JumpIfEitherSmi(Register value1,
|
|||||||
Label* either_smi_label,
|
Label* either_smi_label,
|
||||||
Label* not_smi_label) {
|
Label* not_smi_label) {
|
||||||
STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
|
STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
|
||||||
|
UseScratchRegisterScope temps(this);
|
||||||
|
Register tmp = temps.AcquireX();
|
||||||
// Check if either tag bit is clear.
|
// Check if either tag bit is clear.
|
||||||
And(Tmp0(), value1, value2);
|
And(tmp, value1, value2);
|
||||||
JumpIfSmi(Tmp0(), either_smi_label, not_smi_label);
|
JumpIfSmi(tmp, either_smi_label, not_smi_label);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1437,8 +1445,10 @@ void MacroAssembler::IsObjectJSStringType(Register object,
|
|||||||
|
|
||||||
|
|
||||||
void MacroAssembler::Push(Handle<Object> handle) {
|
void MacroAssembler::Push(Handle<Object> handle) {
|
||||||
Mov(Tmp0(), Operand(handle));
|
UseScratchRegisterScope temps(this);
|
||||||
Push(Tmp0());
|
Register tmp = temps.AcquireX();
|
||||||
|
Mov(tmp, Operand(handle));
|
||||||
|
Push(tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -520,7 +520,6 @@ class MacroAssembler : public Assembler {
|
|||||||
//
|
//
|
||||||
// Other than the registers passed into Pop, the stack pointer and (possibly)
|
// Other than the registers passed into Pop, the stack pointer and (possibly)
|
||||||
// the system stack pointer, these methods do not modify any other registers.
|
// the system stack pointer, these methods do not modify any other registers.
|
||||||
// Scratch registers such as Tmp0() and Tmp1() are preserved.
|
|
||||||
void Push(const CPURegister& src0, const CPURegister& src1 = NoReg,
|
void Push(const CPURegister& src0, const CPURegister& src1 = NoReg,
|
||||||
const CPURegister& src2 = NoReg, const CPURegister& src3 = NoReg);
|
const CPURegister& src2 = NoReg, const CPURegister& src3 = NoReg);
|
||||||
void Pop(const CPURegister& dst0, const CPURegister& dst1 = NoReg,
|
void Pop(const CPURegister& dst0, const CPURegister& dst1 = NoReg,
|
||||||
@ -746,7 +745,7 @@ class MacroAssembler : public Assembler {
|
|||||||
|
|
||||||
// Set the current stack pointer, but don't generate any code.
|
// Set the current stack pointer, but don't generate any code.
|
||||||
inline void SetStackPointer(const Register& stack_pointer) {
|
inline void SetStackPointer(const Register& stack_pointer) {
|
||||||
ASSERT(!AreAliased(stack_pointer, Tmp0(), Tmp1()));
|
ASSERT(!TmpList()->IncludesAliasOf(stack_pointer));
|
||||||
sp_ = stack_pointer;
|
sp_ = stack_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -940,13 +939,13 @@ class MacroAssembler : public Assembler {
|
|||||||
|
|
||||||
// Copy fields from 'src' to 'dst', where both are tagged objects.
|
// Copy fields from 'src' to 'dst', where both are tagged objects.
|
||||||
// The 'temps' list is a list of X registers which can be used for scratch
|
// The 'temps' list is a list of X registers which can be used for scratch
|
||||||
// values. The temps list must include at least one register, and it must not
|
// values. The temps list must include at least one register.
|
||||||
// contain Tmp0() or Tmp1().
|
|
||||||
//
|
//
|
||||||
// Currently, CopyFields cannot make use of more than three registers from
|
// Currently, CopyFields cannot make use of more than three registers from
|
||||||
// the 'temps' list.
|
// the 'temps' list.
|
||||||
//
|
//
|
||||||
// As with several MacroAssembler methods, Tmp0() and Tmp1() will be used.
|
// CopyFields expects to be able to take at least two registers from
|
||||||
|
// MacroAssembler::TmpList().
|
||||||
void CopyFields(Register dst, Register src, CPURegList temps, unsigned count);
|
void CopyFields(Register dst, Register src, CPURegList temps, unsigned count);
|
||||||
|
|
||||||
// Copies a number of bytes from src to dst. All passed registers are
|
// Copies a number of bytes from src to dst. All passed registers are
|
||||||
@ -1449,7 +1448,6 @@ class MacroAssembler : public Assembler {
|
|||||||
void LoadElementsKind(Register result, Register object);
|
void LoadElementsKind(Register result, Register object);
|
||||||
|
|
||||||
// Compare the object in a register to a value from the root list.
|
// Compare the object in a register to a value from the root list.
|
||||||
// Uses the Tmp0() register as scratch.
|
|
||||||
void CompareRoot(const Register& obj, Heap::RootListIndex index);
|
void CompareRoot(const Register& obj, Heap::RootListIndex index);
|
||||||
|
|
||||||
// Compare the object in a register to a value and jump if they are equal.
|
// Compare the object in a register to a value and jump if they are equal.
|
||||||
@ -1556,7 +1554,8 @@ class MacroAssembler : public Assembler {
|
|||||||
// on access to global objects across environments. The holder register
|
// on access to global objects across environments. The holder register
|
||||||
// is left untouched, whereas both scratch registers are clobbered.
|
// is left untouched, whereas both scratch registers are clobbered.
|
||||||
void CheckAccessGlobalProxy(Register holder_reg,
|
void CheckAccessGlobalProxy(Register holder_reg,
|
||||||
Register scratch,
|
Register scratch1,
|
||||||
|
Register scratch2,
|
||||||
Label* miss);
|
Label* miss);
|
||||||
|
|
||||||
// Hash the interger value in 'key' register.
|
// Hash the interger value in 'key' register.
|
||||||
@ -1588,8 +1587,6 @@ class MacroAssembler : public Assembler {
|
|||||||
// Frames.
|
// Frames.
|
||||||
|
|
||||||
// Activation support.
|
// Activation support.
|
||||||
// Note that Tmp0() and Tmp1() are used as a scratch registers. This is safe
|
|
||||||
// because these methods are not used in Crankshaft.
|
|
||||||
void EnterFrame(StackFrame::Type type);
|
void EnterFrame(StackFrame::Type type);
|
||||||
void LeaveFrame(StackFrame::Type type);
|
void LeaveFrame(StackFrame::Type type);
|
||||||
|
|
||||||
@ -1678,7 +1675,7 @@ class MacroAssembler : public Assembler {
|
|||||||
void LoadContext(Register dst, int context_chain_length);
|
void LoadContext(Register dst, int context_chain_length);
|
||||||
|
|
||||||
// Emit code for a flooring division by a constant. The dividend register is
|
// Emit code for a flooring division by a constant. The dividend register is
|
||||||
// unchanged and Tmp0() gets clobbered. Dividend and result must be different.
|
// unchanged. Dividend and result must be different.
|
||||||
void FlooringDiv(Register result, Register dividend, int32_t divisor);
|
void FlooringDiv(Register result, Register dividend, int32_t divisor);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
@ -1704,7 +1701,7 @@ class MacroAssembler : public Assembler {
|
|||||||
// in new space.
|
// in new space.
|
||||||
void RememberedSetHelper(Register object, // Used for debug code.
|
void RememberedSetHelper(Register object, // Used for debug code.
|
||||||
Register addr,
|
Register addr,
|
||||||
Register scratch,
|
Register scratch1,
|
||||||
SaveFPRegsMode save_fp,
|
SaveFPRegsMode save_fp,
|
||||||
RememberedSetFinalAction and_then);
|
RememberedSetFinalAction and_then);
|
||||||
|
|
||||||
@ -1889,7 +1886,8 @@ class MacroAssembler : public Assembler {
|
|||||||
ElementsKind expected_kind,
|
ElementsKind expected_kind,
|
||||||
ElementsKind transitioned_kind,
|
ElementsKind transitioned_kind,
|
||||||
Register map_in_out,
|
Register map_in_out,
|
||||||
Register scratch,
|
Register scratch1,
|
||||||
|
Register scratch2,
|
||||||
Label* no_map_match);
|
Label* no_map_match);
|
||||||
|
|
||||||
void LoadGlobalFunction(int index, Register function);
|
void LoadGlobalFunction(int index, Register function);
|
||||||
@ -1900,72 +1898,8 @@ class MacroAssembler : public Assembler {
|
|||||||
Register map,
|
Register map,
|
||||||
Register scratch);
|
Register scratch);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
CPURegList* TmpList() { return &tmp_list_; }
|
||||||
// Set the registers used internally by the MacroAssembler as scratch
|
CPURegList* FPTmpList() { return &fptmp_list_; }
|
||||||
// registers. These registers are used to implement behaviours which are not
|
|
||||||
// directly supported by A64, and where an intermediate result is required.
|
|
||||||
//
|
|
||||||
// Both tmp0 and tmp1 may be set to any X register except for xzr, sp,
|
|
||||||
// and StackPointer(). Also, they must not be the same register (though they
|
|
||||||
// may both be NoReg).
|
|
||||||
//
|
|
||||||
// It is valid to set either or both of these registers to NoReg if you don't
|
|
||||||
// want the MacroAssembler to use any scratch registers. In a debug build, the
|
|
||||||
// Assembler will assert that any registers it uses are valid. Be aware that
|
|
||||||
// this check is not present in release builds. If this is a problem, use the
|
|
||||||
// Assembler directly.
|
|
||||||
void SetScratchRegisters(const Register& tmp0, const Register& tmp1) {
|
|
||||||
// V8 assumes the macro assembler uses ip0 and ip1 as temp registers.
|
|
||||||
ASSERT(tmp0.IsNone() || tmp0.Is(ip0));
|
|
||||||
ASSERT(tmp1.IsNone() || tmp1.Is(ip1));
|
|
||||||
|
|
||||||
ASSERT(!AreAliased(xzr, csp, tmp0, tmp1));
|
|
||||||
ASSERT(!AreAliased(StackPointer(), tmp0, tmp1));
|
|
||||||
tmp0_ = tmp0;
|
|
||||||
tmp1_ = tmp1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Register& Tmp0() const {
|
|
||||||
return tmp0_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Register& Tmp1() const {
|
|
||||||
return tmp1_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Register WTmp0() const {
|
|
||||||
return Register::Create(tmp0_.code(), kWRegSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
const Register WTmp1() const {
|
|
||||||
return Register::Create(tmp1_.code(), kWRegSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetFPScratchRegister(const FPRegister& fptmp0) {
|
|
||||||
fptmp0_ = fptmp0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FPRegister& FPTmp0() const {
|
|
||||||
return fptmp0_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Register AppropriateTempFor(
|
|
||||||
const Register& target,
|
|
||||||
const CPURegister& forbidden = NoCPUReg) const {
|
|
||||||
Register candidate = forbidden.Is(Tmp0()) ? Tmp1() : Tmp0();
|
|
||||||
ASSERT(!candidate.Is(target));
|
|
||||||
return Register::Create(candidate.code(), target.SizeInBits());
|
|
||||||
}
|
|
||||||
|
|
||||||
const FPRegister AppropriateTempFor(
|
|
||||||
const FPRegister& target,
|
|
||||||
const CPURegister& forbidden = NoCPUReg) const {
|
|
||||||
USE(forbidden);
|
|
||||||
FPRegister candidate = FPTmp0();
|
|
||||||
ASSERT(!candidate.Is(forbidden));
|
|
||||||
ASSERT(!candidate.Is(target));
|
|
||||||
return FPRegister::Create(candidate.code(), target.SizeInBits());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Like printf, but print at run-time from generated code.
|
// Like printf, but print at run-time from generated code.
|
||||||
//
|
//
|
||||||
@ -1978,7 +1912,7 @@ class MacroAssembler : public Assembler {
|
|||||||
// size.
|
// size.
|
||||||
//
|
//
|
||||||
// The following registers cannot be printed:
|
// The following registers cannot be printed:
|
||||||
// Tmp0(), Tmp1(), StackPointer(), csp.
|
// StackPointer(), csp.
|
||||||
//
|
//
|
||||||
// This function automatically preserves caller-saved registers so that
|
// This function automatically preserves caller-saved registers so that
|
||||||
// calling code can use Printf at any point without having to worry about
|
// calling code can use Printf at any point without having to worry about
|
||||||
@ -2063,11 +1997,14 @@ class MacroAssembler : public Assembler {
|
|||||||
// These each implement CopyFields in a different way.
|
// These each implement CopyFields in a different way.
|
||||||
void CopyFieldsLoopPairsHelper(Register dst, Register src, unsigned count,
|
void CopyFieldsLoopPairsHelper(Register dst, Register src, unsigned count,
|
||||||
Register scratch1, Register scratch2,
|
Register scratch1, Register scratch2,
|
||||||
Register scratch3);
|
Register scratch3, Register scratch4,
|
||||||
|
Register scratch5);
|
||||||
void CopyFieldsUnrolledPairsHelper(Register dst, Register src, unsigned count,
|
void CopyFieldsUnrolledPairsHelper(Register dst, Register src, unsigned count,
|
||||||
Register scratch1, Register scratch2);
|
Register scratch1, Register scratch2,
|
||||||
|
Register scratch3, Register scratch4);
|
||||||
void CopyFieldsUnrolledHelper(Register dst, Register src, unsigned count,
|
void CopyFieldsUnrolledHelper(Register dst, Register src, unsigned count,
|
||||||
Register scratch1);
|
Register scratch1, Register scratch2,
|
||||||
|
Register scratch3);
|
||||||
|
|
||||||
// The actual Push and Pop implementations. These don't generate any code
|
// The actual Push and Pop implementations. These don't generate any code
|
||||||
// other than that required for the push or pop. This allows
|
// other than that required for the push or pop. This allows
|
||||||
@ -2148,10 +2085,9 @@ class MacroAssembler : public Assembler {
|
|||||||
// The register to use as a stack pointer for stack operations.
|
// The register to use as a stack pointer for stack operations.
|
||||||
Register sp_;
|
Register sp_;
|
||||||
|
|
||||||
// Scratch registers used internally by the MacroAssembler.
|
// Scratch registers available for use by the MacroAssembler.
|
||||||
Register tmp0_;
|
CPURegList tmp_list_;
|
||||||
Register tmp1_;
|
CPURegList fptmp_list_;
|
||||||
FPRegister fptmp0_;
|
|
||||||
|
|
||||||
void InitializeNewString(Register string,
|
void InitializeNewString(Register string,
|
||||||
Register length,
|
Register length,
|
||||||
@ -2232,6 +2168,49 @@ class InstructionAccurateScope BASE_EMBEDDED {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// This scope utility allows scratch registers to be managed safely. The
|
||||||
|
// MacroAssembler's TmpList() (and FPTmpList()) is used as a pool of scratch
|
||||||
|
// registers. These registers can be allocated on demand, and will be returned
|
||||||
|
// at the end of the scope.
|
||||||
|
//
|
||||||
|
// When the scope ends, the MacroAssembler's lists will be restored to their
|
||||||
|
// original state, even if the lists were modified by some other means.
|
||||||
|
class UseScratchRegisterScope {
|
||||||
|
public:
|
||||||
|
explicit UseScratchRegisterScope(MacroAssembler* masm)
|
||||||
|
: available_(masm->TmpList()),
|
||||||
|
availablefp_(masm->FPTmpList()),
|
||||||
|
old_available_(available_->list()),
|
||||||
|
old_availablefp_(availablefp_->list()) {
|
||||||
|
ASSERT(available_->type() == CPURegister::kRegister);
|
||||||
|
ASSERT(availablefp_->type() == CPURegister::kFPRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
~UseScratchRegisterScope();
|
||||||
|
|
||||||
|
// Take a register from the appropriate temps list. It will be returned
|
||||||
|
// automatically when the scope ends.
|
||||||
|
Register AcquireW() { return AcquireNextAvailable(available_).W(); }
|
||||||
|
Register AcquireX() { return AcquireNextAvailable(available_).X(); }
|
||||||
|
FPRegister AcquireS() { return AcquireNextAvailable(availablefp_).S(); }
|
||||||
|
FPRegister AcquireD() { return AcquireNextAvailable(availablefp_).D(); }
|
||||||
|
|
||||||
|
Register AcquireSameSizeAs(const Register& reg);
|
||||||
|
FPRegister AcquireSameSizeAs(const FPRegister& reg);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static CPURegister AcquireNextAvailable(CPURegList* available);
|
||||||
|
|
||||||
|
// Available scratch registers.
|
||||||
|
CPURegList* available_; // kRegister
|
||||||
|
CPURegList* availablefp_; // kFPRegister
|
||||||
|
|
||||||
|
// The state of the available lists at the start of this scope.
|
||||||
|
RegList old_available_; // kRegister
|
||||||
|
RegList old_availablefp_; // kFPRegister
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
inline MemOperand ContextMemOperand(Register context, int index) {
|
inline MemOperand ContextMemOperand(Register context, int index) {
|
||||||
return MemOperand(context, Context::SlotOffset(index));
|
return MemOperand(context, Context::SlotOffset(index));
|
||||||
}
|
}
|
||||||
|
@ -903,7 +903,8 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
|
|||||||
// the map check so that we know that the object is actually a global
|
// the map check so that we know that the object is actually a global
|
||||||
// object.
|
// object.
|
||||||
if (current_map->IsJSGlobalProxyMap()) {
|
if (current_map->IsJSGlobalProxyMap()) {
|
||||||
__ CheckAccessGlobalProxy(reg, scratch2, miss);
|
UseScratchRegisterScope temps(masm());
|
||||||
|
__ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss);
|
||||||
} else if (current_map->IsJSGlobalObjectMap()) {
|
} else if (current_map->IsJSGlobalObjectMap()) {
|
||||||
GenerateCheckPropertyCell(
|
GenerateCheckPropertyCell(
|
||||||
masm(), Handle<JSGlobalObject>::cast(current), name,
|
masm(), Handle<JSGlobalObject>::cast(current), name,
|
||||||
@ -940,7 +941,7 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
|
|||||||
ASSERT(current_map->IsJSGlobalProxyMap() ||
|
ASSERT(current_map->IsJSGlobalProxyMap() ||
|
||||||
!current_map->is_access_check_needed());
|
!current_map->is_access_check_needed());
|
||||||
if (current_map->IsJSGlobalProxyMap()) {
|
if (current_map->IsJSGlobalProxyMap()) {
|
||||||
__ CheckAccessGlobalProxy(reg, scratch1, miss);
|
__ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the register containing the holder.
|
// Return the register containing the holder.
|
||||||
|
@ -5614,51 +5614,58 @@ TEST(fcmp) {
|
|||||||
|
|
||||||
// Some of these tests require a floating-point scratch register assigned to
|
// Some of these tests require a floating-point scratch register assigned to
|
||||||
// the macro assembler, but most do not.
|
// the macro assembler, but most do not.
|
||||||
__ SetFPScratchRegister(NoFPReg);
|
{
|
||||||
|
// We're going to mess around with the available scratch registers in this
|
||||||
|
// test. A UseScratchRegisterScope will make sure that they are restored to
|
||||||
|
// the default values once we're finished.
|
||||||
|
UseScratchRegisterScope temps(&masm);
|
||||||
|
masm.FPTmpList()->set_list(0);
|
||||||
|
|
||||||
__ Fmov(s8, 0.0);
|
__ Fmov(s8, 0.0);
|
||||||
__ Fmov(s9, 0.5);
|
__ Fmov(s9, 0.5);
|
||||||
__ Mov(w18, 0x7f800001); // Single precision NaN.
|
__ Mov(w18, 0x7f800001); // Single precision NaN.
|
||||||
__ Fmov(s18, w18);
|
__ Fmov(s18, w18);
|
||||||
|
|
||||||
__ Fcmp(s8, s8);
|
__ Fcmp(s8, s8);
|
||||||
__ Mrs(x0, NZCV);
|
__ Mrs(x0, NZCV);
|
||||||
__ Fcmp(s8, s9);
|
__ Fcmp(s8, s9);
|
||||||
__ Mrs(x1, NZCV);
|
__ Mrs(x1, NZCV);
|
||||||
__ Fcmp(s9, s8);
|
__ Fcmp(s9, s8);
|
||||||
__ Mrs(x2, NZCV);
|
__ Mrs(x2, NZCV);
|
||||||
__ Fcmp(s8, s18);
|
__ Fcmp(s8, s18);
|
||||||
__ Mrs(x3, NZCV);
|
__ Mrs(x3, NZCV);
|
||||||
__ Fcmp(s18, s18);
|
__ Fcmp(s18, s18);
|
||||||
__ Mrs(x4, NZCV);
|
__ Mrs(x4, NZCV);
|
||||||
__ Fcmp(s8, 0.0);
|
__ Fcmp(s8, 0.0);
|
||||||
__ Mrs(x5, NZCV);
|
__ Mrs(x5, NZCV);
|
||||||
__ SetFPScratchRegister(d0);
|
masm.FPTmpList()->set_list(d0.Bit());
|
||||||
__ Fcmp(s8, 255.0);
|
__ Fcmp(s8, 255.0);
|
||||||
__ SetFPScratchRegister(NoFPReg);
|
masm.FPTmpList()->set_list(0);
|
||||||
__ Mrs(x6, NZCV);
|
__ Mrs(x6, NZCV);
|
||||||
|
|
||||||
__ Fmov(d19, 0.0);
|
__ Fmov(d19, 0.0);
|
||||||
__ Fmov(d20, 0.5);
|
__ Fmov(d20, 0.5);
|
||||||
__ Mov(x21, 0x7ff0000000000001UL); // Double precision NaN.
|
__ Mov(x21, 0x7ff0000000000001UL); // Double precision NaN.
|
||||||
__ Fmov(d21, x21);
|
__ Fmov(d21, x21);
|
||||||
|
|
||||||
|
__ Fcmp(d19, d19);
|
||||||
|
__ Mrs(x10, NZCV);
|
||||||
|
__ Fcmp(d19, d20);
|
||||||
|
__ Mrs(x11, NZCV);
|
||||||
|
__ Fcmp(d20, d19);
|
||||||
|
__ Mrs(x12, NZCV);
|
||||||
|
__ Fcmp(d19, d21);
|
||||||
|
__ Mrs(x13, NZCV);
|
||||||
|
__ Fcmp(d21, d21);
|
||||||
|
__ Mrs(x14, NZCV);
|
||||||
|
__ Fcmp(d19, 0.0);
|
||||||
|
__ Mrs(x15, NZCV);
|
||||||
|
masm.FPTmpList()->set_list(d0.Bit());
|
||||||
|
__ Fcmp(d19, 12.3456);
|
||||||
|
masm.FPTmpList()->set_list(0);
|
||||||
|
__ Mrs(x16, NZCV);
|
||||||
|
}
|
||||||
|
|
||||||
__ Fcmp(d19, d19);
|
|
||||||
__ Mrs(x10, NZCV);
|
|
||||||
__ Fcmp(d19, d20);
|
|
||||||
__ Mrs(x11, NZCV);
|
|
||||||
__ Fcmp(d20, d19);
|
|
||||||
__ Mrs(x12, NZCV);
|
|
||||||
__ Fcmp(d19, d21);
|
|
||||||
__ Mrs(x13, NZCV);
|
|
||||||
__ Fcmp(d21, d21);
|
|
||||||
__ Mrs(x14, NZCV);
|
|
||||||
__ Fcmp(d19, 0.0);
|
|
||||||
__ Mrs(x15, NZCV);
|
|
||||||
__ SetFPScratchRegister(d0);
|
|
||||||
__ Fcmp(d19, 12.3456);
|
|
||||||
__ SetFPScratchRegister(NoFPReg);
|
|
||||||
__ Mrs(x16, NZCV);
|
|
||||||
END();
|
END();
|
||||||
|
|
||||||
RUN();
|
RUN();
|
||||||
|
@ -323,11 +323,10 @@ void RegisterDump::Dump(MacroAssembler* masm) {
|
|||||||
ASSERT(__ StackPointer().Is(csp));
|
ASSERT(__ StackPointer().Is(csp));
|
||||||
|
|
||||||
// Ensure that we don't unintentionally clobber any registers.
|
// Ensure that we don't unintentionally clobber any registers.
|
||||||
Register old_tmp0 = __ Tmp0();
|
RegList old_tmp_list = masm->TmpList()->list();
|
||||||
Register old_tmp1 = __ Tmp1();
|
RegList old_fptmp_list = masm->FPTmpList()->list();
|
||||||
FPRegister old_fptmp0 = __ FPTmp0();
|
masm->TmpList()->set_list(0);
|
||||||
__ SetScratchRegisters(NoReg, NoReg);
|
masm->FPTmpList()->set_list(0);
|
||||||
__ SetFPScratchRegister(NoFPReg);
|
|
||||||
|
|
||||||
// Preserve some temporary registers.
|
// Preserve some temporary registers.
|
||||||
Register dump_base = x0;
|
Register dump_base = x0;
|
||||||
@ -419,8 +418,8 @@ void RegisterDump::Dump(MacroAssembler* masm) {
|
|||||||
__ Ldr(dump2, MemOperand(dump2, dump2.code() * kXRegSizeInBytes));
|
__ Ldr(dump2, MemOperand(dump2, dump2.code() * kXRegSizeInBytes));
|
||||||
|
|
||||||
// Restore the MacroAssembler's scratch registers.
|
// Restore the MacroAssembler's scratch registers.
|
||||||
__ SetScratchRegisters(old_tmp0, old_tmp1);
|
masm->TmpList()->set_list(old_tmp_list);
|
||||||
__ SetFPScratchRegister(old_fptmp0);
|
masm->FPTmpList()->set_list(old_fptmp_list);
|
||||||
|
|
||||||
completed_ = true;
|
completed_ = true;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user