зеркало из https://github.com/mozilla/gecko-dev.git
Bug 995230 - Inline Math.clz32. r=jandem
This commit is contained in:
Родитель
077e9036e0
Коммит
d7bd05a650
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче