avr-llvm / llvm

[MERGED UPSTREAM] AVR backend for the LLVM compiler library
220 stars 21 forks source link

Program hangs in the endless loop #222

Closed ghost closed 6 years ago

ghost commented 7 years ago

This is the "blink without delay" program in my custom compiler.

; ModuleID = 'new_module'

declare void @init()

declare i32 @millis()

define void @main() {
entry:
  call void @init()
  call void @pinMode(i8 13, i8 1)
  %ledState = alloca i8
  store i8 0, i8* %ledState
  %previousMillis = alloca i32
  %dword_promotion = sext i16 0 to i32
  store i32 %dword_promotion, i32* %previousMillis
  %interval = alloca i32
  %dword_promotion1 = sext i16 200 to i32
  store i32 %dword_promotion1, i32* %interval
  %currentMillis = alloca i32
  %0 = call i32 @millis()
  store i32 %0, i32* %currentMillis
  br label %forever_loop

forever_loop:                                     ; preds = %if_continue4, %entry
  *****%x = alloca i16*****
  %1 = call i32 @millis()
  store i32 %1, i32* %currentMillis
  %2 = load i32, i32* %currentMillis
  %3 = load i32, i32* %previousMillis
  %aritmetic_op = sub i32 %2, %3
  %4 = load i32, i32* %interval
  %relation_op = icmp sge i32 %aritmetic_op, %4
  br i1 %relation_op, label %then, label %if_continue4

then:                                             ; preds = %forever_loop
  %5 = load i32, i32* %currentMillis
  store i32 %5, i32* %previousMillis
  %6 = load i8, i8* %ledState
  %relation_op2 = icmp eq i8 %6, 0
  br i1 %relation_op2, label %then3, label %else

then3:                                            ; preds = %then
  call void @digitalWrite(i8 13, i8 1)
  store i8 1, i8* %ledState
  br label %if_continue

else:                                             ; preds = %then
  call void @digitalWrite(i8 13, i8 0)
  store i8 0, i8* %ledState
  br label %if_continue

if_continue:                                      ; preds = %else, %then3
  br label %if_continue4

if_continue4:                                     ; preds = %if_continue, %forever_loop
  br label %forever_loop

forever_continue:                                 ; No predecessors!
  ret void
}

declare void @pinMode(i8, i8)

declare void @digitalWrite(i8, i8)

When I declare variable in the "forever" loop (%x = alloca i16), the program hangs, but when I comment that line, everything works fine. What could be the problem? I'm using the Arduino UNO (ATMega328p, 16MHz) for testing.

dylanmckay commented 7 years ago

Let's look at the generated assembly.

Without the alloca

llc -march=avr -mcpu=atmega328p ~/avr/mmavr.ll -o mmavr.no_alloca.s

    .text
    .macosx_version_min 10, 11
    .file   "/Users/dylanmckay/avr/mmavr.ll"
    .globl  main
    .p2align    1
    .type   main,@function
main:                                   ; @main
; BB#0:                                 ; %entry
    push    r16
    push    r17
    push    r28
    push    r29
    in  r28, 61
    in  r29, 62
    sbiw    r28, 13
    in  r0, 63
    cli
    out 62, r29
    out 63, r0
    out 61, r28
    call    init
    ldi r17, 1
    ldi r24, 13
    ldi r22, 1
    call    pinMode
    ldi r16, 0
    std Y+13, r16
    ldi r24, 0
    ldi r25, 0
    std Y+11, r24
    std Y+12, r25
    std Y+9, r24
    std Y+10, r25
    std Y+7, r24
    std Y+8, r25
    ldi r24, 200
    ldi r25, 0
    std Y+5, r24
    std Y+6, r25
    call    millis
    std Y+3, r24
    std Y+4, r25
    std Y+1, r22
    std Y+2, r23
LBB0_1:                                 ; %forever_loop
    ldi r24, 0
    rjmp    LBB0_4
LBB0_2:                                 ; %else
    ldi r24, 13
    ldi r22, 0
    call    digitalWrite
    std Y+13, r16
LBB0_3:                                 ; %forever_loop
    call    millis
    std Y+3, r24
    std Y+4, r25
    std Y+1, r22
    std Y+2, r23
    ldd r18, Y+9
    ldd r19, Y+10
    ldd r20, Y+11
    ldd r21, Y+12
    sub r22, r18
    sbc r23, r19
    sbc r24, r20
    sbc r25, r21
    ldd r18, Y+5
    ldd r19, Y+6
    ldd r20, Y+7
    ldd r21, Y+8
    cp  r22, r18
    cpc r23, r19
    cpc r24, r20
    cpc r25, r21
    ldi r24, 1
    brge    LBB0_1
LBB0_4:                                 ; %forever_loop
    andi    r24, 1
    cpi r24, 0
    brne    LBB0_3
; BB#5:                                 ; %then
    ldd r24, Y+1
    ldd r25, Y+2
    ldd r18, Y+3
    ldd r19, Y+4
    std Y+11, r18
    std Y+12, r19
    std Y+9, r24
    std Y+10, r25
    ldd r24, Y+13
    cpi r24, 0
    brne    LBB0_2
; BB#6:                                 ; %then3
    ldi r24, 13
    ldi r22, 1
    call    digitalWrite
    std Y+13, r17
    rjmp    LBB0_3
.Lfunc_end0:
    .size   main, .Lfunc_end0-main

With the alloca

    .text
    .macosx_version_min 10, 11
    .file   "/Users/dylanmckay/avr/mmavr.ll"
    .globl  main
    .p2align    1
    .type   main,@function
main:                                   ; @main
; BB#0:                                 ; %entry
    push    r16
    push    r17
    push    r28
    push    r29
    in  r28, 61
    in  r29, 62
    sbiw    r28, 13
    in  r0, 63
    cli
    out 62, r29
    out 63, r0
    out 61, r28
    call    init
    ldi r17, 1
    ldi r24, 13
    ldi r22, 1
    call    pinMode
    ldi r16, 0
    std Y+13, r16
    ldi r24, 0
    ldi r25, 0
    std Y+11, r24
    std Y+12, r25
    std Y+9, r24
    std Y+10, r25
    std Y+7, r24
    std Y+8, r25
    ldi r24, 200
    ldi r25, 0
    std Y+5, r24
    std Y+6, r25
    call    millis
    std Y+3, r24
    std Y+4, r25
    std Y+1, r22
    std Y+2, r23
LBB0_1:                                 ; %forever_loop
    ldi r24, 0
    rjmp    LBB0_4
LBB0_2:                                 ; %else
    ldi r24, 13
    ldi r22, 0
    call    digitalWrite
    std Y+13, r16
LBB0_3:                                 ; %forever_loop
    in  r24, 61
    in  r25, 62
    sbiw    r24, 2
    in  r0, 63
    cli
    out 62, r25
    out 63, r0
    out 61, r24
    call    millis
    std Y+3, r24
    std Y+4, r25
    std Y+1, r22
    std Y+2, r23
    ldd r18, Y+9
    ldd r19, Y+10
    ldd r20, Y+11
    ldd r21, Y+12
    sub r22, r18
    sbc r23, r19
    sbc r24, r20
    sbc r25, r21
    ldd r18, Y+5
    ldd r19, Y+6
    ldd r20, Y+7
    ldd r21, Y+8
    cp  r22, r18
    cpc r23, r19
    cpc r24, r20
    cpc r25, r21
    ldi r24, 1
    brge    LBB0_1
LBB0_4:                                 ; %forever_loop
    andi    r24, 1
    cpi r24, 0
    brne    LBB0_3
; BB#5:                                 ; %then
    ldd r24, Y+1
    ldd r25, Y+2
    ldd r18, Y+3
    ldd r19, Y+4
    std Y+11, r18
    std Y+12, r19
    std Y+9, r24
    std Y+10, r25
    ldd r24, Y+13
    cpi r24, 0
    brne    LBB0_2
; BB#6:                                 ; %then3
    ldi r24, 13
    ldi r22, 1
    call    digitalWrite
    std Y+13, r17
    rjmp    LBB0_3
.Lfunc_end0:
    .size   main, .Lfunc_end0-main
dylanmckay commented 7 years ago

The difference between the two files

diff mmavr.no_alloca.s mmavr.with_alloca.s > mmavr.diff

The alloca adds the following lines. I have annotated them.

; Load the lower and upper bytes of the stack pointer
  in    r24, 61
  in    r25, 62
; Reserve two bytes on the stack
  sbiw  r24, 2
; load something into memory, don't change it
  in    r0, 63
  cli
;  store the stack pointer high bytes
  out   62, r25
; put whatever was at IO offset 63 back, even though we didn't modify it
  out   63, r0
; store the stack pointer low byte
  out   61, r24
dylanmckay commented 7 years ago

What makes you think your chip hangs? What symptoms can you see?

dylanmckay commented 7 years ago

it's pretty weird that this operation disables interrupts. I can understand why you'd want to change the stack pointer atomically, but it's pretty important that you restore the interrupt flag afterwards.

ghost commented 7 years ago

What makes you think your chip hangs? What symptoms can you see?

The LED doesn't blink when I upload that code via avrdude, but when I remove that variable declaration, everything works, the LED blinks. Yes, I don't need that variable, but it's not normal that chip hangs if I declare unnecessary variable in a endless loop. I don't know where is the problem, the .ll output looks fine. As you can see, I'm using arduino-core functions. I suppose that millis() function using interrupts, but millis() is "original" arduino function from libcore.a.

dylanmckay commented 7 years ago

Could you take the assembly file and remove the cli instruction, compile and try that.

ghost commented 7 years ago

Doesn't work.

dylanmckay commented 7 years ago

So it still has the problem, even without the cli?

ghost commented 7 years ago

Unfortunately, yes.

dylanmckay commented 7 years ago

I have fixed a bunch of bugs (one of which I'm certain would've broken your code - avr-rust/rust#45).

@mmavr: Does your test case work with the current LLVM master? Note that this repo hasn't been update for 6+ months and so you'll need to checkout llvm-mirror/llvm and compile with cmake -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR.

dylanmckay commented 6 years ago

I believe this to be now fixed, and the issue has also become stale.

The current compiler it way more stable than it was at this point. If this is still an issue, we can reopen.