forked from OSchip/llvm-project
224 lines
5.0 KiB
LLVM
224 lines
5.0 KiB
LLVM
; RUN: llc < %s -march=avr | FileCheck %s
|
|
|
|
@count = global i8 0
|
|
@funcptr = global void () addrspace(1)* null
|
|
|
|
define avr_intrcc void @interrupt_handler() {
|
|
; CHECK-LABEL: interrupt_handler:
|
|
; CHECK: sei
|
|
; CHECK-NEXT: push r0
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: push r0
|
|
; CHECK: pop r0
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: reti
|
|
ret void
|
|
}
|
|
|
|
define void @interrupt_handler_via_ir_attribute() #0 {
|
|
; CHECK-LABEL: interrupt_handler_via_ir_attribute:
|
|
; CHECK: sei
|
|
; CHECK-NEXT: push r0
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: push r0
|
|
; CHECK: pop r0
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: reti
|
|
ret void
|
|
}
|
|
|
|
define avr_signalcc void @signal_handler() {
|
|
; CHECK-LABEL: signal_handler:
|
|
; CHECK-NOT: sei
|
|
; CHECK: push r0
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: push r0
|
|
; CHECK: pop r0
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: reti
|
|
ret void
|
|
}
|
|
|
|
define void @signal_handler_via_attribute() #1 {
|
|
; CHECK-LABEL: signal_handler_via_attribute:
|
|
; CHECK-NOT: sei
|
|
; CHECK: push r0
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: push r0
|
|
; CHECK: pop r0
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: reti
|
|
ret void
|
|
}
|
|
|
|
define avr_intrcc void @interrupt_alloca() {
|
|
; CHECK-LABEL: interrupt_alloca:
|
|
; CHECK: sei
|
|
; CHECK-NEXT: push r0
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: push r0
|
|
; CHECK: push r28
|
|
; CHECK-NEXT: push r29
|
|
; CHECK-NEXT: in r28, 61
|
|
; CHECK-NEXT: in r29, 62
|
|
; CHECK-NEXT: sbiw r28, 1
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: cli
|
|
; CHECK-NEXT: out 62, r29
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: out 61, r28
|
|
; CHECK: adiw r28, 1
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: cli
|
|
; CHECK-NEXT: out 62, r29
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: out 61, r28
|
|
; CHECK-NEXT: pop r29
|
|
; CHECK-NEXT: pop r28
|
|
; CHECK: pop r0
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: reti
|
|
alloca i8
|
|
ret void
|
|
}
|
|
|
|
define void @signal_handler_with_increment() #1 {
|
|
; CHECK-LABEL: signal_handler_with_increment:
|
|
; CHECK: push r0
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: push r0
|
|
; CHECK-NEXT: push r24
|
|
; CHECK-NEXT: lds r24, count
|
|
; CHECK-NEXT: inc r24
|
|
; CHECK-NEXT: sts count, r24
|
|
; CHECK-NEXT: pop r24
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: reti
|
|
%old = load volatile i8, i8* @count
|
|
%new = add i8 %old, 1
|
|
store volatile i8 %new, i8* @count
|
|
ret void
|
|
}
|
|
|
|
; Check that r1 is saved/restored and set to 0 when using inline assembly.
|
|
define void @signal_handler_with_asm() #1 {
|
|
; CHECK-LABEL: signal_handler_with_asm:
|
|
; CHECK: push r0
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: push r0
|
|
; CHECK-NEXT: push r1
|
|
; CHECK-NEXT: clr r1
|
|
; CHECK-NEXT: push r24
|
|
; CHECK-NEXT: ldi
|
|
; ;APP
|
|
; CHECK: mov
|
|
; ;NO_APP
|
|
; CHECK: pop r24
|
|
; CHECK-NEXT: pop r1
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: reti
|
|
call i8 asm sideeffect "mov $0, $1", "=r,r"(i8 3) nounwind
|
|
ret void
|
|
}
|
|
|
|
declare void @foo()
|
|
|
|
; When a signal handler calls a function, it must push/pop all call clobbered
|
|
; registers.
|
|
define void @signal_handler_with_call() #1 {
|
|
; CHECK-LABEL: signal_handler_with_call:
|
|
; CHECK: push r0
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: push r0
|
|
; CHECK-NEXT: push r1
|
|
; CHECK-NEXT: clr r1
|
|
; CHECK-NEXT: push r18
|
|
; CHECK-NEXT: push r19
|
|
; CHECK-NEXT: push r20
|
|
; CHECK-NEXT: push r21
|
|
; CHECK-NEXT: push r22
|
|
; CHECK-NEXT: push r23
|
|
; CHECK-NEXT: push r24
|
|
; CHECK-NEXT: push r25
|
|
; CHECK-NEXT: push r26
|
|
; CHECK-NEXT: push r27
|
|
; CHECK-NEXT: push r30
|
|
; CHECK-NEXT: push r31
|
|
; CHECK-NEXT: call foo
|
|
; CHECK-NEXT: pop r31
|
|
; CHECK-NEXT: pop r30
|
|
; CHECK-NEXT: pop r27
|
|
; CHECK-NEXT: pop r26
|
|
; CHECK-NEXT: pop r25
|
|
; CHECK-NEXT: pop r24
|
|
; CHECK-NEXT: pop r23
|
|
; CHECK-NEXT: pop r22
|
|
; CHECK-NEXT: pop r21
|
|
; CHECK-NEXT: pop r20
|
|
; CHECK-NEXT: pop r19
|
|
; CHECK-NEXT: pop r18
|
|
; CHECK-NEXT: pop r1
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: reti
|
|
call void @foo()
|
|
ret void
|
|
}
|
|
|
|
define void @signal_handler_with_icall() #1 {
|
|
; CHECK-LABEL: signal_handler_with_icall:
|
|
; CHECK: push r0
|
|
; CHECK-NEXT: in r0, 63
|
|
; CHECK-NEXT: push r0
|
|
; CHECK-NEXT: push r1
|
|
; CHECK-NEXT: clr r1
|
|
; CHECK-NEXT: push r18
|
|
; CHECK-NEXT: push r19
|
|
; CHECK-NEXT: push r20
|
|
; CHECK-NEXT: push r21
|
|
; CHECK-NEXT: push r22
|
|
; CHECK-NEXT: push r23
|
|
; CHECK-NEXT: push r24
|
|
; CHECK-NEXT: push r25
|
|
; CHECK-NEXT: push r26
|
|
; CHECK-NEXT: push r27
|
|
; CHECK-NEXT: push r30
|
|
; CHECK-NEXT: push r31
|
|
; CHECK-NEXT: lds r30, funcptr
|
|
; CHECK-NEXT: lds r31, funcptr+1
|
|
; CHECK-NEXT: icall
|
|
; CHECK-NEXT: pop r31
|
|
; CHECK-NEXT: pop r30
|
|
; CHECK-NEXT: pop r27
|
|
; CHECK-NEXT: pop r26
|
|
; CHECK-NEXT: pop r25
|
|
; CHECK-NEXT: pop r24
|
|
; CHECK-NEXT: pop r23
|
|
; CHECK-NEXT: pop r22
|
|
; CHECK-NEXT: pop r21
|
|
; CHECK-NEXT: pop r20
|
|
; CHECK-NEXT: pop r19
|
|
; CHECK-NEXT: pop r18
|
|
; CHECK-NEXT: pop r1
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: out 63, r0
|
|
; CHECK-NEXT: pop r0
|
|
; CHECK-NEXT: reti
|
|
%ptr = load volatile void() addrspace(1)*, void() addrspace(1)** @funcptr
|
|
call void %ptr()
|
|
ret void
|
|
}
|
|
|
|
attributes #0 = { "interrupt" }
|
|
attributes #1 = { "signal" }
|