зеркало из https://github.com/mozilla/gecko-dev.git
Bug 876064 - Implement constant pools for double constants on x64. r=sstangl
This commit is contained in:
Родитель
38f407f42c
Коммит
09d1348447
|
@ -386,27 +386,22 @@ class MacroAssemblerX86Shared : public Assembler
|
|||
bind(&done);
|
||||
}
|
||||
|
||||
bool maybeInlineDouble(uint64_t u, const FloatRegister &dest) {
|
||||
// This implements parts of "13.4 Generating constants" of
|
||||
// "2. Optimizing subroutines in assembly language" by Agner Fog,
|
||||
// generalized to handle any case that can use a pcmpeqw and
|
||||
// up to two shifts.
|
||||
bool maybeInlineDouble(double d, const FloatRegister &dest) {
|
||||
uint64_t u = mozilla::BitwiseCast<uint64_t>(d);
|
||||
|
||||
// Loading zero with xor is specially optimized in hardware.
|
||||
if (u == 0) {
|
||||
xorpd(dest, dest);
|
||||
return true;
|
||||
}
|
||||
|
||||
int tz = js_bitscan_ctz64(u);
|
||||
int lz = js_bitscan_clz64(u);
|
||||
if (u == (~uint64_t(0) << (lz + tz) >> lz)) {
|
||||
pcmpeqw(dest, dest);
|
||||
if (tz != 0)
|
||||
psllq(Imm32(lz + tz), dest);
|
||||
if (lz != 0)
|
||||
psrlq(Imm32(lz), dest);
|
||||
return true;
|
||||
}
|
||||
// It is also possible to load several common constants using pcmpeqw
|
||||
// to get all ones and then psllq and psrlq to get zeros at the ends,
|
||||
// as described in "13.4 Generating constants" of
|
||||
// "2. Optimizing subroutines in assembly language" by Agner Fog, and as
|
||||
// previously implemented here. However, with x86 and x64 both using
|
||||
// constant pool loads for double constants, this is probably only
|
||||
// worthwhile in cases where a load is likely to be delayed.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -8,12 +8,65 @@
|
|||
#include "ion/BaselineFrame.h"
|
||||
#include "ion/MoveEmitter.h"
|
||||
#include "ion/IonFrames.h"
|
||||
#include "mozilla/Casting.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::ion;
|
||||
|
||||
void
|
||||
MacroAssemblerX64::loadConstantDouble(double d, const FloatRegister &dest)
|
||||
{
|
||||
if (maybeInlineDouble(d, dest))
|
||||
return;
|
||||
|
||||
if (!doubleMap_.initialized()) {
|
||||
enoughMemory_ &= doubleMap_.init();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
}
|
||||
size_t doubleIndex;
|
||||
DoubleMap::AddPtr p = doubleMap_.lookupForAdd(d);
|
||||
if (p) {
|
||||
doubleIndex = p->value;
|
||||
} else {
|
||||
doubleIndex = doubles_.length();
|
||||
enoughMemory_ &= doubles_.append(Double(d));
|
||||
enoughMemory_ &= doubleMap_.add(p, d, doubleIndex);
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
}
|
||||
Double &dbl = doubles_[doubleIndex];
|
||||
JS_ASSERT(!dbl.uses.bound());
|
||||
|
||||
// The constants will be stored in a pool appended to the text (see
|
||||
// finish()), so they will always be a fixed distance from the
|
||||
// instructions which reference them. This allows the instructions to use
|
||||
// PC-relative addressing. Use "jump" label support code, because we need
|
||||
// the same PC-relative address patching that jumps use.
|
||||
JmpSrc j = masm.movsd_ripr(dest.code());
|
||||
JmpSrc prev = JmpSrc(dbl.uses.use(j.offset()));
|
||||
masm.setNextJump(j, prev);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::finish()
|
||||
{
|
||||
JS_STATIC_ASSERT(CodeAlignment >= sizeof(double));
|
||||
|
||||
if (!doubles_.empty())
|
||||
masm.align(sizeof(double));
|
||||
|
||||
for (size_t i = 0; i < doubles_.length(); i++) {
|
||||
Double &dbl = doubles_[i];
|
||||
bind(&dbl.uses);
|
||||
masm.doubleConstant(dbl.value);
|
||||
}
|
||||
|
||||
MacroAssemblerX86Shared::finish();
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::setupABICall(uint32_t args)
|
||||
{
|
||||
|
|
|
@ -45,6 +45,16 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
bool dynamicAlignment_;
|
||||
bool enoughMemory_;
|
||||
|
||||
struct Double {
|
||||
double value;
|
||||
NonAssertingLabel uses;
|
||||
Double(double value) : value(value) {}
|
||||
};
|
||||
Vector<Double, 0, IonAllocPolicy> doubles_;
|
||||
|
||||
typedef HashMap<double, size_t, DefaultHasher<double>, IonAllocPolicy> DoubleMap;
|
||||
DoubleMap doubleMap_;
|
||||
|
||||
void setupABICall(uint32_t arg);
|
||||
|
||||
protected:
|
||||
|
@ -71,6 +81,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
{
|
||||
}
|
||||
|
||||
// The buffer is about to be linked, make sure any constant pools or excess
|
||||
// bookkeeping has been flushed to the instruction stream.
|
||||
void finish();
|
||||
|
||||
bool oom() const {
|
||||
return MacroAssemblerX86Shared::oom() || !enoughMemory_;
|
||||
}
|
||||
|
@ -938,17 +952,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
|||
cvtsi2sd(operand.valueReg(), dest);
|
||||
}
|
||||
|
||||
void loadConstantDouble(double d, const FloatRegister &dest) {
|
||||
union DoublePun {
|
||||
uint64_t u;
|
||||
double d;
|
||||
} pun;
|
||||
pun.d = d;
|
||||
if (!maybeInlineDouble(pun.u, dest)) {
|
||||
mov(ImmWord(pun.u), ScratchReg);
|
||||
movqsd(ScratchReg, dest);
|
||||
}
|
||||
}
|
||||
void loadConstantDouble(double d, const FloatRegister &dest);
|
||||
void loadStaticDouble(const double *dp, const FloatRegister &dest) {
|
||||
loadConstantDouble(*dp, dest);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "ion/BaselineFrame.h"
|
||||
#include "ion/MoveEmitter.h"
|
||||
#include "ion/IonFrames.h"
|
||||
#include "mozilla/Casting.h"
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
|
@ -17,12 +18,7 @@ using namespace js::ion;
|
|||
void
|
||||
MacroAssemblerX86::loadConstantDouble(double d, const FloatRegister &dest)
|
||||
{
|
||||
union DoublePun {
|
||||
uint64_t u;
|
||||
double d;
|
||||
} dpun;
|
||||
dpun.d = d;
|
||||
if (maybeInlineDouble(dpun.u, dest))
|
||||
if (maybeInlineDouble(d, dest))
|
||||
return;
|
||||
|
||||
if (!doubleMap_.initialized()) {
|
||||
|
@ -42,10 +38,21 @@ MacroAssemblerX86::loadConstantDouble(double d, const FloatRegister &dest)
|
|||
return;
|
||||
}
|
||||
Double &dbl = doubles_[doubleIndex];
|
||||
masm.movsd_mr(reinterpret_cast<void *>(dbl.uses.prev()), dest.code());
|
||||
JS_ASSERT(!dbl.uses.bound());
|
||||
|
||||
masm.movsd_mr(reinterpret_cast<const void *>(dbl.uses.prev()), dest.code());
|
||||
dbl.uses.setPrev(masm.size());
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::loadStaticDouble(const double *dp, const FloatRegister &dest) {
|
||||
if (maybeInlineDouble(*dp, dest))
|
||||
return;
|
||||
|
||||
// x86 can just load from any old immediate address.
|
||||
movsd(dp, dest);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::finish()
|
||||
{
|
||||
|
|
|
@ -793,9 +793,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
|||
}
|
||||
|
||||
void loadConstantDouble(double d, const FloatRegister &dest);
|
||||
void loadStaticDouble(const double *dp, const FloatRegister &dest) {
|
||||
movsd(dp, dest);
|
||||
}
|
||||
void loadStaticDouble(const double *dp, const FloatRegister &dest);
|
||||
|
||||
void branchTruncateDouble(const FloatRegister &src, const Register &dest, Label *fail) {
|
||||
const uint32_t IndefiniteIntegerValue = 0x80000000;
|
||||
|
|
Загрузка…
Ссылка в новой задаче