зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1062217: Generalize SIMD operation and ctor validation; r=luke
This commit is contained in:
Родитель
e34bfcab70
Коммит
61109135a9
|
@ -558,6 +558,30 @@ class Type
|
|||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid SIMD Type");
|
||||
}
|
||||
|
||||
Type simdToCoercedScalarType() const {
|
||||
JS_ASSERT(isSimd());
|
||||
switch (which_) {
|
||||
case Int32x4:
|
||||
return Intish;
|
||||
case Float32x4:
|
||||
return Floatish;
|
||||
// Scalar types
|
||||
case Double:
|
||||
case MaybeDouble:
|
||||
case Float:
|
||||
case MaybeFloat:
|
||||
case Floatish:
|
||||
case Fixnum:
|
||||
case Int:
|
||||
case Signed:
|
||||
case Unsigned:
|
||||
case Intish:
|
||||
case Void:
|
||||
break;
|
||||
}
|
||||
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Invalid SIMD Type");
|
||||
}
|
||||
|
||||
AsmJSSimdType simdToSimdType() const {
|
||||
JS_ASSERT(isSimd());
|
||||
switch (which_) {
|
||||
|
@ -4718,161 +4742,127 @@ CheckMathBuiltinCall(FunctionCompiler &f, ParseNode *callNode, AsmJSMathBuiltinF
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef Vector<MDefinition*, 4, SystemAllocPolicy> DefinitionVector;
|
||||
|
||||
template<class CheckArgOp>
|
||||
static bool
|
||||
CheckUnarySimd(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global,
|
||||
MDefinition **def, Type *type)
|
||||
CheckSimdCallArgs(FunctionCompiler &f, ParseNode *call, unsigned expectedArity,
|
||||
const CheckArgOp &checkArg, DefinitionVector *defs)
|
||||
{
|
||||
unsigned numArgs = CallArgListLength(call);
|
||||
if (numArgs != 1)
|
||||
return f.failf(call, "expected 1 argument to unary arithmetic SIMD operation, got %u", numArgs);
|
||||
if (numArgs != expectedArity)
|
||||
return f.failf(call, "expected %u arguments to SIMD call, got %u", expectedArity, numArgs);
|
||||
|
||||
DefinitionVector &argDefs = *defs;
|
||||
if (!argDefs.resize(numArgs))
|
||||
return false;
|
||||
|
||||
ParseNode *arg = CallArgList(call);
|
||||
MDefinition *argDef;
|
||||
Type argType;
|
||||
if (!CheckExpr(f, arg, &argDef, &argType))
|
||||
return false;
|
||||
for (size_t i = 0; i < numArgs; i++, arg = NextNode(arg)) {
|
||||
MOZ_ASSERT(!!arg);
|
||||
|
||||
// For now, the only unary SIMD operation is splat(scalar).
|
||||
MOZ_ASSERT(global->simdOperation() == AsmJSSimdOperation_splat);
|
||||
switch (global->simdOperationType()) {
|
||||
case AsmJSSimdType_int32x4:
|
||||
if (!argType.isIntish())
|
||||
return f.failf(arg, "%s is not a subtype of intish", argType.toChars());
|
||||
break;
|
||||
case AsmJSSimdType_float32x4:
|
||||
if (!CheckFloatCoercionArg(f, arg, argType, argDef, &argDef))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
*type = global->simdOperationType();
|
||||
*def = f.splatSimd(argDef, type->toMIRType());
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckBinarySimd(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global,
|
||||
MDefinition **def, Type *type)
|
||||
{
|
||||
unsigned numArgs = CallArgListLength(call);
|
||||
if (numArgs != 2)
|
||||
return f.failf(call, "expected 2 arguments to binary arithmetic SIMD operation, got %u", numArgs);
|
||||
|
||||
ParseNode *lhs = CallArgList(call);
|
||||
ParseNode *rhs = NextNode(lhs);
|
||||
|
||||
MDefinition *lhsDef, *rhsDef;
|
||||
Type lhsType, rhsType;
|
||||
if (!CheckExpr(f, lhs, &lhsDef, &lhsType))
|
||||
return false;
|
||||
if (!CheckExpr(f, rhs, &rhsDef, &rhsType))
|
||||
return false;
|
||||
|
||||
Type retType = global->simdOperationType();
|
||||
if (lhsType != retType || rhsType != retType)
|
||||
return f.failf(lhs, "arguments to SIMD binary op should both be %s", retType.toChars());
|
||||
|
||||
MIRType opType = retType.toMIRType();
|
||||
switch (global->simdOperation()) {
|
||||
case AsmJSSimdOperation_add:
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryArith::Add, opType);
|
||||
*type = retType;
|
||||
break;
|
||||
case AsmJSSimdOperation_sub:
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryArith::Sub, opType);
|
||||
*type = retType;
|
||||
break;
|
||||
case AsmJSSimdOperation_mul:
|
||||
JS_ASSERT(!retType.isInt32x4());
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryArith::Mul, opType);
|
||||
*type = retType;
|
||||
break;
|
||||
case AsmJSSimdOperation_div:
|
||||
JS_ASSERT(!retType.isInt32x4());
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryArith::Div, opType);
|
||||
*type = retType;
|
||||
break;
|
||||
case AsmJSSimdOperation_lessThan:
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryComp::lessThan);
|
||||
*type = Type::Int32x4;
|
||||
break;
|
||||
case AsmJSSimdOperation_lessThanOrEqual:
|
||||
JS_ASSERT(!retType.isInt32x4());
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryComp::lessThanOrEqual);
|
||||
*type = Type::Int32x4;
|
||||
break;
|
||||
case AsmJSSimdOperation_equal:
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryComp::equal);
|
||||
*type = Type::Int32x4;
|
||||
break;
|
||||
case AsmJSSimdOperation_notEqual:
|
||||
JS_ASSERT(!retType.isInt32x4());
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryComp::notEqual);
|
||||
*type = Type::Int32x4;
|
||||
break;
|
||||
case AsmJSSimdOperation_greaterThan:
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryComp::greaterThan);
|
||||
*type = Type::Int32x4;
|
||||
break;
|
||||
case AsmJSSimdOperation_greaterThanOrEqual:
|
||||
JS_ASSERT(!retType.isInt32x4());
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryComp::greaterThanOrEqual);
|
||||
*type = Type::Int32x4;
|
||||
break;
|
||||
case AsmJSSimdOperation_and:
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryBitwise::and_, opType);
|
||||
*type = retType;
|
||||
break;
|
||||
case AsmJSSimdOperation_or:
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryBitwise::or_, opType);
|
||||
*type = retType;
|
||||
break;
|
||||
case AsmJSSimdOperation_xor:
|
||||
*def = f.binarySimd(lhsDef, rhsDef, MSimdBinaryBitwise::xor_, opType);
|
||||
*type = retType;
|
||||
break;
|
||||
case AsmJSSimdOperation_splat:
|
||||
case AsmJSSimdOperation_select:
|
||||
MOZ_CRASH("unexpected SIMD binary operation");
|
||||
Type argType;
|
||||
if (!CheckExpr(f, arg, &argDefs[i], &argType))
|
||||
return false;
|
||||
if (!checkArg(f, arg, i, argType, &argDefs[i]))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CheckSimdSelect(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global,
|
||||
MDefinition **def, Type *type)
|
||||
namespace {
|
||||
|
||||
class CheckSimdScalarArgs
|
||||
{
|
||||
MOZ_ASSERT(global->simdOperation() == AsmJSSimdOperation_select);
|
||||
Type formalType_;
|
||||
|
||||
unsigned numArgs = CallArgListLength(call);
|
||||
if (numArgs != 3)
|
||||
return f.failf(call, "expected 3 arguments to ternary SIMD operation, got %u", numArgs);
|
||||
public:
|
||||
explicit CheckSimdScalarArgs(Type t) : formalType_(t.simdToCoercedScalarType()) {}
|
||||
|
||||
ParseNode *mask = CallArgList(call);
|
||||
ParseNode *lhs = NextNode(mask);
|
||||
ParseNode *rhs = NextNode(lhs);
|
||||
bool operator()(FunctionCompiler &f, ParseNode *arg, unsigned argIndex, Type actualType,
|
||||
MDefinition **argDef) const
|
||||
{
|
||||
if (formalType_ == Type::Floatish)
|
||||
return CheckFloatCoercionArg(f, arg, actualType, *argDef, argDef);
|
||||
|
||||
MDefinition *maskDef;
|
||||
Type maskType;
|
||||
if (!CheckExpr(f, mask, &maskDef, &maskType))
|
||||
if (!(actualType <= formalType_)) {
|
||||
return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
|
||||
formalType_.toChars());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class CheckSimdVectorArgs
|
||||
{
|
||||
Type formalType_;
|
||||
|
||||
public:
|
||||
explicit CheckSimdVectorArgs(Type t) : formalType_(t) {}
|
||||
|
||||
bool operator()(FunctionCompiler &f, ParseNode *arg, unsigned argIndex, Type actualType,
|
||||
MDefinition **argDef) const
|
||||
{
|
||||
if (!(actualType <= formalType_)) {
|
||||
return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
|
||||
formalType_.toChars());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class CheckSimdSelectArgs
|
||||
{
|
||||
Type formalType_;
|
||||
|
||||
public:
|
||||
explicit CheckSimdSelectArgs(Type t) : formalType_(t) {}
|
||||
|
||||
bool operator()(FunctionCompiler &f, ParseNode *arg, unsigned argIndex, Type actualType,
|
||||
MDefinition **argDef) 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());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(actualType <= formalType_)) {
|
||||
return f.failf(arg, "%s is not a subtype of %s", actualType.toChars(),
|
||||
formalType_.toChars());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
template<class OpEnum>
|
||||
static inline bool
|
||||
CheckSimdBinary(FunctionCompiler &f, ParseNode *call, Type retType, OpEnum op, MDefinition **def,
|
||||
Type *type)
|
||||
{
|
||||
DefinitionVector argDefs;
|
||||
if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorArgs(retType), &argDefs))
|
||||
return false;
|
||||
if (maskType != Type::Int32x4)
|
||||
return f.failf(mask, "%s is not a subtype of int32x4", maskType.toChars());
|
||||
|
||||
MDefinition *lhsDef, *rhsDef;
|
||||
Type lhsType, rhsType;
|
||||
if (!CheckExpr(f, lhs, &lhsDef, &lhsType))
|
||||
return false;
|
||||
if (!CheckExpr(f, rhs, &rhsDef, &rhsType))
|
||||
return false;
|
||||
|
||||
Type retType = global->simdOperationType();
|
||||
if (lhsType != retType || rhsType != retType)
|
||||
return f.failf(mask, "last two arguments to SIMD ternary op should both be %s", retType.toChars());
|
||||
|
||||
*def = f.binarySimd(argDefs[0], argDefs[1], op, retType.toMIRType());
|
||||
*type = retType;
|
||||
*def = f.ternarySimd(maskDef, lhsDef, rhsDef, MSimdTernaryBitwise::select, retType.toMIRType());
|
||||
return true;
|
||||
}
|
||||
|
||||
template<>
|
||||
inline bool
|
||||
CheckSimdBinary<MSimdBinaryComp::Operation>(FunctionCompiler &f, ParseNode *call, Type retType,
|
||||
MSimdBinaryComp::Operation op, MDefinition **def,
|
||||
Type *type)
|
||||
{
|
||||
DefinitionVector argDefs;
|
||||
if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorArgs(retType), &argDefs))
|
||||
return false;
|
||||
*def = f.binarySimd(argDefs[0], argDefs[1], op);
|
||||
*type = Type::Int32x4;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -4880,26 +4870,58 @@ static bool
|
|||
CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global,
|
||||
MDefinition **def, Type *type)
|
||||
{
|
||||
JS_ASSERT(global->isSimdOperation());
|
||||
MOZ_ASSERT(global->isSimdOperation());
|
||||
|
||||
Type retType = global->simdOperationType();
|
||||
|
||||
switch (global->simdOperation()) {
|
||||
case AsmJSSimdOperation_splat:
|
||||
return CheckUnarySimd(f, call, global, def, type);
|
||||
case AsmJSSimdOperation_add:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryArith::Add, def, type);
|
||||
case AsmJSSimdOperation_sub:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryArith::Sub, def, type);
|
||||
case AsmJSSimdOperation_mul:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryArith::Mul, def, type);
|
||||
case AsmJSSimdOperation_div:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryArith::Div, def, type);
|
||||
|
||||
case AsmJSSimdOperation_lessThan:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryComp::lessThan, def, type);
|
||||
case AsmJSSimdOperation_lessThanOrEqual:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryComp::lessThanOrEqual, def, type);
|
||||
case AsmJSSimdOperation_equal:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryComp::equal, def, type);
|
||||
case AsmJSSimdOperation_notEqual:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryComp::notEqual, def, type);
|
||||
case AsmJSSimdOperation_greaterThan:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryComp::greaterThan, def, type);
|
||||
case AsmJSSimdOperation_greaterThanOrEqual:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryComp::greaterThanOrEqual, def, type);
|
||||
|
||||
case AsmJSSimdOperation_and:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryBitwise::and_, def, type);
|
||||
case AsmJSSimdOperation_or:
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryBitwise::or_, def, type);
|
||||
case AsmJSSimdOperation_xor:
|
||||
return CheckBinarySimd(f, call, global, def, type);
|
||||
case AsmJSSimdOperation_select:
|
||||
return CheckSimdSelect(f, call, global, def, type);
|
||||
return CheckSimdBinary(f, call, retType, MSimdBinaryBitwise::xor_, def, type);
|
||||
|
||||
case AsmJSSimdOperation_splat: {
|
||||
DefinitionVector defs;
|
||||
if (!CheckSimdCallArgs(f, call, 1, CheckSimdScalarArgs(retType), &defs))
|
||||
return false;
|
||||
*def = f.splatSimd(defs[0], retType.toMIRType());
|
||||
*type = retType;
|
||||
return true;
|
||||
}
|
||||
|
||||
case AsmJSSimdOperation_select: {
|
||||
DefinitionVector defs;
|
||||
if (!CheckSimdCallArgs(f, call, 3, CheckSimdSelectArgs(retType), &defs))
|
||||
return false;
|
||||
*def = f.ternarySimd(defs[0], defs[1], defs[2], MSimdTernaryBitwise::select,
|
||||
retType.toMIRType());
|
||||
*type = retType;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
MOZ_CRASH("unexpected simd operation in CheckSimdOperationCall");
|
||||
}
|
||||
|
@ -4916,44 +4938,22 @@ CheckSimdCtorCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Gl
|
|||
return CheckCoercionArg(f, argNode, coercion, def, type);
|
||||
|
||||
AsmJSSimdType simdType = global->simdCtorType();
|
||||
unsigned numArgs = CallArgListLength(call);
|
||||
unsigned length = SimdTypeToLength(simdType);
|
||||
if (numArgs != length)
|
||||
return f.failName(call, "invalid number of arguments in call to '%s'", CallCallee(call)->name());
|
||||
Type retType = simdType;
|
||||
|
||||
Vector<MDefinition*, 4, SystemAllocPolicy> defs;
|
||||
if (!defs.resize(length))
|
||||
DefinitionVector defs;
|
||||
if (!CheckSimdCallArgs(f, call, length, CheckSimdScalarArgs(retType), &defs))
|
||||
return false;
|
||||
|
||||
argNode = CallArgList(call);
|
||||
size_t i = 0;
|
||||
for (; argNode; argNode = NextNode(argNode), ++i)
|
||||
{
|
||||
JS_ASSERT(i < length);
|
||||
|
||||
Type argType;
|
||||
if (!CheckExpr(f, argNode, &defs[i], &argType))
|
||||
return false;
|
||||
|
||||
switch (simdType) {
|
||||
case AsmJSSimdType_int32x4:
|
||||
if (!argType.isIntish())
|
||||
return f.failf(argNode, "argument %d of Int32x4 ctor isn't a subtype of intish", i);
|
||||
break;
|
||||
case AsmJSSimdType_float32x4:
|
||||
if (!CheckFloatCoercionArg(f, argNode, argType, defs[i], &defs[i]))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
JS_ASSERT(i == length);
|
||||
|
||||
*type = simdType;
|
||||
// This code will need to be generalized when we handle float64x2
|
||||
MOZ_ASSERT(length == 4);
|
||||
|
||||
MIRType opType = retType.toMIRType();
|
||||
if (defs[1] == defs[0] && defs[2] == defs[0] && defs[3] == defs[0])
|
||||
*def = f.splatSimd(defs[0], type->toMIRType());
|
||||
*def = f.splatSimd(defs[0], opType);
|
||||
else
|
||||
*def = f.constructSimd<MSimdValueX4>(defs[0], defs[1], defs[2], defs[3], type->toMIRType());
|
||||
*def = f.constructSimd<MSimdValueX4>(defs[0], defs[1], defs[2], defs[3], opType);
|
||||
*type = retType;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче