Bug 995230 - Inline Math.clz32. r=jandem

This commit is contained in:
Tom Schuster 2014-08-23 12:58:22 +02:00
Родитель 077e9036e0
Коммит d7bd05a650
16 изменённых файлов: 187 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,28 @@
function f() {
var x = 0;
for (var i = 1; i < 1e6; i++) {
if (i > 0)
x += Math.clz32(i);
}
return x;
}
function g() {
var x = 0;
for (var i = 1; i < 1e6; i++) {
x += Math.clz32(i);
}
return x;
}
function h() {
var x = 0;
for (var i = 0; i < 1e6; i++) {
x += Math.clz32(i);
}
return x;
}
assertEq(f(), 13048543);
assertEq(g(), 13048543);
assertEq(h(), 13048575);

Просмотреть файл

@ -684,6 +684,7 @@ class IonBuilder : public MIRGenerator
InliningStatus inlineMathAbs(CallInfo &callInfo);
InliningStatus inlineMathFloor(CallInfo &callInfo);
InliningStatus inlineMathCeil(CallInfo &callInfo);
InliningStatus inlineMathClz32(CallInfo &callInfo);
InliningStatus inlineMathRound(CallInfo &callInfo);
InliningStatus inlineMathSqrt(CallInfo &callInfo);
InliningStatus inlineMathAtan2(CallInfo &callInfo);

Просмотреть файл

@ -2677,6 +2677,20 @@ class LAbsF : public LInstructionHelper<1, 1, 0>
}
};
// Count leading zeroes
class LClzI : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(ClzI)
LClzI(const LAllocation &num) {
setOperand(0, num);
}
MClz *mir() const {
return mir_->toClz();
}
};
// Square root of a double.
class LSqrtD : public LInstructionHelper<1, 1, 0>
{

Просмотреть файл

@ -115,6 +115,7 @@
_(AbsI) \
_(AbsD) \
_(AbsF) \
_(ClzI) \
_(SqrtD) \
_(SqrtF) \
_(Atan2D) \

Просмотреть файл

@ -1296,6 +1296,15 @@ LIRGenerator::visitAbs(MAbs *ins)
return defineReuseInput(lir, ins, 0);
}
bool
LIRGenerator::visitClz(MClz *ins)
{
MDefinition *num = ins->num();
LClzI *lir = new(alloc()) LClzI(useRegisterAtStart(num));
return define(lir, ins);
}
bool
LIRGenerator::visitSqrt(MSqrt *ins)
{

Просмотреть файл

@ -125,6 +125,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitRound(MRound *ins);
bool visitMinMax(MMinMax *ins);
bool visitAbs(MAbs *ins);
bool visitClz(MClz *ins);
bool visitSqrt(MSqrt *ins);
bool visitAtan2(MAtan2 *ins);
bool visitHypot(MHypot *ins);

Просмотреть файл

@ -54,6 +54,8 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
return inlineMathFloor(callInfo);
if (native == js::math_ceil)
return inlineMathCeil(callInfo);
if (native == js::math_clz32)
return inlineMathClz32(callInfo);
if (native == js::math_round)
return inlineMathRound(callInfo);
if (native == js::math_sqrt)
@ -791,6 +793,31 @@ IonBuilder::inlineMathCeil(CallInfo &callInfo)
return InliningStatus_NotInlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineMathClz32(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
if (callInfo.argc() != 1)
return InliningStatus_NotInlined;
MIRType returnType = getInlineReturnType();
if (returnType != MIRType_Int32)
return InliningStatus_NotInlined;
if (!IsNumberType(callInfo.getArg(0)->type()))
return InliningStatus_NotInlined;
callInfo.setImplicitlyUsedUnchecked();
MClz *ins = MClz::New(alloc(), callInfo.getArg(0));
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineMathRound(CallInfo &callInfo)
{

Просмотреть файл

@ -3424,6 +3424,19 @@ MSqrt::trySpecializeFloat32(TempAllocator &alloc) {
setPolicyType(MIRType_Float32);
}
MDefinition *
MClz::foldsTo(TempAllocator &alloc)
{
if (num()->isConstant()) {
int32_t n = num()->toConstant()->value().toInt32();
if (n == 0)
return MConstant::New(alloc, Int32Value(32));
return MConstant::New(alloc, Int32Value(mozilla::CountLeadingZeroes32(n)));
}
return this;
}
MDefinition *
MBoundsCheck::foldsTo(TempAllocator &alloc)
{

Просмотреть файл

@ -4531,6 +4531,50 @@ class MAbs
ALLOW_CLONE(MAbs)
};
class MClz
: public MUnaryInstruction
, public BitwisePolicy
{
bool operandIsNeverZero_;
MClz(MDefinition *num)
: MUnaryInstruction(num),
operandIsNeverZero_(false)
{
JS_ASSERT(IsNumberType(num->type()));
specialization_ = MIRType_Int32;
setResultType(MIRType_Int32);
setMovable();
}
public:
INSTRUCTION_HEADER(Clz)
static MClz *New(TempAllocator &alloc, MDefinition *num) {
return new(alloc) MClz(num);
}
MDefinition *num() const {
return getOperand(0);
}
TypePolicy *typePolicy() {
return this;
}
bool congruentTo(const MDefinition *ins) const {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const {
return AliasSet::None();
}
bool operandIsNeverZero() const {
return operandIsNeverZero_;
}
MDefinition *foldsTo(TempAllocator &alloc);
void computeRange(TempAllocator &alloc);
void collectRangeInfoPreTrunc();
};
// Inline implementation of Math.sqrt().
class MSqrt
: public MUnaryInstruction,

Просмотреть файл

@ -63,6 +63,7 @@ namespace jit {
_(Ursh) \
_(MinMax) \
_(Abs) \
_(Clz) \
_(Sqrt) \
_(Atan2) \
_(Hypot) \

Просмотреть файл

@ -161,6 +161,7 @@ class ParallelSafetyVisitor : public MDefinitionVisitor
SAFE_OP(Ursh)
SPECIALIZED_OP(MinMax, PERMIT_NUMERIC)
SAFE_OP(Abs)
SAFE_OP(Clz)
SAFE_OP(Sqrt)
UNSAFE_OP(Atan2)
UNSAFE_OP(Hypot)

Просмотреть файл

@ -1228,6 +1228,12 @@ MCeil::computeRange(TempAllocator &alloc)
setRange(Range::ceil(alloc, &other));
}
void
MClz::computeRange(TempAllocator &alloc)
{
setRange(Range::NewUInt32Range(alloc, 0, 32));
}
void
MMinMax::computeRange(TempAllocator &alloc)
{
@ -2667,6 +2673,14 @@ MLoadElementHole::collectRangeInfoPreTrunc()
needsNegativeIntCheck_ = false;
}
void
MClz::collectRangeInfoPreTrunc()
{
Range inputRange(input());
if (!inputRange.canBeZero())
operandIsNeverZero_ = true;
}
void
MDiv::collectRangeInfoPreTrunc()
{

Просмотреть файл

@ -1160,6 +1160,9 @@ class AssemblerX86Shared : public AssemblerShared
MOZ_CRASH("unexpected operand kind");
}
}
void bsr(const Register &src, const Register &dest) {
masm.bsr_rr(src.code(), dest.code());
}
void imull(Register multiplier) {
masm.imull_r(multiplier.code());
}

Просмотреть файл

@ -324,6 +324,7 @@ private:
OP_SETCC = 0x90,
OP2_IMUL_GvEv = 0xAF,
OP2_CMPXCHG_GvEw = 0xB1,
OP2_BSR_GvEv = 0xBD,
OP2_MOVSX_GvEb = 0xBE,
OP2_MOVSX_GvEw = 0xBF,
OP2_MOVZX_GvEb = 0xB6,
@ -1301,6 +1302,12 @@ public:
}
#endif
void bsr_rr(RegisterID src, RegisterID dst)
{
spew("bsr %s, %s", nameIReg(4, src), nameIReg(4, dst));
m_formatter.twoByteOp(OP2_BSR_GvEv, dst, src);
}
void imull_rr(RegisterID src, RegisterID dst)
{
spew("imull %s, %s", nameIReg(4,src), nameIReg(4, dst));

Просмотреть файл

@ -544,6 +544,28 @@ CodeGeneratorX86Shared::visitAbsF(LAbsF *ins)
return true;
}
bool
CodeGeneratorX86Shared::visitClzI(LClzI *ins)
{
Register input = ToRegister(ins->input());
Register output = ToRegister(ins->output());
// bsr is undefined on 0
Label done, nonzero;
if (!ins->mir()->operandIsNeverZero()) {
masm.testl(input, input);
masm.j(Assembler::NonZero, &nonzero);
masm.move32(Imm32(32), output);
masm.jump(&done);
}
masm.bind(&nonzero);
masm.bsr(input, output);
masm.xor32(Imm32(0x1F), output);
masm.bind(&done);
return true;
}
bool
CodeGeneratorX86Shared::visitSqrtD(LSqrtD *ins)
{

Просмотреть файл

@ -153,6 +153,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
virtual bool visitMinMaxD(LMinMaxD *ins);
virtual bool visitAbsD(LAbsD *ins);
virtual bool visitAbsF(LAbsF *ins);
virtual bool visitClzI(LClzI *ins);
virtual bool visitSqrtD(LSqrtD *ins);
virtual bool visitSqrtF(LSqrtF *ins);
virtual bool visitPowHalfD(LPowHalfD *ins);