Bug 1069956: SIMD: Add support for int32x4.fromFloat32x4Bits and float32x4.fromInt32x4Bits in Odin; r=luke
authorBenjamin Bouvier <benj@benj.me>
Thu, 25 Sep 2014 13:18:21 +0200
changeset 222697 e2c803c2aeec002102c76757fc1b6efdff769f68
parent 222696 c965698b314e116da8d54f5b5e7665ee75e29477
child 222698 128d8d99b72d227f4d37a2b4ed6bf1f002925856
push id7107
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 17:43:31 +0000
treeherdermozilla-aurora@b4b34e0acc75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1069956
milestone35.0a1
Bug 1069956: SIMD: Add support for int32x4.fromFloat32x4Bits and float32x4.fromInt32x4Bits in Odin; r=luke
js/src/asmjs/AsmJSLink.cpp
js/src/asmjs/AsmJSModule.h
js/src/asmjs/AsmJSValidate.cpp
js/src/jit-test/tests/asm.js/testSIMD.js
--- a/js/src/asmjs/AsmJSLink.cpp
+++ b/js/src/asmjs/AsmJSLink.cpp
@@ -360,24 +360,26 @@ ValidateSimdOperation(JSContext *cx, Asm
           case AsmJSSimdOperation_xor: native = simd_int32x4_xor; break;
           case AsmJSSimdOperation_select: native = simd_int32x4_select; break;
           case AsmJSSimdOperation_splat: native = simd_int32x4_splat; break;
           case AsmJSSimdOperation_withX: native = simd_int32x4_withX; break;
           case AsmJSSimdOperation_withY: native = simd_int32x4_withY; break;
           case AsmJSSimdOperation_withZ: native = simd_int32x4_withZ; break;
           case AsmJSSimdOperation_withW: native = simd_int32x4_withW; break;
           case AsmJSSimdOperation_fromFloat32x4: native = simd_int32x4_fromFloat32x4; break;
+          case AsmJSSimdOperation_fromFloat32x4Bits: native = simd_int32x4_fromFloat32x4Bits; break;
           case AsmJSSimdOperation_lessThanOrEqual:
           case AsmJSSimdOperation_greaterThanOrEqual:
           case AsmJSSimdOperation_notEqual:
           case AsmJSSimdOperation_mul:
           case AsmJSSimdOperation_div:
           case AsmJSSimdOperation_max:
           case AsmJSSimdOperation_min:
           case AsmJSSimdOperation_fromInt32x4:
+          case AsmJSSimdOperation_fromInt32x4Bits:
             MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("shouldn't have been validated in the first "
                                                     "place");
         }
         break;
       case AsmJSSimdType_float32x4:
         switch (global.simdOperation()) {
           case AsmJSSimdOperation_add: native = simd_float32x4_add; break;
           case AsmJSSimdOperation_sub: native = simd_float32x4_sub; break;
@@ -396,17 +398,19 @@ ValidateSimdOperation(JSContext *cx, Asm
           case AsmJSSimdOperation_xor: native = simd_float32x4_xor; break;
           case AsmJSSimdOperation_select: native = simd_float32x4_select; break;
           case AsmJSSimdOperation_splat: native = simd_float32x4_splat; break;
           case AsmJSSimdOperation_withX: native = simd_float32x4_withX; break;
           case AsmJSSimdOperation_withY: native = simd_float32x4_withY; break;
           case AsmJSSimdOperation_withZ: native = simd_float32x4_withZ; break;
           case AsmJSSimdOperation_withW: native = simd_float32x4_withW; break;
           case AsmJSSimdOperation_fromInt32x4: native = simd_float32x4_fromInt32x4; break;
+          case AsmJSSimdOperation_fromInt32x4Bits: native = simd_float32x4_fromInt32x4Bits; break;
           case AsmJSSimdOperation_fromFloat32x4:
+          case AsmJSSimdOperation_fromFloat32x4Bits:
              MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("shouldn't have been validated in the first "
                                                      "place");
         }
         break;
     }
     if (!native || !IsNativeFunction(v, native))
         return LinkFail(cx, "bad SIMD.type.* operation");
     return true;
--- a/js/src/asmjs/AsmJSModule.h
+++ b/js/src/asmjs/AsmJSModule.h
@@ -93,17 +93,19 @@ enum AsmJSSimdOperation
     AsmJSSimdOperation_xor,
     AsmJSSimdOperation_select,
     AsmJSSimdOperation_splat,
     AsmJSSimdOperation_withX,
     AsmJSSimdOperation_withY,
     AsmJSSimdOperation_withZ,
     AsmJSSimdOperation_withW,
     AsmJSSimdOperation_fromInt32x4,
-    AsmJSSimdOperation_fromFloat32x4
+    AsmJSSimdOperation_fromFloat32x4,
+    AsmJSSimdOperation_fromInt32x4Bits,
+    AsmJSSimdOperation_fromFloat32x4Bits
 };
 
 // These labels describe positions in the prologue/epilogue of functions while
 // compiling an AsmJSModule.
 struct AsmJSFunctionLabels
 {
     AsmJSFunctionLabels(jit::Label &entry, jit::Label &overflowExit)
       : entry(entry), overflowExit(overflowExit) {}
--- a/js/src/asmjs/AsmJSValidate.cpp
+++ b/js/src/asmjs/AsmJSValidate.cpp
@@ -1424,17 +1424,19 @@ class MOZ_STACK_CLASS ModuleCompiler
             !addStandardLibrarySimdOpName("splat", AsmJSSimdOperation_splat) ||
             !addStandardLibrarySimdOpName("max", AsmJSSimdOperation_max) ||
             !addStandardLibrarySimdOpName("min", AsmJSSimdOperation_min) ||
             !addStandardLibrarySimdOpName("withX", AsmJSSimdOperation_withX) ||
             !addStandardLibrarySimdOpName("withY", AsmJSSimdOperation_withY) ||
             !addStandardLibrarySimdOpName("withZ", AsmJSSimdOperation_withZ) ||
             !addStandardLibrarySimdOpName("withW", AsmJSSimdOperation_withW) ||
             !addStandardLibrarySimdOpName("fromFloat32x4", AsmJSSimdOperation_fromFloat32x4) ||
-            !addStandardLibrarySimdOpName("fromInt32x4", AsmJSSimdOperation_fromInt32x4))
+            !addStandardLibrarySimdOpName("fromInt32x4", AsmJSSimdOperation_fromInt32x4) ||
+            !addStandardLibrarySimdOpName("fromFloat32x4Bits", AsmJSSimdOperation_fromFloat32x4Bits) ||
+            !addStandardLibrarySimdOpName("fromInt32x4Bits", AsmJSSimdOperation_fromInt32x4Bits))
         {
             return false;
         }
 
         uint32_t srcStart = parser_.pc->maybeFunction->pn_body->pn_pos.begin;
         uint32_t srcBodyStart = tokenStream().currentToken().pos.end;
 
         // "use strict" should be added to the source if we are in an implicit
@@ -2506,23 +2508,24 @@ class FunctionCompiler
         MOZ_ASSERT(mask->type() == MIRType_Int32x4);
         MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
         MOZ_ASSERT(lhs->type() == type);
         MSimdTernaryBitwise *ins = MSimdTernaryBitwise::NewAsmJS(alloc(), mask, lhs, rhs, op, type);
         curBlock_->add(ins);
         return ins;
     }
 
+    template<class T>
     MDefinition *convertSimd(MDefinition *vec, MIRType from, MIRType to)
     {
         if (inDeadCode())
             return nullptr;
 
         MOZ_ASSERT(IsSimdType(from) && IsSimdType(to) && from != to);
-        MSimdConvert *ins = MSimdConvert::NewAsmJS(alloc(), vec, from, to);
+        T *ins = T::NewAsmJS(alloc(), vec, from, to);
         curBlock_->add(ins);
         return ins;
     }
 
     MDefinition *splatSimd(MDefinition *v, MIRType type)
     {
         if (inDeadCode())
             return nullptr;
@@ -3597,25 +3600,27 @@ IsSimdValidOperationType(AsmJSSimdType t
       case AsmJSSimdOperation_select:
       case AsmJSSimdOperation_splat:
       case AsmJSSimdOperation_withX:
       case AsmJSSimdOperation_withY:
       case AsmJSSimdOperation_withZ:
       case AsmJSSimdOperation_withW:
         return true;
       case AsmJSSimdOperation_fromFloat32x4:
+      case AsmJSSimdOperation_fromFloat32x4Bits:
         return type == AsmJSSimdType_int32x4;
       case AsmJSSimdOperation_mul:
       case AsmJSSimdOperation_div:
       case AsmJSSimdOperation_max:
       case AsmJSSimdOperation_min:
       case AsmJSSimdOperation_lessThanOrEqual:
       case AsmJSSimdOperation_notEqual:
       case AsmJSSimdOperation_greaterThanOrEqual:
       case AsmJSSimdOperation_fromInt32x4:
+      case AsmJSSimdOperation_fromInt32x4Bits:
         return type == AsmJSSimdType_float32x4;
     }
     return false;
 }
 
 static bool
 CheckGlobalMathImport(ModuleCompiler &m, ParseNode *initNode, PropertyName *varName,
                       PropertyName *field)
@@ -4979,25 +4984,41 @@ CheckSimdOperationCall(FunctionCompiler 
         return CheckSimdWith(f, call, retType, SimdLane::LaneZ, def, type);
       case AsmJSSimdOperation_withW:
         return CheckSimdWith(f, call, retType, SimdLane::LaneW, def, type);
 
       case AsmJSSimdOperation_fromInt32x4: {
         DefinitionVector defs;
         if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(Type::Int32x4), &defs))
             return false;
-        *def = f.convertSimd(defs[0], MIRType_Int32x4, retType.toMIRType());
+        *def = f.convertSimd<MSimdConvert>(defs[0], MIRType_Int32x4, retType.toMIRType());
+        *type = retType;
+        return true;
+      }
+      case AsmJSSimdOperation_fromInt32x4Bits: {
+        DefinitionVector defs;
+        if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(Type::Int32x4), &defs))
+            return false;
+        *def = f.convertSimd<MSimdReinterpretCast>(defs[0], MIRType_Int32x4, retType.toMIRType());
         *type = retType;
         return true;
       }
       case AsmJSSimdOperation_fromFloat32x4: {
         DefinitionVector defs;
         if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(Type::Float32x4), &defs))
             return false;
-        *def = f.convertSimd(defs[0], MIRType_Float32x4, retType.toMIRType());
+        *def = f.convertSimd<MSimdConvert>(defs[0], MIRType_Float32x4, retType.toMIRType());
+        *type = retType;
+        return true;
+      }
+      case AsmJSSimdOperation_fromFloat32x4Bits: {
+        DefinitionVector defs;
+        if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(Type::Float32x4), &defs))
+            return false;
+        *def = f.convertSimd<MSimdReinterpretCast>(defs[0], MIRType_Float32x4, retType.toMIRType());
         *type = retType;
         return true;
       }
 
       case AsmJSSimdOperation_splat: {
         DefinitionVector defs;
         Type formalType = retType.simdToCoercedScalarType();
         if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(formalType), &defs))
--- a/js/src/jit-test/tests/asm.js/testSIMD.js
+++ b/js/src/jit-test/tests/asm.js/testSIMD.js
@@ -581,16 +581,61 @@ assertEqX4(f(SIMD.int32x4(0,INT32_MIN,IN
 // values can't be converted into an int32 without overflowing.  In these
 // tests, we assume x86/x64, so a conversion which failed will return the
 // undefined int32 value. See also bug 1068028.
 const UNDEFINED_INT32 = 0x80000000 | 0;
 var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTFI + 'function f(x){x=f4(x); var y=i4(0,0,0,0); y=cvt(x); return i4(y);} return f'), this);
 assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4]);
 assertEqX4(f(SIMD.float32x4(NaN,Infinity,-Infinity,-0)), [UNDEFINED_INT32, UNDEFINED_INT32, UNDEFINED_INT32, 0]);
 
+// Cast operators
+const CVTIFB = 'var cvt=f4.fromInt32x4Bits;';
+const CVTFIB = 'var cvt=i4.fromFloat32x4Bits;';
+
+var cast = (function() {
+    var i32 = new Int32Array(1);
+    var f32 = new Float32Array(i32.buffer);
+
+    function fromInt32Bits(x) {
+        i32[0] = x;
+        return f32[0];
+    }
+
+    function fromFloat32Bits(x) {
+        f32[0] = x;
+        return i32[0];
+    }
+
+    return {
+        fromInt32Bits,
+        fromFloat32Bits
+    }
+})();
+
+assertAsmTypeFail('glob', USE_ASM + I32 + "var cvt=i4.fromInt32x4; return {}");
+assertAsmTypeFail('glob', USE_ASM + F32 + "var cvt=f4.fromFloat32x4; return {}");
+assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=i4(1,2,3,4); x=cvt(x);} return f");
+assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CVTIFB + "function f() {var x=f4(1,2,3,4); x=cvt(x);} return f");
+
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTIFB + 'function f(x){x=i4(x); var y=f4(0,0,0,0); y=cvt(x); return f4(y);} return f'), this);
+assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits));
+assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits));
+
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + F32A + CVTIFB + 'function f(x){x=i4(x); var y=f4(0,0,0,0); var z=f4(1,1,1,1); y=cvt(x); y=f4a(y, z); return f4(y)} return f'), this);
+assertEqX4(f(SIMD.int32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromInt32Bits).map((x) => x+1));
+assertEqX4(f(SIMD.int32x4(0,INT32_MIN,INT32_MAX,-1)), [0, INT32_MIN, INT32_MAX, -1].map(cast.fromInt32Bits).map((x) => x+1));
+
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CVTFIB + 'function f(x){x=f4(x); var y=i4(0,0,0,0); y=cvt(x); return i4(y);} return f'), this);
+assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits));
+assertEqX4(f(SIMD.float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits));
+
+var f = asmLink(asmCompile('glob', USE_ASM + I32 + F32 + I32A + CVTFIB + 'function f(x){x=f4(x); var y=i4(0,0,0,0); var z=i4(1,1,1,1); y=cvt(x); y=i4a(y,z); return i4(y);} return f'), this);
+assertEqX4(f(SIMD.float32x4(1,2,3,4)), [1, 2, 3, 4].map(cast.fromFloat32Bits).map((x) => x+1));
+assertEqX4(f(SIMD.float32x4(-0,NaN,+Infinity,-Infinity)), [-0, NaN, +Infinity, -Infinity].map(cast.fromFloat32Bits).map((x) => x+1));
+
 // Bitwise ops
 const ANDI32 = 'var andd=i4.and;';
 const ORI32 = 'var orr=i4.or;';
 const XORI32 = 'var xorr=i4.xor;';
 
 CheckI4(ANDI32, 'var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=andd(x,y)', [42 & 2, 1337 & 4, -1 & 7, 13 & 15]);
 CheckI4(ORI32, ' var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=orr(x,y)',  [42 | 2, 1337 | 4, -1 | 7, 13 | 15]);
 CheckI4(XORI32, 'var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=xorr(x,y)', [42 ^ 2, 1337 ^ 4, -1 ^ 7, 13 ^ 15]);