esp-rs / rust

Rust for the xtensa architecture. Built in targets for the ESP32 and ESP8266
https://www.rust-lang.org
Other
742 stars 39 forks source link

Bad f32 math results, occassional crashes #185

Closed codertao closed 1 year ago

codertao commented 1 year ago

For context: I was doing simple math to calculate an LED pattern, and I was very consistently not seeing the results I expected when using opt levels z or s. Pared down the code in question to the below, and testing under z or s (with 1.66.0 nightly) I'm seeing a crash; under opt level zero I'm not seeing the crash.

I tried this code:

fn main() {
    esp_idf_sys::link_patches();

    let mut d = 0x57;
    loop {
        let val = calculate_on(0.26, d);
        if !val.0 {
            panic!("First interval isn't being calculated as on correctly");
        }
        d = d*3+1;
    }
}

fn calculate_on(mut time: f32, digit: u16) -> (bool, bool) {
    println!("Digit Start: {}", time);
    time -= 0.25;
    if time <= 0.0 { return (false, false) }
    println!("Post Digit Blank: {}", time);
    for bit in [digit&8, digit&4, digit&2, digit&1] {
        time -= if bit > 0 { 0.4 } else { 0.2 };
        if time <= 0.0 { return (true, false) }
        println!("Post Bit On: {}", time);
        time -= 0.1;
        if time <= 0.0 { return (false, false) }
        println!("Post Bit Off: {}", time);
    }
return (false, true)
}

I expected to see this happen: Moderately-infinite loop

Instead, this happened: Crashes on the first loop, with:

I (0) cpu_start: Starting scheduler on APP CPU.
Start Digits: 0.26
Digit Start: 0.26
Post Digit Blank: 0.00999999
Post Bit On: 0.00999999
thread 'main' panicked at 'First interval isn't being calculated as on correctly', apps/raven-f32/src/main.rs:8:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

abort() was called at PC 0x400eadca on core 0

So, it's hitting

time -= if *bit > 0 { 0.4 } else { 0.2 };

which should take time below 0 regardless of *bit; but it's apparently not applying the operation- or something else is going wrong. While doing initial debugging I was also getting GuruError: (I think memory access exception), but I don't have logs for that anymore.

Meta

rustc --version --verbose:

rustc 1.66.0-nightly (84ecb3f01 2022-12-13)
binary: rustc
commit-hash: 84ecb3f010525cb1b2e7d4da306099c2eaa3e6cd
commit-date: 2022-12-13
host: x86_64-unknown-linux-gnu
release: 1.66.0-nightly
LLVM version: 15.0.0

Switching away from f32 fixed the issue in this code, and I expect disabling hardware f32 would also resolve the problem (as mentioned in the FFT issue), but I suspect some of my apps are at the point where the performance overhead would be a problem.

codertao commented 1 year ago

Slightly simpler code:

fn main() {
    esp_idf_sys::link_patches();

    let val = calculate_on(0.26);
    if !val {
        panic!("First interval isn't being calculated as on correctly");
    }
    for _ in 0..100 {
        println!("Works :'(")
    }
    panic!("Hack for reasons");
}

fn calculate_on(mut time: f32) -> bool {
    println!("Digit Start: {}", time);
    time -= 0.25;
    for i in 0..4 {
        time -= if i > 0 { 0.4 } else { 0.2 };
        if time <= 0.0 { return true }
    }
    false
}

Removing any one of if i > 0 (replace w/ const), for i in 0..4, or the println!; causes the test to pass; with all present it fails.

zRedShift commented 1 year ago

Please see https://github.com/esp-rs/rust/issues/180#issuecomment-1587144551 on how to "fix" this before it's fixed in llvm. This is the same issue as #180.