Revision: 5037
Author: [email protected]
Date: Thu Jul 8 05:38:02 2010
Log: ARM: Add support for the VFP mov literal instruction and mov
between single VFP registers. Math.pow implementation has
been updated with the new instructions. This is a commit
of http://codereview.chromium.org/2813046/show for Rodolph
Perfetta.
http://code.google.com/p/v8/source/detail?r=5037
Modified:
/branches/bleeding_edge/src/arm/assembler-arm.cc
/branches/bleeding_edge/src/arm/assembler-arm.h
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/constants-arm.cc
/branches/bleeding_edge/src/arm/constants-arm.h
/branches/bleeding_edge/src/arm/disasm-arm.cc
/branches/bleeding_edge/src/arm/simulator-arm.cc
/branches/bleeding_edge/test/cctest/test-disasm-arm.cc
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Wed Jun 30 05:22:15
2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.cc Thu Jul 8 05:38:02
2010
@@ -1799,6 +1799,113 @@
emit(cond | 0xD8*B20 | base.code()*B16 | src.code()*B12 |
0xB*B8 | ((offset / 4) & 255));
}
+
+
+static void DoubleAsTwoUInt32(double d, uint32_t* lo, uint32_t* hi) {
+ uint64_t i;
+ memcpy(&i, &d, 8);
+
+ *lo = i & 0xffffffff;
+ *hi = i >> 32;
+}
+
+// Only works for little endian floating point formats.
+// We don't support VFP on the mixed endian floating point platform.
+static bool FitsVMOVDoubleImmediate(double d, uint32_t *encoding) {
+ ASSERT(CpuFeatures::IsEnabled(VFP3));
+
+ // VMOV can accept an immediate of the form:
+ //
+ // +/- m * 2^(-n) where 16 <= m <= 31 and 0 <= n <= 7
+ //
+ // The immediate is encoded using an 8-bit quantity, comprised of two
+ // 4-bit fields. For an 8-bit immediate of the form:
+ //
+ // [abcdefgh]
+ //
+ // where a is the MSB and h is the LSB, an immediate 64-bit double can be
+ // created of the form:
+ //
+ // [aBbbbbbb,bbcdefgh,00000000,00000000,
+ // 00000000,00000000,00000000,00000000]
+ //
+ // where B = ~b.
+ //
+
+ uint32_t lo, hi;
+ DoubleAsTwoUInt32(d, &lo, &hi);
+
+ // The most obvious constraint is the long block of zeroes.
+ if ((lo != 0) || ((hi & 0xffff) != 0)) {
+ return false;
+ }
+
+ // Bits 62:55 must be all clear or all set.
+ if (((hi & 0x3fc00000) != 0) && ((hi & 0x3fc00000) != 0x3fc00000)) {
+ return false;
+ }
+
+ // Bit 63 must be NOT bit 62.
+ if (((hi ^ (hi << 1)) & (0x40000000)) == 0) {
+ return false;
+ }
+
+ // Create the encoded immediate in the form:
+ // [00000000,0000abcd,00000000,0000efgh]
+ *encoding = (hi >> 16) & 0xf; // Low nybble.
+ *encoding |= (hi >> 4) & 0x70000; // Low three bits of the high nybble.
+ *encoding |= (hi >> 12) & 0x80000; // Top bit of the high nybble.
+
+ return true;
+}
+
+
+void Assembler::vmov(const DwVfpRegister dst,
+ double imm,
+ const Condition cond) {
+ // Dd = immediate
+ // Instruction details available in ARM DDI 0406B, A8-640.
+ ASSERT(CpuFeatures::IsEnabled(VFP3));
+
+ uint32_t enc;
+ if (FitsVMOVDoubleImmediate(imm, &enc)) {
+ // The double can be encoded in the instruction.
+ emit(cond | 0xE*B24 | 0xB*B20 | dst.code()*B12 | 0xB*B8 | enc);
+ } else {
+ // Synthesise the double from ARM immediates. This could be implemented
+ // using vldr from a constant pool.
+ uint32_t lo, hi;
+ DoubleAsTwoUInt32(imm, &lo, &hi);
+
+ if (lo == hi) {
+ // If the lo and hi parts of the double are equal, the literal is
easier
+ // to create. This is the case with 0.0.
+ mov(ip, Operand(lo));
+ vmov(dst, ip, ip);
+ } else {
+ // Move the low part of the double into the lower of the
corresponsing S
+ // registers of D register dst.
+ mov(ip, Operand(lo));
+ vmov(dst.low(), ip, cond);
+
+ // Move the high part of the double into the higher of the
corresponsing S
+ // registers of D register dst.
+ mov(ip, Operand(hi));
+ vmov(dst.high(), ip, cond);
+ }
+ }
+}
+
+
+void Assembler::vmov(const SwVfpRegister dst,
+ const SwVfpRegister src,
+ const Condition cond) {
+ // Sd = Sm
+ // Instruction details available in ARM DDI 0406B, A8-642.
+ ASSERT(CpuFeatures::IsEnabled(VFP3));
+ emit(cond | 0xE*B24 | 0xB*B20 |
+ dst.code()*B12 | 0x5*B9 | B6 | src.code());
+}
void Assembler::vmov(const DwVfpRegister dst,
@@ -1806,6 +1913,7 @@
const Condition cond) {
// Dd = Dm
// Instruction details available in ARM DDI 0406B, A8-642.
+ ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(cond | 0xE*B24 | 0xB*B20 |
dst.code()*B12 | 0x5*B9 | B8 | B6 | src.code());
}
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h Wed Jun 30 05:22:15 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h Thu Jul 8 05:38:02 2010
@@ -130,6 +130,20 @@
// Supporting d0 to d15, can be later extended to d31.
bool is_valid() const { return 0 <= code_ && code_ < 16; }
bool is(DwVfpRegister reg) const { return code_ == reg.code_; }
+ SwVfpRegister low() const {
+ SwVfpRegister reg;
+ reg.code_ = code_ * 2;
+
+ ASSERT(reg.is_valid());
+ return reg;
+ }
+ SwVfpRegister high() const {
+ SwVfpRegister reg;
+ reg.code_ = (code_ * 2) + 1;
+
+ ASSERT(reg.is_valid());
+ return reg;
+ }
int code() const {
ASSERT(is_valid());
return code_;
@@ -931,6 +945,12 @@
int offset, // Offset must be a multiple of 4.
const Condition cond = al);
+ void vmov(const DwVfpRegister dst,
+ double imm,
+ const Condition cond = al);
+ void vmov(const SwVfpRegister dst,
+ const SwVfpRegister src,
+ const Condition cond = al);
void vmov(const DwVfpRegister dst,
const DwVfpRegister src,
const Condition cond = al);
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Tue Jul 6 06:43:21 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Jul 8 05:38:02 2010
@@ -4343,9 +4343,7 @@
__ bind(&powi);
// Load 1.0 into d0.
- __ mov(scratch2, Operand(0x3ff00000));
- __ mov(scratch1, Operand(0));
- __ vmov(d0, scratch1, scratch2);
+ __ vmov(d0, 1.0);
// Get the absolute untagged value of the exponent and use that for the
// calculation.
@@ -4405,9 +4403,7 @@
AVOID_NANS_AND_INFINITIES);
// Load 1.0 into d2.
- __ mov(scratch2, Operand(0x3ff00000));
- __ mov(scratch1, Operand(0));
- __ vmov(d2, scratch1, scratch2);
+ __ vmov(d2, 1.0);
// Calculate the reciprocal of the square root. 1/sqrt(x) = sqrt(1/x).
__ vdiv(d0, d2, d0);
=======================================
--- /branches/bleeding_edge/src/arm/constants-arm.cc Wed Jun 30 01:46:19
2010
+++ /branches/bleeding_edge/src/arm/constants-arm.cc Thu Jul 8 05:38:02
2010
@@ -37,6 +37,26 @@
namespace v8i = v8::internal;
+double Instr::DoubleImmedVmov() const {
+ // Reconstruct a double from the immediate encoded in the vmov
instruction.
+ //
+ // instruction: [xxxxxxxx,xxxxabcd,xxxxxxxx,xxxxefgh]
+ // double: [aBbbbbbb,bbcdefgh,00000000,00000000,
+ // 00000000,00000000,00000000,00000000]
+ //
+ // where B = ~b. Only the high 16 bits are affected.
+ uint64_t high16;
+ high16 = (Bits(17, 16) << 4) | Bits(3, 0); // xxxxxxxx,xxcdefgh.
+ high16 |= (0xff * Bit(18)) << 6; // xxbbbbbb,bbxxxxxx.
+ high16 |= (Bit(18) ^ 1) << 14; // xBxxxxxx,xxxxxxxx.
+ high16 |= Bit(19) << 15; // axxxxxxx,xxxxxxxx.
+
+ uint64_t imm = high16 << 48;
+ double d;
+ memcpy(&d, &imm, 8);
+ return d;
+}
+
// These register names are defined in a way to match the native
disassembler
// formatting. See for example the command "objdump -d <binary file>".
=======================================
--- /branches/bleeding_edge/src/arm/constants-arm.h Tue Jun 22 01:38:32 2010
+++ /branches/bleeding_edge/src/arm/constants-arm.h Thu Jul 8 05:38:02 2010
@@ -332,6 +332,9 @@
inline bool HasSign() const { return SignField() == 1; }
inline bool HasH() const { return HField() == 1; }
inline bool HasLink() const { return LinkField() == 1; }
+
+ // Decoding the double immediate in the vmov instruction.
+ double DoubleImmedVmov() const;
// Instructions are read of out a code stream. The only way to get a
// reference to an instruction is to convert a pointer. There is no way
=======================================
--- /branches/bleeding_edge/src/arm/disasm-arm.cc Wed Jun 30 05:22:15 2010
+++ /branches/bleeding_edge/src/arm/disasm-arm.cc Thu Jul 8 05:38:02 2010
@@ -412,6 +412,12 @@
PrintCondition(instr);
return 4;
}
+ case 'd': { // 'd: vmov double immediate.
+ double d = instr->DoubleImmedVmov();
+ out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
+ "#%g", d);
+ return 1;
+ }
case 'f': { // 'f: bitfield instructions - v7 and above.
uint32_t lsbit = instr->Bits(11, 7);
uint32_t width = instr->Bits(20, 16) + 1;
@@ -1052,7 +1058,7 @@
if (instr->SzField() == 0x1) {
Format(instr, "vmov.f64'cond 'Dd, 'Dm");
} else {
- Unknown(instr); // Not used by V8.
+ Format(instr, "vmov.f32'cond 'Sd, 'Sm");
}
} else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() ==
0x3)) {
DecodeVCVTBetweenDoubleAndSingle(instr);
@@ -1066,6 +1072,12 @@
DecodeVCMP(instr);
} else if (((instr->Opc2Field() == 0x1)) && (instr->Opc3Field() ==
0x3)) {
Format(instr, "vsqrt.f64'cond 'Dd, 'Dm");
+ } else if (instr->Opc3Field() == 0x0) {
+ if (instr->SzField() == 0x1) {
+ Format(instr, "vmov.f64'cond 'Dd, 'd");
+ } else {
+ Unknown(instr); // Not used by V8.
+ }
} else {
Unknown(instr); // Not used by V8.
}
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Wed Jun 30 05:22:15
2010
+++ /branches/bleeding_edge/src/arm/simulator-arm.cc Thu Jul 8 05:38:02
2010
@@ -2281,7 +2281,7 @@
if (instr->SzField() == 0x1) {
set_d_register_from_double(vd, get_double_from_d_register(vm));
} else {
- UNREACHABLE(); // Not used by V8.
+ set_s_register_from_float(vd, get_float_from_s_register(vm));
}
} else if ((instr->Opc2Field() == 0x7) && (instr->Opc3Field() ==
0x3)) {
DecodeVCVTBetweenDoubleAndSingle(instr);
@@ -2298,6 +2298,13 @@
double dm_value = get_double_from_d_register(vm);
double dd_value = sqrt(dm_value);
set_d_register_from_double(vd, dd_value);
+ } else if (instr->Opc3Field() == 0x0) {
+ // vmov immediate.
+ if (instr->SzField() == 0x1) {
+ set_d_register_from_double(vd, instr->DoubleImmedVmov());
+ } else {
+ UNREACHABLE(); // Not used by v8.
+ }
} else {
UNREACHABLE(); // Not used by V8.
}
=======================================
--- /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Wed Jun 30
05:22:15 2010
+++ /branches/bleeding_edge/test/cctest/test-disasm-arm.cc Thu Jul 8
05:38:02 2010
@@ -437,6 +437,11 @@
"eeb10bc0 vsqrt.f64 d0, d0");
COMPARE(vsqrt(d2, d3, ne),
"1eb12bc3 vsqrt.f64ne d2, d3");
+
+ COMPARE(vmov(d0, 1.0),
+ "eeb70b00 vmov.f64 d0, #1");
+ COMPARE(vmov(d2, -13.0),
+ "eeba2b0a vmov.f64 d2, #-13");
}
VERIFY_RUN();
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev