Bug 1434717: Part 6: Implement UnaryArith IC for doubles r=tcampbell
authorMatthew Gaudet <mgaudet@mozilla.com>
Wed, 07 Feb 2018 14:22:48 -0500
changeset 463857 e7b45cdbc1a55b11d01fcbbed9e6b37420c88f0d
parent 463856 ea25dec22fd06218d1e084980f269a01096959b0
child 463858 456f52fb9f925597b11917f3c4c4d4cea94024c4
push id9165
push userasasaki@mozilla.com
push dateThu, 26 Apr 2018 21:04:54 +0000
treeherdermozilla-beta@064c3804de2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1434717
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1434717: Part 6: Implement UnaryArith IC for doubles r=tcampbell
js/src/jit-test/tests/cacheir/bug1439180.js
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/CacheIRCompiler.cpp
js/src/jit/CacheIRCompiler.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/cacheir/bug1439180.js
@@ -0,0 +1,9 @@
+h = function f(x) {
+        x = +"NaN";
+        return /I/ (~x);
+    }
+for (var j = 0; j < 3; j++) {
+    try {
+        h();
+    } catch (e) {}
+}
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -4857,16 +4857,18 @@ UnaryArithIRGenerator::trackAttached(con
 #endif
 }
 
 bool
 UnaryArithIRGenerator::tryAttachStub()
 {
     if (tryAttachInt32())
         return true;
+    if (tryAttachNumber())
+        return true;
 
     trackAttached(IRGenerator::NotAttached);
     return false;
 }
 
 bool
 UnaryArithIRGenerator::tryAttachInt32()
 {
@@ -4886,9 +4888,36 @@ UnaryArithIRGenerator::tryAttachInt32()
         trackAttached("UnaryArith.Int32Neg");
         break;
       default:
         MOZ_CRASH("Unexected OP");
     }
 
     writer.returnFromIC();
     return true;
+}
+
+bool
+UnaryArithIRGenerator::tryAttachNumber()
+{
+    if (!val_.isNumber() || !res_.isNumber() || !cx_->runtime()->jitSupportsFloatingPoint)
+        return false;
+
+    ValOperandId valId(writer.setInputOperandId(0));
+    writer.guardType(valId, JSVAL_TYPE_DOUBLE);
+    Int32OperandId truncatedId;
+    switch (op_) {
+      case JSOP_BITNOT:
+        truncatedId = writer.truncateDoubleToUInt32(valId);
+        writer.int32NotResult(truncatedId);
+        trackAttached("UnaryArith.DoubleNot");
+        break;
+      case JSOP_NEG:
+        writer.doubleNegationResult(valId);
+        trackAttached("UnaryArith.DoubleNeg");
+        break;
+      default:
+        MOZ_CRASH("Unexpected OP");
+    }
+
+    writer.returnFromIC();
+    return true;
 }
\ No newline at end of file
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -216,16 +216,18 @@ extern const char* CacheKindNames[];
     _(GuardFunctionPrototype)             \
     _(LoadStackValue)                     \
     _(LoadObject)                         \
     _(LoadProto)                          \
     _(LoadEnclosingEnvironment)           \
     _(LoadWrapperTarget)                  \
     _(LoadValueTag)                       \
                                           \
+    _(TruncateDoubleToUInt32)             \
+                                          \
     _(MegamorphicLoadSlotResult)          \
     _(MegamorphicLoadSlotByValueResult)   \
     _(MegamorphicStoreSlot)               \
     _(MegamorphicSetElement)              \
     _(MegamorphicHasPropResult)           \
                                           \
     /* See CacheIR.cpp 'DOM proxies' comment. */ \
     _(LoadDOMExpandoValue)                \
@@ -283,16 +285,17 @@ extern const char* CacheKindNames[];
     _(CallObjectHasSparseElementResult)   \
     _(LoadUndefinedResult)                \
     _(LoadBooleanResult)                  \
     _(LoadStringResult)                   \
     _(LoadInstanceOfObjectResult)         \
     _(LoadTypeOfObjectResult)             \
     _(Int32NotResult)                     \
     _(Int32NegationResult)                \
+    _(DoubleNegationResult)               \
     _(LoadInt32TruthyResult)              \
     _(LoadDoubleTruthyResult)             \
     _(LoadStringTruthyResult)             \
     _(LoadObjectTruthyResult)             \
     _(LoadValueResult)                    \
                                           \
     _(CallStringSplitResult)              \
                                           \
@@ -770,16 +773,23 @@ class MOZ_RAII CacheIRWriter : public JS
 
     ObjOperandId loadWrapperTarget(ObjOperandId obj) {
         ObjOperandId res(nextOperandId_++);
         writeOpWithOperandId(CacheOp::LoadWrapperTarget, obj);
         writeOperandId(res);
         return res;
     }
 
+    Int32OperandId truncateDoubleToUInt32(ValOperandId val) {
+        Int32OperandId res(nextOperandId_++);
+        writeOpWithOperandId(CacheOp::TruncateDoubleToUInt32, val);
+        writeOperandId(res);
+        return res;
+    }
+
     ValueTagOperandId loadValueTag(ValOperandId val) {
         ValueTagOperandId res(nextOperandId_++);
         writeOpWithOperandId(CacheOp::LoadValueTag, val);
         writeOperandId(res);
         return res;
     }
 
     ValOperandId loadDOMExpandoValue(ObjOperandId obj) {
@@ -967,16 +977,19 @@ class MOZ_RAII CacheIRWriter : public JS
     }
 
     void int32NotResult(Int32OperandId id) {
         writeOpWithOperandId(CacheOp::Int32NotResult, id);
     }
     void int32NegationResult(Int32OperandId id) {
         writeOpWithOperandId(CacheOp::Int32NegationResult, id);
     }
+    void doubleNegationResult(ValOperandId val) {
+        writeOpWithOperandId(CacheOp::DoubleNegationResult, val);
+    }
     void loadBooleanResult(bool val) {
         writeOp(CacheOp::LoadBooleanResult);
         buffer_.writeByte(uint32_t(val));
     }
     void loadUndefinedResult() {
         writeOp(CacheOp::LoadUndefinedResult);
     }
     void loadStringResult(JSString* str) {
@@ -1730,16 +1743,17 @@ class MOZ_RAII GetIntrinsicIRGenerator :
 
 class MOZ_RAII UnaryArithIRGenerator : public IRGenerator
 {
     JSOp op_;
     HandleValue val_;
     HandleValue res_;
 
     bool tryAttachInt32();
+    bool tryAttachNumber();
 
     void trackAttached(const char* name);
 
   public:
     UnaryArithIRGenerator(JSContext* cx, HandleScript, jsbytecode* pc, ICState::Mode mode,
                           JSOp op, HandleValue val, HandleValue res);
 
     bool tryAttachStub();
--- a/js/src/jit/CacheIRCompiler.cpp
+++ b/js/src/jit/CacheIRCompiler.cpp
@@ -12,16 +12,18 @@
 #include "builtin/Boolean-inl.h"
 
 #include "jit/MacroAssembler-inl.h"
 #include "vm/JSCompartment-inl.h"
 
 using namespace js;
 using namespace js::jit;
 
+using mozilla::BitwiseCast;
+
 ValueOperand
 CacheRegisterAllocator::useValueRegister(MacroAssembler& masm, ValOperandId op)
 {
     OperandLocation& loc = operandLocations_[op.id()];
 
     switch (loc.kind()) {
       case OperandLocation::ValueReg:
         currentOpRegs_.add(loc.valueReg());
@@ -1841,16 +1843,83 @@ CacheIRCompiler::emitInt32NotResult()
     AutoOutputRegister output(*this);
     Register val = allocator.useRegister(masm, reader.int32OperandId());
     masm.not32(val);
     masm.tagValue(JSVAL_TYPE_INT32, val, output.valueReg());
     return true;
 }
 
 bool
+CacheIRCompiler::emitDoubleNegationResult()
+{
+    AutoOutputRegister output(*this);
+    ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
+
+    FailurePath* failure;
+    if (!addFailurePath(&failure))
+        return false;
+
+    // If we're compiling a Baseline IC, FloatReg0 is always available.
+    Label failurePopReg, done;
+    if (mode_ != Mode::Baseline)
+        masm.push(FloatReg0);
+
+    masm.ensureDouble(val, FloatReg0, (mode_ != Mode::Baseline) ? &failurePopReg : failure->label());
+    masm.negateDouble(FloatReg0);
+    masm.boxDouble(FloatReg0, output.valueReg(), FloatReg0);
+
+    if (mode_ != Mode::Baseline) {
+        masm.pop(FloatReg0);
+        masm.jump(&done);
+
+        masm.bind(&failurePopReg);
+        masm.pop(FloatReg0);
+        masm.jump(failure->label());
+    }
+
+    masm.bind(&done);
+    return true;
+}
+
+bool
+CacheIRCompiler::emitTruncateDoubleToUInt32()
+{
+    ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
+    Register res = allocator.defineRegister(masm, reader.int32OperandId());
+
+    Label doneTruncate,  truncateABICall;
+    if (mode_ != Mode::Baseline)
+        masm.push(FloatReg0);
+
+    masm.unboxDouble(val, FloatReg0);
+    masm.branchTruncateDoubleMaybeModUint32(FloatReg0, res, &truncateABICall);
+    masm.jump(&doneTruncate);
+
+    masm.bind(&truncateABICall);
+    LiveRegisterSet save(GeneralRegisterSet::Volatile(), liveVolatileFloatRegs());
+    save.takeUnchecked(FloatReg0);
+    masm.PushRegsInMask(save);
+
+    masm.setupUnalignedABICall(res);
+    masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
+    masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32),
+                     MoveOp::GENERAL, CheckUnsafeCallWithABI::DontCheckOther);
+    masm.storeCallInt32Result(res);
+
+    LiveRegisterSet ignore;
+    ignore.add(res);
+    masm.PopRegsInMaskIgnore(save, ignore);
+
+    masm.bind(&doneTruncate);
+    if (mode_ != Mode::Baseline)
+        masm.pop(FloatReg0);
+    return true;
+}
+
+bool
 CacheIRCompiler::emitLoadArgumentsObjectLengthResult()
 {
     AutoOutputRegister output(*this);
     Register obj = allocator.useRegister(masm, reader.objOperandId());
     AutoScratchRegisterMaybeOutput scratch(allocator, masm, output);
 
     FailurePath* failure;
     if (!addFailurePath(&failure))
--- a/js/src/jit/CacheIRCompiler.h
+++ b/js/src/jit/CacheIRCompiler.h
@@ -46,16 +46,18 @@ namespace jit {
     _(LoadValueTag)                       \
     _(LoadDOMExpandoValue)                \
     _(LoadDOMExpandoValueIgnoreGeneration)\
     _(LoadUndefinedResult)                \
     _(LoadBooleanResult)                  \
     _(LoadInt32ArrayLengthResult)         \
     _(Int32NegationResult)                \
     _(Int32NotResult)                     \
+    _(DoubleNegationResult)               \
+    _(TruncateDoubleToUInt32)             \
     _(LoadArgumentsObjectLengthResult)    \
     _(LoadFunctionLengthResult)           \
     _(LoadStringLengthResult)             \
     _(LoadStringCharResult)               \
     _(LoadArgumentsObjectArgResult)       \
     _(LoadInstanceOfObjectResult)         \
     _(LoadDenseElementResult)             \
     _(LoadDenseElementHoleResult)         \