- Where: zoom.us
- When: July 24, 4pm-5pm UTC (July 24, 9am-10am Pacific Time)
- Location: link on calendar invite
- Contact:
- Name: JF Bastien
- Email: [email protected]
- Name: Ben Smith
- Email: [email protected]
None required if you've attended before. Email JF Bastien or Ben Smith to sign up if it's your first time. The meeting is open to CG members only.
The meeting will be on a zoom.us video conference. Installation is required, see the calendar invite.
- Opening, welcome and roll call
- Opening of the meeting
- Introduction of attendees
- Find volunteers for note taking (acting chair to volunteer)
- Adoption of the agenda
- Proposals and discussions
- Review of action items from prior meeting.
- Discussion: C++
volatile
in WebAssembly (https://reviews.llvm.org/D49194)
- Closure
None
None
- Andreas Rossberg
- Arun Purushan
- Ben Smith
- Ben Titzer
- Dan Gohman
- Deepti Gandluri
- Heejin Ahn
- Jacob Gravelle
- Jay Phelps
- JF Bastien
- Lars Hansen
- Luke Wagner
- Pat Hickey
- Peter Jensen
- Richard Winterton
- Sergey Rubanov
- Sven Sauleau
- Thomas Yeun
- Yury Delendik
Pat this time
JF seconds
AI(Ben): Move import/export limit of 1,000,000 to an issue WebAssembly/spec#607
BS: I did this before but perhaps misunderstood the purpose of the item. I moved it to the spec issue 607. Lars brought up that we need to loop in implementers directly if we want to do this. I did talk to Kevin (Autodesk) who was asking for a higher limit, he’s been working with Alon so maybe the limit is not necessary. Hopefully he will follow up on github issue to see if that is true. For implementers here: were there any issues with the 1 million limit?
JF: (inaudible)
BS: Lars said perhaps we want to file issues on implementers bug trackers, is that needed?
BT: We’ll land our limits changes in one big chunk
BS: JF you were nodding along
JF: All implementers should be in this call, so they should be aware of the change.
AI(Ben, JF): Create a meeting page on GitHub for TPAC CG
https://github.com/WebAssembly/meetings/blob/master/main/2018/TPAC.md
BS: If you know something you want to discuss at TPAC, file a PR or tell me the topic and I will.
JF: Will Andreas be there? That will affect what we can discuss - he’s championing some of the proposals
BT: The odds are 80% he’ll be there
BS: Action item to follow up with AR
Discussion: C++ volatile in WebAssembly (https://reviews.llvm.org/D49194)
BS: Idk if the CG is the exact right forum for this, but there’s been discussion on the LLVM issue. JF or Dan can correct me if i make mistakes:
BS: Volatile as spec’d by C++ doesn't have anything to do (directly) with atomics, some compilers have stronger guarantees about what it means than others. What should WebAssembly do when you specify something as volatile? If you drop the volatile, thats ignoring semantics the programmer may have wanted, but we don’t want it to be stronger either.
JF: Volatile is used to make sure side effects are visible across setjmp/longjmp (which we don’t have to worry about because of the way javascript implements those), and also (missed it) and also shared array buffers are not allowed to reorder volatile events. And then there’s a bunch of misuses of volatile. When you put it in your source code, the compiler has to touch every byte you said to touch. It can tear, it can’t be reordered, but there is no fence between them. No fusion, elision, speculation. It is sorta usable as a sync mechanism even though its not correct - guarantees effects. With relaxed atomic you are not guaranteed the effects unless you synchronize. If you want to preserve the basic semantics, we can lower to three things. We can error out (very hostile), lower to nonatomic memory accesses, and lower to atomic sequentially consistent accesses.
Nonatomic memory accesses can be elided and fused. Sequentially consistent accesses is the closest we have.
BT: You said that every byte is touched, what does that mean in webassembly memories?
JF: Touched just means you did a store instruction. If the volatile is bigger than the store instruction there may be multiple stores. Sequentially consistent is a stronger guarantee than needed but if you are really doing sync you should be using different primitives.
CW: Is this a memory model question?
LH: For background: this came up with asm.js, spidermonkey hoists code out of loops, if we strip volatile then it breaks a bunch of code. So we lower to seq cst as well.
JF: That code is technically incorrect but we don’t want to break it if we don't have to. We might add actual shared memory that has effect semantics in wasm. We might add setjmp/longjmp or signals as well. If we strengthen the guarantees that volatile gives us, we can't un-strengthen it in the future to relaxed atomics - there’s () in c++ that has the same semantics as volatile except it can’t tear.
CW: This code that’s being compiled that incorrectly is using volatile. What guarantee are they relying on?
JF: on MSVC we might have been relying that volatiles are sequentially consistent - that’s a guarantee that compiler makes and is available in LLVM by an option. They may be relying that the effects are visible at some point. There could be reordering or tearing by the hardware. Volatile is guaranteeing that the stores occur. If those are in a loop you can't lift it out. There’s a bunch of technically incorrect code that relies on this to work.
CW: If having the store be eventually visible is part of the guarantee of volatiles, then it seems as though it wouldn’t be correct to lower non-atomics.
JF: visibility is not guaranteed but it will eventually occur. The store instructions will happen “eventually”.
CW: “we” here is some combination of emscripten and binaryen.
JF: It could be a knob where the user can select the meaning of volatile, we just want to figure out the default for emscripten.
DG: Clang has this knob already, it has independently determined that this knob should be off by default. Why different for wasm?
JF: It has semantics in clang that it does not have in Wasm. The volatile stays there in clang and will not hoist out of loops.
DG: The hoisting out of loops is the same for all targets -- it’s the same optimizer.
LW: Within the wasm engine, browser-side.
DG: In llvm there is one ().cpp and if we set that flag it will turn volatiles into atomics in the front end. If we don't do that the optimizer can do different things.
LW: The ISA -- x86 won’t hoist stores out of loops, but wasm will.
JF: The wasm engine’s optimizer.
LW: Our ISA is a bit more aggressive than the physical one
DG: A guarantee that we never had, may break in wasm… in practice this usually doesn’t break.
JF: The only valid thing to do to a volatile in a loop is to unroll the loop and hoist all the stores out of it, then do all the stores then do the rest of the loop. Nobody actually does this. Standard guarantees every iteration of the loop, whatever you said to be touched, was touched once.
LW: To Dan’s question, the difference with wasm is that it’s a backend thing.
JF: Discarding the volatile flag means we’re removing semantic information that the implementation may need when the optimizer looks at loops.
BS: Do we need an additional thing in wasm to express this?
JF: We do if we add setjmp/longjmp, or signals
BS: We could have an additional constraint in wasm that says ”dont hoist this”
BT: To meet the requirements of C++ you have to emit this constraint
DG: If we add signal handlers -- asynchronous or synchronous -- raising the signal yourself or otherwise, then volatile may be useful, so we can guarantee behaviors in wasm. Do we want to add this in preparation for the future if we add this behavior.
JF: That's another option we didn't discuss, we could do it but I’m not sure we should.
TY: Is there a middle way to handle signal handlers (inaudible)
HA: If the (clang) implements volatile arg is specified, what do other architectures do?
DG: It is implemented entirely in the frontend - it turns volatile into atomic, so it works on all architectures.
JF: It works on all architectures, but the optimizer needs to know that it is volatile.
CW: Doesn’t it depend, since we don’t know which guarantee they are relying on. Hoisting vs atomicity.
JF: It's not allowed to hoist and then not do the things - there's an ordering guarantee in effect
BT: volatile requires accesses matches the program order -- we’re in the situation that we have a second compiler. If we have to communicate that, we need a second mechanism.
JF: Right, and i think we should not discuss adding volatile to the memory model because it's a lot of work for something that doesn’t matter.
Luke: If we added something later that was weaker, we would be in trouble if we tried to change the way code works because it would break implementations that rely on it
HA: If the clang option does what the user wants than they can already just use it
JF: The question is about what the default should be.
CW: The question is, do we introduce the weaker target, so that code doesn't break in the future.
BT: It seems like it's impossible to implement volatile correctly without sequential consistency in the memory model, which is what we have now.
BS: The tenor of the room is: We maybe need to switch volatile to be atomic, or there's a thought that we need to add an additional piece of functionality that might be of pretty limited utility, or should we tell people to use the clang people (should it be the default)
JP: Is there someone here representing LLVM’s opinion on this? If we make a choice here to make more guarantees than volatile gives, then introduce the weaker primitive later, is LLVM comfortable giving a higher commitment than the code provides?
DG: I am the LLVM code owner for the wasm backend. I’m uncomfortable with outputting code that's incorrect to the standard, by default. My instinct is to leave the default as it is, even if it will break things in wasm, they should use the flag.
JF: Things as they are drops the knowledge that a load or store is volatile.
DG: Without setjmp.longjmp or signals then we don't need it. I need to satisfy people who expect aggressive optimizations. If your semantics are defined by the C++ standard this would not trigger anything incorrect.
BT: Do we make all accesses volatile? In order to support c++ without this flag, thats what we’d need to do.
HA: I think what JF wanted was to make the (frontend translation) option the default, plus tearing volatiles
JF: I think the language should deprecate everything but loads and stores to volatiles, im working on that, but thats orthogonal to our conversation. The only thing that makes sense for volatile is loads and stores that can tear. I want to make the code that people wrote already still work - if they wrote a load and store in the source code thats what happens. Some of these corner cases never happen in real code.
BS: We need to gather more information, how likely is this to cause users problems that they can’t diagnose themselves
DG: This isn't being brought up by the users, this is brought up because we’re working on threads and having a debate about how volatile should work there.
HA: Does asm.js currently turn volatiles into atomics?
LH: Emscripten does
BS: We should see if this can be pushed down the stack. Maybe emscripten can pass this flag to clang when it is compiling, with the expectation that users are going that way. When we have a primitive that more effectively maps to volatile, we can get clang to do things that way.
BT: This flag turns volatiles into atomics so early in the pipeline, is this concern this won't be optimized?
DG: The compiler can do different things with volatiles and atomics. If the users are writing code that needs this, we should support it, but if they should be using the flag we should advocate clang to put it on by default.
JF: Clang transforms volatile stores and loads into sequential stores and loads, only when you jump the boundary to no way to express volatility, then you only have atomics to use.
DG: That is different than the MSVC volatile semantics
JF: This is the precedent, the semantics are not quite right but it's what exists
DG: What about a third category that's stronger than volatile but less strong than atomic?
JF: They’re not a lattice
DG: One part of the compiler thinks of it as volatile, and then later in the compiler it thinks of it as atomic - it will have some of the properties of both. I’ll need to think more about this.
JF: If you want me to raise that point on the CFP mailing list I can do that. If I ask them or standards committee, I suspect I will get whatever I propose as an answer
CW: You said there is a precedent for lowering volatile at the last minute
JF: There’s a precedent for making volatile mean sequentially consistent atomic, that's what MSVC does because they did this very early on and they’re stuck with it. LLVM mimics this behavior in order to be compatible with MSVC. So there’s precedent for something similar (early). The precedent for doing it late is in asm.js
DG: I was previously unaware that asm.js did this in clang, so I will study this more. There may be room for some difference here. Emscripten was very much focused on compatibility, I’m more focused now on doing the right thing.
JF: If you want to make an argument on lost optimizations I’d like to see concrete examples. Volatile doesn't happen all that much. The authors may have certain expectations that are incorrect but it doesn't come up all that often. If you break user code and then get no real-world performance out of it, that's not worth it. I want to understand the tradeoff.
BS: Thank you for an engaging discussion
JF: Do we want to conclude this in two weeks?
BS: Yes hopefully with more concrete examples, we can wrap it up.
BT: I think the thing we should discuss is not what clang does for C++, but instead we need to discuss the intersection with the memory model and what the default for wasm engines.
CW: Are you proposing to include release/acquire in the memory model?
BT: I think it would be a volatile annotation
BS: I noticed Andreas is here.
AR: I will be going to the wasm meeting at TPAC, yes.
JP: Thomas messaged in chat. He got an answer to that.
BS: Thank you let's adjourn
(Thanks for taking notes, Pat!)