-
Notifications
You must be signed in to change notification settings - Fork 970
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
Handle signed arithmetic edge cases that would be UB in Metal #6961
Comments
Have we looked into which of these cases need attention in the other backend languages? |
I haven't but suspect HLSL/GLSL would need them. |
MetalSpec notes
What does Tint do?For this wgsl: fn do_stuff(x: i32) {
var div_res = x / -1;
var mod_res = x % -1;
var abs_res = abs(x);
var neg_res = -x;
} Tint outputs: int tint_unary_minus(const int v) {
return select(-v, v, v == -2147483648);
}
int tint_div(int lhs, int rhs) {
return (lhs / select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1)))));
}
int tint_mod(int lhs, int rhs) {
int const rhs_or_one = select(rhs, 1, bool((rhs == 0) | bool((lhs == (-2147483647 - 1)) & (rhs == -1))));
if (any(((uint((lhs | rhs_or_one)) & 2147483648u) != 0u))) {
return as_type<int>((as_type<uint>(lhs) - as_type<uint>(as_type<int>((as_type<uint>((lhs / rhs_or_one)) * as_type<uint>(rhs_or_one))))));
} else {
return (lhs % rhs_or_one);
}
}
void do_stuff(int x) {
int div_res = tint_div(x, -1);
int mod_res = tint_mod(x, -1);
int abs_res = abs(x);
int neg_res = tint_unary_minus(x);
} Interestingly they handle the unary minus but not abs(). Also interesting to note the HLSLSpec notes🙃 What does Tint do?int tint_div(int lhs, int rhs) {
return (lhs / (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs));
}
int tint_mod(int lhs, int rhs) {
int rhs_or_one = (((rhs == 0) | ((lhs == -2147483648) & (rhs == -1))) ? 1 : rhs);
if (any(((uint((lhs | rhs_or_one)) & 2147483648u) != 0u))) {
return (lhs - ((lhs / rhs_or_one) * rhs_or_one));
} else {
return (lhs % rhs_or_one);
}
}
void do_stuff(int x) {
int div_res = tint_div(x, -1);
int mod_res = tint_mod(x, -1);
int abs_res = abs(x);
int neg_res = -(x);
} It's interesting they don't wrap abs or neg. But then nor do they handle signed addition, subtraction, or multiplication for HLSL, whereas they do for MSL, which seems consistent. SPIRVSpec notes
What does tint do?Won't post the whole thing but we can see they have wrapper functions for div and rem, and just use OpSNegate and SAbs directly, which agrees with my read of the spec.
GLSLI might leave GLSL for a follow-up, but for posterity here's what tint does: int tint_mod_i32(int lhs, int rhs) {
uint v = uint((lhs == (-2147483647 - 1)));
bool v_1 = bool((v & uint((rhs == -1))));
uint v_2 = uint((rhs == 0));
int v_3 = mix(rhs, 1, bool((v_2 | uint(v_1))));
return (lhs - ((lhs / v_3) * v_3));
}
int tint_div_i32(int lhs, int rhs) {
uint v_4 = uint((lhs == (-2147483647 - 1)));
bool v_5 = bool((v_4 & uint((rhs == -1))));
uint v_6 = uint((rhs == 0));
return (lhs / mix(rhs, 1, bool((v_6 | uint(v_5)))));
}
void do_stuff(int x) {
int div_res = tint_div_i32(x, -1);
int mod_res = tint_mod_i32(x, -1);
int abs_res = abs(x);
int neg_res = -(x);
} They don't worry about signed addition, subtraction, or multiplication either. |
I asked on the directx discord about signed integer overflow and we'll see what they say |
Sad news
So we do need to handle it, it seems. |
The following operations would overflow with signed integer operands. The results are what the WGSL spec requires.
Related: #6666 / #6959
The text was updated successfully, but these errors were encountered: