Bug 1044256: SIMD: Add support for unary operators in Odin; r=luke

This commit is contained in:
Benjamin Bouvier 2014-10-07 14:10:00 +02:00
parent 2abf42f482
commit 66b40bb34e
3 changed files with 113 additions and 6 deletions

View File

@ -2427,6 +2427,17 @@ class FunctionCompiler
return ins;
}
MDefinition *unarySimd(MDefinition *input, MSimdUnaryArith::Operation op, MIRType type)
{
if (inDeadCode())
return nullptr;
MOZ_ASSERT(IsSimdType(input->type()) && input->type() == type);
MInstruction *ins = MSimdUnaryArith::NewAsmJS(alloc(), input, op, type);
curBlock_->add(ins);
return ins;
}
MDefinition *binarySimd(MDefinition *lhs, MDefinition *rhs, MSimdBinaryArith::Operation op,
MIRType type)
{
@ -4853,6 +4864,18 @@ class CheckSimdVectorScalarArgs
} // anonymous namespace
static inline bool
CheckSimdUnary(FunctionCompiler &f, ParseNode *call, Type retType, MSimdUnaryArith::Operation op,
MDefinition **def, Type *type)
{
DefinitionVector defs;
if (!CheckSimdCallArgs(f, call, 1, CheckArgIsSubtypeOf(retType), &defs))
return false;
*def = f.unarySimd(defs[0], op, retType.toMIRType());
*type = retType;
return true;
}
template<class OpEnum>
static inline bool
CheckSimdBinary(FunctionCompiler &f, ParseNode *call, Type retType, OpEnum op, MDefinition **def,
@ -4985,6 +5008,19 @@ CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompile
case AsmJSSimdOperation_shiftRightLogical:
return CheckSimdBinary(f, call, Type::Int32x4, MSimdShift::ursh, def, type);
case AsmJSSimdOperation_abs:
return CheckSimdUnary(f, call, retType, MSimdUnaryArith::abs, def, type);
case AsmJSSimdOperation_neg:
return CheckSimdUnary(f, call, retType, MSimdUnaryArith::neg, def, type);
case AsmJSSimdOperation_not:
return CheckSimdUnary(f, call, retType, MSimdUnaryArith::not_, def, type);
case AsmJSSimdOperation_sqrt:
return CheckSimdUnary(f, call, retType, MSimdUnaryArith::sqrt, def, type);
case AsmJSSimdOperation_reciprocal:
return CheckSimdUnary(f, call, retType, MSimdUnaryArith::reciprocal, def, type);
case AsmJSSimdOperation_reciprocalSqrt:
return CheckSimdUnary(f, call, retType, MSimdUnaryArith::reciprocalSqrt, def, type);
case AsmJSSimdOperation_splat: {
DefinitionVector defs;
Type formalType = retType.simdToCoercedScalarType();

View File

@ -120,6 +120,10 @@
_(shiftRight) \
_(shiftRightLogical)
#define FOREACH_FLOAT32X4_SIMD_OP(_) \
_(abs) \
_(sqrt) \
_(reciprocal) \
_(reciprocalSqrt) \
_(fromInt32x4) \
_(fromInt32x4Bits) \
_(mul) \
@ -143,7 +147,9 @@
_(withX) \
_(withY) \
_(withZ) \
_(withW)
_(withW) \
_(not) \
_(neg)
#define FORALL_SIMD_OP(_) \
FOREACH_INT32X4_SIMD_OP(_) \
FOREACH_FLOAT32X4_SIMD_OP(_) \

View File

@ -24,11 +24,14 @@ const INT32_MIN = INT32_MAX + 1 | 0;
const assertEqFFI = {assertEq:assertEq};
function assertEqX4(real, expected) {
assertEq(real.x, expected[0]);
assertEq(real.y, expected[1]);
assertEq(real.z, expected[2]);
assertEq(real.w, expected[3]);
function assertEqX4(real, expected, assertFunc) {
if (typeof assertFunc === 'undefined')
assertFunc = assertEq;
assertFunc(real.x, expected[0]);
assertFunc(real.y, expected[1]);
assertFunc(real.z, expected[2]);
assertFunc(real.w, expected[3]);
}
function CheckI4(header, code, expected) {
@ -444,6 +447,68 @@ CheckF4(F32M, 'var x=f4(1,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [4,6,15,8]);
CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4m(x,y)', [Math.fround(13.37) * 4,6,15,8]);
CheckF4(F32M, 'var x=f4(13.37,2,3,4); var y=f4(4,3,5,2); x=f4(f4m(x,y))', [Math.fround(13.37) * 4,6,15,8]);
// Unary arithmetic operators
function CheckUnaryF4(op, checkFunc, assertFunc) {
var _ = asmLink(asmCompile('glob', USE_ASM + F32 + 'var op=f4.' + op + '; function f(x){x=f4(x); return f4(op(x)); } return f'), this);
return function(input) {
var simd = SIMD.float32x4(input[0], input[1], input[2], input[3]);
var exp = input.map(Math.fround).map(checkFunc).map(Math.fround);
var obs = _(simd);
assertEqX4(obs, exp, assertFunc);
}
}
function CheckUnaryI4(op, checkFunc) {
var _ = asmLink(asmCompile('glob', USE_ASM + I32 + 'var op=i4.' + op + '; function f(x){x=i4(x); return i4(op(x)); } return f'), this);
return function(input) {
var simd = SIMD.int32x4(input[0], input[1], input[2], input[3]);
assertEqX4(_(simd), input.map(checkFunc).map(function(x) { return x | 0}));
}
}
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 CheckAbs = CheckUnaryF4('abs', Math.abs);
CheckAbs([1, 42.42, 0.63, 13.37]);
CheckAbs([NaN, -Infinity, Infinity, 0]);
var CheckNegF = CheckUnaryF4('neg', function(x) { return -x });
CheckNegF([1, 42.42, 0.63, 13.37]);
CheckNegF([NaN, -Infinity, Infinity, 0]);
var CheckNotF = CheckUnaryF4('not', (function() {
var f32 = new Float32Array(1);
var i32 = new Int32Array(f32.buffer);
return function(x) {
f32[0] = x;
i32[0] = ~i32[0];
return f32[0];
}
})());
CheckNotF([1, 42.42, 0.63, 13.37]);
CheckNotF([NaN, -Infinity, Infinity, 0]);
var CheckSqrt = CheckUnaryF4('sqrt', function(x) { return Math.sqrt(x); });
CheckSqrt([1, 42.42, 0.63, 13.37]);
CheckSqrt([NaN, -Infinity, Infinity, 0]);
// Reciprocal and reciprocalSqrt give approximate results
function assertNear(a, b) {
if (a !== a && b === b)
throw 'Observed NaN, expected ' + b;
if (Math.abs(a - b) > 1e-3)
throw 'More than 1e-3 between ' + a + ' and ' + b;
}
var CheckRecp = CheckUnaryF4('reciprocal', function(x) { return 1 / x; }, assertNear);
CheckRecp([1, 42.42, 0.63, 13.37]);
CheckRecp([NaN, -Infinity, Infinity, 0]);
var CheckRecp = CheckUnaryF4('reciprocalSqrt', function(x) { return 1 / Math.sqrt(x); }, assertNear);
CheckRecp([1, 42.42, 0.63, 13.37]);
CheckRecp([NaN, -Infinity, Infinity, 0]);
// Min/Max
assertAsmTypeFail('glob', USE_ASM + I32 + "var f4m=i4.min; function f() {} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var f4d=i4.max; function f() {} return f");