mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1134638: 8. Inline SIMD conversions in Ion; r=nbp
This commit is contained in:
parent
fbd55ba283
commit
e0e16ab17a
34
js/src/jit-test/tests/SIMD/convert.js
Normal file
34
js/src/jit-test/tests/SIMD/convert.js
Normal 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();
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>)
|
||||
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user