Bug 1059408: Odin SIMD: Add support for swizzle and shuffle; r=luke

This commit is contained in:
Benjamin Bouvier 2014-10-21 15:39:38 +02:00
Родитель 2c3d97c4d8
Коммит 271c651290
3 изменённых файлов: 178 добавлений и 0 удалений

Просмотреть файл

@ -2576,6 +2576,28 @@ class FunctionCompiler
return ins;
}
MDefinition *swizzleSimd(MDefinition *vector, int32_t X, int32_t Y, int32_t Z, int32_t W,
MIRType type)
{
if (inDeadCode())
return nullptr;
MSimdSwizzle *ins = MSimdSwizzle::NewAsmJS(alloc(), vector, type, X, Y, Z, W);
curBlock_->add(ins);
return ins;
}
MDefinition *shuffleSimd(MDefinition *lhs, MDefinition *rhs, int32_t X, int32_t Y,
int32_t Z, int32_t W, MIRType type)
{
if (inDeadCode())
return nullptr;
MInstruction *ins = MSimdShuffle::NewAsmJS(alloc(), lhs, rhs, type, X, Y, Z, W);
curBlock_->add(ins);
return ins;
}
MDefinition *insertElementSimd(MDefinition *vec, MDefinition *val, SimdLane lane, MIRType type)
{
if (inDeadCode())
@ -5102,6 +5124,71 @@ CheckSimdCast(FunctionCompiler &f, ParseNode *call, Type fromType, Type toType,
return true;
}
static bool
CheckSimdShuffleSelectors(FunctionCompiler &f, ParseNode *lane, int32_t lanes[4], uint32_t maxLane)
{
for (unsigned i = 0; i < 4; i++, lane = NextNode(lane)) {
uint32_t u32;
if (!IsLiteralInt(f.m(), lane, &u32))
return f.failf(lane, "lane selector should be a constant integer literal");
if (u32 >= maxLane)
return f.failf(lane, "lane selector should be less than %u", maxLane);
lanes[i] = int32_t(u32);
}
return true;
}
static bool
CheckSimdSwizzle(FunctionCompiler &f, ParseNode *call, Type retType, MDefinition **def, Type *type)
{
unsigned numArgs = CallArgListLength(call);
if (numArgs != 5)
return f.failf(call, "expected 5 arguments to SIMD swizzle, got %u", numArgs);
ParseNode *vec = CallArgList(call);
MDefinition *vecDef;
Type vecType;
if (!CheckExpr(f, vec, &vecDef, &vecType))
return false;
if (!(vecType <= retType))
return f.failf(vec, "%s is not a subtype of %s", vecType.toChars(), retType.toChars());
int32_t lanes[4];
if (!CheckSimdShuffleSelectors(f, NextNode(vec), lanes, 4))
return false;
*def = f.swizzleSimd(vecDef, lanes[0], lanes[1], lanes[2], lanes[3], retType.toMIRType());
*type = retType;
return true;
}
static bool
CheckSimdShuffle(FunctionCompiler &f, ParseNode *call, Type retType, MDefinition **def, Type *type)
{
unsigned numArgs = CallArgListLength(call);
if (numArgs != 6)
return f.failf(call, "expected 6 arguments to SIMD shuffle, got %u", numArgs);
ParseNode *arg = CallArgList(call);
MDefinition *vecs[2];
for (unsigned i = 0; i < 2; i++, arg = NextNode(arg)) {
Type type;
if (!CheckExpr(f, arg, &vecs[i], &type))
return false;
if (!(type <= retType))
return f.failf(arg, "%s is not a subtype of %s", type.toChars(), retType.toChars());
}
int32_t lanes[4];
if (!CheckSimdShuffleSelectors(f, arg, lanes, 8))
return false;
*def = f.shuffleSimd(vecs[0], vecs[1], lanes[0], lanes[1], lanes[2], lanes[3],
retType.toMIRType());
*type = retType;
return true;
}
static bool
CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompiler::Global *global,
MDefinition **def, Type *type)
@ -5182,6 +5269,11 @@ CheckSimdOperationCall(FunctionCompiler &f, ParseNode *call, const ModuleCompile
case AsmJSSimdOperation_reciprocalSqrt:
return CheckSimdUnary(f, call, retType, MSimdUnaryArith::reciprocalSqrt, def, type);
case AsmJSSimdOperation_swizzle:
return CheckSimdSwizzle(f, call, retType, def, type);
case AsmJSSimdOperation_shuffle:
return CheckSimdShuffle(f, call, retType, def, type);
case AsmJSSimdOperation_splat: {
DefinitionVector defs;
Type formalType = retType.simdToCoercedScalarType();

Просмотреть файл

@ -149,6 +149,8 @@
_(or) \
_(xor) \
_(select) \
_(swizzle) \
_(shuffle) \
_(splat) \
_(withX) \
_(withY) \

Просмотреть файл

@ -832,6 +832,90 @@ assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + 'function f(){var x=i4(1,2
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32A + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); x=i4a(x,x); return i4(x);} return f'), this)(), [1, 2, 3, 4]);
assertEqX4(asmLink(asmCompile('glob', USE_ASM + I32 + I32S + 'function f(){var x=i4(1,2,3,4); var c=0; return i4(x); x=i4s(x,x); return i4(x);} return f'), this)(), [1, 2, 3, 4]);
// Swizzle
assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x, -1, 0, 0, 0);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x, 4, 0, 0, 0);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x, 0.0, 0, 0, 0);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); x=swizzle(x, 0, 0, 0, x);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var swizzle=i4.swizzle; function f() {var x=i4(1,2,3,4); var y=42; x=swizzle(x, 0, 0, 0, y);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var swizzle=i4.swizzle; function f() {var x=f4(1,2,3,4); x=swizzle(x, 0, 0, 0, 0);} return f");
function swizzle(arr, lanes) {
return [arr[lanes[0]], arr[lanes[1]], arr[lanes[2]], arr[lanes[3]]];
}
var before = Date.now();
for (var i = 0; i < Math.pow(4, 4); i++) {
var lanes = [i & 3, (i >> 2) & 3, (i >> 4) & 3, (i >> 6) & 3];
CheckI4('var swizzle=i4.swizzle;', 'var x=i4(1,2,3,4); x=swizzle(x, ' + lanes.join(',') + ')', swizzle([1,2,3,4], lanes));
CheckF4('var swizzle=f4.swizzle;', 'var x=f4(1,2,3,4); x=swizzle(x, ' + lanes.join(',') + ')', swizzle([1,2,3,4], lanes));
}
DEBUG && print('time for checking all swizzles:', Date.now() - before);
// Shuffle
assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, y, -1, 0, 0);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, y, 8, 0, 0, 0);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, y, 0.0, 0, 0, 0);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, 0, 0, 0, 0, 0);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); x=shuffle(x, y, 0, 0, 0, x);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + "var shuffle=i4.shuffle; function f() {var x=i4(1,2,3,4); var y=i4(1,2,3,4); var z=42; x=shuffle(x, y, 0, 0, 0, z);} return f");
assertAsmTypeFail('glob', USE_ASM + I32 + F32 + "var shuffle=i4.shuffle; function f() {var x=f4(1,2,3,4); x=shuffle(x, x, 0, 0, 0, 0);} return f");
function shuffle(lhs, rhs, lanes) {
return [(lanes[0] < 4 ? lhs : rhs)[lanes[0] % 4],
(lanes[1] < 4 ? lhs : rhs)[lanes[1] % 4],
(lanes[2] < 4 ? lhs : rhs)[lanes[2] % 4],
(lanes[3] < 4 ? lhs : rhs)[lanes[3] % 4]];
}
before = Date.now();
const LANE_SELECTORS = [
// Four of lhs or four of rhs, equivalent to swizzle
[0, 1, 2, 3],
[4, 5, 6, 7],
[0, 2, 3, 1],
[4, 7, 4, 6],
// One of lhs, three of rhs
[0, 4, 5, 6],
[4, 0, 5, 6],
[4, 5, 0, 6],
[4, 5, 6, 0],
// Two of lhs, two of rhs
// in one shufps
[1, 2, 4, 5],
[4, 5, 1, 2],
// in two shufps
[7, 0, 5, 2],
[0, 7, 5, 2],
[0, 7, 2, 5],
[7, 0, 2, 5],
// Three of lhs, one of rhs
[7, 0, 1, 2],
[0, 7, 1, 2],
[0, 1, 7, 2],
[0, 1, 2, 7],
// Impl-specific special cases for swizzle
[2, 3, 2, 3],
[0, 1, 0, 1],
[0, 0, 1, 1],
[2, 2, 3, 3],
// Impl-specific special cases for shuffle (case and swapped case)
[2, 3, 6, 7], [6, 7, 2, 3],
[0, 1, 4, 5], [4, 5, 0, 1],
[0, 4, 1, 5], [4, 0, 5, 1],
[2, 6, 3, 7], [6, 2, 7, 3],
[4, 1, 2, 3], [0, 5, 6, 7]
];
for (var lanes of LANE_SELECTORS) {
CheckI4('var shuffle=i4.shuffle;', 'var x=i4(1,2,3,4); var y=i4(5,6,7,8); x=shuffle(x, y, ' + lanes.join(',') + ')', shuffle([1,2,3,4], [5,6,7,8], lanes));
CheckF4('var shuffle=f4.shuffle;', 'var x=f4(1,2,3,4); var y=f4(5,6,7,8); x=shuffle(x, y, ' + lanes.join(',') + ')', shuffle([1,2,3,4], [5,6,7,8], lanes));
}
DEBUG && print('time for checking all shuffles:', Date.now() - before);
// 3. Function calls
// 3.1. No math builtins
assertAsmTypeFail('glob', USE_ASM + I32 + "var fround=glob.Math.fround; function f() {var x=i4(1,2,3,4); return +fround(x);} return f");