Add IR, parsing and binary support for AtomicRMW instructions from wasm threads proposal#1082
Conversation
|
Future PRs will add the visitors, including validation, optimizations, etc. |
kripken
left a comment
There was a problem hiding this comment.
We should update EffectAnalyzer in ast_utils.h, these new opts probably need to set readsMemory and writesMemory, possibly also implicitTrap. (can leave for followups too)
| ReturnType visitSetGlobal(SetGlobal* curr) {} | ||
| ReturnType visitLoad(Load* curr) {} | ||
| ReturnType visitStore(Store* curr) {} | ||
| ReturnType visitAtomicRMW(AtomicRMW* curr) {return ReturnType();} //Stub impl so not every pass has to implement this yet. |
There was a problem hiding this comment.
I'm ok with landing this PR with not all opt passes working yet, we can fix those later. Could we keep this line normal-looking, then, with {} like the others? Or is the return here temporarily necessary?
There was a problem hiding this comment.
The return type is necessary because without it, non-void-returning visitors won't compile unless they have their own override. Probably all of these templates should have the return ReturnType() instead of being empty, otherwise passes can't fall back on them, which I'm guessing was not the intention.
There was a problem hiding this comment.
Right, makes sense. Yeah, I think we should update them all to the { return ReturnType; } form
src/wasm/wasm.cpp
Outdated
| } | ||
|
|
||
| void AtomicRMW::finalize() { | ||
| if (ptr->type == unreachable || value->type == unreachable) |
test/atomics.wast
Outdated
| (type $0 (func)) | ||
| (memory $0 23 256 shared) | ||
| (func $atomics (type $0) | ||
| (func $atomic-loadstoare (type $0) |
There was a problem hiding this comment.
Looks like a typo in store here, must be in the Print code?
There was a problem hiding this comment.
This is the original handwritten test file, so it was just an old-fashioned typo in my fingers :)
|
lgtm with that. |
| CASE_FOR_OP(Xchg); | ||
| default: WASM_UNREACHABLE(); | ||
| } | ||
| #undef CASE_FOR_OP |
There was a problem hiding this comment.
Yay for big ugly macros that make the actual code easier to read.
And yay for cleaning up afterward.
src/wasm/wasm-binary.cpp
Outdated
|
|
||
|
|
||
| bool WasmBinaryBuilder::maybeVisitAtomicRMW(Expression*& out, uint8_t code) { | ||
| if (code < BinaryConsts::I32AtomicRMWAdd || code > BinaryConsts::I64AtomicRMWXchg32U) return false; |
There was a problem hiding this comment.
These bounds look arbitrary without referencing BinaryConsts' definition (and/or the threads proposal).
Would it be worth adding at the end of BinaryConsts' definition something like
AtomicRMW_BEGIN = I32AtomicRMWAdd,
AtomicRMW_END = I64AtomicRMWXchg32U,| #define SET(opcode, optype, size) \ | ||
| curr->op = opcode; \ | ||
| curr->type = optype; \ | ||
| curr->bytes = size |
There was a problem hiding this comment.
Not sure if I should complain that a missing terminal semicolon is a bit odd looking, considering that this is a nested macro that's right next to its use.
I guess: at a quick skim, this gave me a double take, but this is almost-certainly OK.
There was a problem hiding this comment.
Yeah, most function-like macros lack the semicolon so you can do SET(a, b, c); but this (and especially the case-based ones) are a little funny. To fix SET I could wrap them in the standard do {} while(0) but not sure that would be an improvement.
There was a problem hiding this comment.
I often add a comment when I do this in a macro, e.g.:
/* no semicolon */
Kind of like adding // fallthrough when falling throw a case statement.
| return ret; | ||
| } | ||
|
|
||
| static size_t parseMemAttributes(Element& s, Address* offset, Address* align, Address fallback) { |
There was a problem hiding this comment.
Yay method extraction
src/wasm/wasm-s-parser.cpp
Outdated
| uint64_t align = atoll(eq); | ||
| if (align > std::numeric_limits<uint32_t>::max()) throw ParseException("bad align"); | ||
| ret->align = align; | ||
| uint64_t a = atoll(eq); |
There was a problem hiding this comment.
a and o are kinda iffy names, but they're very local and are probably fine. But they have the same initialization code and so this might be more clear as:
uint64_t value = atoll(eq);
if (value > std::numeric_limits<uint32_t>::max()) throw ParseException("memory attribute value too large");
if (str[0] == 'a') {
*align = value;
} else if (str[0] == 'o') {
*offset = value;
} else throw ParseException("bad memory attribute");|
I figured "end" was consistent with C++ iterator ends and other general c-style bounds where the end is one-past-the-end. |
|
FWIW I changed it because the bounds check as it was written before looked funny to me :) |
|
Ah, yeah makes sense. |
Also leave a stub (but valid) visitAtomicRMW in the visitor template so that not all visitors need to implement this function yet.