From: Akira Hatanaka Date: Thu, 9 Feb 2012 18:49:26 +0000 (+0000) Subject: Fix bugs in function MipsABIInfo::returnAggregateInRegs. Functions returning X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=da54ff306270e179f64d046369419724356d30d7;p=clang Fix bugs in function MipsABIInfo::returnAggregateInRegs. Functions returning class objects follow the same rules as those returning struct objects. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150196 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 97b49a0c6b..b48bff8a1e 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -3173,27 +3173,40 @@ MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { llvm::Type* MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const { - const RecordType *RT = RetTy->getAsStructureType(); + const RecordType *RT = RetTy->getAs(); SmallVector RTList; - if (RT) { + if (RT && RT->isStructureOrClassType()) { const RecordDecl *RD = RT->getDecl(); - RecordDecl::field_iterator b = RD->field_begin(), e = RD->field_end(), i; - - for (i = b; (i != e) && (std::distance(b, i) < 2); ++i) { - const BuiltinType *BT = (*i)->getType()->getAs(); + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); + unsigned FieldCnt = Layout.getFieldCount(); + + // N32/64 returns struct/classes in floating point registers if the + // following conditions are met: + // 1. The size of the struct/class is no larger than 128-bit. + // 2. The struct/class has one or two fields all of which are floating + // point types. + // 3. The offset of the first field is zero (this follows what gcc does). + // + // Any other composite results are returned in integer registers. + // + if (FieldCnt && (FieldCnt <= 2) && !Layout.getFieldOffset(0)) { + RecordDecl::field_iterator b = RD->field_begin(), e = RD->field_end(); + for (; b != e; ++b) { + const BuiltinType *BT = (*b)->getType()->getAs(); - if (!BT || !BT->isFloatingPoint()) - break; + if (!BT || !BT->isFloatingPoint()) + break; - RTList.push_back(CGT.ConvertType((*i)->getType())); - } + RTList.push_back(CGT.ConvertType((*b)->getType())); + } - if (i == e) - return llvm::StructType::get(getVMContext(), RTList, - RD->hasAttr()); + if (b == e) + return llvm::StructType::get(getVMContext(), RTList, + RD->hasAttr()); - RTList.clear(); + RTList.clear(); + } } RTList.push_back(llvm::IntegerType::get(getVMContext(), diff --git a/test/CodeGen/mips64-class-return.cpp b/test/CodeGen/mips64-class-return.cpp new file mode 100644 index 0000000000..eca8d5b2f7 --- /dev/null +++ b/test/CodeGen/mips64-class-return.cpp @@ -0,0 +1,31 @@ +// RUN: %clang -target mips64el-unknown-linux -ccc-clang-archs mips64el -O3 -S -mabi=n64 -o - -emit-llvm %s | FileCheck %s + +class B0 { + double d; +}; + +class D0 : public B0 { + float f; +}; + +class B1 { +}; + +class D1 : public B1 { + double d; + float f; +}; + +extern D0 gd0; +extern D1 gd1; + +// CHECK: define { i64, i64 } @_Z4foo1v() +D0 foo1(void) { + return gd0; +} + +// CHECK: define { double, float } @_Z4foo2v() +D1 foo2(void) { + return gd1; +} +