Bug 1060789: OdinMonkey SIMD: Add support for splat; r=luke

This commit is contained in:
Benjamin Bouvier 2014-09-03 13:35:12 +02:00
parent 7823b27296
commit 1cadd3c1dd
4 changed files with 70 additions and 3 deletions

View File

@ -352,6 +352,7 @@ ValidateSimdOperation(JSContext *cx, AsmJSModule::Global &global, HandleValue gl
case AsmJSSimdOperation_or: native = simd_int32x4_or; break; case AsmJSSimdOperation_or: native = simd_int32x4_or; break;
case AsmJSSimdOperation_xor: native = simd_int32x4_xor; break; case AsmJSSimdOperation_xor: native = simd_int32x4_xor; break;
case AsmJSSimdOperation_select: native = simd_int32x4_select; break; case AsmJSSimdOperation_select: native = simd_int32x4_select; break;
case AsmJSSimdOperation_splat: native = simd_int32x4_splat; break;
case AsmJSSimdOperation_lessThanOrEqual: case AsmJSSimdOperation_lessThanOrEqual:
case AsmJSSimdOperation_greaterThanOrEqual: case AsmJSSimdOperation_greaterThanOrEqual:
case AsmJSSimdOperation_notEqual: case AsmJSSimdOperation_notEqual:
@ -377,6 +378,7 @@ ValidateSimdOperation(JSContext *cx, AsmJSModule::Global &global, HandleValue gl
case AsmJSSimdOperation_or: native = simd_float32x4_or; break; case AsmJSSimdOperation_or: native = simd_float32x4_or; break;
case AsmJSSimdOperation_xor: native = simd_float32x4_xor; break; case AsmJSSimdOperation_xor: native = simd_float32x4_xor; break;
case AsmJSSimdOperation_select: native = simd_float32x4_select; break; case AsmJSSimdOperation_select: native = simd_float32x4_select; break;
case AsmJSSimdOperation_splat: native = simd_float32x4_splat; break;
} }
break; break;
} }

View File

@ -90,6 +90,7 @@ enum AsmJSSimdOperation
AsmJSSimdOperation_or, AsmJSSimdOperation_or,
AsmJSSimdOperation_xor, AsmJSSimdOperation_xor,
AsmJSSimdOperation_select, AsmJSSimdOperation_select,
AsmJSSimdOperation_splat
}; };
// These labels describe positions in the prologue/epilogue of functions while // These labels describe positions in the prologue/epilogue of functions while

View File

@ -1378,7 +1378,8 @@ class MOZ_STACK_CLASS ModuleCompiler
!addStandardLibrarySimdOpName("and", AsmJSSimdOperation_and) || !addStandardLibrarySimdOpName("and", AsmJSSimdOperation_and) ||
!addStandardLibrarySimdOpName("or", AsmJSSimdOperation_or) || !addStandardLibrarySimdOpName("or", AsmJSSimdOperation_or) ||
!addStandardLibrarySimdOpName("xor", AsmJSSimdOperation_xor) || !addStandardLibrarySimdOpName("xor", AsmJSSimdOperation_xor) ||
!addStandardLibrarySimdOpName("select", AsmJSSimdOperation_select)) !addStandardLibrarySimdOpName("select", AsmJSSimdOperation_select) ||
!addStandardLibrarySimdOpName("splat", AsmJSSimdOperation_splat))
{ {
return false; return false;
} }
@ -3524,6 +3525,7 @@ IsSimdValidOperationType(AsmJSSimdType type, AsmJSSimdOperation op)
case AsmJSSimdOperation_or: case AsmJSSimdOperation_or:
case AsmJSSimdOperation_xor: case AsmJSSimdOperation_xor:
case AsmJSSimdOperation_select: case AsmJSSimdOperation_select:
case AsmJSSimdOperation_splat:
return true; return true;
case AsmJSSimdOperation_mul: case AsmJSSimdOperation_mul:
case AsmJSSimdOperation_div: case AsmJSSimdOperation_div:
@ -4692,6 +4694,38 @@ CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltinF
return true; return true;
} }
static bool
CheckUnarySimd(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global,
MDefinition **def, Type *type)
{
unsigned numArgs = CallArgListLength(call);
if (numArgs != 1)
return f.failf(call, "expected 1 argument to unary arithmetic SIMD operation, got %u", numArgs);
ParseNode *arg = CallArgList(call);
MDefinition *argDef;
Type argType;
if (!CheckExpr(f, arg, &argDef, &argType))
return false;
// For now, the only unary SIMD operation is splat(scalar).
MOZ_ASSERT(global->simdOperation() == AsmJSSimdOperation_splat);
switch (global->simdOperationType()) {
case AsmJSSimdType_int32x4:
if (!argType.isIntish())
return f.failf(arg, "%s is not a subtype of intish", argType.toChars());
break;
case AsmJSSimdType_float32x4:
if (!CheckFloatCoercionArg(f, arg, argType, argDef, &argDef))
return false;
break;
}
*type = global->simdOperationType();
*def = f.simdSplat<MSimdSplatX4>(argDef, type->toMIRType());
return true;
}
static bool static bool
CheckBinarySimd(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global, CheckBinarySimd(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global,
MDefinition **def, Type *type) MDefinition **def, Type *type)
@ -4714,7 +4748,6 @@ CheckBinarySimd(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Glob
if (lhsType != retType || rhsType != retType) if (lhsType != retType || rhsType != retType)
return f.failf(lhs, "arguments to SIMD binary op should both be %s", retType.toChars()); return f.failf(lhs, "arguments to SIMD binary op should both be %s", retType.toChars());
MIRType opType = retType.toMIRType(); MIRType opType = retType.toMIRType();
switch (global->simdOperation()) { switch (global->simdOperation()) {
case AsmJSSimdOperation_add: case AsmJSSimdOperation_add:
@ -4774,6 +4807,7 @@ CheckBinarySimd(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Glob
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryBitwise::xor_, opType); *def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryBitwise::xor_, opType);
*type = retType; *type = retType;
break; break;
case AsmJSSimdOperation_splat:
case AsmJSSimdOperation_select: case AsmJSSimdOperation_select:
MOZ_CRASH("unexpected SIMD binary operation"); MOZ_CRASH("unexpected SIMD binary operation");
} }
@ -4824,6 +4858,8 @@ CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompile
{ {
JS_ASSERT(global->isSimdOperation()); JS_ASSERT(global->isSimdOperation());
switch (global->simdOperation()) { switch (global->simdOperation()) {
case AsmJSSimdOperation_splat:
return CheckUnarySimd(f, call, global, def, type);
case AsmJSSimdOperation_add: case AsmJSSimdOperation_add:
case AsmJSSimdOperation_sub: case AsmJSSimdOperation_sub:
case AsmJSSimdOperation_mul: case AsmJSSimdOperation_mul:

View File

@ -1,5 +1,5 @@
load(libdir + "asm.js"); load(libdir + "asm.js");
var heap = new ArrayBuffer(4096); var heap = new ArrayBuffer(0x10000);
// Set to true to see more JS debugging spew // Set to true to see more JS debugging spew
const DEBUG = false; const DEBUG = false;
@ -553,6 +553,34 @@ assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]); assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]); assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32SEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return f4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
// Splat
const I32SPLAT = 'var splat=i4.splat;'
const F32SPLAT = 'var splat=f4.splat;'
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); var p=f4(1.,2.,3.,4.); p=splat(1);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat(1, 2)} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat()} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat(m);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat(1.0);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + FROUND + "function f() {var m=i4(1,2,3,4); m=splat(f32(1.0));} return f");
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32SPLAT + 'function f(){return i4(splat(42));} return f'), this)(), [42, 42, 42, 42]);
const l33t = Math.fround(13.37);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(1));} return f'), this)(), [1, 1, 1, 1]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(1 >>> 0));} return f'), this)(), [1, 1, 1, 1]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(13.37));} return f'), this)(), [l33t, l33t, l33t, l33t]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(f32(13.37)));} return f'), this)(), [l33t, l33t, l33t, l33t]);
var i32view = new Int32Array(heap);
var f32view = new Float32Array(heap);
i32view[0] = 42;
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + I32SPLAT + 'var i32=new glob.Int32Array(heap); function f(){return i4(splat(i32[0]));} return f'), this, {}, heap)(), [42, 42, 42, 42]);
f32view[0] = 42;
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + F32SPLAT + 'var f32=new glob.Float32Array(heap); function f(){return f4(splat(f32[0]));} return f'), this, {}, heap)(), [42, 42, 42, 42]);
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + F32SPLAT + FROUND + 'function f(){return f4(splat(f32(1) + f32(2)));} return f'), this, {}, heap)(), [3, 3, 3, 3]);
// Dead code // Dead code
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); return i4(x); x=i4(5,6,7,8); return i4(x);} return f'), this)(), [1, 2, 3, 4]); assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); return i4(x); x=i4(5,6,7,8); return i4(x);} return f'), this)(), [1, 2, 3, 4]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); c=x.x|0; return i4(x);} return f'), this)(), [1, 2, 3, 4]); assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); c=x.x|0; return i4(x);} return f'), this)(), [1, 2, 3, 4]);