diff options
author | Daniel Dunbar <daniel@zuster.org> | 2009-11-22 23:01:23 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2009-11-22 23:01:23 +0000 |
commit | ce9f423d2ce4b8699d9f6c7623053f645ac4dc6d (patch) | |
tree | 78268dac6cc7bfde56e2d7098d72c7f6720156fb | |
parent | 90cb920bfa167ae30cea35fe296533e7779f4ee2 (diff) |
x86_64, PR5582: Layout bases for C++ records.
- Ideally we would have an single iteration interface for this, but this works
for now.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@89632 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/TargetABIInfo.cpp | 28 | ||||
-rw-r--r-- | test/CodeGenCXX/x86_64-arguments.cpp | 27 |
2 files changed, 48 insertions, 7 deletions
diff --git a/lib/CodeGen/TargetABIInfo.cpp b/lib/CodeGen/TargetABIInfo.cpp index ba0bc6668e..2bc61753a0 100644 --- a/lib/CodeGen/TargetABIInfo.cpp +++ b/lib/CodeGen/TargetABIInfo.cpp @@ -771,7 +771,7 @@ void X86_64ABIInfo::classify(QualType Ty, // reference. if (hasNonTrivialDestructorOrCopyConstructor(RT)) return; - + const RecordDecl *RD = RT->getDecl(); // Assume variable sized types are passed in memory. @@ -782,6 +782,32 @@ void X86_64ABIInfo::classify(QualType Ty, // Reset Lo class, this will be recomputed. Current = NoClass; + + // If this is a C++ record, classify the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) { + for (CXXRecordDecl::base_class_const_iterator i = CXXRD->bases_begin(), + e = CXXRD->bases_end(); i != e; ++i) { + assert(!i->isVirtual() && !i->getType()->isDependentType() && + "Unexpected base class!"); + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + + // Classify this field. + // + // AMD64-ABI 3.2.3p2: Rule 3. If the size of the aggregate exceeds a + // single eightbyte, each is classified separately. Each eightbyte gets + // initialized to class NO_CLASS. + Class FieldLo, FieldHi; + uint64_t Offset = OffsetBase + Layout.getBaseClassOffset(Base); + classify(i->getType(), Context, Offset, FieldLo, FieldHi); + Lo = merge(Lo, FieldLo); + Hi = merge(Hi, FieldHi); + if (Lo == Memory || Hi == Memory) + break; + } + } + + // Classify the fields one at a time, merging the results. unsigned idx = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i, ++idx) { diff --git a/test/CodeGenCXX/x86_64-arguments.cpp b/test/CodeGenCXX/x86_64-arguments.cpp index 6b5e7a7a1d..0e4c2abc10 100644 --- a/test/CodeGenCXX/x86_64-arguments.cpp +++ b/test/CodeGenCXX/x86_64-arguments.cpp @@ -1,9 +1,24 @@ -// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o %t %s -struct A { ~A(); }; +// RUN: clang-cc -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck %s -// RUN: grep 'define void @_Z2f11A(.struct.A\* .a)' %t -void f1(A a) { } +// CHECK: [[i64_i64_ty:%.*]] = type { i64, i64 } +// CHECK: [[i64_double_ty:%.*]] = type { i64, double } + +// Basic base class test. +struct f0_s0 { unsigned a; }; +struct f0_s1 : public f0_s0 { void *b; }; +// CHECK: define void @_Z2f05f0_s1([[i64_i64_ty]]) +void f0(f0_s1 a0) { } + +// Check with two eight-bytes in base class. +struct f1_s0 { unsigned a; unsigned b; float c; }; +struct f1_s1 : public f1_s0 { float d;}; +// CHECK: define void @_Z2f15f1_s1([[i64_double_ty]]) +void f1(f1_s1 a0) { } + +// Check with two eight-bytes in base class and merge. +struct f2_s0 { unsigned a; unsigned b; float c; }; +struct f2_s1 : public f2_s0 { char d;}; +// CHECK: define void @_Z2f25f2_s1([[i64_i64_ty]]) +void f2(f2_s1 a0) { } -// RUN: grep 'define void @_Z2f2v(.struct.A\* noalias sret .agg.result)' %t -A f2() { return A(); } |