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:
jacob.bramley@arm.com 2014-03-10 16:25:15 +00:00
parent e19d2bd423
commit 19a04c3a69
14 changed files with 553 additions and 408 deletions

View File

@ -179,9 +179,9 @@ inline void CPURegList::Combine(const CPURegList& other) {
inline void CPURegList::Remove(const CPURegList& other) {
ASSERT(IsValid());
ASSERT(other.type() == type_);
ASSERT(other.RegisterSizeInBits() == size_);
list_ &= ~other.list();
if (other.type() == type_) {
list_ &= ~other.list();
}
}
@ -192,10 +192,14 @@ inline void CPURegList::Combine(const CPURegister& other) {
}
inline void CPURegList::Remove(const CPURegister& other) {
ASSERT(other.type() == type_);
ASSERT(other.SizeInBits() == size_);
Remove(other.code());
inline void CPURegList::Remove(const CPURegister& other1,
const CPURegister& other2,
const CPURegister& other3,
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());
}

View File

@ -461,6 +461,11 @@ class CPURegList {
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
// this list are left unchanged. The type and size of the registers in the
// 'other' list must match those in this list.
@ -471,9 +476,12 @@ class CPURegList {
// in the 'other' list must match those in this list.
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 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;
// the type and size of the register is inferred from this list.
@ -503,9 +511,17 @@ class CPURegList {
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());
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 {

View File

@ -1222,7 +1222,8 @@ void MathPowStub::Generate(MacroAssembler* masm) {
// A64 simulator does not currently simulate FPCR (where the rounding
// mode is set), so test the operation with some 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.
__ Fneg(scratch0_double, zero_double);
// Verify that we correctly generated +0.0 and -0.0.
@ -1500,7 +1501,8 @@ void CEntryStub::GenerateCore(MacroAssembler* masm,
if (__ emit_debug_code()) {
// Verify that the slot below fp[kSPOffset]-8 points to the return location
// (currently in x12).
Register temp = masm->Tmp1();
UseScratchRegisterScope temps(masm);
Register temp = temps.AcquireX();
__ Ldr(temp, MemOperand(fp, ExitFrameConstants::kSPOffset));
__ Ldr(temp, MemOperand(temp, -static_cast<int64_t>(kXRegSizeInBytes)));
__ Cmp(temp, x12);
@ -4720,9 +4722,10 @@ void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
masm, kUpdateRememberedSetOnNoNeedToInformIncrementalMarker, mode);
InformIncrementalMarker(masm);
regs_.Restore(masm); // Restore the extra scratch registers we used.
__ RememberedSetHelper(object_,
address_,
value_,
value_, // scratch1
save_fp_regs_mode_,
MacroAssembler::kReturnAtEnd);
@ -4783,7 +4786,7 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
__ RememberedSetHelper(object_,
address_,
value_,
value_, // scratch1
save_fp_regs_mode_,
MacroAssembler::kReturnAtEnd);
} else {
@ -4826,7 +4829,7 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
__ RememberedSetHelper(object_,
address_,
value_,
value_, // scratch1
save_fp_regs_mode_,
MacroAssembler::kReturnAtEnd);
} else {
@ -4859,7 +4862,7 @@ void RecordWriteStub::Generate(MacroAssembler* masm) {
if (remembered_set_action_ == EMIT_REMEMBERED_SET) {
__ RememberedSetHelper(object_,
address_,
value_,
value_, // scratch1
save_fp_regs_mode_,
MacroAssembler::kReturnAtEnd);
}
@ -5090,12 +5093,11 @@ void NameDictionaryLookupStub::GeneratePositiveLookup(
__ Add(scratch2, scratch2, Operand(scratch2, LSL, 1));
// Check if the key is identical to the name.
UseScratchRegisterScope temps(masm);
Register scratch3 = temps.AcquireX();
__ Add(scratch2, elements, Operand(scratch2, LSL, kPointerSizeLog2));
// TODO(jbramley): We need another scratch here, but some callers can't
// provide a scratch3 so we have to use Tmp1(). We should find a clean way
// to make it unavailable to the MacroAssembler for a short time.
__ Ldr(__ Tmp1(), FieldMemOperand(scratch2, kElementsStartOffset));
__ Cmp(name, __ Tmp1());
__ Ldr(scratch3, FieldMemOperand(scratch2, kElementsStartOffset));
__ Cmp(name, scratch3);
__ B(eq, done);
}

View File

@ -175,8 +175,7 @@ static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
ASSERT((object_regs & non_object_regs) == 0);
ASSERT((scratch.Bit() & object_regs) == 0);
ASSERT((scratch.Bit() & non_object_regs) == 0);
ASSERT((ip0.Bit() & (object_regs | non_object_regs)) == 0);
ASSERT((ip1.Bit() & (object_regs | non_object_regs)) == 0);
ASSERT((masm->TmpList()->list() & (object_regs | non_object_regs)) == 0);
STATIC_ASSERT(kSmiValueSize == 32);
CPURegList non_object_list =

View File

@ -340,6 +340,9 @@ const int Deoptimizer::table_entry_size_ = 2 * kInstructionSize;
void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
UseScratchRegisterScope temps(masm());
Register entry_id = temps.AcquireX();
// Create a sequence of deoptimization entries.
// Note that registers are still live when jumping to an entry.
Label done;
@ -354,15 +357,13 @@ void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
for (int i = 0; i < count(); i++) {
int start = masm()->pc_offset();
USE(start);
__ movz(masm()->Tmp0(), i);
__ movz(entry_id, i);
__ b(&done);
ASSERT(masm()->pc_offset() - start == table_entry_size_);
}
}
__ Bind(&done);
// TODO(all): We need to add some kind of assertion to verify that Tmp0()
// is not clobbered by Push.
__ Push(masm()->Tmp0());
__ Push(entry_id);
}

View File

@ -86,10 +86,10 @@ class JumpPatchSite BASE_EMBEDDED {
}
void EmitJumpIfEitherNotSmi(Register reg1, Register reg2, Label* target) {
// We need to use ip0, so don't allow access to the MacroAssembler.
InstructionAccurateScope scope(masm_);
__ orr(ip0, reg1, reg2);
EmitJumpIfNotSmi(ip0, target);
UseScratchRegisterScope temps(masm_);
Register temp = temps.AcquireX();
__ Orr(temp, reg1, reg2);
EmitJumpIfNotSmi(temp, target);
}
void EmitPatchInfo() {

View File

@ -1074,6 +1074,7 @@ static void KeyedStoreGenerateGenericHelper(
FAST_DOUBLE_ELEMENTS,
receiver_map,
x10,
x11,
slow);
ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
AllocationSiteMode mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS,
@ -1088,6 +1089,7 @@ static void KeyedStoreGenerateGenericHelper(
FAST_ELEMENTS,
receiver_map,
x10,
x11,
slow);
ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
mode = AllocationSite::GetMode(FAST_SMI_ELEMENTS, FAST_ELEMENTS);
@ -1104,6 +1106,7 @@ static void KeyedStoreGenerateGenericHelper(
FAST_ELEMENTS,
receiver_map,
x10,
x11,
slow);
ASSERT(receiver_map.Is(x3)); // Transition code expects map in x3.
mode = AllocationSite::GetMode(FAST_DOUBLE_ELEMENTS, FAST_ELEMENTS);

View File

@ -845,7 +845,13 @@ bool LCodeGen::GenerateDeoptJumpTable() {
}
if (deopt_jump_table_[i].needs_frame) {
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()) {
__ B(&needs_frame);
} else {
@ -853,12 +859,11 @@ bool LCodeGen::GenerateDeoptJumpTable() {
// 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
// building, install a special marker there instead.
// TODO(jochen): Revisit the use of TmpX().
ASSERT(info()->IsStub());
__ Mov(__ Tmp1(), Operand(Smi::FromInt(StackFrame::STUB)));
__ Push(lr, fp, cp, __ Tmp1());
__ Mov(stub_marker, Operand(Smi::FromInt(StackFrame::STUB)));
__ Push(lr, fp, cp, stub_marker);
__ Add(fp, __ StackPointer(), 2 * kPointerSize);
__ Call(__ Tmp0());
__ Call(stub_deopt_entry);
}
} else {
if (info()->saves_caller_doubles()) {

View File

@ -588,7 +588,8 @@ void MacroAssembler::Fcmp(const FPRegister& fn, const FPRegister& fm) {
void MacroAssembler::Fcmp(const FPRegister& fn, double value) {
ASSERT(allow_macro_instructions_);
if (value != 0.0) {
FPRegister tmp = AppropriateTempFor(fn);
UseScratchRegisterScope temps(this);
FPRegister tmp = temps.AcquireSameSizeAs(fn);
Fmov(tmp, value);
fcmp(fn, tmp);
} else {
@ -742,16 +743,19 @@ void MacroAssembler::Fmov(FPRegister fd, double imm) {
// These cases can be handled by the Assembler.
fmov(fd, imm);
} else {
UseScratchRegisterScope temps(this);
// TODO(all): The Assembler would try to relocate the immediate with
// Assembler::ldr(const FPRegister& ft, double imm) but it is not
// implemented yet.
if (fd.SizeInBits() == kDRegSize) {
Mov(Tmp0(), double_to_rawbits(imm));
Fmov(fd, Tmp0());
Register tmp = temps.AcquireX();
Mov(tmp, double_to_rawbits(imm));
Fmov(fd, tmp);
} else {
ASSERT(fd.SizeInBits() == kSRegSize);
Mov(WTmp0(), float_to_rawbits(static_cast<float>(imm)));
Fmov(fd, WTmp0());
Register tmp = temps.AcquireW();
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* not_smi_label) {
STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
UseScratchRegisterScope temps(this);
Register tmp = temps.AcquireX();
// Check if both tag bits are clear.
Orr(Tmp0(), value1, value2);
JumpIfSmi(Tmp0(), both_smi_label, not_smi_label);
Orr(tmp, value1, value2);
JumpIfSmi(tmp, both_smi_label, not_smi_label);
}
@ -1362,9 +1368,11 @@ void MacroAssembler::JumpIfEitherSmi(Register value1,
Label* either_smi_label,
Label* not_smi_label) {
STATIC_ASSERT((kSmiTagSize == 1) && (kSmiTag == 0));
UseScratchRegisterScope temps(this);
Register tmp = temps.AcquireX();
// Check if either tag bit is clear.
And(Tmp0(), value1, value2);
JumpIfSmi(Tmp0(), either_smi_label, not_smi_label);
And(tmp, value1, value2);
JumpIfSmi(tmp, either_smi_label, not_smi_label);
}
@ -1437,8 +1445,10 @@ void MacroAssembler::IsObjectJSStringType(Register object,
void MacroAssembler::Push(Handle<Object> handle) {
Mov(Tmp0(), Operand(handle));
Push(Tmp0());
UseScratchRegisterScope temps(this);
Register tmp = temps.AcquireX();
Mov(tmp, Operand(handle));
Push(tmp);
}

File diff suppressed because it is too large Load Diff

View File

@ -520,7 +520,6 @@ class MacroAssembler : public Assembler {
//
// Other than the registers passed into Pop, the stack pointer and (possibly)
// 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,
const CPURegister& src2 = NoReg, const CPURegister& src3 = 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.
inline void SetStackPointer(const Register& stack_pointer) {
ASSERT(!AreAliased(stack_pointer, Tmp0(), Tmp1()));
ASSERT(!TmpList()->IncludesAliasOf(stack_pointer));
sp_ = stack_pointer;
}
@ -940,13 +939,13 @@ class MacroAssembler : public Assembler {
// 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
// values. The temps list must include at least one register, and it must not
// contain Tmp0() or Tmp1().
// values. The temps list must include at least one register.
//
// Currently, CopyFields cannot make use of more than three registers from
// 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);
// 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);
// 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);
// 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
// is left untouched, whereas both scratch registers are clobbered.
void CheckAccessGlobalProxy(Register holder_reg,
Register scratch,
Register scratch1,
Register scratch2,
Label* miss);
// Hash the interger value in 'key' register.
@ -1588,8 +1587,6 @@ class MacroAssembler : public Assembler {
// Frames.
// 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 LeaveFrame(StackFrame::Type type);
@ -1678,7 +1675,7 @@ class MacroAssembler : public Assembler {
void LoadContext(Register dst, int context_chain_length);
// 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);
// ---------------------------------------------------------------------------
@ -1704,7 +1701,7 @@ class MacroAssembler : public Assembler {
// in new space.
void RememberedSetHelper(Register object, // Used for debug code.
Register addr,
Register scratch,
Register scratch1,
SaveFPRegsMode save_fp,
RememberedSetFinalAction and_then);
@ -1889,7 +1886,8 @@ class MacroAssembler : public Assembler {
ElementsKind expected_kind,
ElementsKind transitioned_kind,
Register map_in_out,
Register scratch,
Register scratch1,
Register scratch2,
Label* no_map_match);
void LoadGlobalFunction(int index, Register function);
@ -1900,72 +1898,8 @@ class MacroAssembler : public Assembler {
Register map,
Register scratch);
// --------------------------------------------------------------------------
// Set the registers used internally by the MacroAssembler as scratch
// 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());
}
CPURegList* TmpList() { return &tmp_list_; }
CPURegList* FPTmpList() { return &fptmp_list_; }
// Like printf, but print at run-time from generated code.
//
@ -1978,7 +1912,7 @@ class MacroAssembler : public Assembler {
// size.
//
// The following registers cannot be printed:
// Tmp0(), Tmp1(), StackPointer(), csp.
// StackPointer(), csp.
//
// This function automatically preserves caller-saved registers so that
// 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.
void CopyFieldsLoopPairsHelper(Register dst, Register src, unsigned count,
Register scratch1, Register scratch2,
Register scratch3);
Register scratch3, Register scratch4,
Register scratch5);
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,
Register scratch1);
Register scratch1, Register scratch2,
Register scratch3);
// The actual Push and Pop implementations. These don't generate any code
// 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.
Register sp_;
// Scratch registers used internally by the MacroAssembler.
Register tmp0_;
Register tmp1_;
FPRegister fptmp0_;
// Scratch registers available for use by the MacroAssembler.
CPURegList tmp_list_;
CPURegList fptmp_list_;
void InitializeNewString(Register string,
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) {
return MemOperand(context, Context::SlotOffset(index));
}

View File

@ -903,7 +903,8 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
// the map check so that we know that the object is actually a global
// object.
if (current_map->IsJSGlobalProxyMap()) {
__ CheckAccessGlobalProxy(reg, scratch2, miss);
UseScratchRegisterScope temps(masm());
__ CheckAccessGlobalProxy(reg, scratch2, temps.AcquireX(), miss);
} else if (current_map->IsJSGlobalObjectMap()) {
GenerateCheckPropertyCell(
masm(), Handle<JSGlobalObject>::cast(current), name,
@ -940,7 +941,7 @@ Register StubCompiler::CheckPrototypes(Handle<HeapType> type,
ASSERT(current_map->IsJSGlobalProxyMap() ||
!current_map->is_access_check_needed());
if (current_map->IsJSGlobalProxyMap()) {
__ CheckAccessGlobalProxy(reg, scratch1, miss);
__ CheckAccessGlobalProxy(reg, scratch1, scratch2, miss);
}
// Return the register containing the holder.

View File

@ -5614,51 +5614,58 @@ TEST(fcmp) {
// Some of these tests require a floating-point scratch register assigned to
// 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(s9, 0.5);
__ Mov(w18, 0x7f800001); // Single precision NaN.
__ Fmov(s18, w18);
__ Fmov(s8, 0.0);
__ Fmov(s9, 0.5);
__ Mov(w18, 0x7f800001); // Single precision NaN.
__ Fmov(s18, w18);
__ Fcmp(s8, s8);
__ Mrs(x0, NZCV);
__ Fcmp(s8, s9);
__ Mrs(x1, NZCV);
__ Fcmp(s9, s8);
__ Mrs(x2, NZCV);
__ Fcmp(s8, s18);
__ Mrs(x3, NZCV);
__ Fcmp(s18, s18);
__ Mrs(x4, NZCV);
__ Fcmp(s8, 0.0);
__ Mrs(x5, NZCV);
__ SetFPScratchRegister(d0);
__ Fcmp(s8, 255.0);
__ SetFPScratchRegister(NoFPReg);
__ Mrs(x6, NZCV);
__ Fcmp(s8, s8);
__ Mrs(x0, NZCV);
__ Fcmp(s8, s9);
__ Mrs(x1, NZCV);
__ Fcmp(s9, s8);
__ Mrs(x2, NZCV);
__ Fcmp(s8, s18);
__ Mrs(x3, NZCV);
__ Fcmp(s18, s18);
__ Mrs(x4, NZCV);
__ Fcmp(s8, 0.0);
__ Mrs(x5, NZCV);
masm.FPTmpList()->set_list(d0.Bit());
__ Fcmp(s8, 255.0);
masm.FPTmpList()->set_list(0);
__ Mrs(x6, NZCV);
__ Fmov(d19, 0.0);
__ Fmov(d20, 0.5);
__ Mov(x21, 0x7ff0000000000001UL); // Double precision NaN.
__ Fmov(d21, x21);
__ Fmov(d19, 0.0);
__ Fmov(d20, 0.5);
__ Mov(x21, 0x7ff0000000000001UL); // Double precision NaN.
__ 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();
RUN();

View File

@ -323,11 +323,10 @@ void RegisterDump::Dump(MacroAssembler* masm) {
ASSERT(__ StackPointer().Is(csp));
// Ensure that we don't unintentionally clobber any registers.
Register old_tmp0 = __ Tmp0();
Register old_tmp1 = __ Tmp1();
FPRegister old_fptmp0 = __ FPTmp0();
__ SetScratchRegisters(NoReg, NoReg);
__ SetFPScratchRegister(NoFPReg);
RegList old_tmp_list = masm->TmpList()->list();
RegList old_fptmp_list = masm->FPTmpList()->list();
masm->TmpList()->set_list(0);
masm->FPTmpList()->set_list(0);
// Preserve some temporary registers.
Register dump_base = x0;
@ -419,8 +418,8 @@ void RegisterDump::Dump(MacroAssembler* masm) {
__ Ldr(dump2, MemOperand(dump2, dump2.code() * kXRegSizeInBytes));
// Restore the MacroAssembler's scratch registers.
__ SetScratchRegisters(old_tmp0, old_tmp1);
__ SetFPScratchRegister(old_fptmp0);
masm->TmpList()->set_list(old_tmp_list);
masm->FPTmpList()->set_list(old_fptmp_list);
completed_ = true;
}