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:
Jakob Stoklund Olesen 2016-02-01 14:55:07 -08:00
Родитель fa7b2a31b0
Коммит d01dd37267
8 изменённых файлов: 109 добавлений и 41 удалений

Просмотреть файл

@ -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();
}