Skip to content

Compiler generates wrong code for VPORTA.output (port at 0x1) #666

@tomtor

Description

@tomtor

Somewhat related to Rahix/avr-device#190
and rust-lang/rust#141260 (@LuigiPiucco )

I discovered this in a normal avr-device program: https://github.com/tomtor/avr-modern-rust

and rewrote it to a minimal program to demonstrate the issue:

#![no_std]
#![no_main]

// const IO: u16 = 0x1; // this value generated bad code
const IO: u16 = 0x2; // this value generates good code

const VPORTA: *mut u8 = (IO) as *mut u8;

const LED: u8 = 0b1000_0000; // PA7


pub fn high_vp(b: u8) {
    unsafe {
        *VPORTA = *VPORTA | b;
    }
}

#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
    loop {}
}

// the body of the next function is nonsense and irrelevant, we just need some code which is not inlined
pub fn nil(a: u16) {
    let mut i: u16 = 0;
    while i < 100 {
        high_vp(LED);
        nil(a - 1);
        i += 1;
    }
}

#[avr_device::entry]
//#[cortex_m_rt::entry]
fn main() -> ! {
    let mut counter: u16 = 0;

    loop {
        counter += 1;

        // The following line produces incorrect code: !!!
        high_vp(LED);

        nil((counter & 0xf) + IO);
    }
}

this generates the following excellent code:

00000094 <_ZN15avr_modern_demo20__avr_device_rt_main17h009e886c0b40ab89E>:
  94:   0f 93           push    r16
  96:   1f 93           push    r17
  98:   80 e0           ldi     r24, 0x00       ; 0
  9a:   90 e0           ldi     r25, 0x00       ; 0
  9c:   17 9a           sbi     0x02, 7 ; 2
  9e:   01 96           adiw    r24, 0x01       ; 1
  a0:   8c 01           movw    r16, r24
  a2:   8f 70           andi    r24, 0x0F       ; 15
  a4:   90 70           andi    r25, 0x00       ; 0
  a6:   02 96           adiw    r24, 0x02       ; 2
  a8:   0e 94 2b 00     call    0x56    ; 0x56 <_ZN15avr_modern_demo3nil17h6637efea0a821bd7E>
  ac:   c8 01           movw    r24, r16
  ae:   f6 cf           rjmp    .-20            ; 0x9c <_ZN15avr_modern_demo20__avr_device_rt_main17h009e886c0b40ab89E+0x8>

however, if we use 0x1 instead of 0x2 we get:

00000096 <_ZN15avr_modern_demo20__avr_device_rt_main17h009e886c0b40ab89E>:
  96:   0f 93           push    r16
  98:   1f 93           push    r17
  9a:   a0 e0           ldi     r26, 0x00       ; 0
  9c:   b0 e0           ldi     r27, 0x00       ; 0
  9e:   8d 91           ld      r24, X+
  a0:   80 68           ori     r24, 0x80       ; 128
  a2:   8d 01           movw    r16, r26
  a4:   af 70           andi    r26, 0x0F       ; 15
  a6:   b0 70           andi    r27, 0x00       ; 0
  a8:   8d 93           st      X+, r24
  aa:   cd 01           movw    r24, r26
  ac:   0e 94 2b 00     call    0x56    ; 0x56 <_ZN15avr_modern_demo3nil17h6637efea0a821bd7E>
  b0:   d8 01           movw    r26, r16
  b2:   f5 cf           rjmp    .-22            ; 0x9e <_ZN15avr_modern_demo20__avr_device_rt_main17h009e886c0b40ab89E+0x8>

The varying argument to nil() is used to store the new contents at 0x1 which is only correct for the first iteration of the loop!

Metadata

Metadata

Assignees

No one assigned

    Labels

    compiler-bugNot a bug in avr-hal, but a bug in the rust compiler/LLVM

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions