172 lines
4.7 KiB
LLVM
172 lines
4.7 KiB
LLVM
; RUN: llc -mtriple=avr < %s | FileCheck %s
|
|
|
|
; CHECK-LABEL: ret_void_args_i8
|
|
define void @ret_void_args_i8(i8 %a) {
|
|
; CHECK: sts 4, r24
|
|
store volatile i8 %a, i8* inttoptr (i64 4 to i8*)
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: ret_void_args_i8_i32
|
|
define void @ret_void_args_i8_i32(i8 %a, i32 %b) {
|
|
; CHECK: sts 4, r24
|
|
store volatile i8 %a, i8* inttoptr (i64 4 to i8*)
|
|
|
|
; CHECK-NEXT: sts 8, r23
|
|
; CHECK-NEXT: sts 7, r22
|
|
; CHECK-NEXT: sts 6, r21
|
|
; CHECK-NEXT: sts 5, r20
|
|
store volatile i32 %b, i32* inttoptr (i64 5 to i32*)
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: ret_void_args_i8_i8_i8_i8
|
|
define void @ret_void_args_i8_i8_i8_i8(i8 %a, i8 %b, i8 %c, i8 %d) {
|
|
; CHECK: sts 4, r24
|
|
store volatile i8 %a, i8* inttoptr (i64 4 to i8*)
|
|
; CHECK-NEXT: sts 5, r22
|
|
store volatile i8 %b, i8* inttoptr (i64 5 to i8*)
|
|
; CHECK-NEXT: sts 6, r20
|
|
store volatile i8 %c, i8* inttoptr (i64 6 to i8*)
|
|
; CHECK-NEXT: sts 7, r18
|
|
store volatile i8 %d, i8* inttoptr (i64 7 to i8*)
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: ret_void_args_i32_16_i8
|
|
define void @ret_void_args_i32_16_i8(i32 %a, i16 %b, i8 %c) {
|
|
; CHECK: sts 7, r25
|
|
; CHECK-NEXT: sts 6, r24
|
|
; CHECK-NEXT: sts 5, r23
|
|
; CHECK-NEXT: sts 4, r22
|
|
store volatile i32 %a, i32* inttoptr (i64 4 to i32*)
|
|
|
|
; CHECK-NEXT: sts 5, r21
|
|
; CHECK-NEXT: sts 4, r20
|
|
store volatile i16 %b, i16* inttoptr (i64 4 to i16*)
|
|
|
|
; CHECK-NEXT: sts 4, r18
|
|
store volatile i8 %c, i8* inttoptr (i64 4 to i8*)
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: ret_void_args_i64
|
|
define void @ret_void_args_i64(i64 %a) {
|
|
; CHECK: sts 11, r25
|
|
; CHECK-NEXT: sts 10, r24
|
|
; CHECK-NEXT: sts 9, r23
|
|
; CHECK-NEXT: sts 8, r22
|
|
; CHECK-NEXT: sts 7, r21
|
|
; CHECK-NEXT: sts 6, r20
|
|
; CHECK-NEXT: sts 5, r19
|
|
; CHECK-NEXT: sts 4, r18
|
|
store volatile i64 %a, i64* inttoptr (i64 4 to i64*)
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: ret_void_args_i64_i64
|
|
define void @ret_void_args_i64_i64(i64 %a, i64 %b) {
|
|
; CHECK-DAG: sts 11, r25
|
|
; CHECK-DAG: sts 10, r24
|
|
; CHECK-DAG: sts 9, r23
|
|
; CHECK-DAG: sts 8, r22
|
|
; CHECK-DAG: sts 7, r21
|
|
; CHECK-DAG: sts 6, r20
|
|
; CHECK-DAG: sts 5, r19
|
|
; CHECK-DAG: sts 4, r18
|
|
store volatile i64 %a, i64* inttoptr (i64 4 to i64*)
|
|
|
|
; CHECK-DAG: sts 11, r17
|
|
; CHECK-DAG: sts 10, r16
|
|
; CHECK-DAG: sts 9, r15
|
|
; CHECK-DAG: sts 8, r14
|
|
; CHECK-DAG: sts 7, r13
|
|
; CHECK-DAG: sts 6, r12
|
|
; CHECK-DAG: sts 5, r11
|
|
; CHECK-DAG: sts 4, r10
|
|
store volatile i64 %b, i64* inttoptr (i64 4 to i64*)
|
|
ret void
|
|
}
|
|
|
|
; This is exactly enough to hit the limit of what can be passed
|
|
; completely in registers.
|
|
; CHECK-LABEL: ret_void_args_i64_i64_i16
|
|
define void @ret_void_args_i64_i64_i16(i64 %a, i64 %b, i16 %c) {
|
|
; CHECK: sts 5, r9
|
|
; CHECK-NEXT: sts 4, r8
|
|
store volatile i16 %c, i16* inttoptr (i64 4 to i16*)
|
|
ret void
|
|
}
|
|
|
|
; NOTE: Both %a (i8) and %b (i8) cost two registers.
|
|
define i8 @foo0(i8 %a, i8 %b) {
|
|
; CHECK-LABEL: foo0:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: sub r24, r22
|
|
; CHECK-NEXT: ret
|
|
%c = sub i8 %a, %b
|
|
ret i8 %c
|
|
}
|
|
|
|
; NOTE: Both %a (i16) and %b (i16) cost two registers.
|
|
define i16 @foo1(i16 %a, i16 %b) {
|
|
; CHECK-LABEL: foo1:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: sub r24, r22
|
|
; CHECK-NEXT: sbc r25, r23
|
|
; CHECK-NEXT: ret
|
|
%c = sub i16 %a, %b
|
|
ret i16 %c
|
|
}
|
|
|
|
; NOTE: Both %a (i32) and %b (i32) cost four registers.
|
|
define i32 @foo2(i32 %a, i32 %b) {
|
|
; CHECK-LABEL: foo2:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: sub r22, r18
|
|
; CHECK-NEXT: sbc r23, r19
|
|
; CHECK-NEXT: sbc r24, r20
|
|
; CHECK-NEXT: sbc r25, r21
|
|
; CHECK-NEXT: ret
|
|
%c = sub i32 %a, %b
|
|
ret i32 %c
|
|
}
|
|
|
|
; NOTE: Each argument costs four registers, and total 16 registers are used.
|
|
define i32 @foo3(i32 %a, i32 %b, i32 %c, i32 %d) {
|
|
; CHECK-LABEL: foo3:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: sub r22, r10
|
|
; CHECK-NEXT: sbc r23, r11
|
|
; CHECK-NEXT: sbc r24, r12
|
|
; CHECK-NEXT: sbc r25, r13
|
|
; CHECK-NEXT: ret
|
|
%e = sub nsw i32 %a, %d
|
|
ret i32 %e
|
|
}
|
|
|
|
; NOTE: Each argument (except %e) cost four registers, and total 16 registers
|
|
; NOTE: are used. Though there are still 2 registers are vacant, the %e has
|
|
; NOTE: to be dropped to the stack.
|
|
define i32 @foo4(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
|
|
; CHECK-LABEL: foo4:
|
|
; CHECK: ; %bb.0:
|
|
; CHECK-NEXT: push r28
|
|
; CHECK-NEXT: push r29
|
|
; CHECK-NEXT: in r28, 61
|
|
; CHECK-NEXT: in r29, 62
|
|
; CHECK-NEXT: ldd r18, Y+5
|
|
; CHECK-NEXT: ldd r19, Y+6
|
|
; CHECK-NEXT: ldd r20, Y+7
|
|
; CHECK-NEXT: ldd r21, Y+8
|
|
; CHECK-NEXT: sub r22, r18
|
|
; CHECK-NEXT: sbc r23, r19
|
|
; CHECK-NEXT: sbc r24, r20
|
|
; CHECK-NEXT: sbc r25, r21
|
|
; CHECK-NEXT: pop r29
|
|
; CHECK-NEXT: pop r28
|
|
; CHECK-NEXT: ret
|
|
%f = sub nsw i32 %a, %e
|
|
ret i32 %f
|
|
}
|