mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-05 16:46:26 +00:00
Bug 1112156 - Add MSimdUnbox to extract SIMD values from the TypedObjects. r=bbouvier
This commit is contained in:
parent
27d6f52ec9
commit
0cb9c4ed18
108
js/src/jit-test/tests/ion/simd-unbox.js
Normal file
108
js/src/jit-test/tests/ion/simd-unbox.js
Normal file
@ -0,0 +1,108 @@
|
||||
if (typeof SIMD === "undefined")
|
||||
quit();
|
||||
|
||||
setJitCompilerOption("baseline.warmup.trigger", 10);
|
||||
setJitCompilerOption("ion.warmup.trigger", 30);
|
||||
var max = 40, pivot = 35;
|
||||
|
||||
var i32x4 = SIMD.int32x4;
|
||||
var f32x4 = SIMD.float32x4;
|
||||
var i32x4Add = SIMD.int32x4.add;
|
||||
|
||||
var FakeSIMDType = function (o) { this.x = o.x; this.y = o.y; this.z = o.z; this.w = o.w; };
|
||||
if (this.hasOwnProperty("TypedObject")) {
|
||||
var TO = TypedObject;
|
||||
FakeSIMDType = new TO.StructType({ x: TO.int32, y: TO.int32, z: TO.int32, w: TO.int32 });
|
||||
}
|
||||
|
||||
|
||||
function simdunbox_bail_undef(i, lhs, rhs) {
|
||||
return i32x4Add(lhs, rhs);
|
||||
}
|
||||
|
||||
function simdunbox_bail_object(i, lhs, rhs) {
|
||||
return i32x4Add(lhs, rhs);
|
||||
}
|
||||
|
||||
function simdunbox_bail_typeobj(i, lhs, rhs) {
|
||||
return i32x4Add(lhs, rhs);
|
||||
}
|
||||
|
||||
function simdunbox_bail_badsimd(i, lhs, rhs) {
|
||||
return i32x4Add(lhs, rhs);
|
||||
}
|
||||
|
||||
var arr_undef = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
|
||||
var fail_undef = 0;
|
||||
var arr_object = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
|
||||
var fail_object = 0;
|
||||
var arr_typeobj = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
|
||||
var fail_typeobj = 0;
|
||||
var arr_badsimd = [ i32x4(0, 1, 1, 2), i32x4(1, 1, 2, 3) ];
|
||||
var fail_badsimd = 0;
|
||||
for (var i = 0; i < max; i++) {
|
||||
try {
|
||||
arr_undef[i + 2] = simdunbox_bail_undef(i, arr_undef[i], arr_undef[i + 1]);
|
||||
} catch (x) {
|
||||
arr_undef[i + 2] = arr_undef[i - 1];
|
||||
fail_undef++;
|
||||
}
|
||||
|
||||
try {
|
||||
arr_object[i + 2] = simdunbox_bail_object(i, arr_object[i], arr_object[i + 1]);
|
||||
} catch (x) {
|
||||
arr_object[i + 2] = arr_object[i - 1];
|
||||
fail_object++;
|
||||
}
|
||||
|
||||
try {
|
||||
arr_typeobj[i + 2] = simdunbox_bail_typeobj(i, arr_typeobj[i], arr_typeobj[i + 1]);
|
||||
} catch (x) {
|
||||
arr_typeobj[i + 2] = arr_typeobj[i - 1];
|
||||
fail_typeobj++;
|
||||
}
|
||||
|
||||
try {
|
||||
arr_badsimd[i + 2] = simdunbox_bail_badsimd(i, arr_badsimd[i], arr_badsimd[i + 1]);
|
||||
} catch (x) {
|
||||
arr_badsimd[i + 2] = arr_badsimd[i - 1];
|
||||
fail_badsimd++;
|
||||
}
|
||||
|
||||
if (i + 2 == pivot) {
|
||||
arr_undef[pivot] = undefined;
|
||||
arr_object[pivot] = { x: 0, y: 1, z: 2, w: 3 };
|
||||
arr_typeobj[pivot] = new FakeSIMDType({ x: 0, y: 1, z: 2, w: 3 });
|
||||
arr_badsimd[pivot] = f32x4(0, 1, 2, 3);
|
||||
}
|
||||
}
|
||||
|
||||
assertEq(fail_undef, 2);
|
||||
assertEq(fail_object, 2);
|
||||
assertEq(fail_typeobj, 2);
|
||||
assertEq(fail_badsimd, 2);
|
||||
|
||||
// Assert that all SIMD values are correct.
|
||||
function assertEqX4(real, expected, assertFunc) {
|
||||
if (typeof assertFunc === 'undefined')
|
||||
assertFunc = assertEq;
|
||||
|
||||
assertFunc(real.x, expected[0]);
|
||||
assertFunc(real.y, expected[1]);
|
||||
assertFunc(real.z, expected[2]);
|
||||
assertFunc(real.w, expected[3]);
|
||||
}
|
||||
|
||||
var fib = [0, 1];
|
||||
for (i = 0; i < max + 5; i++)
|
||||
fib[i+2] = (fib[i] + fib[i+1]) | 0;
|
||||
|
||||
for (i = 0; i < max; i++) {
|
||||
if (i == pivot)
|
||||
continue;
|
||||
var ref = fib.slice(i < pivot ? i : i - 3);
|
||||
assertEqX4(arr_undef[i], ref);
|
||||
assertEqX4(arr_object[i], ref);
|
||||
assertEqX4(arr_typeobj[i], ref);
|
||||
assertEqX4(arr_badsimd[i], ref);
|
||||
}
|
@ -4233,6 +4233,74 @@ CodeGenerator::visitSimdBox(LSimdBox *lir)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitSimdUnbox(LSimdUnbox *lir)
|
||||
{
|
||||
Register object = ToRegister(lir->input());
|
||||
FloatRegister simd = ToFloatRegister(lir->output());
|
||||
Register temp = ToRegister(lir->temp());
|
||||
Label bail;
|
||||
|
||||
// obj->type()
|
||||
masm.loadPtr(Address(object, JSObject::offsetOfType()), temp);
|
||||
|
||||
// Guard that the object has the same representation as the one produced for
|
||||
// SIMD value-type.
|
||||
Address clasp(temp, types::TypeObject::offsetOfClasp());
|
||||
static_assert(!SimdTypeDescr::Opaque, "SIMD objects are transparent");
|
||||
masm.branchPtr(Assembler::NotEqual, clasp, ImmPtr(&InlineTransparentTypedObject::class_),
|
||||
&bail);
|
||||
|
||||
// obj->type()->typeDescr()
|
||||
// The previous class pointer comparison implies that the addendumKind is
|
||||
// Addendum_TypeDescr.
|
||||
masm.loadPtr(Address(temp, types::TypeObject::offsetOfAddendum()), temp);
|
||||
|
||||
// Check for the /Kind/ reserved slot of the TypeDescr. This is an Int32
|
||||
// Value which is equivalent to the object class check.
|
||||
static_assert(JS_DESCR_SLOT_KIND < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
|
||||
Address typeDescrKind(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_KIND));
|
||||
masm.assertTestInt32(Assembler::Equal, typeDescrKind,
|
||||
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_KIND).isInt32())");
|
||||
masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrKind), Imm32(js::type::Simd), &bail);
|
||||
|
||||
// Convert the SIMD MIRType to a SimdTypeDescr::Type.
|
||||
js::SimdTypeDescr::Type type;
|
||||
switch (lir->mir()->type()) {
|
||||
case MIRType_Int32x4:
|
||||
type = js::SimdTypeDescr::TYPE_INT32;
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
type = js::SimdTypeDescr::TYPE_FLOAT32;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected SIMD Type.");
|
||||
}
|
||||
|
||||
// Check if the SimdTypeDescr /Type/ match the specialization of this
|
||||
// MSimdUnbox instruction.
|
||||
static_assert(JS_DESCR_SLOT_TYPE < NativeObject::MAX_FIXED_SLOTS, "Load from fixed slots");
|
||||
Address typeDescrType(temp, NativeObject::getFixedSlotOffset(JS_DESCR_SLOT_TYPE));
|
||||
masm.assertTestInt32(Assembler::Equal, typeDescrType,
|
||||
"MOZ_ASSERT(obj->type()->typeDescr()->getReservedSlot(JS_DESCR_SLOT_TYPE).isInt32())");
|
||||
masm.branch32(Assembler::NotEqual, masm.ToPayload(typeDescrType), Imm32(type), &bail);
|
||||
|
||||
// Load the value from the data of the InlineTypedObject.
|
||||
Address objectData(object, InlineTypedObject::offsetOfDataStart());
|
||||
switch (lir->mir()->type()) {
|
||||
case MIRType_Int32x4:
|
||||
masm.loadUnalignedInt32x4(objectData, simd);
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
masm.loadUnalignedFloat32x4(objectData, simd);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("The impossible happened!");
|
||||
}
|
||||
|
||||
bailoutFrom(&bail, lir->snapshot());
|
||||
}
|
||||
|
||||
typedef js::DeclEnvObject *(*NewDeclEnvObjectFn)(JSContext *, HandleFunction, gc::InitialHeap);
|
||||
static const VMFunction NewDeclEnvObjectInfo =
|
||||
FunctionInfo<NewDeclEnvObjectFn>(DeclEnvObject::createTemplateObject);
|
||||
|
@ -156,6 +156,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
void visitOutOfLineNewObject(OutOfLineNewObject *ool);
|
||||
void visitNewTypedObject(LNewTypedObject *lir);
|
||||
void visitSimdBox(LSimdBox *lir);
|
||||
void visitSimdUnbox(LSimdUnbox *lir);
|
||||
void visitNewDeclEnvObject(LNewDeclEnvObject *lir);
|
||||
void visitNewCallObject(LNewCallObject *lir);
|
||||
void visitNewSingletonCallObject(LNewSingletonCallObject *lir);
|
||||
|
@ -157,6 +157,26 @@ class LSimdBox : public LInstructionHelper<1, 1, 1>
|
||||
}
|
||||
};
|
||||
|
||||
class LSimdUnbox : public LInstructionHelper<1, 1, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(SimdUnbox)
|
||||
|
||||
LSimdUnbox(const LAllocation &obj, const LDefinition &temp)
|
||||
{
|
||||
setOperand(0, obj);
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const LDefinition *temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
|
||||
MSimdUnbox *mir() const {
|
||||
return mir_->toSimdUnbox();
|
||||
}
|
||||
};
|
||||
|
||||
// Constructs a SIMD value with 4 equal components (e.g. int32x4, float32x4).
|
||||
class LSimdSplatX4 : public LInstructionHelper<1, 1, 0>
|
||||
{
|
||||
|
@ -18,6 +18,7 @@
|
||||
_(Double) \
|
||||
_(Float32) \
|
||||
_(SimdBox) \
|
||||
_(SimdUnbox) \
|
||||
_(SimdSplatX4) \
|
||||
_(Int32x4) \
|
||||
_(Float32x4) \
|
||||
|
@ -3734,6 +3734,30 @@ LIRGenerator::visitSimdBox(MSimdBox *ins)
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitSimdUnbox(MSimdUnbox *ins)
|
||||
{
|
||||
MOZ_ASSERT(ins->input()->type() == MIRType_Object);
|
||||
MOZ_ASSERT(IsSimdType(ins->type()));
|
||||
LUse in = useRegister(ins->input());
|
||||
|
||||
BailoutKind kind;
|
||||
switch (ins->type()) {
|
||||
case MIRType_Int32x4:
|
||||
kind = Bailout_NonSimdInt32x4Input;
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
kind = Bailout_NonSimdFloat32x4Input;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected SIMD Type.");
|
||||
};
|
||||
|
||||
LSimdUnbox *lir = new(alloc()) LSimdUnbox(in, temp());
|
||||
assignSnapshot(lir, kind);
|
||||
define(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitSimdConstant(MSimdConstant *ins)
|
||||
{
|
||||
|
@ -266,6 +266,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitRecompileCheck(MRecompileCheck *ins);
|
||||
void visitMemoryBarrier(MMemoryBarrier *ins);
|
||||
void visitSimdBox(MSimdBox *ins);
|
||||
void visitSimdUnbox(MSimdUnbox *ins);
|
||||
void visitSimdExtractElement(MSimdExtractElement *ins);
|
||||
void visitSimdInsertElement(MSimdInsertElement *ins);
|
||||
void visitSimdSignMask(MSimdSignMask *ins);
|
||||
|
@ -2984,6 +2984,33 @@ class MSimdBox
|
||||
}
|
||||
};
|
||||
|
||||
class MSimdUnbox
|
||||
: public MUnaryInstruction,
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
protected:
|
||||
MSimdUnbox(MDefinition *op, MIRType type)
|
||||
: MUnaryInstruction(op)
|
||||
{
|
||||
MOZ_ASSERT(IsSimdType(type));
|
||||
setMovable();
|
||||
setResultType(type);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(SimdUnbox)
|
||||
ALLOW_CLONE(MSimdUnbox)
|
||||
|
||||
static MSimdUnbox *New(TempAllocator &alloc, MDefinition *op, MIRType type)
|
||||
{
|
||||
return new(alloc) MSimdUnbox(op, type);
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const MOZ_OVERRIDE {
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
// Creates a new derived type object. At runtime, this is just a call
|
||||
// to `BinaryBlock::createDerived()`. That is, the MIR itself does not
|
||||
// compile to particularly optimized code. However, using a distinct
|
||||
|
@ -13,6 +13,7 @@ namespace jit {
|
||||
#define MIR_OPCODE_LIST(_) \
|
||||
_(Constant) \
|
||||
_(SimdBox) \
|
||||
_(SimdUnbox) \
|
||||
_(SimdValueX4) \
|
||||
_(SimdSplatX4) \
|
||||
_(SimdConstant) \
|
||||
|
@ -1356,6 +1356,20 @@ MacroAssembler::assumeUnreachable(const char *output)
|
||||
breakpoint();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void
|
||||
MacroAssembler::assertTestInt32(Condition cond, const T &value, const char *output)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
Label ok;
|
||||
branchTestInt32(cond, value, &ok);
|
||||
assumeUnreachable(output);
|
||||
bind(&ok);
|
||||
#endif
|
||||
}
|
||||
|
||||
template void MacroAssembler::assertTestInt32(Condition, const Address &, const char *);
|
||||
|
||||
static void
|
||||
Printf0_(const char *output) {
|
||||
// Use stderr instead of stdout because this is only used for debug
|
||||
|
@ -976,6 +976,10 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
void link(JitCode *code);
|
||||
|
||||
void assumeUnreachable(const char *output);
|
||||
|
||||
template<typename T>
|
||||
void assertTestInt32(Condition cond, const T &value, const char *output);
|
||||
|
||||
void printf(const char *output);
|
||||
void printf(const char *output, Register value);
|
||||
|
||||
|
@ -38,6 +38,7 @@ class MacroAssemblerARM : public Assembler
|
||||
// address.
|
||||
Register secondScratchReg_;
|
||||
|
||||
public:
|
||||
// Higher level tag testing code.
|
||||
Operand ToPayload(Operand base) {
|
||||
return Operand(Register::FromCode(base.base()), base.disp());
|
||||
@ -45,6 +46,8 @@ class MacroAssemblerARM : public Assembler
|
||||
Address ToPayload(Address base) {
|
||||
return ToPayload(Operand(base)).toAddress();
|
||||
}
|
||||
|
||||
protected:
|
||||
Operand ToType(Operand base) {
|
||||
return Operand(Register::FromCode(base.base()), base.disp() + sizeof(void *));
|
||||
}
|
||||
|
@ -67,12 +67,13 @@ static_assert(1 << defaultShift == sizeof(jsval), "The defaultShift is wrong");
|
||||
|
||||
class MacroAssemblerMIPS : public Assembler
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
// higher level tag testing code
|
||||
Operand ToPayload(Operand base);
|
||||
Address ToPayload(Address base) {
|
||||
return ToPayload(Operand(base)).toAddress();
|
||||
}
|
||||
protected:
|
||||
Operand ToType(Operand base);
|
||||
Address ToType(Address base) {
|
||||
return ToType(Operand(base)).toAddress();
|
||||
|
@ -161,6 +161,10 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// X86/X64-common interface.
|
||||
/////////////////////////////////////////////////////////////////
|
||||
Address ToPayload(Address value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
void storeValue(ValueOperand val, Operand dest) {
|
||||
movq(val.valueReg(), dest);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user