Skip to content

Commit 3fd9a32

Browse files
committed
[AVR] Fix incorrect calling convention for varargs functions
An i8 argument should only cost 1 byte on the stack. This is compatible with avr-gcc. There are also more test cases (of calling convention) are added. Reviewed By: aykevl, dylanmckay Differential Revision: https://reviews.llvm.org/D121767
1 parent f014303 commit 3fd9a32

File tree

4 files changed

+277
-3
lines changed

4 files changed

+277
-3
lines changed

llvm/lib/Target/AVR/AVRCallingConv.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ def RetCC_AVR_BUILTIN : CallingConv<[
2727

2828
// Calling convention for variadic functions.
2929
def ArgCC_AVR_Vararg : CallingConv<[
30+
// i8 are always passed through the stack with a byte slot and byte alignment.
31+
CCIfType<[i8], CCAssignToStack<1, 1>>,
3032
// i16 are always passed through the stack with an alignment of 1.
3133
CCAssignToStack<2, 1>
3234
]>;

llvm/test/CodeGen/AVR/calling-conv/c/basic.ll

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: llc < %s -march=avr | FileCheck %s
1+
; RUN: llc -mtriple=avr < %s | FileCheck %s
22

33
; CHECK-LABEL: ret_void_args_i8
44
define void @ret_void_args_i8(i8 %a) {
@@ -97,3 +97,75 @@ define void @ret_void_args_i64_i64_i16(i64 %a, i64 %b, i16 %c) {
9797
store volatile i16 %c, i16* inttoptr (i64 4 to i16*)
9898
ret void
9999
}
100+
101+
; NOTE: Both %a (i8) and %b (i8) cost two registers.
102+
define i8 @foo0(i8 %a, i8 %b) {
103+
; CHECK-LABEL: foo0:
104+
; CHECK: ; %bb.0:
105+
; CHECK-NEXT: sub r24, r22
106+
; CHECK-NEXT: ret
107+
%c = sub i8 %a, %b
108+
ret i8 %c
109+
}
110+
111+
; NOTE: Both %a (i16) and %b (i16) cost two registers.
112+
define i16 @foo1(i16 %a, i16 %b) {
113+
; CHECK-LABEL: foo1:
114+
; CHECK: ; %bb.0:
115+
; CHECK-NEXT: sub r24, r22
116+
; CHECK-NEXT: sbc r25, r23
117+
; CHECK-NEXT: ret
118+
%c = sub i16 %a, %b
119+
ret i16 %c
120+
}
121+
122+
; NOTE: Both %a (i32) and %b (i32) cost four registers.
123+
define i32 @foo2(i32 %a, i32 %b) {
124+
; CHECK-LABEL: foo2:
125+
; CHECK: ; %bb.0:
126+
; CHECK-NEXT: sub r22, r18
127+
; CHECK-NEXT: sbc r23, r19
128+
; CHECK-NEXT: sbc r24, r20
129+
; CHECK-NEXT: sbc r25, r21
130+
; CHECK-NEXT: ret
131+
%c = sub i32 %a, %b
132+
ret i32 %c
133+
}
134+
135+
; NOTE: Each argument costs four registers, and total 16 registers are used.
136+
define i32 @foo3(i32 %a, i32 %b, i32 %c, i32 %d) {
137+
; CHECK-LABEL: foo3:
138+
; CHECK: ; %bb.0:
139+
; CHECK-NEXT: sub r22, r10
140+
; CHECK-NEXT: sbc r23, r11
141+
; CHECK-NEXT: sbc r24, r12
142+
; CHECK-NEXT: sbc r25, r13
143+
; CHECK-NEXT: ret
144+
%e = sub nsw i32 %a, %d
145+
ret i32 %e
146+
}
147+
148+
; NOTE: Each argument (except %e) cost four registers, and total 16 registers
149+
; NOTE: are used. Though there are still 2 registers are vacant, the %e has
150+
; NOTE: to be dropped to the stack.
151+
define i32 @foo4(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
152+
; CHECK-LABEL: foo4:
153+
; CHECK: ; %bb.0:
154+
; CHECK-NEXT: push r28
155+
; CHECK-NEXT: push r29
156+
; CHECK-NEXT: in r28, 61
157+
; CHECK-NEXT: in r29, 62
158+
; CHECK-NEXT: ldd r18, Y+5
159+
; CHECK-NEXT: ldd r19, Y+6
160+
; CHECK-NEXT: ldd r20, Y+7
161+
; CHECK-NEXT: ldd r21, Y+8
162+
; CHECK-NEXT: sub r22, r18
163+
; CHECK-NEXT: sbc r23, r19
164+
; CHECK-NEXT: sbc r24, r20
165+
; CHECK-NEXT: sbc r25, r21
166+
; CHECK-NEXT: pop r29
167+
; CHECK-NEXT: pop r28
168+
; CHECK-NEXT: ret
169+
%f = sub nsw i32 %a, %e
170+
ret i32 %f
171+
}

llvm/test/CodeGen/AVR/calling-conv/c/basic_aggr.ll

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: llc < %s -march=avr | FileCheck %s
1+
; RUN: llc -mtriple=avr < %s | FileCheck %s
22

33
; CHECK-LABEL: ret_void_args_struct_i8_i32
44
define void @ret_void_args_struct_i8_i32({ i8, i32 } %a) {
@@ -82,3 +82,94 @@ start:
8282
ret void
8383
}
8484

85+
; NOTE: The %0 (8-byte array) costs 8 registers and %1 (10-byte array)
86+
; NOTE: costs 10 registers.
87+
define i8 @foo0([8 x i8] %0, [10 x i8] %1) {
88+
; CHECK-LABEL: foo0:
89+
; CHECK: ; %bb.0:
90+
; CHECK-NEXT: sub r18, r8
91+
; CHECK-NEXT: mov r24, r18
92+
; CHECK-NEXT: ret
93+
%3 = extractvalue [8 x i8] %0, 0
94+
%4 = extractvalue [10 x i8] %1, 0
95+
%5 = sub i8 %3, %4
96+
ret i8 %5
97+
}
98+
99+
; NOTE: The %0 (7-byte array) costs 8 registers and %1 (9-byte array)
100+
; NOTE: costs 10 registers.
101+
define i8 @foo1([7 x i8] %0, [9 x i8] %1) {
102+
; CHECK-LABEL: foo1:
103+
; CHECK: ; %bb.0:
104+
; CHECK-NEXT: sub r18, r8
105+
; CHECK-NEXT: mov r24, r18
106+
; CHECK-NEXT: ret
107+
%3 = extractvalue [7 x i8] %0, 0
108+
%4 = extractvalue [9 x i8] %1, 0
109+
%5 = sub i8 %3, %4
110+
ret i8 %5
111+
}
112+
113+
; NOTE: Each argument (6-byte array) costs 6 registers.
114+
define i8 @foo2([6 x i8] %0, [6 x i8] %1, [6 x i8] %2) {
115+
; CHECK-LABEL: foo2:
116+
; CHECK: ; %bb.0:
117+
; CHECK-NEXT: sub r20, r14
118+
; CHECK-NEXT: add r20, r8
119+
; CHECK-NEXT: mov r24, r20
120+
; CHECK-NEXT: ret
121+
%4 = extractvalue [6 x i8] %0, 0
122+
%5 = extractvalue [6 x i8] %1, 0
123+
%6 = extractvalue [6 x i8] %2, 0
124+
%7 = sub i8 %4, %5
125+
%8 = add i8 %7, %6
126+
ret i8 %8
127+
}
128+
129+
; NOTE: The %0 (9-byte array) costs 10 registers. Though there are
130+
; NOTE: 8 registers are vacant, the %b (9-byte array) has to be dropped
131+
; NOTE: to the stack.
132+
define i8 @foo3([9 x i8] %0, [9 x i8] %1) {
133+
; CHECK-LABEL: foo3:
134+
; CHECK: ; %bb.0:
135+
; CHECK-NEXT: push r16
136+
; CHECK-NEXT: push r28
137+
; CHECK-NEXT: push r29
138+
; CHECK-NEXT: in r28, 61
139+
; CHECK-NEXT: in r29, 62
140+
; CHECK-NEXT: ldd r24, Y+6
141+
; CHECK-NEXT: sub r16, r24
142+
; CHECK-NEXT: mov r24, r16
143+
; CHECK-NEXT: pop r29
144+
; CHECK-NEXT: pop r28
145+
; CHECK-NEXT: pop r16
146+
; CHECK-NEXT: ret
147+
%3 = extractvalue [9 x i8] %0, 0
148+
%4 = extractvalue [9 x i8] %1, 0
149+
%5 = sub i8 %3, %4
150+
ret i8 %5
151+
}
152+
153+
; NOTE: Both %0 and %1 are 7-byte arrays, and cost total 16 registers.
154+
; NOTE: Though there are 2 registers are vacant, the %2 (7-byte array) has to
155+
; NOTE: be dropped to the stack.
156+
define i8 @foo4([7 x i8] %0, [7 x i8] %1, [7 x i8] %2) {
157+
; CHECK-LABEL: foo4:
158+
; CHECK: ; %bb.0:
159+
; CHECK-NEXT: push r28
160+
; CHECK-NEXT: push r29
161+
; CHECK-NEXT: in r28, 61
162+
; CHECK-NEXT: in r29, 62
163+
; CHECK-NEXT: sub r18, r10
164+
; CHECK-NEXT: ldd r24, Y+5
165+
; CHECK-NEXT: add r24, r18
166+
; CHECK-NEXT: pop r29
167+
; CHECK-NEXT: pop r28
168+
; CHECK-NEXT: ret
169+
%4 = extractvalue [7 x i8] %0, 0
170+
%5 = extractvalue [7 x i8] %1, 0
171+
%6 = extractvalue [7 x i8] %2, 0
172+
%7 = sub i8 %4, %5
173+
%8 = add i8 %7, %6
174+
ret i8 %8
175+
}

llvm/test/CodeGen/AVR/calling-conv/c/stack.ll

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
; RUN: llc < %s -march=avr | FileCheck %s
1+
; RUN: llc -mtriple=avr < %s | FileCheck %s
22

33
; CHECK-LABEL: ret_void_args_i64_i64_i32
44
define void @ret_void_args_i64_i64_i32(i64 %a, i64 %b, i32 %c) {
@@ -30,3 +30,112 @@ define void @ret_void_args_i64_i64_i32(i64 %a, i64 %b, i32 %c) {
3030
store volatile i32 %c, i32* inttoptr (i64 4 to i32*)
3131
ret void
3232
}
33+
34+
; NOTE: All arguments are passed via the stack for varargs functions.
35+
; NOTE: Both %a & %b occupy a 1-byte stack slot.
36+
define i8 @foo0(i8 %a, i8 %b, ...) {
37+
; CHECK-LABEL: foo0:
38+
; CHECK: ; %bb.0:
39+
; CHECK-NEXT: push r28
40+
; CHECK-NEXT: push r29
41+
; CHECK-NEXT: in r28, 61
42+
; CHECK-NEXT: in r29, 62
43+
; CHECK-NEXT: ldd r25, Y+6
44+
; CHECK-NEXT: ldd r24, Y+5
45+
; CHECK-NEXT: sub r24, r25
46+
; CHECK-NEXT: pop r29
47+
; CHECK-NEXT: pop r28
48+
; CHECK-NEXT: ret
49+
%c = sub i8 %a, %b
50+
ret i8 %c
51+
}
52+
53+
; NOTE: All arguments are passed via the stack since the argument %a is too large.
54+
define i8 @foo1([19 x i8] %a, i8 %b) {
55+
; CHECK-LABEL: foo1:
56+
; CHECK: ; %bb.0:
57+
; CHECK-NEXT: push r28
58+
; CHECK-NEXT: push r29
59+
; CHECK-NEXT: in r28, 61
60+
; CHECK-NEXT: in r29, 62
61+
; CHECK-NEXT: ldd r25, Y+24
62+
; CHECK-NEXT: ldd r24, Y+5
63+
; CHECK-NEXT: sub r24, r25
64+
; CHECK-NEXT: pop r29
65+
; CHECK-NEXT: pop r28
66+
; CHECK-NEXT: ret
67+
%c = extractvalue [19 x i8] %a, 0
68+
%d = sub i8 %c, %b
69+
ret i8 %d
70+
}
71+
72+
; NOTE: The argument %b is passed via the stack, since the argument %a costs
73+
; NOTE: total 18 registers though it is a 17-byte array.
74+
define i8 @foo2([17 x i8] %a, i8 %b) {
75+
; CHECK-LABEL: foo2:
76+
; CHECK: ; %bb.0:
77+
; CHECK-NEXT: push r8
78+
; CHECK-NEXT: push r28
79+
; CHECK-NEXT: push r29
80+
; CHECK-NEXT: in r28, 61
81+
; CHECK-NEXT: in r29, 62
82+
; CHECK-NEXT: ldd r24, Y+6
83+
; CHECK-NEXT: sub r8, r24
84+
; CHECK-NEXT: mov r24, r8
85+
; CHECK-NEXT: pop r29
86+
; CHECK-NEXT: pop r28
87+
; CHECK-NEXT: pop r8
88+
; CHECK-NEXT: ret
89+
%c = extractvalue [17 x i8] %a, 0
90+
%d = sub i8 %c, %b
91+
ret i8 %d
92+
}
93+
94+
; NOTE: Though %a costs 16 registers and 2 registers are vacant, the 4-byte
95+
; NOTE: %b has to be dropped to the stack.
96+
; NOTE: total 18 registers.
97+
define i32 @foo3([4 x i32] %a, i32 %b) {
98+
; CHECK-LABEL: foo3:
99+
; CHECK: ; %bb.0:
100+
; CHECK-NEXT: push r28
101+
; CHECK-NEXT: push r29
102+
; CHECK-NEXT: in r28, 61
103+
; CHECK-NEXT: in r29, 62
104+
; CHECK-NEXT: ldd r22, Y+5
105+
; CHECK-NEXT: ldd r23, Y+6
106+
; CHECK-NEXT: ldd r24, Y+7
107+
; CHECK-NEXT: ldd r25, Y+8
108+
; CHECK-NEXT: sub r22, r10
109+
; CHECK-NEXT: sbc r23, r11
110+
; CHECK-NEXT: sbc r24, r12
111+
; CHECK-NEXT: sbc r25, r13
112+
; CHECK-NEXT: pop r29
113+
; CHECK-NEXT: pop r28
114+
; CHECK-NEXT: ret
115+
%c = extractvalue [4 x i32] %a, 0
116+
%d = sub nsw i32 %b, %c
117+
ret i32 %d
118+
}
119+
120+
; NOTE: Both %1 and %2 are passed via stack, and each has a 1-byte slot.
121+
define i8 @foo4([17 x i8] %0, i8 %1, i8 %2) {
122+
; CHECK-LABEL: foo4:
123+
; CHECK: ; %bb.0:
124+
; CHECK-NEXT: push r8
125+
; CHECK-NEXT: push r28
126+
; CHECK-NEXT: push r29
127+
; CHECK-NEXT: in r28, 61
128+
; CHECK-NEXT: in r29, 62
129+
; CHECK-NEXT: ldd r24, Y+6
130+
; CHECK-NEXT: sub r8, r24
131+
; CHECK-NEXT: ldd r24, Y+7
132+
; CHECK-NEXT: add r24, r8
133+
; CHECK-NEXT: pop r29
134+
; CHECK-NEXT: pop r28
135+
; CHECK-NEXT: pop r8
136+
; CHECK-NEXT: ret
137+
%4 = extractvalue [17 x i8] %0, 0
138+
%5 = sub i8 %4, %1
139+
%6 = add i8 %5, %2
140+
ret i8 %6
141+
}

0 commit comments

Comments
 (0)