Skip to content

Commit bc53832

Browse files
committed
[clang][RISCV] Fix incorrect ABI lowering for inherited structs under hard-float ABIs
The hard float ABIs have a rule that if a flattened struct contains either a single fp value, or an int+fp, or fp+fp then it may be passed in a pair of registers (if sufficient GPRs+FPRs are available). detectFPCCEligibleStruct and the helper it calls, detectFPCCEligibleStructHelper examine the type of the argument/return value to determine if it complies with the requirements for this ABI rule. As reported in bug #57084, this logic produces incorrect results for C++ structs that inherit from other structs. This is because only the fields of the struct were examined, but enumerating RD->fields misses any fields in inherited C++ structs. This patch corrects that issue by adding appropriate logic to enumerate any included base structs. Differential Revision: https://reviews.llvm.org/D131677
1 parent ac6a0cd commit bc53832

File tree

2 files changed

+66
-18
lines changed

2 files changed

+66
-18
lines changed

clang/lib/CodeGen/TargetInfo.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10979,9 +10979,22 @@ bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff,
1097910979
// Unions aren't eligible unless they're empty (which is caught above).
1098010980
if (RD->isUnion())
1098110981
return false;
10982+
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
10983+
// If this is a C++ record, check the bases first.
10984+
if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) {
10985+
for (const CXXBaseSpecifier &B : CXXRD->bases()) {
10986+
const auto *BDecl =
10987+
cast<CXXRecordDecl>(B.getType()->castAs<RecordType>()->getDecl());
10988+
CharUnits BaseOff = Layout.getBaseClassOffset(BDecl);
10989+
bool Ret = detectFPCCEligibleStructHelper(B.getType(), CurOff + BaseOff,
10990+
Field1Ty, Field1Off, Field2Ty,
10991+
Field2Off);
10992+
if (!Ret)
10993+
return false;
10994+
}
10995+
}
1098210996
int ZeroWidthBitFieldCount = 0;
1098310997
for (const FieldDecl *FD : RD->fields()) {
10984-
const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD);
1098510998
uint64_t FieldOffInBits = Layout.getFieldOffset(FD->getFieldIndex());
1098610999
QualType QTy = FD->getType();
1098711000
if (FD->isBitField()) {

clang/test/CodeGen/RISCV/riscv-abi.cpp

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
1-
// RUN: %clang_cc1 -triple riscv32 -emit-llvm -x c++ %s -o - \
1+
// RUN: %clang_cc1 -triple riscv32 -emit-llvm %s -o - \
22
// RUN: | FileCheck -check-prefixes=ILP32,ILP32-ILP32F,ILP32-ILP32F-ILP32D %s
3-
// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm -x c++ %s -o - \
3+
// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-abi ilp32f -emit-llvm %s -o - \
44
// RUN: | FileCheck -check-prefixes=ILP32F,ILP32-ILP32F,ILP32F-ILP32D,ILP32-ILP32F-ILP32D %s
5-
// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-feature +d -target-abi ilp32d -emit-llvm %s -x c++ -o - \
5+
// RUN: %clang_cc1 -triple riscv32 -target-feature +f -target-feature +d -target-abi ilp32d -emit-llvm %s -o - \
66
// RUN: | FileCheck -check-prefixes=ILP32D,ILP32F-ILP32D,ILP32-ILP32F-ILP32D %s
77

8-
// RUN: %clang_cc1 -triple riscv64 -emit-llvm -x c++ %s -o - \
8+
// RUN: %clang_cc1 -triple riscv64 -emit-llvm %s -o - \
99
// RUN: | FileCheck -check-prefixes=LP64,LP64-LP64F,LP64-LP64F-LP64D %s
10-
// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm -x c++ %s -o - \
10+
// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-abi lp64f -emit-llvm %s -o - \
1111
// RUN: | FileCheck -check-prefixes=LP64F,LP64-LP64F,LP64F-LP64D,LP64-LP64F-LP64D %s
12-
// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d -target-abi lp64d -emit-llvm %s -x c++ -o - \
12+
// RUN: %clang_cc1 -triple riscv64 -target-feature +f -target-feature +d -target-abi lp64d -emit-llvm %s -o - \
1313
// RUN: | FileCheck -check-prefixes=LP64D,LP64F-LP64D,LP64-LP64F-LP64D %s
1414

1515
#include <stdint.h>
@@ -39,12 +39,10 @@ struct child2_float_s : parent2_int32_s {
3939
float f1;
4040
};
4141

42-
// TODO: Fix incorrect lowering for hard-float ABIs.
43-
4442
// ILP32: define{{.*}} [2 x i32] @_Z30int32_float_struct_inheritance14child2_float_s([2 x i32] %a.coerce)
45-
// ILP32F-ILP32D: define{{.*}} float @_Z30int32_float_struct_inheritance14child2_float_s(float %0)
43+
// ILP32F-ILP32D: define{{.*}} { i32, float } @_Z30int32_float_struct_inheritance14child2_float_s(i32 %0, float %1)
4644
// LP64: define{{.*}} i64 @_Z30int32_float_struct_inheritance14child2_float_s(i64 %a.coerce)
47-
// LP64F-LP64D: define{{.*}} float @_Z30int32_float_struct_inheritance14child2_float_s(float %0)
45+
// LP64F-LP64D: define{{.*}} { i32, float } @_Z30int32_float_struct_inheritance14child2_float_s(i32 %0, float %1)
4846
struct child2_float_s int32_float_struct_inheritance(struct child2_float_s a) {
4947
return a;
5048
}
@@ -57,10 +55,9 @@ struct child3_int64_s : parent3_float_s {
5755
int64_t i1;
5856
};
5957

60-
// TODO: Fix incorrect lowering for lp64f/lp64d ABIs.
61-
6258
// ILP32-ILP32F-ILP32D-LABEL: define{{.*}} void @_Z30float_int64_struct_inheritance14child3_int64_s(ptr noalias sret(%struct.child3_int64_s)
63-
// LP64-LP64F-LP64D-LABEL: define{{.*}} [2 x i64] @_Z30float_int64_struct_inheritance14child3_int64_s([2 x i64] %a.coerce)
59+
// LP64-LABEL: define{{.*}} [2 x i64] @_Z30float_int64_struct_inheritance14child3_int64_s([2 x i64] %a.coerce)
60+
// LP64F-LP64D-LABEL: define{{.*}} { float, i64 } @_Z30float_int64_struct_inheritance14child3_int64_s(float %0, i64 %1)
6461
struct child3_int64_s float_int64_struct_inheritance(struct child3_int64_s a) {
6562
return a;
6663
}
@@ -73,16 +70,54 @@ struct child4_double_s : parent4_double_s {
7370
double d1;
7471
};
7572

76-
// TODO: Fix incorrect lowering for ilp32d/lp64d ABIs.
77-
7873
// ILP32-ILP32F-LABEL: define{{.*}} void @_Z32double_double_struct_inheritance15child4_double_s(ptr noalias sret(%struct.child4_double_s)
79-
// ILP32D-LABEL: define{{.*}} double @_Z32double_double_struct_inheritance15child4_double_s(double %0)
74+
// ILP32D-LABEL: define{{.*}} { double, double } @_Z32double_double_struct_inheritance15child4_double_s(double %0, double %1)
8075
// LP64-LP64F-LABEL: define{{.*}} [2 x i64] @_Z32double_double_struct_inheritance15child4_double_s([2 x i64] %a.coerce)
81-
// LP64D-LABEL: define{{.*}} double @_Z32double_double_struct_inheritance15child4_double_s(double %0)
76+
// LP64D-LABEL: define{{.*}} { double, double } @_Z32double_double_struct_inheritance15child4_double_s(double %0, double %1)
8277
struct child4_double_s double_double_struct_inheritance(struct child4_double_s a) {
8378
return a;
8479
}
8580

81+
// When virtual inheritance is used, the resulting struct isn't eligible for
82+
// passing in registers.
83+
84+
struct parent5_virtual_s {
85+
int32_t i1;
86+
};
87+
88+
struct child5_virtual_s : virtual parent5_virtual_s {
89+
float f1;
90+
};
91+
92+
// ILP32-ILP32F-ILP32D-LABEL: define{{.*}} void @_ZN16child5_virtual_sC1EOS_(ptr noundef nonnull align 4 dereferenceable(8) %this, ptr noundef nonnull align 4 dereferenceable(8) %0)
93+
// LP64-LP64F-LP64D-LABEL: define{{.*}} void @_ZN16child5_virtual_sC1EOS_(ptr noundef nonnull align 8 dereferenceable(12) %this, ptr noundef nonnull align 8 dereferenceable(12) %0)
94+
struct child5_virtual_s int32_float_virtual_struct_inheritance(struct child5_virtual_s a) {
95+
return a;
96+
}
97+
98+
// Check for correct lowering in the presence of diamond inheritance.
99+
100+
struct parent6_float_s {
101+
float f1;
102+
};
103+
104+
struct child6a_s : parent6_float_s {
105+
};
106+
107+
struct child6b_s : parent6_float_s {
108+
};
109+
110+
struct grandchild_6_s : child6a_s, child6b_s {
111+
};
112+
113+
// ILP32: define{{.*}} [2 x i32] @_Z38float_float_diamond_struct_inheritance14grandchild_6_s([2 x i32] %a.coerce)
114+
// ILP32F-ILP64D: define{{.*}} { float, float } @_Z38float_float_diamond_struct_inheritance14grandchild_6_s(float %0, float %1)
115+
// LP64: define{{.*}} i64 @_Z38float_float_diamond_struct_inheritance14grandchild_6_s(i64 %a.coerce)
116+
// LP64F-LP64D: define{{.*}} { float, float } @_Z38float_float_diamond_struct_inheritance14grandchild_6_s(float %0, float %1)
117+
struct grandchild_6_s float_float_diamond_struct_inheritance(struct grandchild_6_s a) {
118+
return a;
119+
}
120+
86121
// NOTE: These prefixes are unused. Do not add tests below this line:
87122
// ILP32F: {{.*}}
88123
// LP64F: {{.*}}

0 commit comments

Comments
 (0)