Skip to content

Prototype SIMD instructions implemented in LLVM #3440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions scripts/gen-s-parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@
("i32x4.le_u", "makeBinary(s, BinaryOp::LeUVecI32x4)"),
("i32x4.ge_s", "makeBinary(s, BinaryOp::GeSVecI32x4)"),
("i32x4.ge_u", "makeBinary(s, BinaryOp::GeUVecI32x4)"),
("i64x2.eq", "makeBinary(s, BinaryOp::EqVecI64x2)"),
("f32x4.eq", "makeBinary(s, BinaryOp::EqVecF32x4)"),
("f32x4.ne", "makeBinary(s, BinaryOp::NeVecF32x4)"),
("f32x4.lt", "makeBinary(s, BinaryOp::LtVecF32x4)"),
Expand All @@ -350,6 +351,10 @@
("v128.xor", "makeBinary(s, BinaryOp::XorVec128)"),
("v128.andnot", "makeBinary(s, BinaryOp::AndNotVec128)"),
("v128.bitselect", "makeSIMDTernary(s, SIMDTernaryOp::Bitselect)"),
("v8x16.signselect", "makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec8x16)"),
("v16x8.signselect", "makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec16x8)"),
("v32x4.signselect", "makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec32x4)"),
("v64x2.signselect", "makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec64x2)"),
("v128.load8_lane", "makeSIMDLoadStoreLane(s, LoadLaneVec8x16)"),
("v128.load16_lane", "makeSIMDLoadStoreLane(s, LoadLaneVec16x8)"),
("v128.load32_lane", "makeSIMDLoadStoreLane(s, LoadLaneVec32x4)"),
Expand Down Expand Up @@ -427,6 +432,7 @@
("i64x2.neg", "makeUnary(s, UnaryOp::NegVecI64x2)"),
("i64x2.any_true", "makeUnary(s, UnaryOp::AnyTrueVecI64x2)"),
("i64x2.all_true", "makeUnary(s, UnaryOp::AllTrueVecI64x2)"),
("i64x2.bitmask", "makeUnary(s, UnaryOp::BitmaskVecI64x2)"),
("i64x2.shl", "makeSIMDShift(s, SIMDShiftOp::ShlVecI64x2)"),
("i64x2.shr_s", "makeSIMDShift(s, SIMDShiftOp::ShrSVecI64x2)"),
("i64x2.shr_u", "makeSIMDShift(s, SIMDShiftOp::ShrUVecI64x2)"),
Expand Down Expand Up @@ -503,6 +509,10 @@
("i32x4.widen_high_i16x8_s", "makeUnary(s, UnaryOp::WidenHighSVecI16x8ToVecI32x4)"),
("i32x4.widen_low_i16x8_u", "makeUnary(s, UnaryOp::WidenLowUVecI16x8ToVecI32x4)"),
("i32x4.widen_high_i16x8_u", "makeUnary(s, UnaryOp::WidenHighUVecI16x8ToVecI32x4)"),
("i64x2.widen_low_i32x4_s", "makeUnary(s, UnaryOp::WidenLowSVecI32x4ToVecI64x2)"),
("i64x2.widen_high_i32x4_s", "makeUnary(s, UnaryOp::WidenHighSVecI32x4ToVecI64x2)"),
("i64x2.widen_low_i32x4_u", "makeUnary(s, UnaryOp::WidenLowUVecI32x4ToVecI64x2)"),
("i64x2.widen_high_i32x4_u", "makeUnary(s, UnaryOp::WidenHighUVecI32x4ToVecI64x2)"),
("v8x16.swizzle", "makeBinary(s, BinaryOp::SwizzleVec8x16)"),
# reference types instructions
# TODO Add table instructions
Expand Down
131 changes: 98 additions & 33 deletions src/gen-s-parser.inc
Original file line number Diff line number Diff line change
Expand Up @@ -2312,38 +2312,49 @@ switch (op[0]) {
default: goto parse_error;
}
}
case 'b':
if (strcmp(op, "i64x2.bitmask") == 0) { return makeUnary(s, UnaryOp::BitmaskVecI64x2); }
goto parse_error;
case 'e': {
switch (op[9]) {
case 'm': {
switch (op[13]) {
case 'h': {
switch (op[24]) {
case 's':
if (strcmp(op, "i64x2.extmul_high_i32x4_s") == 0) { return makeBinary(s, BinaryOp::ExtMulHighSVecI64x2); }
goto parse_error;
case 'u':
if (strcmp(op, "i64x2.extmul_high_i32x4_u") == 0) { return makeBinary(s, BinaryOp::ExtMulHighUVecI64x2); }
goto parse_error;
default: goto parse_error;
}
}
case 'l': {
switch (op[23]) {
case 's':
if (strcmp(op, "i64x2.extmul_low_i32x4_s") == 0) { return makeBinary(s, BinaryOp::ExtMulLowSVecI64x2); }
goto parse_error;
case 'u':
if (strcmp(op, "i64x2.extmul_low_i32x4_u") == 0) { return makeBinary(s, BinaryOp::ExtMulLowUVecI64x2); }
goto parse_error;
switch (op[7]) {
case 'q':
if (strcmp(op, "i64x2.eq") == 0) { return makeBinary(s, BinaryOp::EqVecI64x2); }
goto parse_error;
case 'x': {
switch (op[9]) {
case 'm': {
switch (op[13]) {
case 'h': {
switch (op[24]) {
case 's':
if (strcmp(op, "i64x2.extmul_high_i32x4_s") == 0) { return makeBinary(s, BinaryOp::ExtMulHighSVecI64x2); }
goto parse_error;
case 'u':
if (strcmp(op, "i64x2.extmul_high_i32x4_u") == 0) { return makeBinary(s, BinaryOp::ExtMulHighUVecI64x2); }
goto parse_error;
default: goto parse_error;
}
}
case 'l': {
switch (op[23]) {
case 's':
if (strcmp(op, "i64x2.extmul_low_i32x4_s") == 0) { return makeBinary(s, BinaryOp::ExtMulLowSVecI64x2); }
goto parse_error;
case 'u':
if (strcmp(op, "i64x2.extmul_low_i32x4_u") == 0) { return makeBinary(s, BinaryOp::ExtMulLowUVecI64x2); }
goto parse_error;
default: goto parse_error;
}
}
default: goto parse_error;
}
}
case 'r':
if (strcmp(op, "i64x2.extract_lane") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecI64x2, 2); }
goto parse_error;
default: goto parse_error;
}
}
case 'r':
if (strcmp(op, "i64x2.extract_lane") == 0) { return makeSIMDExtract(s, SIMDExtractOp::ExtractLaneVecI64x2, 2); }
goto parse_error;
default: goto parse_error;
}
}
Expand Down Expand Up @@ -2408,6 +2419,33 @@ switch (op[0]) {
default: goto parse_error;
}
}
case 'w': {
switch (op[12]) {
case 'h': {
switch (op[23]) {
case 's':
if (strcmp(op, "i64x2.widen_high_i32x4_s") == 0) { return makeUnary(s, UnaryOp::WidenHighSVecI32x4ToVecI64x2); }
goto parse_error;
case 'u':
if (strcmp(op, "i64x2.widen_high_i32x4_u") == 0) { return makeUnary(s, UnaryOp::WidenHighUVecI32x4ToVecI64x2); }
goto parse_error;
default: goto parse_error;
}
}
case 'l': {
switch (op[22]) {
case 's':
if (strcmp(op, "i64x2.widen_low_i32x4_s") == 0) { return makeUnary(s, UnaryOp::WidenLowSVecI32x4ToVecI64x2); }
goto parse_error;
case 'u':
if (strcmp(op, "i64x2.widen_low_i32x4_u") == 0) { return makeUnary(s, UnaryOp::WidenLowUVecI32x4ToVecI64x2); }
goto parse_error;
default: goto parse_error;
}
}
default: goto parse_error;
}
}
default: goto parse_error;
}
}
Expand Down Expand Up @@ -2962,18 +3000,42 @@ switch (op[0]) {
default: goto parse_error;
}
}
case '6':
if (strcmp(op, "v16x8.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec16x8); }
case '6': {
switch (op[6]) {
case 'l':
if (strcmp(op, "v16x8.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec16x8); }
goto parse_error;
case 's':
if (strcmp(op, "v16x8.signselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec16x8); }
goto parse_error;
default: goto parse_error;
}
}
default: goto parse_error;
}
}
case '3': {
switch (op[6]) {
case 'l':
if (strcmp(op, "v32x4.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec32x4); }
goto parse_error;
case 's':
if (strcmp(op, "v32x4.signselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec32x4); }
goto parse_error;
default: goto parse_error;
}
}
case '6': {
switch (op[6]) {
case 'l':
if (strcmp(op, "v64x2.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec64x2); }
goto parse_error;
case 's':
if (strcmp(op, "v64x2.signselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec64x2); }
goto parse_error;
default: goto parse_error;
}
}
case '3':
if (strcmp(op, "v32x4.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec32x4); }
goto parse_error;
case '6':
if (strcmp(op, "v64x2.load_splat") == 0) { return makeSIMDLoad(s, SIMDLoadOp::LoadSplatVec64x2); }
goto parse_error;
case '8': {
switch (op[6]) {
case 'l':
Expand All @@ -2984,6 +3046,9 @@ switch (op[0]) {
case 'h':
if (strcmp(op, "v8x16.shuffle") == 0) { return makeSIMDShuffle(s); }
goto parse_error;
case 'i':
if (strcmp(op, "v8x16.signselect") == 0) { return makeSIMDTernary(s, SIMDTernaryOp::SignSelectVec8x16); }
goto parse_error;
case 'w':
if (strcmp(op, "v8x16.swizzle") == 0) { return makeBinary(s, BinaryOp::SwizzleVec8x16); }
goto parse_error;
Expand Down
10 changes: 10 additions & 0 deletions src/ir/cost.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, Index> {
case NegVecI64x2:
case AnyTrueVecI64x2:
case AllTrueVecI64x2:
case BitmaskVecI64x2:
case AbsVecF32x4:
case NegVecF32x4:
case SqrtVecF32x4:
Expand Down Expand Up @@ -221,6 +222,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, Index> {
case WidenHighSVecI16x8ToVecI32x4:
case WidenLowUVecI16x8ToVecI32x4:
case WidenHighUVecI16x8ToVecI32x4:
case WidenLowSVecI32x4ToVecI64x2:
case WidenHighSVecI32x4ToVecI64x2:
case WidenLowUVecI32x4ToVecI64x2:
case WidenHighUVecI32x4ToVecI64x2:
ret = 1;
break;
case InvalidUnary:
Expand Down Expand Up @@ -363,6 +368,7 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, Index> {
case GtUVecI32x4:
case GeSVecI32x4:
case GeUVecI32x4:
case EqVecI64x2:
case EqVecF32x4:
case NeVecF32x4:
case LtVecF32x4:
Expand Down Expand Up @@ -508,6 +514,10 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, Index> {
Index ret = 0;
switch (curr->op) {
case Bitselect:
case SignSelectVec8x16:
case SignSelectVec16x8:
case SignSelectVec32x4:
case SignSelectVec64x2:
ret = 1;
break;
case QFMAF32x4:
Expand Down
1 change: 1 addition & 0 deletions src/literal.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,7 @@ class Literal {
Literal leUI32x4(const Literal& other) const;
Literal geSI32x4(const Literal& other) const;
Literal geUI32x4(const Literal& other) const;
Literal eqI64x2(const Literal& other) const;
Literal eqF32x4(const Literal& other) const;
Literal neF32x4(const Literal& other) const;
Literal ltF32x4(const Literal& other) const;
Expand Down
30 changes: 30 additions & 0 deletions src/passes/Print.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,18 @@ struct PrintExpressionContents
case QFMSF64x2:
o << "f64x2.qfms";
break;
case SignSelectVec8x16:
o << "v8x16.signselect";
break;
case SignSelectVec16x8:
o << "v16x8.signselect";
break;
case SignSelectVec32x4:
o << "v32x4.signselect";
break;
case SignSelectVec64x2:
o << "v64x2.signselect";
break;
}
}
void visitSIMDShift(SIMDShift* curr) {
Expand Down Expand Up @@ -941,6 +953,9 @@ struct PrintExpressionContents
case AllTrueVecI64x2:
o << "i64x2.all_true";
break;
case BitmaskVecI64x2:
o << "i64x2.bitmask";
break;
case AbsVecF32x4:
o << "f32x4.abs";
break;
Expand Down Expand Up @@ -1031,6 +1046,18 @@ struct PrintExpressionContents
case WidenHighUVecI16x8ToVecI32x4:
o << "i32x4.widen_high_i16x8_u";
break;
case WidenLowSVecI32x4ToVecI64x2:
o << "i64x2.widen_low_i32x4_s";
break;
case WidenHighSVecI32x4ToVecI64x2:
o << "i64x2.widen_high_i32x4_s";
break;
case WidenLowUVecI32x4ToVecI64x2:
o << "i64x2.widen_low_i32x4_u";
break;
case WidenHighUVecI32x4ToVecI64x2:
o << "i64x2.widen_high_i32x4_u";
break;
case InvalidUnary:
WASM_UNREACHABLE("unvalid unary operator");
}
Expand Down Expand Up @@ -1360,6 +1387,9 @@ struct PrintExpressionContents
case GeUVecI32x4:
o << "i32x4.ge_u";
break;
case EqVecI64x2:
o << "i64x2.eq";
break;
case EqVecF32x4:
o << "f32x4.eq";
break;
Expand Down
11 changes: 11 additions & 0 deletions src/wasm-binary.h
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,7 @@ enum ASTNodes {
I32x4LeU = 0x3e,
I32x4GeS = 0x3f,
I32x4GeU = 0x40,
I64x2Eq = 0xc0,
F32x4Eq = 0x41,
F32x4Ne = 0x42,
F32x4Lt = 0x43,
Expand All @@ -802,6 +803,11 @@ enum ASTNodes {
V128Xor = 0x51,
V128Bitselect = 0x52,

V8x16SignSelect = 0x7d,
V16x8SignSelect = 0x7e,
V32x4SignSelect = 0x7f,
V64x2SignSelect = 0x94,

V128Load8Lane = 0x58,
V128Load16Lane = 0x59,
V128Load32Lane = 0x5a,
Expand Down Expand Up @@ -885,6 +891,11 @@ enum ASTNodes {
I32x4MaxU = 0xb9,
I32x4DotSVecI16x8 = 0xba,

I64x2Bitmask = 0xc4,
I64x2WidenLowSI32x4 = 0xc7,
I64x2WidenHighSI32x4 = 0xc8,
I64x2WidenLowUI32x4 = 0xc9,
I64x2WidenHighUI32x4 = 0xca,
I64x2Neg = 0xc1,
I64x2AnyTrue = 0xc2,
I64x2AllTrue = 0xc3,
Expand Down
11 changes: 10 additions & 1 deletion src/wasm-interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,8 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
return value.anyTrueI64x2();
case AllTrueVecI64x2:
return value.allTrueI64x2();
case BitmaskVecI64x2:
WASM_UNREACHABLE("unimp");
case AbsVecF32x4:
return value.absF32x4();
case NegVecF32x4:
Expand Down Expand Up @@ -551,6 +553,11 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
return value.widenLowUToVecI32x4();
case WidenHighUVecI16x8ToVecI32x4:
return value.widenHighUToVecI32x4();
case WidenLowSVecI32x4ToVecI64x2:
case WidenHighSVecI32x4ToVecI64x2:
case WidenLowUVecI32x4ToVecI64x2:
case WidenHighUVecI32x4ToVecI64x2:
WASM_UNREACHABLE("unimp");
case InvalidUnary:
WASM_UNREACHABLE("invalid unary op");
}
Expand Down Expand Up @@ -796,6 +803,8 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
return left.geSI32x4(right);
case GeUVecI32x4:
return left.geUI32x4(right);
case EqVecI64x2:
return left.eqI64x2(right);
case EqVecF32x4:
return left.eqF32x4(right);
case NeVecF32x4:
Expand Down Expand Up @@ -1067,7 +1076,7 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
case Bitselect:
return c.bitselectV128(a, b);
default:
// TODO: implement qfma/qfms
// TODO: implement qfma/qfms and signselect
WASM_UNREACHABLE("not implemented");
}
}
Expand Down
Loading