Skip to content

Commit daa442b

Browse files
authored
Implement prototype v128.load{32,64}_zero instructions (#3011)
Specified in WebAssembly/simd#237. Since these are just prototypes necessary for benchmarking, this PR does not add support for these instructions to the fuzzer or the C or JS APIs. This PR also renumbers the QFMA instructions that previously used the opcodes for these new instructions. The renumbering matches the renumbering in V8 and LLVM.
1 parent 79f2fe4 commit daa442b

18 files changed

+126
-11
lines changed

scripts/gen-s-parser.py

+2
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,8 @@
476476
("i32x4.load16x4_u", "makeSIMDLoad(s, SIMDLoadOp::LoadExtUVec16x4ToVecI32x4)"),
477477
("i64x2.load32x2_s", "makeSIMDLoad(s, SIMDLoadOp::LoadExtSVec32x2ToVecI64x2)"),
478478
("i64x2.load32x2_u", "makeSIMDLoad(s, SIMDLoadOp::LoadExtUVec32x2ToVecI64x2)"),
479+
("v128.load32_zero", "makeSIMDLoad(s, SIMDLoadOp::Load32Zero)"),
480+
("v128.load64_zero", "makeSIMDLoad(s, SIMDLoadOp::Load64Zero)"),
479481
("i8x16.narrow_i16x8_s", "makeBinary(s, BinaryOp::NarrowSVecI16x8ToVecI8x16)"),
480482
("i8x16.narrow_i16x8_u", "makeBinary(s, BinaryOp::NarrowUVecI16x8ToVecI8x16)"),
481483
("i16x8.narrow_i32x4_s", "makeBinary(s, BinaryOp::NarrowSVecI32x4ToVecI16x8)"),

src/binaryen-c.h

+1
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,7 @@ BINARYEN_API BinaryenOp BinaryenLoadExtSVec16x4ToVecI32x4(void);
582582
BINARYEN_API BinaryenOp BinaryenLoadExtUVec16x4ToVecI32x4(void);
583583
BINARYEN_API BinaryenOp BinaryenLoadExtSVec32x2ToVecI64x2(void);
584584
BINARYEN_API BinaryenOp BinaryenLoadExtUVec32x2ToVecI64x2(void);
585+
// TODO: Add Load{32,64}Zero to C and JS APIs once merged to proposal
585586
BINARYEN_API BinaryenOp BinaryenNarrowSVecI16x8ToVecI8x16(void);
586587
BINARYEN_API BinaryenOp BinaryenNarrowUVecI16x8ToVecI8x16(void);
587588
BINARYEN_API BinaryenOp BinaryenNarrowSVecI32x4ToVecI16x8(void);

src/gen-s-parser.inc

+14-3
Original file line numberDiff line numberDiff line change
@@ -2676,9 +2676,20 @@ switch (op[0]) {
26762676
case 'c':
26772677
if (strcmp(op, "v128.const") == 0) { return makeConst(s, Type::v128); }
26782678
goto parse_error;
2679-
case 'l':
2680-
if (strcmp(op, "v128.load") == 0) { return makeLoad(s, Type::v128, /*isAtomic=*/false); }
2681-
goto parse_error;
2679+
case 'l': {
2680+
switch (op[9]) {
2681+
case '\0':
2682+
if (strcmp(op, "v128.load") == 0) { return makeLoad(s, Type::v128, /*isAtomic=*/false); }
2683+
goto parse_error;
2684+
case '3':
2685+
if (strcmp(op, "v128.load32_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load32Zero); }
2686+
goto parse_error;
2687+
case '6':
2688+
if (strcmp(op, "v128.load64_zero") == 0) { return makeSIMDLoad(s, SIMDLoadOp::Load64Zero); }
2689+
goto parse_error;
2690+
default: goto parse_error;
2691+
}
2692+
}
26822693
case 'n':
26832694
if (strcmp(op, "v128.not") == 0) { return makeUnary(s, UnaryOp::NotVec128); }
26842695
goto parse_error;

src/passes/Print.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,12 @@ struct PrintExpressionContents
485485
case LoadExtUVec32x2ToVecI64x2:
486486
o << "i64x2.load32x2_u";
487487
break;
488+
case Load32Zero:
489+
o << "v128.load32_zero";
490+
break;
491+
case Load64Zero:
492+
o << "v128.load64_zero";
493+
break;
488494
}
489495
restoreNormalColor(o);
490496
if (curr->offset) {

src/tools/fuzzing.h

+4
Original file line numberDiff line numberDiff line change
@@ -2544,6 +2544,7 @@ class TranslateToFuzzReader {
25442544
}
25452545

25462546
Expression* makeSIMDLoad() {
2547+
// TODO: add Load{32,64}Zero if merged to proposal
25472548
SIMDLoadOp op = pick(LoadSplatVec8x16,
25482549
LoadSplatVec16x8,
25492550
LoadSplatVec32x4,
@@ -2575,6 +2576,9 @@ class TranslateToFuzzReader {
25752576
case LoadExtUVec32x2ToVecI64x2:
25762577
align = pick(1, 2, 4, 8);
25772578
break;
2579+
case Load32Zero:
2580+
case Load64Zero:
2581+
WASM_UNREACHABLE("Unexpected SIMD loads");
25782582
}
25792583
Expression* ptr = makePointer();
25802584
return builder.makeSIMDLoad(op, offset, align, ptr);

src/wasm-binary.h

+6-3
Original file line numberDiff line numberDiff line change
@@ -833,12 +833,12 @@ enum ASTNodes {
833833
I32x4ShrU = 0xad,
834834
I32x4Add = 0xae,
835835
I32x4Sub = 0xb1,
836-
I32x4DotSVecI16x8 = 0xb4,
837836
I32x4Mul = 0xb5,
838837
I32x4MinS = 0xb6,
839838
I32x4MinU = 0xb7,
840839
I32x4MaxS = 0xb8,
841840
I32x4MaxU = 0xb9,
841+
I32x4DotSVecI16x8 = 0xba,
842842

843843
I64x2Neg = 0xc1,
844844
I64x2AnyTrue = 0xc2,
@@ -888,8 +888,11 @@ enum ASTNodes {
888888
F32x4ConvertSI32x4 = 0xfa,
889889
F32x4ConvertUI32x4 = 0xfb,
890890

891-
F32x4QFMA = 0xfc,
892-
F32x4QFMS = 0xfd,
891+
V128Load32Zero = 0xfc,
892+
V128Load64Zero = 0xfd,
893+
894+
F32x4QFMA = 0xb4,
895+
F32x4QFMS = 0xd4,
893896
F64x2QFMA = 0xfe,
894897
F64x2QFMS = 0xff,
895898

src/wasm-interpreter.h

+22
Original file line numberDiff line numberDiff line change
@@ -1238,6 +1238,7 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
12381238
Flow visitSIMDLoad(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
12391239
Flow visitSIMDLoadSplat(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
12401240
Flow visitSIMDLoadExtend(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
1241+
Flow visitSIMDLoadZero(SIMDLoad* curr) { WASM_UNREACHABLE("unimp"); }
12411242
Flow visitPop(Pop* curr) { WASM_UNREACHABLE("unimp"); }
12421243
Flow visitRefNull(RefNull* curr) {
12431244
NOTE_ENTER("RefNull");
@@ -2174,6 +2175,9 @@ template<typename GlobalManager, typename SubType> class ModuleInstanceBase {
21742175
case LoadExtSVec32x2ToVecI64x2:
21752176
case LoadExtUVec32x2ToVecI64x2:
21762177
return visitSIMDLoadExtend(curr);
2178+
case Load32Zero:
2179+
case Load64Zero:
2180+
return visitSIMDLoadZero(curr);
21772181
}
21782182
WASM_UNREACHABLE("invalid op");
21792183
}
@@ -2266,6 +2270,24 @@ template<typename GlobalManager, typename SubType> class ModuleInstanceBase {
22662270
}
22672271
WASM_UNREACHABLE("invalid op");
22682272
}
2273+
Flow visitSIMDLoadZero(SIMDLoad* curr) {
2274+
Flow flow = this->visit(curr->ptr);
2275+
if (flow.breaking()) {
2276+
return flow;
2277+
}
2278+
NOTE_EVAL1(flow);
2279+
Address src = instance.getFinalAddress(
2280+
curr, flow.getSingleValue(), curr->op == Load32Zero ? 32 : 64);
2281+
auto zero =
2282+
Literal::makeSingleZero(curr->op == Load32Zero ? Type::i32 : Type::i64);
2283+
if (curr->op == Load32Zero) {
2284+
auto val = Literal(instance.externalInterface->load32u(src));
2285+
return Literal(std::array<Literal, 4>{{val, zero, zero, zero}});
2286+
} else {
2287+
auto val = Literal(instance.externalInterface->load64u(src));
2288+
return Literal(std::array<Literal, 2>{{val, zero}});
2289+
}
2290+
}
22692291
Flow visitHost(Host* curr) {
22702292
NOTE_ENTER("Host");
22712293
switch (curr->op) {

src/wasm.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,9 @@ enum SIMDLoadOp {
481481
LoadExtSVec16x4ToVecI32x4,
482482
LoadExtUVec16x4ToVecI32x4,
483483
LoadExtSVec32x2ToVecI64x2,
484-
LoadExtUVec32x2ToVecI64x2
484+
LoadExtUVec32x2ToVecI64x2,
485+
Load32Zero,
486+
Load64Zero
485487
};
486488

487489
enum SIMDTernaryOp { Bitselect, QFMAF32x4, QFMSF32x4, QFMAF64x2, QFMSF64x2 };

src/wasm/wasm-binary.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -4598,6 +4598,14 @@ bool WasmBinaryBuilder::maybeVisitSIMDLoad(Expression*& out, uint32_t code) {
45984598
curr = allocator.alloc<SIMDLoad>();
45994599
curr->op = LoadExtUVec32x2ToVecI64x2;
46004600
break;
4601+
case BinaryConsts::V128Load32Zero:
4602+
curr = allocator.alloc<SIMDLoad>();
4603+
curr->op = Load32Zero;
4604+
break;
4605+
case BinaryConsts::V128Load64Zero:
4606+
curr = allocator.alloc<SIMDLoad>();
4607+
curr->op = Load64Zero;
4608+
break;
46014609
default:
46024610
return false;
46034611
}

src/wasm/wasm-s-parser.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1528,6 +1528,7 @@ Expression* SExpressionWasmBuilder::makeSIMDLoad(Element& s, SIMDLoadOp op) {
15281528
defaultAlign = 2;
15291529
break;
15301530
case LoadSplatVec32x4:
1531+
case Load32Zero:
15311532
defaultAlign = 4;
15321533
break;
15331534
case LoadSplatVec64x2:
@@ -1537,6 +1538,7 @@ Expression* SExpressionWasmBuilder::makeSIMDLoad(Element& s, SIMDLoadOp op) {
15371538
case LoadExtUVec16x4ToVecI32x4:
15381539
case LoadExtSVec32x2ToVecI64x2:
15391540
case LoadExtUVec32x2ToVecI64x2:
1541+
case Load64Zero:
15401542
defaultAlign = 8;
15411543
break;
15421544
}

src/wasm/wasm-stack.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,12 @@ void BinaryInstWriter::visitSIMDLoad(SIMDLoad* curr) {
632632
case LoadExtUVec32x2ToVecI64x2:
633633
o << U32LEB(BinaryConsts::I64x2LoadExtUVec32x2);
634634
break;
635+
case Load32Zero:
636+
o << U32LEB(BinaryConsts::V128Load32Zero);
637+
break;
638+
case Load64Zero:
639+
o << U32LEB(BinaryConsts::V128Load64Zero);
640+
break;
635641
}
636642
assert(curr->align);
637643
emitMemoryAccess(curr->align, /*(unused) bytes=*/0, curr->offset);

src/wasm/wasm-validator.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -1139,6 +1139,7 @@ void FunctionValidator::visitSIMDLoad(SIMDLoad* curr) {
11391139
case LoadSplatVec8x16:
11401140
case LoadSplatVec16x8:
11411141
case LoadSplatVec32x4:
1142+
case Load32Zero:
11421143
memAlignType = Type::i32;
11431144
break;
11441145
case LoadSplatVec64x2:
@@ -1148,6 +1149,7 @@ void FunctionValidator::visitSIMDLoad(SIMDLoad* curr) {
11481149
case LoadExtUVec16x4ToVecI32x4:
11491150
case LoadExtSVec32x2ToVecI64x2:
11501151
case LoadExtUVec32x2ToVecI64x2:
1152+
case Load64Zero:
11511153
memAlignType = Type::i64;
11521154
break;
11531155
}

src/wasm/wasm.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ Index SIMDLoad::getMemBytes() {
629629
case LoadSplatVec16x8:
630630
return 2;
631631
case LoadSplatVec32x4:
632+
case Load32Zero:
632633
return 4;
633634
case LoadSplatVec64x2:
634635
case LoadExtSVec8x8ToVecI16x8:
@@ -637,6 +638,7 @@ Index SIMDLoad::getMemBytes() {
637638
case LoadExtUVec16x4ToVecI32x4:
638639
case LoadExtSVec32x2ToVecI64x2:
639640
case LoadExtUVec32x2ToVecI64x2:
641+
case Load64Zero:
640642
return 8;
641643
}
642644
WASM_UNREACHABLE("unexpected op");

test/simd.wast

+10
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,16 @@
11441144
(local.get $0)
11451145
)
11461146
)
1147+
(func $v128.load32_zero (param $0 i32) (result v128)
1148+
(v128.load32_zero
1149+
(local.get $0)
1150+
)
1151+
)
1152+
(func $v128.load64_zero (param $0 i32) (result v128)
1153+
(v128.load64_zero
1154+
(local.get $0)
1155+
)
1156+
)
11471157
(func $v8x16.swizzle (param $0 v128) (param $1 v128) (result v128)
11481158
(v8x16.swizzle
11491159
(local.get $0)

test/simd.wast.from-wast

+11-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
(type $v128_v128_=>_v128 (func (param v128 v128) (result v128)))
33
(type $v128_=>_v128 (func (param v128) (result v128)))
44
(type $v128_=>_i32 (func (param v128) (result i32)))
5-
(type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
65
(type $i32_=>_v128 (func (param i32) (result v128)))
6+
(type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
77
(type $none_=>_v128 (func (result v128)))
88
(type $v128_v128_v128_=>_v128 (func (param v128 v128 v128) (result v128)))
99
(type $i32_v128_=>_none (func (param i32 v128)))
@@ -1160,6 +1160,16 @@
11601160
(local.get $0)
11611161
)
11621162
)
1163+
(func $v128.load32_zero (param $0 i32) (result v128)
1164+
(v128.load32_zero
1165+
(local.get $0)
1166+
)
1167+
)
1168+
(func $v128.load64_zero (param $0 i32) (result v128)
1169+
(v128.load64_zero
1170+
(local.get $0)
1171+
)
1172+
)
11631173
(func $v8x16.swizzle (param $0 v128) (param $1 v128) (result v128)
11641174
(v8x16.swizzle
11651175
(local.get $0)

test/simd.wast.fromBinary

+11-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
(type $v128_v128_=>_v128 (func (param v128 v128) (result v128)))
33
(type $v128_=>_v128 (func (param v128) (result v128)))
44
(type $v128_=>_i32 (func (param v128) (result i32)))
5-
(type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
65
(type $i32_=>_v128 (func (param i32) (result v128)))
6+
(type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
77
(type $none_=>_v128 (func (result v128)))
88
(type $v128_v128_v128_=>_v128 (func (param v128 v128 v128) (result v128)))
99
(type $i32_v128_=>_none (func (param i32 v128)))
@@ -1160,6 +1160,16 @@
11601160
(local.get $0)
11611161
)
11621162
)
1163+
(func $v128.load32_zero (param $0 i32) (result v128)
1164+
(v128.load32_zero
1165+
(local.get $0)
1166+
)
1167+
)
1168+
(func $v128.load64_zero (param $0 i32) (result v128)
1169+
(v128.load64_zero
1170+
(local.get $0)
1171+
)
1172+
)
11631173
(func $v8x16.swizzle (param $0 v128) (param $1 v128) (result v128)
11641174
(v8x16.swizzle
11651175
(local.get $0)

test/simd.wast.fromBinary.noDebugInfo

+12-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
(type $v128_v128_=>_v128 (func (param v128 v128) (result v128)))
33
(type $v128_=>_v128 (func (param v128) (result v128)))
44
(type $v128_=>_i32 (func (param v128) (result i32)))
5-
(type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
65
(type $i32_=>_v128 (func (param i32) (result v128)))
6+
(type $v128_i32_=>_v128 (func (param v128 i32) (result v128)))
77
(type $none_=>_v128 (func (result v128)))
88
(type $v128_v128_v128_=>_v128 (func (param v128 v128 v128) (result v128)))
99
(type $i32_v128_=>_none (func (param i32 v128)))
@@ -1160,7 +1160,17 @@
11601160
(local.get $0)
11611161
)
11621162
)
1163-
(func $205 (param $0 v128) (param $1 v128) (result v128)
1163+
(func $205 (param $0 i32) (result v128)
1164+
(v128.load32_zero
1165+
(local.get $0)
1166+
)
1167+
)
1168+
(func $206 (param $0 i32) (result v128)
1169+
(v128.load64_zero
1170+
(local.get $0)
1171+
)
1172+
)
1173+
(func $207 (param $0 v128) (param $1 v128) (result v128)
11641174
(v8x16.swizzle
11651175
(local.get $0)
11661176
(local.get $1)

test/spec/simd.wast

+4
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,8 @@
232232
(func (export "i32x4.load16x4_s") (param $0 i32) (result v128) (i32x4.load16x4_s (local.get $0)))
233233
(func (export "i64x2.load32x2_u") (param $0 i32) (result v128) (i64x2.load32x2_u (local.get $0)))
234234
(func (export "i64x2.load32x2_s") (param $0 i32) (result v128) (i64x2.load32x2_s (local.get $0)))
235+
(func (export "v128.load32_zero") (param $0 i32) (result v128) (v128.load32_zero (local.get $0)))
236+
(func (export "v128.load64_zero") (param $0 i32) (result v128) (v128.load64_zero (local.get $0)))
235237
(func (export "v8x16.swizzle") (param $0 v128) (param $1 v128) (result v128) (v8x16.swizzle (local.get $0) (local.get $1)))
236238
)
237239

@@ -944,6 +946,8 @@
944946
(assert_return (invoke "i32x4.load16x4_u" (i32.const 256)) (v128.const i32x4 0x00009080 0x0000b0a0 0x0000d0c0 0x0000f0e0))
945947
(assert_return (invoke "i64x2.load32x2_s" (i32.const 256)) (v128.const i64x2 0xffffffffb0a09080 0xfffffffff0e0d0c0))
946948
(assert_return (invoke "i64x2.load32x2_u" (i32.const 256)) (v128.const i64x2 0x00000000b0a09080 0x00000000f0e0d0c0))
949+
(assert_return (invoke "v128.load32_zero" (i32.const 256)) (v128.const i32x4 0xb0a09080 0 0 0))
950+
(assert_return (invoke "v128.load64_zero" (i32.const 256)) (v128.const i64x2 0xf0e0d0c0b0a09080 0))
947951
(assert_return
948952
(invoke "v8x16.swizzle"
949953
(v128.const i8x16 0xf0 0xf1 0xf2 0xf3 0xf4 0xf5 0xf6 0xf7 0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff)

0 commit comments

Comments
 (0)