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

Should SIMD add/sub/etc. trigger panics on overflow in debug mode? #56

Closed
workingjubilee opened this issue Jan 27, 2021 · 13 comments · Fixed by #243
Closed

Should SIMD add/sub/etc. trigger panics on overflow in debug mode? #56

workingjubilee opened this issue Jan 27, 2021 · 13 comments · Fixed by #243
Labels
E-needs-docs Needs documentation added.

Comments

@workingjubilee
Copy link
Member

Per topic, this affects our vector implementations of Add, Sub, and Neg.

This came up during discussion for #54 and #55.

@workingjubilee workingjubilee added I-nominated We should discuss this at the next weekly meeting E-needs-design Call for participation: Needs design. labels Jan 27, 2021
@Lokathor
Copy link
Contributor

I don't think so.

First of all a technical question: can rust code even cfg on overflow-checks being true or false?

Second: even if we could, we should not. it would make the debug code unacceptably slow. rust has a lot of things that make for slow debug code and long compiles in release, we should not compound the problem if we don't have to.

@calebzulawski
Copy link
Member

I do tend to agree that maybe SIMD should default to wrapping implementations (but provide checked member fns as well). I would have left Neg alone in #54 if I hadn't misread it...

@workingjubilee
Copy link
Member Author

First of all a technical question: can rust code even cfg on overflow-checks being true or false?

I do not believe so.

Second: even if we could, we should not. it would make the debug code unacceptably slow. rust has a lot of things that make for slow debug code and long compiles in release, we should not compound the problem if we don't have to.

In the spirit of sounding out the alternatives (or at least warming up our counterarguments for when someone inevitably asks), I must note that scalar math triggers panics on overflows in debug mode. Why should this not be consistent? Yes, it is slower, but what special need is there to speed this up in debug mode versus any special need in scalar math?

@Lokathor
Copy link
Contributor

"because you only pick simd in the first place if you want to go faster"

but I'm quite biased. I've never ever wanted checked in debug wrapping in release anyway. it was a bad decision then, we shouldn't double down on it now.

@calebzulawski
Copy link
Member

I think I agree, the only reason to use SIMD is for performance, so the default should probably be the most performant. I tend to agree that wrapping would probably have been the better default. When safety is involved I use add_checked or whatever anyway. I'm probably biased in the same way.

@thomcc
Copy link
Member

thomcc commented Jan 27, 2021

but I'm quite biased. I've never ever wanted checked in debug wrapping in release anyway. it was a bad decision then, we shouldn't double down on it now.

I don't agree with this, but I agree with the broad sentiment that it doesn't make sense for SIMD.

@calebzulawski
Copy link
Member

I do think it's worth pointing out that there are generic bit tricks you can do to produce relatively performant "any of" mask checks (and special instructions like movemask on some architectures). The branch will really be what hurts, though, and that's unavoidable.

@thomcc
Copy link
Member

thomcc commented Jan 27, 2021

I think a bigger issue is that it encourages some sort of manual checking at various points which is awkward and usually unnecessary.

I'm not concerned about debug performance here, short of wanting to avoid the debug performance issues of core::arch where nothing is inlined and you typically loose a ton of debug perf when switching from scalar to simd.

@workingjubilee
Copy link
Member Author

workingjubilee commented Jan 27, 2021

I would also note that if you are doing one math, you are likely to do another math, as it were, in SIMD, whereas ordinary math ops are much more likely to appear isolatively, and it is correct to note that any such guard should probably not be in the middle of the code! Also, SIMD ops being much more likely to come one after the other means that any branching in debug mode is much harder on perf since it will happen a lot, yet is much more likely to be a concern with a typical usage of SIMD stuff such as "draw a million triangles, now" or "encode/decode thousands of digital subsamples of audio, now".

So, "We are at least mildly against panicking on debug overflows because the perf concerns are much higher-pressure on testing SIMD code, and also because we think it results in an antipattern" seems like sound reasoning to me.

@workingjubilee
Copy link
Member Author

If we go with this, we should include a note to this effect in our documentation.

@tarcieri
Copy link

tarcieri commented Feb 1, 2021

Cryptography occasionally benefits from checked arithmetic, but offhand I can't think of a cryptographic SIMD use case which needs anything other than Wrapping semantics.

Also generally where checked arithmetic is appropriate in cryptographic use cases it's an "always on" sort of thing and not the overflow-checks style on-for-debug, off-for-release approach.

@workingjubilee workingjubilee removed the I-nominated We should discuss this at the next weekly meeting label Feb 15, 2021
@workingjubilee
Copy link
Member Author

workingjubilee commented Feb 15, 2021

We discussed this on 2021-02-08 and came to a consensus that we should avoid branching in our API, generally, unless it makes sense to always check for a branch. Here it doesn't, really, and, well, it might be UB in certain languages but it certainly isn't that in Rust. And SIMD intrinsics for specific architectures (as far as we are aware) do not define overflow as UB either, since you're just compiling relatively "directly" to a set of assembly instructions, so we don't think it's exactly a familiar expectation for SIMD programmers. Obviously-ish that means that we're still having some equivalent of the checked_* math ops, since, well, it's in the name to check!

We further discussed this on 2021-02-15 and are even currently inclined against providing the wrapping_* ops, because their presence would imply you need to use them in order to avoid overflow in debug mode.

@gilescope
Copy link

gilescope commented May 2, 2021

Could be worth pointing out in * ops docs like add that the operations wrap then?

@workingjubilee workingjubilee added E-needs-docs Needs documentation added. and removed E-needs-design Call for participation: Needs design. labels May 3, 2021
workingjubilee added a commit that referenced this issue Feb 9, 2022
Remove overflow panic from divrem and add basic docs to Simd<T, N>

This finishes normalizing Simd<T, N> to being approximately equivalent to Simd<Wrapping<T>, N> for all implemented operations I can think of. It also documents this fact, allowing this to close #56.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-needs-docs Needs documentation added.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants