-
Notifications
You must be signed in to change notification settings - Fork 12.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
Bound check for multiplication in for loops #81237
Comments
The code in C with both gcc and clang optimized well but not in Rust ? https://rust.godbolt.org/z/voMWdc. The code in C: #include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
const size_t WIDTH = 64;
const size_t HEIGHT = 32;
const size_t DISPLAY_SIZE = WIDTH * HEIGHT;
bool draw(uint8_t x, uint8_t y) {
x = (size_t)(x) % WIDTH;
y = (size_t)(y) % HEIGHT;
for (; y < HEIGHT; ++y)
{
size_t coord = x + y * WIDTH;
if (coord >= DISPLAY_SIZE) {
return false;
}
}
return true;
} Gcc and clang just straights to generate |
Comparing llvm-ir outputs between clang and rust: https://rust.godbolt.org/z/soE8d3. I wonder if implement the same optimization pass in MIR |
For a more fair comparison you can add the array update in the C code too, to make the two Rust/C versions as close as possible. |
Something like this (untested): const WIDTH: usize = 64;
const HEIGHT: usize = 32;
const DISPLAY_SIZE: usize = WIDTH * HEIGHT;
pub fn draw(data: &[u8; DISPLAY_SIZE], x: u8, y: u8) -> bool {
let x2 = usize::from(x) % WIDTH;
let y2 = usize::from(y) % HEIGHT;
let mut collision = false;
for y3 in y2 .. HEIGHT {
let coord = x2 + y3 * WIDTH;
collision |= data[coord] != 0;
}
return collision;
} #include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
const size_t WIDTH = 64;
const size_t HEIGHT = 32;
const size_t DISPLAY_SIZE = WIDTH * HEIGHT;
bool draw(const uint8_t* data[DISPLAY_SIZE], const uint8_t x, const uint8_t y) {
const size_t x2 = ((size_t)x) % WIDTH;
const size_t y2 = ((size_t)y) % HEIGHT;
bool collision = false;
for (size_t y3 = y2; y3 < HEIGHT; y3++) {
const size_t coord = x2 + y3 * WIDTH;
if (coord < DISPLAY_SIZE) {
collision |= data[coord] != 0;
} else {
exit(1);
}
}
return collision;
} |
The problem for bound checks in Rust is that the compiler couldn't prove that |
cc @felix91gr I guess this is a good test case for value range analysis on MIR? |
@oli-obk definitely! ... hmm, I'll open an issue on this. We'd better start listing the use, test and edge cases we notice :) |
Updating to LLVM 15 in Rust 1.65 fixed the issue: https://rust.godbolt.org/z/55GoEW5df |
Bound checking happens when I using
x + y * HEIGHT
formula tocalculate the coordinate in an array. The generated code is
saved on Godbolt: https://rust.godbolt.org/z/76qEhK.
I tried this code:
I expected to see this happen: No bound checks in generated code.
Instead, this happened: There are bound checks.
Note that bound checks doesn't happen if I don't use for loop and just use a immutable
y
value.Meta
rustc --version --verbose
:The text was updated successfully, but these errors were encountered: