Skip to content

Add IR, parsing and binary support for AtomicRMW instructions from wasm threads proposal#1082

Merged
dschuff merged 10 commits intomasterfrom
atomicrmw
Jul 7, 2017
Merged

Add IR, parsing and binary support for AtomicRMW instructions from wasm threads proposal#1082
dschuff merged 10 commits intomasterfrom
atomicrmw

Conversation

@dschuff
Copy link
Member

@dschuff dschuff commented Jul 6, 2017

Also leave a stub (but valid) visitAtomicRMW in the visitor template so that not all visitors need to implement this function yet.

@dschuff
Copy link
Member Author

dschuff commented Jul 6, 2017

Future PRs will add the visitors, including validation, optimizations, etc.

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, makes sense. Yeah, I think we should update them all to the { return ReturnType; } form

}

void AtomicRMW::finalize() {
if (ptr->type == unreachable || value->type == unreachable)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{, } around if body

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

(type $0 (func))
(memory $0 23 256 shared)
(func $atomics (type $0)
(func $atomic-loadstoare (type $0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a typo in store here, must be in the Print code?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the original handwritten test file, so it was just an old-fashioned typo in my fingers :)

@kripken
Copy link
Member

kripken commented Jul 6, 2017

lgtm with that.

CASE_FOR_OP(Xchg);
default: WASM_UNREACHABLE();
}
#undef CASE_FOR_OP
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay for big ugly macros that make the actual code easier to read.
And yay for cleaning up afterward.



bool WasmBinaryBuilder::maybeVisitAtomicRMW(Expression*& out, uint8_t code) {
if (code < BinaryConsts::I32AtomicRMWAdd || code > BinaryConsts::I64AtomicRMWXchg32U) return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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,

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

#define SET(opcode, optype, size) \
curr->op = opcode; \
curr->type = optype; \
curr->bytes = size
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay method extraction

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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");

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I like that better.

@dschuff
Copy link
Member Author

dschuff commented Jul 6, 2017

I figured "end" was consistent with C++ iterator ends and other general c-style bounds where the end is one-past-the-end.

@dschuff
Copy link
Member Author

dschuff commented Jul 6, 2017

FWIW I changed it because the bounds check as it was written before looked funny to me :)

@jgravelle-google
Copy link
Contributor

Ah, yeah makes sense.

@dschuff dschuff merged commit 4995132 into master Jul 7, 2017
@dschuff dschuff mentioned this pull request Jul 10, 2017
10 tasks
@dschuff dschuff deleted the atomicrmw branch July 10, 2017 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants