зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1160971 - Part 3: SIMD boolean vector support for JIT. r=bbouvier
Based on a patch by Sajjad Taheri!
This commit is contained in:
Родитель
22a7a7f807
Коммит
2ada54cf8d
|
@ -121,6 +121,7 @@ js::ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out)
|
|||
|
||||
template bool js::ToSimdConstant<Int32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
|
||||
template bool js::ToSimdConstant<Float32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
|
||||
template bool js::ToSimdConstant<Bool32x4>(JSContext* cx, HandleValue v, jit::SimdConstant* out);
|
||||
|
||||
template<typename Elem>
|
||||
static Elem
|
||||
|
|
|
@ -391,13 +391,6 @@
|
|||
_(and) \
|
||||
_(or) \
|
||||
_(xor)
|
||||
#define COMP_COMMONX4_TO_INT32X4_SIMD_OP(_) \
|
||||
_(lessThan) \
|
||||
_(lessThanOrEqual) \
|
||||
_(equal) \
|
||||
_(notEqual) \
|
||||
_(greaterThan) \
|
||||
_(greaterThanOrEqual)
|
||||
#define COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(_) \
|
||||
_(lessThan) \
|
||||
_(lessThanOrEqual) \
|
||||
|
@ -428,7 +421,7 @@
|
|||
_(check)
|
||||
#define FOREACH_COMMONX4_SIMD_OP(_) \
|
||||
ION_COMMONX4_SIMD_OP(_) \
|
||||
COMP_COMMONX4_TO_INT32X4_SIMD_OP(_)
|
||||
COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(_)
|
||||
#define FORALL_SIMD_OP(_) \
|
||||
FOREACH_INT32X4_SIMD_OP(_) \
|
||||
FOREACH_FLOAT32X4_SIMD_OP(_) \
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
load(libdir + "simd.js");
|
||||
|
||||
setJitCompilerOption("ion.warmup.trigger", 50);
|
||||
|
||||
// Test constant folding into the Bool32x4 constructor.
|
||||
// Verify that we get the truthiness right, c.f. the ECMA ToBoolean() function.
|
||||
function f1() {
|
||||
var B = SIMD.Bool32x4;
|
||||
var S = SIMD.Bool32x4.splat;
|
||||
return [
|
||||
B(false, false, false, true),
|
||||
B(true),
|
||||
B(undefined, null, "", "x"),
|
||||
B({}, 0, 1, -0.0),
|
||||
B(NaN, -NaN, Symbol(), objectEmulatingUndefined()),
|
||||
|
||||
S(false),
|
||||
S(true),
|
||||
S(undefined),
|
||||
S(null),
|
||||
|
||||
S(""),
|
||||
S("x"),
|
||||
S(0),
|
||||
S(1),
|
||||
|
||||
S({}),
|
||||
S(-0.0),
|
||||
S(NaN),
|
||||
S(Symbol()),
|
||||
|
||||
S(objectEmulatingUndefined())
|
||||
];
|
||||
}
|
||||
|
||||
function f() {
|
||||
for (var i = 0; i < 100; i++) {
|
||||
var a = f1()
|
||||
assertEqX4(a[0], [false, false, false, true]);
|
||||
assertEqX4(a[1], [true, false, false, false]);
|
||||
assertEqX4(a[2], [false, false, false, true]);
|
||||
assertEqX4(a[3], [true, false, true, false]);
|
||||
assertEqX4(a[4], [false, false, true, false]);
|
||||
|
||||
// Splats.
|
||||
assertEqX4(a[5], [false, false, false, false]);
|
||||
assertEqX4(a[6], [true, true, true, true]);
|
||||
assertEqX4(a[7], [false, false, false, false]);
|
||||
assertEqX4(a[8], [false, false, false, false]);
|
||||
|
||||
assertEqX4(a[9], [false, false, false, false]);
|
||||
assertEqX4(a[10], [true, true, true, true]);
|
||||
assertEqX4(a[11], [false, false, false, false]);
|
||||
assertEqX4(a[12], [true, true, true, true]);
|
||||
|
||||
assertEqX4(a[13], [true, true, true, true]);
|
||||
assertEqX4(a[14], [false, false, false, false]);
|
||||
assertEqX4(a[15], [false, false, false, false]);
|
||||
assertEqX4(a[16], [true, true, true, true]);
|
||||
|
||||
assertEqX4(a[17], [false, false, false, false]);
|
||||
}
|
||||
}
|
||||
|
||||
f();
|
|
@ -1893,6 +1893,7 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
|
|||
case Bailout_NonObjectInput:
|
||||
case Bailout_NonStringInput:
|
||||
case Bailout_NonSymbolInput:
|
||||
case Bailout_NonSimdBool32x4Input:
|
||||
case Bailout_NonSimdInt32x4Input:
|
||||
case Bailout_NonSimdFloat32x4Input:
|
||||
case Bailout_NonSharedTypedArrayInput:
|
||||
|
|
|
@ -5700,25 +5700,37 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args,
|
|||
|
||||
if (JitSupportsSimd()) {
|
||||
#define ADD_INT32X4_SIMD_OP_NAME_(OP) || native == js::simd_int32x4_##OP
|
||||
#define ADD_BOOL32X4_SIMD_OP_NAME_(OP) || native == js::simd_bool32x4_##OP
|
||||
#define ADD_FLOAT32X4_SIMD_OP_NAME_(OP) || native == js::simd_float32x4_##OP
|
||||
if (false
|
||||
ION_COMMONX4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
|
||||
COMP_COMMONX4_TO_INT32X4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
|
||||
COMP_COMMONX4_TO_INT32X4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)
|
||||
FOREACH_INT32X4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_))
|
||||
{
|
||||
// Operations producing an int32x4.
|
||||
if (false
|
||||
ION_COMMONX4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
|
||||
FOREACH_INT32X4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_))
|
||||
{
|
||||
Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Int32x4>(cx));
|
||||
res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
|
||||
return !!res;
|
||||
}
|
||||
if (false
|
||||
FOREACH_FLOAT32X4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)
|
||||
ION_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
|
||||
{
|
||||
}
|
||||
// Operations producing a bool32x4.
|
||||
if (false
|
||||
BITWISE_COMMONX4_SIMD_OP(ADD_BOOL32X4_SIMD_OP_NAME_)
|
||||
COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_)
|
||||
COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
|
||||
{
|
||||
Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Bool32x4>(cx));
|
||||
res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
|
||||
return !!res;
|
||||
}
|
||||
// Operations producing a float32x4.
|
||||
if (false
|
||||
FOREACH_FLOAT32X4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)
|
||||
ION_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_))
|
||||
{
|
||||
Rooted<SimdTypeDescr*> descr(cx, cx->global()->getOrCreateSimdTypeDescr<Float32x4>(cx));
|
||||
res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr));
|
||||
return !!res;
|
||||
}
|
||||
}
|
||||
#undef ADD_BOOL32X4_SIMD_OP_NAME_
|
||||
#undef ADD_INT32X4_SIMD_OP_NAME_
|
||||
#undef ADD_FLOAT32X4_SIMD_OP_NAME_
|
||||
}
|
||||
|
|
|
@ -4741,6 +4741,7 @@ CodeGenerator::visitSimdBox(LSimdBox* lir)
|
|||
|
||||
Address objectData(object, InlineTypedObject::offsetOfDataStart());
|
||||
switch (type) {
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4:
|
||||
masm.storeUnalignedInt32x4(in, objectData);
|
||||
break;
|
||||
|
@ -4809,6 +4810,9 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox* lir)
|
|||
// Convert the SIMD MIRType to a SimdTypeDescr::Type.
|
||||
js::SimdTypeDescr::Type type;
|
||||
switch (lir->mir()->type()) {
|
||||
case MIRType_Bool32x4:
|
||||
type = js::SimdTypeDescr::Bool32x4;
|
||||
break;
|
||||
case MIRType_Int32x4:
|
||||
type = js::SimdTypeDescr::Int32x4;
|
||||
break;
|
||||
|
@ -4830,6 +4834,7 @@ CodeGenerator::visitSimdUnbox(LSimdUnbox* lir)
|
|||
// Load the value from the data of the InlineTypedObject.
|
||||
Address objectData(object, InlineTypedObject::offsetOfDataStart());
|
||||
switch (lir->mir()->type()) {
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4:
|
||||
masm.loadUnalignedInt32x4(objectData, simd);
|
||||
break;
|
||||
|
|
|
@ -20,6 +20,7 @@ MIRTypeToSimdTypeDescr(MIRType type)
|
|||
switch (type) {
|
||||
case MIRType_Float32x4: return SimdTypeDescr::Float32x4;
|
||||
case MIRType_Int32x4: return SimdTypeDescr::Int32x4;
|
||||
case MIRType_Bool32x4: return SimdTypeDescr::Bool32x4;
|
||||
default: break;
|
||||
}
|
||||
MOZ_CRASH("unexpected MIRType");
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
\
|
||||
_(SimdInt32x4) \
|
||||
_(SimdFloat32x4) \
|
||||
_(SimdBool32x4) \
|
||||
\
|
||||
_(TestBailout) \
|
||||
_(TestAssertFloat32) \
|
||||
|
|
|
@ -2471,6 +2471,7 @@ IsResumableMIRType(MIRType type)
|
|||
case MIRType_Value:
|
||||
case MIRType_Float32x4:
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
return true;
|
||||
|
||||
case MIRType_MagicHole:
|
||||
|
|
|
@ -11249,12 +11249,12 @@ IonBuilder::SimdTypeDescrToMIRType(SimdTypeDescr::Type type)
|
|||
switch (type) {
|
||||
case SimdTypeDescr::Int32x4: return MIRType_Int32x4;
|
||||
case SimdTypeDescr::Float32x4: return MIRType_Float32x4;
|
||||
case SimdTypeDescr::Bool32x4: return MIRType_Bool32x4;
|
||||
case SimdTypeDescr::Int8x16:
|
||||
case SimdTypeDescr::Int16x8:
|
||||
case SimdTypeDescr::Float64x2:
|
||||
case SimdTypeDescr::Bool8x16:
|
||||
case SimdTypeDescr::Bool16x8:
|
||||
case SimdTypeDescr::Bool32x4:
|
||||
case SimdTypeDescr::Bool64x2: return MIRType_Undefined;
|
||||
}
|
||||
MOZ_CRASH("unimplemented MIR type for a SimdTypeDescr::Type");
|
||||
|
|
|
@ -859,9 +859,11 @@ class IonBuilder
|
|||
unsigned numArgs, InlineTypedObject** templateObj);
|
||||
IonBuilder::InliningStatus boxSimd(CallInfo& callInfo, MInstruction* ins,
|
||||
InlineTypedObject* templateObj);
|
||||
MDefinition* convertToBooleanSimdLane(MDefinition* scalar);
|
||||
|
||||
InliningStatus inlineSimdInt32x4(CallInfo& callInfo, JSNative native);
|
||||
InliningStatus inlineSimdFloat32x4(CallInfo& callInfo, JSNative native);
|
||||
InliningStatus inlineSimdBool32x4(CallInfo& callInfo, JSNative native);
|
||||
|
||||
template <typename T>
|
||||
InliningStatus inlineBinarySimd(CallInfo& callInfo, JSNative native,
|
||||
|
@ -890,6 +892,8 @@ class IonBuilder
|
|||
InliningStatus inlineSimdStore(CallInfo& callInfo, JSNative native, SimdTypeDescr::Type type,
|
||||
unsigned numElems);
|
||||
|
||||
InliningStatus inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native);
|
||||
|
||||
// Utility intrinsics.
|
||||
InliningStatus inlineIsCallable(CallInfo& callInfo);
|
||||
InliningStatus inlineIsObject(CallInfo& callInfo);
|
||||
|
|
|
@ -102,6 +102,7 @@ enum BailoutKind
|
|||
Bailout_NonSymbolInput,
|
||||
|
||||
// SIMD Unbox expects a given type, bails out if it doesn't match.
|
||||
Bailout_NonSimdBool32x4Input,
|
||||
Bailout_NonSimdInt32x4Input,
|
||||
Bailout_NonSimdFloat32x4Input,
|
||||
|
||||
|
@ -213,6 +214,8 @@ BailoutKindString(BailoutKind kind)
|
|||
return "Bailout_NonStringInput";
|
||||
case Bailout_NonSymbolInput:
|
||||
return "Bailout_NonSymbolInput";
|
||||
case Bailout_NonSimdBool32x4Input:
|
||||
return "Bailout_NonSimdBool32x4Input";
|
||||
case Bailout_NonSimdInt32x4Input:
|
||||
return "Bailout_NonSimdInt32x4Input";
|
||||
case Bailout_NonSimdFloat32x4Input:
|
||||
|
@ -414,6 +417,7 @@ enum MIRType
|
|||
MIRType_Last = MIRType_ObjectGroup,
|
||||
MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT),
|
||||
MIRType_Int32x4 = MIRType_Int32 | (2 << VECTOR_SCALE_SHIFT),
|
||||
MIRType_Bool32x4 = MIRType_Boolean | (2 << VECTOR_SCALE_SHIFT),
|
||||
MIRType_Doublex2 = MIRType_Double | (1 << VECTOR_SCALE_SHIFT)
|
||||
};
|
||||
|
||||
|
@ -571,7 +575,7 @@ IsNullOrUndefined(MIRType type)
|
|||
static inline bool
|
||||
IsSimdType(MIRType type)
|
||||
{
|
||||
return type == MIRType_Int32x4 || type == MIRType_Float32x4;
|
||||
return type == MIRType_Int32x4 || type == MIRType_Float32x4 || type == MIRType_Bool32x4;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
|
@ -586,6 +590,12 @@ IsIntegerSimdType(MIRType type)
|
|||
return type == MIRType_Int32x4;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsBooleanSimdType(MIRType type)
|
||||
{
|
||||
return type == MIRType_Bool32x4;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsMagicType(MIRType type)
|
||||
{
|
||||
|
@ -655,7 +665,7 @@ ScalarTypeToLength(Scalar::Type type)
|
|||
}
|
||||
|
||||
// Get the type of the individual lanes in a SIMD type.
|
||||
// For example, Int32x4 -> Int32, FLoat32x4 -> Float32 etc.
|
||||
// For example, Int32x4 -> Int32, Float32x4 -> Float32 etc.
|
||||
static inline MIRType
|
||||
SimdTypeToLaneType(MIRType type)
|
||||
{
|
||||
|
@ -665,6 +675,19 @@ SimdTypeToLaneType(MIRType type)
|
|||
return MIRType((type >> ELEMENT_TYPE_SHIFT) & ELEMENT_TYPE_MASK);
|
||||
}
|
||||
|
||||
// Get the type expected when inserting a lane into a SIMD type.
|
||||
// This is the argument type expected by the MSimdValue constructors as well as
|
||||
// MSimdSplat and MSimdInsertElement.
|
||||
static inline MIRType
|
||||
SimdTypeToLaneArgumentType(MIRType type)
|
||||
{
|
||||
MIRType laneType = SimdTypeToLaneType(type);
|
||||
|
||||
// Boolean lanes should be pre-converted to an Int32 with the values 0 or -1.
|
||||
// All other lane types are inserted directly.
|
||||
return laneType == MIRType_Boolean ? MIRType_Int32 : laneType;
|
||||
}
|
||||
|
||||
// Indicates a lane in a SIMD register: X for the first lane, Y for the second,
|
||||
// Z for the third (if any), W for the fourth (if any).
|
||||
enum SimdLane {
|
||||
|
|
|
@ -568,6 +568,7 @@ class LDefinition
|
|||
return LDefinition::SLOTS;
|
||||
case MIRType_Pointer:
|
||||
return LDefinition::GENERAL;
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4:
|
||||
return LDefinition::INT32X4;
|
||||
case MIRType_Float32x4:
|
||||
|
|
|
@ -4017,6 +4017,9 @@ LIRGenerator::visitSimdUnbox(MSimdUnbox* ins)
|
|||
|
||||
BailoutKind kind;
|
||||
switch (ins->type()) {
|
||||
case MIRType_Bool32x4:
|
||||
kind = Bailout_NonSimdBool32x4Input;
|
||||
break;
|
||||
case MIRType_Int32x4:
|
||||
kind = Bailout_NonSimdInt32x4Input;
|
||||
break;
|
||||
|
@ -4037,12 +4040,17 @@ LIRGenerator::visitSimdConstant(MSimdConstant* ins)
|
|||
{
|
||||
MOZ_ASSERT(IsSimdType(ins->type()));
|
||||
|
||||
if (ins->type() == MIRType_Int32x4)
|
||||
switch (ins->type()) {
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4:
|
||||
define(new(alloc()) LInt32x4(), ins);
|
||||
else if (ins->type() == MIRType_Float32x4)
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
define(new(alloc()) LFloat32x4(), ins);
|
||||
else
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown SIMD kind when generating constant");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4083,15 +4091,25 @@ LIRGenerator::visitSimdExtractElement(MSimdExtractElement* ins)
|
|||
MOZ_ASSERT(IsSimdType(ins->input()->type()));
|
||||
MOZ_ASSERT(!IsSimdType(ins->type()));
|
||||
|
||||
if (ins->input()->type() == MIRType_Int32x4) {
|
||||
switch (ins->input()->type()) {
|
||||
case MIRType_Int32x4: {
|
||||
// Note: there could be int16x8 in the future, which doesn't use the
|
||||
// same instruction. We either need to pass the arity or create new LIns.
|
||||
LUse use = useRegisterAtStart(ins->input());
|
||||
define(new(alloc()) LSimdExtractElementI(use), ins);
|
||||
} else if (ins->input()->type() == MIRType_Float32x4) {
|
||||
break;
|
||||
}
|
||||
case MIRType_Float32x4: {
|
||||
LUse use = useRegisterAtStart(ins->input());
|
||||
define(new(alloc()) LSimdExtractElementF(use), ins);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
case MIRType_Bool32x4: {
|
||||
LUse use = useRegisterAtStart(ins->input());
|
||||
define(new(alloc()) LSimdExtractElementB(use), ins);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Unknown SIMD kind when extracting element");
|
||||
}
|
||||
}
|
||||
|
@ -4103,12 +4121,17 @@ LIRGenerator::visitSimdInsertElement(MSimdInsertElement* ins)
|
|||
|
||||
LUse vec = useRegisterAtStart(ins->vector());
|
||||
LUse val = useRegister(ins->value());
|
||||
if (ins->type() == MIRType_Int32x4)
|
||||
switch (ins->type()) {
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
defineReuseInput(new(alloc()) LSimdInsertElementI(vec, val), ins, 0);
|
||||
else if (ins->type() == MIRType_Float32x4)
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
defineReuseInput(new(alloc()) LSimdInsertElementF(vec, val), ins, 0);
|
||||
else
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unknown SIMD kind when generating constant");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4130,6 +4153,26 @@ LIRGenerator::visitSimdSignMask(MSimdSignMask* ins)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitSimdAllTrue(MSimdAllTrue* ins)
|
||||
{
|
||||
MDefinition* input = ins->input();
|
||||
MOZ_ASSERT(IsBooleanSimdType(input->type()));
|
||||
|
||||
LUse use = useRegisterAtStart(input);
|
||||
define(new(alloc()) LSimdAllTrue(use), ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitSimdAnyTrue(MSimdAnyTrue* ins)
|
||||
{
|
||||
MDefinition* input = ins->input();
|
||||
MOZ_ASSERT(IsBooleanSimdType(input->type()));
|
||||
|
||||
LUse use = useRegisterAtStart(input);
|
||||
define(new(alloc()) LSimdAnyTrue(use), ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitSimdSwizzle(MSimdSwizzle* ins)
|
||||
{
|
||||
|
@ -4208,7 +4251,7 @@ LIRGenerator::visitSimdUnaryArith(MSimdUnaryArith* ins)
|
|||
// Cannot be at start, as the ouput is used as a temporary to store values.
|
||||
LUse in = use(ins->input());
|
||||
|
||||
if (ins->type() == MIRType_Int32x4) {
|
||||
if (ins->type() == MIRType_Int32x4 || ins->type() == MIRType_Bool32x4) {
|
||||
LSimdUnaryArithIx4* lir = new(alloc()) LSimdUnaryArithIx4(in);
|
||||
define(lir, ins);
|
||||
} else if (ins->type() == MIRType_Float32x4) {
|
||||
|
@ -4224,7 +4267,7 @@ LIRGenerator::visitSimdBinaryComp(MSimdBinaryComp* ins)
|
|||
{
|
||||
MOZ_ASSERT(IsSimdType(ins->lhs()->type()));
|
||||
MOZ_ASSERT(IsSimdType(ins->rhs()->type()));
|
||||
MOZ_ASSERT(ins->type() == MIRType_Int32x4);
|
||||
MOZ_ASSERT(IsBooleanSimdType(ins->type()));
|
||||
|
||||
if (ShouldReorderCommutative(ins->lhs(), ins->rhs(), ins))
|
||||
ins->reverse();
|
||||
|
@ -4251,10 +4294,15 @@ LIRGenerator::visitSimdBinaryBitwise(MSimdBinaryBitwise* ins)
|
|||
MDefinition* rhs = ins->rhs();
|
||||
ReorderCommutative(&lhs, &rhs, ins);
|
||||
|
||||
if (ins->type() == MIRType_Int32x4 || ins->type() == MIRType_Float32x4) {
|
||||
switch (ins->type()) {
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Float32x4: {
|
||||
LSimdBinaryBitwiseX4* lir = new(alloc()) LSimdBinaryBitwiseX4;
|
||||
lowerForFPU(lir, ins, lhs, rhs);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Unknown SIMD kind when doing bitwise operations");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -296,6 +296,8 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
void visitSimdConstant(MSimdConstant* ins);
|
||||
void visitSimdConvert(MSimdConvert* ins);
|
||||
void visitSimdReinterpretCast(MSimdReinterpretCast* ins);
|
||||
void visitSimdAllTrue(MSimdAllTrue* ins);
|
||||
void visitSimdAnyTrue(MSimdAnyTrue* ins);
|
||||
void visitPhi(MPhi* ins);
|
||||
void visitBeta(MBeta* ins);
|
||||
void visitObjectState(MObjectState* ins);
|
||||
|
|
|
@ -206,6 +206,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
|
|||
return inlineSimdInt32x4(callInfo, target->native());
|
||||
case InlinableNative::SimdFloat32x4:
|
||||
return inlineSimdFloat32x4(callInfo, target->native());
|
||||
case InlinableNative::SimdBool32x4:
|
||||
return inlineSimdBool32x4(callInfo, target->native());
|
||||
|
||||
// Testing functions.
|
||||
case InlinableNative::TestBailout:
|
||||
|
@ -3048,6 +3050,38 @@ IonBuilder::inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* descr)
|
|||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineSimdBool32x4(CallInfo& callInfo, JSNative native)
|
||||
{
|
||||
#define INLINE_SIMD_BITWISE_(OP) \
|
||||
if (native == js::simd_bool32x4_##OP) \
|
||||
return inlineBinarySimd<MSimdBinaryBitwise>(callInfo, native, MSimdBinaryBitwise::OP##_, \
|
||||
SimdTypeDescr::Bool32x4);
|
||||
|
||||
BITWISE_COMMONX4_SIMD_OP(INLINE_SIMD_BITWISE_)
|
||||
#undef INLINE_SIMD_BITWISE_
|
||||
|
||||
if (native == js::simd_bool32x4_extractLane)
|
||||
return inlineSimdExtractLane(callInfo, native, SimdTypeDescr::Bool32x4);
|
||||
if (native == js::simd_bool32x4_replaceLane)
|
||||
return inlineSimdReplaceLane(callInfo, native, SimdTypeDescr::Bool32x4);
|
||||
|
||||
if (native == js::simd_bool32x4_not)
|
||||
return inlineUnarySimd(callInfo, native, MSimdUnaryArith::not_, SimdTypeDescr::Bool32x4);
|
||||
|
||||
if (native == js::simd_bool32x4_splat)
|
||||
return inlineSimdSplat(callInfo, native, SimdTypeDescr::Bool32x4);
|
||||
if (native == js::simd_bool32x4_check)
|
||||
return inlineSimdCheck(callInfo, native, SimdTypeDescr::Bool32x4);
|
||||
|
||||
if (native == js::simd_bool32x4_allTrue)
|
||||
return inlineSimdAnyAllTrue(callInfo, true, native);
|
||||
if (native == js::simd_bool32x4_anyTrue)
|
||||
return inlineSimdAnyAllTrue(callInfo, false, native);
|
||||
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineSimdInt32x4(CallInfo& callInfo, JSNative native)
|
||||
{
|
||||
|
@ -3078,7 +3112,7 @@ IonBuilder::inlineSimdInt32x4(CallInfo& callInfo, JSNative native)
|
|||
if (native == js::simd_int32x4_##OP) \
|
||||
return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Int32x4);
|
||||
|
||||
COMP_COMMONX4_TO_INT32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
|
||||
COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
|
||||
#undef INLINE_SIMD_COMPARISON_
|
||||
|
||||
if (native == js::simd_int32x4_extractLane)
|
||||
|
@ -3160,7 +3194,7 @@ IonBuilder::inlineSimdFloat32x4(CallInfo& callInfo, JSNative native)
|
|||
if (native == js::simd_float32x4_##OP) \
|
||||
return inlineCompSimd(callInfo, native, MSimdBinaryComp::OP, SimdTypeDescr::Float32x4);
|
||||
|
||||
COMP_COMMONX4_TO_INT32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
|
||||
COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(INLINE_SIMD_COMPARISON_)
|
||||
#undef INLINE_SIMD_COMPARISON_
|
||||
|
||||
if (native == js::simd_float32x4_extractLane)
|
||||
|
@ -3221,6 +3255,37 @@ IonBuilder::inlineSimdFloat32x4(CallInfo& callInfo, JSNative native)
|
|||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
// The representation of boolean SIMD vectors is the same as the corresponding
|
||||
// integer SIMD vectors with -1 lanes meaning true and 0 lanes meaning false.
|
||||
//
|
||||
// Functions that set the value of a boolean vector lane work by applying
|
||||
// ToBoolean on the input argument, so they accept any argument type, just like
|
||||
// the MNot and MTest instructions.
|
||||
//
|
||||
// Convert any scalar value into an appropriate SIMD lane value: An Int32 value
|
||||
// that is either 0 for false or -1 for true.
|
||||
MDefinition*
|
||||
IonBuilder::convertToBooleanSimdLane(MDefinition* scalar)
|
||||
{
|
||||
MSub* result;
|
||||
|
||||
if (scalar->type() == MIRType_Boolean) {
|
||||
// The input scalar is already a boolean with the int32 values 0 / 1.
|
||||
// Compute result = 0 - scalar.
|
||||
result = MSub::New(alloc(), constant(Int32Value(0)), scalar);
|
||||
} else {
|
||||
// For any other type, let MNot handle the conversion to boolean.
|
||||
// Compute result = !scalar - 1.
|
||||
MNot* inv = MNot::New(alloc(), scalar);
|
||||
current->add(inv);
|
||||
result = MSub::New(alloc(), inv, constant(Int32Value(1)));
|
||||
}
|
||||
|
||||
result->setInt32Specialization();
|
||||
current->add(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr)
|
||||
{
|
||||
|
@ -3246,10 +3311,12 @@ IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr)
|
|||
// When there are missing arguments, provide a default value
|
||||
// containing the coercion of 'undefined' to the right type.
|
||||
MConstant* defVal = nullptr;
|
||||
MIRType laneType = SimdTypeToLaneType(simdType);
|
||||
if (callInfo.argc() < SimdTypeToLength(simdType)) {
|
||||
MIRType laneType = SimdTypeToLaneType(simdType);
|
||||
if (laneType == MIRType_Int32) {
|
||||
defVal = constant(Int32Value(0));
|
||||
} else if (laneType == MIRType_Boolean) {
|
||||
defVal = constant(BooleanValue(false));
|
||||
} else {
|
||||
MOZ_ASSERT(IsFloatingPointType(laneType));
|
||||
defVal = constant(DoubleNaNValue());
|
||||
|
@ -3257,10 +3324,18 @@ IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr)
|
|||
}
|
||||
}
|
||||
|
||||
MDefinition* lane[4];
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
lane[i] = callInfo.getArgWithDefault(i, defVal);
|
||||
|
||||
// Convert boolean lanes into Int32 0 / -1.
|
||||
if (laneType == MIRType_Boolean) {
|
||||
for (unsigned i = 0; i < 4; i++)
|
||||
lane[i] = convertToBooleanSimdLane(lane[i]);
|
||||
}
|
||||
|
||||
MSimdValueX4* values =
|
||||
MSimdValueX4::New(alloc(), simdType,
|
||||
callInfo.getArgWithDefault(0, defVal), callInfo.getArgWithDefault(1, defVal),
|
||||
callInfo.getArgWithDefault(2, defVal), callInfo.getArgWithDefault(3, defVal));
|
||||
MSimdValueX4::New(alloc(), simdType, lane[0], lane[1], lane[2], lane[3]);
|
||||
current->add(values);
|
||||
|
||||
MSimdBox* obj = MSimdBox::New(alloc(), constraints(), values, inlineTypedObject,
|
||||
|
@ -3326,7 +3401,7 @@ IonBuilder::inlineCompSimd(CallInfo& callInfo, JSNative native, MSimdBinaryComp:
|
|||
SimdTypeDescr::Type compType)
|
||||
{
|
||||
InlineTypedObject* templateObj = nullptr;
|
||||
if (!checkInlineSimd(callInfo, native, SimdTypeDescr::Int32x4, 2, &templateObj))
|
||||
if (!checkInlineSimd(callInfo, native, SimdTypeDescr::Bool32x4, 2, &templateObj))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
// If the type of any of the arguments is neither a SIMD type, an Object
|
||||
|
@ -3362,7 +3437,13 @@ IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, SimdTypeDescr::
|
|||
|
||||
// See comment in inlineBinarySimd
|
||||
MIRType mirType = SimdTypeDescrToMIRType(type);
|
||||
MSimdSplatX4* ins = MSimdSplatX4::New(alloc(), callInfo.getArg(0), mirType);
|
||||
MDefinition* arg = callInfo.getArg(0);
|
||||
|
||||
// Convert to 0 / -1 before splatting a boolean lane.
|
||||
if (SimdTypeToLaneType(mirType) == MIRType_Boolean)
|
||||
arg = convertToBooleanSimdLane(arg);
|
||||
|
||||
MSimdSplatX4* ins = MSimdSplatX4::New(alloc(), arg, mirType);
|
||||
return boxSimd(callInfo, ins, templateObj);
|
||||
}
|
||||
|
||||
|
@ -3408,8 +3489,14 @@ IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, SimdTypeD
|
|||
|
||||
// See comment in inlineBinarySimd
|
||||
MIRType mirType = SimdTypeDescrToMIRType(type);
|
||||
MSimdInsertElement* ins = MSimdInsertElement::New(alloc(), callInfo.getArg(0),
|
||||
callInfo.getArg(2), mirType, SimdLane(lane));
|
||||
|
||||
// Convert to 0 / -1 before inserting a boolean lane.
|
||||
MDefinition* value = callInfo.getArg(2);
|
||||
if (SimdTypeToLaneType(mirType) == MIRType_Boolean)
|
||||
value = convertToBooleanSimdLane(value);
|
||||
|
||||
MSimdInsertElement* ins =
|
||||
MSimdInsertElement::New(alloc(), callInfo.getArg(0), value, mirType, SimdLane(lane));
|
||||
return boxSimd(callInfo, ins, templateObj);
|
||||
}
|
||||
|
||||
|
@ -3486,6 +3573,25 @@ IonBuilder::inlineSimdShuffle(CallInfo& callInfo, JSNative native, SimdTypeDescr
|
|||
return boxSimd(callInfo, ins, templateObj);
|
||||
}
|
||||
|
||||
IonBuilder::InliningStatus
|
||||
IonBuilder::inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native)
|
||||
{
|
||||
InlineTypedObject* templateObj = nullptr;
|
||||
if (!checkInlineSimd(callInfo, native, SimdTypeDescr::Bool32x4, 1, &templateObj))
|
||||
return InliningStatus_NotInlined;
|
||||
|
||||
MUnaryInstruction* ins;
|
||||
if (IsAllTrue)
|
||||
ins = MSimdAllTrue::New(alloc(), callInfo.getArg(0), MIRType_Bool32x4);
|
||||
else
|
||||
ins = MSimdAnyTrue::New(alloc(), callInfo.getArg(0), MIRType_Bool32x4);
|
||||
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
// Get the typed array element type corresponding to the lanes in a SIMD vector type.
|
||||
// This only applies to SIMD types that can be loaded and stored to a typed array.
|
||||
static Scalar::Type
|
||||
|
|
|
@ -906,7 +906,7 @@ MConstant::canProduceFloat32() const
|
|||
MDefinition*
|
||||
MSimdValueX4::foldsTo(TempAllocator& alloc)
|
||||
{
|
||||
DebugOnly<MIRType> laneType = SimdTypeToLaneType(type());
|
||||
DebugOnly<MIRType> laneType = SimdTypeToLaneArgumentType(type());
|
||||
bool allConstants = true;
|
||||
bool allSame = true;
|
||||
|
||||
|
@ -925,6 +925,13 @@ MSimdValueX4::foldsTo(TempAllocator& alloc)
|
|||
if (allConstants) {
|
||||
SimdConstant cst;
|
||||
switch (type()) {
|
||||
case MIRType_Bool32x4: {
|
||||
int32_t a[4];
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
a[i] = getOperand(i)->constantToBoolean() ? -1 : 0;
|
||||
cst = SimdConstant::CreateX4(a);
|
||||
break;
|
||||
}
|
||||
case MIRType_Int32x4: {
|
||||
int32_t a[4];
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
|
@ -952,7 +959,7 @@ MSimdValueX4::foldsTo(TempAllocator& alloc)
|
|||
MDefinition*
|
||||
MSimdSplatX4::foldsTo(TempAllocator& alloc)
|
||||
{
|
||||
DebugOnly<MIRType> laneType = SimdTypeToLaneType(type());
|
||||
DebugOnly<MIRType> laneType = SimdTypeToLaneArgumentType(type());
|
||||
MDefinition* op = getOperand(0);
|
||||
if (!op->isConstantValue())
|
||||
return this;
|
||||
|
@ -960,20 +967,19 @@ MSimdSplatX4::foldsTo(TempAllocator& alloc)
|
|||
|
||||
SimdConstant cst;
|
||||
switch (type()) {
|
||||
case MIRType_Bool32x4: {
|
||||
int32_t v = op->constantToBoolean() ? -1 : 0;
|
||||
cst = SimdConstant::SplatX4(v);
|
||||
break;
|
||||
}
|
||||
case MIRType_Int32x4: {
|
||||
int32_t a[4];
|
||||
int32_t v = getOperand(0)->constantValue().toInt32();
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
a[i] = v;
|
||||
cst = SimdConstant::CreateX4(a);
|
||||
int32_t v = op->constantValue().toInt32();
|
||||
cst = SimdConstant::SplatX4(v);
|
||||
break;
|
||||
}
|
||||
case MIRType_Float32x4: {
|
||||
float a[4];
|
||||
float v = getOperand(0)->constantValue().toNumber();
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
a[i] = v;
|
||||
cst = SimdConstant::CreateX4(a);
|
||||
float v = op->constantValue().toNumber();
|
||||
cst = SimdConstant::SplatX4(v);
|
||||
break;
|
||||
}
|
||||
default: MOZ_CRASH("unexpected type in MSimdSplatX4::foldsTo");
|
||||
|
|
|
@ -1401,7 +1401,7 @@ class MSimdValueX4
|
|||
static MSimdValueX4* NewAsmJS(TempAllocator& alloc, MIRType type, MDefinition* x,
|
||||
MDefinition* y, MDefinition* z, MDefinition* w)
|
||||
{
|
||||
mozilla::DebugOnly<MIRType> laneType = SimdTypeToLaneType(type);
|
||||
mozilla::DebugOnly<MIRType> laneType = SimdTypeToLaneArgumentType(type);
|
||||
MOZ_ASSERT(laneType == x->type());
|
||||
MOZ_ASSERT(laneType == y->type());
|
||||
MOZ_ASSERT(laneType == z->type());
|
||||
|
@ -1445,7 +1445,7 @@ class MSimdSplatX4
|
|||
|
||||
static MSimdSplatX4* NewAsmJS(TempAllocator& alloc, MDefinition* v, MIRType type)
|
||||
{
|
||||
MOZ_ASSERT(SimdTypeToLaneType(type) == v->type());
|
||||
MOZ_ASSERT(SimdTypeToLaneArgumentType(type) == v->type());
|
||||
return new(alloc) MSimdSplatX4(type, v);
|
||||
}
|
||||
|
||||
|
@ -1493,6 +1493,9 @@ class MSimdConstant
|
|||
bool congruentTo(const MDefinition* ins) const override {
|
||||
if (!ins->isSimdConstant())
|
||||
return false;
|
||||
// Bool32x4 and Int32x4 share the same underlying SimdConstant representation.
|
||||
if (type() != ins->type())
|
||||
return false;
|
||||
return value() == ins->toSimdConstant()->value();
|
||||
}
|
||||
|
||||
|
@ -1602,7 +1605,10 @@ class MSimdExtractElement
|
|||
MOZ_ASSERT(IsSimdType(vecType));
|
||||
MOZ_ASSERT(uint32_t(lane) < SimdTypeToLength(vecType));
|
||||
MOZ_ASSERT(!IsSimdType(laneType));
|
||||
MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType);
|
||||
// The resulting type should match the lane type.
|
||||
// Allow extracting boolean lanes directly into an Int32 (for asm.js).
|
||||
MOZ_ASSERT(SimdTypeToLaneType(vecType) == laneType ||
|
||||
(IsBooleanSimdType(vecType) && laneType == MIRType_Int32));
|
||||
|
||||
setMovable();
|
||||
specialization_ = vecType;
|
||||
|
@ -1665,7 +1671,7 @@ class MSimdInsertElement
|
|||
MIRType type, SimdLane lane)
|
||||
{
|
||||
MOZ_ASSERT(vec->type() == type);
|
||||
MOZ_ASSERT(SimdTypeToLaneType(type) == val->type());
|
||||
MOZ_ASSERT(SimdTypeToLaneArgumentType(type) == val->type());
|
||||
return new(alloc) MSimdInsertElement(vec, val, type, lane);
|
||||
}
|
||||
|
||||
|
@ -1752,6 +1758,83 @@ class MSimdSignMask
|
|||
ALLOW_CLONE(MSimdSignMask)
|
||||
};
|
||||
|
||||
// Returns true if all lanes are true.
|
||||
class MSimdAllTrue
|
||||
: public MUnaryInstruction,
|
||||
public SimdPolicy<0>::Data
|
||||
{
|
||||
protected:
|
||||
explicit MSimdAllTrue(MDefinition* obj, MIRType simdType, MIRType result)
|
||||
: MUnaryInstruction(obj)
|
||||
{
|
||||
MOZ_ASSERT(result == MIRType_Boolean || result == MIRType_Int32);
|
||||
setResultType(result);
|
||||
specialization_ = simdType;
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(SimdAllTrue)
|
||||
|
||||
static MSimdAllTrue* NewAsmJS(TempAllocator& alloc, MDefinition* obj)
|
||||
{
|
||||
MOZ_ASSERT(IsSimdType(obj->type()));
|
||||
return new(alloc) MSimdAllTrue(obj, obj->type(), MIRType_Int32);
|
||||
}
|
||||
|
||||
static MSimdAllTrue* New(TempAllocator& alloc, MDefinition* obj, MIRType type)
|
||||
{
|
||||
return new(alloc) MSimdAllTrue(obj, type, MIRType_Boolean);
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
bool congruentTo(const MDefinition* ins) const override {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
ALLOW_CLONE(MSimdAllTrue)
|
||||
};
|
||||
|
||||
// Returns true if any lane is true.
|
||||
class MSimdAnyTrue
|
||||
: public MUnaryInstruction,
|
||||
public SimdPolicy<0>::Data
|
||||
{
|
||||
protected:
|
||||
explicit MSimdAnyTrue(MDefinition* obj, MIRType simdType, MIRType result)
|
||||
: MUnaryInstruction(obj)
|
||||
{
|
||||
MOZ_ASSERT(result == MIRType_Boolean || result == MIRType_Int32);
|
||||
setResultType(result);
|
||||
specialization_ = simdType;
|
||||
setMovable();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(SimdAnyTrue)
|
||||
|
||||
static MSimdAnyTrue* NewAsmJS(TempAllocator& alloc, MDefinition* obj)
|
||||
{
|
||||
MOZ_ASSERT(IsSimdType(obj->type()));
|
||||
return new(alloc) MSimdAnyTrue(obj, obj->type(), MIRType_Int32);
|
||||
}
|
||||
|
||||
static MSimdAnyTrue* New(TempAllocator& alloc, MDefinition* obj, MIRType type)
|
||||
{
|
||||
return new(alloc) MSimdAnyTrue(obj, type, MIRType_Boolean);
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
bool congruentTo(const MDefinition* ins) const override {
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
|
||||
ALLOW_CLONE(MSimdAnyTrue)
|
||||
};
|
||||
|
||||
// Base for the MSimdSwizzle and MSimdShuffle classes.
|
||||
class MSimdShuffleBase
|
||||
{
|
||||
|
@ -2049,14 +2132,14 @@ class MSimdBinaryComp
|
|||
public:
|
||||
enum Operation {
|
||||
#define NAME_(x) x,
|
||||
COMP_COMMONX4_TO_INT32X4_SIMD_OP(NAME_)
|
||||
COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(NAME_)
|
||||
#undef NAME_
|
||||
};
|
||||
|
||||
static const char* OperationName(Operation op) {
|
||||
switch (op) {
|
||||
#define NAME_(x) case x: return #x;
|
||||
COMP_COMMONX4_TO_INT32X4_SIMD_OP(NAME_)
|
||||
COMP_COMMONX4_TO_BOOL32X4_SIMD_OP(NAME_)
|
||||
#undef NAME_
|
||||
}
|
||||
MOZ_CRASH("unexpected operation");
|
||||
|
@ -2068,7 +2151,7 @@ class MSimdBinaryComp
|
|||
MSimdBinaryComp(MDefinition* left, MDefinition* right, Operation op, MIRType opType)
|
||||
: MBinaryInstruction(left, right), operation_(op)
|
||||
{
|
||||
setResultType(MIRType_Int32x4);
|
||||
setResultType(MIRType_Bool32x4);
|
||||
specialization_ = opType;
|
||||
setMovable();
|
||||
if (op == equal || op == notEqual)
|
||||
|
@ -2344,7 +2427,7 @@ class MSimdSelect
|
|||
static MSimdSelect* NewAsmJS(TempAllocator& alloc, MDefinition* mask, MDefinition* lhs,
|
||||
MDefinition* rhs, MIRType t, bool isElementWise)
|
||||
{
|
||||
MOZ_ASSERT(mask->type() == MIRType_Int32x4);
|
||||
MOZ_ASSERT(mask->type() == (isElementWise ? MIRType_Bool32x4 : t));
|
||||
MOZ_ASSERT(lhs->type() == rhs->type());
|
||||
MOZ_ASSERT(lhs->type() == t);
|
||||
return new(alloc) MSimdSelect(mask, lhs, rhs, t, isElementWise);
|
||||
|
|
|
@ -31,6 +31,8 @@ namespace jit {
|
|||
_(SimdBinaryBitwise) \
|
||||
_(SimdShift) \
|
||||
_(SimdSelect) \
|
||||
_(SimdAllTrue) \
|
||||
_(SimdAnyTrue) \
|
||||
_(CloneLiteral) \
|
||||
_(Parameter) \
|
||||
_(Callee) \
|
||||
|
|
|
@ -1339,6 +1339,11 @@ RSimdBox::recover(JSContext* cx, SnapshotIterator& iter) const
|
|||
MOZ_ASSERT(iter.allocationReadable(a));
|
||||
const FloatRegisters::RegisterContent* raw = iter.floatAllocationPointer(a);
|
||||
switch (SimdTypeDescr::Type(type_)) {
|
||||
case SimdTypeDescr::Bool32x4:
|
||||
MOZ_ASSERT_IF(a.mode() == RValueAllocation::ANY_FLOAT_REG,
|
||||
a.fpuReg().isSimd128());
|
||||
resultObject = js::CreateSimd<Bool32x4>(cx, (const Bool32x4::Elem*) raw);
|
||||
break;
|
||||
case SimdTypeDescr::Int32x4:
|
||||
MOZ_ASSERT_IF(a.mode() == RValueAllocation::ANY_FLOAT_REG,
|
||||
a.fpuReg().isSimd128());
|
||||
|
@ -1364,9 +1369,6 @@ RSimdBox::recover(JSContext* cx, SnapshotIterator& iter) const
|
|||
case SimdTypeDescr::Bool16x8:
|
||||
MOZ_CRASH("NYI, RSimdBox of Bool16x8");
|
||||
break;
|
||||
case SimdTypeDescr::Bool32x4:
|
||||
MOZ_CRASH("NYI, RSimdBox of Bool32x4");
|
||||
break;
|
||||
case SimdTypeDescr::Bool64x2:
|
||||
MOZ_CRASH("NYI, RSimdBox of Bool64x2");
|
||||
break;
|
||||
|
|
|
@ -570,6 +570,15 @@ SimdScalarPolicy<Op>::staticAdjustInputs(TempAllocator& alloc, MInstruction* ins
|
|||
MIRType laneType = SimdTypeToLaneType(ins->type());
|
||||
|
||||
MDefinition* in = ins->getOperand(Op);
|
||||
|
||||
// A vector with boolean lanes requires Int32 inputs that have already been
|
||||
// converted to 0/-1.
|
||||
// We can't insert a MIRType_Boolean lane directly - it requires conversion.
|
||||
if (laneType == MIRType_Boolean) {
|
||||
MOZ_ASSERT(in->type() == MIRType_Int32, "Boolean SIMD vector requires Int32 lanes.");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in->type() == laneType)
|
||||
return true;
|
||||
|
||||
|
@ -857,8 +866,8 @@ SimdSelectPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
|
|||
{
|
||||
MIRType specialization = ins->typePolicySpecialization();
|
||||
|
||||
// First input is the mask, which has to be an int32x4 (for now).
|
||||
if (!MaybeSimdUnbox(alloc, ins, MIRType_Int32x4, 0))
|
||||
// First input is the mask, which has to be a bool32x4.
|
||||
if (!MaybeSimdUnbox(alloc, ins, MIRType_Bool32x4, 0))
|
||||
return false;
|
||||
|
||||
// Next inputs are the two vectors of a particular type.
|
||||
|
|
|
@ -458,6 +458,7 @@ CodeGeneratorShared::encodeAllocation(LSnapshot* snapshot, MDefinition* mir,
|
|||
break;
|
||||
}
|
||||
case MIRType_Float32:
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Float32x4:
|
||||
{
|
||||
|
|
|
@ -250,6 +250,16 @@ class LSimdExtractElementBase : public LInstructionHelper<1, 1, 0>
|
|||
}
|
||||
};
|
||||
|
||||
// Extracts an element from a given SIMD bool32x4 lane.
|
||||
class LSimdExtractElementB : public LSimdExtractElementBase
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(SimdExtractElementB);
|
||||
explicit LSimdExtractElementB(const LAllocation& base)
|
||||
: LSimdExtractElementBase(base)
|
||||
{}
|
||||
};
|
||||
|
||||
// Extracts an element from a given SIMD int32x4 lane.
|
||||
class LSimdExtractElementI : public LSimdExtractElementBase
|
||||
{
|
||||
|
@ -259,6 +269,7 @@ class LSimdExtractElementI : public LSimdExtractElementBase
|
|||
: LSimdExtractElementBase(base)
|
||||
{}
|
||||
};
|
||||
|
||||
// Extracts an element from a given SIMD float32x4 lane.
|
||||
class LSimdExtractElementF : public LSimdExtractElementBase
|
||||
{
|
||||
|
@ -293,7 +304,8 @@ class LSimdInsertElementBase : public LInstructionHelper<1, 2, 0>
|
|||
}
|
||||
};
|
||||
|
||||
// Replace an element from a given SIMD int32x4 lane with a given value.
|
||||
// Replace an element from a given SIMD integer or boolean lane with a given value.
|
||||
// The value inserted into a boolean lane should be 0 or -1.
|
||||
class LSimdInsertElementI : public LSimdInsertElementBase
|
||||
{
|
||||
public:
|
||||
|
@ -606,6 +618,37 @@ class LSimdSelect : public LInstructionHelper<1, 3, 1>
|
|||
}
|
||||
};
|
||||
|
||||
class LSimdAnyTrue : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(SimdAnyTrue)
|
||||
explicit LSimdAnyTrue(const LAllocation& input) {
|
||||
setOperand(0, input);
|
||||
}
|
||||
const LAllocation* vector() {
|
||||
return getOperand(0);
|
||||
}
|
||||
MSimdAnyTrue* mir() const {
|
||||
return mir_->toSimdAnyTrue();
|
||||
}
|
||||
};
|
||||
|
||||
class LSimdAllTrue : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(SimdAllTrue)
|
||||
explicit LSimdAllTrue(const LAllocation& input) {
|
||||
setOperand(0, input);
|
||||
}
|
||||
const LAllocation* vector() {
|
||||
return getOperand(0);
|
||||
}
|
||||
MSimdAllTrue* mir() const {
|
||||
return mir_->toSimdAllTrue();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Constant 32-bit integer.
|
||||
class LInteger : public LInstructionHelper<1, 0, 0>
|
||||
{
|
||||
|
@ -693,7 +736,7 @@ class LFloat32 : public LInstructionHelper<1, 0, 0>
|
|||
}
|
||||
};
|
||||
|
||||
// Constant SIMD int32x4
|
||||
// Constant SIMD int32x4. Also used for bool32x4.
|
||||
class LInt32x4 : public LInstructionHelper<1, 0, 0>
|
||||
{
|
||||
public:
|
||||
|
@ -703,7 +746,7 @@ class LInt32x4 : public LInstructionHelper<1, 0, 0>
|
|||
const SimdConstant& getValue() const { return mir_->toSimdConstant()->value(); }
|
||||
};
|
||||
|
||||
// Constant SIMD float32x4
|
||||
// Constant SIMD float32x4.
|
||||
class LFloat32x4 : public LInstructionHelper<1, 0, 0>
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -22,8 +22,11 @@
|
|||
_(SimdSplatX4) \
|
||||
_(Int32x4) \
|
||||
_(Float32x4) \
|
||||
_(SimdAllTrue) \
|
||||
_(SimdAnyTrue) \
|
||||
_(SimdReinterpretCast) \
|
||||
_(SimdExtractElementI) \
|
||||
_(SimdExtractElementB) \
|
||||
_(SimdExtractElementF) \
|
||||
_(SimdInsertElementI) \
|
||||
_(SimdInsertElementF) \
|
||||
|
|
|
@ -159,6 +159,7 @@ LIRGeneratorShared::defineReturn(LInstruction* lir, MDefinition* mir)
|
|||
case MIRType_Double:
|
||||
lir->setDef(0, LDefinition(vreg, LDefinition::DOUBLE, LFloatReg(ReturnDoubleReg)));
|
||||
break;
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4:
|
||||
lir->setDef(0, LDefinition(vreg, LDefinition::INT32X4, LFloatReg(ReturnSimd128Reg)));
|
||||
break;
|
||||
|
|
|
@ -54,6 +54,7 @@ ABIArgGenerator::next(MIRType type)
|
|||
case MIRType_Double:
|
||||
current_ = ABIArg(FloatArgRegs[regIndex_++]);
|
||||
break;
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Float32x4:
|
||||
// On Win64, >64 bit args need to be passed by reference, but asm.js
|
||||
|
@ -88,6 +89,7 @@ ABIArgGenerator::next(MIRType type)
|
|||
else
|
||||
current_ = ABIArg(FloatArgRegs[floatRegIndex_++]);
|
||||
break;
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Float32x4:
|
||||
if (floatRegIndex_ == NumFloatArgRegs) {
|
||||
|
|
|
@ -751,6 +751,7 @@ CodeGeneratorX64::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins)
|
|||
// Aligned access: code is aligned on PageSize + there is padding
|
||||
// before the global data section.
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
label = masm.loadRipRelativeInt32x4(ToFloatRegister(ins->output()));
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
|
@ -785,6 +786,7 @@ CodeGeneratorX64::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins)
|
|||
// Aligned access: code is aligned on PageSize + there is padding
|
||||
// before the global data section.
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
label = masm.storeRipRelativeInt32x4(ToFloatRegister(ins->value()));
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
|
|
|
@ -287,6 +287,7 @@ CodeGeneratorX86Shared::visitAsmJSPassStackArg(LAsmJSPassStackArg* ins)
|
|||
// StackPointer is SIMD-aligned and ABIArgGenerator guarantees
|
||||
// stack offsets are SIMD-aligned.
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
masm.storeAlignedInt32x4(ToFloatRegister(ins->arg()), dst);
|
||||
return;
|
||||
case MIRType_Float32x4:
|
||||
|
@ -2308,7 +2309,7 @@ CodeGeneratorX86Shared::visitOutOfLineSimdFloatToIntCheck(OutOfLineSimdFloatToIn
|
|||
void
|
||||
CodeGeneratorX86Shared::visitSimdValueInt32x4(LSimdValueInt32x4* ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->mir()->type() == MIRType_Int32x4);
|
||||
MOZ_ASSERT(ins->mir()->type() == MIRType_Int32x4 || ins->mir()->type() == MIRType_Bool32x4);
|
||||
|
||||
FloatRegister output = ToFloatRegister(ins->output());
|
||||
if (AssemblerX86Shared::HasSSE41()) {
|
||||
|
@ -2359,7 +2360,8 @@ CodeGeneratorX86Shared::visitSimdSplatX4(LSimdSplatX4* ins)
|
|||
JS_STATIC_ASSERT(sizeof(float) == sizeof(int32_t));
|
||||
|
||||
switch (mir->type()) {
|
||||
case MIRType_Int32x4: {
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4: {
|
||||
Register r = ToRegister(ins->getOperand(0));
|
||||
masm.vmovd(r, output);
|
||||
masm.vpshufd(0, output, output);
|
||||
|
@ -2397,6 +2399,28 @@ CodeGeneratorX86Shared::visitSimdReinterpretCast(LSimdReinterpretCast* ins)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorX86Shared::visitSimdExtractElementB(LSimdExtractElementB* ins)
|
||||
{
|
||||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
SimdLane lane = ins->lane();
|
||||
if (lane == LaneX) {
|
||||
// The value we want to extract is in the low double-word
|
||||
masm.moveLowInt32(input, output);
|
||||
} else if (AssemblerX86Shared::HasSSE41()) {
|
||||
masm.vpextrd(lane, input, output);
|
||||
} else {
|
||||
uint32_t mask = MacroAssembler::ComputeShuffleMask(lane);
|
||||
masm.shuffleInt32(mask, input, ScratchSimd128Reg);
|
||||
masm.moveLowInt32(ScratchSimd128Reg, output);
|
||||
}
|
||||
|
||||
// We need to generate a 0/1 value. We have 0/-1.
|
||||
masm.and32(Imm32(1), output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorX86Shared::visitSimdExtractElementI(LSimdExtractElementI* ins)
|
||||
{
|
||||
|
@ -2508,6 +2532,28 @@ CodeGeneratorX86Shared::visitSimdSignMaskX4(LSimdSignMaskX4* ins)
|
|||
masm.vmovmskps(input, output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorX86Shared::visitSimdAllTrue(LSimdAllTrue* ins)
|
||||
{
|
||||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
masm.vmovmskps(input, output);
|
||||
masm.cmp32(output, Imm32(0xf));
|
||||
masm.emitSet(Assembler::Zero, output);
|
||||
}
|
||||
|
||||
void
|
||||
CodeGeneratorX86Shared::visitSimdAnyTrue(LSimdAnyTrue* ins)
|
||||
{
|
||||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
masm.vmovmskps(input, output);
|
||||
masm.cmp32(output, Imm32(0x0));
|
||||
masm.emitSet(Assembler::NonZero, output);
|
||||
}
|
||||
|
||||
template <class T, class Reg> void
|
||||
CodeGeneratorX86Shared::visitSimdGeneralShuffle(LSimdGeneralShuffleBase* ins, Reg tempRegister)
|
||||
{
|
||||
|
|
|
@ -262,6 +262,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
|
|||
void visitInt32x4ToFloat32x4(LInt32x4ToFloat32x4* ins);
|
||||
void visitFloat32x4ToInt32x4(LFloat32x4ToInt32x4* ins);
|
||||
void visitSimdReinterpretCast(LSimdReinterpretCast* lir);
|
||||
void visitSimdExtractElementB(LSimdExtractElementB* lir);
|
||||
void visitSimdExtractElementI(LSimdExtractElementI* lir);
|
||||
void visitSimdExtractElementF(LSimdExtractElementF* lir);
|
||||
void visitSimdInsertElementI(LSimdInsertElementI* lir);
|
||||
|
@ -279,6 +280,8 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
|
|||
void visitSimdBinaryBitwiseX4(LSimdBinaryBitwiseX4* lir);
|
||||
void visitSimdShift(LSimdShift* lir);
|
||||
void visitSimdSelect(LSimdSelect* ins);
|
||||
void visitSimdAllTrue(LSimdAllTrue* ins);
|
||||
void visitSimdAnyTrue(LSimdAnyTrue* ins);
|
||||
|
||||
template <class T, class Reg> void visitSimdGeneralShuffle(LSimdGeneralShuffleBase* lir, Reg temp);
|
||||
void visitSimdGeneralShuffleI(LSimdGeneralShuffleI* lir);
|
||||
|
|
|
@ -639,6 +639,7 @@ LIRGeneratorX86Shared::visitSimdSplatX4(MSimdSplatX4* ins)
|
|||
|
||||
switch (ins->type()) {
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
define(lir, ins);
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
|
@ -656,7 +657,8 @@ LIRGeneratorX86Shared::visitSimdSplatX4(MSimdSplatX4* ins)
|
|||
void
|
||||
LIRGeneratorX86Shared::visitSimdValueX4(MSimdValueX4* ins)
|
||||
{
|
||||
if (ins->type() == MIRType_Float32x4) {
|
||||
switch (ins->type()) {
|
||||
case MIRType_Float32x4: {
|
||||
// Ideally, x would be used at start and reused for the output, however
|
||||
// register allocation currently doesn't permit us to tie together two
|
||||
// virtual registers with different types.
|
||||
|
@ -666,14 +668,19 @@ LIRGeneratorX86Shared::visitSimdValueX4(MSimdValueX4* ins)
|
|||
LAllocation w = useRegister(ins->getOperand(3));
|
||||
LDefinition t = temp(LDefinition::FLOAT32X4);
|
||||
define(new (alloc()) LSimdValueFloat32x4(x, y, z, w, t), ins);
|
||||
} else {
|
||||
MOZ_ASSERT(ins->type() == MIRType_Int32x4);
|
||||
|
||||
break;
|
||||
}
|
||||
case MIRType_Bool32x4:
|
||||
case MIRType_Int32x4: {
|
||||
// No defineReuseInput => useAtStart for everyone.
|
||||
LAllocation x = useRegisterAtStart(ins->getOperand(0));
|
||||
LAllocation y = useRegisterAtStart(ins->getOperand(1));
|
||||
LAllocation z = useRegisterAtStart(ins->getOperand(2));
|
||||
LAllocation w = useRegisterAtStart(ins->getOperand(3));
|
||||
define(new(alloc()) LSimdValueInt32x4(x, y, z, w), ins);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Unknown SIMD kind");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ ABIArgGenerator::next(MIRType type)
|
|||
break;
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Float32x4:
|
||||
case MIRType_Bool32x4:
|
||||
// SIMD values aren't passed in or out of C++, so we can make up
|
||||
// whatever internal ABI we like. visitAsmJSPassArg assumes
|
||||
// SimdMemoryAlignment.
|
||||
|
|
|
@ -792,6 +792,7 @@ CodeGeneratorX86::visitAsmJSLoadGlobalVar(LAsmJSLoadGlobalVar* ins)
|
|||
// Aligned access: code is aligned on PageSize + there is padding
|
||||
// before the global data section.
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
label = masm.vmovdqaWithPatch(PatchedAbsoluteAddress(), ToFloatRegister(ins->output()));
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
|
@ -825,6 +826,7 @@ CodeGeneratorX86::visitAsmJSStoreGlobalVar(LAsmJSStoreGlobalVar* ins)
|
|||
// Aligned access: code is aligned on PageSize + there is padding
|
||||
// before the global data section.
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
label = masm.vmovdqaWithPatch(ToFloatRegister(ins->value()), PatchedAbsoluteAddress());
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
|
|
Загрузка…
Ссылка в новой задаче