Skip to content

Instantly share code, notes, and snippets.

@evilpie
Created August 7, 2012 18:25
Show Gist options
  • Save evilpie/3288066 to your computer and use it in GitHub Desktop.
Save evilpie/3288066 to your computer and use it in GitHub Desktop.
diff --git a/js/src/assembler/assembler/X86Assembler.h b/js/src/assembler/assembler/X86Assembler.h
--- a/js/src/assembler/assembler/X86Assembler.h
+++ b/js/src/assembler/assembler/X86Assembler.h
@@ -279,16 +279,17 @@ private:
OP2_ADDSD_VsdWsd = 0x58,
OP2_MULSD_VsdWsd = 0x59,
OP2_CVTSS2SD_VsdEd = 0x5A,
OP2_CVTSD2SS_VsdEd = 0x5A,
OP2_SUBSD_VsdWsd = 0x5C,
OP2_DIVSD_VsdWsd = 0x5E,
OP2_SQRTSD_VsdWsd = 0x51,
OP2_ANDPD_VpdWpd = 0x54,
+ OP2_ORPD_VpdWpd = 0x56,
OP2_XORPD_VpdWpd = 0x57,
OP2_MOVD_VdEd = 0x6E,
OP2_PSRLDQ_Vd = 0x73,
OP2_PCMPEQW = 0x75,
OP2_MOVD_EdVd = 0x7E,
OP2_JCC_rel32 = 0x80,
OP_SETCC = 0x90,
OP2_IMUL_GvEv = 0xAF,
@@ -2444,16 +2445,25 @@ public:
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "xorpd %s, %s\n", MAYBE_PAD,
nameFPReg(src), nameFPReg(dst));
m_formatter.prefix(PRE_SSE_66);
m_formatter.twoByteOp(OP2_XORPD_VpdWpd, (RegisterID)dst, (RegisterID)src);
}
+ void orpd_rr(XMMRegisterID src, XMMRegisterID dst)
+ {
+ js::JaegerSpew(js::JSpew_Insns,
+ IPFX "orpd %s, %s\n", MAYBE_PAD,
+ nameFPReg(src), nameFPReg(dst));
+ m_formatter.prefix(PRE_SSE_66);
+ m_formatter.twoByteOp(OP2_ORPD_VpdWpd, (RegisterID)dst, (RegisterID)src);
+ }
+
void andpd_rr(XMMRegisterID src, XMMRegisterID dst)
{
js::JaegerSpew(js::JSpew_Insns,
IPFX "andpd %s, %s\n", MAYBE_PAD,
nameFPReg(src), nameFPReg(dst));
m_formatter.prefix(PRE_SSE_66);
m_formatter.twoByteOp(OP2_ANDPD_VpdWpd, (RegisterID)dst, (RegisterID)src);
}
diff --git a/js/src/ion/CodeGenerator.cpp b/js/src/ion/CodeGenerator.cpp
--- a/js/src/ion/CodeGenerator.cpp
+++ b/js/src/ion/CodeGenerator.cpp
@@ -1505,16 +1505,45 @@ CodeGenerator::visitStringLength(LString
Register output = ToRegister(lir->output());
masm.loadPtr(lengthAndFlags, output);
masm.rshiftPtr(Imm32(JSString::LENGTH_SHIFT), output);
return true;
}
bool
+CodeGenerator::visitMinMaxI(LMinMaxI *ins)
+{
+ Register first = ToRegister(ins->first());
+ Register output = ToRegister(ins->output());
+
+ JS_ASSERT(first == output);
+
+ if (ins->second()->isConstant())
+ masm.cmp32(first, Imm32(ToInt32(ins->second())));
+ else
+ masm.cmp32(first, ToRegister(ins->second()));
+
+ Label done;
+ if (ins->mir()->isMax())
+ masm.j(Assembler::GreaterThan, &done);
+ else
+ masm.j(Assembler::LessThan, &done);
+
+ if (ins->second()->isConstant())
+ masm.move32(Imm32(ToInt32(ins->second())), output);
+ else
+ masm.mov(ToRegister(ins->second()), output);
+
+
+ masm.bind(&done);
+ return true;
+}
+
+bool
CodeGenerator::visitAbsI(LAbsI *ins)
{
Register input = ToRegister(ins->input());
Label positive;
JS_ASSERT(input == ToRegister(ins->output()));
masm.test32(input, input);
masm.j(Assembler::GreaterThanOrEqual, &positive);
diff --git a/js/src/ion/CodeGenerator.h b/js/src/ion/CodeGenerator.h
--- a/js/src/ion/CodeGenerator.h
+++ b/js/src/ion/CodeGenerator.h
@@ -104,16 +104,17 @@ class CodeGenerator : public CodeGenerat
bool visitLoadFixedSlotT(LLoadFixedSlotT *ins);
bool visitStoreFixedSlotV(LStoreFixedSlotV *ins);
bool visitStoreFixedSlotT(LStoreFixedSlotT *ins);
bool visitAbsI(LAbsI *lir);
bool visitPowI(LPowI *lir);
bool visitPowD(LPowD *lir);
bool visitMathFunctionD(LMathFunctionD *ins);
bool visitModD(LModD *ins);
+ bool visitMinMaxI(LMinMaxI *lir);
bool visitBinaryV(LBinaryV *lir);
bool visitCompareS(LCompareS *lir);
bool visitCompareV(LCompareV *lir);
bool visitIsNullOrUndefined(LIsNullOrUndefined *lir);
bool visitIsNullOrUndefinedAndBranch(LIsNullOrUndefinedAndBranch *lir);
bool visitConcat(LConcat *lir);
bool visitCharCodeAt(LCharCodeAt *lir);
bool visitFromCharCode(LFromCharCode *lir);
diff --git a/js/src/ion/IonBuilder.h b/js/src/ion/IonBuilder.h
--- a/js/src/ion/IonBuilder.h
+++ b/js/src/ion/IonBuilder.h
@@ -376,16 +376,17 @@ class IonBuilder : public MIRGenerator
InliningStatus inlineArrayPopShift(MArrayPopShift::Mode mode, uint32 argc, bool constructing);
InliningStatus inlineArrayPush(uint32 argc, bool constructing);
// Math natives.
InliningStatus inlineMathAbs(uint32 argc, bool constructing);
InliningStatus inlineMathFloor(uint32 argc, bool constructing);
InliningStatus inlineMathRound(uint32 argc, bool constructing);
InliningStatus inlineMathSqrt(uint32 argc, bool constructing);
+ InliningStatus inlineMathMinMax(bool max, uint32 argc, bool constructing);
InliningStatus inlineMathPow(uint32 argc, bool constructing);
InliningStatus inlineMathFunction(MMathFunction::Function function, uint32 argc,
bool constructing);
// String natives.
InliningStatus inlineStrCharCodeAt(uint32 argc, bool constructing);
InliningStatus inlineStrFromCharCode(uint32 argc, bool constructing);
InliningStatus inlineStrCharAt(uint32 argc, bool constructing);
diff --git a/js/src/ion/IonCaches.cpp b/js/src/ion/IonCaches.cpp
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -783,16 +783,19 @@ js::ion::GetElementCache(JSContext *cx,
// Override the return value if we are invalidated (bug 728188).
AutoDetectInvalidation adi(cx, res.address(), ion);
RootedId id(cx);
if (!FetchElementId(cx, obj, idval, id.address(), res))
return false;
+ obj->dump();
+ js_DumpValue(idval);
+
if (cache.stubCount() < MAX_STUBS) {
if (obj->isNative() && cache.monitoredResult()) {
cache.incrementStubCount();
uint32_t dummy;
if (idval.isString() && JSID_IS_ATOM(id) && !JSID_TO_ATOM(id)->isIndex(&dummy)) {
if (!cache.attachGetProp(cx, obj, idval, JSID_TO_ATOM(id)->asPropertyName()))
return false;
diff --git a/js/src/ion/LIR-Common.h b/js/src/ion/LIR-Common.h
--- a/js/src/ion/LIR-Common.h
+++ b/js/src/ion/LIR-Common.h
@@ -1117,16 +1117,64 @@ class LBinaryMath : public LInstructionH
const LAllocation *lhs() {
return this->getOperand(0);
}
const LAllocation *rhs() {
return this->getOperand(1);
}
};
+class LMinMaxI : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(MinMaxI);
+ LMinMaxI(const LAllocation &first, const LAllocation &second)
+ {
+ setOperand(0, first);
+ setOperand(1, second);
+ }
+
+ const LAllocation *first() {
+ return this->getOperand(0);
+ }
+ const LAllocation *second() {
+ return this->getOperand(1);
+ }
+ const LDefinition *output() {
+ return this->getDef(0);
+ }
+ MMinMax *mir() const {
+ return mir_->toMinMax();
+ }
+};
+
+class LMinMaxD : public LInstructionHelper<1, 2, 0>
+{
+ public:
+ LIR_HEADER(MinMaxD);
+ LMinMaxD(const LAllocation &first, const LAllocation &second)
+ {
+ setOperand(0, first);
+ setOperand(1, second);
+ }
+
+ const LAllocation *first() {
+ return this->getOperand(0);
+ }
+ const LAllocation *second() {
+ return this->getOperand(1);
+ }
+ const LDefinition *output() {
+ return this->getDef(0);
+ }
+ MMinMax *mir() const {
+ return mir_->toMinMax();
+ }
+};
+
// Absolute value of an integer.
class LAbsI : public LInstructionHelper<1, 1, 0>
{
public:
LIR_HEADER(AbsI);
LAbsI(const LAllocation &num) {
setOperand(0, num);
}
diff --git a/js/src/ion/LOpcodes.h b/js/src/ion/LOpcodes.h
--- a/js/src/ion/LOpcodes.h
+++ b/js/src/ion/LOpcodes.h
@@ -54,16 +54,18 @@
_(CompareS) \
_(CompareV) \
_(CompareAndBranch) \
_(CompareDAndBranch) \
_(CompareB) \
_(CompareBAndBranch) \
_(IsNullOrUndefined) \
_(IsNullOrUndefinedAndBranch) \
+ _(MinMaxI) \
+ _(MinMaxD) \
_(AbsI) \
_(AbsD) \
_(SqrtD) \
_(PowI) \
_(PowD) \
_(MathFunctionD) \
_(NotI) \
_(NotD) \
diff --git a/js/src/ion/Lowering.cpp b/js/src/ion/Lowering.cpp
--- a/js/src/ion/Lowering.cpp
+++ b/js/src/ion/Lowering.cpp
@@ -647,16 +647,32 @@ LIRGenerator::visitRound(MRound *ins)
JS_ASSERT(ins->num()->type() == MIRType_Double);
LRound *lir = new LRound(useRegister(ins->num()), tempFloat());
if (!assignSnapshot(lir))
return false;
return define(lir, ins);
}
bool
+LIRGenerator::visitMinMax(MMinMax *ins)
+{
+ MDefinition *first = ins->getOperand(0);
+ MDefinition *second = ins->getOperand(1);
+
+ if (ins->specialization() == MIRType_Int32) {
+ ReorderCommutative(&first, &second);
+ LMinMaxI *lir = new LMinMaxI(useRegisterAtStart(first), useRegisterOrConstant(second));
+ return defineReuseInput(lir, ins, 0);
+ } else {
+ LMinMaxD *lir = new LMinMaxD(useRegisterAtStart(first), useRegister(second));
+ return defineReuseInput(lir, ins, 0);
+ }
+}
+
+bool
LIRGenerator::visitAbs(MAbs *ins)
{
MDefinition *num = ins->num();
if (num->type() == MIRType_Int32) {
LAbsI *lir = new LAbsI(useRegisterAtStart(num));
// needed to handle abs(INT32_MIN)
if (!ins->range()->isFinite() && !assignSnapshot(lir))
diff --git a/js/src/ion/Lowering.h b/js/src/ion/Lowering.h
--- a/js/src/ion/Lowering.h
+++ b/js/src/ion/Lowering.h
@@ -99,16 +99,17 @@ class LIRGenerator : public LIRGenerator
bool visitBitAnd(MBitAnd *ins);
bool visitBitOr(MBitOr *ins);
bool visitBitXor(MBitXor *ins);
bool visitLsh(MLsh *ins);
bool visitRsh(MRsh *ins);
bool visitUrsh(MUrsh *ins);
bool visitFloor(MFloor *ins);
bool visitRound(MRound *ins);
+ bool visitMinMax(MMinMax *ins);
bool visitAbs(MAbs *ins);
bool visitSqrt(MSqrt *ins);
bool visitPow(MPow *ins);
bool visitMathFunction(MMathFunction *ins);
bool visitAdd(MAdd *ins);
bool visitSub(MSub *ins);
bool visitMul(MMul *ins);
bool visitDiv(MDiv *ins);
diff --git a/js/src/ion/MCallOptimize.cpp b/js/src/ion/MCallOptimize.cpp
--- a/js/src/ion/MCallOptimize.cpp
+++ b/js/src/ion/MCallOptimize.cpp
@@ -32,16 +32,20 @@ IonBuilder::inlineNativeCall(JSNative na
if (native == js_math_abs)
return inlineMathAbs(argc, constructing);
if (native == js_math_floor)
return inlineMathFloor(argc, constructing);
if (native == js_math_round)
return inlineMathRound(argc, constructing);
if (native == js_math_sqrt)
return inlineMathSqrt(argc, constructing);
+ if (native == js_math_max)
+ return inlineMathMinMax(true /* max */, argc, constructing);
+ if (native == js_math_min)
+ return inlineMathMinMax(false /* max */, argc, constructing);
if (native == js_math_pow)
return inlineMathPow(argc, constructing);
if (native == js::math_sin)
return inlineMathFunction(MMathFunction::Sin, argc, constructing);
if (native == js::math_cos)
return inlineMathFunction(MMathFunction::Cos, argc, constructing);
if (native == js::math_tan)
return inlineMathFunction(MMathFunction::Tan, argc, constructing);
@@ -535,16 +539,50 @@ IonBuilder::inlineMathPow(uint32 argc, b
MPow *ins = MPow::New(argv[1], argv[2], arg2Type);
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
+IonBuilder::inlineMathMinMax(bool max, uint32 argc, bool constructing)
+{
+ if (argc != 2 || constructing)
+ return InliningStatus_NotInlined;
+
+ MIRType returnType = getInlineReturnType();
+ if (returnType != MIRType_Double && returnType != MIRType_Int32)
+ return InliningStatus_NotInlined;
+
+ MIRType arg1Type = getInlineArgType(argc, 1);
+ if (arg1Type != MIRType_Double && arg1Type != MIRType_Int32)
+ return InliningStatus_NotInlined;
+ MIRType arg2Type = getInlineArgType(argc, 2);
+ if (arg2Type != MIRType_Double && arg2Type != MIRType_Int32)
+ return InliningStatus_NotInlined;
+
+ if (returnType == MIRType_Int32 &&
+ (arg1Type == MIRType_Double || arg2Type == MIRType_Double))
+ {
+ // We would need to inform TI, if we happen to return a double.
+ return InliningStatus_NotInlined;
+ }
+
+ MDefinitionVector argv;
+ if (!discardCall(argc, argv, current))
+ return InliningStatus_Error;
+
+ MMinMax *ins = MMinMax::New(argv[1], argv[2], returnType, max);
+ current->add(ins);
+ current->push(ins);
+ return InliningStatus_Inlined;
+}
+
+IonBuilder::InliningStatus
IonBuilder::inlineStrCharCodeAt(uint32 argc, bool constructing)
{
if (argc != 1 || constructing)
return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Int32)
return InliningStatus_NotInlined;
if (getInlineArgType(argc, 0) != MIRType_String)
diff --git a/js/src/ion/MIR.h b/js/src/ion/MIR.h
--- a/js/src/ion/MIR.h
+++ b/js/src/ion/MIR.h
@@ -2117,16 +2117,61 @@ class MBinaryArithInstruction
}
AliasSet getAliasSet() const {
if (specialization_ >= MIRType_Object)
return AliasSet::Store(AliasSet::Any);
return AliasSet::None();
}
};
+class MMinMax
+ : public MBinaryInstruction,
+ public ArithPolicy
+{
+ bool isMax_;
+
+ MMinMax(MDefinition *left, MDefinition *right, MIRType type, bool isMax)
+ : MBinaryInstruction(left, right),
+ isMax_(isMax)
+ {
+ JS_ASSERT(type == MIRType_Double || type == MIRType_Int32);
+ setResultType(type);
+ setMovable();
+ specialization_ = type;
+ }
+
+ public:
+ INSTRUCTION_HEADER(MinMax);
+ static MMinMax *New(MDefinition *left, MDefinition *right, MIRType type, bool isMax) {
+ return new MMinMax(left, right, type, isMax);
+ }
+
+ bool isMax() const {
+ return isMax_;
+ }
+ MIRType specialization() const {
+ return specialization_;
+ }
+
+ TypePolicy *typePolicy() {
+ return this;
+ }
+ bool congruentTo(MDefinition *const &ins) const {
+ if (!ins->isMinMax())
+ return false;
+ if (isMax() != ins->toMinMax()->isMax())
+ return false;
+ return congruentIfOperandsEqual(ins);
+ }
+
+ AliasSet getAliasSet() const {
+ return AliasSet::None();
+ }
+};
+
class MAbs
: public MUnaryInstruction,
public ArithPolicy
{
MAbs(MDefinition *num, MIRType type)
: MUnaryInstruction(num)
{
JS_ASSERT(type == MIRType_Double || type == MIRType_Int32);
diff --git a/js/src/ion/MOpcodes.h b/js/src/ion/MOpcodes.h
--- a/js/src/ion/MOpcodes.h
+++ b/js/src/ion/MOpcodes.h
@@ -38,16 +38,17 @@ namespace ion {
_(TypeOf) \
_(ToId) \
_(BitAnd) \
_(BitOr) \
_(BitXor) \
_(Lsh) \
_(Rsh) \
_(Ursh) \
+ _(MinMax) \
_(Abs) \
_(Sqrt) \
_(Pow) \
_(PowHalf) \
_(MathFunction) \
_(Add) \
_(Sub) \
_(Mul) \
diff --git a/js/src/ion/arm/CodeGenerator-arm.cpp b/js/src/ion/arm/CodeGenerator-arm.cpp
--- a/js/src/ion/arm/CodeGenerator-arm.cpp
+++ b/js/src/ion/arm/CodeGenerator-arm.cpp
@@ -271,16 +271,106 @@ CodeGeneratorARM::visitOutOfLineBailout(
masm.ma_mov(Imm32(ool->snapshot()->snapshotOffset()), ScratchRegister);
masm.ma_push(ScratchRegister);
masm.ma_push(ScratchRegister);
masm.ma_b(deoptLabel_);
return true;
}
bool
+CodeGeneratorARM::visitMinMaxD(LMinMaxD *ins)
+{
+ FloatRegister first = ToFloatRegister(ins->first());
+ FloatRegister second = ToFloatRegister(ins->second());
+ FloatRegister output = ToFloatRegister(ins->output());
+
+ JS_ASSERT(first == output);
+
+ Assembler::Condition cond = ins->mir()->isMax()
+ ? VFP_GreaterThanOrEqual
+ : VFP_LessThanOrEqual;
+ Label nan, equal, returnSecond, done;
+
+ masm.compareDouble(first, second);
+ masm.ma_b(&nan, VFP_Unordered); // first or second is NaN, result is NaN.
+ masm.ma_b(&equal, VFP_Equal); // make sure we handle -0 and 0 right.
+ masm.ma_b(&returnSecond, cond);
+ masm.ma_b(&done);
+
+ // Check for zero.
+ masm.bind(&equal);
+ masm.compareDouble(first, InvalidFloatReg);
+ masm.ma_b(&done, VFP_NotEqual); // first wasn't 0 or -0, so just return it.
+ // So now both operands are either -0 or 0.
+ if (ins->mir()->isMax()) {
+ masm.ma_vadd(second, first, first); // -0 + -0 = -0 and -0 + 0 = 0.
+ } else {
+ masm.ma_vneg(first, first);
+ masm.ma_vsub(first, second, first);
+ masm.ma_vneg(first, first);
+ }
+ masm.jmp(&done);
+
+ masm.bind(&nan);
+ masm.loadStaticDouble(&js_NaN, output);
+ masm.jmp(&done);
+
+ masm.bind(&returnSecond);
+ masm.movsd(second, output);
+
+ masm.bind(&done);
+ return true;
+
+ Assembler::Condition cond = ins->mir()->isMax()
+ ? Assembler::Above
+ : Assembler::Below;
+
+
+
+ Label nan, secondCheck, normal, done;
+
+ masm.compareDouble(first, second);
+ masm.ma_b(&nan, VFP_Unordered); // If one argument is NaN the result is NaN.
+ masm.ma_b(&secondCheck, VFP_NotEqual);
+
+ masm.compareDouble(second, InvalidFloatReg);
+ masm.ma_b(&nan, VFP_Unordered); // Second argument was NaN.
+ masm.ma_b(&normal, VFP_NotEqual);
+
+ // We need to check which argument could be -0.
+ {
+ if (ins->mir()->isMax())
+ masm.branchTestNegativeZero(Assembler::NotEqual, first, &done);
+ else
+ masm.branchTestNegativeZero(Assembler::Equal, first, &done);
+ masm.moveDouble(second, output);
+ masm.ma_b(&done);
+ }
+
+ masm.bind(&nan);
+ masm.loadStaticDouble(&js_NaN, output);
+ masm.ma_b(&done);
+
+ masm.bind(&secondCheck);
+ // first is not NaN and not zero so we only need to check if second is NaN.
+ masm.compareDouble(second, InvalidFloatReg);
+ masm.ma_b(&nan, VFP_Unordered);
+
+ masm.bind(&normal);
+ if (ins->mir()->isMax())
+ masm.branchDouble(Assembler::DoubleGreaterThan, first, second, &done);
+ else
+ masm.branchDouble(Assembler::DoubleLessThan, first, second, &done);
+ masm.moveDouble(second, output);
+
+ masm.bind(&done);
+ return true;
+}
+
+bool
CodeGeneratorARM::visitAbsD(LAbsD *ins)
{
FloatRegister input = ToFloatRegister(ins->input());
JS_ASSERT(input == ToFloatRegister(ins->output()));
masm.as_vabs(input, input);
return true;
}
diff --git a/js/src/ion/arm/CodeGenerator-arm.h b/js/src/ion/arm/CodeGenerator-arm.h
--- a/js/src/ion/arm/CodeGenerator-arm.h
+++ b/js/src/ion/arm/CodeGenerator-arm.h
@@ -61,16 +61,17 @@ class CodeGeneratorARM : public CodeGene
void emitSet(Assembler::Condition cond, const Register &dest);
// Emits a branch that directs control flow to the true block if |cond| is
// true, and the false block if |cond| is false.
void emitBranch(Assembler::Condition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
public:
// Instruction visitors.
+ virtual bool visitMinMaxD(LMinMaxD *ins);
virtual bool visitAbsD(LAbsD *ins);
virtual bool visitSqrtD(LSqrtD *ins);
virtual bool visitAddI(LAddI *ins);
virtual bool visitSubI(LSubI *ins);
virtual bool visitBitNotI(LBitNotI *ins);
virtual bool visitBitOpI(LBitOpI *ins);
virtual bool visitMulI(LMulI *ins);
diff --git a/js/src/ion/arm/MacroAssembler-arm.cpp b/js/src/ion/arm/MacroAssembler-arm.cpp
--- a/js/src/ion/arm/MacroAssembler-arm.cpp
+++ b/js/src/ion/arm/MacroAssembler-arm.cpp
@@ -1922,16 +1922,25 @@ MacroAssemblerARMCompat::branchDouble(Do
ma_b(label, VFP_Unordered);
ma_b(label, VFP_Equal);
return;
}
ma_b(label, ConditionFromDoubleCondition(cond));
}
+void
+MacroAssemblerARMCompat::branchTestNegativeZero(Assembler::Condition cond, const FloatRegister &input,
+ Label *label)
+{
+ as_vxfer(ScratchRegister, InvalidReg, input, FloatToCore, Always, 1);
+ as_tst(ScratchRegister, O2Reg(ScratchRegister));
+ as_b(label, InvertCondition(cond));
+}
+
// higher level tag testing code
Operand ToPayload(Operand base) {
return Operand(Register::FromCode(base.base()),
base.disp());
}
Operand ToType(Operand base) {
return Operand(Register::FromCode(base.base()),
base.disp() + sizeof(void *));
diff --git a/js/src/ion/arm/MacroAssembler-arm.h b/js/src/ion/arm/MacroAssembler-arm.h
--- a/js/src/ion/arm/MacroAssembler-arm.h
+++ b/js/src/ion/arm/MacroAssembler-arm.h
@@ -954,16 +954,20 @@ class MacroAssemblerARMCompat : public M
}
void storeDouble(FloatRegister src, BaseIndex addr) {
// Harder cases not handled yet.
JS_ASSERT(addr.offset == 0);
uint32 scale = Imm32::ShiftOf(addr.scale).value;
ma_vstr(src, addr.base, addr.index, scale);
}
+ void moveDouble(FloatRegister src, FloatRegister dest) {
+ ma_vmov(src, dest);
+ }
+
void storeFloat(FloatRegister src, Address addr) {
ma_vstr(VFPRegister(src).singleOverlay(), Operand(addr));
}
void storeFloat(FloatRegister src, BaseIndex addr) {
// Harder cases not handled yet.
JS_ASSERT(addr.offset == 0);
uint32 scale = Imm32::ShiftOf(addr.scale).value;
ma_vstr(VFPRegister(src).singleOverlay(), addr.base, addr.index, scale);
@@ -993,16 +997,18 @@ class MacroAssemblerARMCompat : public M
void setStackArg(const Register &reg, uint32 arg);
void breakpoint();
void compareDouble(FloatRegister lhs, FloatRegister rhs);
void branchDouble(DoubleCondition cond, const FloatRegister &lhs, const FloatRegister &rhs,
Label *label);
+ void branchTestNegativeZero(Condition cond, const FloatRegister &input, Label *label);
+
void checkStackAlignment();
void rshiftPtr(Imm32 imm, Register dest) {
ma_lsr(imm, dest, dest);
}
void lshiftPtr(Imm32 imm, Register dest) {
ma_lsl(imm, dest, dest);
}
diff --git a/js/src/ion/shared/Assembler-x86-shared.h b/js/src/ion/shared/Assembler-x86-shared.h
--- a/js/src/ion/shared/Assembler-x86-shared.h
+++ b/js/src/ion/shared/Assembler-x86-shared.h
@@ -1050,16 +1050,19 @@ class AssemblerX86Shared
masm.mulsd_rr(src.code(), dest.code());
}
void divsd(const FloatRegister &src, const FloatRegister &dest) {
masm.divsd_rr(src.code(), dest.code());
}
void xorpd(const FloatRegister &src, const FloatRegister &dest) {
masm.xorpd_rr(src.code(), dest.code());
}
+ void orpd(const FloatRegister &src, const FloatRegister &dest) {
+ masm.orpd_rr(src.code(), dest.code());
+ }
void andpd(const FloatRegister &src, const FloatRegister &dest) {
masm.andpd_rr(src.code(), dest.code());
}
void sqrtsd(const FloatRegister &src, const FloatRegister &dest) {
masm.sqrtsd_rr(src.code(), dest.code());
}
void roundsd(const FloatRegister &src, const FloatRegister &dest,
JSC::X86Assembler::RoundingMode mode)
diff --git a/js/src/ion/shared/CodeGenerator-x86-shared.cpp b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -397,16 +397,60 @@ CodeGeneratorX86Shared::visitOutOfLineBa
if (!deoptLabel_)
deoptLabel_ = new HeapLabel();
masm.push(Imm32(ool->snapshot()->snapshotOffset()));
masm.jmp(deoptLabel_);
return true;
}
+
+bool
+CodeGeneratorX86Shared::visitMinMaxD(LMinMaxD *ins)
+{
+ FloatRegister first = ToFloatRegister(ins->first());
+ FloatRegister second = ToFloatRegister(ins->second());
+ FloatRegister output = ToFloatRegister(ins->output());
+
+ JS_ASSERT(first == output);
+
+ Assembler::Condition cond = ins->mir()->isMax()
+ ? Assembler::Above
+ : Assembler::Below;
+ Label nan, equal, returnSecond, done;
+
+ masm.ucomisd(second, first);
+ masm.j(Assembler::Parity, &nan); // first or second is NaN, result is NaN.
+ masm.j(Assembler::Equal, &equal); // make sure we handle -0 and 0 right.
+ masm.j(cond, &returnSecond);
+ masm.jmp(&done);
+
+ // Check for zero.
+ masm.bind(&equal);
+ masm.xorpd(ScratchFloatReg, ScratchFloatReg);
+ masm.ucomisd(first, ScratchFloatReg);
+ masm.j(Assembler::NotEqual, &done); // first wasn't 0 or -0, so just return it.
+ // So now both operands are either -0 or 0.
+ if (ins->mir()->isMax())
+ masm.addsd(second, first); // -0 + -0 = -0 and -0 + 0 = 0.
+ else
+ masm.orpd(second, first); // This just ors the sign bit.
+ masm.jmp(&done);
+
+ masm.bind(&nan);
+ masm.loadStaticDouble(&js_NaN, output);
+ masm.jmp(&done);
+
+ masm.bind(&returnSecond);
+ masm.movsd(second, output);
+
+ masm.bind(&done);
+ return true;
+}
+
bool
CodeGeneratorX86Shared::visitAbsD(LAbsD *ins)
{
FloatRegister input = ToFloatRegister(ins->input());
JS_ASSERT(input == ToFloatRegister(ins->output()));
masm.xorpd(ScratchFloatReg, ScratchFloatReg);
masm.subsd(input, ScratchFloatReg); // negate the sign bit.
masm.andpd(ScratchFloatReg, input); // s & ~s
diff --git a/js/src/ion/shared/CodeGenerator-x86-shared.h b/js/src/ion/shared/CodeGenerator-x86-shared.h
--- a/js/src/ion/shared/CodeGenerator-x86-shared.h
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.h
@@ -80,16 +80,17 @@ class CodeGeneratorX86Shared : public Co
NaNCond ifNaN = NaN_Unexpected);
void emitBranch(Assembler::DoubleCondition cond, MBasicBlock *ifTrue, MBasicBlock *ifFalse);
public:
CodeGeneratorX86Shared(MIRGenerator *gen, LIRGraph &graph);
public:
// Instruction visitors.
+ virtual bool visitMinMaxD(LMinMaxD *ins);
virtual bool visitAbsD(LAbsD *ins);
virtual bool visitSqrtD(LSqrtD *ins);
virtual bool visitPowHalfD(LPowHalfD *ins);
virtual bool visitAddI(LAddI *ins);
virtual bool visitSubI(LSubI *ins);
virtual bool visitMulI(LMulI *ins);
virtual bool visitDivI(LDivI *ins);
virtual bool visitModI(LModI *ins);
diff --git a/js/src/ion/shared/MacroAssembler-x86-shared.h b/js/src/ion/shared/MacroAssembler-x86-shared.h
--- a/js/src/ion/shared/MacroAssembler-x86-shared.h
+++ b/js/src/ion/shared/MacroAssembler-x86-shared.h
@@ -242,16 +242,19 @@ class MacroAssemblerX86Shared : public A
movsd(Operand(src), dest);
}
void storeDouble(FloatRegister src, const Address &dest) {
movsd(src, Operand(dest));
}
void storeDouble(FloatRegister src, const BaseIndex &dest) {
movsd(src, Operand(dest));
}
+ void moveDouble(FloatRegister src, FloatRegister dest) {
+ movsd(src, dest);
+ }
void zeroDouble(FloatRegister reg) {
xorpd(reg, reg);
}
void addDouble(FloatRegister src, FloatRegister dest) {
addsd(src, dest);
}
void convertDoubleToFloat(const FloatRegister &src, const FloatRegister &dest) {
cvtsd2ss(src, dest);
@@ -270,16 +273,28 @@ class MacroAssemblerX86Shared : public A
}
void storeFloat(FloatRegister src, const Address &dest) {
movss(src, Operand(dest));
}
void storeFloat(FloatRegister src, const BaseIndex &dest) {
movss(src, Operand(dest));
}
+ void branchTestNegativeZero(Condition cond, const FloatRegister &input, Label *label) {
+ JS_ASSERT(cond == Assembler::Equal || cond == Assembler::NotEqual);
+
+ movsd(input, ScratchFloatReg);
+ // Move the sign bit into some position so it's not NaN. (It's 2.0 when -0.0)
+ psrlq(Imm32(1), ScratchFloatReg);
+ // If |input| was 0 it is still going to compare equal to ScratchFloatReg.
+ compareDouble(Assembler::DoubleEqual, input, ScratchFloatReg);
+
+ j(InvertCondition(cond), label);
+ }
+
void clampIntToUint8(Register src, Register dest) {
Label inRange, done;
branchTest32(Assembler::Zero, src, Imm32(0xffffff00), &inRange);
{
Label negative;
branchTest32(Assembler::Signed, src, src, &negative);
{
movl(Imm32(255), dest);
diff --git a/js/src/jit-test/tests/ion/mathMinMax.js b/js/src/jit-test/tests/ion/mathMinMax.js
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/ion/mathMinMax.js
@@ -0,0 +1,39 @@
+var nan = Number.NaN;
+var negative_zero = -0;
+
+function max(a, b) {
+ return Math.max(a, b);
+}
+function min(a, b) {
+ return Math.min(a, b);
+}
+
+function main() {
+ for (var i = 0; i < 100; i++) {
+ assertEq(max(negative_zero, 0), 0);
+ assertEq(max(0, negative_zero), 0);
+ assertEq(min(0, negative_zero), negative_zero);
+ assertEq(min(negative_zero, 0), negative_zero);
+
+ assertEq(min(negative_zero, negative_zero), negative_zero);
+ assertEq(max(negative_zero, negative_zero), negative_zero);
+
+ assertEq(max(nan, 0), nan);
+ assertEq(min(nan, 0), nan);
+
+ assertEq(max(0, nan), nan);
+ assertEq(max(nan, 0), nan);
+
+ assertEq(max(3, 5), 5);
+ assertEq(max(5, 3), 5);
+
+ assertEq(max(Infinity, -Infinity), Infinity);
+ assertEq(min(Infinity, -Infinity), -Infinity);
+ assertEq(max(Infinity, nan), nan);
+
+ assertEq(max(negative_zero, -5), negative_zero);
+ assertEq(min(negative_zero, -5), -5);
+ }
+}
+
+main();
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment