Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (194061 => 194062)
--- trunk/Source/_javascript_Core/ChangeLog 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/ChangeLog 2015-12-14 22:44:22 UTC (rev 194062)
@@ -1,3 +1,75 @@
+2015-12-14 Benjamin Poulain <[email protected]>
+
+ [JSC] Add ceil() support for x86 and expose it to B3
+ https://bugs.webkit.org/show_bug.cgi?id=152231
+
+ Reviewed by Geoffrey Garen.
+
+ Most x86 CPUs we care about support ceil() natively
+ with the round instruction.
+
+ This patch expose that behind a runtime flag, use it
+ in the Math.ceil() thunk and expose it to B3.
+
+ * assembler/MacroAssemblerARM64.h:
+ (JSC::MacroAssemblerARM64::supportsFloatingPointCeil):
+ * assembler/MacroAssemblerARMv7.h:
+ (JSC::MacroAssemblerARMv7::supportsFloatingPointCeil):
+ * assembler/MacroAssemblerMIPS.h:
+ (JSC::MacroAssemblerMIPS::supportsFloatingPointCeil):
+ * assembler/MacroAssemblerSH4.h:
+ (JSC::MacroAssemblerSH4::supportsFloatingPointCeil):
+ * assembler/MacroAssemblerX86Common.cpp:
+ * assembler/MacroAssemblerX86Common.h:
+ (JSC::MacroAssemblerX86Common::ceilDouble):
+ (JSC::MacroAssemblerX86Common::ceilFloat):
+ (JSC::MacroAssemblerX86Common::supportsFloatingPointCeil):
+ (JSC::MacroAssemblerX86Common::supportsLZCNT):
+ * assembler/X86Assembler.h:
+ (JSC::X86Assembler::roundss_rr):
+ (JSC::X86Assembler::roundss_mr):
+ (JSC::X86Assembler::roundsd_rr):
+ (JSC::X86Assembler::roundsd_mr):
+ (JSC::X86Assembler::mfence):
+ (JSC::X86Assembler::X86InstructionFormatter::threeByteOp):
+ * b3/B3ConstDoubleValue.cpp:
+ (JSC::B3::ConstDoubleValue::ceilConstant):
+ * b3/B3ConstDoubleValue.h:
+ * b3/B3ConstFloatValue.cpp:
+ (JSC::B3::ConstFloatValue::ceilConstant):
+ * b3/B3ConstFloatValue.h:
+ * b3/B3LowerMacrosAfterOptimizations.cpp:
+ * b3/B3LowerToAir.cpp:
+ (JSC::B3::Air::LowerToAir::lower):
+ * b3/B3Opcode.cpp:
+ (WTF::printInternal):
+ * b3/B3Opcode.h:
+ * b3/B3ReduceDoubleToFloat.cpp:
+ * b3/B3ReduceStrength.cpp:
+ * b3/B3Validate.cpp:
+ * b3/B3Value.cpp:
+ (JSC::B3::Value::ceilConstant):
+ (JSC::B3::Value::effects):
+ (JSC::B3::Value::key):
+ (JSC::B3::Value::typeFor):
+ * b3/B3Value.h:
+ * b3/air/AirOpcode.opcodes:
+ * b3/testb3.cpp:
+ (JSC::B3::testCeilArg):
+ (JSC::B3::testCeilImm):
+ (JSC::B3::testCeilMem):
+ (JSC::B3::testCeilCeilArg):
+ (JSC::B3::testCeilIToD64):
+ (JSC::B3::testCeilIToD32):
+ (JSC::B3::testCeilArgWithUselessDoubleConversion):
+ (JSC::B3::testCeilArgWithEffectfulDoubleConversion):
+ (JSC::B3::populateWithInterestingValues):
+ (JSC::B3::run):
+ * ftl/FTLB3Output.h:
+ (JSC::FTL::Output::ceil64):
+ * jit/ThunkGenerators.cpp:
+ (JSC::ceilThunkGenerator):
+
2015-12-14 Andreas Kling <[email protected]>
ResourceUsageOverlay should show GC timers.
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h (194061 => 194062)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARM64.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -1199,6 +1199,7 @@
static bool supportsFloatingPointTruncate() { return true; }
static bool supportsFloatingPointSqrt() { return true; }
static bool supportsFloatingPointAbs() { return true; }
+ static bool supportsFloatingPointCeil() { return true; }
enum BranchTruncateType { BranchIfTruncateFailed, BranchIfTruncateSuccessful };
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h (194061 => 194062)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerARMv7.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -856,6 +856,7 @@
static bool supportsFloatingPointTruncate() { return true; }
static bool supportsFloatingPointSqrt() { return true; }
static bool supportsFloatingPointAbs() { return true; }
+ static bool supportsFloatingPointCeil() { return false; }
void loadDouble(ImplicitAddress address, FPRegisterID dest)
{
@@ -1046,6 +1047,12 @@
m_assembler.vneg(dest, src);
}
+ NO_RETURN_DUE_TO_CRASH void ceilDouble(FPRegisterID, FPRegisterID)
+ {
+ ASSERT(!supportsFloatingPointCeil());
+ CRASH();
+ }
+
void convertInt32ToDouble(RegisterID src, FPRegisterID dest)
{
m_assembler.vmov(fpTempRegister, src, src);
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerMIPS.h (194061 => 194062)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerMIPS.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerMIPS.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -625,6 +625,12 @@
RELEASE_ASSERT_NOT_REACHED();
}
+ NO_RETURN_DUE_TO_CRASH void ceilDouble(FPRegisterID, FPRegisterID)
+ {
+ ASSERT(!supportsFloatingPointCeil());
+ CRASH();
+ }
+
ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
{
ConvertibleLoadLabel result(this);
@@ -1209,6 +1215,7 @@
#endif
}
static bool supportsFloatingPointAbs() { return false; }
+ static bool supportsFloatingPointCeil() { return false; }
// Stack manipulation operations:
//
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerSH4.h (194061 => 194062)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerSH4.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerSH4.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -1091,6 +1091,7 @@
static bool supportsFloatingPointTruncate() { return true; }
static bool supportsFloatingPointSqrt() { return true; }
static bool supportsFloatingPointAbs() { return true; }
+ static bool supportsFloatingPointCeil() { return false; }
void moveDoubleToInts(FPRegisterID src, RegisterID dest1, RegisterID dest2)
{
@@ -1574,6 +1575,12 @@
m_assembler.dabs(dest);
}
+ NO_RETURN_DUE_TO_CRASH void ceilDouble(FPRegisterID, FPRegisterID)
+ {
+ ASSERT(!supportsFloatingPointCeil());
+ CRASH();
+ }
+
Jump branchTest8(ResultCondition cond, Address address, TrustedImm32 mask = TrustedImm32(-1))
{
RegisterID addressTempRegister = claimScratch();
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -552,7 +552,8 @@
MacroAssemblerX86Common::SSE2CheckState MacroAssemblerX86Common::s_sse2CheckState = NotCheckedSSE2;
#endif
-MacroAssemblerX86Common::LZCNTCheckState MacroAssemblerX86Common::s_lzcntCheckState = LZCNTCheckState::NotChecked;
+MacroAssemblerX86Common::CPUIDCheckState MacroAssemblerX86Common::s_sse4_1CheckState = CPUIDCheckState::NotChecked;
+MacroAssemblerX86Common::CPUIDCheckState MacroAssemblerX86Common::s_lzcntCheckState = CPUIDCheckState::NotChecked;
} // namespace JSC
Modified: trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h (194061 => 194062)
--- trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/assembler/MacroAssemblerX86Common.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -570,7 +570,26 @@
m_assembler.xorpd_rr(src, dst);
}
+ void ceilDouble(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundsd_rr(src, dst, X86Assembler::RoundingType::TowardInfiniti);
+ }
+ void ceilDouble(Address src, FPRegisterID dst)
+ {
+ m_assembler.roundsd_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardInfiniti);
+ }
+
+ void ceilFloat(FPRegisterID src, FPRegisterID dst)
+ {
+ m_assembler.roundss_rr(src, dst, X86Assembler::RoundingType::TowardInfiniti);
+ }
+
+ void ceilFloat(Address src, FPRegisterID dst)
+ {
+ m_assembler.roundss_mr(src.offset, src.base, dst, X86Assembler::RoundingType::TowardInfiniti);
+ }
+
// Memory access operations:
//
// Loads are of the form load(address, destination) and stores of the form
@@ -1797,6 +1816,42 @@
return X86Assembler::maxJumpReplacementSize();
}
+ static bool supportsFloatingPointCeil()
+ {
+ if (s_sse4_1CheckState == CPUIDCheckState::NotChecked) {
+ int flags = 0;
+#if COMPILER(MSVC)
+ int cpuInfo[4];
+ __cpuid(cpuInfo, 0x1);
+ flags = cpuInfo[2];
+#elif COMPILER(GCC_OR_CLANG)
+#if CPU(X86_64)
+ asm (
+ "movl $0x1, %%eax;"
+ "cpuid;"
+ "movl %%ecx, %0;"
+ : "=g" (flags)
+ :
+ : "%eax", "%ebx", "%ecx", "%edx"
+ );
+#else
+ asm (
+ "movl $0x1, %%eax;"
+ "pushl %%ebx;"
+ "cpuid;"
+ "popl %%ebx;"
+ "movl %%ecx, %0;"
+ : "=g" (flags)
+ :
+ : "%eax", "%ecx", "%edx"
+ );
+#endif
+#endif // COMPILER(GCC_OR_CLANG)
+ s_sse4_1CheckState = (flags & (1 << 19)) ? CPUIDCheckState::Set : CPUIDCheckState::Clear;
+ }
+ return s_sse4_1CheckState == CPUIDCheckState::Set;
+ }
+
#if ENABLE(MASM_PROBE)
void probe(ProbeFunction, void* arg1, void* arg2);
#endif // ENABLE(MASM_PROBE)
@@ -1837,10 +1892,10 @@
m_assembler.cmovl_rr(cond, src, dest);
#endif
}
-
+
static bool supportsLZCNT()
{
- if (s_lzcntCheckState == LZCNTCheckState::NotChecked) {
+ if (s_lzcntCheckState == CPUIDCheckState::NotChecked) {
int flags = 0;
#if COMPILER(MSVC)
int cpuInfo[4];
@@ -1869,9 +1924,9 @@
);
#endif
#endif // COMPILER(GCC_OR_CLANG)
- s_lzcntCheckState = (flags & 0x20) ? LZCNTCheckState::Set : LZCNTCheckState::Clear;
+ s_lzcntCheckState = (flags & 0x20) ? CPUIDCheckState::Set : CPUIDCheckState::Clear;
}
- return s_lzcntCheckState == LZCNTCheckState::Set;
+ return s_lzcntCheckState == CPUIDCheckState::Set;
}
private:
@@ -2041,12 +2096,13 @@
#endif
- enum class LZCNTCheckState {
+ enum class CPUIDCheckState {
NotChecked,
Clear,
Set
};
- static LZCNTCheckState s_lzcntCheckState;
+ static CPUIDCheckState s_sse4_1CheckState;
+ static CPUIDCheckState s_lzcntCheckState;
};
} // namespace JSC
Modified: trunk/Source/_javascript_Core/assembler/X86Assembler.h (194061 => 194062)
--- trunk/Source/_javascript_Core/assembler/X86Assembler.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/assembler/X86Assembler.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -264,6 +264,7 @@
OP2_CVTSI2SD_VsdEd = 0x2A,
OP2_CVTTSD2SI_GdWsd = 0x2C,
OP2_UCOMISD_VsdWsd = 0x2E,
+ OP2_3BYTE_ESCAPE_3A = 0x3A,
OP2_CMOVCC = 0x40,
OP2_ADDSD_VsdWsd = 0x58,
OP2_MULSD_VsdWsd = 0x59,
@@ -280,7 +281,7 @@
OP2_MOVD_EdVd = 0x7E,
OP2_JCC_rel32 = 0x80,
OP_SETCC = 0x90,
- OP2_3BYTE_ESCAPE = 0xAE,
+ OP2_3BYTE_ESCAPE_AE = 0xAE,
OP2_IMUL_GvEv = 0xAF,
OP2_MOVZX_GvEb = 0xB6,
OP2_BSR = 0xBD,
@@ -295,7 +296,9 @@
} TwoByteOpcodeID;
typedef enum {
- OP3_MFENCE = 0xF0,
+ OP3_ROUNDSS_VssWssIb = 0x0A,
+ OP3_ROUNDSD_VsdWsdIb = 0x0B,
+ OP3_MFENCE = 0xF0,
} ThreeByteOpcodeID;
@@ -2349,6 +2352,41 @@
m_formatter.twoByteOp(OP2_SQRTSD_VsdWsd, (RegisterID)dst, base, offset);
}
+ enum class RoundingType : uint8_t {
+ ToNearestWithTiesToEven = 0,
+ TowardNegativeInfiniti = 1,
+ TowardInfiniti = 2,
+ TowardZero = 3
+ };
+
+ void roundss_rr(XMMRegisterID src, XMMRegisterID dst, RoundingType rounding)
+ {
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.threeByteOp(OP2_3BYTE_ESCAPE_3A, OP3_ROUNDSS_VssWssIb, (RegisterID)dst, (RegisterID)src);
+ m_formatter.immediate8(static_cast<uint8_t>(rounding));
+ }
+
+ void roundss_mr(int offset, RegisterID base, XMMRegisterID dst, RoundingType rounding)
+ {
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.threeByteOp(OP2_3BYTE_ESCAPE_3A, OP3_ROUNDSS_VssWssIb, (RegisterID)dst, base, offset);
+ m_formatter.immediate8(static_cast<uint8_t>(rounding));
+ }
+
+ void roundsd_rr(XMMRegisterID src, XMMRegisterID dst, RoundingType rounding)
+ {
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.threeByteOp(OP2_3BYTE_ESCAPE_3A, OP3_ROUNDSD_VsdWsdIb, (RegisterID)dst, (RegisterID)src);
+ m_formatter.immediate8(static_cast<uint8_t>(rounding));
+ }
+
+ void roundsd_mr(int offset, RegisterID base, XMMRegisterID dst, RoundingType rounding)
+ {
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.threeByteOp(OP2_3BYTE_ESCAPE_3A, OP3_ROUNDSD_VsdWsdIb, (RegisterID)dst, base, offset);
+ m_formatter.immediate8(static_cast<uint8_t>(rounding));
+ }
+
// Misc instructions:
void int3()
@@ -2368,7 +2406,7 @@
void mfence()
{
- m_formatter.threeByteOp(OP3_MFENCE);
+ m_formatter.threeByteOp(OP2_3BYTE_ESCAPE_AE, OP3_MFENCE);
}
// Assembler admin methods:
@@ -2847,14 +2885,34 @@
}
#endif
- void threeByteOp(ThreeByteOpcodeID opcode)
+ void threeByteOp(TwoByteOpcodeID twoBytePrefix, ThreeByteOpcodeID opcode)
{
m_buffer.ensureSpace(maxInstructionSize);
m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
- m_buffer.putByteUnchecked(OP2_3BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(twoBytePrefix);
m_buffer.putByteUnchecked(opcode);
}
+ void threeByteOp(TwoByteOpcodeID twoBytePrefix, ThreeByteOpcodeID opcode, int reg, RegisterID rm)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, 0, rm);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(twoBytePrefix);
+ m_buffer.putByteUnchecked(opcode);
+ registerModRM(reg, rm);
+ }
+
+ void threeByteOp(TwoByteOpcodeID twoBytePrefix, ThreeByteOpcodeID opcode, int reg, RegisterID base, int displacement)
+ {
+ m_buffer.ensureSpace(maxInstructionSize);
+ emitRexIfNeeded(reg, 0, base);
+ m_buffer.putByteUnchecked(OP_2BYTE_ESCAPE);
+ m_buffer.putByteUnchecked(twoBytePrefix);
+ m_buffer.putByteUnchecked(opcode);
+ memoryModRM(reg, base, displacement);
+ }
+
#if CPU(X86_64)
// Quad-word-sized operands:
//
Modified: trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -92,6 +92,11 @@
return proc.add<ConstDoubleValue>(origin(), fabs(m_value));
}
+Value* ConstDoubleValue::ceilConstant(Procedure& proc) const
+{
+ return proc.add<ConstDoubleValue>(origin(), ceil(m_value));
+}
+
Value* ConstDoubleValue::sqrtConstant(Procedure& proc) const
{
return proc.add<ConstDoubleValue>(origin(), sqrt(m_value));
Modified: trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3ConstDoubleValue.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -51,6 +51,7 @@
Value* bitwiseCastConstant(Procedure&) const override;
Value* doubleToFloatConstant(Procedure&) const override;
Value* absConstant(Procedure&) const override;
+ Value* ceilConstant(Procedure&) const override;
Value* sqrtConstant(Procedure&) const override;
TriState equalConstant(const Value* other) const override;
Modified: trunk/Source/_javascript_Core/b3/B3ConstFloatValue.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3ConstFloatValue.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3ConstFloatValue.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -92,6 +92,11 @@
return proc.add<ConstFloatValue>(origin(), static_cast<float>(fabs(m_value)));
}
+Value* ConstFloatValue::ceilConstant(Procedure& proc) const
+{
+ return proc.add<ConstFloatValue>(origin(), ceilf(m_value));
+}
+
Value* ConstFloatValue::sqrtConstant(Procedure& proc) const
{
return proc.add<ConstFloatValue>(origin(), static_cast<float>(sqrt(m_value)));
Modified: trunk/Source/_javascript_Core/b3/B3ConstFloatValue.h (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3ConstFloatValue.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3ConstFloatValue.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -50,6 +50,7 @@
Value* bitwiseCastConstant(Procedure&) const override;
Value* floatToDoubleConstant(Procedure&) const override;
Value* absConstant(Procedure&) const override;
+ Value* ceilConstant(Procedure&) const override;
Value* sqrtConstant(Procedure&) const override;
TriState equalConstant(const Value* other) const override;
Modified: trunk/Source/_javascript_Core/b3/B3LowerMacrosAfterOptimizations.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3LowerMacrosAfterOptimizations.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3LowerMacrosAfterOptimizations.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -30,8 +30,10 @@
#include "B3BasicBlockInlines.h"
#include "B3BlockInsertionSet.h"
+#include "B3CCallValue.h"
#include "B3ConstDoubleValue.h"
#include "B3ConstFloatValue.h"
+#include "B3ConstPtrValue.h"
#include "B3InsertionSetInlines.h"
#include "B3PhaseScope.h"
@@ -85,6 +87,27 @@
m_value->replaceWithIdentity(result);
break;
}
+ case Ceil: {
+ if (MacroAssembler::supportsFloatingPointCeil())
+ break;
+
+ Value* functionAddress = nullptr;
+ if (m_value->type() == Double)
+ functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, ceil);
+ else if (m_value->type() == Float)
+ functionAddress = m_insertionSet.insert<ConstPtrValue>(m_index, m_origin, ceilf);
+ else
+ RELEASE_ASSERT_NOT_REACHED();
+
+ Value* result = m_insertionSet.insert<CCallValue>(m_index,
+ m_value->type(),
+ m_origin,
+ Effects::none(),
+ functionAddress,
+ m_value->child(0));
+ m_value->replaceWithIdentity(result);
+ break;
+ }
default:
break;
}
Modified: trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3LowerToAir.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -1654,6 +1654,11 @@
return;
}
+ case Ceil: {
+ appendUnOp<Air::Oops, Air::Oops, CeilDouble, CeilFloat>(m_value->child(0));
+ return;
+ }
+
case Sqrt: {
appendUnOp<Air::Oops, Air::Oops, SqrtDouble, SqrtFloat>(m_value->child(0));
return;
Modified: trunk/Source/_javascript_Core/b3/B3Opcode.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3Opcode.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -149,6 +149,9 @@
case Abs:
out.print("Abs");
return;
+ case Ceil:
+ out.print("Ceil");
+ return;
case Sqrt:
out.print("Sqrt");
return;
Modified: trunk/Source/_javascript_Core/b3/B3Opcode.h (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3Opcode.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3Opcode.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -86,6 +86,7 @@
// Floating point math.
Abs,
+ Ceil,
Sqrt,
// Casts and such.
Modified: trunk/Source/_javascript_Core/b3/B3ReduceDoubleToFloat.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3ReduceDoubleToFloat.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3ReduceDoubleToFloat.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -49,6 +49,7 @@
}
break;
case Abs:
+ case Ceil:
case Sqrt:
if (candidate->child(0)->opcode() == FloatToDouble) {
candidate->child(0) = candidate->child(0)->child(0);
Modified: trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3ReduceStrength.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -564,6 +564,32 @@
}
break;
+ case Ceil:
+ // Turn this: Ceil(constant)
+ // Into this: ceil<value->type()>(constant)
+ if (Value* constant = m_value->child(0)->ceilConstant(m_proc)) {
+ replaceWithNewValue(constant);
+ break;
+ }
+
+ // Turn this: Ceil(Ceil(value))
+ // Into this: Ceil(value)
+ if (m_value->child(0)->opcode() == Ceil) {
+ m_value->replaceWithIdentity(m_value->child(0));
+ break;
+ }
+
+ // Turn this: Ceil(IToD(value))
+ // Into this: IToD(value)
+ //
+ // That works for Int64 because both ARM64 and x86_64
+ // perform rounding when converting a 64bit integer to double.
+ if (m_value->child(0)->opcode() == IToD) {
+ m_value->replaceWithIdentity(m_value->child(0));
+ break;
+ }
+ break;
+
case Sqrt:
// Turn this: Sqrt(constant)
// Into this: sqrt<value->type()>(constant)
Modified: trunk/Source/_javascript_Core/b3/B3Validate.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3Validate.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3Validate.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -210,6 +210,7 @@
VALIDATE(value->type() == Int32, ("At ", *value));
break;
case Abs:
+ case Ceil:
case Sqrt:
VALIDATE(value->numChildren() == 1, ("At ", *value));
VALIDATE(isFloat(value->child(0)->type()), ("At ", *value));
Modified: trunk/Source/_javascript_Core/b3/B3Value.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3Value.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3Value.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -226,6 +226,11 @@
return nullptr;
}
+Value* Value::ceilConstant(Procedure&) const
+{
+ return nullptr;
+}
+
Value* Value::sqrtConstant(Procedure&) const
{
return nullptr;
@@ -363,6 +368,7 @@
case ZShr:
case Clz:
case Abs:
+ case Ceil:
case Sqrt:
case BitwiseCast:
case SExt8:
@@ -442,6 +448,7 @@
return ValueKey(opcode(), type());
case Identity:
case Abs:
+ case Ceil:
case Sqrt:
case SExt8:
case SExt16:
@@ -549,6 +556,7 @@
case ZShr:
case Clz:
case Abs:
+ case Ceil:
case Sqrt:
case CheckAdd:
case CheckSub:
Modified: trunk/Source/_javascript_Core/b3/B3Value.h (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/B3Value.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/B3Value.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -132,6 +132,7 @@
virtual Value* doubleToFloatConstant(Procedure&) const;
virtual Value* floatToDoubleConstant(Procedure&) const;
virtual Value* absConstant(Procedure&) const;
+ virtual Value* ceilConstant(Procedure&) const;
virtual Value* sqrtConstant(Procedure&) const;
virtual TriState equalConstant(const Value* other) const;
Modified: trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/air/AirOpcode.opcodes 2015-12-14 22:44:22 UTC (rev 194062)
@@ -275,6 +275,14 @@
Tmp
x86: Addr
+CeilDouble U:F, UD:F
+ Tmp, Tmp
+ Addr, Tmp
+
+CeilFloat U:F, UD:F
+ Tmp, Tmp
+ Addr, Tmp
+
SqrtDouble U:F, UD:F
Tmp, Tmp
x86: Addr, Tmp
Modified: trunk/Source/_javascript_Core/b3/testb3.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/b3/testb3.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/b3/testb3.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -3235,6 +3235,175 @@
CHECK(isIdentical(effect, fabs(a)));
}
+void testCeilArg(double a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(
+ proc, Ceil, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0)));
+
+ CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(a)));
+}
+
+void testCeilImm(double a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* argument = root->appendNew<ConstDoubleValue>(proc, Origin(), a);
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(proc, Ceil, Origin(), argument));
+
+ CHECK(isIdentical(compileAndRun<double>(proc), ceil(a)));
+}
+
+void testCeilMem(double a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ MemoryValue* loadDouble = root->appendNew<MemoryValue>(proc, Load, Double, Origin(), address);
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(proc, Ceil, Origin(), loadDouble));
+
+ CHECK(isIdentical(compileAndRun<double>(proc, &a), ceil(a)));
+}
+
+void testCeilCeilArg(double a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* firstCeil = root->appendNew<Value>(proc, Ceil, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), FPRInfo::argumentFPR0));
+ Value* secondCeil = root->appendNew<Value>(proc, Ceil, Origin(), firstCeil);
+ root->appendNew<ControlValue>(proc, Return, Origin(), secondCeil);
+
+ CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(a)));
+}
+
+void testCeilIToD64(int64_t a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* argument = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ Value* argumentAsDouble = root->appendNew<Value>(proc, IToD, Origin(), argument);
+
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(proc, Ceil, Origin(), argumentAsDouble));
+
+ CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(static_cast<double>(a))));
+}
+
+void testCeilIToD32(int64_t a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* argument = root->appendNew<Value>(proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+ Value* argumentAsDouble = root->appendNew<Value>(proc, IToD, Origin(), argument);
+
+ root->appendNew<ControlValue>(
+ proc, Return, Origin(),
+ root->appendNew<Value>(proc, Ceil, Origin(), argumentAsDouble));
+
+ CHECK(isIdentical(compileAndRun<double>(proc, a), ceil(static_cast<double>(a))));
+}
+
+void testCeilArg(float a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+ Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+ Value* result = root->appendNew<Value>(proc, Ceil, Origin(), argument);
+ Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+ root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+ CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(ceilf(a))));
+}
+
+void testCeilImm(float a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* argument = root->appendNew<ConstFloatValue>(proc, Origin(), a);
+ Value* result = root->appendNew<Value>(proc, Ceil, Origin(), argument);
+ Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+ root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+ CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(ceilf(a))));
+}
+
+void testCeilMem(float a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* address = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0);
+ MemoryValue* loadFloat = root->appendNew<MemoryValue>(proc, Load, Float, Origin(), address);
+ Value* result = root->appendNew<Value>(proc, Ceil, Origin(), loadFloat);
+ Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), result);
+ root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+ CHECK(isIdentical(compileAndRun<int32_t>(proc, &a), bitwise_cast<int32_t>(ceilf(a))));
+}
+
+void testCeilCeilArg(float a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+ Value* argument = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+ Value* firstCeil = root->appendNew<Value>(proc, Ceil, Origin(), argument);
+ Value* secondCeil = root->appendNew<Value>(proc, Ceil, Origin(), firstCeil);
+ root->appendNew<ControlValue>(proc, Return, Origin(), secondCeil);
+
+ CHECK(isIdentical(compileAndRun<float>(proc, bitwise_cast<int32_t>(a)), ceilf(a)));
+}
+
+void testCeilArgWithUselessDoubleConversion(float a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+ Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+ Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+ Value* result = root->appendNew<Value>(proc, Ceil, Origin(), asDouble);
+ Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+ Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+ root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+ CHECK(isIdentical(compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a)), bitwise_cast<int32_t>(ceilf(a))));
+}
+
+void testCeilArgWithEffectfulDoubleConversion(float a)
+{
+ Procedure proc;
+ BasicBlock* root = proc.addBlock();
+ Value* argument32 = root->appendNew<Value>(proc, Trunc, Origin(),
+ root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR0));
+ Value* floatValue = root->appendNew<Value>(proc, BitwiseCast, Origin(), argument32);
+ Value* asDouble = root->appendNew<Value>(proc, FloatToDouble, Origin(), floatValue);
+ Value* result = root->appendNew<Value>(proc, Ceil, Origin(), asDouble);
+ Value* floatResult = root->appendNew<Value>(proc, DoubleToFloat, Origin(), result);
+ Value* result32 = root->appendNew<Value>(proc, BitwiseCast, Origin(), floatResult);
+ Value* doubleAddress = root->appendNew<ArgumentRegValue>(proc, Origin(), GPRInfo::argumentGPR1);
+ root->appendNew<MemoryValue>(proc, Store, Origin(), result, doubleAddress);
+ root->appendNew<ControlValue>(proc, Return, Origin(), result32);
+
+ double effect = 0;
+ int32_t resultValue = compileAndRun<int32_t>(proc, bitwise_cast<int32_t>(a), &effect);
+ CHECK(isIdentical(resultValue, bitwise_cast<int32_t>(ceilf(a))));
+ CHECK(isIdentical(effect, ceilf(a)));
+}
+
void testSqrtArg(double a)
{
Procedure proc;
@@ -8008,6 +8177,12 @@
{
operands.append({ "0.", static_cast<FloatType>(0.) });
operands.append({ "-0.", static_cast<FloatType>(-0.) });
+ operands.append({ "0.4", static_cast<FloatType>(0.5) });
+ operands.append({ "-0.4", static_cast<FloatType>(-0.5) });
+ operands.append({ "0.5", static_cast<FloatType>(0.5) });
+ operands.append({ "-0.5", static_cast<FloatType>(-0.5) });
+ operands.append({ "0.6", static_cast<FloatType>(0.5) });
+ operands.append({ "-0.6", static_cast<FloatType>(-0.5) });
operands.append({ "1.", static_cast<FloatType>(1.) });
operands.append({ "-1.", static_cast<FloatType>(-1.) });
operands.append({ "2.", static_cast<FloatType>(2.) });
@@ -8638,6 +8813,19 @@
RUN_UNARY(testAbsArgWithUselessDoubleConversion, floatingPointOperands<float>());
RUN_UNARY(testAbsArgWithEffectfulDoubleConversion, floatingPointOperands<float>());
+ RUN_UNARY(testCeilArg, floatingPointOperands<double>());
+ RUN_UNARY(testCeilImm, floatingPointOperands<double>());
+ RUN_UNARY(testCeilMem, floatingPointOperands<double>());
+ RUN_UNARY(testCeilCeilArg, floatingPointOperands<double>());
+ RUN_UNARY(testCeilIToD64, int64Operands());
+ RUN_UNARY(testCeilIToD32, int32Operands());
+ RUN_UNARY(testCeilArg, floatingPointOperands<float>());
+ RUN_UNARY(testCeilImm, floatingPointOperands<float>());
+ RUN_UNARY(testCeilMem, floatingPointOperands<float>());
+ RUN_UNARY(testCeilCeilArg, floatingPointOperands<float>());
+ RUN_UNARY(testCeilArgWithUselessDoubleConversion, floatingPointOperands<float>());
+ RUN_UNARY(testCeilArgWithEffectfulDoubleConversion, floatingPointOperands<float>());
+
RUN_UNARY(testSqrtArg, floatingPointOperands<double>());
RUN_UNARY(testSqrtImm, floatingPointOperands<double>());
RUN_UNARY(testSqrtMem, floatingPointOperands<double>());
Modified: trunk/Source/_javascript_Core/ftl/FTLB3Output.h (194061 => 194062)
--- trunk/Source/_javascript_Core/ftl/FTLB3Output.h 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/ftl/FTLB3Output.h 2015-12-14 22:44:22 UTC (rev 194062)
@@ -154,7 +154,7 @@
LValue lShr(LValue left, LValue right) { return m_block->appendNew<B3::Value>(m_proc, B3::ZShr, origin(), left, castToInt32(right)); }
LValue bitNot(LValue);
- LValue ceil64(LValue operand) { CRASH(); }
+ LValue ceil64(LValue operand) { return m_block->appendNew<B3::Value>(m_proc, B3::Ceil, origin(), value); }
LValue ctlz32(LValue operand) { return m_block->appendNew<B3::Value>(m_proc, B3::Clz, origin(), operand); }
LValue addWithOverflow32(LValue left, LValue right) { CRASH(); }
LValue subWithOverflow32(LValue left, LValue right) { CRASH(); }
Modified: trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp (194061 => 194062)
--- trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp 2015-12-14 22:26:40 UTC (rev 194061)
+++ trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp 2015-12-14 22:44:22 UTC (rev 194062)
@@ -828,11 +828,11 @@
jit.returnInt32(SpecializedThunkJIT::regT0);
nonIntJump.link(&jit);
jit.loadDoubleArgument(0, SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0);
-#if CPU(ARM64)
- jit.ceilDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
-#else
- jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(ceil));
-#endif // CPU(ARM64)
+ if (jit.supportsFloatingPointCeil())
+ jit.ceilDouble(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::fpRegT0);
+ else
+ jit.callDoubleToDoublePreservingReturn(UnaryDoubleOpWrapper(ceil));
+
SpecializedThunkJIT::JumpList doubleResult;
jit.branchConvertDoubleToInt32(SpecializedThunkJIT::fpRegT0, SpecializedThunkJIT::regT0, doubleResult, SpecializedThunkJIT::fpRegT1);
jit.returnInt32(SpecializedThunkJIT::regT0);