; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mattr=avr6,sram -mtriple=avr < %s | FileCheck %s --check-prefix=AVR
; RUN: llc -mcpu=attiny10 -mtriple=avr < %s | FileCheck %s --check-prefix=TINY

;TODO: test returning byval structs
; TODO: test naked functions

define void @return_void() {
; AVR-LABEL: return_void:
; AVR:       ; %bb.0:
; AVR-NEXT:    ret
;
; TINY-LABEL: return_void:
; TINY:       ; %bb.0:
; TINY-NEXT:    ret
    ret void
}

define i8 @return8_imm() {
; AVR-LABEL: return8_imm:
; AVR:       ; %bb.0:
; AVR-NEXT:    ldi r24, 5
; AVR-NEXT:    ret
;
; TINY-LABEL: return8_imm:
; TINY:       ; %bb.0:
; TINY-NEXT:    ldi r24, 5
; TINY-NEXT:    ret
    ret i8 5
}

define i8 @return8_arg(i8 %x) {
; AVR-LABEL: return8_arg:
; AVR:       ; %bb.0:
; AVR-NEXT:    ret
;
; TINY-LABEL: return8_arg:
; TINY:       ; %bb.0:
; TINY-NEXT:    ret
    ret i8 %x
}

define i8 @return8_arg2(i8 %x, i8 %y, i8 %z) {
; AVR-LABEL: return8_arg2:
; AVR:       ; %bb.0:
; AVR-NEXT:    mov r24, r20
; AVR-NEXT:    ret
;
; TINY-LABEL: return8_arg2:
; TINY:       ; %bb.0:
; TINY-NEXT:    mov r24, r20
; TINY-NEXT:    ret
    ret i8 %z
}

define i16 @return16_imm() {
; AVR-LABEL: return16_imm:
; AVR:       ; %bb.0:
; AVR-NEXT:    ldi r24, 57
; AVR-NEXT:    ldi r25, 48
; AVR-NEXT:    ret
;
; TINY-LABEL: return16_imm:
; TINY:       ; %bb.0:
; TINY-NEXT:    ldi r24, 57
; TINY-NEXT:    ldi r25, 48
; TINY-NEXT:    ret
    ret i16 12345
}

define i16 @return16_arg(i16 %x) {
; AVR-LABEL: return16_arg:
; AVR:       ; %bb.0:
; AVR-NEXT:    ret
;
; TINY-LABEL: return16_arg:
; TINY:       ; %bb.0:
; TINY-NEXT:    ret
    ret i16 %x
}

define i16 @return16_arg2(i16 %x, i16 %y, i16 %z) {
; AVR-LABEL: return16_arg2:
; AVR:       ; %bb.0:
; AVR-NEXT:    movw r24, r20
; AVR-NEXT:    ret
;
; TINY-LABEL: return16_arg2:
; TINY:       ; %bb.0:
; TINY-NEXT:    mov r24, r20
; TINY-NEXT:    mov r25, r21
; TINY-NEXT:    ret
    ret i16 %z
}

define i32 @return32_imm() {
; AVR-LABEL: return32_imm:
; AVR:       ; %bb.0:
; AVR-NEXT:    ldi r22, 21
; AVR-NEXT:    ldi r23, 205
; AVR-NEXT:    ldi r24, 91
; AVR-NEXT:    ldi r25, 7
; AVR-NEXT:    ret
;
; TINY-LABEL: return32_imm:
; TINY:       ; %bb.0:
; TINY-NEXT:    ldi r22, 21
; TINY-NEXT:    ldi r23, 205
; TINY-NEXT:    ldi r24, 91
; TINY-NEXT:    ldi r25, 7
; TINY-NEXT:    ret
    ret i32 123456789
}

define i32 @return32_arg(i32 %x) {
; AVR-LABEL: return32_arg:
; AVR:       ; %bb.0:
; AVR-NEXT:    ret
;
; TINY-LABEL: return32_arg:
; TINY:       ; %bb.0:
; TINY-NEXT:    ret
    ret i32 %x
}

define i32 @return32_arg2(i32 %x, i32 %y, i32 %z) {
; AVR-LABEL: return32_arg2:
; AVR:       ; %bb.0:
; AVR-NEXT:    movw r22, r14
; AVR-NEXT:    movw r24, r16
; AVR-NEXT:    ret
;
; TINY-LABEL: return32_arg2:
; TINY:       ; %bb.0:
; TINY-NEXT:    push r28
; TINY-NEXT:    push r29
; TINY-NEXT:    in r28, 61
; TINY-NEXT:    in r29, 62
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 247
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r22, Y+
; TINY-NEXT:    ld r23, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 9
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 245
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r24, Y+
; TINY-NEXT:    ld r25, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 11
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    pop r29
; TINY-NEXT:    pop r28
; TINY-NEXT:    ret
    ret i32 %z
}

define i64 @return64_imm() {
; AVR-LABEL: return64_imm:
; AVR:       ; %bb.0:
; AVR-NEXT:    ldi r18, 204
; AVR-NEXT:    ldi r19, 204
; AVR-NEXT:    ldi r20, 104
; AVR-NEXT:    ldi r21, 37
; AVR-NEXT:    ldi r22, 25
; AVR-NEXT:    ldi r23, 22
; AVR-NEXT:    ldi r24, 236
; AVR-NEXT:    ldi r25, 190
; AVR-NEXT:    ret
;
; TINY-LABEL: return64_imm:
; TINY:       ; %bb.0:
; TINY-NEXT:    ldi r20, 236
; TINY-NEXT:    ldi r21, 190
; TINY-NEXT:    mov r30, r24
; TINY-NEXT:    mov r31, r25
; TINY-NEXT:    subi r30, 250
; TINY-NEXT:    sbci r31, 255
; TINY-NEXT:    st Z+, r20
; TINY-NEXT:    st Z+, r21
; TINY-NEXT:    subi r30, 8
; TINY-NEXT:    sbci r31, 0
; TINY-NEXT:    ldi r24, 25
; TINY-NEXT:    ldi r25, 22
; TINY-NEXT:    subi r30, 252
; TINY-NEXT:    sbci r31, 255
; TINY-NEXT:    st Z+, r24
; TINY-NEXT:    st Z+, r25
; TINY-NEXT:    subi r30, 6
; TINY-NEXT:    sbci r31, 0
; TINY-NEXT:    ldi r24, 104
; TINY-NEXT:    ldi r25, 37
; TINY-NEXT:    subi r30, 254
; TINY-NEXT:    sbci r31, 255
; TINY-NEXT:    st Z+, r24
; TINY-NEXT:    st Z+, r25
; TINY-NEXT:    subi r30, 4
; TINY-NEXT:    sbci r31, 0
; TINY-NEXT:    ldi r24, 204
; TINY-NEXT:    ldi r25, 204
; TINY-NEXT:    st Z+, r24
; TINY-NEXT:    st Z+, r25
; TINY-NEXT:    ret
    ret i64 13757395258967641292
}

define i64 @return64_arg(i64 %x) {
; AVR-LABEL: return64_arg:
; AVR:       ; %bb.0:
; AVR-NEXT:    ret
;
; TINY-LABEL: return64_arg:
; TINY:       ; %bb.0:
; TINY-NEXT:    push r28
; TINY-NEXT:    push r29
; TINY-NEXT:    in r28, 61
; TINY-NEXT:    in r29, 62
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 245
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r20, Y+
; TINY-NEXT:    ld r21, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 11
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    mov r30, r24
; TINY-NEXT:    mov r31, r25
; TINY-NEXT:    subi r30, 250
; TINY-NEXT:    sbci r31, 255
; TINY-NEXT:    st Z+, r20
; TINY-NEXT:    st Z+, r21
; TINY-NEXT:    subi r30, 8
; TINY-NEXT:    sbci r31, 0
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 247
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r24, Y+
; TINY-NEXT:    ld r25, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 9
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    subi r30, 252
; TINY-NEXT:    sbci r31, 255
; TINY-NEXT:    st Z+, r24
; TINY-NEXT:    st Z+, r25
; TINY-NEXT:    subi r30, 6
; TINY-NEXT:    sbci r31, 0
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 249
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r24, Y+
; TINY-NEXT:    ld r25, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 7
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    subi r30, 254
; TINY-NEXT:    sbci r31, 255
; TINY-NEXT:    st Z+, r24
; TINY-NEXT:    st Z+, r25
; TINY-NEXT:    subi r30, 4
; TINY-NEXT:    sbci r31, 0
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 251
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r24, Y+
; TINY-NEXT:    ld r25, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 5
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    st Z+, r24
; TINY-NEXT:    st Z+, r25
; TINY-NEXT:    pop r29
; TINY-NEXT:    pop r28
; TINY-NEXT:    ret
    ret i64 %x
}

define i64 @return64_arg2(i64 %x, i64 %y, i64 %z) {
; AVR-LABEL: return64_arg2:
; AVR:       ; %bb.0:
; AVR-NEXT:    push r28
; AVR-NEXT:    push r29
; AVR-NEXT:    in r28, 61
; AVR-NEXT:    in r29, 62
; AVR-NEXT:    ldd r18, Y+5
; AVR-NEXT:    ldd r19, Y+6
; AVR-NEXT:    ldd r20, Y+7
; AVR-NEXT:    ldd r21, Y+8
; AVR-NEXT:    ldd r22, Y+9
; AVR-NEXT:    ldd r23, Y+10
; AVR-NEXT:    ldd r24, Y+11
; AVR-NEXT:    ldd r25, Y+12
; AVR-NEXT:    pop r29
; AVR-NEXT:    pop r28
; AVR-NEXT:    ret
;
; TINY-LABEL: return64_arg2:
; TINY:       ; %bb.0:
; TINY-NEXT:    push r28
; TINY-NEXT:    push r29
; TINY-NEXT:    in r28, 61
; TINY-NEXT:    in r29, 62
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 229
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r20, Y+
; TINY-NEXT:    ld r21, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 27
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    mov r30, r24
; TINY-NEXT:    mov r31, r25
; TINY-NEXT:    subi r30, 250
; TINY-NEXT:    sbci r31, 255
; TINY-NEXT:    st Z+, r20
; TINY-NEXT:    st Z+, r21
; TINY-NEXT:    subi r30, 8
; TINY-NEXT:    sbci r31, 0
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 231
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r24, Y+
; TINY-NEXT:    ld r25, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 25
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    subi r30, 252
; TINY-NEXT:    sbci r31, 255
; TINY-NEXT:    st Z+, r24
; TINY-NEXT:    st Z+, r25
; TINY-NEXT:    subi r30, 6
; TINY-NEXT:    sbci r31, 0
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 233
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r24, Y+
; TINY-NEXT:    ld r25, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 23
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    subi r30, 254
; TINY-NEXT:    sbci r31, 255
; TINY-NEXT:    st Z+, r24
; TINY-NEXT:    st Z+, r25
; TINY-NEXT:    subi r30, 4
; TINY-NEXT:    sbci r31, 0
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 235
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r24, Y+
; TINY-NEXT:    ld r25, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 21
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    st Z+, r24
; TINY-NEXT:    st Z+, r25
; TINY-NEXT:    pop r29
; TINY-NEXT:    pop r28
; TINY-NEXT:    ret
    ret i64 %z
}

define i32 @return64_trunc(i32 %a, i32 %b, i32 %c, i64 %d) {
; AVR-LABEL: return64_trunc:
; AVR:       ; %bb.0:
; AVR-NEXT:    push r28
; AVR-NEXT:    push r29
; AVR-NEXT:    in r28, 61
; AVR-NEXT:    in r29, 62
; AVR-NEXT:    ldd r22, Y+5
; AVR-NEXT:    ldd r23, Y+6
; AVR-NEXT:    ldd r24, Y+7
; AVR-NEXT:    ldd r25, Y+8
; AVR-NEXT:    pop r29
; AVR-NEXT:    pop r28
; AVR-NEXT:    ret
;
; TINY-LABEL: return64_trunc:
; TINY:       ; %bb.0:
; TINY-NEXT:    push r28
; TINY-NEXT:    push r29
; TINY-NEXT:    in r28, 61
; TINY-NEXT:    in r29, 62
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 243
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r22, Y+
; TINY-NEXT:    ld r23, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 13
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    subi r28, 241
; TINY-NEXT:    sbci r29, 255
; TINY-NEXT:    ld r24, Y+
; TINY-NEXT:    ld r25, Y+
; TINY-NEXT:    subi r28, 2
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    subi r28, 15
; TINY-NEXT:    sbci r29, 0
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    pop r29
; TINY-NEXT:    pop r28
; TINY-NEXT:    ret
  %result = trunc i64 %d to i32
  ret i32 %result
}

define avr_intrcc void @interrupt_handler() {
; AVR-LABEL: interrupt_handler:
; AVR:       ; %bb.0:
; AVR-NEXT:    sei
; AVR-NEXT:    push r0
; AVR-NEXT:    in r0, 63
; AVR-NEXT:    push r0
; AVR-NEXT:    pop r0
; AVR-NEXT:    out 63, r0
; AVR-NEXT:    pop r0
; AVR-NEXT:    reti
;
; TINY-LABEL: interrupt_handler:
; TINY:       ; %bb.0:
; TINY-NEXT:    sei
; TINY-NEXT:    push r16
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    push r16
; TINY-NEXT:    pop r16
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    pop r16
; TINY-NEXT:    reti
  ret void
}

define avr_signalcc void @signal_handler() {
; AVR-LABEL: signal_handler:
; AVR:       ; %bb.0:
; AVR-NEXT:    push r0
; AVR-NEXT:    in r0, 63
; AVR-NEXT:    push r0
; AVR-NEXT:    pop r0
; AVR-NEXT:    out 63, r0
; AVR-NEXT:    pop r0
; AVR-NEXT:    reti
;
; TINY-LABEL: signal_handler:
; TINY:       ; %bb.0:
; TINY-NEXT:    push r16
; TINY-NEXT:    in r16, 63
; TINY-NEXT:    push r16
; TINY-NEXT:    pop r16
; TINY-NEXT:    out 63, r16
; TINY-NEXT:    pop r16
; TINY-NEXT:    reti
  ret void
}
