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