зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1240796 - Connect SIMD.Uint32x4 operations to the Ion inliner. r=bbouvier
Add a new InlinableNative::SimdUint32x4 enumerator, and emit the corresponding JSJitInfo objects in SIMD.cpp. Start producing template objects for Uint32x4 operations in BaselineIC.cpp. Add a new SimdSign enum class to SIMD.h which will be used to distinguish between signed and unsigned integers in the few places where it matters. Map the SIMD.Uint32x4 type to the existing MIRType_Int32x4 + SimdSign::Unsigned. Map SIMD.Int32x4 to MITType_Int32x4 + SimdSign::Signed. Add a 'SimdSign sign' argument to those inlineSimd...() functions that care. Some MIR instructions will get similar fields in the following commits. For now, abort inlining if unsigned vectors are actually encountered. These cases will be fixed in the following commits.
This commit is contained in:
Родитель
fa7b2a31b0
Коммит
d01dd37267
|
@ -39,21 +39,6 @@ using mozilla::NumberIsInt32;
|
|||
|
||||
static_assert(unsigned(SimdType::Count) == 12, "sync with TypedObjectConstants.h");
|
||||
|
||||
bool
|
||||
js::IsSignedIntSimdType(SimdType type)
|
||||
{
|
||||
switch (type) {
|
||||
case SimdType::Int32x4:
|
||||
return true;
|
||||
case SimdType::Float32x4:
|
||||
case SimdType::Bool32x4:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unknown SIMD type");
|
||||
}
|
||||
|
||||
PropertyName*
|
||||
js::SimdTypeToName(JSContext* cx, SimdType type)
|
||||
{
|
||||
|
@ -252,6 +237,10 @@ FLOAT32X4_FUNCTION_LIST(TDEFN)
|
|||
INT32X4_FUNCTION_LIST(TDEFN)
|
||||
#undef TDEFN
|
||||
|
||||
#define TDEFN(Name, Func, Operands) DEFN(Uint32x4, Name)
|
||||
UINT32X4_FUNCTION_LIST(TDEFN)
|
||||
#undef TDEFN
|
||||
|
||||
#define TDEFN(Name, Func, Operands) DEFN(Bool32x4, Name)
|
||||
BOOL32X4_FUNCTION_LIST(TDEFN)
|
||||
#undef TDEFN
|
||||
|
@ -317,7 +306,7 @@ const JSFunctionSpec Uint16x8Defn::Methods[] = {
|
|||
|
||||
const JSFunctionSpec Uint32x4Defn::Methods[] = {
|
||||
#define SIMD_UINT32X4_FUNCTION_ITEM(Name, Func, Operands) \
|
||||
JS_FN(#Name, js::simd_uint32x4_##Name, Operands, 0),
|
||||
JS_INLINABLE_FN(#Name, js::simd_uint32x4_##Name, Operands, 0, SimdUint32x4_##Name),
|
||||
UINT32X4_FUNCTION_LIST(SIMD_UINT32X4_FUNCTION_ITEM)
|
||||
#undef SIMD_UINT32X4_FUNCTION_ITEM
|
||||
JS_FS_END
|
||||
|
|
|
@ -799,6 +799,45 @@ enum class SimdType : uint8_t {
|
|||
Count
|
||||
};
|
||||
|
||||
// The integer SIMD types have a lot of operations that do the exact same thing
|
||||
// for signed and unsigned integer types. Sometimes it is simpler to treat
|
||||
// signed and unsigned integer SIMD types as the same type, using a SimdSign to
|
||||
// distinguish the few cases where there is a difference.
|
||||
enum class SimdSign {
|
||||
// Signedness is not applicable to this type. (i.e., Float or Bool).
|
||||
NotApplicable,
|
||||
// Treat as an unsigned integer with a range 0 .. 2^N-1.
|
||||
Unsigned,
|
||||
// Treat as a signed integer in two's complement encoding.
|
||||
Signed,
|
||||
};
|
||||
|
||||
// Get the signedness of a SIMD type.
|
||||
inline SimdSign
|
||||
GetSimdSign(SimdType t)
|
||||
{
|
||||
switch(t) {
|
||||
case SimdType::Int8x16:
|
||||
case SimdType::Int16x8:
|
||||
case SimdType::Int32x4:
|
||||
return SimdSign::Signed;
|
||||
|
||||
case SimdType::Uint8x16:
|
||||
case SimdType::Uint16x8:
|
||||
case SimdType::Uint32x4:
|
||||
return SimdSign::Unsigned;
|
||||
|
||||
default:
|
||||
return SimdSign::NotApplicable;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsSignedIntSimdType(SimdType type)
|
||||
{
|
||||
return GetSimdSign(type) == SimdSign::Signed;
|
||||
}
|
||||
|
||||
// Get the boolean SIMD type with the same shape as t.
|
||||
//
|
||||
// This is the result type of a comparison operation, and it can also be used to
|
||||
|
@ -1041,8 +1080,6 @@ struct Bool64x2 {
|
|||
}
|
||||
};
|
||||
|
||||
bool IsSignedIntSimdType(SimdType type);
|
||||
|
||||
PropertyName* SimdTypeToName(JSContext* cx, SimdType type);
|
||||
|
||||
template<typename V>
|
||||
|
|
|
@ -5563,6 +5563,7 @@ GetTemplateObjectForSimd(JSContext* cx, JSFunction* target, MutableHandleObject
|
|||
SimdType ctrlType;
|
||||
switch (jitInfo->inlinableNative) {
|
||||
case InlinableNative::SimdInt32x4: ctrlType = SimdType::Int32x4; break;
|
||||
case InlinableNative::SimdUint32x4: ctrlType = SimdType::Uint32x4; break;
|
||||
case InlinableNative::SimdFloat32x4: ctrlType = SimdType::Float32x4; break;
|
||||
case InlinableNative::SimdBool32x4: ctrlType = SimdType::Bool32x4; break;
|
||||
// This is not an inlinable SIMD operation.
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
_(ObjectCreate) \
|
||||
\
|
||||
_(SimdInt32x4) \
|
||||
_(SimdUint32x4) \
|
||||
_(SimdFloat32x4) \
|
||||
_(SimdBool32x4) \
|
||||
\
|
||||
|
|
|
@ -860,23 +860,27 @@ class IonBuilder
|
|||
InlineTypedObject* templateObj);
|
||||
MDefinition* convertToBooleanSimdLane(MDefinition* scalar);
|
||||
|
||||
InliningStatus inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType);
|
||||
InliningStatus inlineSimd(CallInfo& callInfo, JSFunction* target,
|
||||
MIRType simdType, SimdSign sign = SimdSign::NotApplicable);
|
||||
|
||||
template <typename T>
|
||||
InliningStatus inlineSimdBinary(CallInfo& callInfo, JSNative native,
|
||||
typename T::Operation op, MIRType mirType);
|
||||
InliningStatus inlineSimdComp(CallInfo& callInfo, JSNative native,
|
||||
MSimdBinaryComp::Operation op, MIRType compType);
|
||||
MSimdBinaryComp::Operation op,
|
||||
MIRType compType, SimdSign sign);
|
||||
InliningStatus inlineSimdUnary(CallInfo& callInfo, JSNative native,
|
||||
MSimdUnaryArith::Operation op, MIRType mirType);
|
||||
InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native, MIRType vecType);
|
||||
InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native,
|
||||
MIRType vecType, SimdSign sign);
|
||||
InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, MIRType mirType);
|
||||
InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, MIRType mirType);
|
||||
InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, MIRType type,
|
||||
unsigned numVectors, unsigned numLanes);
|
||||
InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, MIRType type);
|
||||
InliningStatus inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
|
||||
MIRType from, MIRType to);
|
||||
MIRType from, MIRType to,
|
||||
SimdSign sign = SimdSign::NotApplicable);
|
||||
InliningStatus inlineSimdSelect(CallInfo& callInfo, JSNative native, MIRType type);
|
||||
|
||||
bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements,
|
||||
|
|
|
@ -420,6 +420,7 @@ enum MIRType
|
|||
MIRType_ObjectGroup, // An ObjectGroup pointer.
|
||||
MIRType_Last = MIRType_ObjectGroup,
|
||||
MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT),
|
||||
// Representing both SIMD.Int32x4 and SIMD.Uint32x4.
|
||||
MIRType_Int32x4 = MIRType_Int32 | (2 << VECTOR_SCALE_SHIFT),
|
||||
MIRType_Bool32x4 = MIRType_Boolean | (2 << VECTOR_SCALE_SHIFT),
|
||||
MIRType_Doublex2 = MIRType_Double | (1 << VECTOR_SCALE_SHIFT)
|
||||
|
|
|
@ -203,7 +203,9 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
|
|||
|
||||
// SIMD natives.
|
||||
case InlinableNative::SimdInt32x4:
|
||||
return inlineSimd(callInfo, target, MIRType_Int32x4);
|
||||
return inlineSimd(callInfo, target, MIRType_Int32x4, SimdSign::Signed);
|
||||
case InlinableNative::SimdUint32x4:
|
||||
return inlineSimd(callInfo, target, MIRType_Int32x4, SimdSign::Unsigned);
|
||||
case InlinableNative::SimdFloat32x4:
|
||||
return inlineSimd(callInfo, target, MIRType_Float32x4);
|
||||
case InlinableNative::SimdBool32x4:
|
||||
|
@ -3057,8 +3059,10 @@ IonBuilder::inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* descr)
|
|||
}
|
||||
|
||||
// Main entry point for SIMD inlining.
|
||||
// When the controlling simdType is an integer type, sign indicates whether the lanes should
|
||||
// be treated as signed or unsigned integers.
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType)
|
||||
IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType, SimdSign sign)
|
||||
{
|
||||
if (!JitSupportsSimd()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::NoSimdJitSupport);
|
||||
|
@ -3069,7 +3073,10 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType)
|
|||
const JSJitInfo* jitInfo = target->jitInfo();
|
||||
MOZ_ASSERT(jitInfo && jitInfo->type() == JSJitInfo::InlinableNative);
|
||||
SimdOperation simdOp = SimdOperation(jitInfo->nativeOp);
|
||||
|
||||
MOZ_ASSERT(IsSimdType(simdType));
|
||||
MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(simdType),
|
||||
"Signedness must be specified for ints, and only for ints");
|
||||
|
||||
switch(simdOp) {
|
||||
case SimdOperation::Constructor:
|
||||
|
@ -3082,7 +3089,7 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType)
|
|||
case SimdOperation::Fn_splat:
|
||||
return inlineSimdSplat(callInfo, native, simdType);
|
||||
case SimdOperation::Fn_extractLane:
|
||||
return inlineSimdExtractLane(callInfo, native, simdType);
|
||||
return inlineSimdExtractLane(callInfo, native, simdType, sign);
|
||||
case SimdOperation::Fn_replaceLane:
|
||||
return inlineSimdReplaceLane(callInfo, native, simdType);
|
||||
case SimdOperation::Fn_select:
|
||||
|
@ -3149,9 +3156,8 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType)
|
|||
case SimdOperation::Fn_shiftLeftByScalar:
|
||||
return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::lsh, simdType);
|
||||
case SimdOperation::Fn_shiftRightByScalar:
|
||||
// TODO: select opcode from simdType signedness.
|
||||
MOZ_ASSERT(simdType == MIRType_Int32x4);
|
||||
return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::rsh, simdType);
|
||||
return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::rshForSign(sign),
|
||||
simdType);
|
||||
case SimdOperation::Fn_shiftRightArithmeticByScalar:
|
||||
return inlineSimdBinary<MSimdShift>(callInfo, native, MSimdShift::rsh, simdType);
|
||||
case SimdOperation::Fn_shiftRightLogicalByScalar:
|
||||
|
@ -3165,25 +3171,33 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType)
|
|||
|
||||
// Comparisons.
|
||||
case SimdOperation::Fn_lessThan:
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThan, simdType);
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThan,
|
||||
simdType, sign);
|
||||
case SimdOperation::Fn_lessThanOrEqual:
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThanOrEqual, simdType);
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThanOrEqual,
|
||||
simdType, sign);
|
||||
case SimdOperation::Fn_equal:
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::equal, simdType);
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::equal,
|
||||
simdType, sign);
|
||||
case SimdOperation::Fn_notEqual:
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::notEqual, simdType);
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::notEqual,
|
||||
simdType, sign);
|
||||
case SimdOperation::Fn_greaterThan:
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThan, simdType);
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThan,
|
||||
simdType, sign);
|
||||
case SimdOperation::Fn_greaterThanOrEqual:
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThanOrEqual, simdType);
|
||||
return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThanOrEqual,
|
||||
simdType, sign);
|
||||
|
||||
// Int <-> Float conversions.
|
||||
case SimdOperation::Fn_fromInt32x4:
|
||||
return inlineSimdConvert(callInfo, native, false, MIRType_Int32x4, simdType);
|
||||
return inlineSimdConvert(callInfo, native, false, MIRType_Int32x4,
|
||||
simdType, SimdSign::Signed);
|
||||
case SimdOperation::Fn_fromUint32x4:
|
||||
return InliningStatus_NotInlined;
|
||||
return inlineSimdConvert(callInfo, native, false, MIRType_Int32x4,
|
||||
simdType, SimdSign::Unsigned);
|
||||
case SimdOperation::Fn_fromFloat32x4:
|
||||
return inlineSimdConvert(callInfo, native, false, MIRType_Float32x4, simdType);
|
||||
return inlineSimdConvert(callInfo, native, false, MIRType_Float32x4, simdType, sign);
|
||||
|
||||
// Load/store.
|
||||
case SimdOperation::Fn_load:
|
||||
|
@ -3208,10 +3222,10 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType)
|
|||
case SimdOperation::Fn_fromInt16x8Bits:
|
||||
return InliningStatus_NotInlined;
|
||||
case SimdOperation::Fn_fromInt32x4Bits:
|
||||
case SimdOperation::Fn_fromUint32x4Bits:
|
||||
return inlineSimdConvert(callInfo, native, true, MIRType_Int32x4, simdType);
|
||||
case SimdOperation::Fn_fromUint8x16Bits:
|
||||
case SimdOperation::Fn_fromUint16x8Bits:
|
||||
case SimdOperation::Fn_fromUint32x4Bits:
|
||||
return InliningStatus_NotInlined;
|
||||
case SimdOperation::Fn_fromFloat32x4Bits:
|
||||
return inlineSimdConvert(callInfo, native, true, MIRType_Float32x4, simdType);
|
||||
|
@ -3391,12 +3405,16 @@ IonBuilder::inlineSimdBinary(CallInfo& callInfo, JSNative native, typename T::Op
|
|||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineSimdComp(CallInfo& callInfo, JSNative native, MSimdBinaryComp::Operation op,
|
||||
MIRType mirType)
|
||||
MIRType mirType, SimdSign sign)
|
||||
{
|
||||
InlineTypedObject* templateObj = nullptr;
|
||||
if (!canInlineSimd(callInfo, native, 2, &templateObj))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// TODO JSO: Implement unsigned integer comparisons.
|
||||
if (sign == SimdSign::Unsigned)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// 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
|
||||
|
@ -3440,7 +3458,8 @@ IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, MIRType mirType
|
|||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, MIRType vecType)
|
||||
IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native,
|
||||
MIRType vecType, SimdSign sign)
|
||||
{
|
||||
// extractLane() returns a scalar, so don't use canInlineSimd() which looks
|
||||
// for a template object.
|
||||
|
@ -3449,6 +3468,10 @@ IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, MIRType v
|
|||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
// TODO JSO: Implement unsigned integer lane values.
|
||||
if (sign == SimdSign::Unsigned)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MDefinition* arg = callInfo.getArg(1);
|
||||
if (!arg->isConstantValue() || arg->type() != MIRType_Int32)
|
||||
return InliningStatus_NotInlined;
|
||||
|
@ -3491,14 +3514,21 @@ IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, MIRType m
|
|||
return boxSimd(callInfo, ins, templateObj);
|
||||
}
|
||||
|
||||
// Inline a SIMD conversion or bitcast. When isCast==false, one of the types
|
||||
// must be floating point and the other integer. In this case, sign indicates if
|
||||
// the integer lanes should be treated as signed or unsigned integers.
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast,
|
||||
MIRType fromType, MIRType toType)
|
||||
MIRType fromType, MIRType toType, SimdSign sign)
|
||||
{
|
||||
InlineTypedObject* templateObj = nullptr;
|
||||
if (!canInlineSimd(callInfo, native, 1, &templateObj))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// TODO JSO: Implement unsigned integer conversions.
|
||||
if (sign == SimdSign::Unsigned)
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// See comment in inlineSimdBinary
|
||||
MInstruction* ins;
|
||||
if (isCast)
|
||||
|
|
|
@ -2367,6 +2367,11 @@ class MSimdShift
|
|||
return new(alloc) MSimdShift(left, right, op);
|
||||
}
|
||||
|
||||
// Get the relevant right shift operation given the signedness of a type.
|
||||
static Operation rshForSign(SimdSign sign) {
|
||||
return sign == SimdSign::Unsigned ? ursh : rsh;
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче