mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-05 05:30:29 +00:00
Bug 1160971 - Part 5: ASM.js boolean vectors. r=bbouvier
Implement asm.js support for Bool32x4. Also remove asm.js tests for the now removed bitwise operations on Float32x4.
This commit is contained in:
parent
9e32ee152d
commit
7f13078252
@ -105,7 +105,7 @@ GetDataProperty(JSContext* cx, HandleValue objVal, HandlePropertyName field, Mut
|
||||
static bool
|
||||
HasPureCoercion(JSContext* cx, HandleValue v)
|
||||
{
|
||||
if (IsVectorObject<Int32x4>(v) || IsVectorObject<Float32x4>(v))
|
||||
if (IsVectorObject<Int32x4>(v) || IsVectorObject<Float32x4>(v) || IsVectorObject<Bool32x4>(v))
|
||||
return true;
|
||||
|
||||
// Ideally, we'd reject all non-SIMD non-primitives, but Emscripten has a
|
||||
@ -148,6 +148,8 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSModule& module, AsmJSModule::Gl
|
||||
*(double*)datum = v.f64();
|
||||
break;
|
||||
case ValType::I32x4:
|
||||
case ValType::B32x4:
|
||||
// Bool32x4 uses the same data layout as Int32x4.
|
||||
memcpy(datum, v.i32x4(), Simd128DataSize);
|
||||
break;
|
||||
case ValType::F32x4:
|
||||
@ -195,6 +197,14 @@ ValidateGlobalVariable(JSContext* cx, const AsmJSModule& module, AsmJSModule::Gl
|
||||
memcpy(datum, simdConstant.asFloat32x4(), Simd128DataSize);
|
||||
break;
|
||||
}
|
||||
case ValType::B32x4: {
|
||||
SimdConstant simdConstant;
|
||||
if (!ToSimdConstant<Bool32x4>(cx, v, &simdConstant))
|
||||
return false;
|
||||
// Bool32x4 uses the same data layout as Int32x4.
|
||||
memcpy(datum, simdConstant.asInt32x4(), Simd128DataSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -307,6 +317,7 @@ SimdTypeToName(JSContext* cx, AsmJSSimdType type)
|
||||
switch (type) {
|
||||
case AsmJSSimdType_int32x4: return cx->names().int32x4;
|
||||
case AsmJSSimdType_float32x4: return cx->names().float32x4;
|
||||
case AsmJSSimdType_bool32x4: return cx->names().bool32x4;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected SIMD type");
|
||||
}
|
||||
@ -317,6 +328,7 @@ AsmJSSimdTypeToTypeDescrType(AsmJSSimdType type)
|
||||
switch (type) {
|
||||
case AsmJSSimdType_int32x4: return Int32x4::type;
|
||||
case AsmJSSimdType_float32x4: return Float32x4::type;
|
||||
case AsmJSSimdType_bool32x4: return Bool32x4::type;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unexpected AsmJSSimdType");
|
||||
}
|
||||
@ -376,6 +388,7 @@ ValidateSimdOperation(JSContext* cx, AsmJSModule::Global& global, HandleValue gl
|
||||
switch (global.simdOperationType()) {
|
||||
#define SET_NATIVE_INT32X4(op) case AsmJSSimdOperation_##op: native = simd_int32x4_##op; break;
|
||||
#define SET_NATIVE_FLOAT32X4(op) case AsmJSSimdOperation_##op: native = simd_float32x4_##op; break;
|
||||
#define SET_NATIVE_BOOL32X4(op) case AsmJSSimdOperation_##op: native = simd_bool32x4_##op; break;
|
||||
#define FALLTHROUGH(op) case AsmJSSimdOperation_##op:
|
||||
case AsmJSSimdType_int32x4:
|
||||
switch (global.simdOperation()) {
|
||||
@ -393,9 +406,18 @@ ValidateSimdOperation(JSContext* cx, AsmJSModule::Global& global, HandleValue gl
|
||||
"place");
|
||||
}
|
||||
break;
|
||||
case AsmJSSimdType_bool32x4:
|
||||
switch (global.simdOperation()) {
|
||||
FORALL_BOOL_SIMD_OP(SET_NATIVE_BOOL32X4)
|
||||
default:
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("shouldn't have been validated in the first "
|
||||
"place");
|
||||
}
|
||||
break;
|
||||
#undef FALLTHROUGH
|
||||
#undef SET_NATIVE_FLOAT32X4
|
||||
#undef SET_NATIVE_INT32X4
|
||||
#undef SET_NATIVE_BOOL32X4
|
||||
#undef SET_NATIVE
|
||||
}
|
||||
if (!native || !IsNativeFunction(v, native))
|
||||
@ -717,6 +739,14 @@ CallAsmJS(JSContext* cx, unsigned argc, Value* vp)
|
||||
memcpy(&coercedArgs[i], simd.asFloat32x4(), Simd128DataSize);
|
||||
break;
|
||||
}
|
||||
case ValType::B32x4: {
|
||||
SimdConstant simd;
|
||||
if (!ToSimdConstant<Bool32x4>(cx, v, &simd))
|
||||
return false;
|
||||
// Bool32x4 uses the same representation as Int32x4.
|
||||
memcpy(&coercedArgs[i], simd.asInt32x4(), Simd128DataSize);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -784,6 +814,12 @@ CallAsmJS(JSContext* cx, unsigned argc, Value* vp)
|
||||
return false;
|
||||
callArgs.rval().set(ObjectValue(*simdObj));
|
||||
break;
|
||||
case ExprType::B32x4:
|
||||
simdObj = CreateSimd<Bool32x4>(cx, (int32_t*)&coercedArgs[0]);
|
||||
if (!simdObj)
|
||||
return false;
|
||||
callArgs.rval().set(ObjectValue(*simdObj));
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -73,7 +73,8 @@ enum AsmJSAtomicsBuiltinFunction
|
||||
enum AsmJSSimdType
|
||||
{
|
||||
AsmJSSimdType_int32x4,
|
||||
AsmJSSimdType_float32x4
|
||||
AsmJSSimdType_float32x4,
|
||||
AsmJSSimdType_bool32x4
|
||||
};
|
||||
|
||||
// Set of known operations, for a given SIMD type (int32x4, float32x4,...)
|
||||
@ -871,9 +872,19 @@ class AsmJSModule
|
||||
MOZ_ASSERT(!isFinished());
|
||||
unsigned width = 0;
|
||||
switch (type) {
|
||||
case wasm::ValType::I32: case wasm::ValType::F32: width = 4; break;
|
||||
case wasm::ValType::I64: case wasm::ValType::F64: width = 8; break;
|
||||
case wasm::ValType::I32x4: case wasm::ValType::F32x4: width = 16; break;
|
||||
case wasm::ValType::I32:
|
||||
case wasm::ValType::F32:
|
||||
width = 4;
|
||||
break;
|
||||
case wasm::ValType::I64:
|
||||
case wasm::ValType::F64:
|
||||
width = 8;
|
||||
break;
|
||||
case wasm::ValType::I32x4:
|
||||
case wasm::ValType::F32x4:
|
||||
case wasm::ValType::B32x4:
|
||||
width = 16;
|
||||
break;
|
||||
}
|
||||
return allocateGlobalBytes(width, width, globalDataOffset);
|
||||
}
|
||||
|
@ -532,6 +532,7 @@ class NumLit
|
||||
Float,
|
||||
Int32x4,
|
||||
Float32x4,
|
||||
Bool32x4,
|
||||
OutOfRangeInt = -1
|
||||
};
|
||||
|
||||
@ -584,7 +585,7 @@ class NumLit
|
||||
}
|
||||
|
||||
bool isSimd() const {
|
||||
return which_ == Int32x4 || which_ == Float32x4;
|
||||
return which_ == Int32x4 || which_ == Float32x4 || which_ == Bool32x4;
|
||||
}
|
||||
|
||||
const jit::SimdConstant& simdValue() const {
|
||||
@ -610,6 +611,8 @@ class NumLit
|
||||
return ValType::I32x4;
|
||||
case NumLit::Float32x4:
|
||||
return ValType::F32x4;
|
||||
case NumLit::Bool32x4:
|
||||
return ValType::B32x4;
|
||||
case NumLit::OutOfRangeInt:;
|
||||
}
|
||||
MOZ_CRASH("bad literal");
|
||||
@ -629,6 +632,8 @@ class NumLit
|
||||
return Val(simdValue().asInt32x4());
|
||||
case NumLit::Float32x4:
|
||||
return Val(simdValue().asFloat32x4());
|
||||
case NumLit::Bool32x4:
|
||||
return Val(simdValue().asInt32x4(), ValType::B32x4);
|
||||
case NumLit::OutOfRangeInt:;
|
||||
}
|
||||
MOZ_CRASH("bad literal");
|
||||
@ -647,6 +652,7 @@ class Type
|
||||
Float = NumLit::Float,
|
||||
Int32x4 = NumLit::Int32x4,
|
||||
Float32x4 = NumLit::Float32x4,
|
||||
Bool32x4 = NumLit::Bool32x4,
|
||||
Double,
|
||||
MaybeDouble,
|
||||
MaybeFloat,
|
||||
@ -670,6 +676,9 @@ class Type
|
||||
case AsmJSSimdType_float32x4:
|
||||
which_ = Float32x4;
|
||||
return;
|
||||
case AsmJSSimdType_bool32x4:
|
||||
which_ = Bool32x4;
|
||||
return;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad AsmJSSimdType");
|
||||
}
|
||||
@ -682,6 +691,7 @@ class Type
|
||||
case ValType::F64: return Double;
|
||||
case ValType::I32x4: return Int32x4;
|
||||
case ValType::F32x4: return Float32x4;
|
||||
case ValType::B32x4: return Bool32x4;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type");
|
||||
}
|
||||
@ -695,6 +705,7 @@ class Type
|
||||
case ExprType::F64: return Double;
|
||||
case ExprType::I32x4: return Int32x4;
|
||||
case ExprType::F32x4: return Float32x4;
|
||||
case ExprType::B32x4: return Bool32x4;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type");
|
||||
}
|
||||
@ -702,7 +713,7 @@ class Type
|
||||
static Type lit(const NumLit& lit) {
|
||||
MOZ_ASSERT(lit.valid());
|
||||
Which which = Type::Which(lit.which());
|
||||
MOZ_ASSERT(which >= Fixnum && which <= Float32x4);
|
||||
MOZ_ASSERT(which >= Fixnum && which <= Bool32x4);
|
||||
Type t;
|
||||
t.which_ = which;
|
||||
return t;
|
||||
@ -722,6 +733,7 @@ class Type
|
||||
case Float: return isFloat();
|
||||
case Int32x4: return isInt32x4();
|
||||
case Float32x4: return isFloat32x4();
|
||||
case Bool32x4: return isBool32x4();
|
||||
case MaybeDouble: return isMaybeDouble();
|
||||
case MaybeFloat: return isMaybeFloat();
|
||||
case Floatish: return isFloatish();
|
||||
@ -741,6 +753,7 @@ class Type
|
||||
case ValType::F64: return isDouble();
|
||||
case ValType::I32x4: return isInt32x4();
|
||||
case ValType::F32x4: return isFloat32x4();
|
||||
case ValType::B32x4: return isBool32x4();
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected rhs type");
|
||||
}
|
||||
@ -805,8 +818,12 @@ class Type
|
||||
return which_ == Float32x4;
|
||||
}
|
||||
|
||||
bool isBool32x4() const {
|
||||
return which_ == Bool32x4;
|
||||
}
|
||||
|
||||
bool isSimd() const {
|
||||
return isInt32x4() || isFloat32x4();
|
||||
return isInt32x4() || isFloat32x4() || isBool32x4();
|
||||
}
|
||||
|
||||
bool isVarType() const {
|
||||
@ -846,6 +863,8 @@ class Type
|
||||
return jit::MIRType_Int32x4;
|
||||
case Float32x4:
|
||||
return jit::MIRType_Float32x4;
|
||||
case Bool32x4:
|
||||
return jit::MIRType_Bool32x4;
|
||||
case Void:
|
||||
return jit::MIRType_None;
|
||||
}
|
||||
@ -859,6 +878,8 @@ class Type
|
||||
return AsmJSSimdType_int32x4;
|
||||
case Float32x4:
|
||||
return AsmJSSimdType_float32x4;
|
||||
case Bool32x4:
|
||||
return AsmJSSimdType_bool32x4;
|
||||
// Scalar types
|
||||
case Double:
|
||||
case DoubleLit:
|
||||
@ -892,6 +913,7 @@ class Type
|
||||
case Intish: return "intish";
|
||||
case Int32x4: return "int32x4";
|
||||
case Float32x4: return "float32x4";
|
||||
case Bool32x4: return "bool32x4";
|
||||
case Void: return "void";
|
||||
}
|
||||
MOZ_CRASH("Invalid Type");
|
||||
@ -1791,6 +1813,9 @@ IsCoercionCall(ModuleValidator& m, ParseNode* pn, ValType* coerceTo, ParseNode**
|
||||
case AsmJSSimdType_float32x4:
|
||||
*coerceTo = ValType::F32x4;
|
||||
return true;
|
||||
case AsmJSSimdType_bool32x4:
|
||||
*coerceTo = ValType::B32x4;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1814,8 +1839,9 @@ static unsigned
|
||||
SimdTypeToLength(AsmJSSimdType type)
|
||||
{
|
||||
switch (type) {
|
||||
case AsmJSSimdType_float32x4:
|
||||
case AsmJSSimdType_int32x4:
|
||||
case AsmJSSimdType_float32x4:
|
||||
case AsmJSSimdType_bool32x4:
|
||||
return 4;
|
||||
}
|
||||
MOZ_CRASH("unexpected SIMD type");
|
||||
@ -1863,6 +1889,7 @@ IsSimdLiteral(ModuleValidator& m, ParseNode* pn)
|
||||
uint32_t _;
|
||||
switch (type) {
|
||||
case AsmJSSimdType_int32x4:
|
||||
case AsmJSSimdType_bool32x4:
|
||||
if (!IsLiteralInt(m, arg, &_))
|
||||
return false;
|
||||
case AsmJSSimdType_float32x4:
|
||||
@ -1933,6 +1960,17 @@ ExtractSimdValue(ModuleValidator& m, ParseNode* pn)
|
||||
MOZ_ASSERT(arg == nullptr);
|
||||
return NumLit(NumLit::Float32x4, SimdConstant::CreateX4(val));
|
||||
}
|
||||
case AsmJSSimdType_bool32x4: {
|
||||
MOZ_ASSERT(SimdTypeToLength(type) == 4);
|
||||
int32_t val[4];
|
||||
for (size_t i = 0; i < 4; i++, arg = NextNode(arg)) {
|
||||
uint32_t u32;
|
||||
JS_ALWAYS_TRUE(IsLiteralInt(m, arg, &u32));
|
||||
val[i] = u32 ? -1 : 0;
|
||||
}
|
||||
MOZ_ASSERT(arg == nullptr);
|
||||
return NumLit(NumLit::Bool32x4, SimdConstant::CreateX4(val));
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_CRASH("Unexpected SIMD type.");
|
||||
@ -2001,6 +2039,7 @@ IsLiteralInt(NumLit lit, uint32_t* u32)
|
||||
case NumLit::OutOfRangeInt:
|
||||
case NumLit::Int32x4:
|
||||
case NumLit::Float32x4:
|
||||
case NumLit::Bool32x4:
|
||||
return false;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad literal type");
|
||||
@ -2226,6 +2265,11 @@ class MOZ_STACK_CLASS FunctionValidator
|
||||
writeOp(F32X4::Literal);
|
||||
funcIR().writeF32X4(lit.simdValue().asFloat32x4());
|
||||
return;
|
||||
case NumLit::Bool32x4:
|
||||
// Boolean vectors use the Int32x4 memory representation.
|
||||
writeOp(B32X4::Literal);
|
||||
funcIR().writeI32X4(lit.simdValue().asInt32x4());
|
||||
return;
|
||||
case NumLit::OutOfRangeInt:
|
||||
break;
|
||||
}
|
||||
@ -2553,6 +2597,10 @@ IsSimdTypeName(ModuleValidator& m, PropertyName* name, AsmJSSimdType* type)
|
||||
*type = AsmJSSimdType_float32x4;
|
||||
return true;
|
||||
}
|
||||
if (name == m.cx()->names().bool32x4) {
|
||||
*type = AsmJSSimdType_bool32x4;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2573,6 +2621,12 @@ IsSimdValidOperationType(AsmJSSimdType type, AsmJSSimdOperation op)
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
case AsmJSSimdType_bool32x4:
|
||||
switch (op) {
|
||||
FORALL_BOOL_SIMD_OP(CASE) return true;
|
||||
default: return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#undef CASE
|
||||
MOZ_CRASH("Unhandles SIMD type");
|
||||
@ -2950,6 +3004,7 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
|
||||
case ValType::F64: f.writeOp(F64::GetLocal); break;
|
||||
case ValType::I32x4: f.writeOp(I32X4::GetLocal); break;
|
||||
case ValType::F32x4: f.writeOp(F32X4::GetLocal); break;
|
||||
case ValType::B32x4: f.writeOp(B32X4::GetLocal); break;
|
||||
}
|
||||
f.writeU32(local->slot);
|
||||
*type = Type::var(local->type);
|
||||
@ -2970,6 +3025,7 @@ CheckVarRef(FunctionValidator& f, ParseNode* varRef, Type* type)
|
||||
case Type::Float: f.writeOp(F32::GetGlobal); break;
|
||||
case Type::Int32x4: f.writeOp(I32X4::GetGlobal); break;
|
||||
case Type::Float32x4: f.writeOp(F32X4::GetGlobal); break;
|
||||
case Type::Bool32x4: f.writeOp(B32X4::GetGlobal); break;
|
||||
default: MOZ_CRASH("unexpected global type");
|
||||
}
|
||||
|
||||
@ -3303,6 +3359,7 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type
|
||||
case ValType::F32: f.patchOp(opcodeAt, F32::SetLocal); break;
|
||||
case ValType::I32x4: f.patchOp(opcodeAt, I32X4::SetLocal); break;
|
||||
case ValType::F32x4: f.patchOp(opcodeAt, F32X4::SetLocal); break;
|
||||
case ValType::B32x4: f.patchOp(opcodeAt, B32X4::SetLocal); break;
|
||||
}
|
||||
|
||||
f.patch32(indexAt, lhsVar->slot);
|
||||
@ -3325,6 +3382,7 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type
|
||||
case Type::Double: f.patchOp(opcodeAt, F64::SetGlobal); break;
|
||||
case Type::Int32x4: f.patchOp(opcodeAt, I32X4::SetGlobal); break;
|
||||
case Type::Float32x4: f.patchOp(opcodeAt, F32X4::SetGlobal); break;
|
||||
case Type::Bool32x4: f.patchOp(opcodeAt, B32X4::SetGlobal); break;
|
||||
default: MOZ_CRASH("unexpected global type");
|
||||
}
|
||||
|
||||
@ -3872,6 +3930,7 @@ CheckInternalCall(FunctionValidator& f, ParseNode* callNode, PropertyName* calle
|
||||
case ExprType::F64: f.writeOp(F64::CallInternal); break;
|
||||
case ExprType::I32x4: f.writeOp(I32X4::CallInternal); break;
|
||||
case ExprType::F32x4: f.writeOp(F32X4::CallInternal); break;
|
||||
case ExprType::B32x4: f.writeOp(B32X4::CallInternal); break;
|
||||
}
|
||||
|
||||
// Function's index, to find out the function's entry
|
||||
@ -3966,6 +4025,7 @@ CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, ExprType ret, Type*
|
||||
case ExprType::F64: f.writeOp(F64::CallIndirect); break;
|
||||
case ExprType::I32x4: f.writeOp(I32X4::CallIndirect); break;
|
||||
case ExprType::F32x4: f.writeOp(F32X4::CallIndirect); break;
|
||||
case ExprType::B32x4: f.writeOp(B32X4::CallIndirect); break;
|
||||
}
|
||||
|
||||
// Table's mask
|
||||
@ -4034,6 +4094,7 @@ CheckFFICall(FunctionValidator& f, ParseNode* callNode, unsigned ffiIndex, ExprT
|
||||
case ExprType::F64: f.writeOp(F64::CallImport); break;
|
||||
case ExprType::I32x4: f.writeOp(I32X4::CallImport); break;
|
||||
case ExprType::F32x4: f.writeOp(F32X4::CallImport); break;
|
||||
case ExprType::B32x4: f.writeOp(B32X4::CallImport); break;
|
||||
}
|
||||
|
||||
// Global data offset
|
||||
@ -4119,6 +4180,11 @@ CheckCoercionArg(FunctionValidator& f, ParseNode* arg, ValType expected, Type* t
|
||||
return f.fail(arg, "argument to SIMD float32x4 coercion isn't float32x4");
|
||||
f.patchOp(opcodeAt, F32X4::Id);
|
||||
break;
|
||||
case ValType::B32x4:
|
||||
if (!argType.isBool32x4())
|
||||
return f.fail(arg, "argument to SIMD bool32x4 coercion isn't bool32x4");
|
||||
f.patchOp(opcodeAt, B32X4::Id);
|
||||
break;
|
||||
case ValType::I32:
|
||||
case ValType::F64:
|
||||
MOZ_CRASH("not call coercions");
|
||||
@ -4286,6 +4352,7 @@ SimdToCoercedScalarType(AsmJSSimdType t)
|
||||
{
|
||||
switch (t) {
|
||||
case AsmJSSimdType_int32x4:
|
||||
case AsmJSSimdType_bool32x4:
|
||||
return Type::Intish;
|
||||
case AsmJSSimdType_float32x4:
|
||||
return Type::Floatish;
|
||||
@ -4325,6 +4392,7 @@ class CheckSimdScalarArgs
|
||||
return true;
|
||||
|
||||
switch (simdType_) {
|
||||
case AsmJSSimdType_bool32x4:
|
||||
case AsmJSSimdType_int32x4: f.patchOp(patchAt, I32::Id); return true;
|
||||
case AsmJSSimdType_float32x4: f.patchOp(patchAt, F32::Id); return true;
|
||||
}
|
||||
@ -4343,9 +4411,9 @@ class CheckSimdSelectArgs
|
||||
bool operator()(FunctionValidator& f, ParseNode* arg, unsigned argIndex, Type actualType) const
|
||||
{
|
||||
if (argIndex == 0) {
|
||||
// First argument of select is an int32x4 mask.
|
||||
if (!(actualType <= Type::Int32x4))
|
||||
return f.failf(arg, "%s is not a subtype of Int32x4", actualType.toChars());
|
||||
// First argument of select is a bool32x4 mask.
|
||||
if (!(actualType <= Type::Bool32x4))
|
||||
return f.failf(arg, "%s is not a subtype of Bool32x4", actualType.toChars());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4381,6 +4449,7 @@ class CheckSimdVectorScalarArgs
|
||||
switch (formalSimdType_) {
|
||||
case AsmJSSimdType_int32x4: f.patchOp(patchAt, I32X4::Id); return true;
|
||||
case AsmJSSimdType_float32x4: f.patchOp(patchAt, F32X4::Id); return true;
|
||||
case AsmJSSimdType_bool32x4: f.patchOp(patchAt, B32X4::Id); return true;
|
||||
}
|
||||
|
||||
MOZ_CRASH("unexpected simd type");
|
||||
@ -4442,6 +4511,7 @@ class CheckSimdReplaceLaneArgs
|
||||
switch (formalSimdType_) {
|
||||
case AsmJSSimdType_int32x4: f.patchOp(patchAt, I32X4::Id); break;
|
||||
case AsmJSSimdType_float32x4: f.patchOp(patchAt, F32X4::Id); break;
|
||||
case AsmJSSimdType_bool32x4: f.patchOp(patchAt, B32X4::Id); break;
|
||||
}
|
||||
return true;
|
||||
case 1:
|
||||
@ -4463,11 +4533,12 @@ class CheckSimdReplaceLaneArgs
|
||||
} // namespace
|
||||
|
||||
static void
|
||||
SwitchPackOp(FunctionValidator& f, AsmJSSimdType type, I32X4 i32x4, F32X4 f32x4)
|
||||
SwitchPackOp(FunctionValidator& f, AsmJSSimdType type, I32X4 i32x4, F32X4 f32x4, B32X4 b32x4)
|
||||
{
|
||||
switch (type) {
|
||||
case AsmJSSimdType_int32x4: f.writeOp(i32x4); return;
|
||||
case AsmJSSimdType_float32x4: f.writeOp(f32x4); return;
|
||||
case AsmJSSimdType_bool32x4: f.writeOp(b32x4); return;
|
||||
}
|
||||
MOZ_CRASH("unexpected simd type");
|
||||
}
|
||||
@ -4476,7 +4547,7 @@ static bool
|
||||
CheckSimdUnary(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType,
|
||||
MSimdUnaryArith::Operation op, Type* type)
|
||||
{
|
||||
SwitchPackOp(f, opType, I32X4::Unary, F32X4::Unary);
|
||||
SwitchPackOp(f, opType, I32X4::Unary, F32X4::Unary, B32X4::Unary);
|
||||
f.writeU8(uint8_t(op));
|
||||
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
|
||||
return false;
|
||||
@ -4500,7 +4571,7 @@ static bool
|
||||
CheckSimdBinary(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType,
|
||||
MSimdBinaryArith::Operation op, Type* type)
|
||||
{
|
||||
SwitchPackOp(f, opType, I32X4::Binary, F32X4::Binary);
|
||||
SwitchPackOp(f, opType, I32X4::Binary, F32X4::Binary, B32X4::Binary);
|
||||
return CheckSimdBinaryGuts(f, call, opType, op, type);
|
||||
}
|
||||
|
||||
@ -4508,7 +4579,7 @@ static bool
|
||||
CheckSimdBinary(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType,
|
||||
MSimdBinaryBitwise::Operation op, Type* type)
|
||||
{
|
||||
SwitchPackOp(f, opType, I32X4::BinaryBitwise, F32X4::Bad);
|
||||
SwitchPackOp(f, opType, I32X4::BinaryBitwise, F32X4::Bad, B32X4::BinaryBitwise);
|
||||
return CheckSimdBinaryGuts(f, call, opType, op, type);
|
||||
}
|
||||
|
||||
@ -4517,13 +4588,19 @@ CheckSimdBinary(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType,
|
||||
MSimdBinaryComp::Operation op, Type* type)
|
||||
{
|
||||
switch (opType) {
|
||||
case AsmJSSimdType_int32x4: f.writeOp(I32X4::BinaryCompI32X4); break;
|
||||
case AsmJSSimdType_float32x4: f.writeOp(I32X4::BinaryCompF32X4); break;
|
||||
case AsmJSSimdType_int32x4:
|
||||
f.writeOp(B32X4::BinaryCompI32X4);
|
||||
break;
|
||||
case AsmJSSimdType_float32x4:
|
||||
f.writeOp(B32X4::BinaryCompF32X4);
|
||||
break;
|
||||
case AsmJSSimdType_bool32x4:
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Can't compare boolean vectors");
|
||||
}
|
||||
f.writeU8(uint8_t(op));
|
||||
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(opType)))
|
||||
return false;
|
||||
*type = Type::Int32x4;
|
||||
*type = Type::Bool32x4;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -4551,6 +4628,10 @@ CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType
|
||||
f.writeOp(F32::F32X4ExtractLane);
|
||||
*type = Type::Float;
|
||||
break;
|
||||
case AsmJSSimdType_bool32x4:
|
||||
f.writeOp(I32::B32X4ExtractLane);
|
||||
*type = Type::Int;
|
||||
break;
|
||||
}
|
||||
return CheckSimdCallArgs(f, call, 2, CheckSimdExtractLaneArgs(opType));
|
||||
}
|
||||
@ -4558,7 +4639,7 @@ CheckSimdExtractLane(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType
|
||||
static bool
|
||||
CheckSimdReplaceLane(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType, Type* type)
|
||||
{
|
||||
SwitchPackOp(f, opType, I32X4::ReplaceLane, F32X4::ReplaceLane);
|
||||
SwitchPackOp(f, opType, I32X4::ReplaceLane, F32X4::ReplaceLane, B32X4::ReplaceLane);
|
||||
if (!CheckSimdCallArgsPatchable(f, call, 3, CheckSimdReplaceLaneArgs(opType)))
|
||||
return false;
|
||||
*type = opType;
|
||||
@ -4576,7 +4657,8 @@ CheckSimdCast(FunctionValidator& f, ParseNode* call, AsmJSSimdType fromType, Asm
|
||||
{
|
||||
SwitchPackOp(f, toType,
|
||||
bitcast ? I32X4::FromF32X4Bits : I32X4::FromF32X4,
|
||||
bitcast ? F32X4::FromI32X4Bits : F32X4::FromI32X4);
|
||||
bitcast ? F32X4::FromI32X4Bits : F32X4::FromI32X4,
|
||||
B32X4::Bad);
|
||||
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(fromType)))
|
||||
return false;
|
||||
*type = toType;
|
||||
@ -4606,7 +4688,7 @@ CheckSimdSwizzle(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType, Ty
|
||||
if (numArgs != 5)
|
||||
return f.failf(call, "expected 5 arguments to SIMD swizzle, got %u", numArgs);
|
||||
|
||||
SwitchPackOp(f, opType, I32X4::Swizzle, F32X4::Swizzle);
|
||||
SwitchPackOp(f, opType, I32X4::Swizzle, F32X4::Swizzle, B32X4::Bad);
|
||||
|
||||
Type retType = opType;
|
||||
ParseNode* vec = CallArgList(call);
|
||||
@ -4634,7 +4716,7 @@ CheckSimdShuffle(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType, Ty
|
||||
if (numArgs != 6)
|
||||
return f.failf(call, "expected 6 arguments to SIMD shuffle, got %u", numArgs);
|
||||
|
||||
SwitchPackOp(f, opType, I32X4::Shuffle, F32X4::Shuffle);
|
||||
SwitchPackOp(f, opType, I32X4::Shuffle, F32X4::Shuffle, B32X4::Bad);
|
||||
|
||||
Type retType = opType;
|
||||
ParseNode* arg = CallArgList(call);
|
||||
@ -4678,6 +4760,7 @@ CheckSimdLoadStoreArgs(FunctionValidator& f, ParseNode* call, AsmJSSimdType opTy
|
||||
switch (opType) {
|
||||
case AsmJSSimdType_int32x4: *viewType = Scalar::Int32x4; break;
|
||||
case AsmJSSimdType_float32x4: *viewType = Scalar::Float32x4; break;
|
||||
case AsmJSSimdType_bool32x4: MOZ_CRASH("Cannot load/store boolean SIMD type");
|
||||
}
|
||||
|
||||
ParseNode* indexExpr = NextNode(view);
|
||||
@ -4718,7 +4801,7 @@ CheckSimdLoad(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType,
|
||||
if (numArgs != 2)
|
||||
return f.failf(call, "expected 2 arguments to SIMD load, got %u", numArgs);
|
||||
|
||||
SwitchPackOp(f, opType, I32X4::Load, F32X4::Load);
|
||||
SwitchPackOp(f, opType, I32X4::Load, F32X4::Load, B32X4::Bad);
|
||||
size_t viewTypeAt = f.tempU8();
|
||||
size_t needsBoundsCheckAt = f.tempU8();
|
||||
f.writeU8(numElems);
|
||||
@ -4743,7 +4826,7 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType,
|
||||
if (numArgs != 3)
|
||||
return f.failf(call, "expected 3 arguments to SIMD store, got %u", numArgs);
|
||||
|
||||
SwitchPackOp(f, opType, I32X4::Store, F32X4::Store);
|
||||
SwitchPackOp(f, opType, I32X4::Store, F32X4::Store, B32X4::Bad);
|
||||
size_t viewTypeAt = f.tempU8();
|
||||
size_t needsBoundsCheckAt = f.tempU8();
|
||||
f.writeU8(numElems);
|
||||
@ -4771,13 +4854,47 @@ CheckSimdStore(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType,
|
||||
static bool
|
||||
CheckSimdSelect(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType, Type* type)
|
||||
{
|
||||
SwitchPackOp(f, opType, I32X4::Select, F32X4::Select);
|
||||
SwitchPackOp(f, opType, I32X4::Select, F32X4::Select, B32X4::Bad);
|
||||
if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(opType)))
|
||||
return false;
|
||||
*type = opType;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckSimdAllTrue(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType, Type* type)
|
||||
{
|
||||
switch (opType) {
|
||||
case AsmJSSimdType_bool32x4:
|
||||
f.writeOp(I32::B32X4AllTrue);
|
||||
break;
|
||||
case AsmJSSimdType_int32x4:
|
||||
case AsmJSSimdType_float32x4:
|
||||
MOZ_CRASH("allTrue is only defined on bool SIMD types");
|
||||
}
|
||||
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
|
||||
return false;
|
||||
*type = Type::Int;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckSimdAnyTrue(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType, Type* type)
|
||||
{
|
||||
switch (opType) {
|
||||
case AsmJSSimdType_bool32x4:
|
||||
f.writeOp(I32::B32X4AnyTrue);
|
||||
break;
|
||||
case AsmJSSimdType_int32x4:
|
||||
case AsmJSSimdType_float32x4:
|
||||
MOZ_CRASH("anyTrue is only defined on bool SIMD types");
|
||||
}
|
||||
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(opType)))
|
||||
return false;
|
||||
*type = Type::Int;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckSimdCheck(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType, Type* type)
|
||||
{
|
||||
@ -4791,7 +4908,7 @@ CheckSimdCheck(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType, Type
|
||||
static bool
|
||||
CheckSimdSplat(FunctionValidator& f, ParseNode* call, AsmJSSimdType opType, Type* type)
|
||||
{
|
||||
SwitchPackOp(f, opType, I32X4::Splat, F32X4::Splat);
|
||||
SwitchPackOp(f, opType, I32X4::Splat, F32X4::Splat, B32X4::Splat);
|
||||
if (!CheckSimdCallArgsPatchable(f, call, 1, CheckSimdScalarArgs(opType)))
|
||||
return false;
|
||||
*type = opType;
|
||||
@ -4900,8 +5017,9 @@ CheckSimdOperationCall(FunctionValidator& f, ParseNode* call, const ModuleValida
|
||||
return CheckSimdSplat(f, call, opType, type);
|
||||
|
||||
case AsmJSSimdOperation_allTrue:
|
||||
return CheckSimdAllTrue(f, call, opType, type);
|
||||
case AsmJSSimdOperation_anyTrue:
|
||||
MOZ_CRASH("unreachable and nyi"); // TODO bug 1160971
|
||||
return CheckSimdAnyTrue(f, call, opType, type);
|
||||
}
|
||||
MOZ_CRASH("unexpected simd operation in CheckSimdOperationCall");
|
||||
}
|
||||
@ -4913,7 +5031,7 @@ CheckSimdCtorCall(FunctionValidator& f, ParseNode* call, const ModuleValidator::
|
||||
MOZ_ASSERT(call->isKind(PNK_CALL));
|
||||
|
||||
AsmJSSimdType simdType = global->simdCtorType();
|
||||
SwitchPackOp(f, simdType, I32X4::Ctor, F32X4::Ctor);
|
||||
SwitchPackOp(f, simdType, I32X4::Ctor, F32X4::Ctor, B32X4::Ctor);
|
||||
|
||||
unsigned length = SimdTypeToLength(simdType);
|
||||
if (!CheckSimdCallArgsPatchable(f, call, length, CheckSimdScalarArgs(simdType)))
|
||||
@ -4964,6 +5082,8 @@ CoerceResult(FunctionValidator& f, ParseNode* expr, ExprType expected, Type actu
|
||||
f.patchOp(patchAt, Stmt::I32X4Expr);
|
||||
else if (actual.isFloat32x4())
|
||||
f.patchOp(patchAt, Stmt::F32X4Expr);
|
||||
else if (actual.isBool32x4())
|
||||
f.patchOp(patchAt, Stmt::B32X4Expr);
|
||||
else if (actual.isVoid())
|
||||
f.patchOp(patchAt, Stmt::Id);
|
||||
else
|
||||
@ -5002,6 +5122,11 @@ CoerceResult(FunctionValidator& f, ParseNode* expr, ExprType expected, Type actu
|
||||
return f.failf(expr, "%s is not a subtype of float32x4", actual.toChars());
|
||||
f.patchOp(patchAt, F32X4::Id);
|
||||
break;
|
||||
case ExprType::B32x4:
|
||||
if (!actual.isBool32x4())
|
||||
return f.failf(expr, "%s is not a subtype of bool32x4", actual.toChars());
|
||||
f.patchOp(patchAt, B32X4::Id);
|
||||
break;
|
||||
}
|
||||
|
||||
*type = Type::ret(expected);
|
||||
@ -5034,7 +5159,6 @@ CheckCoercedSimdCall(FunctionValidator& f, ParseNode* call, const ModuleValidato
|
||||
MOZ_ASSERT(global->isSimdOperation());
|
||||
if (!CheckSimdOperationCall(f, call, global, &actual))
|
||||
return false;
|
||||
MOZ_ASSERT_IF(global->simdOperation() != AsmJSSimdOperation_extractLane, actual.isSimd());
|
||||
}
|
||||
|
||||
return CoerceResult(f, call, ret, actual, opcodeAt, type);
|
||||
@ -5249,6 +5373,8 @@ CheckComma(FunctionValidator& f, ParseNode* comma, Type* type)
|
||||
f.patchOp(commaAt, I32X4::Comma);
|
||||
else if (type->isFloat32x4())
|
||||
f.patchOp(commaAt, F32X4::Comma);
|
||||
else if (type->isBool32x4())
|
||||
f.patchOp(commaAt, B32X4::Comma);
|
||||
else
|
||||
MOZ_CRASH("unexpected or unimplemented expression statement");
|
||||
|
||||
@ -5296,6 +5422,9 @@ CheckConditional(FunctionValidator& f, ParseNode* ternary, Type* type)
|
||||
} else if (elseType.isFloat32x4() && thenType.isFloat32x4()) {
|
||||
f.patchOp(opcodeAt, F32X4::Conditional);
|
||||
*type = Type::Float32x4;
|
||||
} else if (elseType.isBool32x4() && thenType.isBool32x4()) {
|
||||
f.patchOp(opcodeAt, B32X4::Conditional);
|
||||
*type = Type::Bool32x4;
|
||||
} else {
|
||||
return f.failf(ternary, "then/else branches of conditional must both produce int, float, "
|
||||
"double or SIMD types, current types are %s and %s",
|
||||
@ -5324,6 +5453,7 @@ IsValidIntMultiplyConstant(ModuleValidator& m, ParseNode* expr)
|
||||
case NumLit::OutOfRangeInt:
|
||||
case NumLit::Int32x4:
|
||||
case NumLit::Float32x4:
|
||||
case NumLit::Bool32x4:
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5692,6 +5822,8 @@ CheckAsExprStatement(FunctionValidator& f, ParseNode* expr)
|
||||
f.patchOp(opcodeAt, Stmt::I32X4Expr);
|
||||
else if (type.isFloat32x4())
|
||||
f.patchOp(opcodeAt, Stmt::F32X4Expr);
|
||||
else if (type.isBool32x4())
|
||||
f.patchOp(opcodeAt, Stmt::B32X4Expr);
|
||||
else
|
||||
MOZ_CRASH("unexpected or unimplemented expression statement");
|
||||
|
||||
@ -5897,6 +6029,7 @@ CheckCaseExpr(FunctionValidator& f, ParseNode* caseExpr, int32_t* value)
|
||||
case NumLit::Float:
|
||||
case NumLit::Int32x4:
|
||||
case NumLit::Float32x4:
|
||||
case NumLit::Bool32x4:
|
||||
return f.fail(caseExpr, "switch case expression must be an integer literal");
|
||||
}
|
||||
|
||||
@ -6075,6 +6208,8 @@ CheckReturn(FunctionValidator& f, ParseNode* returnStmt)
|
||||
ret = ExprType::I32x4;
|
||||
else if (type.isFloat32x4())
|
||||
ret = ExprType::F32x4;
|
||||
else if (type.isBool32x4())
|
||||
ret = ExprType::B32x4;
|
||||
else if (type.isVoid())
|
||||
ret = ExprType::Void;
|
||||
else
|
||||
|
@ -43,13 +43,20 @@ enum class ValType
|
||||
F32,
|
||||
F64,
|
||||
I32x4,
|
||||
F32x4
|
||||
F32x4,
|
||||
B32x4
|
||||
};
|
||||
|
||||
static inline bool
|
||||
IsSimdType(ValType vt)
|
||||
{
|
||||
return vt == ValType::I32x4 || vt == ValType::F32x4;
|
||||
return vt == ValType::I32x4 || vt == ValType::F32x4 || vt == ValType::B32x4;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsSimdBoolType(ValType vt)
|
||||
{
|
||||
return vt == ValType::B32x4;
|
||||
}
|
||||
|
||||
static inline jit::MIRType
|
||||
@ -62,6 +69,7 @@ ToMIRType(ValType vt)
|
||||
case ValType::F64: return jit::MIRType_Double;
|
||||
case ValType::I32x4: return jit::MIRType_Int32x4;
|
||||
case ValType::F32x4: return jit::MIRType_Float32x4;
|
||||
case ValType::B32x4: return jit::MIRType_Bool32x4;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("bad type");
|
||||
}
|
||||
@ -97,7 +105,11 @@ class Val
|
||||
explicit Val(uint64_t i64) : type_(ValType::I64) { u.i64_ = i64; }
|
||||
explicit Val(float f32) : type_(ValType::F32) { u.f32_ = f32; }
|
||||
explicit Val(double f64) : type_(ValType::F64) { u.f64_ = f64; }
|
||||
explicit Val(const I32x4& i32x4) : type_(ValType::I32x4) { memcpy(u.i32x4_, i32x4, sizeof(u.i32x4_)); }
|
||||
|
||||
explicit Val(const I32x4& i32x4, ValType type = ValType::I32x4) : type_(type) {
|
||||
MOZ_ASSERT(type_ == ValType::I32x4 || type_ == ValType::B32x4);
|
||||
memcpy(u.i32x4_, i32x4, sizeof(u.i32x4_));
|
||||
}
|
||||
explicit Val(const F32x4& f32x4) : type_(ValType::F32x4) { memcpy(u.f32x4_, f32x4, sizeof(u.f32x4_)); }
|
||||
|
||||
ValType type() const { return type_; }
|
||||
@ -107,7 +119,10 @@ class Val
|
||||
uint64_t i64() const { MOZ_ASSERT(type_ == ValType::I64); return u.i64_; }
|
||||
float f32() const { MOZ_ASSERT(type_ == ValType::F32); return u.f32_; }
|
||||
double f64() const { MOZ_ASSERT(type_ == ValType::F64); return u.f64_; }
|
||||
const I32x4& i32x4() const { MOZ_ASSERT(type_ == ValType::I32x4); return u.i32x4_; }
|
||||
const I32x4& i32x4() const {
|
||||
MOZ_ASSERT(type_ == ValType::I32x4 || type_ == ValType::B32x4);
|
||||
return u.i32x4_;
|
||||
}
|
||||
const F32x4& f32x4() const { MOZ_ASSERT(type_ == ValType::F32x4); return u.f32x4_; }
|
||||
};
|
||||
|
||||
@ -125,6 +140,7 @@ enum class ExprType : uint8_t
|
||||
F64 = uint8_t(ValType::F64),
|
||||
I32x4 = uint8_t(ValType::I32x4),
|
||||
F32x4 = uint8_t(ValType::F32x4),
|
||||
B32x4 = uint8_t(ValType::B32x4),
|
||||
Void
|
||||
};
|
||||
|
||||
|
@ -64,6 +64,7 @@ enum class Stmt : uint8_t
|
||||
F64Expr,
|
||||
I32X4Expr,
|
||||
F32X4Expr,
|
||||
B32X4Expr,
|
||||
|
||||
Id,
|
||||
Noop,
|
||||
@ -173,6 +174,9 @@ enum class I32 : uint8_t
|
||||
|
||||
// SIMD opcodes
|
||||
I32X4ExtractLane,
|
||||
B32X4ExtractLane,
|
||||
B32X4AllTrue,
|
||||
B32X4AnyTrue,
|
||||
|
||||
// Specific to AsmJS
|
||||
Id,
|
||||
@ -312,8 +316,6 @@ enum class I32X4 : uint8_t
|
||||
Unary,
|
||||
|
||||
Binary,
|
||||
BinaryCompI32X4,
|
||||
BinaryCompF32X4,
|
||||
BinaryBitwise,
|
||||
BinaryShift,
|
||||
|
||||
@ -377,6 +379,43 @@ enum class F32X4 : uint8_t
|
||||
Bad
|
||||
};
|
||||
|
||||
enum class B32X4 : uint8_t
|
||||
{
|
||||
// Common opcodes
|
||||
GetLocal,
|
||||
SetLocal,
|
||||
|
||||
GetGlobal,
|
||||
SetGlobal,
|
||||
|
||||
CallInternal,
|
||||
CallIndirect,
|
||||
CallImport,
|
||||
|
||||
Conditional,
|
||||
Comma,
|
||||
|
||||
Literal,
|
||||
|
||||
// Specific opcodes
|
||||
Ctor,
|
||||
|
||||
Unary,
|
||||
|
||||
Binary,
|
||||
BinaryCompI32X4,
|
||||
BinaryCompF32X4,
|
||||
BinaryBitwise,
|
||||
|
||||
ReplaceLane,
|
||||
|
||||
Splat,
|
||||
|
||||
// asm.js specific
|
||||
Id,
|
||||
Bad
|
||||
};
|
||||
|
||||
enum NeedsBoundsCheck : uint8_t
|
||||
{
|
||||
NO_BOUNDS_CHECK,
|
||||
|
@ -129,6 +129,10 @@ class FunctionCompiler
|
||||
case ValType::F32x4:
|
||||
ins = MSimdConstant::New(alloc(), SimdConstant::CreateX4(v.f32x4()), MIRType_Float32x4);
|
||||
break;
|
||||
case ValType::B32x4:
|
||||
// Bool32x4 uses the same data layout as Int32x4.
|
||||
ins = MSimdConstant::New(alloc(), SimdConstant::CreateX4(v.i32x4()), MIRType_Bool32x4);
|
||||
break;
|
||||
}
|
||||
|
||||
curBlock_->add(ins);
|
||||
@ -315,7 +319,6 @@ class FunctionCompiler
|
||||
return nullptr;
|
||||
|
||||
MOZ_ASSERT(IsSimdType(mask->type()));
|
||||
MOZ_ASSERT(mask->type() == MIRType_Int32x4);
|
||||
MOZ_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
|
||||
MOZ_ASSERT(lhs->type() == type);
|
||||
MSimdSelect* ins = MSimdSelect::NewAsmJS(alloc(), mask, lhs, rhs, type);
|
||||
@ -323,6 +326,26 @@ class FunctionCompiler
|
||||
return ins;
|
||||
}
|
||||
|
||||
MDefinition* simdAllTrue(MDefinition* boolVector)
|
||||
{
|
||||
if (inDeadCode())
|
||||
return nullptr;
|
||||
|
||||
MSimdAllTrue* ins = MSimdAllTrue::NewAsmJS(alloc(), boolVector);
|
||||
curBlock_->add(ins);
|
||||
return ins;
|
||||
}
|
||||
|
||||
MDefinition* simdAnyTrue(MDefinition* boolVector)
|
||||
{
|
||||
if (inDeadCode())
|
||||
return nullptr;
|
||||
|
||||
MSimdAnyTrue* ins = MSimdAnyTrue::NewAsmJS(alloc(), boolVector);
|
||||
curBlock_->add(ins);
|
||||
return ins;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
MDefinition* convertSimd(MDefinition* vec, MIRType from, MIRType to)
|
||||
{
|
||||
@ -1290,6 +1313,12 @@ EmitLiteral(FunctionCompiler& f, ValType type, MDefinition**def)
|
||||
*def = f.constant(lit, MIRType_Float32x4);
|
||||
return true;
|
||||
}
|
||||
case ValType::B32x4: {
|
||||
// Boolean vectors are stored as an Int vector with -1 / 0 lanes.
|
||||
SimdConstant lit(f.readI32X4());
|
||||
*def = f.constant(lit, MIRType_Bool32x4);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("unexpected literal type");
|
||||
}
|
||||
@ -1317,7 +1346,9 @@ static bool EmitF32Expr(FunctionCompiler& f, MDefinition** def);
|
||||
static bool EmitF64Expr(FunctionCompiler& f, MDefinition** def);
|
||||
static bool EmitI32X4Expr(FunctionCompiler& f, MDefinition** def);
|
||||
static bool EmitF32X4Expr(FunctionCompiler& f, MDefinition** def);
|
||||
static bool EmitB32X4Expr(FunctionCompiler& f, MDefinition** def);
|
||||
static bool EmitExpr(FunctionCompiler& f, ValType type, MDefinition** def);
|
||||
static bool EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def);
|
||||
|
||||
static bool
|
||||
EmitLoadArray(FunctionCompiler& f, Scalar::Type scalarType, MDefinition** def)
|
||||
@ -1526,6 +1557,7 @@ EmitCallArgs(FunctionCompiler& f, const LifoSig& sig, FunctionCompiler::Call* ca
|
||||
case ValType::F64: if (!EmitF64Expr(f, &arg)) return false; break;
|
||||
case ValType::I32x4: if (!EmitI32X4Expr(f, &arg)) return false; break;
|
||||
case ValType::F32x4: if (!EmitF32X4Expr(f, &arg)) return false; break;
|
||||
case ValType::B32x4: if (!EmitB32X4Expr(f, &arg)) return false; break;
|
||||
}
|
||||
if (!f.passArg(arg, sig.arg(i), call))
|
||||
return false;
|
||||
@ -1734,6 +1766,7 @@ SimdToLaneType(ValType type)
|
||||
switch (type) {
|
||||
case ValType::I32x4: return ValType::I32;
|
||||
case ValType::F32x4: return ValType::F32;
|
||||
case ValType::B32x4: return ValType::I32; // Boolean lanes are Int32 in asm.
|
||||
case ValType::I32:
|
||||
case ValType::I64:
|
||||
case ValType::F32:
|
||||
@ -1789,8 +1822,12 @@ EmitSimdReplaceLane(FunctionCompiler& f, ValType simdType, MDefinition** def)
|
||||
}
|
||||
|
||||
MDefinition* scalar;
|
||||
if (!EmitExpr(f, SimdToLaneType(simdType), &scalar))
|
||||
return false;
|
||||
if (IsSimdBoolType(simdType)) {
|
||||
if (!EmitSimdBooleanLaneExpr(f, &scalar))
|
||||
return false;
|
||||
} else if (!EmitExpr(f, SimdToLaneType(simdType), &scalar)) {
|
||||
return false;
|
||||
}
|
||||
*def = f.insertElementSimd(vector, scalar, lane, ToMIRType(simdType));
|
||||
return true;
|
||||
}
|
||||
@ -1878,10 +1915,36 @@ EmitSimdStore(FunctionCompiler& f, ValType type, MDefinition** def)
|
||||
static bool
|
||||
EmitSimdSelect(FunctionCompiler& f, ValType type, MDefinition** def)
|
||||
{
|
||||
MDefinition* defs[3];
|
||||
if (!EmitI32X4Expr(f, &defs[0]) || !EmitExpr(f, type, &defs[1]) || !EmitExpr(f, type, &defs[2]))
|
||||
MDefinition* mask;
|
||||
MDefinition* defs[2];
|
||||
|
||||
// The mask is a boolean vector for elementwise select.
|
||||
if (!EmitB32X4Expr(f, &mask))
|
||||
return false;
|
||||
*def = f.selectSimd(defs[0], defs[1], defs[2], ToMIRType(type));
|
||||
|
||||
if (!EmitExpr(f, type, &defs[0]) || !EmitExpr(f, type, &defs[1]))
|
||||
return false;
|
||||
*def = f.selectSimd(mask, defs[0], defs[1], ToMIRType(type));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitSimdAllTrue(FunctionCompiler& f, ValType type, MDefinition** def)
|
||||
{
|
||||
MDefinition* in;
|
||||
if (!EmitExpr(f, type, &in))
|
||||
return false;
|
||||
*def = f.simdAllTrue(in);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitSimdAnyTrue(FunctionCompiler& f, ValType type, MDefinition** def)
|
||||
{
|
||||
MDefinition* in;
|
||||
if (!EmitExpr(f, type, &in))
|
||||
return false;
|
||||
*def = f.simdAnyTrue(in);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1895,6 +1958,16 @@ EmitSimdSplat(FunctionCompiler& f, ValType type, MDefinition** def)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitSimdBooleanSplat(FunctionCompiler& f, MDefinition** def)
|
||||
{
|
||||
MDefinition* in;
|
||||
if (!EmitSimdBooleanLaneExpr(f, &in))
|
||||
return false;
|
||||
*def = f.splatSimd(in, MIRType_Bool32x4);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitSimdCtor(FunctionCompiler& f, ValType type, MDefinition** def)
|
||||
{
|
||||
@ -1917,6 +1990,15 @@ EmitSimdCtor(FunctionCompiler& f, ValType type, MDefinition** def)
|
||||
*def = f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3], MIRType_Float32x4);
|
||||
return true;
|
||||
}
|
||||
case ValType::B32x4: {
|
||||
MDefinition* args[4];
|
||||
for (unsigned i = 0; i < 4; i++) {
|
||||
if (!EmitSimdBooleanLaneExpr(f, &args[i]))
|
||||
return false;
|
||||
}
|
||||
*def = f.constructSimd<MSimdValueX4>(args[0], args[1], args[2], args[3], MIRType_Bool32x4);
|
||||
return true;
|
||||
}
|
||||
case ValType::I32:
|
||||
case ValType::I64:
|
||||
case ValType::F32:
|
||||
@ -2177,10 +2259,24 @@ EmitExpr(FunctionCompiler& f, ValType type, MDefinition** def)
|
||||
case ValType::F64: return EmitF64Expr(f, def);
|
||||
case ValType::I32x4: return EmitI32X4Expr(f, def);
|
||||
case ValType::F32x4: return EmitF32X4Expr(f, def);
|
||||
case ValType::B32x4: return EmitB32X4Expr(f, def);
|
||||
}
|
||||
MOZ_CRASH("unexpected asm type");
|
||||
}
|
||||
|
||||
// Emit an I32 expression and then convert it to a boolean SIMD lane value, i.e. -1 or 0.
|
||||
static bool
|
||||
EmitSimdBooleanLaneExpr(FunctionCompiler& f, MDefinition** def)
|
||||
{
|
||||
MDefinition* i32;
|
||||
if (!EmitI32Expr(f, &i32))
|
||||
return false;
|
||||
// Now compute !i32 - 1 to force the value range into {0, -1}.
|
||||
MDefinition* noti32 = f.unary<MNot>(i32);
|
||||
*def = f.binary<MSub>(noti32, f.constant(Int32Value(1), MIRType_Int32), MIRType_Int32);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitInterruptCheck(FunctionCompiler& f)
|
||||
{
|
||||
@ -2480,6 +2576,7 @@ EmitStatement(FunctionCompiler& f, Stmt stmt, LabelVector* maybeLabels /*= nullp
|
||||
case Stmt::F64Expr: return EmitF64Expr(f, &_);
|
||||
case Stmt::I32X4Expr: return EmitI32X4Expr(f, &_);
|
||||
case Stmt::F32X4Expr: return EmitF32X4Expr(f, &_);
|
||||
case Stmt::B32X4Expr: return EmitB32X4Expr(f, &_);
|
||||
case Stmt::CallInternal: return EmitInternalCall(f, ExprType::Void, &_);
|
||||
case Stmt::CallIndirect: return EmitFuncPtrCall(f, ExprType::Void, &_);
|
||||
case Stmt::CallImport: return EmitFFICall(f, ExprType::Void, &_);
|
||||
@ -2623,6 +2720,12 @@ EmitI32Expr(FunctionCompiler& f, MDefinition** def)
|
||||
return EmitAtomicsBinOp(f, def);
|
||||
case I32::I32X4ExtractLane:
|
||||
return EmitExtractLane(f, ValType::I32x4, def);
|
||||
case I32::B32X4ExtractLane:
|
||||
return EmitExtractLane(f, ValType::B32x4, def);
|
||||
case I32::B32X4AllTrue:
|
||||
return EmitSimdAllTrue(f, ValType::B32x4, def);
|
||||
case I32::B32X4AnyTrue:
|
||||
return EmitSimdAnyTrue(f, ValType::B32x4, def);
|
||||
case I32::Bad:
|
||||
break;
|
||||
}
|
||||
@ -2810,10 +2913,6 @@ EmitI32X4Expr(FunctionCompiler& f, MDefinition** def)
|
||||
return EmitSimdBinaryArith(f, ValType::I32x4, def);
|
||||
case I32X4::BinaryBitwise:
|
||||
return EmitSimdBinaryBitwise(f, ValType::I32x4, def);
|
||||
case I32X4::BinaryCompI32X4:
|
||||
return EmitSimdBinaryComp(f, ValType::I32x4, def);
|
||||
case I32X4::BinaryCompF32X4:
|
||||
return EmitSimdBinaryComp(f, ValType::F32x4, def);
|
||||
case I32X4::BinaryShift:
|
||||
return EmitSimdBinaryShift(f, def);
|
||||
case I32X4::ReplaceLane:
|
||||
@ -2897,6 +2996,55 @@ EmitF32X4Expr(FunctionCompiler& f, MDefinition** def)
|
||||
MOZ_CRASH("unexpected float32x4 expression");
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitB32X4Expr(FunctionCompiler& f, MDefinition** def)
|
||||
{
|
||||
B32X4 op = B32X4(f.readU8());
|
||||
switch (op) {
|
||||
case B32X4::Id:
|
||||
return EmitB32X4Expr(f, def);
|
||||
case B32X4::GetLocal:
|
||||
return EmitGetLoc(f, DebugOnly<MIRType>(MIRType_Bool32x4), def);
|
||||
case B32X4::SetLocal:
|
||||
return EmitSetLoc(f, ValType::B32x4, def);
|
||||
case B32X4::GetGlobal:
|
||||
return EmitGetGlo(f, MIRType_Bool32x4, def);
|
||||
case B32X4::SetGlobal:
|
||||
return EmitSetGlo(f, ValType::B32x4, def);
|
||||
case B32X4::Comma:
|
||||
return EmitComma(f, ValType::B32x4, def);
|
||||
case B32X4::Conditional:
|
||||
return EmitConditional(f, ValType::B32x4, def);
|
||||
case B32X4::CallInternal:
|
||||
return EmitInternalCall(f, ExprType::B32x4, def);
|
||||
case B32X4::CallIndirect:
|
||||
return EmitFuncPtrCall(f, ExprType::B32x4, def);
|
||||
case B32X4::CallImport:
|
||||
return EmitFFICall(f, ExprType::B32x4, def);
|
||||
case B32X4::Literal:
|
||||
return EmitLiteral(f, ValType::B32x4, def);
|
||||
case B32X4::Ctor:
|
||||
return EmitSimdCtor(f, ValType::B32x4, def);
|
||||
case B32X4::Unary:
|
||||
return EmitSimdUnary(f, ValType::B32x4, def);
|
||||
case B32X4::Binary:
|
||||
return EmitSimdBinaryArith(f, ValType::B32x4, def);
|
||||
case B32X4::BinaryBitwise:
|
||||
return EmitSimdBinaryBitwise(f, ValType::B32x4, def);
|
||||
case B32X4::BinaryCompI32X4:
|
||||
return EmitSimdBinaryComp(f, ValType::I32x4, def);
|
||||
case B32X4::BinaryCompF32X4:
|
||||
return EmitSimdBinaryComp(f, ValType::F32x4, def);
|
||||
case B32X4::ReplaceLane:
|
||||
return EmitSimdReplaceLane(f, ValType::B32x4, def);
|
||||
case B32X4::Splat:
|
||||
return EmitSimdBooleanSplat(f, def);
|
||||
case B32X4::Bad:
|
||||
break;
|
||||
}
|
||||
MOZ_CRASH("unexpected bool32x4 expression");
|
||||
}
|
||||
|
||||
bool
|
||||
wasm::CompileFunction(CompileTask* task)
|
||||
{
|
||||
|
@ -190,6 +190,7 @@ GenerateEntry(MacroAssembler& masm, AsmJSModule& module, unsigned exportIndex,
|
||||
"EntryArg must be big enough to store SIMD values");
|
||||
switch (type) {
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
masm.loadUnalignedInt32x4(src, iter->fpu());
|
||||
break;
|
||||
case MIRType_Float32x4:
|
||||
@ -222,6 +223,7 @@ GenerateEntry(MacroAssembler& masm, AsmJSModule& module, unsigned exportIndex,
|
||||
masm.storeFloat32(ScratchFloat32Reg, Address(masm.getStackPointer(), iter->offsetFromArgBase()));
|
||||
break;
|
||||
case MIRType_Int32x4:
|
||||
case MIRType_Bool32x4:
|
||||
masm.loadUnalignedInt32x4(src, ScratchSimd128Reg);
|
||||
masm.storeAlignedInt32x4(ScratchSimd128Reg,
|
||||
Address(masm.getStackPointer(), iter->offsetFromArgBase()));
|
||||
@ -269,6 +271,7 @@ GenerateEntry(MacroAssembler& masm, AsmJSModule& module, unsigned exportIndex,
|
||||
masm.storeDouble(ReturnDoubleReg, Address(argv, 0));
|
||||
break;
|
||||
case ExprType::I32x4:
|
||||
case ExprType::B32x4:
|
||||
// We don't have control on argv alignment, do an unaligned access.
|
||||
masm.storeUnalignedInt32x4(ReturnSimd128Reg, Address(argv, 0));
|
||||
break;
|
||||
@ -549,6 +552,7 @@ GenerateInterpExit(MacroAssembler& masm, AsmJSModule& module, unsigned exitIndex
|
||||
break;
|
||||
case ExprType::I32x4:
|
||||
case ExprType::F32x4:
|
||||
case ExprType::B32x4:
|
||||
MOZ_CRASH("SIMD types shouldn't be returned from a FFI");
|
||||
}
|
||||
|
||||
@ -800,6 +804,7 @@ GenerateIonExit(MacroAssembler& masm, AsmJSModule& module, unsigned exitIndex,
|
||||
break;
|
||||
case ExprType::I32x4:
|
||||
case ExprType::F32x4:
|
||||
case ExprType::B32x4:
|
||||
MOZ_CRASH("SIMD types shouldn't be returned from a FFI");
|
||||
}
|
||||
|
||||
|
@ -58,6 +58,7 @@ var code = `
|
||||
|
||||
var i4 = global.SIMD.Int32x4;
|
||||
var f4 = global.SIMD.Float32x4;
|
||||
var b4 = global.SIMD.Bool32x4;
|
||||
var i4add = i4.add;
|
||||
var i4and = i4.and;
|
||||
var f4select = f4.select;
|
||||
@ -68,6 +69,7 @@ var code = `
|
||||
var f4splat = f4.splat;
|
||||
var f4load = f4.load;
|
||||
var f4store = f4.store;
|
||||
var b4any = b4.anyTrue;
|
||||
|
||||
const zerox4 = f4(0.0,0.0,0.0,0.0);
|
||||
|
||||
@ -95,7 +97,7 @@ var code = `
|
||||
var accelx4 = f4(0.0,0.0,0.0,0.0);
|
||||
var a = 0;
|
||||
var posDeltax4 = f4(0.0,0.0,0.0,0.0);
|
||||
var cmpx4 = i4(0,0,0,0);
|
||||
var cmpx4 = b4(0,0,0,0);
|
||||
var newVelTruex4 = f4(0.0,0.0,0.0,0.0);
|
||||
|
||||
steps = getAccelDataSteps | 0;
|
||||
@ -122,7 +124,7 @@ var code = `
|
||||
newVelx4 = f4add(newVelx4, f4mul(accelx4, subTimeDeltax4));
|
||||
cmpx4 = f4greaterThan(newPosx4, maxPosx4);
|
||||
|
||||
if (cmpx4.signMask) {
|
||||
if (b4any(cmpx4)) {
|
||||
// Work around unimplemented 'neg' operation, using 0 - x.
|
||||
newVelTruex4 = f4sub(zerox4, newVelx4);
|
||||
newVelx4 = f4select(cmpx4, newVelTruex4, newVelx4);
|
||||
|
@ -34,13 +34,16 @@ var moduleCode = `
|
||||
var i4add = i4.add;
|
||||
var i4and = i4.and;
|
||||
var i4ext = i4.extractLane;
|
||||
var i4sel = i4.select;
|
||||
var f4add = f4.add;
|
||||
var f4sub = f4.sub;
|
||||
var f4mul = f4.mul;
|
||||
var f4lessThanOrEqual = f4.lessThanOrEqual;
|
||||
var f4splat = f4.splat;
|
||||
var imul = global.Math.imul;
|
||||
const one4 = i4(1,1,1,1), two4 = f4(2,2,2,2), four4 = f4(4,4,4,4);
|
||||
var b4 = global.SIMD.Bool32x4;
|
||||
var b4any = b4.anyTrue;
|
||||
const zero4 = i4(0,0,0,0), one4 = i4(1,1,1,1), two4 = f4(2,2,2,2), four4 = f4(4,4,4,4);
|
||||
|
||||
const mk0 = 0x007fffff;
|
||||
|
||||
@ -85,7 +88,7 @@ var moduleCode = `
|
||||
var z_re24 = f4(0,0,0,0), z_im24 = f4(0,0,0,0);
|
||||
var new_re4 = f4(0,0,0,0), new_im4 = f4(0,0,0,0);
|
||||
var i = 0;
|
||||
var mi4 = i4(0,0,0,0);
|
||||
var mb4 = b4(0,0,0,0);
|
||||
|
||||
c_re4 = f4splat(xf);
|
||||
c_im4 = f4(yf, toF(yd + yf), toF(yd + toF(yd + yf)), toF(yd + toF(yd + toF(yd + yf))));
|
||||
@ -96,16 +99,16 @@ var moduleCode = `
|
||||
for (i = 0; (i | 0) < (max_iterations | 0); i = (i + 1) | 0) {
|
||||
z_re24 = f4mul(z_re4, z_re4);
|
||||
z_im24 = f4mul(z_im4, z_im4);
|
||||
mi4 = f4lessThanOrEqual(f4add(z_re24, z_im24), four4);
|
||||
mb4 = f4lessThanOrEqual(f4add(z_re24, z_im24), four4);
|
||||
// If all 4 values are greater than 4.0, there's no reason to continue.
|
||||
if ((mi4.signMask | 0) == 0x00)
|
||||
if (!b4any(mb4))
|
||||
break;
|
||||
|
||||
new_re4 = f4sub(z_re24, z_im24);
|
||||
new_im4 = f4mul(f4mul(two4, z_re4), z_im4);
|
||||
z_re4 = f4add(c_re4, new_re4);
|
||||
z_im4 = f4add(c_im4, new_im4);
|
||||
count4 = i4add(count4, i4and(mi4, one4));
|
||||
count4 = i4add(count4, i4sel(mb4, one4, zero4));
|
||||
}
|
||||
return ci4(count4);
|
||||
}
|
||||
|
@ -23,9 +23,16 @@ const F32S = 'var f4s = f4.sub;'
|
||||
const F32M = 'var f4m = f4.mul;'
|
||||
const F32D = 'var f4d = f4.div;'
|
||||
const FROUND = 'var f32=glob.Math.fround;'
|
||||
const B32 = 'var b4 = glob.SIMD.Bool32x4;'
|
||||
const CB32 = 'var cb4 = b4.check;'
|
||||
|
||||
const EXTI4 = 'var e = i4.extractLane;'
|
||||
const EXTF4 = 'var e = f4.extractLane;'
|
||||
const EXTB4 = 'var e = b4.extractLane;'
|
||||
|
||||
// anyTrue / allTrue on boolean vectors.
|
||||
const ANYB4 = 'var anyt=b4.anyTrue;'
|
||||
const ALLB4 = 'var allt=b4.allTrue;'
|
||||
|
||||
const INT32_MAX = Math.pow(2, 31) - 1;
|
||||
const INT32_MIN = INT32_MAX + 1 | 0;
|
||||
@ -46,6 +53,13 @@ function CheckF4(header, code, expected) {
|
||||
assertEqX4(observed, expected.map(Math.fround));
|
||||
}
|
||||
|
||||
function CheckB4(header, code, expected) {
|
||||
// code needs to contain a local called x
|
||||
header = USE_ASM + B32 + CB32 + header;
|
||||
var observed = asmLink(asmCompile('glob', header + ';function f() {' + code + ';return cb4(x)} return f'), this)();
|
||||
assertEqX4(observed, expected);
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// 1. Constructors
|
||||
@ -137,6 +151,8 @@ assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + I32 + CI32 + "var
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + F32 + CF32 + FROUND + "var h=new glob.Float32Array(heap); function f(i) {i=i|0; return cf4(f4(h[i>>2], f32(2), f32(3), f32(4)))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [NaN, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + FROUND + "function f(i) {i=i|0; return cf4(f4(f32(1) + f32(2), f32(2), f32(3), f32(4)))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + FROUND + "function f(i) {i=i|0; return cf4(f4(f32(1) + f32(2), 2.0, 3.0, 4.0))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [3, 2, 3, 4]);
|
||||
// Bool32x4 ctor should accept int?
|
||||
assertEqX4(asmLink(asmCompile('glob', 'ffi', 'heap', USE_ASM + B32 + CB32 + "var i32=new glob.Int32Array(heap); function f(i) {i=i|0; return cb4(b4(i32[i>>2], 2, 0, 4))} return f"), this, {}, new ArrayBuffer(0x10000))(0x20000), [false, true, false, true]);
|
||||
|
||||
// 1.3.2 Getters - Reading values out of lanes
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + EXTI4 + "function f() {var x=1; return e(x,1) | 0;} return f");
|
||||
@ -162,8 +178,8 @@ assertAsmTypeFail('glob', USE_ASM + FROUND + "function f() {var x=f32(42.); retu
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + 'function f() { var x=i4(1,2,3,4); return x.signMask | 0 } return f');
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + FROUND + 'var Infinity = glob.Infinity; function f() { var x=f4(0,0,0,0); x=f4(f32(1), f32(-13.37), f32(42), f32(-Infinity)); return x.signMask | 0 } return f');
|
||||
|
||||
// signMask
|
||||
function CheckSignMask(innerBody, type, expected) {
|
||||
// Check lane extraction.
|
||||
function CheckLanes(innerBody, type, expected) {
|
||||
var coerceBefore, coerceAfter, extractLane;
|
||||
|
||||
if (type === SIMD.Int32x4) {
|
||||
@ -175,38 +191,46 @@ function CheckSignMask(innerBody, type, expected) {
|
||||
coerceAfter = '';
|
||||
extractLane = 'ef';
|
||||
expected = expected.map(Math.fround);
|
||||
} else throw "unexpected type in CheckSignMask";
|
||||
} else if (type === SIMD.Bool32x4) {
|
||||
coerceBefore = '';
|
||||
coerceAfter = '|0';
|
||||
extractLane = 'eb';
|
||||
} else throw "unexpected type in CheckLanes";
|
||||
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var lane = i;
|
||||
var laneCheckCode = `"use asm";
|
||||
var i4=glob.SIMD.Int32x4;
|
||||
var f4=glob.SIMD.Float32x4;
|
||||
var b4=glob.SIMD.Bool32x4;
|
||||
var ei=i4.extractLane;
|
||||
var ef=f4.extractLane;
|
||||
var eb=b4.extractLane;
|
||||
function f() {${innerBody}; return ${coerceBefore}${extractLane}(x, ${lane})${coerceAfter} }
|
||||
return f;`;
|
||||
assertEq(asmLink(asmCompile('glob', laneCheckCode), this)(), expected[i]);
|
||||
}
|
||||
}
|
||||
function CheckSignMaskI4(innerBody, expected) { return CheckSignMask(innerBody, SIMD.Int32x4, expected); }
|
||||
function CheckSignMaskF4(innerBody, expected) { return CheckSignMask(innerBody, SIMD.Float32x4, expected); }
|
||||
function CheckLanesI4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Int32x4, expected); }
|
||||
function CheckLanesF4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Float32x4, expected); }
|
||||
function CheckLanesB4(innerBody, expected) { return CheckLanes(innerBody, SIMD.Bool32x4, expected); }
|
||||
|
||||
CheckSignMaskI4('var x=i4(0,0,0,0);', [0,0,0,0]);
|
||||
CheckSignMaskI4('var x=i4(1,2,3,4);', [1,2,3,4]);
|
||||
CheckSignMaskI4('var x=i4(' + INT32_MIN + ',2,3,' + INT32_MAX + ')', [INT32_MIN,2,3,INT32_MAX]);
|
||||
CheckSignMaskI4('var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]);
|
||||
CheckSignMaskI4('var a=1; var b=i4(9,8,7,6); var c=13.37; var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]);
|
||||
CheckSignMaskI4('var y=i4(5,6,7,8); var x=i4(1,2,3,4)', [1,2,3,4]);
|
||||
CheckLanesI4('var x=i4(0,0,0,0);', [0,0,0,0]);
|
||||
CheckLanesI4('var x=i4(1,2,3,4);', [1,2,3,4]);
|
||||
CheckLanesI4('var x=i4(' + INT32_MIN + ',2,3,' + INT32_MAX + ')', [INT32_MIN,2,3,INT32_MAX]);
|
||||
CheckLanesI4('var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]);
|
||||
CheckLanesI4('var a=1; var b=i4(9,8,7,6); var c=13.37; var x=i4(1,2,3,4); var y=i4(5,6,7,8)', [1,2,3,4]);
|
||||
CheckLanesI4('var y=i4(5,6,7,8); var x=i4(1,2,3,4)', [1,2,3,4]);
|
||||
|
||||
CheckSignMaskF4('var x=f4(' + INT32_MAX + ', 2, 3, ' + INT32_MIN + ')', [INT32_MAX, 2, 3, INT32_MIN]);
|
||||
CheckSignMaskF4('var x=f4(' + (INT32_MAX + 1) + ', 2, 3, 4)', [INT32_MAX + 1, 2, 3, 4]);
|
||||
CheckSignMaskF4('var x=f4(1.3, 2.4, 3.5, 98.76)', [1.3, 2.4, 3.5, 98.76]);
|
||||
CheckSignMaskF4('var x=f4(13.37, 2., 3., -0)', [13.37, 2, 3, -0]);
|
||||
CheckLanesF4('var x=f4(' + INT32_MAX + ', 2, 3, ' + INT32_MIN + ')', [INT32_MAX, 2, 3, INT32_MIN]);
|
||||
CheckLanesF4('var x=f4(' + (INT32_MAX + 1) + ', 2, 3, 4)', [INT32_MAX + 1, 2, 3, 4]);
|
||||
CheckLanesF4('var x=f4(1.3, 2.4, 3.5, 98.76)', [1.3, 2.4, 3.5, 98.76]);
|
||||
CheckLanesF4('var x=f4(13.37, 2., 3., -0)', [13.37, 2, 3, -0]);
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); var y=0.0; y=x.signMask;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f() {var x=i4(1,2,3,4); return (x.signMask > (1>>>0)) | 0;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + "function f() {var x=i4(1,2,3,4); var y=f32(0.0); y=x.signMask;} return f");
|
||||
CheckLanesB4('var x=b4(0,0,0,0);', [0,0,0,0]);
|
||||
CheckLanesB4('var x=b4(0,1,0,0);', [0,1,0,0]);
|
||||
CheckLanesB4('var x=b4(0,2,0,0);', [0,1,0,0]);
|
||||
CheckLanesB4('var x=b4(-1,0,1,-1);', [1,0,1,1]);
|
||||
|
||||
// 1.3.3. Variable assignments
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + I32A + "function f() {var x=i4(1,2,3,4); x=i4();} return f");
|
||||
@ -256,6 +280,7 @@ assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + "function f() {var x=f4(1,2,3,4); var c=4; x=1?c:x;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4); var y=i4(1,2,3,4); x=1?x:y;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + I32 + "function f() {var x=f4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + B32 + I32 + "function f() {var x=b4(1,2,3,4); var y=i4(1,2,3,4); x=1?y:y;} return f");
|
||||
|
||||
CheckF4('', 'var x=f4(1,2,3,4); var y=f4(4,3,2,1); x=3?y:x', [4, 3, 2, 1]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=x|0; var v=f4(1,2,3,4); var w=f4(5,6,7,8); return cf4(x?w:v);} return f"), this)(1), [5,6,7,8]);
|
||||
@ -275,6 +300,7 @@ assertAsmTypeFail('glob', USE_ASM + I32 + CI32 + FROUND + "function f() {var x=f
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f() {var x=i4(1,2,3,4); return ci4(x)} return f"), this)(), [1,2,3,4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f() {var x=f4(1,2,3,4); return cf4(x)} return f"), this)(), [1,2,3,4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + "function f() {var x=b4(1,2,0,4); return cb4(x)} return f"), this)(), [true,true,false,true]);
|
||||
|
||||
// 1.3.5 Coerce and pass arguments
|
||||
// Via check
|
||||
@ -302,6 +328,10 @@ var f32x4 = SIMD.Float32x4(13.37, 42.42, -0, NaN);
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x)} return f"), this)(f32x4), undefined);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + "function f(x) {x=cf4(x); return cf4(x);} return f"), this)(f32x4), [13.37, 42.42, -0, NaN].map(Math.fround));
|
||||
|
||||
var b32x4 = SIMD.Bool32x4(true, false, false, true);
|
||||
assertEq(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + "function f(x) {x=cb4(x)} return f"), this)(b32x4), undefined);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + "function f(x) {x=cb4(x); return cb4(x);} return f"), this)(b32x4), [true, false, false, true]);
|
||||
|
||||
// Legacy coercions
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4();} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "function f(x) {x=i4(x);} return f");
|
||||
@ -334,6 +364,7 @@ assertCaught(f, 1);
|
||||
assertCaught(f, {});
|
||||
assertCaught(f, "I sincerely am a SIMD typed object.");
|
||||
assertCaught(f, SIMD.Int32x4(1,2,3,4));
|
||||
assertCaught(f, SIMD.Bool32x4(true, true, false, true));
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + "function f(x) {x=ci4(x); return ci4(x);} return f"), this);
|
||||
assertCaught(f);
|
||||
@ -341,6 +372,15 @@ assertCaught(f, 1);
|
||||
assertCaught(f, {});
|
||||
assertCaught(f, "I sincerely am a SIMD typed object.");
|
||||
assertCaught(f, SIMD.Float32x4(4,3,2,1));
|
||||
assertCaught(f, SIMD.Bool32x4(true, true, false, true));
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + "function f(x) {x=cb4(x); return cb4(x);} return f"), this);
|
||||
assertCaught(f);
|
||||
assertCaught(f, 1);
|
||||
assertCaught(f, {});
|
||||
assertCaught(f, "I sincerely am a SIMD typed object.");
|
||||
assertCaught(f, SIMD.Int32x4(1,2,3,4));
|
||||
assertCaught(f, SIMD.Float32x4(4,3,2,1));
|
||||
|
||||
// 1.3.6 Globals
|
||||
// 1.3.6.1 Local globals
|
||||
@ -371,6 +411,9 @@ CheckF4('var x=f4(1.,2.,3.,4.)', '', [1, 2, 3, 4]);
|
||||
CheckF4('var _=42; var h=f4(5.,5.,5.,5.); var __=13.37; var x=f4(4.,13.37,9.,-0.);', '', [4, 13.37, 9, -0]);
|
||||
CheckF4('var x=f4(1,2,3,4)', '', [1, 2, 3, 4]);
|
||||
|
||||
CheckB4('var x=b4(1,0,3,0)', '', [true, false, true, false]);
|
||||
CheckB4('var _=42; var h=b4(5,0,5,5); var __=13.37; var x=b4(0,0,9,2);', '', [false, false, true, true]);
|
||||
|
||||
// Write
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4; g=x|0;} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + "var g=i4(1,2,3,4); function f() {var x=4.; g=+x;} return f");
|
||||
@ -387,9 +430,11 @@ assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + "var g=i4(1,2,3,4); funct
|
||||
|
||||
CheckI4('var x=i4(0,0,0,0);', 'x=i4(1,2,3,4)', [1,2,3,4]);
|
||||
CheckF4('var x=f4(0.,0.,0.,0.);', 'x=f4(5.,3.,4.,2.)', [5,3,4,2]);
|
||||
CheckB4('var x=b4(0,0,0,0);', 'x=b4(0,0,1,1)', [false, false, true, true]);
|
||||
|
||||
CheckI4('var x=i4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=i4(1,2,3,4); y=24; z=4.9; w=23.10;', [1,2,3,4]);
|
||||
CheckF4('var x=f4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=f4(1,2,3,4); y=24; z=4.9; w=23.10;', [1,2,3,4]);
|
||||
CheckB4('var x=b4(0,0,0,0); var y=42; var z=3.9; var w=13.37', 'x=b4(1,0,0,0); y=24; z=4.9; w=23.10;', [true, false, false, false]);
|
||||
|
||||
// 1.3.6.2 Imported globals
|
||||
// Read
|
||||
@ -411,6 +456,15 @@ assertEq(SIMD.Float32x4.extractLane(Float32x4, 3), 4);
|
||||
for (var v of [1, {}, "totally legit SIMD variable", SIMD.Int32x4(1,2,3,4)])
|
||||
assertCaught(asmCompile('glob', 'ffi', USE_ASM + F32 + CF32 + "var g=cf4(ffi.g); function f() {return cf4(g)} return f"), this, {g: v});
|
||||
|
||||
var Bool32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + "var g=cb4(ffi.g); function f() {return cb4(g)} return f"), this, {g: SIMD.Bool32x4(false, false, false, true)})();
|
||||
assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 0), false);
|
||||
assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 1), false);
|
||||
assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 2), false);
|
||||
assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 3), true);
|
||||
|
||||
for (var v of [1, {}, "totally legit SIMD variable", SIMD.Int32x4(1,2,3,4)])
|
||||
assertCaught(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + "var g=cb4(ffi.g); function f() {return cb4(g)} return f"), this, {g: v});
|
||||
|
||||
// Write
|
||||
var Int32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + I32 + CI32 + "var g=ci4(ffi.g); function f() {g=i4(4,5,6,7); return ci4(g)} return f"), this, {g: SIMD.Int32x4(1,2,3,4)})();
|
||||
assertEq(SIMD.Int32x4.extractLane(Int32x4, 0), 4);
|
||||
@ -424,6 +478,12 @@ assertEq(SIMD.Float32x4.extractLane(Float32x4, 1), 5);
|
||||
assertEq(SIMD.Float32x4.extractLane(Float32x4, 2), 6);
|
||||
assertEq(SIMD.Float32x4.extractLane(Float32x4, 3), 7);
|
||||
|
||||
var Bool32x4 = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + "var g=cb4(ffi.g); function f() {g=b4(1,1,0,0); return cb4(g)} return f"), this, {g: SIMD.Bool32x4(1,1,1,0)})();
|
||||
assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 0), true);
|
||||
assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 1), true);
|
||||
assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 2), false);
|
||||
assertEq(SIMD.Bool32x4.extractLane(Bool32x4, 3), false);
|
||||
|
||||
// 2. SIMD operations
|
||||
// 2.1 Compilation
|
||||
assertAsmTypeFail('glob', USE_ASM + "var add = Int32x4.add; return {}");
|
||||
@ -560,9 +620,22 @@ function CheckUnaryI4(op, checkFunc) {
|
||||
}
|
||||
}
|
||||
|
||||
function CheckUnaryB4(op, checkFunc) {
|
||||
var _ = asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + 'var op=b4.' + op + '; function f(x){x=cb4(x); return cb4(op(x)); } return f'), this);
|
||||
return function(input) {
|
||||
var simd = SIMD.Bool32x4(input[0], input[1], input[2], input[3]);
|
||||
assertEqX4(_(simd), input.map(checkFunc).map(function(x) { return !!x}));
|
||||
}
|
||||
}
|
||||
|
||||
CheckUnaryI4('neg', function(x) { return -x })([1, -2, INT32_MIN, INT32_MAX]);
|
||||
CheckUnaryI4('not', function(x) { return ~x })([1, -2, INT32_MIN, INT32_MAX]);
|
||||
|
||||
var CheckNotB = CheckUnaryB4('not', function(x) { return !x });
|
||||
CheckNotB([true, false, true, true]);
|
||||
CheckNotB([true, true, true, true]);
|
||||
CheckNotB([false, false, false, false]);
|
||||
|
||||
var CheckAbs = CheckUnaryF4('abs', Math.abs);
|
||||
CheckAbs([1, 42.42, 0.63, 13.37]);
|
||||
CheckAbs([NaN, -Infinity, Infinity, 0]);
|
||||
@ -658,11 +731,16 @@ CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 1, 42);', [1, 42, 3, 4]);
|
||||
CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 2, 42);', [1, 2, 42, 4]);
|
||||
CheckI4(RLI, 'var x = i4(1,2,3,4); x = r(x, 3, 42);', [1, 2, 3, 42]);
|
||||
|
||||
const RLB = 'var r = b4.replaceLane;';
|
||||
CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 0, 0);', [false, true, false, false]);
|
||||
CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 1, 0);', [true, false, false, false]);
|
||||
CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 2, 2);', [true, true, true, false]);
|
||||
CheckB4(RLB, 'var x = b4(1,1,0,0); x = r(x, 3, 1);', [true, true, false, true]);
|
||||
|
||||
// Comparisons
|
||||
// True yields all bits set to 1 (i.e as an int32, 0xFFFFFFFF === -1), false
|
||||
// yields all bits set to 0 (i.e 0).
|
||||
const T = -1;
|
||||
const F = 0;
|
||||
// Comparison operators produce Bool32x4 vectors.
|
||||
const T = true;
|
||||
const F = false;
|
||||
|
||||
const EQI32 = 'var eq = i4.equal';
|
||||
const NEI32 = 'var ne = i4.notEqual';
|
||||
@ -671,29 +749,29 @@ const LEI32 = 'var le = i4.lessThanOrEqual';
|
||||
const GTI32 = 'var gt = i4.greaterThan;';
|
||||
const GEI32 = 'var ge = i4.greaterThanOrEqual';
|
||||
|
||||
CheckI4(EQI32, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=eq(x,y)', [F, F, F, F]);
|
||||
CheckI4(EQI32, 'var x=i4(-1,1,0,2); var y=i4(1,2,3,4); x=eq(x,y)', [F, F, F, F]);
|
||||
CheckI4(EQI32, 'var x=i4(1,0,3,4); var y=i4(1,1,7,0); x=eq(x,y)', [T, F, F, F]);
|
||||
CheckB4(I32+EQI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=eq(a,b)', [F, F, F, F]);
|
||||
CheckB4(I32+EQI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=eq(a,b)', [F, F, F, F]);
|
||||
CheckB4(I32+EQI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=eq(a,b)', [T, F, F, F]);
|
||||
|
||||
CheckI4(NEI32, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=ne(x,y)', [T, T, T, T]);
|
||||
CheckI4(NEI32, 'var x=i4(-1,1,0,2); var y=i4(1,2,3,4); x=ne(x,y)', [T, T, T, T]);
|
||||
CheckI4(NEI32, 'var x=i4(1,0,3,4); var y=i4(1,1,7,0); x=ne(x,y)', [F, T, T, T]);
|
||||
CheckB4(I32+NEI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=ne(a,b)', [T, T, T, T]);
|
||||
CheckB4(I32+NEI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=ne(a,b)', [T, T, T, T]);
|
||||
CheckB4(I32+NEI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=ne(a,b)', [F, T, T, T]);
|
||||
|
||||
CheckI4(LTI32, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=lt(x,y)', [F, F, F, F]);
|
||||
CheckI4(LTI32, 'var x=i4(-1,1,0,2); var y=i4(1,2,3,4); x=lt(x,y)', [T, T, T, T]);
|
||||
CheckI4(LTI32, 'var x=i4(1,0,3,4); var y=i4(1,1,7,0); x=lt(x,y)', [F, T, T, F]);
|
||||
CheckB4(I32+LTI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=lt(a,b)', [F, F, F, F]);
|
||||
CheckB4(I32+LTI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=lt(a,b)', [T, T, T, T]);
|
||||
CheckB4(I32+LTI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=lt(a,b)', [F, T, T, F]);
|
||||
|
||||
CheckI4(LEI32, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=le(x,y)', [F, F, F, F]);
|
||||
CheckI4(LEI32, 'var x=i4(-1,1,0,2); var y=i4(1,2,3,4); x=le(x,y)', [T, T, T, T]);
|
||||
CheckI4(LEI32, 'var x=i4(1,0,3,4); var y=i4(1,1,7,0); x=le(x,y)', [T, T, T, F]);
|
||||
CheckB4(I32+LEI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=le(a,b)', [F, F, F, F]);
|
||||
CheckB4(I32+LEI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=le(a,b)', [T, T, T, T]);
|
||||
CheckB4(I32+LEI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=le(a,b)', [T, T, T, F]);
|
||||
|
||||
CheckI4(GTI32, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=gt(x,y)', [T, T, T, T]);
|
||||
CheckI4(GTI32, 'var x=i4(-1,1,0,2); var y=i4(1,2,3,4); x=gt(x,y)', [F, F, F, F]);
|
||||
CheckI4(GTI32, 'var x=i4(1,0,3,4); var y=i4(1,1,7,0); x=gt(x,y)', [F, F, F, T]);
|
||||
CheckB4(I32+GTI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=gt(a,b)', [T, T, T, T]);
|
||||
CheckB4(I32+GTI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=gt(a,b)', [F, F, F, F]);
|
||||
CheckB4(I32+GTI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=gt(a,b)', [F, F, F, T]);
|
||||
|
||||
CheckI4(GEI32, 'var x=i4(1,2,3,4); var y=i4(-1,1,0,2); x=ge(x,y)', [T, T, T, T]);
|
||||
CheckI4(GEI32, 'var x=i4(-1,1,0,2); var y=i4(1,2,3,4); x=ge(x,y)', [F, F, F, F]);
|
||||
CheckI4(GEI32, 'var x=i4(1,0,3,4); var y=i4(1,1,7,0); x=ge(x,y)', [T, F, F, T]);
|
||||
CheckB4(I32+GEI32, 'var x=b4(0,0,0,0); var a=i4(1,2,3,4); var b=i4(-1,1,0,2); x=ge(a,b)', [T, T, T, T]);
|
||||
CheckB4(I32+GEI32, 'var x=b4(0,0,0,0); var a=i4(-1,1,0,2); var b=i4(1,2,3,4); x=ge(a,b)', [F, F, F, F]);
|
||||
CheckB4(I32+GEI32, 'var x=b4(0,0,0,0); var a=i4(1,0,3,4); var b=i4(1,1,7,0); x=ge(a,b)', [T, F, F, T]);
|
||||
|
||||
const LTF32 = 'var lt=f4.lessThan;';
|
||||
const LEF32 = 'var le=f4.lessThanOrEqual;';
|
||||
@ -704,35 +782,45 @@ const NEF32 = 'var ne=f4.notEqual;';
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + "var lt=f4.lessThan; function f() {var x=f4(1,2,3,4); var y=f4(5,6,7,8); x=lt(x,y);} return f");
|
||||
|
||||
CheckI4(LTF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=lt(y,z)', [F, F, F, F]);
|
||||
CheckI4(LTF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=lt(y,z)', [T, T, T, T]);
|
||||
CheckI4(LTF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=lt(y,z)', [F, T, T, F]);
|
||||
CheckI4(LTF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=lt(y,z);', [F, F, F, F]);
|
||||
CheckB4(F32+LTF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=lt(y,z)', [F, F, F, F]);
|
||||
CheckB4(F32+LTF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=lt(y,z)', [T, T, T, T]);
|
||||
CheckB4(F32+LTF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=lt(y,z)', [F, T, T, F]);
|
||||
CheckB4(F32+LTF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=lt(y,z);', [F, F, F, F]);
|
||||
|
||||
CheckI4(LEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=le(y,z)', [F, F, F, F]);
|
||||
CheckI4(LEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=le(y,z)', [T, T, T, T]);
|
||||
CheckI4(LEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=le(y,z)', [T, T, T, F]);
|
||||
CheckI4(LEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=le(y,z);', [T, T, F, F]);
|
||||
CheckB4(F32+LEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=le(y,z)', [F, F, F, F]);
|
||||
CheckB4(F32+LEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=le(y,z)', [T, T, T, T]);
|
||||
CheckB4(F32+LEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=le(y,z)', [T, T, T, F]);
|
||||
CheckB4(F32+LEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=le(y,z);', [T, T, F, F]);
|
||||
|
||||
CheckI4(EQF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=eq(y,z)', [F, F, F, F]);
|
||||
CheckI4(EQF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=eq(y,z)', [F, F, F, F]);
|
||||
CheckI4(EQF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=eq(y,z)', [T, F, F, F]);
|
||||
CheckI4(EQF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=eq(y,z);', [T, T, F, F]);
|
||||
CheckB4(F32+EQF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=eq(y,z)', [F, F, F, F]);
|
||||
CheckB4(F32+EQF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=eq(y,z)', [F, F, F, F]);
|
||||
CheckB4(F32+EQF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=eq(y,z)', [T, F, F, F]);
|
||||
CheckB4(F32+EQF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=eq(y,z);', [T, T, F, F]);
|
||||
|
||||
CheckI4(NEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=ne(y,z)', [T, T, T, T]);
|
||||
CheckI4(NEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=ne(y,z)', [T, T, T, T]);
|
||||
CheckI4(NEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=ne(y,z)', [F, T, T, T]);
|
||||
CheckI4(NEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=ne(y,z);', [F, F, T, T]);
|
||||
CheckB4(F32+NEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=ne(y,z)', [T, T, T, T]);
|
||||
CheckB4(F32+NEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=ne(y,z)', [T, T, T, T]);
|
||||
CheckB4(F32+NEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=ne(y,z)', [F, T, T, T]);
|
||||
CheckB4(F32+NEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=ne(y,z);', [F, F, T, T]);
|
||||
|
||||
CheckI4(GTF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=gt(y,z)', [T, T, T, T]);
|
||||
CheckI4(GTF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=gt(y,z)', [F, F, F, F]);
|
||||
CheckI4(GTF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=gt(y,z)', [F, F, F, T]);
|
||||
CheckI4(GTF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=gt(y,z);', [F, F, F, F]);
|
||||
CheckB4(F32+GTF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=gt(y,z)', [T, T, T, T]);
|
||||
CheckB4(F32+GTF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=gt(y,z)', [F, F, F, F]);
|
||||
CheckB4(F32+GTF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=gt(y,z)', [F, F, F, T]);
|
||||
CheckB4(F32+GTF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=gt(y,z);', [F, F, F, F]);
|
||||
|
||||
CheckI4(GEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=i4(0,0,0,0); x=ge(y,z)', [T, T, T, T]);
|
||||
CheckI4(GEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=i4(0,0,0,0); x=ge(y,z)', [F, F, F, F]);
|
||||
CheckI4(GEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=i4(0,0,0,0); x=ge(y,z)', [T, F, F, T]);
|
||||
CheckI4(GEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=i4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=ge(y,z);', [T, T, F, F]);
|
||||
CheckB4(F32+GEF32, 'var y=f4(1,2,3,4); var z=f4(-1,1,0,2); var x=b4(0,0,0,0); x=ge(y,z)', [T, T, T, T]);
|
||||
CheckB4(F32+GEF32, 'var y=f4(-1,1,0,2); var z=f4(1,2,3,4); var x=b4(0,0,0,0); x=ge(y,z)', [F, F, F, F]);
|
||||
CheckB4(F32+GEF32, 'var y=f4(1,0,3,4); var z=f4(1,1,7,0); var x=b4(0,0,0,0); x=ge(y,z)', [T, F, F, T]);
|
||||
CheckB4(F32+GEF32 + 'const nan = glob.NaN; const fround=glob.Math.fround', 'var y=f4(0,0,0,0); var z=f4(0,0,0,0); var x=b4(0,0,0,0); y=f4(fround(0.0),fround(-0.0),fround(0.0),fround(nan)); z=f4(fround(-0.0),fround(0.0),fround(nan),fround(0.0)); x=ge(y,z);', [T, T, F, F]);
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + LTI32 + B32 + ANYB4 + 'function f(x){x=ci4(x); var y=i4(-1,0,4,5); var b=b4(0,0,0,0); b=lt(x,y); return anyt(b)|0;} return f'), this);
|
||||
assertEq(f(SIMD.Int32x4(1,2,3,4)), 1);
|
||||
assertEq(f(SIMD.Int32x4(1,2,4,5)), 0);
|
||||
assertEq(f(SIMD.Int32x4(1,2,3,5)), 1);
|
||||
|
||||
var f = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + LTI32 + B32 + ALLB4 + 'function f(x){x=ci4(x); var y=i4(-1,0,4,5); var b=b4(0,0,0,0); b=lt(x,y); return allt(b)|0;} return f'), this);
|
||||
assertEq(f(SIMD.Int32x4(-2,-2,3,4)), 1);
|
||||
assertEq(f(SIMD.Int32x4(1,2,4,5)), 0);
|
||||
assertEq(f(SIMD.Int32x4(1,2,3,5)), 0);
|
||||
|
||||
// Conversions operators
|
||||
const CVTIF = 'var cvt=f4.fromInt32x4;';
|
||||
@ -815,6 +903,14 @@ CheckI4(ANDI32, 'var x=i4(42,1337,-1,13); var y=i4(2, 4, 7, 15); x=andd(x,y)', [
|
||||
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]);
|
||||
|
||||
const ANDB32 = 'var andd=b4.and;';
|
||||
const ORB32 = 'var orr=b4.or;';
|
||||
const XORB32 = 'var xorr=b4.xor;';
|
||||
|
||||
CheckB4(ANDB32, 'var x=b4(1,0,1,0); var y=b4(1,1,0,0); x=andd(x,y)', [true, false, false, false]);
|
||||
CheckB4(ORB32, ' var x=b4(1,0,1,0); var y=b4(1,1,0,0); x=orr(x,y)', [true, true, true, false]);
|
||||
CheckB4(XORB32, 'var x=b4(1,0,1,0); var y=b4(1,1,0,0); x=xorr(x,y)', [false, true, true, false]);
|
||||
|
||||
// No bitwise ops on Float32x4.
|
||||
const ANDF32 = 'var andd=f4.and;';
|
||||
const ORF32 = 'var orr=f4.or;';
|
||||
@ -863,15 +959,17 @@ for (var i = 1; i < 64; i++) {
|
||||
// Select
|
||||
const I32SEL = 'var i4sel = i4.select;'
|
||||
const F32SEL = 'var f4sel = f4.select;'
|
||||
const I32BSEL = 'var i4sel = i4.selectBits;'
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var x=f4(1,2,3,4); return ci4(i4sel(x,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=i4(1,2,3,4); var y=f4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var x=f4(1,2,3,4); return ci4(i4sel(x,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=i4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=f4(1,2,3,4); return ci4(i4sel(m,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=f4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=i4(1,2,3,4); var y=f4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,2,3,4); var x=i4(1,2,3,4); var y=b4(5,6,7,8); return ci4(i4sel(m,x,y));} return f");
|
||||
|
||||
assertAsmTypeFail('glob', USE_ASM + F32 + CF32 + F32SEL + "function f() {var m=f4(1,2,3,4); return cf4(f4sel(x,x,x));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return cf4(f4sel(m,x,x));} return f");
|
||||
@ -879,56 +977,20 @@ assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {v
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); var y=i4(5,6,7,8); return cf4(f4sel(m,x,y));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(1,2,3,4); var x=i4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y));} return f");
|
||||
|
||||
// These pass with select but not selectBits
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(-1,-2,-3,-42); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(1,-1,2,-2); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(42,45,-42,-47); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + CI32 + I32SEL + "function f() {var m=b4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + CI32 + I32SEL + "function f() {var m=b4(1,1,1,1); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + CI32 + I32SEL + "function f() {var m=b4(0,1,0,1); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + CI32 + I32SEL + "function f() {var m=b4(0,0,1,1); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(-1,-2,-3,-42); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(1,-1,2,-2); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(42,45,-42,-47); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
// These pass for both select and selectBits
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32SEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + F32SEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + 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 cf4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + F32 + CF32 + 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 cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f() {var m=i4(0,0,0,0); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f() {var m=i4(0xffffffff,0xffffffff,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f() {var m=i4(0,0xffffffff,0,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f() {var m=i4(0,0,0xffffffff,0xffffffff); var x=i4(1,2,3,4); var y=i4(5,6,7,8); return ci4(i4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
// Specific selectBits tests
|
||||
var masks = [
|
||||
SIMD.Int32x4(1337, 0x1337, 0x42, 42),
|
||||
SIMD.Int32x4(0x00FF1CE, 0xBAADF00D, 0xDEADBEEF, 0xCAFED00D),
|
||||
SIMD.Int32x4(0xD15EA5E, 0xDEADC0DE, 0xFACEB00C, 0x4B1D4B1D)
|
||||
];
|
||||
|
||||
var inputs = [
|
||||
[SIMD.Int32x4(0,4,9,16), SIMD.Int32x4(1,2,3,4)],
|
||||
[SIMD.Int32x4(-1, 2, INT32_MAX, INT32_MIN), SIMD.Int32x4(INT32_MAX, -4, INT32_MIN, 42)]
|
||||
];
|
||||
|
||||
var i32bsel = asmLink(asmCompile('glob', USE_ASM + I32 + CI32 + I32BSEL + "function f(mask, ifTrue, ifFalse) {mask=ci4(mask); ifTrue=ci4(ifTrue); ifFalse=ci4(ifFalse); return ci4(i4sel(mask,ifTrue,ifFalse)); } return f"), this)
|
||||
|
||||
for (var mask of masks) {
|
||||
for (var [x, y] of inputs) {
|
||||
assertEqX4(i32bsel(mask, x, y), simdToArray(SIMD.Int32x4.selectBits(mask, x, y)));
|
||||
}
|
||||
}
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(0,0,0,0); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 7, 8]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(1,1,1,1); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [1, 2, 3, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(0,1,0,1); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 2, 7, 4]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + B32 + F32 + CF32 + F32SEL + "function f() {var m=b4(0,0,1,1); var x=f4(1,2,3,4); var y=f4(5,6,7,8); return cf4(f4sel(m,x,y)); } return f"), this)(), [5, 6, 3, 4]);
|
||||
|
||||
// Splat
|
||||
const I32SPLAT = 'var splat=i4.splat;'
|
||||
const F32SPLAT = 'var splat=f4.splat;'
|
||||
const B32SPLAT = 'var splat=b4.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(f32(1));} return f");
|
||||
assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2,3,4); m=splat(1, 2)} return f");
|
||||
@ -939,6 +1001,8 @@ assertAsmTypeFail('glob', USE_ASM + I32 + I32SPLAT + "function f() {var m=i4(1,2
|
||||
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 + CI32 + I32SPLAT + 'function f(){return ci4(splat(42));} return f'), this)(), [42, 42, 42, 42]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + B32SPLAT + 'function f(){return cb4(splat(42));} return f'), this)(), [true, true, true, true]);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + B32 + CB32 + B32SPLAT + 'function f(){return cb4(splat(0));} return f'), this)(), [false, false, false, false]);
|
||||
|
||||
const l33t = Math.fround(13.37);
|
||||
assertEqX4(asmLink(asmCompile('glob', USE_ASM + F32 + CF32 + F32SPLAT + FROUND + 'function f(){return cf4(splat(f32(1)));} return f'), this)(), [1, 1, 1, 1]);
|
||||
@ -1070,10 +1134,12 @@ assertAsmTypeFail('glob', USE_ASM + I32 + "var pow=glob.Math.pow; function f() {
|
||||
// Can't pass SIMD arguments to FFI
|
||||
assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); func(x);} return f");
|
||||
assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); func(x);} return f");
|
||||
assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + "var func=ffi.func; function f() {var x=b4(1,2,3,4); func(x);} return f");
|
||||
|
||||
// Can't have FFI return SIMD values
|
||||
assertAsmTypeFail('glob', 'ffi', USE_ASM + I32 + "var func=ffi.func; function f() {var x=i4(1,2,3,4); x=i4(func());} return f");
|
||||
assertAsmTypeFail('glob', 'ffi', USE_ASM + F32 + "var func=ffi.func; function f() {var x=f4(1,2,3,4); x=f4(func());} return f");
|
||||
assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + "var func=ffi.func; function f() {var x=b4(1,2,3,4); x=b4(func());} return f");
|
||||
|
||||
// 3.3 Internal calls
|
||||
// asm.js -> asm.js
|
||||
@ -1150,6 +1216,24 @@ for (var i = 1; i < 10; ++i) {
|
||||
asmLink(asmCompile('glob', 'ffi', c), this, ffi)();
|
||||
}
|
||||
|
||||
// Passing boolean results to extern functions.
|
||||
// Verify that these functions are typed correctly.
|
||||
function isone(x) { return (x===1)|0 }
|
||||
var f = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + ANYB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(anyt(i)|0)|0; } return f'), this, {isone:isone});
|
||||
assertEq(f(SIMD.Bool32x4(0,0,1,0)), 1)
|
||||
assertEq(f(SIMD.Bool32x4(0,0,0,0)), 0)
|
||||
assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + CB32 + ANYB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(anyt(i))|0; } return f');
|
||||
|
||||
var f = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + ALLB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(allt(i)|0)|0; } return f'), this, {isone:isone});
|
||||
assertEq(f(SIMD.Bool32x4(1,1,1,1)), 1)
|
||||
assertEq(f(SIMD.Bool32x4(0,1,0,0)), 0)
|
||||
assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + CB32 + ALLB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(allt(i))|0; } return f');
|
||||
|
||||
var f = asmLink(asmCompile('glob', 'ffi', USE_ASM + B32 + CB32 + EXTB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(e(i,2)|0)|0; } return f'), this, {isone:isone});
|
||||
assertEq(f(SIMD.Bool32x4(1,1,1,1)), 1)
|
||||
assertEq(f(SIMD.Bool32x4(0,1,0,0)), 0)
|
||||
assertAsmTypeFail('glob', 'ffi', USE_ASM + B32 + CB32 + EXTB4 + 'var isone=ffi.isone; function f(i) { i=cb4(i); return isone(e(i,2))|0; } return f');
|
||||
|
||||
// Stress-test for register spilling code and stack depth checks
|
||||
var code = `
|
||||
"use asm";
|
||||
|
@ -182,25 +182,25 @@ function testSimdX4(ctor, shift, scale, disp, simdName, simdCtor) {
|
||||
|
||||
// Stores
|
||||
if (!t) {
|
||||
simdCtor.store(arr, index, simdCtor.not(v));
|
||||
simdCtor.store(arr, index, simdCtor.neg(v));
|
||||
f.store(i, v);
|
||||
assertEqX4(simdCtor.load(arr, index), v);
|
||||
} else
|
||||
assertThrowsInstanceOf(() => f.store(i, simdCtor()), RangeError);
|
||||
if (!t3) {
|
||||
simdCtor.store3(arr, index, simdCtor.not(v3));
|
||||
simdCtor.store3(arr, index, simdCtor.neg(v3));
|
||||
f.store3(i, v3);
|
||||
assertEqX4(simdCtor.load3(arr, index), v3);
|
||||
} else
|
||||
assertThrowsInstanceOf(() => f.store3(i, simdCtor()), RangeError);
|
||||
if (!t2) {
|
||||
simdCtor.store2(arr, index, simdCtor.not(v2));
|
||||
simdCtor.store2(arr, index, simdCtor.neg(v2));
|
||||
f.store2(i, v2);
|
||||
assertEqX4(simdCtor.load2(arr, index), v2);
|
||||
} else
|
||||
assertThrowsInstanceOf(() => f.store2(i, simdCtor()), RangeError);
|
||||
if (!t1) {
|
||||
simdCtor.store1(arr, index, simdCtor.not(v1));
|
||||
simdCtor.store1(arr, index, simdCtor.neg(v1));
|
||||
f.store1(i, v1);
|
||||
assertEqX4(simdCtor.load1(arr, index), v1);
|
||||
} else
|
||||
|
Loading…
x
Reference in New Issue
Block a user