Skip to content

Commit fd2a006

Browse files
committed
Prototype prefetch instructions
As proposed in WebAssembly/simd#352, using the opcodes used in the LLVM and V8 implementations.
1 parent b79661e commit fd2a006

21 files changed

+194
-3
lines changed

scripts/gen-s-parser.py

+3
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,9 @@
516516
("i16x8.extadd_pairwise_i8x16_u", "makeUnary(s, UnaryOp::ExtAddPairwiseUVecI8x16ToI16x8)"),
517517
("i32x4.extadd_pairwise_i16x8_s", "makeUnary(s, UnaryOp::ExtAddPairwiseSVecI16x8ToI32x4)"),
518518
("i32x4.extadd_pairwise_i16x8_u", "makeUnary(s, UnaryOp::ExtAddPairwiseUVecI16x8ToI32x4)"),
519+
# prefetch instructions
520+
("prefetch.t", "makePrefetch(s, PrefetchOp::PrefetchTemporal)"),
521+
("prefetch.nt", "makePrefetch(s, PrefetchOp::PrefetchNontemporal)"),
519522
# reference types instructions
520523
# TODO Add table instructions
521524
("ref.null", "makeRefNull(s)"),

src/gen-s-parser.inc

+19-3
Original file line numberDiff line numberDiff line change
@@ -2759,9 +2759,25 @@ switch (op[0]) {
27592759
case 'n':
27602760
if (strcmp(op, "nop") == 0) { return makeNop(); }
27612761
goto parse_error;
2762-
case 'p':
2763-
if (strcmp(op, "pop") == 0) { return makePop(s); }
2764-
goto parse_error;
2762+
case 'p': {
2763+
switch (op[1]) {
2764+
case 'o':
2765+
if (strcmp(op, "pop") == 0) { return makePop(s); }
2766+
goto parse_error;
2767+
case 'r': {
2768+
switch (op[9]) {
2769+
case 'n':
2770+
if (strcmp(op, "prefetch.nt") == 0) { return makePrefetch(s, PrefetchOp::PrefetchNontemporal); }
2771+
goto parse_error;
2772+
case 't':
2773+
if (strcmp(op, "prefetch.t") == 0) { return makePrefetch(s, PrefetchOp::PrefetchTemporal); }
2774+
goto parse_error;
2775+
default: goto parse_error;
2776+
}
2777+
}
2778+
default: goto parse_error;
2779+
}
2780+
}
27652781
case 'r': {
27662782
switch (op[1]) {
27672783
case 'e': {

src/ir/ReFinalize.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ void ReFinalize::visitSIMDLoad(SIMDLoad* curr) { curr->finalize(); }
112112
void ReFinalize::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
113113
curr->finalize();
114114
}
115+
void ReFinalize::visitPrefetch(Prefetch* curr) { curr->finalize(); }
115116
void ReFinalize::visitMemoryInit(MemoryInit* curr) { curr->finalize(); }
116117
void ReFinalize::visitDataDrop(DataDrop* curr) { curr->finalize(); }
117118
void ReFinalize::visitMemoryCopy(MemoryCopy* curr) { curr->finalize(); }

src/ir/cost.h

+1
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ struct CostAnalyzer : public OverriddenVisitor<CostAnalyzer, Index> {
537537
Index visitSIMDShuffle(SIMDShuffle* curr) {
538538
return 1 + visit(curr->left) + visit(curr->right);
539539
}
540+
Index visitPrefetch(Prefetch* curr) { return 1 + visit(curr->ptr); }
540541
Index visitRefNull(RefNull* curr) { return 1; }
541542
Index visitRefIsNull(RefIsNull* curr) { return 1 + visit(curr->value); }
542543
Index visitRefFunc(RefFunc* curr) { return 1; }

src/ir/effects.h

+5
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,11 @@ class EffectAnalyzer {
415415
}
416416
parent.implicitTrap = true;
417417
}
418+
void visitPrefetch(Prefetch* curr) {
419+
// Do not reorder with respect to other memory ops
420+
parent.writesMemory = true;
421+
parent.readsMemory = true;
422+
}
418423
void visitMemoryInit(MemoryInit* curr) {
419424
parent.writesMemory = true;
420425
parent.implicitTrap = true;

src/passes/Print.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,24 @@ struct PrintExpressionContents
683683
}
684684
o << " " << int(curr->index);
685685
}
686+
void visitPrefetch(Prefetch* curr) {
687+
prepareColor(o);
688+
switch (curr->op) {
689+
case PrefetchTemporal:
690+
o << "prefetch.t";
691+
break;
692+
case PrefetchNontemporal:
693+
o << "prefetch.nt";
694+
break;
695+
}
696+
restoreNormalColor(o);
697+
if (curr->offset) {
698+
o << " offset=" << curr->offset;
699+
}
700+
if (curr->align != 1) {
701+
o << " align=" << curr->align;
702+
}
703+
}
686704
void visitMemoryInit(MemoryInit* curr) {
687705
prepareColor(o);
688706
o << "memory.init " << curr->segment;
@@ -2212,6 +2230,13 @@ struct PrintSExpression : public OverriddenVisitor<PrintSExpression> {
22122230
printFullLine(curr->vec);
22132231
decIndent();
22142232
}
2233+
void visitPrefetch(Prefetch* curr) {
2234+
o << '(';
2235+
PrintExpressionContents(currFunction, o).visit(curr);
2236+
incIndent();
2237+
printFullLine(curr->ptr);
2238+
decIndent();
2239+
}
22152240
void visitMemoryInit(MemoryInit* curr) {
22162241
o << '(';
22172242
PrintExpressionContents(currFunction, o).visit(curr);

src/wasm-binary.h

+6
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,11 @@ enum ASTNodes {
973973
I64x2ExtMulLowUI32x4 = 0xd6,
974974
I64x2ExtMulHighUI32x4 = 0xd7,
975975

976+
// prefetch opcodes
977+
978+
PrefetchT = 0xc5,
979+
PrefetchNT = 0xc6,
980+
976981
// bulk memory opcodes
977982

978983
MemoryInit = 0x08,
@@ -1481,6 +1486,7 @@ class WasmBinaryBuilder {
14811486
bool maybeVisitSIMDShift(Expression*& out, uint32_t code);
14821487
bool maybeVisitSIMDLoad(Expression*& out, uint32_t code);
14831488
bool maybeVisitSIMDLoadStoreLane(Expression*& out, uint32_t code);
1489+
bool maybeVisitPrefetch(Expression*& out, uint32_t code);
14841490
bool maybeVisitMemoryInit(Expression*& out, uint32_t code);
14851491
bool maybeVisitDataDrop(Expression*& out, uint32_t code);
14861492
bool maybeVisitMemoryCopy(Expression*& out, uint32_t code);

src/wasm-delegations-fields.h

+9
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,15 @@ switch (DELEGATE_ID) {
371371
DELEGATE_END(SIMDLoadStoreLane);
372372
break;
373373
}
374+
case Expression::Id::PrefetchId: {
375+
DELEGATE_START(Prefetch);
376+
DELEGATE_FIELD_CHILD(Prefetch, ptr);
377+
DELEGATE_FIELD_INT(Prefetch, op);
378+
DELEGATE_FIELD_ADDRESS(Prefetch, offset);
379+
DELEGATE_FIELD_ADDRESS(Prefetch, align);
380+
DELEGATE_END(Prefetch);
381+
break;
382+
}
374383
case Expression::Id::MemoryInitId: {
375384
DELEGATE_START(MemoryInit);
376385
DELEGATE_FIELD_CHILD(MemoryInit, size);

src/wasm-delegations.h

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ DELEGATE(SIMDTernary);
4040
DELEGATE(SIMDShift);
4141
DELEGATE(SIMDLoad);
4242
DELEGATE(SIMDLoadStoreLane);
43+
DELEGATE(Prefetch);
4344
DELEGATE(MemoryInit);
4445
DELEGATE(DataDrop);
4546
DELEGATE(MemoryCopy);

src/wasm-interpreter.h

+8
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,14 @@ class ExpressionRunner : public OverriddenVisitor<SubType, Flow> {
11671167
NOTE_ENTER("Nop");
11681168
return Flow();
11691169
}
1170+
Flow visitPrefetch(Prefetch* curr) {
1171+
NOTE_ENTER("Prefetch");
1172+
Flow flow = visit(curr->ptr);
1173+
if (flow.breaking()) {
1174+
return flow;
1175+
}
1176+
return Flow();
1177+
}
11701178
Flow visitUnreachable(Unreachable* curr) {
11711179
NOTE_ENTER("Unreachable");
11721180
trap("unreachable");

src/wasm-s-parser.h

+1
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ class SExpressionWasmBuilder {
220220
Expression* makeSIMDShift(Element& s, SIMDShiftOp op);
221221
Expression* makeSIMDLoad(Element& s, SIMDLoadOp op);
222222
Expression* makeSIMDLoadStoreLane(Element& s, SIMDLoadStoreLaneOp op);
223+
Expression* makePrefetch(Element& s, PrefetchOp op);
223224
Expression* makeMemoryInit(Element& s);
224225
Expression* makeDataDrop(Element& s);
225226
Expression* makeMemoryCopy(Element& s);

src/wasm.h

+18
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,11 @@ enum SIMDTernaryOp {
530530
SignSelectVec64x2
531531
};
532532

533+
enum PrefetchOp {
534+
PrefetchTemporal,
535+
PrefetchNontemporal,
536+
};
537+
533538
//
534539
// Expressions
535540
//
@@ -577,6 +582,7 @@ class Expression {
577582
MemorySizeId,
578583
MemoryGrowId,
579584
NopId,
585+
PrefetchId,
580586
UnreachableId,
581587
AtomicRMWId,
582588
AtomicCmpxchgId,
@@ -1037,6 +1043,18 @@ class SIMDLoadStoreLane
10371043
void finalize();
10381044
};
10391045

1046+
class Prefetch : public SpecificExpression<Expression::PrefetchId> {
1047+
public:
1048+
Prefetch() = default;
1049+
Prefetch(MixedArena& allocator) : Prefetch() {}
1050+
1051+
PrefetchOp op;
1052+
Address offset;
1053+
Address align;
1054+
Expression* ptr;
1055+
void finalize();
1056+
};
1057+
10401058
class MemoryInit : public SpecificExpression<Expression::MemoryInitId> {
10411059
public:
10421060
MemoryInit() = default;

src/wasm/wasm-binary.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -2967,6 +2967,9 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) {
29672967
if (maybeVisitSIMDLoadStoreLane(curr, opcode)) {
29682968
break;
29692969
}
2970+
if (maybeVisitPrefetch(curr, opcode)) {
2971+
break;
2972+
}
29702973
throwError("invalid code after SIMD prefix: " + std::to_string(opcode));
29712974
break;
29722975
}
@@ -5372,6 +5375,27 @@ bool WasmBinaryBuilder::maybeVisitSIMDLoadStoreLane(Expression*& out,
53725375
return true;
53735376
}
53745377

5378+
bool WasmBinaryBuilder::maybeVisitPrefetch(Expression*& out, uint32_t code) {
5379+
PrefetchOp op;
5380+
switch (code) {
5381+
case BinaryConsts::PrefetchT:
5382+
op = PrefetchTemporal;
5383+
break;
5384+
case BinaryConsts::PrefetchNT:
5385+
op = PrefetchNontemporal;
5386+
break;
5387+
default:
5388+
return false;
5389+
}
5390+
auto* curr = allocator.alloc<Prefetch>();
5391+
curr->op = op;
5392+
readMemoryAccess(curr->align, curr->offset);
5393+
curr->ptr = popNonVoidExpression();
5394+
curr->finalize();
5395+
out = curr;
5396+
return true;
5397+
}
5398+
53755399
void WasmBinaryBuilder::visitSelect(Select* curr, uint8_t code) {
53765400
BYN_TRACE("zz node: Select, code " << int32_t(code) << std::endl);
53775401
if (code == BinaryConsts::SelectWithType) {

src/wasm/wasm-s-parser.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -1662,6 +1662,15 @@ SExpressionWasmBuilder::makeSIMDLoadStoreLane(Element& s,
16621662
return ret;
16631663
}
16641664

1665+
Expression* SExpressionWasmBuilder::makePrefetch(Element& s, PrefetchOp op) {
1666+
auto* ret = allocator.alloc<Prefetch>();
1667+
ret->op = op;
1668+
size_t i = parseMemAttributes(s, ret->offset, ret->align, /*defaultAlign*/ 1);
1669+
ret->ptr = parseExpression(s[i]);
1670+
ret->finalize();
1671+
return ret;
1672+
}
1673+
16651674
Expression* SExpressionWasmBuilder::makeMemoryInit(Element& s) {
16661675
auto ret = allocator.alloc<MemoryInit>();
16671676
ret->segment = atoi(s[1]->str().c_str());

src/wasm/wasm-stack.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,20 @@ void BinaryInstWriter::visitSIMDLoadStoreLane(SIMDLoadStoreLane* curr) {
694694
o << curr->index;
695695
}
696696

697+
void BinaryInstWriter::visitPrefetch(Prefetch* curr) {
698+
o << int8_t(BinaryConsts::SIMDPrefix);
699+
switch (curr->op) {
700+
case PrefetchTemporal:
701+
o << U32LEB(BinaryConsts::PrefetchT);
702+
break;
703+
case PrefetchNontemporal:
704+
o << U32LEB(BinaryConsts::PrefetchNT);
705+
break;
706+
}
707+
assert(curr->align);
708+
emitMemoryAccess(curr->align, /*(unused) bytes=*/0, curr->offset);
709+
}
710+
697711
void BinaryInstWriter::visitMemoryInit(MemoryInit* curr) {
698712
o << int8_t(BinaryConsts::MiscPrefix);
699713
o << U32LEB(BinaryConsts::MemoryInit);

src/wasm/wasm.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ const char* getExpressionName(Expression* curr) {
174174
return "simd_load";
175175
case Expression::Id::SIMDLoadStoreLaneId:
176176
return "simd_load_store_lane";
177+
case Expression::Id::PrefetchId:
178+
return "prefetch";
177179
case Expression::Id::MemoryInitId:
178180
return "memory.init";
179181
case Expression::Id::DataDropId:
@@ -656,6 +658,10 @@ bool SIMDLoadStoreLane::isStore() {
656658
WASM_UNREACHABLE("unexpected op");
657659
}
658660

661+
void Prefetch::finalize() {
662+
type = ptr->type == Type::unreachable ? Type::unreachable : Type::none;
663+
}
664+
659665
Const* Const::set(Literal value_) {
660666
value = value_;
661667
type = value.type;

src/wasm2js.h

+1
Original file line numberDiff line numberDiff line change
@@ -1984,6 +1984,7 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m,
19841984
}
19851985

19861986
Ref visitNop(Nop* curr) { return ValueBuilder::makeToplevel(); }
1987+
Ref visitPrefetch(Prefetch* curr) { return ValueBuilder::makeToplevel(); }
19871988

19881989
Ref visitUnreachable(Unreachable* curr) {
19891990
return ValueBuilder::makeCall(ABORT_FUNC);

test/simd.wast

+10
Original file line numberDiff line numberDiff line change
@@ -1396,4 +1396,14 @@
13961396
(local.get $1)
13971397
)
13981398
)
1399+
(func $prefetch.t (param $0 i32)
1400+
(prefetch.t offset=3 align=2
1401+
(local.get $0)
1402+
)
1403+
)
1404+
(func $prefetch.nt (param $0 i32)
1405+
(prefetch.nt offset=3 align=2
1406+
(local.get $0)
1407+
)
1408+
)
13991409
)

test/simd.wast.from-wast

+11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
(type $i32_v128_=>_none (func (param i32 v128)))
99
(type $i32_v128_=>_v128 (func (param i32 v128) (result v128)))
1010
(type $none_=>_v128 (func (result v128)))
11+
(type $i32_=>_none (func (param i32)))
1112
(type $v128_=>_i64 (func (param v128) (result i64)))
1213
(type $v128_=>_f32 (func (param v128) (result f32)))
1314
(type $v128_=>_f64 (func (param v128) (result f64)))
@@ -1413,4 +1414,14 @@
14131414
(local.get $1)
14141415
)
14151416
)
1417+
(func $prefetch.t (param $0 i32)
1418+
(prefetch.t offset=3 align=2
1419+
(local.get $0)
1420+
)
1421+
)
1422+
(func $prefetch.nt (param $0 i32)
1423+
(prefetch.nt offset=3 align=2
1424+
(local.get $0)
1425+
)
1426+
)
14161427
)

test/simd.wast.fromBinary

+11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
(type $i32_v128_=>_none (func (param i32 v128)))
99
(type $i32_v128_=>_v128 (func (param i32 v128) (result v128)))
1010
(type $none_=>_v128 (func (result v128)))
11+
(type $i32_=>_none (func (param i32)))
1112
(type $v128_=>_i64 (func (param v128) (result i64)))
1213
(type $v128_=>_f32 (func (param v128) (result f32)))
1314
(type $v128_=>_f64 (func (param v128) (result f64)))
@@ -1413,5 +1414,15 @@
14131414
(local.get $1)
14141415
)
14151416
)
1417+
(func $prefetch.t (param $0 i32)
1418+
(prefetch.t offset=3 align=2
1419+
(local.get $0)
1420+
)
1421+
)
1422+
(func $prefetch.nt (param $0 i32)
1423+
(prefetch.nt offset=3 align=2
1424+
(local.get $0)
1425+
)
1426+
)
14161427
)
14171428

0 commit comments

Comments
 (0)