Bug 1073064: SIMD: Add int32x4.shift{left,right,rightLogical} to asm.js; r=luke

This commit is contained in:
Benjamin Bouvier 2014-10-01 14:57:29 +02:00
parent 99d2d28c3d
commit 1b86dbcbb4
3 changed files with 63 additions and 6 deletions

View File

@ -2453,13 +2453,13 @@ class FunctionCompiler
return ins;
}
MDefinition *binarySimd(MDefinition *lhs, MDefinition *rhs, MSimdBinaryComp::Operation op)
template<class T>
MDefinition *binarySimd(MDefinition *lhs, MDefinition *rhs, typename T::Operation op)
{
if (inDeadCode())
return nullptr;
JS_ASSERT(IsSimdType(lhs->type()) && rhs->type() == lhs->type());
MSimdBinaryComp *ins = MSimdBinaryComp::NewAsmJS(alloc(), lhs, rhs, op);
T *ins = T::NewAsmJS(alloc(), lhs, rhs, op);
curBlock_->add(ins);
return ins;
}
@ -4875,7 +4875,20 @@ CheckSimdBinary<MSimdBinaryComp::Operation>(FunctionCompiler &f, ParseNode *call
DefinitionVector argDefs;
if (!CheckSimdCallArgs(f, call, 2, CheckArgIsSubtypeOf(retType), &argDefs))
return false;
*def = f.binarySimd(argDefs[0], argDefs[1], op);
*def = f.binarySimd<MSimdBinaryComp>(argDefs[0], argDefs[1], op);
*type = Type::Int32x4;
return true;
}
template<>
inline bool
CheckSimdBinary<MSimdShift::Operation>(FunctionCompiler &f, ParseNode *call, Type retType,
MSimdShift::Operation op, MDefinition **def, Type *type)
{
DefinitionVector argDefs;
if (!CheckSimdCallArgs(f, call, 2, CheckSimdVectorScalarArgs(retType), &argDefs))
return false;
*def = f.binarySimd<MSimdShift>(argDefs[0], argDefs[1], op);
*type = Type::Int32x4;
return true;
}
@ -4965,6 +4978,13 @@ CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompile
case AsmJSSimdOperation_fromFloat32x4Bits:
return CheckSimdCast<MSimdReinterpretCast>(f, call, Type::Float32x4, retType, def, type);
case AsmJSSimdOperation_shiftLeft:
return CheckSimdBinary(f, call, Type::Int32x4, MSimdShift::lsh, def, type);
case AsmJSSimdOperation_shiftRight:
return CheckSimdBinary(f, call, Type::Int32x4, MSimdShift::rsh, def, type);
case AsmJSSimdOperation_shiftRightLogical:
return CheckSimdBinary(f, call, Type::Int32x4, MSimdShift::ursh, def, type);
case AsmJSSimdOperation_splat: {
DefinitionVector defs;
Type formalType = retType.simdToCoercedScalarType();

View File

@ -115,7 +115,10 @@
#define FOREACH_INT32X4_SIMD_OP(_) \
_(fromFloat32x4) \
_(fromFloat32x4Bits)
_(fromFloat32x4Bits) \
_(shiftLeft) \
_(shiftRight) \
_(shiftRightLogical)
#define FOREACH_FLOAT32X4_SIMD_OP(_) \
_(fromInt32x4) \
_(fromInt32x4Bits) \

View File

@ -665,11 +665,45 @@ CheckF4(ANDF32, 'var x=f4(42, 13.37,-1.42, 23.10); var y=f4(19.89, 2.4, 8.15, 16
CheckF4(ORF32, 'var x=f4(42, 13.37,-1.42, 23.10); var y=f4(19.89, 2.4, 8.15, 16.36); x=orr(x,y)', bitwise.or( [42, 13.37, -1.42, 23.10], [19.89, 2.4, 8.15, 16.36]));
CheckF4(XORF32, 'var x=f4(42, 13.37,-1.42, 23.10); var y=f4(19.89, 2.4, 8.15, 16.36); x=xorr(x,y)', bitwise.xor([42, 13.37, -1.42, 23.10], [19.89, 2.4, 8.15, 16.36]));
// Logical ops
const LSHI = 'var lsh=i4.shiftLeft;'
const RSHI = 'var rsh=i4.shiftRight;'
const URSHI = 'var ursh=i4.shiftRightLogical;'
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return i4(lsh(x,f32(42)));} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + FROUND + LSHI + "function f() {var x=f4(1,2,3,4); return i4(lsh(x,42));} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return i4(lsh(x,42.0));} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + FROUND + LSHI + "function f() {var x=i4(1,2,3,4); return i4(lsh(x,f32(42)));} return f");
var input = 'i4(0, 1, ' + INT32_MIN + ', ' + INT32_MAX + ')';
var vinput = [0, 1, INT32_MIN, INT32_MAX];
// TODO: What to do for masks > 31? Should we keep only the five low bits of
// the mask (JS) or not (x86)?
// Behave as x86 for now, fix when more broadly specified. See also bug 1068028
function Lsh(i) { if (i > 31) return () => 0; return function(x) { return (x << i) | 0 } }
function Rsh(i) { if (i > 31) return (x) => (x<0)?-1:0; return function(x) { return (x >> i) | 0 } }
function Ursh(i) { if (i > 31) return () => 0; return function(x) { return (x >>> i) | 0 } }
var asmLsh = asmLink(asmCompile('glob', USE_ASM + I32 + LSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return i4(lsh(v, x+y))} return f;'), this)
var asmRsh = asmLink(asmCompile('glob', USE_ASM + I32 + RSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return i4(rsh(v, x+y))} return f;'), this)
var asmUrsh = asmLink(asmCompile('glob', USE_ASM + I32 + URSHI + 'function f(x, y){x=x|0;y=y|0; var v=' + input + ';return i4(ursh(v, x+y))} return f;'), this)
for (var i = 1; i < 64; i++) {
CheckI4(LSHI, 'var x=' + input + '; x=lsh(x, ' + i + ')', vinput.map(Lsh(i)));
CheckI4(RSHI, 'var x=' + input + '; x=rsh(x, ' + i + ')', vinput.map(Rsh(i)));
CheckI4(URSHI, 'var x=' + input + '; x=ursh(x, ' + i + ')', vinput.map(Ursh(i)));
assertEqX4(asmLsh(i, 3), vinput.map(Lsh(i + 3)));
assertEqX4(asmRsh(i, 3), vinput.map(Rsh(i + 3)));
assertEqX4(asmUrsh(i, 3), vinput.map(Ursh(i + 3)));
}
// Select
const I32SEL = 'var i4sel = i4.select;'
const F32SEL = 'var f4sel = f4.select;'
assertAsmTypeFail('glob', USE_ASM + F32 + I32SEL + "function f() {var m=f4(1,2,3,4); return i4(i4sel(x,x,x));} return f");
assertAsmTypeFail('glob', USE_ASM + F32 + I32SEL + "function f() {var x=f4(1,2,3,4); return i4(i4sel(x,x,x));} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=i4(1,2,3,4); return i4(i4sel(m,x,x));} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SEL + "function f() {var m=f4(1,2,3,4); var x=f4(1,2,3,4); return i4(i4sel(m,x,x));} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + I32SEL + "function f() {var m=i4(1,2,3,4); var x=f4(1,2,3,4); return i4(i4sel(m,x,x));} return f");