// The original source code covered by the above license above has been
// modified significantly by Google Inc.
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
#include "v8.h"
}
+void Assembler::vldm(BlockAddrMode am,
+ Register base,
+ DwVfpRegister first,
+ DwVfpRegister last,
+ Condition cond) {
+ // Instruction details available in ARM DDI 0406A, A8-626.
+ // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
+ // first(15-12) | 1010(11-8) | (count * 2)
+ ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT_LE(first.code(), last.code());
+ ASSERT(am == ia || am == ia_w || am == db_w);
+ ASSERT(!base.is(pc));
+
+ int sd, d;
+ first.split_code(&sd, &d);
+ int count = last.code() - first.code() + 1;
+ emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
+ 0xB*B8 | count*2);
+}
+
+
+void Assembler::vstm(BlockAddrMode am,
+ Register base,
+ DwVfpRegister first,
+ DwVfpRegister last,
+ Condition cond) {
+ // Instruction details available in ARM DDI 0406A, A8-784.
+ // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
+ // first(15-12) | 1011(11-8) | (count * 2)
+ ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT_LE(first.code(), last.code());
+ ASSERT(am == ia || am == ia_w || am == db_w);
+ ASSERT(!base.is(pc));
+
+ int sd, d;
+ first.split_code(&sd, &d);
+ int count = last.code() - first.code() + 1;
+ emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
+ 0xB*B8 | count*2);
+}
+
+void Assembler::vldm(BlockAddrMode am,
+ Register base,
+ SwVfpRegister first,
+ SwVfpRegister last,
+ Condition cond) {
+ // Instruction details available in ARM DDI 0406A, A8-626.
+ // cond(31-28) | 110(27-25)| PUDW1(24-20) | Rbase(19-16) |
+ // first(15-12) | 1010(11-8) | (count/2)
+ ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT_LE(first.code(), last.code());
+ ASSERT(am == ia || am == ia_w || am == db_w);
+ ASSERT(!base.is(pc));
+
+ int sd, d;
+ first.split_code(&sd, &d);
+ int count = last.code() - first.code() + 1;
+ emit(cond | B27 | B26 | am | d*B22 | B20 | base.code()*B16 | sd*B12 |
+ 0xA*B8 | count);
+}
+
+
+void Assembler::vstm(BlockAddrMode am,
+ Register base,
+ SwVfpRegister first,
+ SwVfpRegister last,
+ Condition cond) {
+ // Instruction details available in ARM DDI 0406A, A8-784.
+ // cond(31-28) | 110(27-25)| PUDW0(24-20) | Rbase(19-16) |
+ // first(15-12) | 1011(11-8) | (count/2)
+ ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT_LE(first.code(), last.code());
+ ASSERT(am == ia || am == ia_w || am == db_w);
+ ASSERT(!base.is(pc));
+
+ int sd, d;
+ first.split_code(&sd, &d);
+ int count = last.code() - first.code() + 1;
+ emit(cond | B27 | B26 | am | d*B22 | base.code()*B16 | sd*B12 |
+ 0xA*B8 | count);
+}
+
static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
uint64_t i;
memcpy(&i, &d, 8);
// The original source code covered by the above license above has been
// modified significantly by Google Inc.
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// A light-weight ARM Assembler
// Generates user mode instructions for the ARM architecture up to version 5
const MemOperand& dst,
const Condition cond = al);
+ void vldm(BlockAddrMode am,
+ Register base,
+ DwVfpRegister first,
+ DwVfpRegister last,
+ Condition cond = al);
+
+ void vstm(BlockAddrMode am,
+ Register base,
+ DwVfpRegister first,
+ DwVfpRegister last,
+ Condition cond = al);
+
+ void vldm(BlockAddrMode am,
+ Register base,
+ SwVfpRegister first,
+ SwVfpRegister last,
+ Condition cond = al);
+
+ void vstm(BlockAddrMode am,
+ Register base,
+ SwVfpRegister first,
+ SwVfpRegister last,
+ Condition cond = al);
+
void vmov(const DwVfpRegister dst,
double imm,
const Condition cond = al);
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
da_x = (0|0|0) << 21, // Decrement after.
ia_x = (0|4|0) << 21, // Increment after.
db_x = (8|0|0) << 21, // Decrement before.
- ib_x = (8|4|0) << 21 // Increment before.
+ ib_x = (8|4|0) << 21, // Increment before.
+
+ kBlockAddrModeMask = (8|4|1) << 21
};
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
int Decoder::FormatVFPRegister(Instruction* instr, const char* format) {
ASSERT((format[0] == 'S') || (format[0] == 'D'));
+ VFPRegPrecision precision =
+ format[0] == 'D' ? kDoublePrecision : kSinglePrecision;
+
+ int retval = 2;
+ int reg = -1;
if (format[1] == 'n') {
- int reg = instr->VnValue();
- if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->NValue()));
- if (format[0] == 'D') PrintDRegister(reg);
- return 2;
+ reg = instr->VFPNRegValue(precision);
} else if (format[1] == 'm') {
- int reg = instr->VmValue();
- if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->MValue()));
- if (format[0] == 'D') PrintDRegister(reg);
- return 2;
+ reg = instr->VFPMRegValue(precision);
} else if (format[1] == 'd') {
- int reg = instr->VdValue();
- if (format[0] == 'S') PrintSRegister(((reg << 1) | instr->DValue()));
- if (format[0] == 'D') PrintDRegister(reg);
- return 2;
+ reg = instr->VFPDRegValue(precision);
+ if (format[2] == '+') {
+ int immed8 = instr->Immed8Value();
+ if (format[0] == 'S') reg += immed8 - 1;
+ if (format[0] == 'D') reg += (immed8 / 2 - 1);
+ }
+ if (format[2] == '+') retval = 3;
+ } else {
+ UNREACHABLE();
}
- UNREACHABLE();
- return -1;
+ if (precision == kSinglePrecision) {
+ PrintSRegister(reg);
+ } else {
+ PrintDRegister(reg);
+ }
+
+ return retval;
}
Format(instr, "vstr'cond 'Sd, ['rn + 4*'imm08@00]");
}
break;
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ case 0x9:
+ case 0xB: {
+ bool to_vfp_register = (instr->VLValue() == 0x1);
+ if (to_vfp_register) {
+ Format(instr, "vldm'cond'pu 'rn'w, {'Sd-'Sd+}");
+ } else {
+ Format(instr, "vstm'cond'pu 'rn'w, {'Sd-'Sd+}");
+ }
+ break;
+ }
default:
Unknown(instr); // Not used by V8.
- break;
}
} else if (instr->CoprocessorValue() == 0xB) {
switch (instr->OpcodeValue()) {
Format(instr, "vstr'cond 'Dd, ['rn + 4*'imm08@00]");
}
break;
+ case 0x4:
+ case 0x5:
+ case 0x9: {
+ bool to_vfp_register = (instr->VLValue() == 0x1);
+ if (to_vfp_register) {
+ Format(instr, "vldm'cond'pu 'rn'w, {'Dd-'Dd+}");
+ } else {
+ Format(instr, "vstm'cond'pu 'rn'w, {'Dd-'Dd+}");
+ }
+ break;
+ }
default:
Unknown(instr); // Not used by V8.
- break;
}
} else {
Unknown(instr); // Not used by V8.
// Optionally save all double registers.
if (save_doubles) {
- sub(sp, sp, Operand(DwVfpRegister::kNumRegisters * kDoubleSize));
- const int offset = -2 * kPointerSize;
- for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) {
- DwVfpRegister reg = DwVfpRegister::from_code(i);
- vstr(reg, fp, offset - ((i + 1) * kDoubleSize));
- }
+ DwVfpRegister first = d0;
+ DwVfpRegister last =
+ DwVfpRegister::from_code(DwVfpRegister::kNumRegisters - 1);
+ vstm(db_w, sp, first, last);
// Note that d0 will be accessible at
// fp - 2 * kPointerSize - DwVfpRegister::kNumRegisters * kDoubleSize,
// since the sp slot and code slot were pushed after the fp.
Register argument_count) {
// Optionally restore all double registers.
if (save_doubles) {
- for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) {
- DwVfpRegister reg = DwVfpRegister::from_code(i);
- const int offset = -2 * kPointerSize;
- vldr(reg, fp, offset - ((i + 1) * kDoubleSize));
- }
+ // Calculate the stack location of the saved doubles and restore them.
+ const int offset = 2 * kPointerSize;
+ sub(r3, fp, Operand(offset + DwVfpRegister::kNumRegisters * kDoubleSize));
+ DwVfpRegister first = d0;
+ DwVfpRegister last =
+ DwVfpRegister::from_code(DwVfpRegister::kNumRegisters - 1);
+ vldm(ia, r3, first, last);
}
// Clear top frame.
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
}
-// Addressing Mode 4 - Load and Store Multiple
-void Simulator::HandleRList(Instruction* instr, bool load) {
+void Simulator::ProcessPUW(Instruction* instr,
+ int num_regs,
+ int reg_size,
+ intptr_t* start_address,
+ intptr_t* end_address) {
int rn = instr->RnValue();
int32_t rn_val = get_register(rn);
- int rlist = instr->RlistValue();
- int num_regs = count_bits(rlist);
-
- intptr_t start_address = 0;
- intptr_t end_address = 0;
switch (instr->PUField()) {
case da_x: {
UNIMPLEMENTED();
break;
}
case ia_x: {
- start_address = rn_val;
- end_address = rn_val + (num_regs * 4) - 4;
- rn_val = rn_val + (num_regs * 4);
+ *start_address = rn_val;
+ *end_address = rn_val + (num_regs * reg_size) - reg_size;
+ rn_val = rn_val + (num_regs * reg_size);
break;
}
case db_x: {
- start_address = rn_val - (num_regs * 4);
- end_address = rn_val - 4;
- rn_val = start_address;
+ *start_address = rn_val - (num_regs * reg_size);
+ *end_address = rn_val - reg_size;
+ rn_val = *start_address;
break;
}
case ib_x: {
- start_address = rn_val + 4;
- end_address = rn_val + (num_regs * 4);
- rn_val = end_address;
+ *start_address = rn_val + reg_size;
+ *end_address = rn_val + (num_regs * reg_size);
+ rn_val = *end_address;
break;
}
default: {
if (instr->HasW()) {
set_register(rn, rn_val);
}
+}
+
+// Addressing Mode 4 - Load and Store Multiple
+void Simulator::HandleRList(Instruction* instr, bool load) {
+ int rlist = instr->RlistValue();
+ int num_regs = count_bits(rlist);
+
+ intptr_t start_address = 0;
+ intptr_t end_address = 0;
+ ProcessPUW(instr, num_regs, kPointerSize, &start_address, &end_address);
+
intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
int reg = 0;
while (rlist != 0) {
}
+// Addressing Mode 6 - Load and Store Multiple Coprocessor registers.
+void Simulator::HandleVList(Instruction* instr) {
+ VFPRegPrecision precision =
+ (instr->SzValue() == 0) ? kSinglePrecision : kDoublePrecision;
+ int operand_size = (precision == kSinglePrecision) ? 4 : 8;
+
+ bool load = (instr->VLValue() == 0x1);
+
+ int vd;
+ int num_regs;
+ vd = instr->VFPDRegValue(precision);
+ if (precision == kSinglePrecision) {
+ num_regs = instr->Immed8Value();
+ } else {
+ num_regs = instr->Immed8Value() / 2;
+ }
+
+ intptr_t start_address = 0;
+ intptr_t end_address = 0;
+ ProcessPUW(instr, num_regs, operand_size, &start_address, &end_address);
+
+ intptr_t* address = reinterpret_cast<intptr_t*>(start_address);
+ for (int reg = vd; reg < vd + num_regs; reg++) {
+ if (precision == kSinglePrecision) {
+ if (load) {
+ set_s_register_from_sinteger(
+ reg, ReadW(reinterpret_cast<int32_t>(address), instr));
+ } else {
+ WriteW(reinterpret_cast<int32_t>(address),
+ get_sinteger_from_s_register(reg), instr);
+ }
+ address += 1;
+ } else {
+ if (load) {
+ set_s_register_from_sinteger(
+ 2 * reg, ReadW(reinterpret_cast<int32_t>(address), instr));
+ set_s_register_from_sinteger(
+ 2 * reg + 1, ReadW(reinterpret_cast<int32_t>(address + 1), instr));
+ } else {
+ WriteW(reinterpret_cast<int32_t>(address),
+ get_sinteger_from_s_register(2 * reg), instr);
+ WriteW(reinterpret_cast<int32_t>(address + 1),
+ get_sinteger_from_s_register(2 * reg + 1), instr);
+ }
+ address += 2;
+ }
+ }
+ ASSERT_EQ(((intptr_t)address) - operand_size, end_address);
+}
+
+
// Calls into the V8 runtime are based on this very simple interface.
// Note: To be able to return two values from some calls the code in runtime.cc
// uses the ObjectPair which is essentially two 32-bit values stuffed into a
}
break;
}
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ case 0x9:
+ case 0xB:
+ // Load/store multiple single from memory: vldm/vstm.
+ HandleVList(instr);
+ break;
default:
UNIMPLEMENTED(); // Not used by V8.
- break;
}
} else if (instr->CoprocessorValue() == 0xB) {
switch (instr->OpcodeValue()) {
}
break;
}
+ case 0x4:
+ case 0x5:
+ case 0x9:
+ // Load/store multiple double from memory: vldm/vstm.
+ HandleVList(instr);
+ break;
default:
UNIMPLEMENTED(); // Not used by V8.
- break;
}
} else {
UNIMPLEMENTED(); // Not used by V8.
-// Copyright 2009 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// Helper functions to decode common "addressing" modes
int32_t GetShiftRm(Instruction* instr, bool* carry_out);
int32_t GetImm(Instruction* instr, bool* carry_out);
+ void ProcessPUW(Instruction* instr,
+ int num_regs,
+ int operand_size,
+ intptr_t* start_address,
+ intptr_t* end_address);
void HandleRList(Instruction* instr, bool load);
+ void HandleVList(Instruction* inst);
void SoftwareInterrupt(Instruction* instr);
// Stop helper functions.
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// Define these function prototypes to match JSEntryFunction in execution.cc.
typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
-typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
+typedef Object* (*F3)(void* p0, int p1, int p2, int p3, int p4);
+typedef Object* (*F4)(void* p0, void* p1, int p2, int p3, int p4);
static v8::Persistent<v8::Context> env;
TestRoundingMode(u32_f64, RN, (kMaxUInt + 1.0), kMaxUInt, true);
}
+TEST(8) {
+ // Test VFP multi load/store with ia_w.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ double g;
+ double h;
+ } D;
+ D d;
+
+ typedef struct {
+ float a;
+ float b;
+ float c;
+ float d;
+ float e;
+ float f;
+ float g;
+ float h;
+ } F;
+ F f;
+
+ // Create a function that uses vldm/vstm to move some double and
+ // single precision values around in memory.
+ Assembler assm(Isolate::Current(), NULL, 0);
+
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+
+ __ mov(ip, Operand(sp));
+ __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+ __ sub(fp, ip, Operand(4));
+
+ __ add(r4, r0, Operand(OFFSET_OF(D, a)));
+ __ vldm(ia_w, r4, d0, d3);
+ __ vldm(ia_w, r4, d4, d7);
+
+ __ add(r4, r0, Operand(OFFSET_OF(D, a)));
+ __ vstm(ia_w, r4, d6, d7);
+ __ vstm(ia_w, r4, d0, d5);
+
+ __ add(r4, r1, Operand(OFFSET_OF(F, a)));
+ __ vldm(ia_w, r4, s0, s3);
+ __ vldm(ia_w, r4, s4, s7);
+
+ __ add(r4, r1, Operand(OFFSET_OF(F, a)));
+ __ vstm(ia_w, r4, s6, s7);
+ __ vstm(ia_w, r4, s0, s5);
+
+ __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+#ifdef DEBUG
+ Code::cast(code)->Print();
+#endif
+ F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
+ d.a = 1.1;
+ d.b = 2.2;
+ d.c = 3.3;
+ d.d = 4.4;
+ d.e = 5.5;
+ d.f = 6.6;
+ d.g = 7.7;
+ d.h = 8.8;
+
+ f.a = 1.0;
+ f.b = 2.0;
+ f.c = 3.0;
+ f.d = 4.0;
+ f.e = 5.0;
+ f.f = 6.0;
+ f.g = 7.0;
+ f.h = 8.0;
+
+ Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(7.7, d.a);
+ CHECK_EQ(8.8, d.b);
+ CHECK_EQ(1.1, d.c);
+ CHECK_EQ(2.2, d.d);
+ CHECK_EQ(3.3, d.e);
+ CHECK_EQ(4.4, d.f);
+ CHECK_EQ(5.5, d.g);
+ CHECK_EQ(6.6, d.h);
+
+ CHECK_EQ(7.0, f.a);
+ CHECK_EQ(8.0, f.b);
+ CHECK_EQ(1.0, f.c);
+ CHECK_EQ(2.0, f.d);
+ CHECK_EQ(3.0, f.e);
+ CHECK_EQ(4.0, f.f);
+ CHECK_EQ(5.0, f.g);
+ CHECK_EQ(6.0, f.h);
+ }
+}
+
+
+TEST(9) {
+ // Test VFP multi load/store with ia.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ double g;
+ double h;
+ } D;
+ D d;
+
+ typedef struct {
+ float a;
+ float b;
+ float c;
+ float d;
+ float e;
+ float f;
+ float g;
+ float h;
+ } F;
+ F f;
+
+ // Create a function that uses vldm/vstm to move some double and
+ // single precision values around in memory.
+ Assembler assm(Isolate::Current(), NULL, 0);
+
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+
+ __ mov(ip, Operand(sp));
+ __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+ __ sub(fp, ip, Operand(4));
+
+ __ add(r4, r0, Operand(OFFSET_OF(D, a)));
+ __ vldm(ia, r4, d0, d3);
+ __ add(r4, r4, Operand(4 * 8));
+ __ vldm(ia, r4, d4, d7);
+
+ __ add(r4, r0, Operand(OFFSET_OF(D, a)));
+ __ vstm(ia, r4, d6, d7);
+ __ add(r4, r4, Operand(2 * 8));
+ __ vstm(ia, r4, d0, d5);
+
+ __ add(r4, r1, Operand(OFFSET_OF(F, a)));
+ __ vldm(ia, r4, s0, s3);
+ __ add(r4, r4, Operand(4 * 4));
+ __ vldm(ia, r4, s4, s7);
+
+ __ add(r4, r1, Operand(OFFSET_OF(F, a)));
+ __ vstm(ia, r4, s6, s7);
+ __ add(r4, r4, Operand(2 * 4));
+ __ vstm(ia, r4, s0, s5);
+
+ __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+#ifdef DEBUG
+ Code::cast(code)->Print();
+#endif
+ F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
+ d.a = 1.1;
+ d.b = 2.2;
+ d.c = 3.3;
+ d.d = 4.4;
+ d.e = 5.5;
+ d.f = 6.6;
+ d.g = 7.7;
+ d.h = 8.8;
+
+ f.a = 1.0;
+ f.b = 2.0;
+ f.c = 3.0;
+ f.d = 4.0;
+ f.e = 5.0;
+ f.f = 6.0;
+ f.g = 7.0;
+ f.h = 8.0;
+
+ Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(7.7, d.a);
+ CHECK_EQ(8.8, d.b);
+ CHECK_EQ(1.1, d.c);
+ CHECK_EQ(2.2, d.d);
+ CHECK_EQ(3.3, d.e);
+ CHECK_EQ(4.4, d.f);
+ CHECK_EQ(5.5, d.g);
+ CHECK_EQ(6.6, d.h);
+
+ CHECK_EQ(7.0, f.a);
+ CHECK_EQ(8.0, f.b);
+ CHECK_EQ(1.0, f.c);
+ CHECK_EQ(2.0, f.d);
+ CHECK_EQ(3.0, f.e);
+ CHECK_EQ(4.0, f.f);
+ CHECK_EQ(5.0, f.g);
+ CHECK_EQ(6.0, f.h);
+ }
+}
+
+
+TEST(10) {
+ // Test VFP multi load/store with db_w.
+ InitializeVM();
+ v8::HandleScope scope;
+
+ typedef struct {
+ double a;
+ double b;
+ double c;
+ double d;
+ double e;
+ double f;
+ double g;
+ double h;
+ } D;
+ D d;
+
+ typedef struct {
+ float a;
+ float b;
+ float c;
+ float d;
+ float e;
+ float f;
+ float g;
+ float h;
+ } F;
+ F f;
+
+ // Create a function that uses vldm/vstm to move some double and
+ // single precision values around in memory.
+ Assembler assm(Isolate::Current(), NULL, 0);
+
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+
+ __ mov(ip, Operand(sp));
+ __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+ __ sub(fp, ip, Operand(4));
+
+ __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8));
+ __ vldm(db_w, r4, d4, d7);
+ __ vldm(db_w, r4, d0, d3);
+
+ __ add(r4, r0, Operand(OFFSET_OF(D, h) + 8));
+ __ vstm(db_w, r4, d0, d5);
+ __ vstm(db_w, r4, d6, d7);
+
+ __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4));
+ __ vldm(db_w, r4, s4, s7);
+ __ vldm(db_w, r4, s0, s3);
+
+ __ add(r4, r1, Operand(OFFSET_OF(F, h) + 4));
+ __ vstm(db_w, r4, s0, s5);
+ __ vstm(db_w, r4, s6, s7);
+
+ __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Object* code = HEAP->CreateCode(
+ desc,
+ Code::ComputeFlags(Code::STUB),
+ Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
+ CHECK(code->IsCode());
+#ifdef DEBUG
+ Code::cast(code)->Print();
+#endif
+ F4 fn = FUNCTION_CAST<F4>(Code::cast(code)->entry());
+ d.a = 1.1;
+ d.b = 2.2;
+ d.c = 3.3;
+ d.d = 4.4;
+ d.e = 5.5;
+ d.f = 6.6;
+ d.g = 7.7;
+ d.h = 8.8;
+
+ f.a = 1.0;
+ f.b = 2.0;
+ f.c = 3.0;
+ f.d = 4.0;
+ f.e = 5.0;
+ f.f = 6.0;
+ f.g = 7.0;
+ f.h = 8.0;
+
+ Object* dummy = CALL_GENERATED_CODE(fn, &d, &f, 0, 0, 0);
+ USE(dummy);
+
+ CHECK_EQ(7.7, d.a);
+ CHECK_EQ(8.8, d.b);
+ CHECK_EQ(1.1, d.c);
+ CHECK_EQ(2.2, d.d);
+ CHECK_EQ(3.3, d.e);
+ CHECK_EQ(4.4, d.f);
+ CHECK_EQ(5.5, d.g);
+ CHECK_EQ(6.6, d.h);
+
+ CHECK_EQ(7.0, f.a);
+ CHECK_EQ(8.0, f.b);
+ CHECK_EQ(1.0, f.c);
+ CHECK_EQ(2.0, f.d);
+ CHECK_EQ(3.0, f.e);
+ CHECK_EQ(4.0, f.f);
+ CHECK_EQ(5.0, f.g);
+ CHECK_EQ(6.0, f.h);
+ }
+}
+
#undef __
-// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
"aef1aa10 vmrsge r10, FPSCR");
COMPARE(vmrs(pc),
"eef1fa10 vmrs APSR, FPSCR");
+
+ COMPARE(vstm(ia, r0, d1, d3),
+ "ec801b06 vstmia r0, {d1-d3}");
+ COMPARE(vldm(ia, r1, d2, d5),
+ "ec912b08 vldmia r1, {d2-d5}");
+ COMPARE(vstm(ia, r2, d0, d15),
+ "ec820b20 vstmia r2, {d0-d15}");
+ COMPARE(vldm(ia, r3, d0, d15),
+ "ec930b20 vldmia r3, {d0-d15}");
+ COMPARE(vstm(ia, r4, s1, s3),
+ "ecc40a03 vstmia r4, {s1-s3}");
+ COMPARE(vldm(ia, r5, s2, s5),
+ "ec951a04 vldmia r5, {s2-s5}");
+ COMPARE(vstm(ia, r6, s0, s31),
+ "ec860a20 vstmia r6, {s0-s31}");
+ COMPARE(vldm(ia, r7, s0, s31),
+ "ec970a20 vldmia r7, {s0-s31}");
}
VERIFY_RUN();