Bug 1112156 - Add MSimdUnbox to extract SIMD values from the TypedObjects. r=bbouvier

This commit is contained in:
Nicolas B. Pierron 2015-01-26 12:22:55 +01:00
parent 27d6f52ec9
commit 0cb9c4ed18
14 changed files with 278 additions and 1 deletions

View 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);
}

View File

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

View File

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

View File

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

View File

@ -18,6 +18,7 @@
_(Double) \
_(Float32) \
_(SimdBox) \
_(SimdUnbox) \
_(SimdSplatX4) \
_(Int32x4) \
_(Float32x4) \

View File

@ -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)
{

View File

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

View File

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

View File

@ -13,6 +13,7 @@ namespace jit {
#define MIR_OPCODE_LIST(_) \
_(Constant) \
_(SimdBox) \
_(SimdUnbox) \
_(SimdValueX4) \
_(SimdSplatX4) \
_(SimdConstant) \

View File

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

View File

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

View File

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

View File

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

View File

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