11; RUN: llc < %s -mtriple=avr | FileCheck %s
2-
32declare void @foo (ptr , ptr , ptr )
43
54define void @test1 (i16 %x ) {
65; CHECK-LABEL: test1:
6+
7+ ; r28/r29 are preserved/callee saved per the avr gcc ABI
8+ ; CHECK: push r28
9+ ; CHECK: push r29
10+
711; Frame setup, with frame pointer
12+ ; This includes the fixed size alloca (but not the dynamic alloca)
13+ ; the fixed size alloca was 8 * i16, which is 16 bytes allocated from the stack
814; CHECK: in r28, 61
915; CHECK: in r29, 62
16+ ; CHECK: sbiw r28, 16
17+ ; CHECK: out 62, r29
1018; CHECK: out 61, r28
19+
20+ ; CHECK: lsl r24
21+ ; CHECK: rol r25
22+
1123; allocate first dynalloca
12- ; CHECK: in {{.*}}, 61
13- ; CHECK: in {{.*}}, 62
14- ; CHECK: sub
15- ; CHECK: sbc
24+ ; note that dynalloca is allocated from the stack
25+ ; but does not move the frame pointer (Y+1) down
26+ ; CHECK: in [[REG1:r[0-9]+]], 61
27+ ; CHECK: in [[REG2:r[0-9]+]], 62
28+ ; CHECK: sub [[REG1]], r24
29+ ; CHECK: sbc [[REG2]], r25
30+ ; CHECK: in r0, 63
31+ ; CHECK-NEXT: cli
32+ ; CHECK-NEXT: out 62, [[REG2]]
33+ ; CHECK-NEXT: out 63, r0
34+ ; CHECK-NEXT: out 61, [[REG1]]
35+
36+ ; allocate second dynalloca
37+ ; CHECK: in [[REG3:r[0-9]+]], 61
38+ ; CHECK: in [[REG4:r[0-9]+]], 62
39+ ; CHECK: sub [[REG3]], r24
40+ ; CHECK: sbc [[REG4]], r25
1641; CHECK: in r0, 63
1742; CHECK-NEXT: cli
18- ; CHECK-NEXT: out 62, {{.*}}
43+ ; CHECK-NEXT: out 62, [[REG4]]
1944; CHECK-NEXT: out 63, r0
20- ; CHECK-NEXT: out 61, {{.*}}
45+ ; CHECK-NEXT: out 61, [[REG3]]
46+
2147; Test writes
22- ; CHECK: std Z+13, {{.*}}
23- ; CHECK: std Z+12, {{.*}}
24- ; CHECK: std Z+7, {{.*}}
48+ ; first check that writes to %a
49+ ; (which points to the results of the static alloca)
50+ ; go to the standard function stack frame, pointed
51+ ; to by Y+1 (not the buffers created by dynamic alloca)
52+ ; note that we use GEP with an offset of 2 * i16 which is 4 bytes
53+ ; hence the two data bytes are stored into Y+5 and Y+6
54+ ; CHECK: ldi [[TMP1:r[0-9]+]], 3
55+ ; CHECK: ldi [[TMP2:r[0-9]+]], 0
56+ ; CHECK: std Y+6, [[TMP2]]
57+ ; CHECK: std Y+5, [[TMP1]]
58+
59+
60+ ; CHECK: ldi [[TMP3:r[0-9]+]], 4
61+ ; CHECK: ldi [[TMP4:r[0-9]+]], 0
62+ ; CHECK: mov r30, [[REG1]]
63+ ; CHECK: mov r31, [[REG2]]
64+ ; here the GEP instruction is an offset of 6 * i16
65+ ; making the offset Z+13
66+ ; CHECK: std Z+13, [[TMP4]]
67+ ; CHECK: std Z+12, [[TMP3]]
68+
69+ ; CHECK: ldi [[TMP5:r[0-9]+]], 44
70+
71+ ; CHECK: mov r30, [[REG3]]
72+ ; CHECK: mov r31, [[REG4]]
73+
74+ ; here GEP is 7 * i8
75+ ; CHECK: std Z+7, [[TMP5]]
76+
77+ ; check calling foo with the pointer to the static alloca buffer,
78+ ; which is Y+1 by avr gcc abi conventions
79+ ; CHECK: mov r24, r28
80+ ; CHECK: mov r25, r29
81+ ; CHECK: adiw r24, 1
82+ ; CHECK: rcall foo
83+
84+
85+
86+
2587; CHECK-NOT: std
2688; Test SP restore
89+ ; CHECK: adiw r28, 16
2790; CHECK: in r0, 63
2891; CHECK-NEXT: cli
2992; CHECK-NEXT: out 62, r29
3093; CHECK-NEXT: out 63, r0
3194; CHECK-NEXT: out 61, r28
95+
96+ ; CHECK: pop r29
97+ ; CHECK: pop r28
98+
3299 %a = alloca [8 x i16 ]
33100 %vla = alloca i16 , i16 %x
34101 %add = shl nsw i16 %x , 1
@@ -54,27 +121,27 @@ define void @dynalloca2(i16 %x) {
54121; CHECK: in r28, 61
55122; CHECK: in r29, 62
56123; Allocate stack space for call
57- ; CHECK: in {{.*}} , 61
58- ; CHECK: in {{.*}} , 62
59- ; CHECK: subi
60- ; CHECK: sbci
124+ ; CHECK: in r30 , 61
125+ ; CHECK: in r31 , 62
126+ ; CHECK: subi r30, 8
127+ ; CHECK: sbci r31, 0
61128; CHECK: in r0, 63
62129; CHECK-NEXT: cli
63- ; CHECK-NEXT: out 62, {{.*}}
130+ ; CHECK-NEXT: out 62, r31
64131; CHECK-NEXT: out 63, r0
65- ; CHECK-NEXT: out 61, {{.*}}
132+ ; CHECK-NEXT: out 61, r30
66133; Store values on the stack
67- ; CHECK: ldi r20 , 0
68- ; CHECK: ldi r21 , 0
69- ; CHECK: std Z+8, r21
70- ; CHECK: std Z+7, r20
71- ; CHECK: std Z+6, r21
72- ; CHECK: std Z+5, r20
73- ; CHECK: std Z+4, r21
74- ; CHECK: std Z+3, r20
75- ; CHECK: std Z+2, r21
76- ; CHECK: std Z+1, r20
77- ; CHECK: call
134+ ; CHECK: ldi [[REG1:r[0-9]+]] , 0
135+ ; CHECK: ldi [[REG2:r[0-9]+]] , 0
136+ ; CHECK: std Z+8, [[REG2]]
137+ ; CHECK: std Z+7, [[REG1]]
138+ ; CHECK: std Z+6, [[REG2]]
139+ ; CHECK: std Z+5, [[REG1]]
140+ ; CHECK: std Z+4, [[REG2]]
141+ ; CHECK: std Z+3, [[REG1]]
142+ ; CHECK: std Z+2, [[REG2]]
143+ ; CHECK: std Z+1, [[REG1]]
144+ ; CHECK: rcall foo2
78145; Call frame restore
79146; CHECK-NEXT: in r30, 61
80147; CHECK-NEXT: in r31, 62
@@ -84,7 +151,13 @@ define void @dynalloca2(i16 %x) {
84151; CHECK-NEXT: out 62, r31
85152; CHECK-NEXT: out 63, r0
86153; CHECK-NEXT: out 61, r30
87- ; SP restore
154+ ; SP restore - note this might
155+ ; seem redundant direction after the ADJCALLSTACKUP
156+ ; I think the logic is both should be there because they come from
157+ ; different mechanisms, although clearly an optimisation you could do is
158+ ; discard the ADJCALLSTACKUP if you know the stack pointer is about to be
159+ ; restored back to the value from the start of the function (in r28/r29)
160+ ; straight afterwards
88161; CHECK: in r0, 63
89162; CHECK-NEXT: cli
90163; CHECK-NEXT: out 62, r29
0 commit comments