xref: /llvm-project/llvm/test/CodeGen/AVR/interrupts.ll (revision 9ef1d37ffb5f56a9b949a6307bbb16c2ea0130e3)
1; RUN: llc < %s -mtriple=avr | FileCheck %s
2
3@count = global i8 0
4@funcptr = global ptr addrspace(1) null
5
6define avr_intrcc void @interrupt_handler() {
7; CHECK-LABEL: interrupt_handler:
8; CHECK: sei
9; CHECK-NEXT: push r0
10; CHECK-NEXT: in r0, 63
11; CHECK-NEXT: push r0
12; CHECK: pop r0
13; CHECK-NEXT: out 63, r0
14; CHECK-NEXT: pop r0
15; CHECK-NEXT: reti
16  ret void
17}
18
19define void @interrupt_handler_via_ir_attribute() #0 {
20; CHECK-LABEL: interrupt_handler_via_ir_attribute:
21; CHECK: sei
22; CHECK-NEXT: push r0
23; CHECK-NEXT: in r0, 63
24; CHECK-NEXT: push r0
25; CHECK: pop r0
26; CHECK-NEXT: out 63, r0
27; CHECK-NEXT: pop r0
28; CHECK-NEXT: reti
29  ret void
30}
31
32define avr_signalcc void @signal_handler() {
33; CHECK-LABEL: signal_handler:
34; CHECK-NOT: sei
35; CHECK: push r0
36; CHECK-NEXT: in r0, 63
37; CHECK-NEXT: push r0
38; CHECK: pop r0
39; CHECK-NEXT: out 63, r0
40; CHECK-NEXT: pop r0
41; CHECK-NEXT: reti
42  ret void
43}
44
45define void @signal_handler_via_attribute() #1 {
46; CHECK-LABEL: signal_handler_via_attribute:
47; CHECK-NOT: sei
48; CHECK: push r0
49; CHECK-NEXT: in r0, 63
50; CHECK-NEXT: push r0
51; CHECK: pop r0
52; CHECK-NEXT: out 63, r0
53; CHECK-NEXT: pop r0
54; CHECK-NEXT: reti
55  ret void
56}
57
58define avr_intrcc void @interrupt_alloca() {
59; CHECK-LABEL: interrupt_alloca:
60; CHECK: sei
61; CHECK-NEXT: push r0
62; CHECK-NEXT: in r0, 63
63; CHECK-NEXT: push r0
64; CHECK: push r28
65; CHECK-NEXT: push r29
66; CHECK-NEXT: in r28, 61
67; CHECK-NEXT: in r29, 62
68; CHECK-NEXT: sbiw r28, 1
69; CHECK-NEXT: in r0, 63
70; CHECK-NEXT: cli
71; CHECK-NEXT: out 62, r29
72; CHECK-NEXT: out 63, r0
73; CHECK-NEXT: out 61, r28
74; CHECK: adiw r28, 1
75; CHECK-NEXT: in r0, 63
76; CHECK-NEXT: cli
77; CHECK-NEXT: out 62, r29
78; CHECK-NEXT: out 63, r0
79; CHECK-NEXT: out 61, r28
80; CHECK-NEXT: pop r29
81; CHECK-NEXT: pop r28
82; CHECK: pop r0
83; CHECK-NEXT: out 63, r0
84; CHECK-NEXT: pop r0
85; CHECK-NEXT: reti
86  alloca i8
87  ret void
88}
89
90define void @signal_handler_with_increment() #1 {
91; CHECK-LABEL: signal_handler_with_increment:
92; CHECK:      push r0
93; CHECK-NEXT: in r0, 63
94; CHECK-NEXT: push r0
95; CHECK-NEXT: push r24
96; CHECK-NEXT: lds r24, count
97; CHECK-NEXT: inc r24
98; CHECK-NEXT: sts count, r24
99; CHECK-NEXT: pop r24
100; CHECK-NEXT: pop r0
101; CHECK-NEXT: out 63, r0
102; CHECK-NEXT: pop r0
103; CHECK-NEXT: reti
104  %old = load volatile i8, ptr @count
105  %new = add i8 %old, 1
106  store volatile i8 %new, ptr @count
107  ret void
108}
109
110; Check that r1 is saved/restored and set to 0 when using inline assembly.
111define void @signal_handler_with_asm() #1 {
112; CHECK-LABEL: signal_handler_with_asm:
113; CHECK:      push r0
114; CHECK-NEXT: in r0, 63
115; CHECK-NEXT: push r0
116; CHECK-NEXT: push r1
117; CHECK-NEXT: clr r1
118; CHECK-NEXT: push r24
119; CHECK-NEXT: ldi
120;             ;APP
121; CHECK:      mov
122;             ;NO_APP
123; CHECK:      pop r24
124; CHECK-NEXT: pop r1
125; CHECK-NEXT: pop r0
126; CHECK-NEXT: out 63, r0
127; CHECK-NEXT: pop r0
128; CHECK-NEXT: reti
129  call i8 asm sideeffect "mov $0, $1", "=r,r"(i8 3) nounwind
130  ret void
131}
132
133declare void @foo()
134
135; When a signal handler calls a function, it must push/pop all call clobbered
136; registers.
137define void @signal_handler_with_call() #1 {
138; CHECK-LABEL: signal_handler_with_call:
139; CHECK:      push r0
140; CHECK-NEXT: in r0, 63
141; CHECK-NEXT: push r0
142; CHECK-NEXT: push r1
143; CHECK-NEXT: clr r1
144; CHECK-NEXT: push r18
145; CHECK-NEXT: push r19
146; CHECK-NEXT: push r20
147; CHECK-NEXT: push r21
148; CHECK-NEXT: push r22
149; CHECK-NEXT: push r23
150; CHECK-NEXT: push r24
151; CHECK-NEXT: push r25
152; CHECK-NEXT: push r26
153; CHECK-NEXT: push r27
154; CHECK-NEXT: push r30
155; CHECK-NEXT: push r31
156; CHECK-NEXT: call foo
157; CHECK-NEXT: pop r31
158; CHECK-NEXT: pop r30
159; CHECK-NEXT: pop r27
160; CHECK-NEXT: pop r26
161; CHECK-NEXT: pop r25
162; CHECK-NEXT: pop r24
163; CHECK-NEXT: pop r23
164; CHECK-NEXT: pop r22
165; CHECK-NEXT: pop r21
166; CHECK-NEXT: pop r20
167; CHECK-NEXT: pop r19
168; CHECK-NEXT: pop r18
169; CHECK-NEXT: pop r1
170; CHECK-NEXT: pop r0
171; CHECK-NEXT: out 63, r0
172; CHECK-NEXT: pop r0
173; CHECK-NEXT: reti
174  call void @foo()
175  ret void
176}
177
178define void @signal_handler_with_icall() #1 {
179; CHECK-LABEL: signal_handler_with_icall:
180; CHECK:      push    r0
181; CHECK-NEXT: in      r0, 63
182; CHECK-NEXT: push    r0
183; CHECK-NEXT: push    r1
184; CHECK-NEXT: clr     r1
185; CHECK-NEXT: push    r18
186; CHECK-NEXT: push    r19
187; CHECK-NEXT: push    r20
188; CHECK-NEXT: push    r21
189; CHECK-NEXT: push    r22
190; CHECK-NEXT: push    r23
191; CHECK-NEXT: push    r24
192; CHECK-NEXT: push    r25
193; CHECK-NEXT: push    r26
194; CHECK-NEXT: push    r27
195; CHECK-NEXT: push    r30
196; CHECK-NEXT: push    r31
197; CHECK-NEXT: lds     r30, funcptr
198; CHECK-NEXT: lds     r31, funcptr+1
199; CHECK-NEXT: icall
200; CHECK-NEXT: pop     r31
201; CHECK-NEXT: pop     r30
202; CHECK-NEXT: pop     r27
203; CHECK-NEXT: pop     r26
204; CHECK-NEXT: pop     r25
205; CHECK-NEXT: pop     r24
206; CHECK-NEXT: pop     r23
207; CHECK-NEXT: pop     r22
208; CHECK-NEXT: pop     r21
209; CHECK-NEXT: pop     r20
210; CHECK-NEXT: pop     r19
211; CHECK-NEXT: pop     r18
212; CHECK-NEXT: pop     r1
213; CHECK-NEXT: pop     r0
214; CHECK-NEXT: out     63, r0
215; CHECK-NEXT: pop     r0
216; CHECK-NEXT: reti
217  %ptr = load volatile ptr addrspace(1), ptr @funcptr
218  call void %ptr()
219  ret void
220}
221
222attributes #0 = { "interrupt" }
223attributes #1 = { "signal" }
224