Skip to content

Commit 74c6c69

Browse files
committed
Implement pseudo-min/max SIMD instructions
As specified in WebAssembly/simd#122.
1 parent 655fd6b commit 74c6c69

24 files changed

+389
-47
lines changed

scripts/gen-s-parser.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,8 @@
435435
("f32x4.div", "makeBinary(s, BinaryOp::DivVecF32x4)"),
436436
("f32x4.min", "makeBinary(s, BinaryOp::MinVecF32x4)"),
437437
("f32x4.max", "makeBinary(s, BinaryOp::MaxVecF32x4)"),
438+
("f32x4.pmin", "makeBinary(s, BinaryOp::PMinVecF32x4)"),
439+
("f32x4.pmax", "makeBinary(s, BinaryOp::PMaxVecF32x4)"),
438440
("f64x2.abs", "makeUnary(s, UnaryOp::AbsVecF64x2)"),
439441
("f64x2.neg", "makeUnary(s, UnaryOp::NegVecF64x2)"),
440442
("f64x2.sqrt", "makeUnary(s, UnaryOp::SqrtVecF64x2)"),
@@ -446,6 +448,8 @@
446448
("f64x2.div", "makeBinary(s, BinaryOp::DivVecF64x2)"),
447449
("f64x2.min", "makeBinary(s, BinaryOp::MinVecF64x2)"),
448450
("f64x2.max", "makeBinary(s, BinaryOp::MaxVecF64x2)"),
451+
("f64x2.pmin", "makeBinary(s, BinaryOp::PMinVecF64x2)"),
452+
("f64x2.pmax", "makeBinary(s, BinaryOp::PMaxVecF64x2)"),
449453
("i32x4.trunc_sat_f32x4_s", "makeUnary(s, UnaryOp::TruncSatSVecF32x4ToVecI32x4)"),
450454
("i32x4.trunc_sat_f32x4_u", "makeUnary(s, UnaryOp::TruncSatUVecF32x4ToVecI32x4)"),
451455
("i64x2.trunc_sat_f64x2_s", "makeUnary(s, UnaryOp::TruncSatSVecF64x2ToVecI64x2)"),

src/binaryen-c.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,8 @@ BinaryenOp BinaryenMulVecF32x4(void) { return MulVecF32x4; }
681681
BinaryenOp BinaryenDivVecF32x4(void) { return DivVecF32x4; }
682682
BinaryenOp BinaryenMinVecF32x4(void) { return MinVecF32x4; }
683683
BinaryenOp BinaryenMaxVecF32x4(void) { return MaxVecF32x4; }
684+
BinaryenOp BinaryenPMinVecF32x4(void) { return PMinVecF32x4; }
685+
BinaryenOp BinaryenPMaxVecF32x4(void) { return PMaxVecF32x4; }
684686
BinaryenOp BinaryenAbsVecF64x2(void) { return AbsVecF64x2; }
685687
BinaryenOp BinaryenNegVecF64x2(void) { return NegVecF64x2; }
686688
BinaryenOp BinaryenSqrtVecF64x2(void) { return SqrtVecF64x2; }
@@ -692,6 +694,8 @@ BinaryenOp BinaryenMulVecF64x2(void) { return MulVecF64x2; }
692694
BinaryenOp BinaryenDivVecF64x2(void) { return DivVecF64x2; }
693695
BinaryenOp BinaryenMinVecF64x2(void) { return MinVecF64x2; }
694696
BinaryenOp BinaryenMaxVecF64x2(void) { return MaxVecF64x2; }
697+
BinaryenOp BinaryenPMinVecF64x2(void) { return PMinVecF64x2; }
698+
BinaryenOp BinaryenPMaxVecF64x2(void) { return PMaxVecF64x2; }
695699
BinaryenOp BinaryenTruncSatSVecF32x4ToVecI32x4(void) {
696700
return TruncSatSVecF32x4ToVecI32x4;
697701
}

src/binaryen-c.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,8 @@ BINARYEN_API BinaryenOp BinaryenMulVecF32x4(void);
541541
BINARYEN_API BinaryenOp BinaryenDivVecF32x4(void);
542542
BINARYEN_API BinaryenOp BinaryenMinVecF32x4(void);
543543
BINARYEN_API BinaryenOp BinaryenMaxVecF32x4(void);
544+
BINARYEN_API BinaryenOp BinaryenPMinVecF32x4(void);
545+
BINARYEN_API BinaryenOp BinaryenPMaxVecF32x4(void);
544546
BINARYEN_API BinaryenOp BinaryenAbsVecF64x2(void);
545547
BINARYEN_API BinaryenOp BinaryenNegVecF64x2(void);
546548
BINARYEN_API BinaryenOp BinaryenSqrtVecF64x2(void);
@@ -552,6 +554,8 @@ BINARYEN_API BinaryenOp BinaryenMulVecF64x2(void);
552554
BINARYEN_API BinaryenOp BinaryenDivVecF64x2(void);
553555
BINARYEN_API BinaryenOp BinaryenMinVecF64x2(void);
554556
BINARYEN_API BinaryenOp BinaryenMaxVecF64x2(void);
557+
BINARYEN_API BinaryenOp BinaryenPMinVecF64x2(void);
558+
BINARYEN_API BinaryenOp BinaryenPMaxVecF64x2(void);
555559
BINARYEN_API BinaryenOp BinaryenTruncSatSVecF32x4ToVecI32x4(void);
556560
BINARYEN_API BinaryenOp BinaryenTruncSatUVecF32x4ToVecI32x4(void);
557561
BINARYEN_API BinaryenOp BinaryenTruncSatSVecF64x2ToVecI64x2(void);

src/gen-s-parser.inc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,17 @@ switch (op[0]) {
338338
default: goto parse_error;
339339
}
340340
}
341+
case 'p': {
342+
switch (op[8]) {
343+
case 'a':
344+
if (strcmp(op, "f32x4.pmax") == 0) { return makeBinary(s, BinaryOp::PMaxVecF32x4); }
345+
goto parse_error;
346+
case 'i':
347+
if (strcmp(op, "f32x4.pmin") == 0) { return makeBinary(s, BinaryOp::PMinVecF32x4); }
348+
goto parse_error;
349+
default: goto parse_error;
350+
}
351+
}
341352
case 'q': {
342353
switch (op[9]) {
343354
case 'a':
@@ -619,6 +630,17 @@ switch (op[0]) {
619630
default: goto parse_error;
620631
}
621632
}
633+
case 'p': {
634+
switch (op[8]) {
635+
case 'a':
636+
if (strcmp(op, "f64x2.pmax") == 0) { return makeBinary(s, BinaryOp::PMaxVecF64x2); }
637+
goto parse_error;
638+
case 'i':
639+
if (strcmp(op, "f64x2.pmin") == 0) { return makeBinary(s, BinaryOp::PMinVecF64x2); }
640+
goto parse_error;
641+
default: goto parse_error;
642+
}
643+
}
622644
case 'q': {
623645
switch (op[9]) {
624646
case 'a':

src/ir/cost.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,12 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> {
687687
case MaxVecF32x4:
688688
ret = 1;
689689
break;
690+
case PMinVecF32x4:
691+
ret = 1;
692+
break;
693+
case PMaxVecF32x4:
694+
ret = 1;
695+
break;
690696
case AddVecF64x2:
691697
ret = 1;
692698
break;
@@ -705,6 +711,12 @@ struct CostAnalyzer : public Visitor<CostAnalyzer, Index> {
705711
case MaxVecF64x2:
706712
ret = 1;
707713
break;
714+
case PMinVecF64x2:
715+
ret = 1;
716+
break;
717+
case PMaxVecF64x2:
718+
ret = 1;
719+
break;
708720
case NarrowSVecI16x8ToVecI8x16:
709721
ret = 1;
710722
break;

src/js/binaryen.js-post.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,8 @@ function initializeConstants() {
421421
'DivVecF32x4',
422422
'MinVecF32x4',
423423
'MaxVecF32x4',
424+
'PMinVecF32x4',
425+
'PMaxVecF32x4',
424426
'AbsVecF64x2',
425427
'NegVecF64x2',
426428
'SqrtVecF64x2',
@@ -432,6 +434,8 @@ function initializeConstants() {
432434
'DivVecF64x2',
433435
'MinVecF64x2',
434436
'MaxVecF64x2',
437+
'PMinVecF64x2',
438+
'PMaxVecF64x2',
435439
'TruncSatSVecF32x4ToVecI32x4',
436440
'TruncSatUVecF32x4ToVecI32x4',
437441
'TruncSatSVecF64x2ToVecI64x2',
@@ -1904,6 +1908,12 @@ function wrapModule(module, self) {
19041908
'max': function(left, right) {
19051909
return Module['_BinaryenBinary'](module, Module['MaxVecF32x4'], left, right);
19061910
},
1911+
'pmin': function(left, right) {
1912+
return Module['_BinaryenBinary'](module, Module['PMinVecF32x4'], left, right);
1913+
},
1914+
'pmax': function(left, right) {
1915+
return Module['_BinaryenBinary'](module, Module['PMaxVecF32x4'], left, right);
1916+
},
19071917
'convert_i32x4_s': function(value) {
19081918
return Module['_BinaryenUnary'](module, Module['ConvertSVecI32x4ToVecF32x4'], value);
19091919
},
@@ -1973,6 +1983,12 @@ function wrapModule(module, self) {
19731983
'max': function(left, right) {
19741984
return Module['_BinaryenBinary'](module, Module['MaxVecF64x2'], left, right);
19751985
},
1986+
'pmin': function(left, right) {
1987+
return Module['_BinaryenBinary'](module, Module['PMinVecF64x2'], left, right);
1988+
},
1989+
'pmax': function(left, right) {
1990+
return Module['_BinaryenBinary'](module, Module['PMaxVecF64x2'], left, right);
1991+
},
19761992
'convert_i64x2_s': function(value) {
19771993
return Module['_BinaryenUnary'](module, Module['ConvertSVecI64x2ToVecF64x2'], value);
19781994
},

src/literal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ class Literal {
271271

272272
Literal min(const Literal& other) const;
273273
Literal max(const Literal& other) const;
274+
Literal pmin(const Literal& other) const;
275+
Literal pmax(const Literal& other) const;
274276
Literal copysign(const Literal& other) const;
275277

276278
std::array<Literal, 16> getLanesSI8x16() const;
@@ -424,6 +426,8 @@ class Literal {
424426
Literal divF32x4(const Literal& other) const;
425427
Literal minF32x4(const Literal& other) const;
426428
Literal maxF32x4(const Literal& other) const;
429+
Literal pminF32x4(const Literal& other) const;
430+
Literal pmaxF32x4(const Literal& other) const;
427431
Literal absF64x2() const;
428432
Literal negF64x2() const;
429433
Literal sqrtF64x2() const;
@@ -433,6 +437,8 @@ class Literal {
433437
Literal divF64x2(const Literal& other) const;
434438
Literal minF64x2(const Literal& other) const;
435439
Literal maxF64x2(const Literal& other) const;
440+
Literal pminF64x2(const Literal& other) const;
441+
Literal pmaxF64x2(const Literal& other) const;
436442
Literal truncSatToSI32x4() const;
437443
Literal truncSatToUI32x4() const;
438444
Literal truncSatToSI64x2() const;

src/passes/Print.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,12 @@ struct PrintExpressionContents
13371337
case MaxVecF32x4:
13381338
o << "f32x4.max";
13391339
break;
1340+
case PMinVecF32x4:
1341+
o << "f32x4.pmin";
1342+
break;
1343+
case PMaxVecF32x4:
1344+
o << "f32x4.pmax";
1345+
break;
13401346
case AddVecF64x2:
13411347
o << "f64x2.add";
13421348
break;
@@ -1355,6 +1361,12 @@ struct PrintExpressionContents
13551361
case MaxVecF64x2:
13561362
o << "f64x2.max";
13571363
break;
1364+
case PMinVecF64x2:
1365+
o << "f64x2.pmin";
1366+
break;
1367+
case PMaxVecF64x2:
1368+
o << "f64x2.pmax";
1369+
break;
13581370

13591371
case NarrowSVecI16x8ToVecI8x16:
13601372
o << "i8x16.narrow_i16x8_s";

src/wasm-binary.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,8 @@ enum ASTNodes {
859859
F32x4Div = 0xe7,
860860
F32x4Min = 0xe8,
861861
F32x4Max = 0xe9,
862+
F32x4PMin = 0xea,
863+
F32x4PMax = 0xeb,
862864

863865
F64x2Abs = 0xec,
864866
F64x2Neg = 0xed,
@@ -869,6 +871,8 @@ enum ASTNodes {
869871
F64x2Div = 0xf3,
870872
F64x2Min = 0xf4,
871873
F64x2Max = 0xf5,
874+
F64x2PMin = 0xf6,
875+
F64x2PMax = 0xf7,
872876

873877
I32x4TruncSatSF32x4 = 0xf8,
874878
I32x4TruncSatUF32x4 = 0xf9,

src/wasm-interpreter.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -893,6 +893,10 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
893893
return left.minF32x4(right);
894894
case MaxVecF32x4:
895895
return left.maxF32x4(right);
896+
case PMinVecF32x4:
897+
return left.pminF32x4(right);
898+
case PMaxVecF32x4:
899+
return right.pmaxF32x4(right);
896900
case AddVecF64x2:
897901
return left.addF64x2(right);
898902
case SubVecF64x2:
@@ -905,6 +909,10 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
905909
return left.minF64x2(right);
906910
case MaxVecF64x2:
907911
return left.maxF64x2(right);
912+
case PMinVecF64x2:
913+
return left.pminF64x2(right);
914+
case PMaxVecF64x2:
915+
return left.pmaxF64x2(right);
908916

909917
case NarrowSVecI16x8ToVecI8x16:
910918
return left.narrowSToVecI8x16(right);

src/wasm.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,12 +400,16 @@ enum BinaryOp {
400400
DivVecF32x4,
401401
MinVecF32x4,
402402
MaxVecF32x4,
403+
PMinVecF32x4,
404+
PMaxVecF32x4,
403405
AddVecF64x2,
404406
SubVecF64x2,
405407
MulVecF64x2,
406408
DivVecF64x2,
407409
MinVecF64x2,
408410
MaxVecF64x2,
411+
PMinVecF64x2,
412+
PMaxVecF64x2,
409413

410414
// SIMD Conversion
411415
NarrowSVecI16x8ToVecI8x16,

src/wasm/literal.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,26 @@ Literal Literal::max(const Literal& other) const {
13211321
}
13221322
}
13231323

1324+
Literal Literal::pmin(const Literal& other) const {
1325+
switch (type.getSingle()) {
1326+
case Type::f32:
1327+
case Type::f64:
1328+
return other.lt(*this).geti32() ? other : *this;
1329+
default:
1330+
WASM_UNREACHABLE("unexpected type");
1331+
}
1332+
}
1333+
1334+
Literal Literal::pmax(const Literal& other) const {
1335+
switch (type.getSingle()) {
1336+
case Type::f32:
1337+
case Type::f64:
1338+
return this->lt(other).geti32() ? other : *this;
1339+
default:
1340+
WASM_UNREACHABLE("unexpected type");
1341+
}
1342+
}
1343+
13241344
Literal Literal::copysign(const Literal& other) const {
13251345
// operate on bits directly, to avoid signalling bit being set on a float
13261346
switch (type.getSingle()) {
@@ -1958,6 +1978,12 @@ Literal Literal::minF32x4(const Literal& other) const {
19581978
Literal Literal::maxF32x4(const Literal& other) const {
19591979
return binary<4, &Literal::getLanesF32x4, &Literal::max>(*this, other);
19601980
}
1981+
Literal Literal::pminF32x4(const Literal& other) const {
1982+
return binary<4, &Literal::getLanesF32x4, &Literal::pmin>(*this, other);
1983+
}
1984+
Literal Literal::pmaxF32x4(const Literal& other) const {
1985+
return binary<4, &Literal::getLanesF32x4, &Literal::pmax>(*this, other);
1986+
}
19611987
Literal Literal::addF64x2(const Literal& other) const {
19621988
return binary<2, &Literal::getLanesF64x2, &Literal::add>(*this, other);
19631989
}
@@ -1976,6 +2002,12 @@ Literal Literal::minF64x2(const Literal& other) const {
19762002
Literal Literal::maxF64x2(const Literal& other) const {
19772003
return binary<2, &Literal::getLanesF64x2, &Literal::max>(*this, other);
19782004
}
2005+
Literal Literal::pminF64x2(const Literal& other) const {
2006+
return binary<2, &Literal::getLanesF64x2, &Literal::pmin>(*this, other);
2007+
}
2008+
Literal Literal::pmaxF64x2(const Literal& other) const {
2009+
return binary<2, &Literal::getLanesF64x2, &Literal::pmax>(*this, other);
2010+
}
19792011

19802012
Literal Literal::dotSI16x8toI32x4(const Literal& other) const {
19812013
LaneArray<8> lhs = getLanesSI16x8();

src/wasm/wasm-binary.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4009,6 +4009,14 @@ bool WasmBinaryBuilder::maybeVisitSIMDBinary(Expression*& out, uint32_t code) {
40094009
curr = allocator.alloc<Binary>();
40104010
curr->op = MaxVecF32x4;
40114011
break;
4012+
case BinaryConsts::F32x4PMin:
4013+
curr = allocator.alloc<Binary>();
4014+
curr->op = PMinVecF32x4;
4015+
break;
4016+
case BinaryConsts::F32x4PMax:
4017+
curr = allocator.alloc<Binary>();
4018+
curr->op = PMaxVecF32x4;
4019+
break;
40124020
case BinaryConsts::F64x2Add:
40134021
curr = allocator.alloc<Binary>();
40144022
curr->op = AddVecF64x2;
@@ -4033,6 +4041,14 @@ bool WasmBinaryBuilder::maybeVisitSIMDBinary(Expression*& out, uint32_t code) {
40334041
curr = allocator.alloc<Binary>();
40344042
curr->op = MaxVecF64x2;
40354043
break;
4044+
case BinaryConsts::F64x2PMin:
4045+
curr = allocator.alloc<Binary>();
4046+
curr->op = PMinVecF64x2;
4047+
break;
4048+
case BinaryConsts::F64x2PMax:
4049+
curr = allocator.alloc<Binary>();
4050+
curr->op = PMaxVecF64x2;
4051+
break;
40364052
case BinaryConsts::I8x16NarrowSI16x8:
40374053
curr = allocator.alloc<Binary>();
40384054
curr->op = NarrowSVecI16x8ToVecI8x16;

src/wasm/wasm-stack.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,6 +1561,12 @@ void BinaryInstWriter::visitBinary(Binary* curr) {
15611561
case MaxVecF32x4:
15621562
o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4Max);
15631563
break;
1564+
case PMinVecF32x4:
1565+
o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4PMin);
1566+
break;
1567+
case PMaxVecF32x4:
1568+
o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F32x4PMax);
1569+
break;
15641570
case AddVecF64x2:
15651571
o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Add);
15661572
break;
@@ -1579,6 +1585,12 @@ void BinaryInstWriter::visitBinary(Binary* curr) {
15791585
case MaxVecF64x2:
15801586
o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Max);
15811587
break;
1588+
case PMinVecF64x2:
1589+
o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2PMin);
1590+
break;
1591+
case PMaxVecF64x2:
1592+
o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2PMax);
1593+
break;
15821594

15831595
case NarrowSVecI16x8ToVecI8x16:
15841596
o << int8_t(BinaryConsts::SIMDPrefix)

src/wasm/wasm-validator.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1455,12 +1455,16 @@ void FunctionValidator::visitBinary(Binary* curr) {
14551455
case DivVecF32x4:
14561456
case MinVecF32x4:
14571457
case MaxVecF32x4:
1458+
case PMinVecF32x4:
1459+
case PMaxVecF32x4:
14581460
case AddVecF64x2:
14591461
case SubVecF64x2:
14601462
case MulVecF64x2:
14611463
case DivVecF64x2:
14621464
case MinVecF64x2:
14631465
case MaxVecF64x2:
1466+
case PMinVecF64x2:
1467+
case PMaxVecF64x2:
14641468
case NarrowSVecI16x8ToVecI8x16:
14651469
case NarrowUVecI16x8ToVecI8x16:
14661470
case NarrowSVecI32x4ToVecI16x8:

0 commit comments

Comments
 (0)