зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1316803 part 2 - optimize division for constant rhs. r=lth
This commit is contained in:
Родитель
0aaea58b69
Коммит
6fdff8030c
|
@ -107,10 +107,20 @@ testBinary32('add', 40, 2, 42);
|
|||
testBinary32('sub', 40, 2, 38);
|
||||
testBinary32('mul', 40, 2, 80);
|
||||
testBinary32('div_s', -40, 2, -20);
|
||||
testBinary32('div_s', -40, 8, -5);
|
||||
testBinary32('div_s', -40, 7, -5);
|
||||
testBinary32('div_s', 40, 8, 5);
|
||||
testBinary32('div_s', 40, 7, 5);
|
||||
testBinary32('div_u', -40, 2, 2147483628);
|
||||
testBinary32('div_u', 40, 2, 20);
|
||||
testBinary32('div_u', 40, 8, 5);
|
||||
testBinary32('rem_s', 40, -3, 1);
|
||||
testBinary32('rem_s', 0, -3, 0);
|
||||
testBinary32('rem_s', 5, 2, 1);
|
||||
testBinary32('rem_s', 65, 64, 1);
|
||||
testBinary32('rem_s', -65, 64, -1);
|
||||
testBinary32('rem_u', 40, -3, 40);
|
||||
testBinary32('rem_u', 41, 8, 1);
|
||||
testBinary32('and', 42, 6, 2);
|
||||
testBinary32('or', 42, 6, 46);
|
||||
testBinary32('xor', 42, 2, 40);
|
||||
|
@ -167,16 +177,26 @@ assertEq(testTrunc(13.37), 1);
|
|||
testBinary64('mul', "0x80000000", 2, "0x100000000");
|
||||
testBinary64('mul', "0x7fffffff", 2, "0xfffffffe");
|
||||
testBinary64('div_s', -40, 2, -20);
|
||||
testBinary64('div_s', -40, 8, -5);
|
||||
testBinary64('div_s', -40, 7, -5);
|
||||
testBinary64('div_s', 40, 8, 5);
|
||||
testBinary64('div_s', 40, 7, 5);
|
||||
testBinary64('div_s', "0x1234567887654321", 2, "0x91a2b3c43b2a190");
|
||||
testBinary64('div_s', "0x1234567887654321", "0x1000000000", "0x1234567");
|
||||
testBinary64('div_u', -40, 2, "0x7fffffffffffffec");
|
||||
testBinary64('div_u', "0x1234567887654321", 9, "0x205d0b80f0b4059");
|
||||
testBinary64('div_u', 40, 2, 20);
|
||||
testBinary64('div_u', 40, 8, 5);
|
||||
testBinary64('rem_s', 40, -3, 1);
|
||||
testBinary64('rem_s', 0, -3, 0);
|
||||
testBinary64('rem_s', 5, 2, 1);
|
||||
testBinary64('rem_s', 65, 64, 1);
|
||||
testBinary64('rem_s', "0x1234567887654321", "0x1000000000", "0x887654321");
|
||||
testBinary64('rem_s', "0x7fffffffffffffff", -1, 0);
|
||||
testBinary64('rem_s', "0x8000000000000001", 1000, -807);
|
||||
testBinary64('rem_s', "0x8000000000000000", -1, 0);
|
||||
testBinary64('rem_u', 40, -3, 40);
|
||||
testBinary64('rem_u', 41, 8, 1);
|
||||
testBinary64('rem_u', "0x1234567887654321", "0x1000000000", "0x887654321");
|
||||
testBinary64('rem_u', "0x8000000000000000", -1, "0x8000000000000000");
|
||||
testBinary64('rem_u', "0x8ff00ff00ff00ff0", "0x100000001", "0x80000001");
|
||||
|
|
|
@ -112,6 +112,7 @@
|
|||
|
||||
using mozilla::DebugOnly;
|
||||
using mozilla::FloatingPoint;
|
||||
using mozilla::FloorLog2;
|
||||
using mozilla::IsPowerOfTwo;
|
||||
using mozilla::SpecificNaN;
|
||||
|
||||
|
@ -1709,6 +1710,36 @@ class BaseCompiler
|
|||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool popConstPositivePowerOfTwoI32(int32_t& c,
|
||||
uint_fast8_t& power,
|
||||
int32_t cutoff)
|
||||
{
|
||||
Stk& v = stk_.back();
|
||||
if (v.kind() != Stk::ConstI32)
|
||||
return false;
|
||||
c = v.i32val();
|
||||
if (c <= cutoff || !IsPowerOfTwo(static_cast<uint32_t>(c)))
|
||||
return false;
|
||||
power = FloorLog2(c);
|
||||
stk_.popBack();
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool popConstPositivePowerOfTwoI64(int64_t& c,
|
||||
uint_fast8_t& power,
|
||||
int64_t cutoff)
|
||||
{
|
||||
Stk& v = stk_.back();
|
||||
if (v.kind() != Stk::ConstI64)
|
||||
return false;
|
||||
c = v.i64val();
|
||||
if (c <= cutoff || !IsPowerOfTwo(static_cast<uint64_t>(c)))
|
||||
return false;
|
||||
power = FloorLog2(c);
|
||||
stk_.popBack();
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO / OPTIMIZE (Bug 1316818): At the moment we use ReturnReg
|
||||
// for JoinReg. It is possible other choices would lead to better
|
||||
// register allocation, as ReturnReg is often first in the
|
||||
|
@ -4182,67 +4213,116 @@ BaseCompiler::emitMultiplyF64()
|
|||
void
|
||||
BaseCompiler::emitQuotientI32()
|
||||
{
|
||||
// TODO / OPTIMIZE: Fast case if lhs >= 0 and rhs is power of two (Bug 1316803)
|
||||
RegI32 r0, r1;
|
||||
pop2xI32ForIntMulDiv(&r0, &r1);
|
||||
int32_t c;
|
||||
uint_fast8_t power;
|
||||
if (popConstPositivePowerOfTwoI32(c, power, 0)) {
|
||||
if (power != 0) {
|
||||
RegI32 r = popI32();
|
||||
Label positive;
|
||||
masm.branchTest32(Assembler::NotSigned, r, r, &positive);
|
||||
masm.add32(Imm32(c-1), r);
|
||||
masm.bind(&positive);
|
||||
|
||||
Label done;
|
||||
checkDivideByZeroI32(r1, r0, &done);
|
||||
checkDivideSignedOverflowI32(r1, r0, &done, ZeroOnOverflow(false));
|
||||
masm.quotient32(r1, r0, IsUnsigned(false));
|
||||
masm.bind(&done);
|
||||
masm.rshift32Arithmetic(Imm32(power & 31), r);
|
||||
pushI32(r);
|
||||
}
|
||||
} else {
|
||||
RegI32 r0, r1;
|
||||
pop2xI32ForIntMulDiv(&r0, &r1);
|
||||
|
||||
freeI32(r1);
|
||||
pushI32(r0);
|
||||
Label done;
|
||||
checkDivideByZeroI32(r1, r0, &done);
|
||||
checkDivideSignedOverflowI32(r1, r0, &done, ZeroOnOverflow(false));
|
||||
masm.quotient32(r1, r0, IsUnsigned(false));
|
||||
masm.bind(&done);
|
||||
|
||||
freeI32(r1);
|
||||
pushI32(r0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaseCompiler::emitQuotientU32()
|
||||
{
|
||||
// TODO / OPTIMIZE: Fast case if lhs >= 0 and rhs is power of two (Bug 1316803)
|
||||
RegI32 r0, r1;
|
||||
pop2xI32ForIntMulDiv(&r0, &r1);
|
||||
int32_t c;
|
||||
uint_fast8_t power;
|
||||
if (popConstPositivePowerOfTwoI32(c, power, 0)) {
|
||||
if (power != 0) {
|
||||
RegI32 r = popI32();
|
||||
masm.rshift32(Imm32(power & 31), r);
|
||||
pushI32(r);
|
||||
}
|
||||
} else {
|
||||
RegI32 r0, r1;
|
||||
pop2xI32ForIntMulDiv(&r0, &r1);
|
||||
|
||||
Label done;
|
||||
checkDivideByZeroI32(r1, r0, &done);
|
||||
masm.quotient32(r1, r0, IsUnsigned(true));
|
||||
masm.bind(&done);
|
||||
Label done;
|
||||
checkDivideByZeroI32(r1, r0, &done);
|
||||
masm.quotient32(r1, r0, IsUnsigned(true));
|
||||
masm.bind(&done);
|
||||
|
||||
freeI32(r1);
|
||||
pushI32(r0);
|
||||
freeI32(r1);
|
||||
pushI32(r0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaseCompiler::emitRemainderI32()
|
||||
{
|
||||
// TODO / OPTIMIZE: Fast case if lhs >= 0 and rhs is power of two (Bug 1316803)
|
||||
RegI32 r0, r1;
|
||||
pop2xI32ForIntMulDiv(&r0, &r1);
|
||||
int32_t c;
|
||||
uint_fast8_t power;
|
||||
if (popConstPositivePowerOfTwoI32(c, power, 1)) {
|
||||
RegI32 r = popI32();
|
||||
RegI32 temp = needI32();
|
||||
moveI32(r, temp);
|
||||
|
||||
Label done;
|
||||
checkDivideByZeroI32(r1, r0, &done);
|
||||
checkDivideSignedOverflowI32(r1, r0, &done, ZeroOnOverflow(true));
|
||||
masm.remainder32(r1, r0, IsUnsigned(false));
|
||||
masm.bind(&done);
|
||||
Label positive;
|
||||
masm.branchTest32(Assembler::NotSigned, temp, temp, &positive);
|
||||
masm.add32(Imm32(c-1), temp);
|
||||
masm.bind(&positive);
|
||||
|
||||
freeI32(r1);
|
||||
pushI32(r0);
|
||||
masm.rshift32Arithmetic(Imm32(power & 31), temp);
|
||||
masm.lshift32(Imm32(power & 31), temp);
|
||||
masm.sub32(temp, r);
|
||||
freeI32(temp);
|
||||
|
||||
pushI32(r);
|
||||
} else {
|
||||
RegI32 r0, r1;
|
||||
pop2xI32ForIntMulDiv(&r0, &r1);
|
||||
|
||||
Label done;
|
||||
checkDivideByZeroI32(r1, r0, &done);
|
||||
checkDivideSignedOverflowI32(r1, r0, &done, ZeroOnOverflow(true));
|
||||
masm.remainder32(r1, r0, IsUnsigned(false));
|
||||
masm.bind(&done);
|
||||
|
||||
freeI32(r1);
|
||||
pushI32(r0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaseCompiler::emitRemainderU32()
|
||||
{
|
||||
// TODO / OPTIMIZE: Fast case if lhs >= 0 and rhs is power of two (Bug 1316803)
|
||||
RegI32 r0, r1;
|
||||
pop2xI32ForIntMulDiv(&r0, &r1);
|
||||
int32_t c;
|
||||
uint_fast8_t power;
|
||||
if (popConstPositivePowerOfTwoI32(c, power, 1)) {
|
||||
RegI32 r = popI32();
|
||||
masm.and32(Imm32(c-1), r);
|
||||
pushI32(r);
|
||||
} else {
|
||||
RegI32 r0, r1;
|
||||
pop2xI32ForIntMulDiv(&r0, &r1);
|
||||
|
||||
Label done;
|
||||
checkDivideByZeroI32(r1, r0, &done);
|
||||
masm.remainder32(r1, r0, IsUnsigned(true));
|
||||
masm.bind(&done);
|
||||
Label done;
|
||||
checkDivideByZeroI32(r1, r0, &done);
|
||||
masm.remainder32(r1, r0, IsUnsigned(true));
|
||||
masm.bind(&done);
|
||||
|
||||
freeI32(r1);
|
||||
pushI32(r0);
|
||||
freeI32(r1);
|
||||
pushI32(r0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef INT_DIV_I64_CALLOUT
|
||||
|
@ -4250,11 +4330,27 @@ void
|
|||
BaseCompiler::emitQuotientI64()
|
||||
{
|
||||
# ifdef JS_PUNBOX64
|
||||
RegI64 r0, r1;
|
||||
pop2xI64ForIntDiv(&r0, &r1);
|
||||
quotientI64(r1, r0, IsUnsigned(false));
|
||||
freeI64(r1);
|
||||
pushI64(r0);
|
||||
int64_t c;
|
||||
uint_fast8_t power;
|
||||
if (popConstPositivePowerOfTwoI64(c, power, 0)) {
|
||||
if (power != 0) {
|
||||
RegI64 r = popI64();
|
||||
Label positive;
|
||||
masm.branchTest64(Assembler::NotSigned, r, r, Register::Invalid(),
|
||||
&positive);
|
||||
masm.add64(Imm32(c-1), r);
|
||||
masm.bind(&positive);
|
||||
|
||||
masm.rshift64Arithmetic(Imm32(power & 63), r);
|
||||
pushI64(r);
|
||||
}
|
||||
} else {
|
||||
RegI64 r0, r1;
|
||||
pop2xI64ForIntDiv(&r0, &r1);
|
||||
quotientI64(r1, r0, IsUnsigned(false));
|
||||
freeI64(r1);
|
||||
pushI64(r0);
|
||||
}
|
||||
# else
|
||||
MOZ_CRASH("BaseCompiler platform hook: emitQuotientI64");
|
||||
# endif
|
||||
|
@ -4264,11 +4360,21 @@ void
|
|||
BaseCompiler::emitQuotientU64()
|
||||
{
|
||||
# ifdef JS_PUNBOX64
|
||||
RegI64 r0, r1;
|
||||
pop2xI64ForIntDiv(&r0, &r1);
|
||||
quotientI64(r1, r0, IsUnsigned(true));
|
||||
freeI64(r1);
|
||||
pushI64(r0);
|
||||
int64_t c;
|
||||
uint_fast8_t power;
|
||||
if (popConstPositivePowerOfTwoI64(c, power, 0)) {
|
||||
if (power != 0) {
|
||||
RegI64 r = popI64();
|
||||
masm.rshift64(Imm32(power & 63), r);
|
||||
pushI64(r);
|
||||
}
|
||||
} else {
|
||||
RegI64 r0, r1;
|
||||
pop2xI64ForIntDiv(&r0, &r1);
|
||||
quotientI64(r1, r0, IsUnsigned(true));
|
||||
freeI64(r1);
|
||||
pushI64(r0);
|
||||
}
|
||||
# else
|
||||
MOZ_CRASH("BaseCompiler platform hook: emitQuotientU64");
|
||||
# endif
|
||||
|
@ -4278,11 +4384,32 @@ void
|
|||
BaseCompiler::emitRemainderI64()
|
||||
{
|
||||
# ifdef JS_PUNBOX64
|
||||
RegI64 r0, r1;
|
||||
pop2xI64ForIntDiv(&r0, &r1);
|
||||
remainderI64(r1, r0, IsUnsigned(false));
|
||||
freeI64(r1);
|
||||
pushI64(r0);
|
||||
int64_t c;
|
||||
uint_fast8_t power;
|
||||
if (popConstPositivePowerOfTwoI64(c, power, 1)) {
|
||||
RegI64 r = popI64();
|
||||
RegI64 temp = needI64();
|
||||
moveI64(r, temp);
|
||||
|
||||
Label positive;
|
||||
masm.branchTest64(Assembler::NotSigned, temp, temp,
|
||||
Register::Invalid(), &positive);
|
||||
masm.add64(Imm64(c-1), temp);
|
||||
masm.bind(&positive);
|
||||
|
||||
masm.rshift64Arithmetic(Imm32(power & 63), temp);
|
||||
masm.lshift64(Imm32(power & 63), temp);
|
||||
masm.sub64(temp, r);
|
||||
freeI64(temp);
|
||||
|
||||
pushI64(r);
|
||||
} else {
|
||||
RegI64 r0, r1;
|
||||
pop2xI64ForIntDiv(&r0, &r1);
|
||||
remainderI64(r1, r0, IsUnsigned(false));
|
||||
freeI64(r1);
|
||||
pushI64(r0);
|
||||
}
|
||||
# else
|
||||
MOZ_CRASH("BaseCompiler platform hook: emitRemainderI64");
|
||||
# endif
|
||||
|
@ -4292,11 +4419,19 @@ void
|
|||
BaseCompiler::emitRemainderU64()
|
||||
{
|
||||
# ifdef JS_PUNBOX64
|
||||
RegI64 r0, r1;
|
||||
pop2xI64ForIntDiv(&r0, &r1);
|
||||
remainderI64(r1, r0, IsUnsigned(true));
|
||||
freeI64(r1);
|
||||
pushI64(r0);
|
||||
int64_t c;
|
||||
uint_fast8_t power;
|
||||
if (popConstPositivePowerOfTwoI64(c, power, 1)) {
|
||||
RegI64 r = popI64();
|
||||
masm.and64(Imm64(c-1), r);
|
||||
pushI64(r);
|
||||
} else {
|
||||
RegI64 r0, r1;
|
||||
pop2xI64ForIntDiv(&r0, &r1);
|
||||
remainderI64(r1, r0, IsUnsigned(true));
|
||||
freeI64(r1);
|
||||
pushI64(r0);
|
||||
}
|
||||
# else
|
||||
MOZ_CRASH("BaseCompiler platform hook: emitRemainderU64");
|
||||
# endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче