mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-25 16:47:29 +09:00
Split double MoveOperands that conflict with floats.
This commit is contained in:
parent
4cdd40dc7f
commit
27bb9f94c3
3 changed files with 203 additions and 1 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -252,6 +252,13 @@ class MoveOp
|
|||
bool aliases(const MoveOp& other) const {
|
||||
return aliases(other.from()) || aliases(other.to());
|
||||
}
|
||||
#ifdef JS_CODEGEN_ARM
|
||||
void overwrite(MoveOperand& from, MoveOperand& to, Type type) {
|
||||
from_ = from;
|
||||
to_ = to;
|
||||
type_ = type;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class MoveResolver
|
||||
|
|
@ -299,6 +306,10 @@ class MoveResolver
|
|||
// Internal reset function. Does not clear lists.
|
||||
void resetState();
|
||||
|
||||
#ifdef JS_CODEGEN_ARM
|
||||
bool isDoubleAliasedAsSingle(const MoveOperand& move);
|
||||
#endif
|
||||
|
||||
public:
|
||||
MoveResolver();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if defined(JS_SIMULATOR_ARM)
|
||||
|
||||
#include "jit/arm/Assembler-arm.h"
|
||||
#include "jit/arm/MoveEmitter-arm.h"
|
||||
#include "jit/arm/Simulator-arm.h"
|
||||
|
|
@ -528,5 +529,96 @@ BEGIN_TEST(testJitMoveEmitterCycles_autogen3)
|
|||
return true;
|
||||
}
|
||||
END_TEST(testJitMoveEmitterCycles_autogen3)
|
||||
BEGIN_TEST(testJitMoveEmitterCycles_bug1299147_1)
|
||||
{
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
|
||||
TempAllocator alloc(&lifo);
|
||||
JitContext jc(cx, &alloc);
|
||||
cx->runtime()->getJitRuntime(cx);
|
||||
MacroAssembler masm;
|
||||
MoveEmitter mover(masm);
|
||||
MoveResolver mr;
|
||||
mr.setAllocator(alloc);
|
||||
Simulator* sim = Simulator::Current();
|
||||
// S2 -> S0
|
||||
// S2 -> S6
|
||||
// S3 -> S1
|
||||
// S3 -> S7
|
||||
// D0 -> D1
|
||||
// D0 -> D2
|
||||
TRY(mr.addMove(MoveOperand(s2), MoveOperand(s0), MoveOp::FLOAT32));
|
||||
TRY(mr.addMove(MoveOperand(s2), MoveOperand(s6), MoveOp::FLOAT32));
|
||||
sim->set_s_register_from_float(2, 2);
|
||||
TRY(mr.addMove(MoveOperand(s3), MoveOperand(s1), MoveOp::FLOAT32));
|
||||
TRY(mr.addMove(MoveOperand(s3), MoveOperand(s7), MoveOp::FLOAT32));
|
||||
sim->set_s_register_from_float(3, 4);
|
||||
TRY(mr.addMove(MoveOperand(d0), MoveOperand(d1), MoveOp::FLOAT32));
|
||||
TRY(mr.addMove(MoveOperand(d0), MoveOperand(d2), MoveOp::FLOAT32));
|
||||
sim->set_d_register_from_double(0, 1);
|
||||
// don't explode!
|
||||
TRY(mr.resolve());
|
||||
mover.emit(mr);
|
||||
mover.finish();
|
||||
masm.abiret();
|
||||
JitCode* code = linkAndAllocate(cx, &masm);
|
||||
sim->call(code->raw(), 1, 1);
|
||||
float f;
|
||||
double d;
|
||||
sim->get_double_from_d_register(1, &d);
|
||||
CHECK(d == 1);
|
||||
sim->get_double_from_d_register(2, &d);
|
||||
CHECK(d == 1);
|
||||
sim->get_float_from_s_register(0, &f);
|
||||
CHECK(int(f) == 2);
|
||||
sim->get_float_from_s_register(6, &f);
|
||||
CHECK(int(f) == 2);
|
||||
sim->get_float_from_s_register(1, &f);
|
||||
CHECK(int(f) == 4);
|
||||
sim->get_float_from_s_register(7, &f);
|
||||
CHECK(int(f) == 4);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitMoveEmitterCycles_bug1299147_1)
|
||||
BEGIN_TEST(testJitMoveEmitterCycles_bug1299147)
|
||||
{
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
|
||||
TempAllocator alloc(&lifo);
|
||||
JitContext jc(cx, &alloc);
|
||||
cx->runtime()->getJitRuntime(cx);
|
||||
MacroAssembler masm;
|
||||
MoveEmitter mover(masm);
|
||||
MoveResolver mr;
|
||||
mr.setAllocator(alloc);
|
||||
Simulator* sim = Simulator::Current();
|
||||
// S2 -> S5
|
||||
// S2 -> S6
|
||||
// D0 -> D1
|
||||
TRY(mr.addMove(MoveOperand(s2), MoveOperand(s5), MoveOp::FLOAT32));
|
||||
TRY(mr.addMove(MoveOperand(s2), MoveOperand(s6), MoveOp::FLOAT32));
|
||||
sim->set_s_register_from_float(2, 2);
|
||||
TRY(mr.addMove(MoveOperand(d0), MoveOperand(d1), MoveOp::FLOAT32));
|
||||
sim->set_d_register_from_double(0, 1);
|
||||
// don't explode!
|
||||
TRY(mr.resolve());
|
||||
mover.emit(mr);
|
||||
mover.finish();
|
||||
masm.abiret();
|
||||
JitCode* code = linkAndAllocate(cx, &masm);
|
||||
sim->call(code->raw(), 1, 1);
|
||||
float f;
|
||||
double d;
|
||||
sim->get_double_from_d_register(1, &d);
|
||||
CHECK(d == 1);
|
||||
sim->get_float_from_s_register(5, &f);
|
||||
CHECK(int(f) == 2);
|
||||
sim->get_float_from_s_register(6, &f);
|
||||
CHECK(int(f) == 2);
|
||||
return true;
|
||||
}
|
||||
END_TEST(testJitMoveEmitterCycles_bug1299147)
|
||||
|
||||
#endif
|
||||
#endif // JS_SIMULATOR_ARM
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue