Bug 1134638: 8. Inline SIMD conversions in Ion; r=nbp

This commit is contained in:
Benjamin Bouvier 2015-02-23 19:10:07 +01:00
parent fbd55ba283
commit e0e16ab17a
7 changed files with 160 additions and 52 deletions

View File

@ -0,0 +1,34 @@
load(libdir + 'simd.js');
setJitCompilerOption("ion.warmup.trigger", 50);
var cast = (function() {
var i32 = new Int32Array(1);
var f32 = new Float32Array(i32.buffer);
return {
fromInt32Bits(x) {
i32[0] = x;
return f32[0];
},
fromFloat32Bits(x) {
f32[0] = x;
return i32[0];
}
}
})();
function f() {
var f4 = SIMD.float32x4(1, 2, 3, 4);
var i4 = SIMD.int32x4(1, 2, 3, 4);
var BitOrZero = (x) => x | 0;
for (var i = 0; i < 150; i++) {
assertEqX4(SIMD.float32x4.fromInt32x4(i4), unaryX4(BitOrZero, f4, Math.fround));
assertEqX4(SIMD.float32x4.fromInt32x4Bits(i4), unaryX4(cast.fromInt32Bits, f4, Math.fround));
assertEqX4(SIMD.int32x4.fromFloat32x4(f4), unaryX4(Math.fround, i4, BitOrZero));
assertEqX4(SIMD.int32x4.fromFloat32x4Bits(f4), unaryX4(cast.fromFloat32Bits, i4, BitOrZero));
}
}
f();

View File

@ -9230,7 +9230,8 @@ GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
if (false
ARITH_COMMONX4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
BITWISE_COMMONX4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
|| native == js::simd_int32x4_not || native == js::simd_int32x4_neg)
|| native == js::simd_int32x4_not || native == js::simd_int32x4_neg
|| native == js::simd_int32x4_fromFloat32x4 || native == js::simd_int32x4_fromFloat32x4Bits)
{
Rooted<SimdTypeDescr *> descr(cx, &cx->global()->int32x4TypeDescr().as<SimdTypeDescr>());
res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
@ -9244,7 +9245,8 @@ GetTemplateObjectForNative(JSContext *cx, HandleScript script, jsbytecode *pc,
BITWISE_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)
|| native == js::simd_float32x4_abs || native == js::simd_float32x4_sqrt
|| native == js::simd_float32x4_reciprocal || native == js::simd_float32x4_reciprocalSqrt
|| native == js::simd_float32x4_not || native == js::simd_float32x4_neg)
|| native == js::simd_float32x4_not || native == js::simd_float32x4_neg
|| native == js::simd_float32x4_fromInt32x4 || native == js::simd_float32x4_fromInt32x4Bits)
{
Rooted<SimdTypeDescr *> descr(cx, &cx->global()->float32x4TypeDescr().as<SimdTypeDescr>());
res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));

View File

@ -809,11 +809,19 @@ class IonBuilder
// SIMD intrinsics and natives.
InliningStatus inlineConstructSimdObject(CallInfo &callInfo, SimdTypeDescr *target);
// helpers
bool checkInlineSimd(CallInfo &callInfo, JSNative native, SimdTypeDescr::Type type,
unsigned numArgs, InlineTypedObject **templateObj);
IonBuilder::InliningStatus boxSimd(CallInfo &callInfo, MInstruction *ins,
InlineTypedObject *templateObj);
template <typename T>
InliningStatus inlineBinarySimd(CallInfo &callInfo, JSNative native,
typename T::Operation op, SimdTypeDescr::Type type);
InliningStatus inlineUnarySimd(CallInfo &callInfo, JSNative native,
MSimdUnaryArith::Operation op, SimdTypeDescr::Type type);
InliningStatus inlineSimdConvert(CallInfo &callInfo, JSNative native, bool isCast,
SimdTypeDescr::Type from, SimdTypeDescr::Type to);
// Utility intrinsics.
InliningStatus inlineIsCallable(CallInfo &callInfo);

View File

@ -300,6 +300,16 @@ IonBuilder::inlineNativeCall(CallInfo &callInfo, JSFunction *target)
if (native == js::simd_float32x4_reciprocalSqrt)
return inlineUnarySimd(callInfo, native, MSimdUnaryArith::reciprocalSqrt, SimdTypeDescr::TYPE_FLOAT32);
typedef bool IsCast;
if (native == js::simd_float32x4_fromInt32x4)
return inlineSimdConvert(callInfo, native, IsCast(false), SimdTypeDescr::TYPE_INT32, SimdTypeDescr::TYPE_FLOAT32);
if (native == js::simd_int32x4_fromFloat32x4)
return inlineSimdConvert(callInfo, native, IsCast(false), SimdTypeDescr::TYPE_FLOAT32, SimdTypeDescr::TYPE_INT32);
if (native == js::simd_float32x4_fromInt32x4Bits)
return inlineSimdConvert(callInfo, native, IsCast(true), SimdTypeDescr::TYPE_INT32, SimdTypeDescr::TYPE_FLOAT32);
if (native == js::simd_int32x4_fromFloat32x4Bits)
return inlineSimdConvert(callInfo, native, IsCast(true), SimdTypeDescr::TYPE_FLOAT32, SimdTypeDescr::TYPE_INT32);
return InliningStatus_NotInlined;
}
@ -2902,71 +2912,87 @@ SimdTypeDescrToMIRType(SimdTypeDescr::Type type)
MOZ_CRASH("unexpected SimdTypeDescr");
}
bool
IonBuilder::checkInlineSimd(CallInfo &callInfo, JSNative native, SimdTypeDescr::Type type,
unsigned numArgs, InlineTypedObject **templateObj)
{
if (callInfo.argc() != numArgs)
return false;
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, native);
if (!templateObject)
return false;;
InlineTypedObject *inlineTypedObject = &templateObject->as<InlineTypedObject>();
MOZ_ASSERT(inlineTypedObject->typeDescr().as<SimdTypeDescr>().type() == type);
*templateObj = inlineTypedObject;
return true;
}
IonBuilder::InliningStatus
IonBuilder::boxSimd(CallInfo &callInfo, MInstruction *ins, InlineTypedObject *templateObj)
{
MSimdBox *obj = MSimdBox::New(alloc(), constraints(), ins, templateObj,
templateObj->group()->initialHeap(constraints()));
current->add(ins);
current->add(obj);
current->push(obj);
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
}
template<typename T>
IonBuilder::InliningStatus
IonBuilder::inlineBinarySimd(CallInfo &callInfo, JSNative native, typename T::Operation op,
SimdTypeDescr::Type type)
{
if (callInfo.argc() != 2)
InlineTypedObject *templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 2, &templateObj))
return InliningStatus_NotInlined;
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, native);
if (!templateObject)
return InliningStatus_NotInlined;
InlineTypedObject *inlineTypedObject = &templateObject->as<InlineTypedObject>();
MOZ_ASSERT(inlineTypedObject->typeDescr().as<SimdTypeDescr>().type() == type);
// If the type of any of the arguments is neither a SIMD type, an Object
// type, or a Value, then the applyTypes phase will add a fallible box &
// unbox sequence. This does not matter much as all binary SIMD
// instructions are supposed to produce a TypeError when they're called
// with non SIMD-arguments.
T *ins = T::New(alloc(), callInfo.getArg(0), callInfo.getArg(1), op,
SimdTypeDescrToMIRType(type));
MSimdBox *obj = MSimdBox::New(alloc(), constraints(), ins, inlineTypedObject,
inlineTypedObject->group()->initialHeap(constraints()));
current->add(ins);
current->add(obj);
current->push(obj);
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
MIRType mirType = SimdTypeDescrToMIRType(type);
T *ins = T::New(alloc(), callInfo.getArg(0), callInfo.getArg(1), op, mirType);
return boxSimd(callInfo, ins, templateObj);
}
IonBuilder::InliningStatus
IonBuilder::inlineUnarySimd(CallInfo &callInfo, JSNative native, MSimdUnaryArith::Operation op,
SimdTypeDescr::Type type)
{
if (callInfo.argc() != 1)
InlineTypedObject *templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, type, 1, &templateObj))
return InliningStatus_NotInlined;
JSObject *templateObject = inspector->getTemplateObjectForNative(pc, native);
if (!templateObject)
// See comment in inlineBinarySimd
MIRType mirType = SimdTypeDescrToMIRType(type);
MSimdUnaryArith *ins = MSimdUnaryArith::New(alloc(), callInfo.getArg(0), op, mirType);
return boxSimd(callInfo, ins, templateObj);
}
IonBuilder::InliningStatus
IonBuilder::inlineSimdConvert(CallInfo &callInfo, JSNative native, bool isCast,
SimdTypeDescr::Type from, SimdTypeDescr::Type to)
{
InlineTypedObject *templateObj = nullptr;
if (!checkInlineSimd(callInfo, native, to, 1, &templateObj))
return InliningStatus_NotInlined;
InlineTypedObject *inlineTypedObject = &templateObject->as<InlineTypedObject>();
MOZ_ASSERT(inlineTypedObject->typeDescr().as<SimdTypeDescr>().type() == type);
// See comment in inlineBinarySimd
MInstruction *ins;
MIRType fromType = SimdTypeDescrToMIRType(from);
MIRType toType = SimdTypeDescrToMIRType(to);
if (isCast)
ins = MSimdReinterpretCast::New(alloc(), callInfo.getArg(0), fromType, toType);
else
ins = MSimdConvert::New(alloc(), callInfo.getArg(0), fromType, toType);
// If the type of the argument isn't a SIMD type, an Object type, or a
// Value, then the applyTypes phase will add a fallible box & unbox
// sequence. This does not matter much as all unary SIMD instructions are
// supposed to produce a TypeError when they're called with non
// SIMD-arguments.
MSimdUnaryArith *ins = MSimdUnaryArith::New(alloc(), callInfo.getArg(0), op,
SimdTypeDescrToMIRType(type));
MSimdBox *obj = MSimdBox::New(alloc(), constraints(), ins, inlineTypedObject,
inlineTypedObject->group()->initialHeap(constraints()));
current->add(ins);
current->add(obj);
current->push(obj);
callInfo.setImplicitlyUsedUnchecked();
return InliningStatus_Inlined;
return boxSimd(callInfo, ins, templateObj);
}
} // namespace jit

View File

@ -1512,20 +1512,27 @@ class MSimdConstant
// Converts all lanes of a given vector into the type of another vector
class MSimdConvert
: public MUnaryInstruction,
public NoTypePolicy::Data
public SimdPolicy<0>::Data
{
MSimdConvert(MDefinition *obj, MIRType fromType, MIRType toType)
: MUnaryInstruction(obj)
{
MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
MOZ_ASSERT(IsSimdType(toType));
setResultType(toType);
specialization_ = fromType; // expects fromType as input
}
public:
INSTRUCTION_HEADER(SimdConvert)
static MSimdConvert *NewAsmJS(TempAllocator &alloc, MDefinition *obj, MIRType fromType,
MIRType toType)
{
MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
return new(alloc) MSimdConvert(obj, fromType, toType);
}
static MSimdConvert *New(TempAllocator &alloc, MDefinition *obj, MIRType fromType,
MIRType toType)
{
return new(alloc) MSimdConvert(obj, fromType, toType);
}
@ -1542,20 +1549,27 @@ class MSimdConvert
// Casts bits of a vector input to another SIMD type (doesn't generate code).
class MSimdReinterpretCast
: public MUnaryInstruction,
public NoTypePolicy::Data
public SimdPolicy<0>::Data
{
MSimdReinterpretCast(MDefinition *obj, MIRType fromType, MIRType toType)
: MUnaryInstruction(obj)
{
MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
MOZ_ASSERT(IsSimdType(toType));
setResultType(toType);
specialization_ = fromType; // expects fromType as input
}
public:
INSTRUCTION_HEADER(SimdReinterpretCast)
static MSimdReinterpretCast* NewAsmJS(TempAllocator &alloc, MDefinition *obj, MIRType fromType,
MIRType toType)
{
MOZ_ASSERT(IsSimdType(obj->type()) && fromType == obj->type());
return new(alloc) MSimdReinterpretCast(obj, fromType, toType);
}
static MSimdReinterpretCast* New(TempAllocator &alloc, MDefinition *obj, MIRType fromType,
MIRType toType)
{
return new(alloc) MSimdReinterpretCast(obj, fromType, toType);
}

View File

@ -738,12 +738,10 @@ template bool ObjectPolicy<2>::staticAdjustInputs(TempAllocator &alloc, MInstruc
template bool ObjectPolicy<3>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template <unsigned Op>
bool
SimdSameAsReturnedTypePolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
static bool
MaybeSimdUnbox(TempAllocator &alloc, MInstruction *ins, MIRType type)
{
MIRType type = ins->type();
MOZ_ASSERT(IsSimdType(type));
MDefinition *in = ins->getOperand(Op);
if (in->type() == type)
return true;
@ -755,11 +753,28 @@ SimdSameAsReturnedTypePolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInst
return replace->typePolicy()->adjustInputs(alloc, replace);
}
template <unsigned Op>
bool
SimdSameAsReturnedTypePolicy<Op>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins)
{
return MaybeSimdUnbox<Op>(alloc, ins, ins->type());
}
template bool
SimdSameAsReturnedTypePolicy<0>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template bool
SimdSameAsReturnedTypePolicy<1>::staticAdjustInputs(TempAllocator &alloc, MInstruction *ins);
template <unsigned Op>
bool
SimdPolicy<Op>::adjustInputs(TempAllocator &alloc, MInstruction *ins)
{
return MaybeSimdUnbox<Op>(alloc, ins, ins->typePolicySpecialization());
}
template bool
SimdPolicy<0>::adjustInputs(TempAllocator &alloc, MInstruction *ins);
bool
CallPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
{
@ -1095,6 +1110,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
_(ObjectPolicy<0>) \
_(ObjectPolicy<1>) \
_(ObjectPolicy<3>) \
_(SimdPolicy<0>) \
_(SimdSameAsReturnedTypePolicy<0>) \
_(StringPolicy<0>)

View File

@ -324,6 +324,14 @@ class SimdScalarPolicy MOZ_FINAL : public TypePolicy
}
};
template <unsigned Op>
class SimdPolicy MOZ_FINAL : public TypePolicy
{
public:
SPECIALIZATION_DATA_;
virtual bool adjustInputs(TempAllocator &alloc, MInstruction *ins) MOZ_OVERRIDE;
};
// SIMD value-type policy, use the returned type of the instruction to determine
// how to unbox its operand.
template <unsigned Op>