Skip to content

Commit dfd4102

Browse files
TimNNLazarus535
authored andcommitted
(cherry picked from commit f1630e5)
1 parent ba813f7 commit dfd4102

File tree

3 files changed

+174
-9
lines changed

3 files changed

+174
-9
lines changed

llvm/docs/AVRTarget.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
=================================
2+
Documentation for the AVR backend
3+
=================================
4+
5+
.. contents::
6+
:local:
7+
8+
Calling convention
9+
==================
10+
11+
External links
12+
--------------
13+
14+
* The avr-gcc .. _wiki: https://gcc.gnu.org/wiki/avr-gcc#Calling_Convention has a description of the C calling convention they use
15+
16+
* The avr-libc .. documentation: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_reg_usage has a small summary of the C calling convention
17+
18+
19+
Function return values
20+
----------------------
21+
22+
The avr-gcc documentation states that
23+
24+
Return values with a size of 1 byte up to and including a size of 8 bytes will be returned in registers. Return values whose size is outside that range will be returned in memory.
25+
26+
-- avr-gcc wiki, October 2018
27+
28+
This does not strictly seem to be the case. Scalar return values like i8, i16, and i64 do indeed seem to follow this rule, according to the output of avr-gcc. Integer return values of up to 64-bits (8 bytes) are always returned directly in registers. However, when a struct is being returned, only structs of 4 bytes or less are returned in registers. If the struct is of 5 bytes or larger, avr-gcc will always pass it on the stack.
29+
30+
This means that different return types have different size limits for fitting into registers or the stack.

llvm/lib/Target/AVR/AVRISelLowering.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,35 @@ SDValue AVRTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
13051305
InVals);
13061306
}
13071307

1308+
/// Reverse splitted return values to get the "big endian" format required
1309+
/// to agree with the calling convention ABI.
1310+
static void ReverseArgumentsToBigEndian(MachineFunction &MF,
1311+
SmallVector<CCValAssign, 16> &RVLocs) {
1312+
if (RVLocs.size() > 1) {
1313+
// Some hackery because SelectionDAGBuilder does not split
1314+
// up arguments properly
1315+
Type *retType = MF.getFunction().getReturnType();
1316+
if (retType->isStructTy()) {
1317+
if (retType->getNumContainedTypes() > 1 &&
1318+
retType->getNumContainedTypes() > RVLocs.size()) {
1319+
for (unsigned i = 0, pos = 0;
1320+
i < retType->getNumContainedTypes(); ++i) {
1321+
Type *field = retType->getContainedType(i);
1322+
if(field->isIntegerTy() && field->getIntegerBitWidth() > 16) {
1323+
int Size = field->getIntegerBitWidth() / 16;
1324+
std::reverse(RVLocs.begin()+ pos, RVLocs.end() + pos + Size);
1325+
pos += Size;
1326+
} else {
1327+
pos++;
1328+
}
1329+
}
1330+
}
1331+
} else {
1332+
std::reverse(RVLocs.begin(), RVLocs.end());
1333+
}
1334+
}
1335+
}
1336+
13081337
/// Lower the result values of a call into the
13091338
/// appropriate copies out of appropriate physical registers.
13101339
///
@@ -1322,12 +1351,6 @@ SDValue AVRTargetLowering::LowerCallResult(
13221351
auto CCFunction = CCAssignFnForReturn(CallConv);
13231352
CCInfo.AnalyzeCallResult(Ins, CCFunction);
13241353

1325-
if (CallConv != CallingConv::AVR_BUILTIN && RVLocs.size() > 1) {
1326-
// Reverse splitted return values to get the "big endian" format required
1327-
// to agree with the calling convention ABI.
1328-
std::reverse(RVLocs.begin(), RVLocs.end());
1329-
}
1330-
13311354
// Copy all of the result registers out of their specified physreg.
13321355
for (CCValAssign const &RVLoc : RVLocs) {
13331356
Chain = DAG.getCopyFromReg(Chain, dl, RVLoc.getLocReg(), RVLoc.getValVT(),
@@ -1390,9 +1413,7 @@ AVRTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
13901413

13911414
// Reverse splitted return values to get the "big endian" format required
13921415
// to agree with the calling convention ABI.
1393-
if (e > 1) {
1394-
std::reverse(RVLocs.begin(), RVLocs.end());
1395-
}
1416+
ReverseArgumentsToBigEndian(MF, RVLocs);
13961417

13971418
SDValue Flag;
13981419
SmallVector<SDValue, 4> RetOps(1, Chain);

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

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,117 @@ define i64 @ret_i64() {
3434
; CHECK-NEXT: mov r25, r19
3535
ret i64 18374966859414961920
3636
}
37+
38+
; CHECK-LABEL: ret_struct1
39+
define { i8, i32 } @ret_struct1() {
40+
start:
41+
; CHECK: ldi r22, 221
42+
; CHECK: ldi r23, 204
43+
; CHECK: ldi r20, 187
44+
; CHECK: ldi r21, 170
45+
; CHECK: ldi r24, 111
46+
ret { i8, i32 } { i8 111, i32 2864434397 } ; { 0x6f, 0xaabbccdd }
47+
}
48+
49+
; CHECK-LABEL: ret_struct2
50+
define { i8, i8, i8, i8, i8 } @ret_struct2() {
51+
start:
52+
ret { i8, i8, i8, i8, i8 } { i8 111, i8 221, i8 204, i8 187, i8 170 } ; { 0x6f, 0xaabbccdd }
53+
}
54+
55+
; CHECK-LABEL: ret_struct3
56+
define { i32, i32 } @ret_struct3() {
57+
start:
58+
ret { i32, i32 } zeroinitializer
59+
}
60+
61+
; CHECK-LABEL: ret_struct4
62+
define { i8, i64 } @ret_struct4() {
63+
start:
64+
ret { i8, i64 } zeroinitializer
65+
}
66+
67+
; CHECK-LABEL: ret_struct5
68+
define { i8, i32, i16 } @ret_struct5() {
69+
start:
70+
ret { i8, i32, i16 } zeroinitializer
71+
}
72+
73+
; CHECK-LABEL: ret_struct6
74+
define { i8, i32, i32 } @ret_struct6() {
75+
start:
76+
ret { i8, i32, i32 } zeroinitializer
77+
}
78+
79+
; Structs of size 1 should be returned in registers.
80+
;
81+
; This matches avr-gcc behaviour.
82+
;
83+
; CHECK-LABEL: ret_struct_size1
84+
define { i8 } @ret_struct_size1() {
85+
; CHECK: ldi r24, 123
86+
ret { i8 } { i8 123 }
87+
}
88+
89+
; Structs of size 2 are currently returned on the stack.
90+
;
91+
; BUG(PR39251): avr-gcc returns all structs of four bytes or less in registers.
92+
;
93+
; CHECK-LABEL: ret_struct_size2
94+
define { i8, i8 } @ret_struct_size2() {
95+
ret { i8, i8 } { i8 123, i8 234 }
96+
}
97+
98+
; Structs of size 3 are currently returned on the stack.
99+
;
100+
; BUG(PR39251): avr-gcc returns all structs of four bytes or less in registers.
101+
;
102+
; CHECK-LABEL: ret_struct_size3
103+
define { i8, i8, i8 } @ret_struct_size3() {
104+
ret { i8, i8, i8 } { i8 123, i8 234, i8 255 }
105+
}
106+
107+
; Structs of size 4 are currently returned on the stack.
108+
;
109+
; BUG(PR39251): avr-gcc returns all structs of four bytes or less in registers.
110+
;
111+
; CHECK-LABEL: ret_struct_size4
112+
define { i8, i8, i8, i8 } @ret_struct_size4() {
113+
ret { i8, i8, i8, i8 } { i8 123, i8 234, i8 255, i8 11 }
114+
}
115+
116+
; Structs of size 5 should be returned on the stack.
117+
;
118+
; This matches avr-gcc behaviour.
119+
;
120+
; CHECK-LABEL: ret_struct_size5
121+
define { i8, i8, i8, i8, i8 } @ret_struct_size5() {
122+
ret { i8, i8, i8, i8, i8 } { i8 123, i8 234, i8 255, i8 11, i8 22 }
123+
}
124+
125+
; Structs of size 6 should be returned on the stack.
126+
;
127+
; This matches avr-gcc behaviour.
128+
;
129+
; CHECK-LABEL: ret_struct_size6
130+
define { i8, i8, i8, i8, i8, i8 } @ret_struct_size6() {
131+
ret { i8, i8, i8, i8, i8, i8 } { i8 123, i8 234, i8 255, i8 11, i8 22, i8 33 }
132+
}
133+
134+
; Structs of size 7 should be returned on the stack.
135+
;
136+
; This matches avr-gcc behaviour.
137+
;
138+
; CHECK-LABEL: ret_struct_size7
139+
define { i8, i8, i8, i8, i8, i8, i8 } @ret_struct_size7() {
140+
ret { i8, i8, i8, i8, i8, i8, i8 } { i8 123, i8 234, i8 255, i8 11, i8 22, i8 33, i8 44 }
141+
}
142+
143+
; Structs of size 8 should be returned on the stack.
144+
;
145+
; This matches avr-gcc behaviour.
146+
;
147+
; CHECK-LABEL: ret_struct_size8
148+
define { i8, i8, i8, i8, i8, i8, i8, i8 } @ret_struct_size8() {
149+
ret { i8, i8, i8, i8, i8, i8, i8, i8 } { i8 123, i8 234, i8 255, i8 11, i8 22, i8 33, i8 44, i8 55 }
150+
}

0 commit comments

Comments
 (0)