-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
folded syntax of let #20
Comments
(let (param)* (result)* (local)*
(instr)*
) EDIT: oh, but this doesn't quite make sense w.r.t. consuming the locals. @lukewagner had a good idea that this could be defined inside the let instead, e.g.: (let
(local i32 (i32.const 5))
...
)
|
Ah, interesting, I didn't know
has type:
where
and given the left-to-right order of locals and parameters, putting the
Allowing us to write WDYT? |
Oh, good idea! :) That makes sense to me. So then a function: (func (param t1)* (result t2)* (local t3)* <instr>*) inlined at a callsite: (call (t1.value)*) would become: (t1.value)*
(t3.default)*
let (local t1)* (local t3)* (result t2)*
<instr>*
end Since the stack is always empty at the beginning of the function (so there are no (This is another place where it would have looked more natural if WebAssembly passed |
If we changed |
Interesting idea. I guess in that case (If we kept Given this new (t1.value)* ;; locals
(t2.value)* ;; params
let (local t1)* (param t2)* (result t3)*
;; top of stack is (t2.value)*
<instr>*
end would become the following snippet using (t2.value)* ;; params
(t1.value)* ;; locals
block (param t2)* (param t1)* (result t3)*
let' (local t1)*
;; top of stack is (t2.value)*
<instr>*
end (The function inlining example in my previous comment would work like this too, I believe.) If we did want to mimic the current As another interesting side effect -- this would mean we could create locals more than once per block. Not sure if that's desirable: (func
(local $a i32) ;; $a => index 0
(i32.const 111)
(i32.const 222)
let' (local $b i32) (local $c i32) ;; $b => index 0, $c => 1, $a => 2
(i32.const 333)
(i32.const 444)
let' (local $d i32) (local $e i32) ;; $d => index 0, $e => 1, $b => 2, $c => 3, $a => 4
...
) |
In our work on reducing program size and improving type-checking performance, we found that type annotations were mostly only useful at merge points of control flow, and otherwise we found they would typically both increase program size (because of the annotation) and make type-checking slower (because you had to check that the incoming type matched the annotation, and then that the annotation was sufficient for the subsequent instruction, rather than just directly checking that the unique incoming type was sufficient for the subsequent instruction). So if you can't branch to a As a separate note, along this line, if we had a notion of immutable local variables, then there actually would be no benefit for |
Oh, I see what you mean. It would be the first case where we have an |
(Heads up, I was about to make this comment lightly, then decided to do some digging and just discovered that it's relevant to multi-value. However, it is relevant in a backwards-compatible manner. So there is no urgency here, just something to ponder.) Well, actually, if ever y'all want to do dig into reducing type annotations and speeding up type-checking, the input types on |
@lukewagner, in the presence of multi values,
actually has type:
We could do it the other way round, but that's much less useful, because you could no longer bind locals "locally" without first emptying the operand stack. @RossTate, @binji, that ship has sailed. We had an extensive discussion in the early days whether only OTOH, I don't think |
Can you clarify this, please? I appreciate the historical insight. It sounds like it's an argument for having the control structure correspond with the grammatical structure. That's something I've also come to appreciate because I found it really useful for stack primitives. But I don't get what that has to do with removing the type annotations that are unrelated to control (or maybe you thought I was suggesting removing |
I was referring to the idea of |
Thanks for the link! There's no need to sacrifice simplicity, though. Do the following: First, change control frames to reflect that they may or may not associate a control label and that the end may or may not need to match that label:
and change
Then do the following changes in
This pretty much changes |
The actual point I was getting at was the case for I agree that we could probably have used more reduced type annotations when we designed blocks. But again, this ship has sailed long ago. |
The code for |
As I mentioned in the parens, that would imply that the label index space has holes, which was rejected as a solution. |
Oops, missed that! Sorry. Why was that rejected? It seems y'all have painted yourself into a corner for reasons I don't understand. Note that this problem is only going to get worse and worse. For example, now the various stack primitives in WebAssembly/exception-handling#105 like |
Also, it really doesn't complicate that code much to have a separate stack for just labels. The code for |
I don't remember in detail, but I for one would find that too hacky. But I don't think it matters either way. Most block instructions (except |
The natural construct for C++ destructors does not need any type annotations, and C++ destructors seem common enough that it seems premature to ignore them. Similarly, if we use stack marks to enable self-managed memory or self-managed stack tracing, those will be extremely frequent in some modules. None of these need type annotations. A nice design would be to have a separate stack in the validator code for each stack-based indexing mode in WebAssembly. There would be a stack for labels (that (Sorry, I realized you were probably commenting on the hackiness of holes in the label index. I prefer this multi-stack solution anyways.) |
@rossberg Ah, you might want to update the let section in the Overview.md then; it says So given that, I agree it doesn't make sense to put Considering that the instruction: |
@lukewagner, ah, thanks, fixed Overview. As for putting locals between params and results: I agree that the relation between type annotation and actual instruction type is less direct for Also, the notational symmetry between
and
seems desirable and the latter more what you want to write in practice, especially if we add folded initialiser sugar like @binji mentioned above:
|
Ah right, I forgot about the folded form. That makes sense. |
@tlively, done. |
I have been using let fairly extensively recently (at least hand-writing programs that use it).
The text was updated successfully, but these errors were encountered: