Skip to content

[AVR] Shift left << doesn't work correctly on >= 32-bit integers on a 16-bit platform #82380

Closed
@jacobmischka

Description

@jacobmischka

Shift left seems to not behave correctly, but doing the same resulting operation using multiplication does work as a workaround. This occurs both when using the << operator and when using overflowing_shl. This was tested on an Arduino Nano (actually an Elegoo knockoff with a CH340, link).

I tried this code:

#![no_std]
#![no_main]

extern crate panic_halt;

use arduino_uno::prelude::*;
use ufmt::uwriteln;

#[arduino_uno::entry]
fn main() -> ! {
    let dp = arduino_uno::Peripherals::take().unwrap();

    let mut pins = arduino_uno::Pins::new(dp.PORTB, dp.PORTC, dp.PORTD);
    let mut serial = arduino_uno::Serial::new(
        dp.USART0,
        pins.d0,
        pins.d1.into_output(&mut pins.ddr),
        57600.into_baudrate(),
    );

    for i in 0..64 {
        uwriteln!(&mut serial, "1 << {}\r", i).void_unwrap();

        let shl: u64 = 1u64 << i;
        uwriteln!(&mut serial, "Shift: {:?}\r", shl.to_le_bytes()).void_unwrap();

        let mul: u64 = 1u64 * 2u64.pow(i as u32);
        uwriteln!(&mut serial, "Mul and pow: {:?}\r\n", mul.to_le_bytes()).void_unwrap();
    }

    loop {}
}
Output:
1 << 0
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [1, 0, 0, 0, 0, 0, 0, 0]

1 << 1
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [2, 0, 0, 0, 0, 0, 0, 0]

1 << 2
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [4, 0, 0, 0, 0, 0, 0, 0]

1 << 3
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [8, 0, 0, 0, 0, 0, 0, 0]

1 << 4
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [16, 0, 0, 0, 0, 0, 0, 0]

1 << 5
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [32, 0, 0, 0, 0, 0, 0, 0]

1 << 6
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [64, 0, 0, 0, 0, 0, 0, 0]

1 << 7
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [128, 0, 0, 0, 0, 0, 0, 0]

1 << 8
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 1, 0, 0, 0, 0, 0, 0]

1 << 9
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 2, 0, 0, 0, 0, 0, 0]

1 << 10
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 4, 0, 0, 0, 0, 0, 0]

1 << 11
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 8, 0, 0, 0, 0, 0, 0]

1 << 12
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 16, 0, 0, 0, 0, 0, 0]

1 << 13
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 32, 0, 0, 0, 0, 0, 0]

1 << 14
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 64, 0, 0, 0, 0, 0, 0]

...

1 << 51
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 8, 0]

1 << 52
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 16, 0]

1 << 53
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 32, 0]

1 << 54
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 64, 0]

1 << 55
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 128, 0]

1 << 56
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 0, 1]

1 << 57
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 0, 2]

1 << 58
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 0, 4]

1 << 59
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 0, 8]

1 << 60
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 0, 16]

1 << 61
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 0, 32]

1 << 62
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 0, 64]

1 << 63
Shift: [1, 0, 1, 0, 1, 0, 0, 0]
Mul and pow: [0, 0, 0, 0, 0, 0, 0, 128]
Same code, except `u32` instead of `u64`
1 << 0
Shift: [0, 128, 0, 0]
Mul and pow: [1, 0, 0, 0]

1 << 1
Shift: [0, 128, 0, 0]
Mul and pow: [2, 0, 0, 0]

1 << 2
Shift: [0, 128, 0, 0]
Mul and pow: [4, 0, 0, 0]

1 << 3
Shift: [0, 128, 0, 0]
Mul and pow: [8, 0, 0, 0]

1 << 4
Shift: [0, 128, 0, 0]
Mul and pow: [16, 0, 0, 0]

1 << 5
Shift: [0, 128, 0, 0]
Mul and pow: [32, 0, 0, 0]

1 << 6
Shift: [0, 128, 0, 0]
Mul and pow: [64, 0, 0, 0]

1 << 7
Shift: [0, 128, 0, 0]
Mul and pow: [128, 0, 0, 0]

1 << 8
Shift: [0, 128, 0, 0]
Mul and pow: [0, 1, 0, 0]

1 << 9
Shift: [0, 128, 0, 0]
Mul and pow: [0, 2, 0, 0]

1 << 10
Shift: [0, 128, 0, 0]
Mul and pow: [0, 4, 0, 0]

1 << 11
Shift: [0, 128, 0, 0]
Mul and pow: [0, 8, 0, 0]

1 << 12
Shift: [0, 128, 0, 0]
Mul and pow: [0, 16, 0, 0]

1 << 13
Shift: [0, 128, 0, 0]
Mul and pow: [0, 32, 0, 0]

1 << 14
Shift: [0, 128, 0, 0]
Mul and pow: [0, 64, 0, 0]

1 << 15
Shift: [0, 128, 0, 0]
Mul and pow: [0, 128, 0, 0]

1 << 16
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 1, 0]

1 << 17
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 2, 0]

1 << 18
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 4, 0]

1 << 19
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 8, 0]

1 << 20
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 16, 0]

1 << 21
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 32, 0]

1 << 22
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 64, 0]

1 << 23
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 128, 0]

1 << 24
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 0, 1]

1 << 25
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 0, 2]

1 << 26
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 0, 4]

1 << 27
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 0, 8]

1 << 28
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 0, 16]

1 << 29
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 0, 32]

1 << 30
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 0, 64]

1 << 31
Shift: [0, 128, 0, 0]
Mul and pow: [0, 0, 0, 128]

Meta

rustc --version --verbose:

rustc 1.51.0-nightly (c2de47a9a 2021-01-06)
binary: rustc
commit-hash: c2de47a9aa4c9812884f341f1852e9c9610f5f7a
commit-date: 2021-01-06
host: x86_64-unknown-linux-gnu
release: 1.51.0-nightly

This might be related to #82242. As in that issue, I am using this version of nightly because it's the latest that supports AVR, and it must be built using --release.

Full reproduction repository: https://github.com/jacobmischka/rust-avr-shl

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.O-AVRTarget: AVR processors (ATtiny, ATmega, etc.)T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions