Bug 1160971 - Part 3: SIMD boolean vector support for JIT. r=bbouvier

Based on a patch by Sajjad Taheri!
This commit is contained in:
Sajjad Taheri 2015-12-22 14:17:13 -08:00
Родитель 22a7a7f807
Коммит 2ada54cf8d
32 изменённых файлов: 557 добавлений и 80 удалений

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

@ -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: