mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 13:23:07 +00:00
fc52b62763
- Bug 1204192 - IonMonkey: MIPS: Split shareable code to mips-shared in BaselineIC-mips32. r=nbp (eeae38da4e)
- Bug 1204193 - IonMonkey: MIPS: Split shareable code to mips-shared in Bailouts-mips32. r=nbp (f24f496235)
- Bug 1204194 - IonMonkey: MIPS: Split shareable code to mips-shared in MoveEmitter-mips32. r=nbp (5c3bdc2fc2)
- Bug 1204214 - IonMonkey: MIPS: Split shareable code to mips-shared in BaselineCompiler-mips32. r=nbp (01903406d1)
- Bug 1205229 - IonMonkey: MIPS32: Make more CodeGenerator functions can be shared. r=nbp (d437fe618e)
- Bug 1209528 - IonMonkey: MIPS32: Add suffix 'f' for constant float32. r=arai (0f6600c083)
- Bug 1205232 - IonMonkey: MIPS32: Fix rounding of big negative float32 values in Ion. r=bbouvier (4652bb9b7a)
- Bug 1203044 - IonMonkey: MIPS32: Atomics operations should throw on oob access. r=lth (e898b3af95)
- Bug 1205135 - IonMonkey: MIPS: Split shareable code to mips-shared in CodeGenerator-mips32. r=nbp (b6d81b922d)
- readd some missing bits (2aa8c9fafd)
- Bug 1167189: Remove unnecessary checks after infallible allocations. r=bholley (fa7d8b9f7b)
- Bug 1209398 - Make AC_SUBST_SET emit a list of unique items instead of an actual set. r=gps (83e5877882)
- Bug 904572 - Add support for generating clang compilation database; r=glandium,r=gps (ab3e6e62fa)
- Bug 1209398 - Enable the FasterMake backend by default for desktop Firefox builds. r=gps (29f6fb3883)
- Bug 1204719 - Don't create interfaces.manifest files from the build backend. r=gps (5a63e36259)
- Bug 786520 - Install things to $(DIST)/branding from moz.build instead of manual rules in Makefile.ins. r=mshal (652552b547)
- Bug 1160563 - Part 1: Make ANDROID_RES_DIRS a moz.build variable. r=gps (e0719524f8)
- Bug 1159390 - Set sharedUserId in robocop.apk. r=gbrown (dde6716e2d)
- Bug 1160030 - Use TEST_HARNESS_FILES to install Robocop test files. r=froydnj (00cd01c3f2)
- Bug 1160030 - Use TEST_HARNESS_FILES to install Robocop ini files. r=froydnj (66d52518e7)
- Bug 938659 - Part 2: build system changes. r=mfinkle (0833d22ba3)
- Bug 1160563 - Pre: Allow ANDROID_RES_DIRS that are not relative to srcdir. r=gps (0d8a3ce66e)
- Bug 1160563 - Part 2: Make ANDROID_ASSETS_DIRS a moz.build variable. r=gps (9f4c132e2a)
- Bug 1195388 - Part 1: Make ANDROID_APK_{NAME,PACKAGE} moz.build variables. r=gps (4a2fa3fc09)
- Bug 1195388 - Part 2: Add ANDROID_EXTRA_{PACKAGES,RES_DIRS} moz.buildvariables. r=gps (7ad49e355e)
- Bug 1207893 - Change how we track object consumption from the build backend. r=gps (20ccc5b67a)
- Bug 1184405 - Add annotations for tags, file patterns, and test flavos to moz.build to specify tests potentially impacted by source files. r=gps (2db17131cc)
- Bug 1171105 - Ability to aggregate metadata from Files instances; r=glandium (59c8759e61)
- Bug 1184405 - Add a container type to mozbuild with a namedtuple-likeinterface and typed, mutable fields. r=gps (3062dbae71)
- Bug 1138283 - Fix bad documentation around wildcard patterns; r=glandium (5785d3284d)
- Bug 1155816 - part 2 - move EXTRA_*COMPONENTS manifest check to buildbackend time; r=mshal (c539616b45)
- Bug 1161270 - Add source manifest to reftest manifest representation in moz.build.;r=gps,roc (376b080084)
- Bug 1180813 - Use a cache for BuildConfig to improve mach speed. r=gps (d431b1ec23)
- Bug 1207882 - Associate an install target with every ContextDerived object. r=gps (62f63487a7)
- Bug 1126228 - Directory (--directory) argument for |mach warnings-list| and |mach warnings-summary|. r=gps (37a85d904f)
- Bug 1210642 - Allow to pass defines overrides when processing install manifests. r=gps (5eb483dc8d)
- Bug 1210642 - Add support for --silence-missing-directive-warnings for preprocessing within install manifests. r=gps (3a07d30b36)
- Bug 1176642 - Use absolute_import in mozpack; r=glandium (863ab20c4a)
- Bug 1162826 - Properly display full moz.build processing errors when empty KeyError or ValueError are thrown. r=mshal (57e8367680)
- Bug 1184405 - Add a mach command to expose test-deps file info. r=gps (7bcc10679c)
- Bug 1195735, r=zer0 (7fe14224e3)
- Bug 1205166 - IonMonkey: MIPS: Import MIPS64 support into Architecture-mips-shared. r=nbp f=rankov (84e1f9ec5d)
- Bug 1205166 - IonMonkey: MIPS64: Import Architecture-mips64. r=nbp f=rankov (fe173dd5af)
- Bug 1210322 - IonMonkey: MIPS: Rename BaseFloatRegister/s to FloatRegister/sMIPSShared. r=nbp (ac262cbb5d)
- Bug 1205167 - IonMonkey: MIPS64: Import Assembler-mips64. r=nbp f=rankov (079e84ea49)
- Bug 1215555 - Improve simulated OOM testing of ARM assembler buffer and fix bugs r=jolesen (253b976cec)
- Bug 1205167 - IonMonkey: MIPS: Import MIPS64 support into Assembler-mips-shared. r=froydnj f=rankov (94b23ac585)
- Bug 1213146 - IonMonkey: MIPS: Fix build failure caused by bug 1194139. r=nbp (12f7d5d572)
- Bug 1205566 - IonMonkey: MIPS: bailoutCmp32/Ptr optimization. r=nbp (9a40ee80d0)
- Bug 1209873 - IonMonkey; MIPS: Implement memory barrier. r=lth (964535cb6b)
- Bug 1209572 - IonMonkey: MIPS32: Goto done by short jump in convertUInt32ToFloat32. r=nbp (0b388199e7)
- pointer style (312fc6fe4f)
- missing bit of Bug 1140890 - Make sure the first argument cannot bail in between negative zero removal and creating result in substraction, r=nbp (afcc9bfdc7)
- and sync more build scripts with frontend branch
1891 lines
60 KiB
C++
1891 lines
60 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
* vim: set ts=8 sts=4 et sw=4 tw=99:
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#include "jit/mips-shared/CodeGenerator-mips-shared.h"
|
|
|
|
#include "mozilla/MathAlgorithms.h"
|
|
|
|
#include "jscntxt.h"
|
|
#include "jscompartment.h"
|
|
#include "jsnum.h"
|
|
|
|
#include "jit/CodeGenerator.h"
|
|
#include "jit/JitCompartment.h"
|
|
#include "jit/JitFrames.h"
|
|
#include "jit/MIR.h"
|
|
#include "jit/MIRGraph.h"
|
|
#include "js/Conversions.h"
|
|
#include "vm/Shape.h"
|
|
#include "vm/TraceLogging.h"
|
|
|
|
#include "jsscriptinlines.h"
|
|
|
|
#include "jit/MacroAssembler-inl.h"
|
|
#include "jit/shared/CodeGenerator-shared-inl.h"
|
|
|
|
using namespace js;
|
|
using namespace js::jit;
|
|
|
|
using mozilla::FloorLog2;
|
|
using mozilla::NegativeInfinity;
|
|
using JS::GenericNaN;
|
|
using JS::ToInt32;
|
|
|
|
// inline
|
|
Address
|
|
CodeGeneratorMIPSShared::ToAddress(const LAllocation& a)
|
|
{
|
|
MOZ_ASSERT(a.isMemory());
|
|
int32_t offset = ToStackOffset(&a);
|
|
|
|
return Address(StackPointer, offset);
|
|
}
|
|
|
|
// inline
|
|
Address
|
|
CodeGeneratorMIPSShared::ToAddress(const LAllocation* a)
|
|
{
|
|
return ToAddress(*a);
|
|
}
|
|
|
|
|
|
// shared
|
|
CodeGeneratorMIPSShared::CodeGeneratorMIPSShared(MIRGenerator* gen, LIRGraph* graph, MacroAssembler* masm)
|
|
: CodeGeneratorShared(gen, graph, masm)
|
|
{
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::branchToBlock(Assembler::FloatFormat fmt, FloatRegister lhs, FloatRegister rhs,
|
|
MBasicBlock* mir, Assembler::DoubleCondition cond)
|
|
{
|
|
// Skip past trivial blocks.
|
|
mir = skipTrivialBlocks(mir);
|
|
|
|
Label* label = mir->lir()->label();
|
|
if (Label* oolEntry = labelForBackedgeWithImplicitCheck(mir)) {
|
|
// Note: the backedge is initially a jump to the next instruction.
|
|
// It will be patched to the target block's label during link().
|
|
RepatchLabel rejoin;
|
|
|
|
CodeOffsetJump backedge;
|
|
Label skip;
|
|
if (fmt == Assembler::DoubleFloat)
|
|
masm.ma_bc1d(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump);
|
|
else
|
|
masm.ma_bc1s(lhs, rhs, &skip, Assembler::InvertCondition(cond), ShortJump);
|
|
|
|
backedge = masm.backedgeJump(&rejoin);
|
|
masm.bind(&rejoin);
|
|
masm.bind(&skip);
|
|
|
|
if (!patchableBackedges_.append(PatchableBackedgeInfo(backedge, label, oolEntry)))
|
|
MOZ_CRASH();
|
|
} else {
|
|
if (fmt == Assembler::DoubleFloat)
|
|
masm.branchDouble(cond, lhs, rhs, mir->lir()->label());
|
|
else
|
|
masm.branchFloat(cond, lhs, rhs, mir->lir()->label());
|
|
}
|
|
}
|
|
|
|
void
|
|
OutOfLineBailout::accept(CodeGeneratorMIPSShared* codegen)
|
|
{
|
|
codegen->visitOutOfLineBailout(this);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitTestIAndBranch(LTestIAndBranch* test)
|
|
{
|
|
const LAllocation* opd = test->getOperand(0);
|
|
MBasicBlock* ifTrue = test->ifTrue();
|
|
MBasicBlock* ifFalse = test->ifFalse();
|
|
|
|
emitBranch(ToRegister(opd), Imm32(0), Assembler::NonZero, ifTrue, ifFalse);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitCompare(LCompare* comp)
|
|
{
|
|
Assembler::Condition cond = JSOpToCondition(comp->mir()->compareType(), comp->jsop());
|
|
const LAllocation* left = comp->getOperand(0);
|
|
const LAllocation* right = comp->getOperand(1);
|
|
const LDefinition* def = comp->getDef(0);
|
|
|
|
if (right->isConstant())
|
|
masm.cmp32Set(cond, ToRegister(left), Imm32(ToInt32(right)), ToRegister(def));
|
|
else if (right->isGeneralReg())
|
|
masm.cmp32Set(cond, ToRegister(left), ToRegister(right), ToRegister(def));
|
|
else
|
|
masm.cmp32Set(cond, ToRegister(left), ToAddress(right), ToRegister(def));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitCompareAndBranch(LCompareAndBranch* comp)
|
|
{
|
|
Assembler::Condition cond = JSOpToCondition(comp->cmpMir()->compareType(), comp->jsop());
|
|
if (comp->right()->isConstant()) {
|
|
emitBranch(ToRegister(comp->left()), Imm32(ToInt32(comp->right())), cond,
|
|
comp->ifTrue(), comp->ifFalse());
|
|
} else if (comp->right()->isGeneralReg()) {
|
|
emitBranch(ToRegister(comp->left()), ToRegister(comp->right()), cond,
|
|
comp->ifTrue(), comp->ifFalse());
|
|
} else {
|
|
masm.load32(ToAddress(comp->right()), ScratchRegister);
|
|
emitBranch(ToRegister(comp->left()), ScratchRegister, cond,
|
|
comp->ifTrue(), comp->ifFalse());
|
|
}
|
|
}
|
|
|
|
bool
|
|
CodeGeneratorMIPSShared::generateOutOfLineCode()
|
|
{
|
|
if (!CodeGeneratorShared::generateOutOfLineCode())
|
|
return false;
|
|
|
|
if (deoptLabel_.used()) {
|
|
// All non-table-based bailouts will go here.
|
|
masm.bind(&deoptLabel_);
|
|
|
|
// Push the frame size, so the handler can recover the IonScript.
|
|
// Frame size is stored in 'ra' and pushed by GenerateBailoutThunk
|
|
// We have to use 'ra' because generateBailoutTable will implicitly do
|
|
// the same.
|
|
masm.move32(Imm32(frameSize()), ra);
|
|
|
|
JitCode* handler = gen->jitRuntime()->getGenericBailoutHandler();
|
|
|
|
masm.branch(handler);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::bailoutFrom(Label* label, LSnapshot* snapshot)
|
|
{
|
|
if (masm.bailed())
|
|
return;
|
|
|
|
MOZ_ASSERT(label->used());
|
|
MOZ_ASSERT(!label->bound());
|
|
|
|
encode(snapshot);
|
|
|
|
// Though the assembler doesn't track all frame pushes, at least make sure
|
|
// the known value makes sense. We can't use bailout tables if the stack
|
|
// isn't properly aligned to the static frame size.
|
|
MOZ_ASSERT_IF(frameClass_ != FrameSizeClass::None(),
|
|
frameClass_.frameSize() == masm.framePushed());
|
|
|
|
// We don't use table bailouts because retargeting is easier this way.
|
|
InlineScriptTree* tree = snapshot->mir()->block()->trackedTree();
|
|
OutOfLineBailout* ool = new(alloc()) OutOfLineBailout(snapshot, masm.framePushed());
|
|
addOutOfLineCode(ool, new(alloc()) BytecodeSite(tree, tree->script()->code()));
|
|
|
|
masm.retarget(label, ool->entry());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::bailout(LSnapshot* snapshot)
|
|
{
|
|
Label label;
|
|
masm.jump(&label);
|
|
bailoutFrom(&label, snapshot);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitOutOfLineBailout(OutOfLineBailout* ool)
|
|
{
|
|
// Push snapshotOffset and make sure stack is aligned.
|
|
masm.subPtr(Imm32(2 * sizeof(void*)), StackPointer);
|
|
masm.storePtr(ImmWord(ool->snapshot()->snapshotOffset()), Address(StackPointer, 0));
|
|
|
|
masm.jump(&deoptLabel_);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitMinMaxD(LMinMaxD* ins)
|
|
{
|
|
FloatRegister first = ToFloatRegister(ins->first());
|
|
FloatRegister second = ToFloatRegister(ins->second());
|
|
FloatRegister output = ToFloatRegister(ins->output());
|
|
|
|
MOZ_ASSERT(first == output);
|
|
|
|
Assembler::DoubleCondition cond = ins->mir()->isMax()
|
|
? Assembler::DoubleLessThanOrEqual
|
|
: Assembler::DoubleGreaterThanOrEqual;
|
|
Label nan, equal, returnSecond, done;
|
|
|
|
// First or second is NaN, result is NaN.
|
|
masm.ma_bc1d(first, second, &nan, Assembler::DoubleUnordered, ShortJump);
|
|
// Make sure we handle -0 and 0 right.
|
|
masm.ma_bc1d(first, second, &equal, Assembler::DoubleEqual, ShortJump);
|
|
masm.ma_bc1d(first, second, &returnSecond, cond, ShortJump);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
// Check for zero.
|
|
masm.bind(&equal);
|
|
masm.loadConstantDouble(0.0, ScratchDoubleReg);
|
|
// First wasn't 0 or -0, so just return it.
|
|
masm.ma_bc1d(first, ScratchDoubleReg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump);
|
|
|
|
// So now both operands are either -0 or 0.
|
|
if (ins->mir()->isMax()) {
|
|
// -0 + -0 = -0 and -0 + 0 = 0.
|
|
masm.addDouble(second, first);
|
|
} else {
|
|
masm.negateDouble(first);
|
|
masm.subDouble(second, first);
|
|
masm.negateDouble(first);
|
|
}
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&nan);
|
|
masm.loadConstantDouble(GenericNaN(), output);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&returnSecond);
|
|
masm.moveDouble(second, output);
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitMinMaxF(LMinMaxF* ins)
|
|
{
|
|
FloatRegister first = ToFloatRegister(ins->first());
|
|
FloatRegister second = ToFloatRegister(ins->second());
|
|
FloatRegister output = ToFloatRegister(ins->output());
|
|
|
|
MOZ_ASSERT(first == output);
|
|
|
|
Assembler::DoubleCondition cond = ins->mir()->isMax()
|
|
? Assembler::DoubleLessThanOrEqual
|
|
: Assembler::DoubleGreaterThanOrEqual;
|
|
Label nan, equal, returnSecond, done;
|
|
|
|
// First or second is NaN, result is NaN.
|
|
masm.ma_bc1s(first, second, &nan, Assembler::DoubleUnordered, ShortJump);
|
|
// Make sure we handle -0 and 0 right.
|
|
masm.ma_bc1s(first, second, &equal, Assembler::DoubleEqual, ShortJump);
|
|
masm.ma_bc1s(first, second, &returnSecond, cond, ShortJump);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
// Check for zero.
|
|
masm.bind(&equal);
|
|
masm.loadConstantFloat32(0.0f, ScratchFloat32Reg);
|
|
// First wasn't 0 or -0, so just return it.
|
|
masm.ma_bc1s(first, ScratchFloat32Reg, &done, Assembler::DoubleNotEqualOrUnordered, ShortJump);
|
|
|
|
// So now both operands are either -0 or 0.
|
|
if (ins->mir()->isMax()) {
|
|
// -0 + -0 = -0 and -0 + 0 = 0.
|
|
masm.as_adds(first, first, second);
|
|
} else {
|
|
masm.as_negs(first, first);
|
|
masm.as_subs(first, first, second);
|
|
masm.as_negs(first, first);
|
|
}
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&nan);
|
|
masm.loadConstantFloat32(GenericNaN(), output);
|
|
masm.ma_b(&done, ShortJump);
|
|
masm.bind(&returnSecond);
|
|
masm.as_movs(output, second);
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAbsD(LAbsD* ins)
|
|
{
|
|
FloatRegister input = ToFloatRegister(ins->input());
|
|
MOZ_ASSERT(input == ToFloatRegister(ins->output()));
|
|
masm.as_absd(input, input);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAbsF(LAbsF* ins)
|
|
{
|
|
FloatRegister input = ToFloatRegister(ins->input());
|
|
MOZ_ASSERT(input == ToFloatRegister(ins->output()));
|
|
masm.as_abss(input, input);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitSqrtD(LSqrtD* ins)
|
|
{
|
|
FloatRegister input = ToFloatRegister(ins->input());
|
|
FloatRegister output = ToFloatRegister(ins->output());
|
|
masm.as_sqrtd(output, input);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitSqrtF(LSqrtF* ins)
|
|
{
|
|
FloatRegister input = ToFloatRegister(ins->input());
|
|
FloatRegister output = ToFloatRegister(ins->output());
|
|
masm.as_sqrts(output, input);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAddI(LAddI* ins)
|
|
{
|
|
const LAllocation* lhs = ins->getOperand(0);
|
|
const LAllocation* rhs = ins->getOperand(1);
|
|
const LDefinition* dest = ins->getDef(0);
|
|
|
|
MOZ_ASSERT(rhs->isConstant() || rhs->isGeneralReg());
|
|
|
|
// If there is no snapshot, we don't need to check for overflow
|
|
if (!ins->snapshot()) {
|
|
if (rhs->isConstant())
|
|
masm.ma_addu(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
|
|
else
|
|
masm.as_addu(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
|
return;
|
|
}
|
|
|
|
Label overflow;
|
|
if (rhs->isConstant())
|
|
masm.ma_addTestOverflow(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)), &overflow);
|
|
else
|
|
masm.ma_addTestOverflow(ToRegister(dest), ToRegister(lhs), ToRegister(rhs), &overflow);
|
|
|
|
bailoutFrom(&overflow, ins->snapshot());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitSubI(LSubI* ins)
|
|
{
|
|
const LAllocation* lhs = ins->getOperand(0);
|
|
const LAllocation* rhs = ins->getOperand(1);
|
|
const LDefinition* dest = ins->getDef(0);
|
|
|
|
MOZ_ASSERT(rhs->isConstant() || rhs->isGeneralReg());
|
|
|
|
// If there is no snapshot, we don't need to check for overflow
|
|
if (!ins->snapshot()) {
|
|
if (rhs->isConstant())
|
|
masm.ma_subu(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
|
|
else
|
|
masm.as_subu(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
|
return;
|
|
}
|
|
|
|
Label overflow;
|
|
if (rhs->isConstant())
|
|
masm.ma_subTestOverflow(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)), &overflow);
|
|
else
|
|
masm.ma_subTestOverflow(ToRegister(dest), ToRegister(lhs), ToRegister(rhs), &overflow);
|
|
|
|
bailoutFrom(&overflow, ins->snapshot());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitMulI(LMulI* ins)
|
|
{
|
|
const LAllocation* lhs = ins->lhs();
|
|
const LAllocation* rhs = ins->rhs();
|
|
Register dest = ToRegister(ins->output());
|
|
MMul* mul = ins->mir();
|
|
|
|
MOZ_ASSERT_IF(mul->mode() == MMul::Integer, !mul->canBeNegativeZero() && !mul->canOverflow());
|
|
|
|
if (rhs->isConstant()) {
|
|
int32_t constant = ToInt32(rhs);
|
|
Register src = ToRegister(lhs);
|
|
|
|
// Bailout on -0.0
|
|
if (mul->canBeNegativeZero() && constant <= 0) {
|
|
Assembler::Condition cond = (constant == 0) ? Assembler::LessThan : Assembler::Equal;
|
|
bailoutCmp32(cond, src, Imm32(0), ins->snapshot());
|
|
}
|
|
|
|
switch (constant) {
|
|
case -1:
|
|
if (mul->canOverflow())
|
|
bailoutCmp32(Assembler::Equal, src, Imm32(INT32_MIN), ins->snapshot());
|
|
|
|
masm.ma_negu(dest, src);
|
|
break;
|
|
case 0:
|
|
masm.move32(Imm32(0), dest);
|
|
break;
|
|
case 1:
|
|
masm.move32(src, dest);
|
|
break;
|
|
case 2:
|
|
if (mul->canOverflow()) {
|
|
Label mulTwoOverflow;
|
|
masm.ma_addTestOverflow(dest, src, src, &mulTwoOverflow);
|
|
|
|
bailoutFrom(&mulTwoOverflow, ins->snapshot());
|
|
} else {
|
|
masm.as_addu(dest, src, src);
|
|
}
|
|
break;
|
|
default:
|
|
uint32_t shift = FloorLog2(constant);
|
|
|
|
if (!mul->canOverflow() && (constant > 0)) {
|
|
// If it cannot overflow, we can do lots of optimizations.
|
|
uint32_t rest = constant - (1 << shift);
|
|
|
|
// See if the constant has one bit set, meaning it can be
|
|
// encoded as a bitshift.
|
|
if ((1 << shift) == constant) {
|
|
masm.ma_sll(dest, src, Imm32(shift));
|
|
return;
|
|
}
|
|
|
|
// If the constant cannot be encoded as (1<<C1), see if it can
|
|
// be encoded as (1<<C1) | (1<<C2), which can be computed
|
|
// using an add and a shift.
|
|
uint32_t shift_rest = FloorLog2(rest);
|
|
if (src != dest && (1u << shift_rest) == rest) {
|
|
masm.ma_sll(dest, src, Imm32(shift - shift_rest));
|
|
masm.add32(src, dest);
|
|
if (shift_rest != 0)
|
|
masm.ma_sll(dest, dest, Imm32(shift_rest));
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (mul->canOverflow() && (constant > 0) && (src != dest)) {
|
|
// To stay on the safe side, only optimize things that are a
|
|
// power of 2.
|
|
|
|
if ((1 << shift) == constant) {
|
|
// dest = lhs * pow(2, shift)
|
|
masm.ma_sll(dest, src, Imm32(shift));
|
|
// At runtime, check (lhs == dest >> shift), if this does
|
|
// not hold, some bits were lost due to overflow, and the
|
|
// computation should be resumed as a double.
|
|
masm.ma_sra(ScratchRegister, dest, Imm32(shift));
|
|
bailoutCmp32(Assembler::NotEqual, src, ScratchRegister, ins->snapshot());
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (mul->canOverflow()) {
|
|
Label mulConstOverflow;
|
|
masm.ma_mul_branch_overflow(dest, ToRegister(lhs), Imm32(ToInt32(rhs)),
|
|
&mulConstOverflow);
|
|
|
|
bailoutFrom(&mulConstOverflow, ins->snapshot());
|
|
} else {
|
|
masm.ma_mult(src, Imm32(ToInt32(rhs)));
|
|
masm.as_mflo(dest);
|
|
}
|
|
break;
|
|
}
|
|
} else {
|
|
Label multRegOverflow;
|
|
|
|
if (mul->canOverflow()) {
|
|
masm.ma_mul_branch_overflow(dest, ToRegister(lhs), ToRegister(rhs), &multRegOverflow);
|
|
bailoutFrom(&multRegOverflow, ins->snapshot());
|
|
} else {
|
|
masm.as_mult(ToRegister(lhs), ToRegister(rhs));
|
|
masm.as_mflo(dest);
|
|
}
|
|
|
|
if (mul->canBeNegativeZero()) {
|
|
Label done;
|
|
masm.ma_b(dest, dest, &done, Assembler::NonZero, ShortJump);
|
|
|
|
// Result is -0 if lhs or rhs is negative.
|
|
// In that case result must be double value so bailout
|
|
Register scratch = SecondScratchReg;
|
|
masm.as_or(scratch, ToRegister(lhs), ToRegister(rhs));
|
|
bailoutCmp32(Assembler::Signed, scratch, scratch, ins->snapshot());
|
|
|
|
masm.bind(&done);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitDivI(LDivI* ins)
|
|
{
|
|
// Extract the registers from this instruction
|
|
Register lhs = ToRegister(ins->lhs());
|
|
Register rhs = ToRegister(ins->rhs());
|
|
Register dest = ToRegister(ins->output());
|
|
Register temp = ToRegister(ins->getTemp(0));
|
|
MDiv* mir = ins->mir();
|
|
|
|
Label done;
|
|
|
|
// Handle divide by zero.
|
|
if (mir->canBeDivideByZero()) {
|
|
if (mir->canTruncateInfinities()) {
|
|
// Truncated division by zero is zero (Infinity|0 == 0)
|
|
Label notzero;
|
|
masm.ma_b(rhs, rhs, ¬zero, Assembler::NonZero, ShortJump);
|
|
masm.move32(Imm32(0), dest);
|
|
masm.ma_b(&done, ShortJump);
|
|
masm.bind(¬zero);
|
|
} else {
|
|
MOZ_ASSERT(mir->fallible());
|
|
bailoutCmp32(Assembler::Zero, rhs, rhs, ins->snapshot());
|
|
}
|
|
}
|
|
|
|
// Handle an integer overflow exception from -2147483648 / -1.
|
|
if (mir->canBeNegativeOverflow()) {
|
|
Label notMinInt;
|
|
masm.move32(Imm32(INT32_MIN), temp);
|
|
masm.ma_b(lhs, temp, ¬MinInt, Assembler::NotEqual, ShortJump);
|
|
|
|
masm.move32(Imm32(-1), temp);
|
|
if (mir->canTruncateOverflow()) {
|
|
// (-INT32_MIN)|0 == INT32_MIN
|
|
Label skip;
|
|
masm.ma_b(rhs, temp, &skip, Assembler::NotEqual, ShortJump);
|
|
masm.move32(Imm32(INT32_MIN), dest);
|
|
masm.ma_b(&done, ShortJump);
|
|
masm.bind(&skip);
|
|
} else {
|
|
MOZ_ASSERT(mir->fallible());
|
|
bailoutCmp32(Assembler::Equal, rhs, temp, ins->snapshot());
|
|
}
|
|
masm.bind(¬MinInt);
|
|
}
|
|
|
|
// Handle negative 0. (0/-Y)
|
|
if (!mir->canTruncateNegativeZero() && mir->canBeNegativeZero()) {
|
|
Label nonzero;
|
|
masm.ma_b(lhs, lhs, &nonzero, Assembler::NonZero, ShortJump);
|
|
bailoutCmp32(Assembler::LessThan, rhs, Imm32(0), ins->snapshot());
|
|
masm.bind(&nonzero);
|
|
}
|
|
// Note: above safety checks could not be verified as Ion seems to be
|
|
// smarter and requires double arithmetic in such cases.
|
|
|
|
// All regular. Lets call div.
|
|
if (mir->canTruncateRemainder()) {
|
|
masm.as_div(lhs, rhs);
|
|
masm.as_mflo(dest);
|
|
} else {
|
|
MOZ_ASSERT(mir->fallible());
|
|
|
|
Label remainderNonZero;
|
|
masm.ma_div_branch_overflow(dest, lhs, rhs, &remainderNonZero);
|
|
bailoutFrom(&remainderNonZero, ins->snapshot());
|
|
}
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitDivPowTwoI(LDivPowTwoI* ins)
|
|
{
|
|
Register lhs = ToRegister(ins->numerator());
|
|
Register dest = ToRegister(ins->output());
|
|
Register tmp = ToRegister(ins->getTemp(0));
|
|
int32_t shift = ins->shift();
|
|
|
|
if (shift != 0) {
|
|
MDiv* mir = ins->mir();
|
|
if (!mir->isTruncated()) {
|
|
// If the remainder is going to be != 0, bailout since this must
|
|
// be a double.
|
|
masm.ma_sll(tmp, lhs, Imm32(32 - shift));
|
|
bailoutCmp32(Assembler::NonZero, tmp, tmp, ins->snapshot());
|
|
}
|
|
|
|
if (!mir->canBeNegativeDividend()) {
|
|
// Numerator is unsigned, so needs no adjusting. Do the shift.
|
|
masm.ma_sra(dest, lhs, Imm32(shift));
|
|
return;
|
|
}
|
|
|
|
// Adjust the value so that shifting produces a correctly rounded result
|
|
// when the numerator is negative. See 10-1 "Signed Division by a Known
|
|
// Power of 2" in Henry S. Warren, Jr.'s Hacker's Delight.
|
|
if (shift > 1) {
|
|
masm.ma_sra(tmp, lhs, Imm32(31));
|
|
masm.ma_srl(tmp, tmp, Imm32(32 - shift));
|
|
masm.add32(lhs, tmp);
|
|
} else {
|
|
masm.ma_srl(tmp, lhs, Imm32(32 - shift));
|
|
masm.add32(lhs, tmp);
|
|
}
|
|
|
|
// Do the shift.
|
|
masm.ma_sra(dest, tmp, Imm32(shift));
|
|
} else {
|
|
masm.move32(lhs, dest);
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitModI(LModI* ins)
|
|
{
|
|
// Extract the registers from this instruction
|
|
Register lhs = ToRegister(ins->lhs());
|
|
Register rhs = ToRegister(ins->rhs());
|
|
Register dest = ToRegister(ins->output());
|
|
Register callTemp = ToRegister(ins->callTemp());
|
|
MMod* mir = ins->mir();
|
|
Label done, prevent;
|
|
|
|
masm.move32(lhs, callTemp);
|
|
|
|
// Prevent INT_MIN % -1;
|
|
// The integer division will give INT_MIN, but we want -(double)INT_MIN.
|
|
if (mir->canBeNegativeDividend()) {
|
|
masm.ma_b(lhs, Imm32(INT_MIN), &prevent, Assembler::NotEqual, ShortJump);
|
|
if (mir->isTruncated()) {
|
|
// (INT_MIN % -1)|0 == 0
|
|
Label skip;
|
|
masm.ma_b(rhs, Imm32(-1), &skip, Assembler::NotEqual, ShortJump);
|
|
masm.move32(Imm32(0), dest);
|
|
masm.ma_b(&done, ShortJump);
|
|
masm.bind(&skip);
|
|
} else {
|
|
MOZ_ASSERT(mir->fallible());
|
|
bailoutCmp32(Assembler::Equal, rhs, Imm32(-1), ins->snapshot());
|
|
}
|
|
masm.bind(&prevent);
|
|
}
|
|
|
|
// 0/X (with X < 0) is bad because both of these values *should* be
|
|
// doubles, and the result should be -0.0, which cannot be represented in
|
|
// integers. X/0 is bad because it will give garbage (or abort), when it
|
|
// should give either \infty, -\infty or NAN.
|
|
|
|
// Prevent 0 / X (with X < 0) and X / 0
|
|
// testing X / Y. Compare Y with 0.
|
|
// There are three cases: (Y < 0), (Y == 0) and (Y > 0)
|
|
// If (Y < 0), then we compare X with 0, and bail if X == 0
|
|
// If (Y == 0), then we simply want to bail.
|
|
// if (Y > 0), we don't bail.
|
|
|
|
if (mir->canBeDivideByZero()) {
|
|
if (mir->isTruncated()) {
|
|
Label skip;
|
|
masm.ma_b(rhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump);
|
|
masm.move32(Imm32(0), dest);
|
|
masm.ma_b(&done, ShortJump);
|
|
masm.bind(&skip);
|
|
} else {
|
|
MOZ_ASSERT(mir->fallible());
|
|
bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot());
|
|
}
|
|
}
|
|
|
|
if (mir->canBeNegativeDividend()) {
|
|
Label notNegative;
|
|
masm.ma_b(rhs, Imm32(0), ¬Negative, Assembler::GreaterThan, ShortJump);
|
|
if (mir->isTruncated()) {
|
|
// NaN|0 == 0 and (0 % -X)|0 == 0
|
|
Label skip;
|
|
masm.ma_b(lhs, Imm32(0), &skip, Assembler::NotEqual, ShortJump);
|
|
masm.move32(Imm32(0), dest);
|
|
masm.ma_b(&done, ShortJump);
|
|
masm.bind(&skip);
|
|
} else {
|
|
MOZ_ASSERT(mir->fallible());
|
|
bailoutCmp32(Assembler::Equal, lhs, Imm32(0), ins->snapshot());
|
|
}
|
|
masm.bind(¬Negative);
|
|
}
|
|
|
|
masm.as_div(lhs, rhs);
|
|
masm.as_mfhi(dest);
|
|
|
|
// If X%Y == 0 and X < 0, then we *actually* wanted to return -0.0
|
|
if (mir->canBeNegativeDividend()) {
|
|
if (mir->isTruncated()) {
|
|
// -0.0|0 == 0
|
|
} else {
|
|
MOZ_ASSERT(mir->fallible());
|
|
// See if X < 0
|
|
masm.ma_b(dest, Imm32(0), &done, Assembler::NotEqual, ShortJump);
|
|
bailoutCmp32(Assembler::Signed, callTemp, Imm32(0), ins->snapshot());
|
|
}
|
|
}
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitModPowTwoI(LModPowTwoI* ins)
|
|
{
|
|
Register in = ToRegister(ins->getOperand(0));
|
|
Register out = ToRegister(ins->getDef(0));
|
|
MMod* mir = ins->mir();
|
|
Label negative, done;
|
|
|
|
masm.move32(in, out);
|
|
masm.ma_b(in, in, &done, Assembler::Zero, ShortJump);
|
|
// Switch based on sign of the lhs.
|
|
// Positive numbers are just a bitmask
|
|
masm.ma_b(in, in, &negative, Assembler::Signed, ShortJump);
|
|
{
|
|
masm.and32(Imm32((1 << ins->shift()) - 1), out);
|
|
masm.ma_b(&done, ShortJump);
|
|
}
|
|
|
|
// Negative numbers need a negate, bitmask, negate
|
|
{
|
|
masm.bind(&negative);
|
|
masm.neg32(out);
|
|
masm.and32(Imm32((1 << ins->shift()) - 1), out);
|
|
masm.neg32(out);
|
|
}
|
|
if (mir->canBeNegativeDividend()) {
|
|
if (!mir->isTruncated()) {
|
|
MOZ_ASSERT(mir->fallible());
|
|
bailoutCmp32(Assembler::Equal, out, zero, ins->snapshot());
|
|
} else {
|
|
// -0|0 == 0
|
|
}
|
|
}
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitModMaskI(LModMaskI* ins)
|
|
{
|
|
Register src = ToRegister(ins->getOperand(0));
|
|
Register dest = ToRegister(ins->getDef(0));
|
|
Register tmp0 = ToRegister(ins->getTemp(0));
|
|
Register tmp1 = ToRegister(ins->getTemp(1));
|
|
MMod* mir = ins->mir();
|
|
|
|
if (!mir->isTruncated() && mir->canBeNegativeDividend()) {
|
|
MOZ_ASSERT(mir->fallible());
|
|
|
|
Label bail;
|
|
masm.ma_mod_mask(src, dest, tmp0, tmp1, ins->shift(), &bail);
|
|
bailoutFrom(&bail, ins->snapshot());
|
|
} else {
|
|
masm.ma_mod_mask(src, dest, tmp0, tmp1, ins->shift(), nullptr);
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitBitNotI(LBitNotI* ins)
|
|
{
|
|
const LAllocation* input = ins->getOperand(0);
|
|
const LDefinition* dest = ins->getDef(0);
|
|
MOZ_ASSERT(!input->isConstant());
|
|
|
|
masm.ma_not(ToRegister(dest), ToRegister(input));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitBitOpI(LBitOpI* ins)
|
|
{
|
|
const LAllocation* lhs = ins->getOperand(0);
|
|
const LAllocation* rhs = ins->getOperand(1);
|
|
const LDefinition* dest = ins->getDef(0);
|
|
// all of these bitops should be either imm32's, or integer registers.
|
|
switch (ins->bitop()) {
|
|
case JSOP_BITOR:
|
|
if (rhs->isConstant())
|
|
masm.ma_or(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
|
|
else
|
|
masm.as_or(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
|
break;
|
|
case JSOP_BITXOR:
|
|
if (rhs->isConstant())
|
|
masm.ma_xor(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
|
|
else
|
|
masm.as_xor(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
|
break;
|
|
case JSOP_BITAND:
|
|
if (rhs->isConstant())
|
|
masm.ma_and(ToRegister(dest), ToRegister(lhs), Imm32(ToInt32(rhs)));
|
|
else
|
|
masm.as_and(ToRegister(dest), ToRegister(lhs), ToRegister(rhs));
|
|
break;
|
|
default:
|
|
MOZ_CRASH("unexpected binary opcode");
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitShiftI(LShiftI* ins)
|
|
{
|
|
Register lhs = ToRegister(ins->lhs());
|
|
const LAllocation* rhs = ins->rhs();
|
|
Register dest = ToRegister(ins->output());
|
|
|
|
if (rhs->isConstant()) {
|
|
int32_t shift = ToInt32(rhs) & 0x1F;
|
|
switch (ins->bitop()) {
|
|
case JSOP_LSH:
|
|
if (shift)
|
|
masm.ma_sll(dest, lhs, Imm32(shift));
|
|
else
|
|
masm.move32(lhs, dest);
|
|
break;
|
|
case JSOP_RSH:
|
|
if (shift)
|
|
masm.ma_sra(dest, lhs, Imm32(shift));
|
|
else
|
|
masm.move32(lhs, dest);
|
|
break;
|
|
case JSOP_URSH:
|
|
if (shift) {
|
|
masm.ma_srl(dest, lhs, Imm32(shift));
|
|
} else {
|
|
// x >>> 0 can overflow.
|
|
masm.move32(lhs, dest);
|
|
if (ins->mir()->toUrsh()->fallible())
|
|
bailoutCmp32(Assembler::LessThan, dest, Imm32(0), ins->snapshot());
|
|
}
|
|
break;
|
|
default:
|
|
MOZ_CRASH("Unexpected shift op");
|
|
}
|
|
} else {
|
|
// The shift amounts should be AND'ed into the 0-31 range
|
|
masm.ma_and(dest, ToRegister(rhs), Imm32(0x1F));
|
|
|
|
switch (ins->bitop()) {
|
|
case JSOP_LSH:
|
|
masm.ma_sll(dest, lhs, dest);
|
|
break;
|
|
case JSOP_RSH:
|
|
masm.ma_sra(dest, lhs, dest);
|
|
break;
|
|
case JSOP_URSH:
|
|
masm.ma_srl(dest, lhs, dest);
|
|
if (ins->mir()->toUrsh()->fallible()) {
|
|
// x >>> 0 can overflow.
|
|
bailoutCmp32(Assembler::LessThan, dest, Imm32(0), ins->snapshot());
|
|
}
|
|
break;
|
|
default:
|
|
MOZ_CRASH("Unexpected shift op");
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitUrshD(LUrshD* ins)
|
|
{
|
|
Register lhs = ToRegister(ins->lhs());
|
|
Register temp = ToRegister(ins->temp());
|
|
|
|
const LAllocation* rhs = ins->rhs();
|
|
FloatRegister out = ToFloatRegister(ins->output());
|
|
|
|
if (rhs->isConstant()) {
|
|
masm.ma_srl(temp, lhs, Imm32(ToInt32(rhs)));
|
|
} else {
|
|
masm.ma_srl(temp, lhs, ToRegister(rhs));
|
|
}
|
|
|
|
masm.convertUInt32ToDouble(temp, out);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitClzI(LClzI* ins)
|
|
{
|
|
Register input = ToRegister(ins->input());
|
|
Register output = ToRegister(ins->output());
|
|
|
|
masm.as_clz(output, input);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitPowHalfD(LPowHalfD* ins)
|
|
{
|
|
FloatRegister input = ToFloatRegister(ins->input());
|
|
FloatRegister output = ToFloatRegister(ins->output());
|
|
|
|
Label done, skip;
|
|
|
|
// Masm.pow(-Infinity, 0.5) == Infinity.
|
|
masm.loadConstantDouble(NegativeInfinity<double>(), ScratchDoubleReg);
|
|
masm.ma_bc1d(input, ScratchDoubleReg, &skip, Assembler::DoubleNotEqualOrUnordered, ShortJump);
|
|
masm.as_negd(output, ScratchDoubleReg);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&skip);
|
|
// Math.pow(-0, 0.5) == 0 == Math.pow(0, 0.5).
|
|
// Adding 0 converts any -0 to 0.
|
|
masm.loadConstantDouble(0.0, ScratchDoubleReg);
|
|
masm.as_addd(output, input, ScratchDoubleReg);
|
|
masm.as_sqrtd(output, output);
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
MoveOperand
|
|
CodeGeneratorMIPSShared::toMoveOperand(LAllocation a) const
|
|
{
|
|
if (a.isGeneralReg())
|
|
return MoveOperand(ToRegister(a));
|
|
if (a.isFloatReg()) {
|
|
return MoveOperand(ToFloatRegister(a));
|
|
}
|
|
int32_t offset = ToStackOffset(a);
|
|
MOZ_ASSERT((offset & 3) == 0);
|
|
|
|
return MoveOperand(StackPointer, offset);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitMathD(LMathD* math)
|
|
{
|
|
const LAllocation* src1 = math->getOperand(0);
|
|
const LAllocation* src2 = math->getOperand(1);
|
|
const LDefinition* output = math->getDef(0);
|
|
|
|
switch (math->jsop()) {
|
|
case JSOP_ADD:
|
|
masm.as_addd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
|
|
break;
|
|
case JSOP_SUB:
|
|
masm.as_subd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
|
|
break;
|
|
case JSOP_MUL:
|
|
masm.as_muld(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
|
|
break;
|
|
case JSOP_DIV:
|
|
masm.as_divd(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
|
|
break;
|
|
default:
|
|
MOZ_CRASH("unexpected opcode");
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitMathF(LMathF* math)
|
|
{
|
|
const LAllocation* src1 = math->getOperand(0);
|
|
const LAllocation* src2 = math->getOperand(1);
|
|
const LDefinition* output = math->getDef(0);
|
|
|
|
switch (math->jsop()) {
|
|
case JSOP_ADD:
|
|
masm.as_adds(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
|
|
break;
|
|
case JSOP_SUB:
|
|
masm.as_subs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
|
|
break;
|
|
case JSOP_MUL:
|
|
masm.as_muls(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
|
|
break;
|
|
case JSOP_DIV:
|
|
masm.as_divs(ToFloatRegister(output), ToFloatRegister(src1), ToFloatRegister(src2));
|
|
break;
|
|
default:
|
|
MOZ_CRASH("unexpected opcode");
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitFloor(LFloor* lir)
|
|
{
|
|
FloatRegister input = ToFloatRegister(lir->input());
|
|
FloatRegister scratch = ScratchDoubleReg;
|
|
Register output = ToRegister(lir->output());
|
|
|
|
Label skipCheck, done;
|
|
|
|
// If Nan, 0 or -0 check for bailout
|
|
masm.loadConstantDouble(0.0, scratch);
|
|
masm.ma_bc1d(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
|
|
|
|
// If high part is not zero, it is NaN or -0, so we bail.
|
|
masm.moveFromDoubleHi(input, SecondScratchReg);
|
|
bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot());
|
|
|
|
// Input was zero, so return zero.
|
|
masm.move32(Imm32(0), output);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&skipCheck);
|
|
masm.as_floorwd(scratch, input);
|
|
masm.moveFromDoubleLo(scratch, output);
|
|
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot());
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot());
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitFloorF(LFloorF* lir)
|
|
{
|
|
FloatRegister input = ToFloatRegister(lir->input());
|
|
FloatRegister scratch = ScratchFloat32Reg;
|
|
Register output = ToRegister(lir->output());
|
|
|
|
Label skipCheck, done;
|
|
|
|
// If Nan, 0 or -0 check for bailout
|
|
masm.loadConstantFloat32(0.0f, scratch);
|
|
masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
|
|
|
|
// If binary value is not zero, it is NaN or -0, so we bail.
|
|
masm.moveFromDoubleLo(input, SecondScratchReg);
|
|
bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot());
|
|
|
|
// Input was zero, so return zero.
|
|
masm.move32(Imm32(0), output);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&skipCheck);
|
|
masm.as_floorws(scratch, input);
|
|
masm.moveFromDoubleLo(scratch, output);
|
|
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot());
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot());
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitCeil(LCeil* lir)
|
|
{
|
|
FloatRegister input = ToFloatRegister(lir->input());
|
|
FloatRegister scratch = ScratchDoubleReg;
|
|
Register output = ToRegister(lir->output());
|
|
|
|
Label performCeil, done;
|
|
|
|
// If x < -1 or x > 0 then perform ceil.
|
|
masm.loadConstantDouble(0, scratch);
|
|
masm.branchDouble(Assembler::DoubleGreaterThan, input, scratch, &performCeil);
|
|
masm.loadConstantDouble(-1, scratch);
|
|
masm.branchDouble(Assembler::DoubleLessThanOrEqual, input, scratch, &performCeil);
|
|
|
|
// If high part is not zero, the input was not 0, so we bail.
|
|
masm.moveFromDoubleHi(input, SecondScratchReg);
|
|
bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot());
|
|
|
|
// Input was zero, so return zero.
|
|
masm.move32(Imm32(0), output);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&performCeil);
|
|
masm.as_ceilwd(scratch, input);
|
|
masm.moveFromDoubleLo(scratch, output);
|
|
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot());
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot());
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitCeilF(LCeilF* lir)
|
|
{
|
|
FloatRegister input = ToFloatRegister(lir->input());
|
|
FloatRegister scratch = ScratchFloat32Reg;
|
|
Register output = ToRegister(lir->output());
|
|
|
|
Label performCeil, done;
|
|
|
|
// If x < -1 or x > 0 then perform ceil.
|
|
masm.loadConstantFloat32(0, scratch);
|
|
masm.branchFloat(Assembler::DoubleGreaterThan, input, scratch, &performCeil);
|
|
masm.loadConstantFloat32(-1, scratch);
|
|
masm.branchFloat(Assembler::DoubleLessThanOrEqual, input, scratch, &performCeil);
|
|
|
|
// If binary value is not zero, the input was not 0, so we bail.
|
|
masm.moveFromFloat32(input, SecondScratchReg);
|
|
bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot());
|
|
|
|
// Input was zero, so return zero.
|
|
masm.move32(Imm32(0), output);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&performCeil);
|
|
masm.as_ceilws(scratch, input);
|
|
masm.moveFromFloat32(scratch, output);
|
|
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot());
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot());
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitRound(LRound* lir)
|
|
{
|
|
FloatRegister input = ToFloatRegister(lir->input());
|
|
FloatRegister temp = ToFloatRegister(lir->temp());
|
|
FloatRegister scratch = ScratchDoubleReg;
|
|
Register output = ToRegister(lir->output());
|
|
|
|
Label bail, negative, end, skipCheck;
|
|
|
|
// Load biggest number less than 0.5 in the temp register.
|
|
masm.loadConstantDouble(GetBiggestNumberLessThan(0.5), temp);
|
|
|
|
// Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
|
|
masm.loadConstantDouble(0.0, scratch);
|
|
masm.ma_bc1d(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump);
|
|
|
|
// If Nan, 0 or -0 check for bailout
|
|
masm.ma_bc1d(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
|
|
|
|
// If high part is not zero, it is NaN or -0, so we bail.
|
|
masm.moveFromDoubleHi(input, SecondScratchReg);
|
|
bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot());
|
|
|
|
// Input was zero, so return zero.
|
|
masm.move32(Imm32(0), output);
|
|
masm.ma_b(&end, ShortJump);
|
|
|
|
masm.bind(&skipCheck);
|
|
masm.as_addd(scratch, input, temp);
|
|
masm.as_floorwd(scratch, scratch);
|
|
|
|
masm.moveFromDoubleLo(scratch, output);
|
|
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot());
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot());
|
|
|
|
masm.jump(&end);
|
|
|
|
// Input is negative, but isn't -0.
|
|
masm.bind(&negative);
|
|
|
|
// Inputs in ]-0.5; 0] need to be added 0.5, other negative inputs need to
|
|
// be added the biggest double less than 0.5.
|
|
Label loadJoin;
|
|
masm.loadConstantDouble(-0.5, scratch);
|
|
masm.branchDouble(Assembler::DoubleLessThan, input, scratch, &loadJoin);
|
|
masm.loadConstantDouble(0.5, temp);
|
|
masm.bind(&loadJoin);
|
|
|
|
masm.addDouble(input, temp);
|
|
|
|
// If input + 0.5 >= 0, input is a negative number >= -0.5 and the
|
|
// result is -0.
|
|
masm.branchDouble(Assembler::DoubleGreaterThanOrEqual, temp, scratch, &bail);
|
|
bailoutFrom(&bail, lir->snapshot());
|
|
|
|
// Truncate and round toward zero.
|
|
// This is off-by-one for everything but integer-valued inputs.
|
|
masm.as_floorwd(scratch, temp);
|
|
masm.moveFromDoubleLo(scratch, output);
|
|
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot());
|
|
|
|
masm.bind(&end);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitRoundF(LRoundF* lir)
|
|
{
|
|
FloatRegister input = ToFloatRegister(lir->input());
|
|
FloatRegister temp = ToFloatRegister(lir->temp());
|
|
FloatRegister scratch = ScratchFloat32Reg;
|
|
Register output = ToRegister(lir->output());
|
|
|
|
Label bail, negative, end, skipCheck;
|
|
|
|
// Load biggest number less than 0.5 in the temp register.
|
|
masm.loadConstantFloat32(GetBiggestNumberLessThan(0.5f), temp);
|
|
|
|
// Branch to a slow path for negative inputs. Doesn't catch NaN or -0.
|
|
masm.loadConstantFloat32(0.0f, scratch);
|
|
masm.ma_bc1s(input, scratch, &negative, Assembler::DoubleLessThan, ShortJump);
|
|
|
|
// If Nan, 0 or -0 check for bailout
|
|
masm.ma_bc1s(input, scratch, &skipCheck, Assembler::DoubleNotEqual, ShortJump);
|
|
|
|
// If binary value is not zero, it is NaN or -0, so we bail.
|
|
masm.moveFromFloat32(input, SecondScratchReg);
|
|
bailoutCmp32(Assembler::NotEqual, SecondScratchReg, Imm32(0), lir->snapshot());
|
|
|
|
// Input was zero, so return zero.
|
|
masm.move32(Imm32(0), output);
|
|
masm.ma_b(&end, ShortJump);
|
|
|
|
masm.bind(&skipCheck);
|
|
masm.as_adds(scratch, input, temp);
|
|
masm.as_floorws(scratch, scratch);
|
|
|
|
masm.moveFromFloat32(scratch, output);
|
|
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot());
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MAX), lir->snapshot());
|
|
|
|
masm.jump(&end);
|
|
|
|
// Input is negative, but isn't -0.
|
|
masm.bind(&negative);
|
|
|
|
// Inputs in ]-0.5; 0] need to be added 0.5, other negative inputs need to
|
|
// be added the biggest double less than 0.5.
|
|
Label loadJoin;
|
|
masm.loadConstantFloat32(-0.5f, scratch);
|
|
masm.branchFloat(Assembler::DoubleLessThan, input, scratch, &loadJoin);
|
|
masm.loadConstantFloat32(0.5f, temp);
|
|
masm.bind(&loadJoin);
|
|
|
|
masm.as_adds(temp, input, temp);
|
|
|
|
// If input + 0.5 >= 0, input is a negative number >= -0.5 and the
|
|
// result is -0.
|
|
masm.branchFloat(Assembler::DoubleGreaterThanOrEqual, temp, scratch, &bail);
|
|
bailoutFrom(&bail, lir->snapshot());
|
|
|
|
// Truncate and round toward zero.
|
|
// This is off-by-one for everything but integer-valued inputs.
|
|
masm.as_floorws(scratch, temp);
|
|
masm.moveFromFloat32(scratch, output);
|
|
|
|
bailoutCmp32(Assembler::Equal, output, Imm32(INT_MIN), lir->snapshot());
|
|
|
|
masm.bind(&end);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitTruncateDToInt32(LTruncateDToInt32* ins)
|
|
{
|
|
emitTruncateDouble(ToFloatRegister(ins->input()), ToRegister(ins->output()),
|
|
ins->mir());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitTruncateFToInt32(LTruncateFToInt32* ins)
|
|
{
|
|
emitTruncateFloat32(ToFloatRegister(ins->input()), ToRegister(ins->output()),
|
|
ins->mir());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitValue(LValue* value)
|
|
{
|
|
const ValueOperand out = ToOutValue(value);
|
|
|
|
masm.moveValue(value->value(), out);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitDouble(LDouble* ins)
|
|
{
|
|
const LDefinition* out = ins->getDef(0);
|
|
|
|
masm.loadConstantDouble(ins->getDouble(), ToFloatRegister(out));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitFloat32(LFloat32* ins)
|
|
{
|
|
const LDefinition* out = ins->getDef(0);
|
|
masm.loadConstantFloat32(ins->getFloat(), ToFloatRegister(out));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitTestDAndBranch(LTestDAndBranch* test)
|
|
{
|
|
FloatRegister input = ToFloatRegister(test->input());
|
|
|
|
MBasicBlock* ifTrue = test->ifTrue();
|
|
MBasicBlock* ifFalse = test->ifFalse();
|
|
|
|
masm.loadConstantDouble(0.0, ScratchDoubleReg);
|
|
// If 0, or NaN, the result is false.
|
|
|
|
if (isNextBlock(ifFalse->lir())) {
|
|
branchToBlock(Assembler::DoubleFloat, input, ScratchDoubleReg, ifTrue,
|
|
Assembler::DoubleNotEqual);
|
|
} else {
|
|
branchToBlock(Assembler::DoubleFloat, input, ScratchDoubleReg, ifFalse,
|
|
Assembler::DoubleEqualOrUnordered);
|
|
jumpToBlock(ifTrue);
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitTestFAndBranch(LTestFAndBranch* test)
|
|
{
|
|
FloatRegister input = ToFloatRegister(test->input());
|
|
|
|
MBasicBlock* ifTrue = test->ifTrue();
|
|
MBasicBlock* ifFalse = test->ifFalse();
|
|
|
|
masm.loadConstantFloat32(0.0f, ScratchFloat32Reg);
|
|
// If 0, or NaN, the result is false.
|
|
|
|
if (isNextBlock(ifFalse->lir())) {
|
|
branchToBlock(Assembler::SingleFloat, input, ScratchFloat32Reg, ifTrue,
|
|
Assembler::DoubleNotEqual);
|
|
} else {
|
|
branchToBlock(Assembler::SingleFloat, input, ScratchFloat32Reg, ifFalse,
|
|
Assembler::DoubleEqualOrUnordered);
|
|
jumpToBlock(ifTrue);
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitCompareD(LCompareD* comp)
|
|
{
|
|
FloatRegister lhs = ToFloatRegister(comp->left());
|
|
FloatRegister rhs = ToFloatRegister(comp->right());
|
|
Register dest = ToRegister(comp->output());
|
|
|
|
Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
|
|
masm.ma_cmp_set_double(dest, lhs, rhs, cond);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitCompareF(LCompareF* comp)
|
|
{
|
|
FloatRegister lhs = ToFloatRegister(comp->left());
|
|
FloatRegister rhs = ToFloatRegister(comp->right());
|
|
Register dest = ToRegister(comp->output());
|
|
|
|
Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->mir()->jsop());
|
|
masm.ma_cmp_set_float32(dest, lhs, rhs, cond);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitCompareDAndBranch(LCompareDAndBranch* comp)
|
|
{
|
|
FloatRegister lhs = ToFloatRegister(comp->left());
|
|
FloatRegister rhs = ToFloatRegister(comp->right());
|
|
|
|
Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop());
|
|
MBasicBlock* ifTrue = comp->ifTrue();
|
|
MBasicBlock* ifFalse = comp->ifFalse();
|
|
|
|
if (isNextBlock(ifFalse->lir())) {
|
|
branchToBlock(Assembler::DoubleFloat, lhs, rhs, ifTrue, cond);
|
|
} else {
|
|
branchToBlock(Assembler::DoubleFloat, lhs, rhs, ifFalse,
|
|
Assembler::InvertCondition(cond));
|
|
jumpToBlock(ifTrue);
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitCompareFAndBranch(LCompareFAndBranch* comp)
|
|
{
|
|
FloatRegister lhs = ToFloatRegister(comp->left());
|
|
FloatRegister rhs = ToFloatRegister(comp->right());
|
|
|
|
Assembler::DoubleCondition cond = JSOpToDoubleCondition(comp->cmpMir()->jsop());
|
|
MBasicBlock* ifTrue = comp->ifTrue();
|
|
MBasicBlock* ifFalse = comp->ifFalse();
|
|
|
|
if (isNextBlock(ifFalse->lir())) {
|
|
branchToBlock(Assembler::SingleFloat, lhs, rhs, ifTrue, cond);
|
|
} else {
|
|
branchToBlock(Assembler::SingleFloat, lhs, rhs, ifFalse,
|
|
Assembler::InvertCondition(cond));
|
|
jumpToBlock(ifTrue);
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitBitAndAndBranch(LBitAndAndBranch* lir)
|
|
{
|
|
if (lir->right()->isConstant())
|
|
masm.ma_and(ScratchRegister, ToRegister(lir->left()), Imm32(ToInt32(lir->right())));
|
|
else
|
|
masm.as_and(ScratchRegister, ToRegister(lir->left()), ToRegister(lir->right()));
|
|
emitBranch(ScratchRegister, ScratchRegister, Assembler::NonZero, lir->ifTrue(),
|
|
lir->ifFalse());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir)
|
|
{
|
|
masm.convertUInt32ToDouble(ToRegister(lir->input()), ToFloatRegister(lir->output()));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir)
|
|
{
|
|
masm.convertUInt32ToFloat32(ToRegister(lir->input()), ToFloatRegister(lir->output()));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitNotI(LNotI* ins)
|
|
{
|
|
masm.cmp32Set(Assembler::Equal, ToRegister(ins->input()), Imm32(0),
|
|
ToRegister(ins->output()));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitNotD(LNotD* ins)
|
|
{
|
|
// Since this operation is not, we want to set a bit if
|
|
// the double is falsey, which means 0.0, -0.0 or NaN.
|
|
FloatRegister in = ToFloatRegister(ins->input());
|
|
Register dest = ToRegister(ins->output());
|
|
|
|
Label falsey, done;
|
|
masm.loadConstantDouble(0.0, ScratchDoubleReg);
|
|
masm.ma_bc1d(in, ScratchDoubleReg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump);
|
|
|
|
masm.move32(Imm32(0), dest);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&falsey);
|
|
masm.move32(Imm32(1), dest);
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitNotF(LNotF* ins)
|
|
{
|
|
// Since this operation is not, we want to set a bit if
|
|
// the float32 is falsey, which means 0.0, -0.0 or NaN.
|
|
FloatRegister in = ToFloatRegister(ins->input());
|
|
Register dest = ToRegister(ins->output());
|
|
|
|
Label falsey, done;
|
|
masm.loadConstantFloat32(0.0f, ScratchFloat32Reg);
|
|
masm.ma_bc1s(in, ScratchFloat32Reg, &falsey, Assembler::DoubleEqualOrUnordered, ShortJump);
|
|
|
|
masm.move32(Imm32(0), dest);
|
|
masm.ma_b(&done, ShortJump);
|
|
|
|
masm.bind(&falsey);
|
|
masm.move32(Imm32(1), dest);
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitGuardShape(LGuardShape* guard)
|
|
{
|
|
Register obj = ToRegister(guard->input());
|
|
Register tmp = ToRegister(guard->tempInt());
|
|
|
|
masm.loadPtr(Address(obj, JSObject::offsetOfShape()), tmp);
|
|
bailoutCmpPtr(Assembler::NotEqual, tmp, ImmGCPtr(guard->mir()->shape()),
|
|
guard->snapshot());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitGuardObjectGroup(LGuardObjectGroup* guard)
|
|
{
|
|
Register obj = ToRegister(guard->input());
|
|
Register tmp = ToRegister(guard->tempInt());
|
|
MOZ_ASSERT(obj != tmp);
|
|
|
|
masm.loadPtr(Address(obj, JSObject::offsetOfGroup()), tmp);
|
|
Assembler::Condition cond = guard->mir()->bailOnEquality()
|
|
? Assembler::Equal
|
|
: Assembler::NotEqual;
|
|
bailoutCmpPtr(cond, tmp, ImmGCPtr(guard->mir()->group()), guard->snapshot());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitGuardClass(LGuardClass* guard)
|
|
{
|
|
Register obj = ToRegister(guard->input());
|
|
Register tmp = ToRegister(guard->tempInt());
|
|
|
|
masm.loadObjClass(obj, tmp);
|
|
bailoutCmpPtr(Assembler::NotEqual, tmp, ImmPtr(guard->mir()->getClass()),
|
|
guard->snapshot());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitMemoryBarrier(LMemoryBarrier* ins)
|
|
{
|
|
memoryBarrier(ins->type());
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::memoryBarrier(MemoryBarrierBits barrier)
|
|
{
|
|
if (barrier)
|
|
masm.as_sync();
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::generateInvalidateEpilogue()
|
|
{
|
|
// Ensure that there is enough space in the buffer for the OsiPoint
|
|
// patching to occur. Otherwise, we could overwrite the invalidation
|
|
// epilogue.
|
|
for (size_t i = 0; i < sizeof(void*); i += Assembler::NopSize())
|
|
masm.nop();
|
|
|
|
masm.bind(&invalidate_);
|
|
|
|
// Push the return address of the point that we bailed out at to the stack
|
|
masm.Push(ra);
|
|
|
|
// Push the Ion script onto the stack (when we determine what that
|
|
// pointer is).
|
|
invalidateEpilogueData_ = masm.pushWithPatch(ImmWord(uintptr_t(-1)));
|
|
JitCode* thunk = gen->jitRuntime()->getInvalidationThunk();
|
|
|
|
masm.branch(thunk);
|
|
|
|
// We should never reach this point in JIT code -- the invalidation thunk
|
|
// should pop the invalidated JS frame and return directly to its caller.
|
|
masm.assumeUnreachable("Should have returned directly to its caller instead of here.");
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitLoadTypedArrayElementStatic(LLoadTypedArrayElementStatic* ins)
|
|
{
|
|
MOZ_CRASH("NYI");
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitStoreTypedArrayElementStatic(LStoreTypedArrayElementStatic* ins)
|
|
{
|
|
MOZ_CRASH("NYI");
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSCall(LAsmJSCall* ins)
|
|
{
|
|
emitAsmJSCall(ins);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSLoadHeap(LAsmJSLoadHeap* ins)
|
|
{
|
|
const MAsmJSLoadHeap* mir = ins->mir();
|
|
const LAllocation* ptr = ins->ptr();
|
|
const LDefinition* out = ins->output();
|
|
|
|
bool isSigned;
|
|
int size;
|
|
bool isFloat = false;
|
|
switch (mir->accessType()) {
|
|
case Scalar::Int8: isSigned = true; size = 8; break;
|
|
case Scalar::Uint8: isSigned = false; size = 8; break;
|
|
case Scalar::Int16: isSigned = true; size = 16; break;
|
|
case Scalar::Uint16: isSigned = false; size = 16; break;
|
|
case Scalar::Int32: isSigned = true; size = 32; break;
|
|
case Scalar::Uint32: isSigned = false; size = 32; break;
|
|
case Scalar::Float64: isFloat = true; size = 64; break;
|
|
case Scalar::Float32: isFloat = true; size = 32; break;
|
|
default: MOZ_CRASH("unexpected array type");
|
|
}
|
|
|
|
memoryBarrier(mir->barrierBefore());
|
|
if (ptr->isConstant()) {
|
|
MOZ_ASSERT(!mir->needsBoundsCheck());
|
|
int32_t ptrImm = ptr->toConstant()->toInt32();
|
|
MOZ_ASSERT(ptrImm >= 0);
|
|
if (isFloat) {
|
|
if (size == 32) {
|
|
masm.loadFloat32(Address(HeapReg, ptrImm), ToFloatRegister(out));
|
|
} else {
|
|
masm.loadDouble(Address(HeapReg, ptrImm), ToFloatRegister(out));
|
|
}
|
|
} else {
|
|
masm.ma_load(ToRegister(out), Address(HeapReg, ptrImm),
|
|
static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
|
|
}
|
|
memoryBarrier(mir->barrierAfter());
|
|
return;
|
|
}
|
|
|
|
Register ptrReg = ToRegister(ptr);
|
|
|
|
if (!mir->needsBoundsCheck()) {
|
|
if (isFloat) {
|
|
if (size == 32) {
|
|
masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
|
|
} else {
|
|
masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
|
|
}
|
|
} else {
|
|
masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne),
|
|
static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
|
|
}
|
|
memoryBarrier(mir->barrierAfter());
|
|
return;
|
|
}
|
|
|
|
BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister);
|
|
|
|
Label done, outOfRange;
|
|
masm.ma_b(ptrReg, ScratchRegister, &outOfRange, Assembler::AboveOrEqual, ShortJump);
|
|
// Offset is ok, let's load value.
|
|
if (isFloat) {
|
|
if (size == 32)
|
|
masm.loadFloat32(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
|
|
else
|
|
masm.loadDouble(BaseIndex(HeapReg, ptrReg, TimesOne), ToFloatRegister(out));
|
|
} else {
|
|
masm.ma_load(ToRegister(out), BaseIndex(HeapReg, ptrReg, TimesOne),
|
|
static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
|
|
}
|
|
masm.ma_b(&done, ShortJump);
|
|
masm.bind(&outOfRange);
|
|
// Offset is out of range. Load default values.
|
|
if (isFloat) {
|
|
if (size == 32)
|
|
masm.loadFloat32(Address(GlobalReg, AsmJSNaN32GlobalDataOffset - AsmJSGlobalRegBias),
|
|
ToFloatRegister(out));
|
|
else
|
|
masm.loadDouble(Address(GlobalReg, AsmJSNaN64GlobalDataOffset - AsmJSGlobalRegBias),
|
|
ToFloatRegister(out));
|
|
} else {
|
|
if (mir->isAtomicAccess())
|
|
masm.ma_b(gen->outOfBoundsLabel());
|
|
else
|
|
masm.move32(Imm32(0), ToRegister(out));
|
|
}
|
|
masm.bind(&done);
|
|
|
|
memoryBarrier(mir->barrierAfter());
|
|
masm.append(AsmJSHeapAccess(bo.getOffset()));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSStoreHeap(LAsmJSStoreHeap* ins)
|
|
{
|
|
const MAsmJSStoreHeap* mir = ins->mir();
|
|
const LAllocation* value = ins->value();
|
|
const LAllocation* ptr = ins->ptr();
|
|
|
|
bool isSigned;
|
|
int size;
|
|
bool isFloat = false;
|
|
switch (mir->accessType()) {
|
|
case Scalar::Int8: isSigned = true; size = 8; break;
|
|
case Scalar::Uint8: isSigned = false; size = 8; break;
|
|
case Scalar::Int16: isSigned = true; size = 16; break;
|
|
case Scalar::Uint16: isSigned = false; size = 16; break;
|
|
case Scalar::Int32: isSigned = true; size = 32; break;
|
|
case Scalar::Uint32: isSigned = false; size = 32; break;
|
|
case Scalar::Float64: isFloat = true; size = 64; break;
|
|
case Scalar::Float32: isFloat = true; size = 32; break;
|
|
default: MOZ_CRASH("unexpected array type");
|
|
}
|
|
|
|
memoryBarrier(mir->barrierBefore());
|
|
if (ptr->isConstant()) {
|
|
MOZ_ASSERT(!mir->needsBoundsCheck());
|
|
int32_t ptrImm = ptr->toConstant()->toInt32();
|
|
MOZ_ASSERT(ptrImm >= 0);
|
|
|
|
if (isFloat) {
|
|
if (size == 32) {
|
|
masm.storeFloat32(ToFloatRegister(value), Address(HeapReg, ptrImm));
|
|
} else {
|
|
masm.storeDouble(ToFloatRegister(value), Address(HeapReg, ptrImm));
|
|
}
|
|
} else {
|
|
masm.ma_store(ToRegister(value), Address(HeapReg, ptrImm),
|
|
static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
|
|
}
|
|
memoryBarrier(mir->barrierAfter());
|
|
return;
|
|
}
|
|
|
|
Register ptrReg = ToRegister(ptr);
|
|
Address dstAddr(ptrReg, 0);
|
|
|
|
if (!mir->needsBoundsCheck()) {
|
|
if (isFloat) {
|
|
if (size == 32) {
|
|
masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
|
|
} else
|
|
masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
|
|
} else {
|
|
masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne),
|
|
static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
|
|
}
|
|
memoryBarrier(mir->barrierAfter());
|
|
return;
|
|
}
|
|
|
|
BufferOffset bo = masm.ma_BoundsCheck(ScratchRegister);
|
|
|
|
Label done, outOfRange;
|
|
masm.ma_b(ptrReg, ScratchRegister, &outOfRange, Assembler::AboveOrEqual, ShortJump);
|
|
|
|
// Offset is ok, let's store value.
|
|
if (isFloat) {
|
|
if (size == 32) {
|
|
masm.storeFloat32(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
|
|
} else
|
|
masm.storeDouble(ToFloatRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne));
|
|
} else {
|
|
masm.ma_store(ToRegister(value), BaseIndex(HeapReg, ptrReg, TimesOne),
|
|
static_cast<LoadStoreSize>(size), isSigned ? SignExtend : ZeroExtend);
|
|
}
|
|
masm.ma_b(&done, ShortJump);
|
|
masm.bind(&outOfRange);
|
|
// Offset is out of range.
|
|
if (mir->isAtomicAccess())
|
|
masm.ma_b(gen->outOfBoundsLabel());
|
|
masm.bind(&done);
|
|
|
|
memoryBarrier(mir->barrierAfter());
|
|
masm.append(AsmJSHeapAccess(bo.getOffset()));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins)
|
|
{
|
|
MOZ_CRASH("NYI");
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins)
|
|
{
|
|
MOZ_CRASH("NYI");
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSPassStackArg(LAsmJSPassStackArg* ins)
|
|
{
|
|
const MAsmJSPassStackArg* mir = ins->mir();
|
|
if (ins->arg()->isConstant()) {
|
|
masm.storePtr(ImmWord(ToInt32(ins->arg())), Address(StackPointer, mir->spOffset()));
|
|
} else {
|
|
if (ins->arg()->isGeneralReg()) {
|
|
masm.storePtr(ToRegister(ins->arg()), Address(StackPointer, mir->spOffset()));
|
|
} else {
|
|
masm.storeDouble(ToFloatRegister(ins->arg()).doubleOverlay(),
|
|
Address(StackPointer, mir->spOffset()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitUDivOrMod(LUDivOrMod* ins)
|
|
{
|
|
Register lhs = ToRegister(ins->lhs());
|
|
Register rhs = ToRegister(ins->rhs());
|
|
Register output = ToRegister(ins->output());
|
|
Label done;
|
|
|
|
// Prevent divide by zero.
|
|
if (ins->canBeDivideByZero()) {
|
|
if (ins->mir()->isTruncated()) {
|
|
// Infinity|0 == 0
|
|
Label notzero;
|
|
masm.ma_b(rhs, rhs, ¬zero, Assembler::NonZero, ShortJump);
|
|
masm.move32(Imm32(0), output);
|
|
masm.ma_b(&done, ShortJump);
|
|
masm.bind(¬zero);
|
|
} else {
|
|
bailoutCmp32(Assembler::Equal, rhs, Imm32(0), ins->snapshot());
|
|
}
|
|
}
|
|
|
|
masm.as_divu(lhs, rhs);
|
|
masm.as_mfhi(output);
|
|
|
|
// If the remainder is > 0, bailout since this must be a double.
|
|
if (ins->mir()->isDiv()) {
|
|
if (!ins->mir()->toDiv()->canTruncateRemainder())
|
|
bailoutCmp32(Assembler::NonZero, output, output, ins->snapshot());
|
|
// Get quotient
|
|
masm.as_mflo(output);
|
|
}
|
|
|
|
if (!ins->mir()->isTruncated())
|
|
bailoutCmp32(Assembler::LessThan, output, Imm32(0), ins->snapshot());
|
|
|
|
masm.bind(&done);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitEffectiveAddress(LEffectiveAddress* ins)
|
|
{
|
|
const MEffectiveAddress* mir = ins->mir();
|
|
Register base = ToRegister(ins->base());
|
|
Register index = ToRegister(ins->index());
|
|
Register output = ToRegister(ins->output());
|
|
|
|
BaseIndex address(base, index, mir->scale(), mir->displacement());
|
|
masm.computeEffectiveAddress(address, output);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins)
|
|
{
|
|
const MAsmJSLoadGlobalVar* mir = ins->mir();
|
|
unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias;
|
|
if (mir->type() == MIRType_Int32)
|
|
masm.load32(Address(GlobalReg, addr), ToRegister(ins->output()));
|
|
else if (mir->type() == MIRType_Float32)
|
|
masm.loadFloat32(Address(GlobalReg, addr), ToFloatRegister(ins->output()));
|
|
else
|
|
masm.loadDouble(Address(GlobalReg, addr), ToFloatRegister(ins->output()));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins)
|
|
{
|
|
const MAsmJSStoreGlobalVar* mir = ins->mir();
|
|
|
|
MOZ_ASSERT(IsNumberType(mir->value()->type()));
|
|
unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias;
|
|
if (mir->value()->type() == MIRType_Int32)
|
|
masm.store32(ToRegister(ins->value()), Address(GlobalReg, addr));
|
|
else if (mir->value()->type() == MIRType_Float32)
|
|
masm.storeFloat32(ToFloatRegister(ins->value()), Address(GlobalReg, addr));
|
|
else
|
|
masm.storeDouble(ToFloatRegister(ins->value()), Address(GlobalReg, addr));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins)
|
|
{
|
|
const MAsmJSLoadFuncPtr* mir = ins->mir();
|
|
|
|
Register index = ToRegister(ins->index());
|
|
Register out = ToRegister(ins->output());
|
|
unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias;
|
|
|
|
BaseIndex source(GlobalReg, index, ScalePointer, addr);
|
|
masm.loadPtr(source, out);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins)
|
|
{
|
|
const MAsmJSLoadFFIFunc* mir = ins->mir();
|
|
masm.loadPtr(Address(GlobalReg, mir->globalDataOffset() - AsmJSGlobalRegBias),
|
|
ToRegister(ins->output()));
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitNegI(LNegI* ins)
|
|
{
|
|
Register input = ToRegister(ins->input());
|
|
Register output = ToRegister(ins->output());
|
|
|
|
masm.ma_negu(output, input);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitNegD(LNegD* ins)
|
|
{
|
|
FloatRegister input = ToFloatRegister(ins->input());
|
|
FloatRegister output = ToFloatRegister(ins->output());
|
|
|
|
masm.as_negd(output, input);
|
|
}
|
|
|
|
void
|
|
CodeGeneratorMIPSShared::visitNegF(LNegF* ins)
|
|
{
|
|
FloatRegister input = ToFloatRegister(ins->input());
|
|
FloatRegister output = ToFloatRegister(ins->output());
|
|
|
|
masm.as_negs(output, input);
|
|
}
|