Skip to content

Commit

Permalink
Bug 1044256: SIMD: Add support for unary operators in Odin; r=luke
Browse files Browse the repository at this point in the history
  • Loading branch information
bnjbvr committed Oct 7, 2014
1 parent 0fc41ae commit 56a3a17
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 6 deletions.
36 changes: 36 additions & 0 deletions js/src/asmjs/AsmJSValidate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2523,6 +2523,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)
{
Expand Down Expand Up @@ -5008,6 +5019,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,
Expand Down Expand Up @@ -5140,6 +5163,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();
Expand Down
8 changes: 7 additions & 1 deletion js/src/builtin/SIMD.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@
_(shiftRight) \
_(shiftRightLogical)
#define FOREACH_FLOAT32X4_SIMD_OP(_) \
_(abs) \
_(sqrt) \
_(reciprocal) \
_(reciprocalSqrt) \
_(fromInt32x4) \
_(fromInt32x4Bits) \
_(mul) \
Expand All @@ -143,7 +147,9 @@
_(withX) \
_(withY) \
_(withZ) \
_(withW)
_(withW) \
_(not) \
_(neg)
#define FORALL_SIMD_OP(_) \
FOREACH_INT32X4_SIMD_OP(_) \
FOREACH_FLOAT32X4_SIMD_OP(_) \
Expand Down
75 changes: 70 additions & 5 deletions js/src/jit-test/tests/asm.js/testSIMD.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit 56a3a17

Please sign in to comment.