-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Proposal: Improve overflow operations #20203
Comments
I think that In an example such as |
Note that if we accept ranged ints (#3806), then fn addWithOverflow(comptime T: type, a: T, b: T) struct { u1, T } {
const result = a + b;
const overflow = result < minInt(T) or result > maxInt(T);
return .{ overflow, @truncate(result) };
} |
My brain woke up. |
I was initially quite confused by this: I assume this was formulated only for unsigned numbers, right? EDIT: Actually, for the use case of "adding it to the next word", i.e. when implementing a big integer out of several segments/limbs, the sign information (I assume) won't be stored at each segment individually anyway. |
Yep, youre right, I didnt think about that. I think it would still make sense to return the complete carry, and both addWithOverflow and subWithOverflow would return {T, i2}. |
It seems to me that if we want those operations, then it would still be useful to have a |
Sorry for the naive question, but is there any reason for those overflow operations to not return an error union? |
@mhcerri Error unions use error values, which under-the-hood are a program-wide enum (to allow easier coercion from any smaller error set to the global error set |
Context
The current overflow operations (
@addWithOverflow
,@subWithOverflow
,@mulWithOverflow
,@shlWithOverflow
) do currently not spark joy in my opinion: These seem initially just designed from the corresponding LLVM instruction, however, they have some problems in reality:@subWithOverflow
returns a bool whether overflow happened, while in my opinion a carry would be more useful. This would work cleanly with returning ani1
instead of au1
: A carry returns-1
and no carry returns0
. In this case carries can be naively added to the next word instead of with an awkward cast.u1
instead of a bool if its intended as flag? If its meant to be overflow, then why are the other overflow parts not as described above?@mulWithOverflow
returning au1
is even less useful. In many situations, the CPU already gives you the high words. This also ties into wide multiplication: Currently, the primary way to do that is to cast to a larger word size, but the CPU already has a nativeT * T -> {T, T}
instruction in many cases. Trying to detect an upcast from the backend is difficult from a compiler backend perspective, and emitting a full2T
multiplication operation is often much less efficient.@shlWithOverflow
would be much more useful if it also returns the overflow bits in my opinion. I don't think it would be much more expensive in code either.Proposal
My proposal is to change the overflow builtins to return the full overflow value too. The interface would largely remain the same, only the return types need to be modified:
@addWithOverflow
remains the same@subWithOverflow(a, b)
would returnstruct{@TypeOf(a, b), i1}
.@mulWithOverflow(a, b)
would returnstruct{@TypeOf(a, b), @TypeOf(a, b)}
.@shlWithOverflow(a, b)
would returnstruct(@TypeOf(a, b), @TypeOf(a, b)}
.The text was updated successfully, but these errors were encountered: