diff options
Diffstat (limited to 'js/src/jit/MoveResolver.cpp')
-rw-r--r-- | js/src/jit/MoveResolver.cpp | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/js/src/jit/MoveResolver.cpp b/js/src/jit/MoveResolver.cpp index 5fd6c7bd5..383b45073 100644 --- a/js/src/jit/MoveResolver.cpp +++ b/js/src/jit/MoveResolver.cpp @@ -106,12 +106,111 @@ MoveResolver::findCycledMove(PendingMoveIterator* iter, PendingMoveIterator end, return nullptr; } +#ifdef JS_CODEGEN_ARM +static inline bool +MoveIsDouble(const MoveOperand& move) +{ + if (!move.isFloatReg()) + return false; + return move.floatReg().isDouble(); +} +#endif + +#ifdef JS_CODEGEN_ARM +static inline bool +MoveIsSingle(const MoveOperand& move) +{ + if (!move.isFloatReg()) + return false; + return move.floatReg().isSingle(); +} +#endif + +#ifdef JS_CODEGEN_ARM +bool +MoveResolver::isDoubleAliasedAsSingle(const MoveOperand& move) +{ + if (!MoveIsDouble(move)) + return false; + + for (auto iter = pending_.begin(); iter != pending_.end(); ++iter) { + PendingMove* other = *iter; + if (other->from().aliases(move) && MoveIsSingle(other->from())) + return true; + if (other->to().aliases(move) && MoveIsSingle(other->to())) + return true; + } + return false; +} +#endif + +#ifdef JS_CODEGEN_ARM +static MoveOperand +SplitIntoLowerHalf(const MoveOperand& move) +{ + if (MoveIsDouble(move)) { + FloatRegister lowerSingle = move.floatReg().asSingle(); + return MoveOperand(lowerSingle); + } + + MOZ_ASSERT(move.isMemoryOrEffectiveAddress()); + return move; +} +#endif + +#ifdef JS_CODEGEN_ARM +static MoveOperand +SplitIntoUpperHalf(const MoveOperand& move) +{ + if (MoveIsDouble(move)) { + FloatRegister lowerSingle = move.floatReg().asSingle(); + FloatRegister upperSingle = VFPRegister(lowerSingle.code() + 1, VFPRegister::Single); + return MoveOperand(upperSingle); + } + + MOZ_ASSERT(move.isMemoryOrEffectiveAddress()); + return MoveOperand(move.base(), move.disp() + sizeof(float)); +} +#endif + bool MoveResolver::resolve() { resetState(); orderedMoves_.clear(); +#ifdef JS_CODEGEN_ARM + // Some of ARM's double registers alias two of its single registers, + // but the algorithm below assumes that every register can participate + // in at most one cycle. To satisfy the algorithm, any double registers + // that may conflict are split into their single-register halves. + // + // This logic is only applicable because ARM only uses registers d0-d15, + // all of which alias s0-s31. Double registers d16-d31 are unused. + // Therefore there is never a double move that cannot be split. + // If this changes in the future, the algorithm will have to be fixed. + for (auto iter = pending_.begin(); iter != pending_.end(); ++iter) { + PendingMove* pm = *iter; + + if (isDoubleAliasedAsSingle(pm->from()) || isDoubleAliasedAsSingle(pm->to())) { + PendingMove* lower = movePool_.allocate(); + if (!lower) + return false; + + // Insert the new node before the current position to not affect iteration. + MoveOperand fromLower = SplitIntoLowerHalf(pm->from()); + MoveOperand toLower = SplitIntoLowerHalf(pm->to()); + new (lower) PendingMove(fromLower, toLower, MoveOp::FLOAT32); + pending_.insertBefore(pm, lower); + + // Overwrite pm in place for the upper move. Iteration proceeds as normal. + MoveOperand fromUpper = SplitIntoUpperHalf(pm->from()); + MoveOperand toUpper = SplitIntoUpperHalf(pm->to()); + pm->overwrite(fromUpper, toUpper, MoveOp::FLOAT32); + } + } +#endif + InlineList<PendingMove> stack; // This is a depth-first-search without recursion, which tries to find |