Skip to content

Commit c94c8d8

Browse files
committed
[AVR][clang] Fix wrong calling convention in functions return struct type
According to AVR ABI (https://gcc.gnu.org/wiki/avr-gcc), returned struct value within size 1-8 bytes should be returned directly (via register r18-r25), while larger ones should be returned via an implicit struct pointer argument. Reviewed By: dylanmckay Differential Revision: https://reviews.llvm.org/D99237
1 parent ae79854 commit c94c8d8

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

clang/lib/CodeGen/TargetInfo.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8154,14 +8154,39 @@ void M68kTargetCodeGenInfo::setTargetAttributes(
81548154
}
81558155

81568156
//===----------------------------------------------------------------------===//
8157-
// AVR ABI Implementation.
8157+
// AVR ABI Implementation. Documented at
8158+
// https://gcc.gnu.org/wiki/avr-gcc#Calling_Convention
8159+
// https://gcc.gnu.org/wiki/avr-gcc#Reduced_Tiny
81588160
//===----------------------------------------------------------------------===//
81598161

81608162
namespace {
8163+
class AVRABIInfo : public DefaultABIInfo {
8164+
public:
8165+
AVRABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {}
8166+
8167+
ABIArgInfo classifyReturnType(QualType Ty) const {
8168+
// A return struct with size less than or equal to 8 bytes is returned
8169+
// directly via registers R18-R25.
8170+
if (isAggregateTypeForABI(Ty) && getContext().getTypeSize(Ty) <= 64)
8171+
return ABIArgInfo::getDirect();
8172+
else
8173+
return DefaultABIInfo::classifyReturnType(Ty);
8174+
}
8175+
8176+
// Just copy the original implementation of DefaultABIInfo::computeInfo(),
8177+
// since DefaultABIInfo::classify{Return,Argument}Type() are not virtual.
8178+
void computeInfo(CGFunctionInfo &FI) const override {
8179+
if (!getCXXABI().classifyReturnType(FI))
8180+
FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
8181+
for (auto &I : FI.arguments())
8182+
I.info = classifyArgumentType(I.type);
8183+
}
8184+
};
8185+
81618186
class AVRTargetCodeGenInfo : public TargetCodeGenInfo {
81628187
public:
81638188
AVRTargetCodeGenInfo(CodeGenTypes &CGT)
8164-
: TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
8189+
: TargetCodeGenInfo(std::make_unique<AVRABIInfo>(CGT)) {}
81658190

81668191
LangAS getGlobalVarAddressSpace(CodeGenModule &CGM,
81678192
const VarDecl *D) const override {

clang/test/CodeGen/avr/struct.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %clang_cc1 -triple avr -emit-llvm %s -o - | FileCheck %s
2+
3+
// Structure that is more than 8 bytes.
4+
struct s10 {
5+
int a, b, c, d, e;
6+
};
7+
8+
// Structure that is less than 8 bytes.
9+
struct s06 {
10+
int a, b, c;
11+
};
12+
13+
struct s10 foo10(int a, int b, int c) {
14+
struct s10 a0;
15+
return a0;
16+
}
17+
18+
struct s06 foo06(int a, int b, int c) {
19+
struct s06 a0;
20+
return a0;
21+
}
22+
23+
// CHECK: %struct.s10 = type { i16, i16, i16, i16, i16 }
24+
// CHECK: %struct.s06 = type { i16, i16, i16 }
25+
// CHECK: define{{.*}} void @foo10(%struct.s10* {{.*}}, i16 %a, i16 %b, i16 %c)
26+
// CHECK: define{{.*}} %struct.s06 @foo06(i16 %a, i16 %b, i16 %c)

0 commit comments

Comments
 (0)