Commit 9891a057 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

MIPS: Update for 23-May commits, and a few older ones.

Make mips-specifc changes for r7999, r8001, r8002.

Also bring in changes for older commits 7203, 7279, 7693, 7715, 7788.

Mips changes for 7715 (Arm: Support hardfloat in SCons build), and
7693 (Implement hardfloat calling convention in macro assembler and simulator)
resulted in changes to SConstruct.

BUG=
TEST=

Review URL: http://codereview.chromium.org//6966031

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8022 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 179702df
......@@ -210,6 +210,9 @@ LIBRARY_FLAGS = {
'LINKFLAGS': ['-m32'],
'mipsabi:softfloat': {
'CPPDEFINES': ['__mips_soft_float=1'],
},
'mipsabi:hardfloat': {
'CPPDEFINES': ['__mips_hard_float=1'],
}
},
'arch:x64': {
......@@ -511,10 +514,29 @@ SAMPLE_FLAGS = {
},
'arch:mips': {
'CPPDEFINES': ['V8_TARGET_ARCH_MIPS'],
'mips_arch_variant:mips32r2': {
'CPPDEFINES': ['_MIPS_ARCH_MIPS32R2']
},
'simulator:none': {
'CCFLAGS': ['-EL', '-mips32r2', '-Wa,-mips32r2', '-fno-inline'],
'CCFLAGS': ['-EL'],
'LINKFLAGS': ['-EL'],
'LDFLAGS': ['-EL']
'mips_arch_variant:mips32r2': {
'CCFLAGS': ['-mips32r2', '-Wa,-mips32r2']
},
'mips_arch_variant:mips32r1': {
'CCFLAGS': ['-mips32', '-Wa,-mips32']
},
'library:static': {
'LINKFLAGS': ['-static', '-static-libgcc']
},
'mipsabi:softfloat': {
'CCFLAGS': ['-msoft-float'],
'LINKFLAGS': ['-msoft-float']
},
'mipsabi:hardfloat': {
'CCFLAGS': ['-mhard-float'],
'LINKFLAGS': ['-mhard-float']
}
}
},
'simulator:arm': {
......@@ -678,6 +700,9 @@ PREPARSER_FLAGS = {
'LINKFLAGS': ['-m32'],
'mipsabi:softfloat': {
'CPPDEFINES': ['__mips_soft_float=1'],
},
'mipsabi:hardfloat': {
'CPPDEFINES': ['__mips_hard_float=1'],
}
},
'mode:release': {
......@@ -1238,12 +1263,8 @@ def PostprocessOptions(options, os):
if 'msvcltcg' in ARGUMENTS:
print "Warning: forcing msvcltcg on as it is required for pgo (%s)" % options['pgo']
options['msvcltcg'] = 'on'
if (options['simulator'] == 'mips' and options['mipsabi'] != 'softfloat'):
# Print a warning if soft-float ABI is not selected for mips simulator
print "Warning: forcing soft-float mips ABI when running on simulator"
options['mipsabi'] = 'softfloat'
if (options['mipsabi'] != 'none') and (options['arch'] != 'mips') and (options['simulator'] != 'mips'):
options['mipsabi'] = 'none'
if (options['mipsabi'] != 'none') and (options['arch'] != 'mips') and (options['simulator'] != 'mips'):
options['mipsabi'] = 'none'
if options['liveobjectlist'] == 'on':
if (options['debuggersupport'] != 'on') or (options['mode'] == 'release'):
# Print a warning that liveobjectlist will implicitly enable the debugger
......
This diff is collapsed.
......@@ -37,18 +37,6 @@
namespace v8 {
namespace internal {
#if(defined(__mips_hard_float) && __mips_hard_float != 0)
// Use floating-point coprocessor instructions. This flag is raised when
// -mhard-float is passed to the compiler.
static const bool IsMipsSoftFloatABI = false;
#elif(defined(__mips_soft_float) && __mips_soft_float != 0)
// Not using floating-point coprocessor instructions. This flag is raised when
// -msoft-float is passed to the compiler.
static const bool IsMipsSoftFloatABI = true;
#else
static const bool IsMipsSoftFloatABI = true;
#endif
// Forward declarations
class CompilationInfo;
......
......@@ -47,6 +47,19 @@
#endif
#if(defined(__mips_hard_float) && __mips_hard_float != 0)
// Use floating-point coprocessor instructions. This flag is raised when
// -mhard-float is passed to the compiler.
static const bool IsMipsSoftFloatABI = false;
#elif(defined(__mips_soft_float) && __mips_soft_float != 0)
// Not using floating-point coprocessor instructions. This flag is raised when
// -msoft-float is passed to the compiler.
static const bool IsMipsSoftFloatABI = true;
#else
static const bool IsMipsSoftFloatABI = true;
#endif
// Defines constants and accessor classes to assemble, disassemble and
// simulate MIPS32 instructions.
//
......
......@@ -105,7 +105,7 @@ void BreakLocationIterator::SetDebugBreakAtSlot() {
// call t9 (jalr t9 / nop instruction pair)
CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
patcher.masm()->li(v8::internal::t9, Operand(reinterpret_cast<int32_t>(
Isolate::Current()->debug()->debug_break_return()->entry())));
Isolate::Current()->debug()->debug_break_slot()->entry())));
patcher.masm()->Call(v8::internal::t9);
}
......
......@@ -79,6 +79,43 @@ static const int kNumSafepointSavedRegisters =
typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];
static const int kUndefIndex = -1;
// Map with indexes on stack that corresponds to codes of saved registers.
static const int kSafepointRegisterStackIndexMap[kNumRegs] = {
kUndefIndex,
kUndefIndex,
0, // v0
kUndefIndex,
1, // a0
2, // a1
3, // a2
4, // a3
kUndefIndex,
kUndefIndex,
kUndefIndex,
kUndefIndex,
kUndefIndex,
kUndefIndex,
kUndefIndex,
kUndefIndex,
5, // Saved temporaries.
6,
7,
8,
9,
10,
11,
12,
kUndefIndex,
kUndefIndex,
kUndefIndex,
kUndefIndex,
13, // gp
14, // sp
15, // fp
kUndefIndex
};
// ----------------------------------------------------
......
......@@ -930,8 +930,8 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// check for an enum cache. Leave the map in a2 for the subsequent
// prototype load.
__ lw(a2, FieldMemOperand(a1, HeapObject::kMapOffset));
__ lw(a3, FieldMemOperand(a2, Map::kInstanceDescriptorsOffset));
__ Branch(&call_runtime, eq, a3, Operand(empty_descriptor_array_value));
__ lw(a3, FieldMemOperand(a2, Map::kInstanceDescriptorsOrBitField3Offset));
__ JumpIfSmi(a3, &call_runtime);
// Check that there is an enum cache in the non-empty instance
// descriptors (a3). This is the case if the next enumeration
......@@ -972,7 +972,7 @@ void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
// We got a map in register v0. Get the enumeration cache from it.
__ bind(&use_cache);
__ lw(a1, FieldMemOperand(v0, Map::kInstanceDescriptorsOffset));
__ LoadInstanceDescriptors(v0, a1);
__ lw(a1, FieldMemOperand(a1, DescriptorArray::kEnumerationIndexOffset));
__ lw(a2, FieldMemOperand(a1, DescriptorArray::kEnumCacheBridgeCacheOffset));
......@@ -2551,7 +2551,7 @@ void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
// Look for valueOf symbol in the descriptor array, and indicate false if
// found. The type is not checked, so if it is a transition it is a false
// negative.
__ lw(t0, FieldMemOperand(a1, Map::kInstanceDescriptorsOffset));
__ LoadInstanceDescriptors(a1, t0);
__ lw(a3, FieldMemOperand(t0, FixedArray::kLengthOffset));
// t0: descriptor array
// a3: length of descriptor array
......@@ -2866,11 +2866,9 @@ void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
// 0x41300000 is the top half of 1.0 x 2^20 as a double.
__ li(a1, Operand(0x41300000));
// Move 0x41300000xxxxxxxx (x = random bits in v0) to FPU.
__ mtc1(a1, f13);
__ mtc1(v0, f12);
__ Move(f12, v0, a1);
// Move 0x4130000000000000 to FPU.
__ mtc1(a1, f15);
__ mtc1(zero_reg, f14);
__ Move(f14, zero_reg, a1);
// Subtract and store the result in the heap number.
__ sub_d(f0, f12, f14);
__ sdc1(f0, MemOperand(s0, HeapNumber::kValueOffset - kHeapObjectTag));
......
......@@ -193,6 +193,77 @@ void MacroAssembler::RecordWriteHelper(Register object,
sw(scratch, MemOperand(object, Page::kDirtyFlagOffset));
}
// Push and pop all registers that can hold pointers.
void MacroAssembler::PushSafepointRegisters() {
// Safepoints expect a block of kNumSafepointRegisters values on the
// stack, so adjust the stack for unsaved registers.
const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
ASSERT(num_unsaved >= 0);
Subu(sp, sp, Operand(num_unsaved * kPointerSize));
MultiPush(kSafepointSavedRegisters);
}
void MacroAssembler::PopSafepointRegisters() {
const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
MultiPop(kSafepointSavedRegisters);
Addu(sp, sp, Operand(num_unsaved * kPointerSize));
}
void MacroAssembler::PushSafepointRegistersAndDoubles() {
PushSafepointRegisters();
Subu(sp, sp, Operand(FPURegister::kNumAllocatableRegisters * kDoubleSize));
for (int i = 0; i < FPURegister::kNumAllocatableRegisters; i+=2) {
FPURegister reg = FPURegister::FromAllocationIndex(i);
sdc1(reg, MemOperand(sp, i * kDoubleSize));
}
}
void MacroAssembler::PopSafepointRegistersAndDoubles() {
for (int i = 0; i < FPURegister::kNumAllocatableRegisters; i+=2) {
FPURegister reg = FPURegister::FromAllocationIndex(i);
ldc1(reg, MemOperand(sp, i * kDoubleSize));
}
Addu(sp, sp, Operand(FPURegister::kNumAllocatableRegisters * kDoubleSize));
PopSafepointRegisters();
}
void MacroAssembler::StoreToSafepointRegistersAndDoublesSlot(Register src,
Register dst) {
sw(src, SafepointRegistersAndDoublesSlot(dst));
}
void MacroAssembler::StoreToSafepointRegisterSlot(Register src, Register dst) {
sw(src, SafepointRegisterSlot(dst));
}
void MacroAssembler::LoadFromSafepointRegisterSlot(Register dst, Register src) {
lw(dst, SafepointRegisterSlot(src));
}
int MacroAssembler::SafepointRegisterStackIndex(int reg_code) {
// The registers are pushed starting with the highest encoding,
// which means that lowest encodings are closest to the stack pointer.
return kSafepointRegisterStackIndexMap[reg_code];
}
MemOperand MacroAssembler::SafepointRegisterSlot(Register reg) {
return MemOperand(sp, SafepointRegisterStackIndex(reg.code()) * kPointerSize);
}
MemOperand MacroAssembler::SafepointRegistersAndDoublesSlot(Register reg) {
// General purpose registers are pushed last on the stack.
int doubles_size = FPURegister::kNumAllocatableRegisters * kDoubleSize;
int register_offset = SafepointRegisterStackIndex(reg.code()) * kPointerSize;
return MemOperand(sp, doubles_size + register_offset);
}
void MacroAssembler::InNewSpace(Register object,
Register scratch,
......@@ -1903,13 +1974,6 @@ void MacroAssembler::Call(Label* target) {
}
void MacroAssembler::Move(Register dst, Register src) {
if (!dst.is(src)) {
mov(dst, src);
}
}
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::DebugBreak() {
......@@ -2585,17 +2649,56 @@ void MacroAssembler::CheckMap(Register obj,
void MacroAssembler::GetCFunctionDoubleResult(const DoubleRegister dst) {
CpuFeatures::Scope scope(FPU);
if (IsMipsSoftFloatABI) {
mtc1(v0, dst);
mtc1(v1, FPURegister::from_code(dst.code() + 1));
Move(v0, v1, dst);
} else {
Move(f0, dst); // Reg f0 is o32 ABI FP return value.
}
}
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg) {
CpuFeatures::Scope scope(FPU);
if (!IsMipsSoftFloatABI) {
Move(f12, dreg);
} else {
if (!dst.is(f0)) {
mov_d(dst, f0); // Reg f0 is o32 ABI FP return value.
Move(a0, a1, dreg);
}
}
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg1,
DoubleRegister dreg2) {
CpuFeatures::Scope scope(FPU);
if (!IsMipsSoftFloatABI) {
if (dreg2.is(f12)) {
ASSERT(!dreg1.is(f14));
Move(f14, dreg2);
Move(f12, dreg1);
} else {
Move(f12, dreg1);
Move(f14, dreg2);
}
} else {
Move(a0, a1, dreg1);
Move(a2, a3, dreg2);
}
}
void MacroAssembler::SetCallCDoubleArguments(DoubleRegister dreg,
Register reg) {
CpuFeatures::Scope scope(FPU);
if (!IsMipsSoftFloatABI) {
Move(f12, dreg);
Move(a2, reg);
} else {
Move(a2, reg);
Move(a0, a1, dreg);
}
}
// -----------------------------------------------------------------------------
// JavaScript invokes.
......@@ -3490,14 +3593,27 @@ void MacroAssembler::EnterExitFrame(bool save_doubles,
li(t8, Operand(ExternalReference(Isolate::k_context_address, isolate())));
sw(cp, MemOperand(t8));
// Ensure we are not saving doubles, since it's not implemented yet.
ASSERT(save_doubles == 0);
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
if (save_doubles) {
// The stack must be allign to 0 modulo 8 for stores with sdc1.
ASSERT(kDoubleSize == frame_alignment);
if (frame_alignment > 0) {
ASSERT(IsPowerOf2(frame_alignment));
And(sp, sp, Operand(-frame_alignment)); // Align stack.
}
int space = FPURegister::kNumRegisters * kDoubleSize;
Subu(sp, sp, Operand(space));
// Remember: we only need to save every 2nd double FPU value.
for (int i = 0; i < FPURegister::kNumRegisters; i+=2) {
FPURegister reg = FPURegister::from_code(i);
sdc1(reg, MemOperand(sp, i * kDoubleSize));
}
}
// Reserve place for the return address, stack space and an optional slot
// (used by the DirectCEntryStub to hold the return value if a struct is
// returned) and align the frame preparing for calling the runtime function.
ASSERT(stack_space >= 0);
const int frame_alignment = MacroAssembler::ActivationFrameAlignment();
Subu(sp, sp, Operand((stack_space + 2) * kPointerSize));
if (frame_alignment > 0) {
ASSERT(IsPowerOf2(frame_alignment));
......@@ -3513,8 +3629,15 @@ void MacroAssembler::EnterExitFrame(bool save_doubles,
void MacroAssembler::LeaveExitFrame(bool save_doubles,
Register argument_count) {
// Ensure we are not restoring doubles, since it's not implemented yet.
ASSERT(save_doubles == 0);
// Optionally restore all double registers.
if (save_doubles) {
// Remember: we only need to restore every 2nd double FPU value.
lw(t8, MemOperand(fp, ExitFrameConstants::kSPOffset));
for (int i = 0; i < FPURegister::kNumRegisters; i+=2) {
FPURegister reg = FPURegister::from_code(i);
ldc1(reg, MemOperand(t8, i * kDoubleSize + kPointerSize));
}
}
// Clear top frame.
li(t8, Operand(ExternalReference(Isolate::k_c_entry_fp_address, isolate())));
......@@ -3837,6 +3960,17 @@ void MacroAssembler::CallCFunctionHelper(Register function,
#undef BRANCH_ARGS_CHECK
void MacroAssembler::LoadInstanceDescriptors(Register map,
Register descriptors) {
lw(descriptors,
FieldMemOperand(map, Map::kInstanceDescriptorsOrBitField3Offset));
Label not_smi;
JumpIfNotSmi(descriptors, &not_smi);
li(descriptors, Operand(FACTORY->empty_descriptor_array()));
bind(&not_smi);
}
CodePatcher::CodePatcher(byte* address, int instructions)
: address_(address),
instructions_(instructions),
......
......@@ -207,9 +207,28 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
void Swap(Register reg1, Register reg2, Register scratch = no_reg);
void Call(Label* target);
// May do nothing if the registers are identical.
void Move(Register dst, Register src);
inline void Move(Register dst, Register src) {
if (!dst.is(src)) {
mov(dst, src);
}
}
inline void Move(FPURegister dst, FPURegister src) {
if (!dst.is(src)) {
mov_d(dst, src);
}
}
inline void Move(Register dst_low, Register dst_high, FPURegister src) {
mfc1(dst_low, src);
mfc1(dst_high, FPURegister::from_code(src.code() + 1));
}
inline void Move(FPURegister dst, Register src_low, Register src_high) {
mtc1(src_low, dst);
mtc1(src_high, FPURegister::from_code(dst.code() + 1));
}
// Jump unconditionally to given label.
// We NEED a nop in the branch delay slot, as it used by v8, for example in
......@@ -509,34 +528,19 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
Addu(sp, sp, Operand(count * kPointerSize));
}
// ---------------------------------------------------------------------------
// These functions are only used by crankshaft, so they are currently
// unimplemented.
// Push and pop the registers that can hold pointers, as defined by the
// RegList constant kSafepointSavedRegisters.
void PushSafepointRegisters() {
UNIMPLEMENTED_MIPS();
}
void PopSafepointRegisters() {
UNIMPLEMENTED_MIPS();
}
void PushSafepointRegistersAndDoubles() {
UNIMPLEMENTED_MIPS();
}
void PopSafepointRegistersAndDoubles() {
UNIMPLEMENTED_MIPS();
}
static int SafepointRegisterStackIndex(int reg_code) {
UNIMPLEMENTED_MIPS();
return 0;
}
// ---------------------------------------------------------------------------
void PushSafepointRegisters();
void PopSafepointRegisters();
void PushSafepointRegistersAndDoubles();
void PopSafepointRegistersAndDoubles();
// Store value in register src in the safepoint stack slot for
// register dst.
void StoreToSafepointRegisterSlot(Register src, Register dst);
void StoreToSafepointRegistersAndDoublesSlot(Register src, Register dst);
// Load the value of the src register from its safepoint stack slot
// into register dst.
void LoadFromSafepointRegisterSlot(Register dst, Register src);
// MIPS32 R2 instruction macro.
void Ins(Register rt, Register rs, uint16_t pos, uint16_t size);
......@@ -881,6 +885,14 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
void CallCFunction(Register function, Register scratch, int num_arguments);
void GetCFunctionDoubleResult(const DoubleRegister dst);
// There are two ways of passing double arguments on MIPS, depending on
// whether soft or hard floating point ABI is used. These functions
// abstract parameter passing for the three different ways we call
// C functions from generated code.
void SetCallCDoubleArguments(DoubleRegister dreg);
void SetCallCDoubleArguments(DoubleRegister dreg1, DoubleRegister dreg2);
void SetCallCDoubleArguments(DoubleRegister dreg, Register reg);
// Calls an API function. Allocates HandleScope, extracts returned value
// from handle and propagates exceptions. Restores context.
MaybeObject* TryCallApiFunctionAndReturn(ExternalReference function,
......@@ -1060,6 +1072,8 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
Register scratch2,
Label* failure);
void LoadInstanceDescriptors(Register map, Register descriptors);
private:
void CallCFunctionHelper(Register function,
ExternalReference function_reference,
......@@ -1100,11 +1114,19 @@ DECLARE_NOTARGET_PROTOTYPE(Ret)
Register scratch1,
Register scratch2);
// Compute memory operands for safepoint stack slots.
static int SafepointRegisterStackIndex(int reg_code);
MemOperand SafepointRegisterSlot(Register reg);
MemOperand SafepointRegistersAndDoublesSlot(Register reg);
bool generating_stub_;
bool allow_stub_calls_;
// This handle will be patched with the code object on installation.
Handle<Object> code_object_;
// Needs access to SafepointRegisterStackIndex for optimized frame
// traversal.
friend class OptimizedFrame;
};
......@@ -1181,4 +1203,3 @@ static inline MemOperand CFunctionArgumentOperand(int index) {
} } // namespace v8::internal
#endif // V8_MIPS_MACRO_ASSEMBLER_MIPS_H_
This diff is collapsed.
......@@ -323,9 +323,12 @@ class Simulator {
static void* RedirectExternalReference(void* external_function,
ExternalReference::Type type);
// Used for real time calls that takes two double values as arguments and
// returns a double.
void SetFpResult(double result);
// For use in calls that take double value arguments.
void GetFpArgs(double* x, double* y);
void GetFpArgs(double* x);
void GetFpArgs(double* x, int32_t* y);
void SetFpResult(const double& result);
// Architecture state.
// Registers.
......
......@@ -3410,7 +3410,7 @@ MaybeObject* ExternalArrayStoreStubCompiler::CompileStore(
a3,
Handle<Map>(receiver->map()),
Handle<Code>(stub),
DONT_DO_SMI_CHECK);
DO_SMI_CHECK);
Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss();
__ Jump(ic, RelocInfo::CODE_TARGET);
......@@ -3566,8 +3566,21 @@ void KeyedLoadStubCompiler::GenerateLoadExternalArray(
__ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset - kHeapObjectTag));
__ Ret();
} else {
WriteInt32ToHeapNumberStub stub(value, v0, t2, t3);
__ TailCallStub(&stub);
Register dst1 = t2;
Register dst2 = t3;
FloatingPointHelper::Destination dest =
FloatingPointHelper::kCoreRegisters;
FloatingPointHelper::ConvertIntToDouble(masm,
value,
dest,
f0,
dst1,
dst2,
t1,
f2);
__ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
__ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
__ Ret();
}
} else if (array_type == kExternalUnsignedIntArray) {
// The test is different for unsigned int values. Since we need
......
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