Skip to content
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

What does "consistent across runs" mean? #1

Closed
ngzhian opened this issue Mar 16, 2021 · 6 comments
Closed

What does "consistent across runs" mean? #1

ngzhian opened this issue Mar 16, 2021 · 6 comments

Comments

@ngzhian
Copy link
Member

ngzhian commented Mar 16, 2021

Filing this issue to track the discussions we have had over in WebAssembly/design#1401. (I tried to summarize the discussion to seed this issue with some content, any misrepresentation of the discussion that happened there is entirely my fault.)

The gist of the problem is, given an instruction that is specified to be non-deterministic (e.g. quasi-FMA (qfma)), it is valid (though unlikely in a Web VM) for two adjacent calls to the same instruction to return two different results, e.g.:

function foo:
  qfma(x, y, z); // returns result with 1 rounding (real fma)
  qfma(x, y, z); // returns result with 2 roundings (mul + add)

One idea from @sunfishcode WebAssembly/design#1401 (comment) is an opaque fpenv value that these instructions will take.

Another idea from the same author is "intrinsic functions" WebAssembly/design#1401 (comment).

The key goal with both ideas is allowing applications to be able to specify this need for consistency.

One counter-argument (by @tlively) is that the usefulness of this ability to express such fine-grained intent is not worth the complexity, see WebAssembly/design#1401 (comment), especially for Web use cases.

Another issue (by @Maratyszcza) is that the fpenv/intrinsic functions will not resolve under-specified instructions like reciprocal algorithms, since they differ across processor models, and no way to emulate them. However, full emulation isn't the goal.

@sunfishcode
Copy link
Member

I recently discussed this topic offline with @tlively and they suggested the idea of having fpenv be a module-level construct similar to event in the exception-handling proposal. Modules could have fpenv definitions, so a main module wouldn't need to import one, but could define one and still export it to be imported by dependent modules. Instructions like qfma would have an immediate index, rather than a first-class operand, to identify which fpenv to use.

This is a much simpler approach than my earlier ideas. It eliminates the need for first-class fpenv values. It eliminates the question of what to name the outermost import. It eliminates the need to provide a way for JS API users to obtain fpenv values to link with. It should have a smaller impact on code size. And it still addresses my original concerns, of being able to have dependent modules import an fpenv to indicate that they share floating-point behavior with another module.

@ngzhian
Copy link
Member Author

ngzhian commented Mar 17, 2021

I was still digesting your "intrinsic functions" solution, thinking of how it would work. My feeling was that it looks rather similar to fpenv value idea, but doesn't put an "extra" item on the stack... and then I saw you comment :) This module level construct sounds promising!

Exploring this path further, I'm looking at the exception overview, event has an attribute (which is just exception for now) and a type. What would a fpenv type contain? Is the idea that it is still opaque (maybe a single byte), and is used as a sort of tag for the main module to export, and for dependent modules to indicate that they should be in the same env?

@sunfishcode
Copy link
Member

I expect fpenv would just contain an attribute, which initially would just have one value, leaving space for future extensibility. I don't see a need for a type field for fpenv.

Is the idea that it is still opaque (maybe a single byte), and is used as a sort of tag for the main module to export, and for dependent modules to indicate that they should be in the same env?

Yes, exactly :-).

@ngzhian
Copy link
Member Author

ngzhian commented Mar 23, 2021

I'm writing a description of this for the overview (WIP at https://github.com/ngzhian/relaxed-simd/blob/fpenv/proposals/relaxed-simd/Overview.md), I have a question to bring up for discussion:

Is the "identity" of the fpenv the index, or the value contained within? (Based on the discussion so far I think it's the index). Here's a pseudo example:

(func foo (param v128)
  non-det 0 (local.get 0)  ;; (1)
  non-det 1 (local.get 0)  ;; (2)
)
(fpenv 0)                  ;; (a)
(fpenv 0)                  ;; (b)

Assume that non-det takes as an immediate, an index into the fpenv section. (1) refers to fpenv (a), and (2) refers to fpenv (b), both fpenv have the same value 0.

Is it okay for the two instructions to return different results? If the "identity" is the index into the fpenv section, then it is okay to get different results.

I think either way, fpenv still remains opaque, because applications don't know what 0 means in this case. And instead of threading one particular fpenv via imports/exports, they only need to specify 0.

@sunfishcode
Copy link
Member

If the 0 is the identity, then when running modules from multiple sources, we wouldn't be able to tell the difference between two modules that specifically want the same behavior, and two unrelated modules that both just happen to use 0. So I think we do want to keep the import/export part of this -- that's wasm's mechanism for describing relationships between modules, which is what we want here.

So I think what we want to say is that the identity is a value encapsulated inside of fpenv which is nondeterministically determined, and which is distinct from the attribute field. And then the attribute field 0 is just a placeholder for future extensibility.

@ngzhian
Copy link
Member Author

ngzhian commented Mar 24, 2021

Thanks for the explanation, I drafted a description of fpenv in #15, can you ptal? There is nothing concrete about text/binary format yet, only pseudo-wast-code.

@ngzhian ngzhian closed this as completed Mar 22, 2022
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

No branches or pull requests

2 participants