Skip to content

Commit f12ede6

Browse files
committed
Bug 1731856 - Prototype relaxed-SIMD min/max instructions. r=lth
See WebAssembly/relaxed-simd#33 Differential Revision: https://phabricator.services.mozilla.com/D126390
1 parent 4ac9558 commit f12ede6

12 files changed

+259
-5
lines changed

js/src/jit-test/lib/wasm-binary.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,10 @@ const F32x4RelaxedFmaCode = 0xaf;
137137
const F32x4RelaxedFmsCode = 0xb0;
138138
const F64x2RelaxedFmaCode = 0xcf;
139139
const F64x2RelaxedFmsCode = 0xd0;
140+
const F32x4RelaxedMin = 0xb4;
141+
const F32x4RelaxedMax = 0xe2;
142+
const F64x2RelaxedMin = 0xd4;
143+
const F64x2RelaxedMax = 0xee;
140144

141145
// SIMD wormhole opcodes.
142146
const WORMHOLE_SELFTEST = 0;

js/src/jit-test/tests/wasm/simd/experimental.js

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ function wasmEval(bytes, imports) {
1010
return new WebAssembly.Instance(new WebAssembly.Module(bytes), imports);
1111
}
1212

13+
function wasmValidateAndEval(bytes, imports) {
14+
assertEq(WebAssembly.validate(bytes), true, "test of WasmValidate.cpp");
15+
return wasmEval(bytes, imports);
16+
}
17+
1318
function get(arr, loc, len) {
1419
let res = [];
1520
for ( let i=0; i < len; i++ ) {
@@ -82,7 +87,7 @@ for ( let [opcode, as, xs, ys, operator] of [[F32x4RelaxedFmaCode, fas, fxs, fys
8287
var k = xs.length;
8388
var ans = iota(k).map((i) => operator(as[i], xs[i], ys[i]))
8489

85-
var ins = wasmEval(moduleWithSections([
90+
var ins = wasmValidateAndEval(moduleWithSections([
8691
sigSection([v2vSig]),
8792
declSection([0]),
8893
memorySection(1),
@@ -102,4 +107,82 @@ for ( let [opcode, as, xs, ys, operator] of [[F32x4RelaxedFmaCode, fas, fxs, fys
102107
ins.exports.run();
103108
var result = get(mem, 0, k);
104109
assertSame(result, ans);
110+
111+
assertEq(false, WebAssembly.validate(moduleWithSections([
112+
sigSection([v2vSig]),
113+
declSection([0]),
114+
memorySection(1),
115+
exportSection([{funcIndex: 0, name: "run"},
116+
{memIndex: 0, name: "mem"}]),
117+
bodySection([
118+
funcBody({locals:[],
119+
body: [...V128StoreExpr(0, [...V128Load(0),
120+
...V128Load(0),
121+
SimdPrefix, varU32(opcode)])]})])])));
122+
}
123+
124+
125+
// Relaxed MIN/MAX, https://github.com/WebAssembly/relaxed-simd/issues/33
126+
127+
const Neg0 = -1/Infinity;
128+
var minMaxTests = [
129+
{a: 0, b: 0, min: 0, max: 0, },
130+
{a: Neg0, b: Neg0, min: Neg0, max: Neg0, },
131+
{a: 1/3, b: 2/3, min: 1/3, max: 2/3, },
132+
{a: -1/3, b: -2/3, min: -2/3, max: -1/3, },
133+
{a: -1000, b: 1, min: -1000, max: 1, },
134+
{a: 10, b: -2, min: -2, max: 10, },
135+
];
136+
137+
for (let k of [4, 2]) {
138+
const minOpcode = k == 4 ? F32x4RelaxedMin : F64x2RelaxedMin;
139+
const maxOpcode = k == 4 ? F32x4RelaxedMax : F64x2RelaxedMax;
140+
141+
var ins = wasmValidateAndEval(moduleWithSections([
142+
sigSection([v2vSig]),
143+
declSection([0, 0]),
144+
memorySection(1),
145+
exportSection([{funcIndex: 0, name: "min"},
146+
{funcIndex: 1, name: "max"},
147+
{memIndex: 0, name: "mem"}]),
148+
bodySection([
149+
funcBody({locals:[],
150+
body: [...V128StoreExpr(0, [...V128Load(16),
151+
...V128Load(32),
152+
SimdPrefix, varU32(minOpcode)])]}),
153+
funcBody({locals:[],
154+
body: [...V128StoreExpr(0, [...V128Load(16),
155+
...V128Load(32),
156+
SimdPrefix, varU32(maxOpcode)])]})])]));
157+
for (let i = 0; i < minMaxTests.length; i++) {
158+
var Ty = k == 4 ? Float32Array : Float64Array;
159+
var mem = new Ty(ins.exports.mem.buffer);
160+
var minResult = new Ty(k);
161+
var maxResult = new Ty(k);
162+
for (let j = 0; j < k; j++) {
163+
const {a, b, min, max } = minMaxTests[(j + i) % minMaxTests.length];
164+
mem[j + k] = a;
165+
mem[j + k * 2] = b;
166+
minResult[j] = min;
167+
maxResult[j] = max;
168+
}
169+
ins.exports.min();
170+
var result = get(mem, 0, k);
171+
assertSame(result, minResult);
172+
ins.exports.max();
173+
var result = get(mem, 0, k);
174+
assertSame(result, maxResult);
175+
}
176+
177+
for (let op of [minOpcode, maxOpcode]) {
178+
assertEq(false, WebAssembly.validate(moduleWithSections([
179+
sigSection([v2vSig]),
180+
declSection([0, 0]),
181+
memorySection(1),
182+
exportSection([]),
183+
bodySection([
184+
funcBody({locals:[],
185+
body: [...V128StoreExpr(0, [...V128Load(0),
186+
SimdPrefix, varU32(op)])]})])])));
187+
}
105188
}

js/src/jit/MacroAssembler.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3485,6 +3485,30 @@ class MacroAssembler : public MacroAssemblerSpecific {
34853485
inline void fmsFloat64x2(FloatRegister src1, FloatRegister src2,
34863486
FloatRegister srcDest) DEFINED_ON(x86_shared, arm64);
34873487

3488+
inline void minFloat32x4Relaxed(FloatRegister src, FloatRegister srcDest)
3489+
DEFINED_ON(x86_shared, arm64);
3490+
3491+
inline void minFloat32x4Relaxed(FloatRegister lhs, FloatRegister rhs,
3492+
FloatRegister dest) DEFINED_ON(arm64);
3493+
3494+
inline void maxFloat32x4Relaxed(FloatRegister src, FloatRegister srcDest)
3495+
DEFINED_ON(x86_shared, arm64);
3496+
3497+
inline void maxFloat32x4Relaxed(FloatRegister lhs, FloatRegister rhs,
3498+
FloatRegister dest) DEFINED_ON(arm64);
3499+
3500+
inline void minFloat64x2Relaxed(FloatRegister src, FloatRegister srcDest)
3501+
DEFINED_ON(x86_shared, arm64);
3502+
3503+
inline void minFloat64x2Relaxed(FloatRegister lhs, FloatRegister rhs,
3504+
FloatRegister dest) DEFINED_ON(arm64);
3505+
3506+
inline void maxFloat64x2Relaxed(FloatRegister src, FloatRegister srcDest)
3507+
DEFINED_ON(x86_shared, arm64);
3508+
3509+
inline void maxFloat64x2Relaxed(FloatRegister lhs, FloatRegister rhs,
3510+
FloatRegister dest) DEFINED_ON(arm64);
3511+
34883512
public:
34893513
// ========================================================================
34903514
// Truncate floating point.

js/src/jit/arm64/CodeGenerator-arm64.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3372,6 +3372,18 @@ void CodeGenerator::visitWasmBinarySimd128(LWasmBinarySimd128* ins) {
33723372
case wasm::SimdOp::I16x8Q15MulrSatS:
33733373
masm.q15MulrSatInt16x8(lhs, rhs, dest);
33743374
break;
3375+
case wasm::SimdOp::F32x4RelaxedMin:
3376+
masm.minFloat32x4Relaxed(lhs, rhs, dest);
3377+
break;
3378+
case wasm::SimdOp::F32x4RelaxedMax:
3379+
masm.maxFloat32x4Relaxed(lhs, rhs, dest);
3380+
break;
3381+
case wasm::SimdOp::F64x2RelaxedMin:
3382+
masm.minFloat64x2Relaxed(lhs, rhs, dest);
3383+
break;
3384+
case wasm::SimdOp::F64x2RelaxedMax:
3385+
masm.maxFloat64x2Relaxed(lhs, rhs, dest);
3386+
break;
33753387
default:
33763388
MOZ_CRASH("Binary SimdOp not implemented");
33773389
}

js/src/jit/arm64/MacroAssembler-arm64-inl.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3849,6 +3849,46 @@ void MacroAssembler::fmsFloat64x2(FloatRegister src1, FloatRegister src2,
38493849
Fmls(Simd2D(srcDest), Simd2D(src1), Simd2D(src2));
38503850
}
38513851

3852+
void MacroAssembler::minFloat32x4Relaxed(FloatRegister src,
3853+
FloatRegister srcDest) {
3854+
Fmin(Simd4S(srcDest), Simd4S(src), Simd4S(srcDest));
3855+
}
3856+
3857+
void MacroAssembler::minFloat32x4Relaxed(FloatRegister lhs, FloatRegister rhs,
3858+
FloatRegister dest) {
3859+
Fmin(Simd4S(dest), Simd4S(rhs), Simd4S(lhs));
3860+
}
3861+
3862+
void MacroAssembler::maxFloat32x4Relaxed(FloatRegister src,
3863+
FloatRegister srcDest) {
3864+
Fmax(Simd4S(srcDest), Simd4S(src), Simd4S(srcDest));
3865+
}
3866+
3867+
void MacroAssembler::maxFloat32x4Relaxed(FloatRegister lhs, FloatRegister rhs,
3868+
FloatRegister dest) {
3869+
Fmax(Simd4S(dest), Simd4S(rhs), Simd4S(lhs));
3870+
}
3871+
3872+
void MacroAssembler::minFloat64x2Relaxed(FloatRegister src,
3873+
FloatRegister srcDest) {
3874+
Fmin(Simd2D(srcDest), Simd2D(src), Simd2D(srcDest));
3875+
}
3876+
3877+
void MacroAssembler::minFloat64x2Relaxed(FloatRegister lhs, FloatRegister rhs,
3878+
FloatRegister dest) {
3879+
Fmin(Simd2D(dest), Simd2D(rhs), Simd2D(lhs));
3880+
}
3881+
3882+
void MacroAssembler::maxFloat64x2Relaxed(FloatRegister src,
3883+
FloatRegister srcDest) {
3884+
Fmax(Simd2D(srcDest), Simd2D(src), Simd2D(srcDest));
3885+
}
3886+
3887+
void MacroAssembler::maxFloat64x2Relaxed(FloatRegister lhs, FloatRegister rhs,
3888+
FloatRegister dest) {
3889+
Fmax(Simd2D(dest), Simd2D(rhs), Simd2D(lhs));
3890+
}
3891+
38523892
//}}} check_macroassembler_style
38533893
// ===============================================================
38543894

js/src/jit/x86-shared/CodeGenerator-x86-shared.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2662,6 +2662,18 @@ void CodeGenerator::visitWasmBinarySimd128(LWasmBinarySimd128* ins) {
26622662
case wasm::SimdOp::I16x8Q15MulrSatS:
26632663
masm.q15MulrSatInt16x8(rhs, lhsDest);
26642664
break;
2665+
case wasm::SimdOp::F32x4RelaxedMin:
2666+
masm.minFloat32x4Relaxed(rhs, lhsDest);
2667+
break;
2668+
case wasm::SimdOp::F32x4RelaxedMax:
2669+
masm.maxFloat32x4Relaxed(rhs, lhsDest);
2670+
break;
2671+
case wasm::SimdOp::F64x2RelaxedMin:
2672+
masm.minFloat64x2Relaxed(rhs, lhsDest);
2673+
break;
2674+
case wasm::SimdOp::F64x2RelaxedMax:
2675+
masm.maxFloat64x2Relaxed(rhs, lhsDest);
2676+
break;
26652677
# ifdef ENABLE_WASM_SIMD_WORMHOLE
26662678
case wasm::SimdOp::MozWHSELFTEST:
26672679
masm.loadConstantSimd128(wasm::WormholeSignature(), lhsDest);

js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2872,6 +2872,26 @@ void MacroAssembler::fmsFloat64x2(FloatRegister src1, FloatRegister src2,
28722872
subFloat64x2(scratch, srcDest);
28732873
}
28742874

2875+
void MacroAssembler::minFloat32x4Relaxed(FloatRegister src,
2876+
FloatRegister srcDest) {
2877+
vminps(Operand(src), srcDest, srcDest);
2878+
}
2879+
2880+
void MacroAssembler::maxFloat32x4Relaxed(FloatRegister src,
2881+
FloatRegister srcDest) {
2882+
vmaxps(Operand(src), srcDest, srcDest);
2883+
}
2884+
2885+
void MacroAssembler::minFloat64x2Relaxed(FloatRegister src,
2886+
FloatRegister srcDest) {
2887+
vminpd(Operand(src), srcDest, srcDest);
2888+
}
2889+
2890+
void MacroAssembler::maxFloat64x2Relaxed(FloatRegister src,
2891+
FloatRegister srcDest) {
2892+
vmaxpd(Operand(src), srcDest, srcDest);
2893+
}
2894+
28752895
// ========================================================================
28762896
// Truncate floating point.
28772897

js/src/wasm/WasmBaselineCompile.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7389,6 +7389,23 @@ static void RelaxedFmsF64x2(MacroAssembler& masm, RegV128 rs1, RegV128 rs2,
73897389
RegV128 rsd) {
73907390
masm.fmsFloat64x2(rs1, rs2, rsd);
73917391
}
7392+
7393+
static void RelaxedMinF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
7394+
masm.minFloat32x4Relaxed(rs, rsd);
7395+
}
7396+
7397+
static void RelaxedMaxF32x4(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
7398+
masm.maxFloat32x4Relaxed(rs, rsd);
7399+
}
7400+
7401+
static void RelaxedMinF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
7402+
masm.minFloat64x2Relaxed(rs, rsd);
7403+
}
7404+
7405+
static void RelaxedMaxF64x2(MacroAssembler& masm, RegV128 rs, RegV128 rsd) {
7406+
masm.maxFloat64x2Relaxed(rs, rsd);
7407+
}
7408+
73927409
# endif
73937410

73947411
void BaseCompiler::emitVectorAndNot() {
@@ -9008,6 +9025,26 @@ bool BaseCompiler::emitBody() {
90089025
}
90099026
CHECK_NEXT(dispatchTernary1(RelaxedFmsF64x2, ValType::V128));
90109027
break;
9028+
case uint32_t(SimdOp::F32x4RelaxedMin):
9029+
if (!moduleEnv_.v128RelaxedEnabled()) {
9030+
return iter_.unrecognizedOpcode(&op);
9031+
}
9032+
CHECK_NEXT(dispatchVectorBinary(RelaxedMinF32x4));
9033+
case uint32_t(SimdOp::F32x4RelaxedMax):
9034+
if (!moduleEnv_.v128RelaxedEnabled()) {
9035+
return iter_.unrecognizedOpcode(&op);
9036+
}
9037+
CHECK_NEXT(dispatchVectorBinary(RelaxedMaxF32x4));
9038+
case uint32_t(SimdOp::F64x2RelaxedMin):
9039+
if (!moduleEnv_.v128RelaxedEnabled()) {
9040+
return iter_.unrecognizedOpcode(&op);
9041+
}
9042+
CHECK_NEXT(dispatchVectorBinary(RelaxedMinF64x2));
9043+
case uint32_t(SimdOp::F64x2RelaxedMax):
9044+
if (!moduleEnv_.v128RelaxedEnabled()) {
9045+
return iter_.unrecognizedOpcode(&op);
9046+
}
9047+
CHECK_NEXT(dispatchVectorBinary(RelaxedMaxF64x2));
90119048
# endif
90129049
default:
90139050
break;

js/src/wasm/WasmConstants.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -683,7 +683,7 @@ enum class SimdOp {
683683
I32x4Sub = 0xb1,
684684
// SubSatS = 0xb2
685685
// SubSatU = 0xb3
686-
// Dot = 0xb4
686+
F32x4RelaxedMin = 0xb4,
687687
I32x4Mul = 0xb5,
688688
I32x4MinS = 0xb6,
689689
I32x4MinU = 0xb7,
@@ -715,7 +715,7 @@ enum class SimdOp {
715715
I64x2Sub = 0xd1,
716716
// Unused = 0xd2
717717
// Unused = 0xd3
718-
// Dot = 0xd4
718+
F64x2RelaxedMin = 0xd4,
719719
I64x2Mul = 0xd5,
720720
I64x2Eq = 0xd6,
721721
I64x2Ne = 0xd7,
@@ -729,7 +729,7 @@ enum class SimdOp {
729729
I64x2ExtMulHighUI32x4 = 0xdf,
730730
F32x4Abs = 0xe0,
731731
F32x4Neg = 0xe1,
732-
// Round = 0xe2
732+
F32x4RelaxedMax = 0xe2,
733733
F32x4Sqrt = 0xe3,
734734
F32x4Add = 0xe4,
735735
F32x4Sub = 0xe5,
@@ -741,7 +741,7 @@ enum class SimdOp {
741741
F32x4PMax = 0xeb,
742742
F64x2Abs = 0xec,
743743
F64x2Neg = 0xed,
744-
// Round = 0xee
744+
F64x2RelaxedMax = 0xee,
745745
F64x2Sqrt = 0xef,
746746
F64x2Add = 0xf0,
747747
F64x2Sub = 0xf1,

js/src/wasm/WasmIonCompile.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5463,6 +5463,15 @@ static bool EmitBodyExprs(FunctionCompiler& f) {
54635463
}
54645464
CHECK(EmitTernarySimd128(f, SimdOp(op.b1)));
54655465
}
5466+
case uint32_t(SimdOp::F32x4RelaxedMin):
5467+
case uint32_t(SimdOp::F32x4RelaxedMax):
5468+
case uint32_t(SimdOp::F64x2RelaxedMin):
5469+
case uint32_t(SimdOp::F64x2RelaxedMax): {
5470+
if (!f.moduleEnv().v128RelaxedEnabled()) {
5471+
return f.iter().unrecognizedOpcode(&op);
5472+
}
5473+
CHECK(EmitBinarySimd128(f, /* commutative= */ true, SimdOp(op.b1)));
5474+
}
54665475
# endif
54675476

54685477
default:

js/src/wasm/WasmOpIter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,10 @@ OpKind wasm::Classify(OpBytes op) {
496496
case SimdOp::I64x2ExtMulLowUI32x4:
497497
case SimdOp::I64x2ExtMulHighUI32x4:
498498
case SimdOp::I16x8Q15MulrSatS:
499+
case SimdOp::F32x4RelaxedMin:
500+
case SimdOp::F32x4RelaxedMax:
501+
case SimdOp::F64x2RelaxedMin:
502+
case SimdOp::F64x2RelaxedMax:
499503
WASM_SIMD_OP(OpKind::Binary);
500504
case SimdOp::I8x16Neg:
501505
case SimdOp::I16x8Neg:

js/src/wasm/WasmValidate.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,6 +1017,15 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
10171017
CHECK(
10181018
iter.readTernary(ValType::V128, &nothing, &nothing, &nothing));
10191019
}
1020+
case uint32_t(SimdOp::F32x4RelaxedMin):
1021+
case uint32_t(SimdOp::F32x4RelaxedMax):
1022+
case uint32_t(SimdOp::F64x2RelaxedMin):
1023+
case uint32_t(SimdOp::F64x2RelaxedMax): {
1024+
if (!env.v128RelaxedEnabled()) {
1025+
return iter.unrecognizedOpcode(&op);
1026+
}
1027+
CHECK(iter.readBinary(ValType::V128, &nothing, &nothing));
1028+
}
10201029
# endif
10211030

10221031
default:

0 commit comments

Comments
 (0)