Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (208847 => 208848)
--- trunk/Source/_javascript_Core/ChangeLog 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-11-17 17:52:03 UTC (rev 208848)
@@ -1,3 +1,92 @@
+2016-11-17 Keith Miller <[email protected]>
+
+ Add support for rotate in B3 and the relevant assemblers
+ https://bugs.webkit.org/show_bug.cgi?id=164869
+
+ Reviewed by Geoffrey Garen.
+
+ This patch runs RotR and RotL (rotate right and left respectively)
+ through B3 and B3's assemblers. One thing of note is that ARM64 does
+ not support rotate left instead it allows negative right rotations.
+
+ This patch also fixes a theoretical bug in the assembler where
+ on X86 doing someShiftOp(reg, edx) would instead shift the shift
+ amount by the value. Additionally, this patch refactors some
+ of the X86 assembler to use templates when deciding how to format
+ the appropriate shift instruction.
+
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::rotateRight32):
+ (JSC::MacroAssemblerARM64::rotateRight64):
+ * assembler/MacroAssemblerX86Common.h:
+ (JSC::MacroAssemblerX86Common::rotateRight32):
+ (JSC::MacroAssemblerX86Common::rotateLeft32):
+ * assembler/MacroAssemblerX86_64.h:
+ (JSC::MacroAssemblerX86_64::lshift64):
+ (JSC::MacroAssemblerX86_64::rshift64):
+ (JSC::MacroAssemblerX86_64::urshift64):
+ (JSC::MacroAssemblerX86_64::rotateRight64):
+ (JSC::MacroAssemblerX86_64::rotateLeft64):
+ (JSC::MacroAssemblerX86_64::or64):
+ * assembler/X86Assembler.h:
+ (JSC::X86Assembler::xorq_rm):
+ (JSC::X86Assembler::shiftInstruction32):
+ (JSC::X86Assembler::sarl_i8r):
+ (JSC::X86Assembler::shrl_i8r):
+ (JSC::X86Assembler::shll_i8r):
+ (JSC::X86Assembler::rorl_i8r):
+ (JSC::X86Assembler::rorl_CLr):
+ (JSC::X86Assembler::roll_i8r):
+ (JSC::X86Assembler::roll_CLr):
+ (JSC::X86Assembler::shiftInstruction64):
+ (JSC::X86Assembler::sarq_CLr):
+ (JSC::X86Assembler::sarq_i8r):
+ (JSC::X86Assembler::shrq_i8r):
+ (JSC::X86Assembler::shlq_i8r):
+ (JSC::X86Assembler::rorq_i8r):
+ (JSC::X86Assembler::rorq_CLr):
+ (JSC::X86Assembler::rolq_i8r):
+ (JSC::X86Assembler::rolq_CLr):
+ * b3/B3Common.h:
+ (JSC::B3::rotateRight):
+ (JSC::B3::rotateLeft):
+ * b3/B3Const32Value.cpp:
+ (JSC::B3::Const32Value::rotRConstant):
+ (JSC::B3::Const32Value::rotLConstant):
+ * b3/B3Const32Value.h:
+ * b3/B3Const64Value.cpp:
+ (JSC::B3::Const64Value::rotRConstant):
+ (JSC::B3::Const64Value::rotLConstant):
+ * b3/B3Const64Value.h:
+ * b3/B3LowerToAir.cpp:
+ (JSC::B3::Air::LowerToAir::lower):
+ * b3/B3Opcode.cpp:
+ (WTF::printInternal):
+ * b3/B3Opcode.h:
+ * b3/B3ReduceStrength.cpp:
+ * b3/B3Validate.cpp:
+ * b3/B3Value.cpp:
+ (JSC::B3::Value::rotRConstant):
+ (JSC::B3::Value::rotLConstant):
+ (JSC::B3::Value::effects):
+ (JSC::B3::Value::key):
+ (JSC::B3::Value::typeFor):
+ * b3/B3Value.h:
+ * b3/B3ValueKey.cpp:
+ (JSC::B3::ValueKey::materialize):
+ * b3/air/AirInstInlines.h:
+ (JSC::B3::Air::isRotateRight32Valid):
+ (JSC::B3::Air::isRotateLeft32Valid):
+ (JSC::B3::Air::isRotateRight64Valid):
+ (JSC::B3::Air::isRotateLeft64Valid):
+ * b3/air/AirOpcode.opcodes:
+ * b3/testb3.cpp:
+ (JSC::B3::testRotR):
+ (JSC::B3::testRotL):
+ (JSC::B3::testRotRWithImmShift):
+ (JSC::B3::testRotLWithImmShift):
+ (JSC::B3::run):
+
2016-11-17 Saam Barati <[email protected]>
Remove async/await compile time flag and enable tests
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (208847 => 208848)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -664,11 +664,36 @@
m_assembler.orr<64>(dest, dest, dataTempRegister);
}
+ void rotateRight32(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.ror<32>(dest, src, imm.m_value & 31);
+ }
+
+ void rotateRight32(TrustedImm32 imm, RegisterID srcDst)
+ {
+ rotateRight32(srcDst, imm, srcDst);
+ }
+
+ void rotateRight32(RegisterID src, RegisterID shiftAmmount, RegisterID dest)
+ {
+ m_assembler.ror<32>(dest, src, shiftAmmount);
+ }
+
+ void rotateRight64(RegisterID src, TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.ror<64>(dest, src, imm.m_value & 63);
+ }
+
void rotateRight64(TrustedImm32 imm, RegisterID srcDst)
{
- m_assembler.ror<64>(srcDst, srcDst, imm.m_value & 63);
+ rotateRight64(srcDst, imm, srcDst);
}
+ void rotateRight64(RegisterID src, RegisterID shiftAmmount, RegisterID dest)
+ {
+ m_assembler.ror<64>(dest, src, shiftAmmount);
+ }
+
void rshift32(RegisterID src, RegisterID shiftAmount, RegisterID dest)
{
m_assembler.asr<32>(dest, src, shiftAmount);
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (208847 => 208848)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -566,7 +566,45 @@
move32IfNeeded(src, dest);
urshift32(imm, dest);
}
-
+
+ void rotateRight32(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.rorl_i8r(imm.m_value, dest);
+ }
+
+ void rotateRight32(RegisterID src, RegisterID dest)
+ {
+ if (src == X86Registers::ecx)
+ m_assembler.rorl_CLr(dest);
+ else {
+ ASSERT(src != dest);
+
+ // Can only rotate by ecx, so we do some swapping if we see anything else.
+ swap(src, X86Registers::ecx);
+ m_assembler.rorl_CLr(dest == X86Registers::ecx ? src : dest);
+ swap(src, X86Registers::ecx);
+ }
+ }
+
+ void rotateLeft32(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.roll_i8r(imm.m_value, dest);
+ }
+
+ void rotateLeft32(RegisterID src, RegisterID dest)
+ {
+ if (src == X86Registers::ecx)
+ m_assembler.roll_CLr(dest);
+ else {
+ ASSERT(src != dest);
+
+ // Can only rotate by ecx, so we do some swapping if we see anything else.
+ swap(src, X86Registers::ecx);
+ m_assembler.roll_CLr(dest == X86Registers::ecx ? src : dest);
+ swap(src, X86Registers::ecx);
+ }
+ }
+
void sub32(RegisterID src, RegisterID dest)
{
m_assembler.subl_rr(src, dest);
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h (208847 => 208848)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86_64.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -402,10 +402,10 @@
m_assembler.shlq_CLr(dest);
else {
ASSERT(src != dest);
-
+
// Can only shift by ecx, so we do some swapping if we see anything else.
swap(src, X86Registers::ecx);
- m_assembler.shlq_CLr(dest);
+ m_assembler.shlq_CLr(dest == X86Registers::ecx ? src : dest);
swap(src, X86Registers::ecx);
}
}
@@ -424,7 +424,7 @@
// Can only shift by ecx, so we do some swapping if we see anything else.
swap(src, X86Registers::ecx);
- m_assembler.sarq_CLr(dest);
+ m_assembler.sarq_CLr(dest == X86Registers::ecx ? src : dest);
swap(src, X86Registers::ecx);
}
}
@@ -443,11 +443,49 @@
// Can only shift by ecx, so we do some swapping if we see anything else.
swap(src, X86Registers::ecx);
- m_assembler.shrq_CLr(dest);
+ m_assembler.shrq_CLr(dest == X86Registers::ecx ? src : dest);
swap(src, X86Registers::ecx);
}
}
+ void rotateRight64(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.rorq_i8r(imm.m_value, dest);
+ }
+
+ void rotateRight64(RegisterID src, RegisterID dest)
+ {
+ if (src == X86Registers::ecx)
+ m_assembler.rorq_CLr(dest);
+ else {
+ ASSERT(src != dest);
+
+ // Can only rotate by ecx, so we do some swapping if we see anything else.
+ swap(src, X86Registers::ecx);
+ m_assembler.rorq_CLr(dest == X86Registers::ecx ? src : dest);
+ swap(src, X86Registers::ecx);
+ }
+ }
+
+ void rotateLeft64(TrustedImm32 imm, RegisterID dest)
+ {
+ m_assembler.rolq_i8r(imm.m_value, dest);
+ }
+
+ void rotateLeft64(RegisterID src, RegisterID dest)
+ {
+ if (src == X86Registers::ecx)
+ m_assembler.rolq_CLr(dest);
+ else {
+ ASSERT(src != dest);
+
+ // Can only rotate by ecx, so we do some swapping if we see anything else.
+ swap(src, X86Registers::ecx);
+ m_assembler.rolq_CLr(dest == X86Registers::ecx ? src : dest);
+ swap(src, X86Registers::ecx);
+ }
+ }
+
void mul64(RegisterID src, RegisterID dest)
{
m_assembler.imulq_rr(src, dest);
@@ -542,11 +580,6 @@
move(src, dest);
or64(imm, dest);
}
-
- void rotateRight64(TrustedImm32 imm, RegisterID srcDst)
- {
- m_assembler.rorq_i8r(imm.m_value, srcDst);
- }
void sub64(RegisterID src, RegisterID dest)
{
Modified: trunk/Source/_javascript_Core/assembler/X86Assembler.h (208847 => 208848)
--- trunk/Source/_javascript_Core/assembler/X86Assembler.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/assembler/X86Assembler.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -967,16 +967,6 @@
{
m_formatter.oneByteOp64(OP_XOR_EvGv, src, base, offset);
}
-
- void rorq_i8r(int imm, RegisterID dst)
- {
- if (imm == 1)
- m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_ROR, dst);
- else {
- m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_ROR, dst);
- m_formatter.immediate8(imm);
- }
- }
#endif
@@ -1028,16 +1018,24 @@
}
#endif
- void sarl_i8r(int imm, RegisterID dst)
+private:
+ template<GroupOpcodeID op>
+ void shiftInstruction32(int imm, RegisterID dst)
{
if (imm == 1)
- m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst);
+ m_formatter.oneByteOp(OP_GROUP2_Ev1, op, dst);
else {
- m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst);
+ m_formatter.oneByteOp(OP_GROUP2_EvIb, op, dst);
m_formatter.immediate8(imm);
}
}
+public:
+ void sarl_i8r(int imm, RegisterID dst)
+ {
+ shiftInstruction32<GROUP2_OP_SAR>(imm, dst);
+ }
+
void sarl_CLr(RegisterID dst)
{
m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
@@ -1045,12 +1043,7 @@
void shrl_i8r(int imm, RegisterID dst)
{
- if (imm == 1)
- m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst);
- else {
- m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst);
- m_formatter.immediate8(imm);
- }
+ shiftInstruction32<GROUP2_OP_SHR>(imm, dst);
}
void shrl_CLr(RegisterID dst)
@@ -1060,12 +1053,7 @@
void shll_i8r(int imm, RegisterID dst)
{
- if (imm == 1)
- m_formatter.oneByteOp(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst);
- else {
- m_formatter.oneByteOp(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst);
- m_formatter.immediate8(imm);
- }
+ shiftInstruction32<GROUP2_OP_SHL>(imm, dst);
}
void shll_CLr(RegisterID dst)
@@ -1073,30 +1061,52 @@
m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst);
}
-#if CPU(X86_64)
- void sarq_CLr(RegisterID dst)
+ void rorl_i8r(int imm, RegisterID dst)
{
- m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
+ shiftInstruction32<GROUP2_OP_ROR>(imm, dst);
}
- void sarq_i8r(int imm, RegisterID dst)
+ void rorl_CLr(RegisterID dst)
{
+ m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_ROR, dst);
+ }
+
+ void roll_i8r(int imm, RegisterID dst)
+ {
+ shiftInstruction32<GROUP2_OP_ROL>(imm, dst);
+ }
+
+ void roll_CLr(RegisterID dst)
+ {
+ m_formatter.oneByteOp(OP_GROUP2_EvCL, GROUP2_OP_ROL, dst);
+ }
+
+#if CPU(X86_64)
+private:
+ template<GroupOpcodeID op>
+ void shiftInstruction64(int imm, RegisterID dst)
+ {
if (imm == 1)
- m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SAR, dst);
+ m_formatter.oneByteOp64(OP_GROUP2_Ev1, op, dst);
else {
- m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SAR, dst);
+ m_formatter.oneByteOp64(OP_GROUP2_EvIb, op, dst);
m_formatter.immediate8(imm);
}
}
+public:
+ void sarq_CLr(RegisterID dst)
+ {
+ m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SAR, dst);
+ }
+ void sarq_i8r(int imm, RegisterID dst)
+ {
+ shiftInstruction64<GROUP2_OP_SAR>(imm, dst);
+ }
+
void shrq_i8r(int imm, RegisterID dst)
{
- if (imm == 1)
- m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHR, dst);
- else {
- m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHR, dst);
- m_formatter.immediate8(imm);
- }
+ shiftInstruction64<GROUP2_OP_SHR>(imm, dst);
}
void shrq_CLr(RegisterID dst)
@@ -1106,12 +1116,7 @@
void shlq_i8r(int imm, RegisterID dst)
{
- if (imm == 1)
- m_formatter.oneByteOp64(OP_GROUP2_Ev1, GROUP2_OP_SHL, dst);
- else {
- m_formatter.oneByteOp64(OP_GROUP2_EvIb, GROUP2_OP_SHL, dst);
- m_formatter.immediate8(imm);
- }
+ shiftInstruction64<GROUP2_OP_SHL>(imm, dst);
}
void shlq_CLr(RegisterID dst)
@@ -1118,6 +1123,26 @@
{
m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_SHL, dst);
}
+
+ void rorq_i8r(int imm, RegisterID dst)
+ {
+ shiftInstruction64<GROUP2_OP_ROR>(imm, dst);
+ }
+
+ void rorq_CLr(RegisterID dst)
+ {
+ m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_ROR, dst);
+ }
+
+ void rolq_i8r(int imm, RegisterID dst)
+ {
+ shiftInstruction64<GROUP2_OP_ROL>(imm, dst);
+ }
+
+ void rolq_CLr(RegisterID dst)
+ {
+ m_formatter.oneByteOp64(OP_GROUP2_EvCL, GROUP2_OP_ROL, dst);
+ }
#endif // CPU(X86_64)
void imull_rr(RegisterID src, RegisterID dst)
Modified: trunk/Source/_javascript_Core/b3/B3Common.h (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Common.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Common.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -148,6 +148,28 @@
return unsignedNumerator % unsignedDenominator;
}
+template<typename IntType>
+static IntType rotateRight(IntType value, int32_t shift)
+{
+ typedef typename std::make_unsigned<IntType>::type UnsignedIntType;
+ UnsignedIntType uValue = static_cast<UnsignedIntType>(value);
+ int32_t bits = sizeof(IntType) * 8;
+ int32_t mask = bits - 1;
+ shift &= mask;
+ return (uValue >> shift) | (uValue << ((bits - shift) & mask));
+}
+
+template<typename IntType>
+static IntType rotateLeft(IntType value, int32_t shift)
+{
+ typedef typename std::make_unsigned<IntType>::type UnsignedIntType;
+ UnsignedIntType uValue = static_cast<UnsignedIntType>(value);
+ int32_t bits = sizeof(IntType) * 8;
+ int32_t mask = bits - 1;
+ shift &= mask;
+ return (uValue << shift) | (uValue >> ((bits - shift) & mask));
+}
+
} } // namespace JSC::B3
#endif // ENABLE(B3_JIT)
Modified: trunk/Source/_javascript_Core/b3/B3Const32Value.cpp (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Const32Value.cpp 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Const32Value.cpp 2016-11-17 17:52:03 UTC (rev 208848)
@@ -175,6 +175,20 @@
return proc.add<Const32Value>(origin(), static_cast<int32_t>(static_cast<uint32_t>(m_value) >> (other->asInt32() & 31)));
}
+Value* Const32Value::rotRConstant(Procedure& proc, const Value* other) const
+{
+ if (!other->hasInt32())
+ return nullptr;
+ return proc.add<Const32Value>(origin(), rotateRight(m_value, other->asInt32()));
+}
+
+Value* Const32Value::rotLConstant(Procedure& proc, const Value* other) const
+{
+ if (!other->hasInt32())
+ return nullptr;
+ return proc.add<Const32Value>(origin(), rotateLeft(m_value, other->asInt32()));
+}
+
Value* Const32Value::bitwiseCastConstant(Procedure& proc) const
{
return proc.add<ConstFloatValue>(origin(), bitwise_cast<float>(m_value));
Modified: trunk/Source/_javascript_Core/b3/B3Const32Value.h (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Const32Value.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Const32Value.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -58,6 +58,8 @@
Value* shlConstant(Procedure&, const Value* other) const override;
Value* sShrConstant(Procedure&, const Value* other) const override;
Value* zShrConstant(Procedure&, const Value* other) const override;
+ Value* rotRConstant(Procedure&, const Value* other) const override;
+ Value* rotLConstant(Procedure&, const Value* other) const override;
Value* bitwiseCastConstant(Procedure&) const override;
Value* iToDConstant(Procedure&) const override;
Value* iToFConstant(Procedure&) const override;
Modified: trunk/Source/_javascript_Core/b3/B3Const64Value.cpp (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Const64Value.cpp 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Const64Value.cpp 2016-11-17 17:52:03 UTC (rev 208848)
@@ -175,6 +175,20 @@
return proc.add<Const64Value>(origin(), static_cast<int64_t>(static_cast<uint64_t>(m_value) >> (other->asInt32() & 63)));
}
+Value* Const64Value::rotRConstant(Procedure& proc, const Value* other) const
+{
+ if (!other->hasInt32())
+ return nullptr;
+ return proc.add<Const64Value>(origin(), rotateRight(m_value, other->asInt32()));
+}
+
+Value* Const64Value::rotLConstant(Procedure& proc, const Value* other) const
+{
+ if (!other->hasInt32())
+ return nullptr;
+ return proc.add<Const64Value>(origin(), rotateLeft(m_value, other->asInt32()));
+}
+
Value* Const64Value::bitwiseCastConstant(Procedure& proc) const
{
return proc.add<ConstDoubleValue>(origin(), bitwise_cast<double>(m_value));
Modified: trunk/Source/_javascript_Core/b3/B3Const64Value.h (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Const64Value.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Const64Value.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -58,6 +58,8 @@
Value* shlConstant(Procedure&, const Value* other) const override;
Value* sShrConstant(Procedure&, const Value* other) const override;
Value* zShrConstant(Procedure&, const Value* other) const override;
+ Value* rotRConstant(Procedure&, const Value* other) const override;
+ Value* rotLConstant(Procedure&, const Value* other) const override;
Value* bitwiseCastConstant(Procedure&) const override;
Value* iToDConstant(Procedure&) const override;
Value* iToFConstant(Procedure&) const override;
Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2016-11-17 17:52:03 UTC (rev 208848)
@@ -2191,6 +2191,16 @@
return;
}
+ case RotR: {
+ appendShift<RotateRight32, RotateRight64>(m_value->child(0), m_value->child(1));
+ return;
+ }
+
+ case RotL: {
+ appendShift<RotateLeft32, RotateLeft64>(m_value->child(0), m_value->child(1));
+ return;
+ }
+
case Clz: {
appendUnOp<CountLeadingZeros32, CountLeadingZeros64>(m_value->child(0));
return;
Modified: trunk/Source/_javascript_Core/b3/B3Opcode.cpp (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Opcode.cpp 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.cpp 2016-11-17 17:52:03 UTC (rev 208848)
@@ -152,6 +152,12 @@
case ZShr:
out.print("ZShr");
return;
+ case RotR:
+ out.print("RotR");
+ return;
+ case RotL:
+ out.print("RotL");
+ return;
case Clz:
out.print("Clz");
return;
Modified: trunk/Source/_javascript_Core/b3/B3Opcode.h (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Opcode.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -95,6 +95,8 @@
Shl,
SShr, // Arithmetic Shift.
ZShr, // Logical Shift.
+ RotR, // Rotate Right.
+ RotL, // Rotate Left.
Clz, // Count leading zeros.
// Floating point math.
Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2016-11-17 17:52:03 UTC (rev 208848)
@@ -1069,9 +1069,7 @@
break;
}
- if (handleShiftAmount())
- break;
-
+ handleShiftAmount();
break;
case SShr:
@@ -1131,9 +1129,7 @@
break;
}
- if (handleShiftAmount())
- break;
-
+ handleShiftAmount();
break;
case ZShr:
@@ -1144,11 +1140,41 @@
break;
}
- if (handleShiftAmount())
+ handleShiftAmount();
+ break;
+
+ case RotR:
+ // Turn this: RotR(constant1, constant2)
+ // Into this: (constant1 >> constant2) | (constant1 << sizeof(constant1) * 8 - constant2)
+ if (Value* constant = m_value->child(0)->rotRConstant(m_proc, m_value->child(1))) {
+ replaceWithNewValue(constant);
break;
+ }
+ handleShiftAmount();
break;
+ case RotL:
+ // Turn this: RotL(constant1, constant2)
+ // Into this: (constant1 << constant2) | (constant1 >> sizeof(constant1) * 8 - constant2)
+ if (Value* constant = m_value->child(0)->rotLConstant(m_proc, m_value->child(1))) {
+ replaceWithNewValue(constant);
+ break;
+ }
+
+ // ARM64 only has rotate right.
+ // Turn this: RotL(value, shift)
+ // Into this: RotR(value, Neg(shift))
+ if (isARM64()) {
+ Value* newShift = m_insertionSet.insert<Value>(m_index, Neg, m_value->origin(), m_value->child(1));
+ Value* rotate = m_insertionSet.insert<Value>(m_index, RotR, m_value->origin(), m_value->child(0), newShift);
+ replaceWithIdentity(rotate);
+ break;
+ }
+
+ handleShiftAmount();
+ break;
+
case Abs:
// Turn this: Abs(constant)
// Into this: fabs<value->type()>(constant)
@@ -2184,12 +2210,12 @@
m_changed = true;
}
- bool handleShiftAmount()
+ void handleShiftAmount()
{
// Shift anything by zero is identity.
if (m_value->child(1)->isInt32(0)) {
replaceWithIdentity(m_value->child(0));
- return true;
+ return;
}
// The shift already masks its shift amount. If the shift amount is being masked by a
@@ -2202,11 +2228,7 @@
&& (m_value->child(1)->child(1)->asInt32() & mask) == mask) {
m_value->child(1) = m_value->child(1)->child(0);
m_changed = true;
- // Don't need to return true, since we're still the same shift, and we can still cascade
- // through other optimizations.
}
-
- return false;
}
void replaceIfRedundant()
Modified: trunk/Source/_javascript_Core/b3/B3Validate.cpp (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Validate.cpp 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Validate.cpp 2016-11-17 17:52:03 UTC (rev 208848)
@@ -229,6 +229,8 @@
case Shl:
case SShr:
case ZShr:
+ case RotR:
+ case RotL:
VALIDATE(!value->kind().hasExtraBits(), ("At ", *value));
VALIDATE(value->numChildren() == 2, ("At ", *value));
VALIDATE(value->type() == value->child(0)->type(), ("At ", *value));
Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Value.cpp 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp 2016-11-17 17:52:03 UTC (rev 208848)
@@ -343,6 +343,16 @@
return nullptr;
}
+Value* Value::rotRConstant(Procedure&, const Value*) const
+{
+ return nullptr;
+}
+
+Value* Value::rotLConstant(Procedure&, const Value*) const
+{
+ return nullptr;
+}
+
Value* Value::bitwiseCastConstant(Procedure&) const
{
return nullptr;
@@ -550,6 +560,8 @@
case Shl:
case SShr:
case ZShr:
+ case RotR:
+ case RotL:
case Clz:
case Abs:
case Ceil:
@@ -696,6 +708,8 @@
case Shl:
case SShr:
case ZShr:
+ case RotR:
+ case RotL:
case Equal:
case NotEqual:
case LessThan:
@@ -777,6 +791,8 @@
case Shl:
case SShr:
case ZShr:
+ case RotR:
+ case RotL:
case Clz:
case Abs:
case Ceil:
Modified: trunk/Source/_javascript_Core/b3/B3Value.h (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3Value.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3Value.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -175,6 +175,8 @@
virtual Value* shlConstant(Procedure&, const Value* other) const;
virtual Value* sShrConstant(Procedure&, const Value* other) const;
virtual Value* zShrConstant(Procedure&, const Value* other) const;
+ virtual Value* rotRConstant(Procedure&, const Value* other) const;
+ virtual Value* rotLConstant(Procedure&, const Value* other) const;
virtual Value* bitwiseCastConstant(Procedure&) const;
virtual Value* iToDConstant(Procedure&) const;
virtual Value* iToFConstant(Procedure&) const;
@@ -333,6 +335,8 @@
case Shl:
case SShr:
case ZShr:
+ case RotR:
+ case RotL:
case Equal:
case NotEqual:
case LessThan:
Modified: trunk/Source/_javascript_Core/b3/B3ValueKey.cpp (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/B3ValueKey.cpp 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/B3ValueKey.cpp 2016-11-17 17:52:03 UTC (rev 208848)
@@ -86,6 +86,8 @@
case Shl:
case SShr:
case ZShr:
+ case RotR:
+ case RotL:
case Equal:
case NotEqual:
case LessThan:
Modified: trunk/Source/_javascript_Core/b3/air/AirInstInlines.h (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/air/AirInstInlines.h 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/air/AirInstInlines.h 2016-11-17 17:52:03 UTC (rev 208848)
@@ -214,6 +214,26 @@
return isShiftValid(inst);
}
+inline bool isRotateRight32Valid(const Inst& inst)
+{
+ return isShiftValid(inst);
+}
+
+inline bool isRotateLeft32Valid(const Inst& inst)
+{
+ return isShiftValid(inst);
+}
+
+inline bool isRotateRight64Valid(const Inst& inst)
+{
+ return isShiftValid(inst);
+}
+
+inline bool isRotateLeft64Valid(const Inst& inst)
+{
+ return isShiftValid(inst);
+}
+
inline bool isX86DivHelperValid(const Inst& inst)
{
#if CPU(X86) || CPU(X86_64)
Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2016-11-17 17:52:03 UTC (rev 208848)
@@ -373,7 +373,7 @@
Tmp*, Tmp
Imm, Tmp
-arm64: Lshift64 U:G:64, U:G:64, ZD:G:64
+arm64: Lshift64 U:G:64, U:G:64, D:G:64
Tmp, Tmp, Tmp
Tmp, Imm, Tmp
@@ -389,7 +389,7 @@
Tmp*, Tmp
Imm, Tmp
-arm64: Rshift64 U:G:64, U:G:64, ZD:G:64
+arm64: Rshift64 U:G:64, U:G:64, D:G:64
Tmp, Tmp, Tmp
Tmp, Imm, Tmp
@@ -405,7 +405,7 @@
Tmp*, Tmp
Imm, Tmp
-arm64: Urshift64 U:G:64, U:G:64, ZD:G:64
+arm64: Urshift64 U:G:64, U:G:64, D:G:64
Tmp, Tmp, Tmp
Tmp, Imm, Tmp
@@ -413,6 +413,30 @@
Tmp*, Tmp
Imm, Tmp
+x86_64: RotateRight32 U:G:32, UZD:G:32
+ Tmp*, Tmp
+ Imm, Tmp
+
+arm64: RotateRight32 U:G:32, U:G:32, ZD:G:32
+ Tmp, Tmp, Tmp
+ Tmp, Imm, Tmp
+
+x86_64: RotateRight64 U:G:64, UD:G:64
+ Tmp*, Tmp
+ Imm, Tmp
+
+arm64: RotateRight64 U:G:64, U:G:64, D:G:64
+ Tmp, Tmp, Tmp
+ Tmp, Imm, Tmp
+
+x86_64: RotateLeft32 U:G:32, UZD:G:32
+ Tmp*, Tmp
+ Imm, Tmp
+
+x86_64: RotateLeft64 U:G:64, UD:G:64
+ Tmp*, Tmp
+ Imm, Tmp
+
Or32 U:G:32, U:G:32, ZD:G:32
Tmp, Tmp, Tmp
arm64: BitImm, Tmp, Tmp
Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (208847 => 208848)
--- trunk/Source/_javascript_Core/b3/testb3.cpp 2016-11-17 17:28:52 UTC (rev 208847)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp 2016-11-17 17:52:03 UTC (rev 208848)
@@ -11959,6 +11959,76 @@
}
template<typename T>
+void testRotR(T valueInt, int32_t shift)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ if (sizeof(T) == 4)
+ value = root->appendNew<Value>(proc, Trunc, Origin(), value);
+
+ Value* ammount = root->appendNew<Value>(proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+ root->appendNewControlValue(proc, Return, Origin(),
+ root->appendNew<Value>(proc, RotR, Origin(), value, ammount));
+
+ CHECK_EQ(compileAndRun<T>(proc, valueInt, shift), rotateRight(valueInt, shift));
+}
+
+template<typename T>
+void testRotL(T valueInt, int32_t shift)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ if (sizeof(T) == 4)
+ value = root->appendNew<Value>(proc, Trunc, Origin(), value);
+
+ Value* ammount = root->appendNew<Value>(proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1));
+ root->appendNewControlValue(proc, Return, Origin(),
+ root->appendNew<Value>(proc, RotL, Origin(), value, ammount));
+
+ CHECK_EQ(compileAndRun<T>(proc, valueInt, shift), rotateLeft(valueInt, shift));
+}
+
+template<typename T>
+void testRotRWithImmShift(T valueInt, int32_t shift)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ if (sizeof(T) == 4)
+ value = root->appendNew<Value>(proc, Trunc, Origin(), value);
+
+ Value* ammount = root->appendIntConstant(proc, Origin(), Int32, shift);
+ root->appendNewControlValue(proc, Return, Origin(),
+ root->appendNew<Value>(proc, RotR, Origin(), value, ammount));
+
+ CHECK_EQ(compileAndRun<T>(proc, valueInt, shift), rotateRight(valueInt, shift));
+}
+
+template<typename T>
+void testRotLWithImmShift(T valueInt, int32_t shift)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+
+ Value* value = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ if (sizeof(T) == 4)
+ value = root->appendNew<Value>(proc, Trunc, Origin(), value);
+
+ Value* ammount = root->appendIntConstant(proc, Origin(), Int32, shift);
+ root->appendNewControlValue(proc, Return, Origin(),
+ root->appendNew<Value>(proc, RotL, Origin(), value, ammount));
+
+ CHECK_EQ(compileAndRun<T>(proc, valueInt, shift), rotateLeft(valueInt, shift));
+}
+
+template<typename T>
void testComputeDivisionMagic(T value, T magicMultiplier, unsigned shift)
{
DivisionMagic<T> magic = computeDivisionMagic(value);
@@ -15293,6 +15363,16 @@
RUN(testCheckMul64SShr());
+ RUN_BINARY(testRotR, int32Operands(), int32Operands());
+ RUN_BINARY(testRotR, int64Operands(), int32Operands());
+ RUN_BINARY(testRotL, int32Operands(), int32Operands());
+ RUN_BINARY(testRotL, int64Operands(), int32Operands());
+
+ RUN_BINARY(testRotRWithImmShift, int32Operands(), int32Operands());
+ RUN_BINARY(testRotRWithImmShift, int64Operands(), int32Operands());
+ RUN_BINARY(testRotLWithImmShift, int32Operands(), int32Operands());
+ RUN_BINARY(testRotLWithImmShift, int64Operands(), int32Operands());
+
RUN(testComputeDivisionMagic<int32_t>(2, -2147483647, 0));
RUN(testTrivialInfiniteLoop());
RUN(testFoldPathEqual());