Bug 1129491: Add SIMD.{type}.check() to asm.js; r=luke
authorBenjamin Bouvier <benj@benj.me>
Thu, 12 Feb 2015 19:02:54 +0100
changeset 229238 a1bd894fbfc812f1f3ba524d8088eea1ab5bb474
parent 229237 099b350c49c49674aa49842334ed53c693497e84
child 229239 d9d47b2795b44f9952a95a6aaca3d37c2f315e7a
push id28282
push usercbook@mozilla.com
push dateMon, 16 Feb 2015 15:06:35 +0000
treeherdermozilla-central@09f4968d5f42 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1129491
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1129491: Add SIMD.{type}.check() to asm.js; r=luke
js/src/asmjs/AsmJSValidate.cpp
js/src/builtin/SIMD.h
js/src/jit-test/tests/asm.js/testSIMD.js
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -2132,18 +2132,23 @@ IsCoercionCall(ModuleCompiler &m, ParseN
     if (coercedExpr)
         *coercedExpr = CallArgList(pn);
 
     if (global->isMathFunction() && global->mathBuiltinFunction() == AsmJSMathBuiltin_fround) {
         *coercion = AsmJS_FRound;
         return true;
     }
 
-    if (global->isSimdCtor()) {
-        switch (global->simdCtorType()) {
+    if (global->isSimdCtor() ||
+        (global->isSimdOperation() && global->simdOperation() == AsmJSSimdOperation_check))
+    {
+        AsmJSSimdType type = global->isSimdCtor()
+                             ? global->simdCtorType()
+                             : global->simdOperationType();
+        switch (type) {
           case AsmJSSimdType_int32x4:
             *coercion = AsmJS_ToInt32x4;
             return true;
           case AsmJSSimdType_float32x4:
             *coercion = AsmJS_ToFloat32x4;
             return true;
         }
     }
@@ -5839,24 +5844,38 @@ CheckSimdSelect(FunctionCompiler &f, Par
     if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(opType), &defs))
         return false;
     *type = opType;
     *def = f.selectSimd(defs[0], defs[1], defs[2], type->toMIRType(), isElementWise);
     return true;
 }
 
 static bool
+CheckSimdCheck(FunctionCompiler &f, ParseNode *call, AsmJSSimdType opType, MDefinition **def,
+               Type *type)
+{
+    AsmJSCoercion coercion;
+    ParseNode *argNode;
+    if (!IsCoercionCall(f.m(), call, &coercion, &argNode))
+        return f.failf(call, "expected 1 argument in call to check");
+    return CheckCoercionArg(f, argNode, coercion, def, type);
+}
+
+static bool
 CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global,
                        MDefinition **def, Type *type)
 {
     MOZ_ASSERT(global->isSimdOperation());
 
     AsmJSSimdType opType = global->simdOperationType();
 
     switch (global->simdOperation()) {
+      case AsmJSSimdOperation_check:
+        return CheckSimdCheck(f, call, opType, def, type);
+
 #define OP_CHECK_CASE_LIST_(OP)                                                         \
       case AsmJSSimdOperation_##OP:                                                     \
         return CheckSimdBinary(f, call, opType, MSimdBinaryArith::Op_##OP, def, type);
       ARITH_COMMONX4_SIMD_OP(OP_CHECK_CASE_LIST_)
       ARITH_FLOAT32X4_SIMD_OP(OP_CHECK_CASE_LIST_)
 #undef OP_CHECK_CASE_LIST_
 
       case AsmJSSimdOperation_lessThan:
--- a/js/src/builtin/SIMD.h
+++ b/js/src/builtin/SIMD.h
@@ -237,17 +237,18 @@
     _(neg)                           \
     _(load)                          \
     _(loadX)                         \
     _(loadXY)                        \
     _(loadXYZ)                       \
     _(store)                         \
     _(storeX)                        \
     _(storeXY)                       \
-    _(storeXYZ)
+    _(storeXYZ)                      \
+    _(check)
 #define FORALL_SIMD_OP(_)            \
     FOREACH_INT32X4_SIMD_OP(_)       \
     FOREACH_FLOAT32X4_SIMD_OP(_)     \
     FOREACH_COMMONX4_SIMD_OP(_)
 
 namespace js {
 
 class SIMDObject : public JSObject
--- a/js/src/jit-test/tests/asm.js/testSIMD.js
+++ b/js/src/jit-test/tests/asm.js/testSIMD.js
@@ -254,16 +254,47 @@ assertAsmTypeFail('glob', USE_ASM + I32 
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1; return i4(x + x)} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=1.; return i4(x)} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f() {var x=f32(1.); return i4(x)} return f");
 
 assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return i4(x)} return f"), this)(), [1,2,3,4]);
 assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); return f4(x)} return f"), this)(), [1,2,3,4]);
 
 // 1.3.5 Coerce and pass arguments
+// Via check
+const CHECK_I32 = 'var c=i4.check;';
+
+assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f() {c();} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f(x) {x=i4(x); c(x, x);} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f() {c(1);} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f() {c(1.);} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + FROUND + "function f() {c(f32(1.));} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + F32 + "function f(x) {x=f4(x); c(x);} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + CHECK_I32 + "function f(x) {x=i4(x); return 1 + c(x) | 0;} return f");
+
+var i32x4 = SIMD.int32x4(1, 3, 3, 7);
+assertEq(asmLink(asmCompile('glob', USE_ASM + I32 + CHECK_I32 + "function f(x) {x=c(x)} return f"), this)(i32x4), undefined);
+assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CHECK_I32 + "function f(x) {x=i4(x); return c(x);} return f"), this)(i32x4), [1,3,3,7]);
+
+const CHECK_F32 = 'var c=f4.check;';
+
+assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f() {c();} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f(x) {x=f4(x); c(x, x);} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f() {c(1);} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f() {c(1.);} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + FROUND + "function f() {c(f32(1.));} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + I32 + "function f(x) {x=i4(x); c(x);} return f");
+assertAsmTypeFail('glob', USE_ASM + F32 + CHECK_F32 + "function f(x) {x=f4(x); return 1 + c(x) | 0;} return f");
+
+var f32x4 = SIMD.float32x4(13.37, 42.42, -0, NaN);
+assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + CHECK_F32 + "function f(x) {x=c(x)} return f"), this)(f32x4), undefined);
+assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CHECK_F32 + "function f(x) {x=c(x); return c(x);} return f"), this)(f32x4),
+           [Math.fround(13.37), Math.fround(42.42), -0, NaN]);
+
+// Legacy coercions
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4();} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4(1,2,3,4);} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x,y) {x=i4(y);y=+y} return f");
 
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {return +i4(1,2,3,4)} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {return 0|i4(1,2,3,4)} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f(x) {return f32(i4(1,2,3,4))} return f");
 assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "function f(x) {return f4(i4(1,2,3,4))} return f");