From eaf856db5d1a272dc7188937206ef4572836f82a Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Fri, 13 Apr 2012 11:22:00 +0000 Subject: [PATCH] Step forward with supporting of ARM homogenous aggregates: - Handle unions - Handle C++ classes git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154664 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCall.cpp | 121 +++++++++++++++++++++++++--------- lib/CodeGen/CGExpr.cpp | 13 ++++ lib/CodeGen/CodeGenFunction.h | 2 + lib/CodeGen/TargetInfo.cpp | 24 ++++--- 4 files changed, 118 insertions(+), 42 deletions(-) diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 4455f1a086..90b6bee2f7 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -419,16 +419,37 @@ void CodeGenTypes::GetExpandedTypes(QualType type, uint64_t NumElts = AT->getSize().getZExtValue(); for (uint64_t Elt = 0; Elt < NumElts; ++Elt) GetExpandedTypes(AT->getElementType(), expandedTypes); - } else if (const RecordType *RT = type->getAsStructureType()) { + } else if (const RecordType *RT = type->getAs()) { const RecordDecl *RD = RT->getDecl(); assert(!RD->hasFlexibleArrayMember() && "Cannot expand structure with flexible array."); - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - const FieldDecl *FD = *i; - assert(!FD->isBitField() && - "Cannot expand structure with bit-field members."); - GetExpandedTypes(FD->getType(), expandedTypes); + if (RD->isUnion()) { + // Unions can be here only in degenerative cases - all the fields are same + // after flattening. Thus we have to use the "largest" field. + const FieldDecl *LargestFD = 0; + CharUnits UnionSize = CharUnits::Zero(); + + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + assert(!FD->isBitField() && + "Cannot expand structure with bit-field members."); + CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType()); + if (UnionSize < FieldSize) { + UnionSize = FieldSize; + LargestFD = FD; + } + } + if (LargestFD) + GetExpandedTypes(LargestFD->getType(), expandedTypes); + } else { + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + assert(!FD->isBitField() && + "Cannot expand structure with bit-field members."); + GetExpandedTypes(FD->getType(), expandedTypes); + } } } else if (const ComplexType *CT = type->getAs()) { llvm::Type *EltTy = ConvertType(CT->getElementType()); @@ -453,16 +474,40 @@ CodeGenFunction::ExpandTypeFromArgs(QualType Ty, LValue LV, LValue LV = MakeAddrLValue(EltAddr, EltTy); AI = ExpandTypeFromArgs(EltTy, LV, AI); } - } else if (const RecordType *RT = Ty->getAsStructureType()) { + } else if (const RecordType *RT = Ty->getAs()) { RecordDecl *RD = RT->getDecl(); - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - FieldDecl *FD = *i; - QualType FT = FD->getType(); + if (RD->isUnion()) { + // Unions can be here only in degenerative cases - all the fields are same + // after flattening. Thus we have to use the "largest" field. + const FieldDecl *LargestFD = 0; + CharUnits UnionSize = CharUnits::Zero(); - // FIXME: What are the right qualifiers here? - LValue LV = EmitLValueForField(Addr, FD, 0); - AI = ExpandTypeFromArgs(FT, LV, AI); + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + assert(!FD->isBitField() && + "Cannot expand structure with bit-field members."); + CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType()); + if (UnionSize < FieldSize) { + UnionSize = FieldSize; + LargestFD = FD; + } + } + if (LargestFD) { + // FIXME: What are the right qualifiers here? + LValue LV = EmitLValueForField(Addr, LargestFD, 0); + AI = ExpandTypeFromArgs(LargestFD->getType(), LV, AI); + } + } else { + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + FieldDecl *FD = *i; + QualType FT = FD->getType(); + + // FIXME: What are the right qualifiers here? + LValue LV = EmitLValueForField(Addr, FD, 0); + AI = ExpandTypeFromArgs(FT, LV, AI); + } } } else if (const ComplexType *CT = Ty->getAs()) { QualType EltTy = CT->getElementType(); @@ -1760,26 +1805,38 @@ void CodeGenFunction::ExpandTypeToArgs(QualType Ty, RValue RV, EltRV = EmitLoadOfLValue(LV); ExpandTypeToArgs(EltTy, EltRV, Args, IRFuncTy); } - } else if (const RecordType *RT = Ty->getAsStructureType()) { + } else if (const RecordType *RT = Ty->getAs()) { RecordDecl *RD = RT->getDecl(); assert(RV.isAggregate() && "Unexpected rvalue during struct expansion"); llvm::Value *Addr = RV.getAggregateAddr(); - for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); - i != e; ++i) { - FieldDecl *FD = *i; - QualType FT = FD->getType(); - - // FIXME: What are the right qualifiers here? - LValue LV = EmitLValueForField(Addr, FD, 0); - RValue FldRV; - if (FT->isAnyComplexType()) - // FIXME: Volatile? - FldRV = RValue::getComplex(LoadComplexFromAddr(LV.getAddress(), false)); - else if (CodeGenFunction::hasAggregateLLVMType(FT)) - FldRV = LV.asAggregateRValue(); - else - FldRV = EmitLoadOfLValue(LV); - ExpandTypeToArgs(FT, FldRV, Args, IRFuncTy); + + if (RD->isUnion()) { + const FieldDecl *LargestFD = 0; + CharUnits UnionSize = CharUnits::Zero(); + + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + const FieldDecl *FD = *i; + assert(!FD->isBitField() && + "Cannot expand structure with bit-field members."); + CharUnits FieldSize = getContext().getTypeSizeInChars(FD->getType()); + if (UnionSize < FieldSize) { + UnionSize = FieldSize; + LargestFD = FD; + } + } + if (LargestFD) { + RValue FldRV = EmitRValueForField(Addr, LargestFD); + ExpandTypeToArgs(LargestFD->getType(), FldRV, Args, IRFuncTy); + } + } else { + for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + i != e; ++i) { + FieldDecl *FD = *i; + + RValue FldRV = EmitRValueForField(Addr, FD); + ExpandTypeToArgs(FD->getType(), FldRV, Args, IRFuncTy); + } } } else if (Ty->isAnyComplexType()) { ComplexPairTy CV = RV.getComplexVal(); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 08970fd738..a7f5c47bbc 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -2378,6 +2378,19 @@ LValue CodeGenFunction::EmitMaterializeTemporaryExpr( return MakeAddrLValue(RV.getScalarVal(), E->getType()); } +RValue CodeGenFunction::EmitRValueForField(llvm::Value *Addr, + const FieldDecl *FD) { + QualType FT = FD->getType(); + // FIXME: What are the right qualifiers here? + LValue LV = EmitLValueForField(Addr, FD, 0); + if (FT->isAnyComplexType()) + // FIXME: Volatile? + return RValue::getComplex(LoadComplexFromAddr(LV.getAddress(), false)); + else if (CodeGenFunction::hasAggregateLLVMType(FT)) + return LV.asAggregateRValue(); + + return EmitLoadOfLValue(LV); +} //===--------------------------------------------------------------------===// // Expression Emission diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 3e0cd14625..f57dd5f587 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -2104,6 +2104,8 @@ public: LValue EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E); LValue EmitOpaqueValueLValue(const OpaqueValueExpr *e); + RValue EmitRValueForField(llvm::Value *Addr, const FieldDecl *FD); + class ConstantEmission { llvm::PointerIntPair ValueAndIsReference; ConstantEmission(llvm::Constant *C, bool isReference) diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 3ed1778cc9..2b71fdd504 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -2527,19 +2527,16 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { static bool isHomogeneousAggregate(QualType Ty, const Type *&Base, ASTContext &Context, uint64_t *HAMembers = 0) { - uint64_t Members; + uint64_t Members = 0; if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { if (!isHomogeneousAggregate(AT->getElementType(), Base, Context, &Members)) return false; Members *= AT->getSize().getZExtValue(); } else if (const RecordType *RT = Ty->getAs()) { const RecordDecl *RD = RT->getDecl(); - if (RD->isUnion() || RD->hasFlexibleArrayMember()) + if (RD->hasFlexibleArrayMember()) return false; - if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) { - if (!CXXRD->isAggregate()) - return false; - } + Members = 0; for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); i != e; ++i) { @@ -2547,7 +2544,9 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base, uint64_t FldMembers; if (!isHomogeneousAggregate(FD->getType(), Base, Context, &FldMembers)) return false; - Members += FldMembers; + + Members = (RD->isUnion() ? + std::max(Members, FldMembers) : Members + FldMembers); } } else { Members = 1; @@ -2584,7 +2583,8 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base, // Homogeneous Aggregates can have at most 4 members of the base type. if (HAMembers) *HAMembers = Members; - return (Members <= 4); + + return (Members > 0 && Members <= 4); } ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { @@ -2609,8 +2609,10 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { if (getABIKind() == ARMABIInfo::AAPCS_VFP) { // Homogeneous Aggregates need to be expanded. const Type *Base = 0; - if (isHomogeneousAggregate(Ty, Base, getContext())) + if (isHomogeneousAggregate(Ty, Base, getContext())) { + assert(Base && "Base class should be set for homogeneous aggregate"); return ABIArgInfo::getExpand(); + } } // Otherwise, pass by coercing to a structure of the appropriate size. @@ -2776,9 +2778,11 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const { // Check for homogeneous aggregates with AAPCS-VFP. if (getABIKind() == AAPCS_VFP) { const Type *Base = 0; - if (isHomogeneousAggregate(RetTy, Base, getContext())) + if (isHomogeneousAggregate(RetTy, Base, getContext())) { + assert(Base && "Base class should be set for homogeneous aggregate"); // Homogeneous Aggregates are returned directly. return ABIArgInfo::getDirect(); + } } // Aggregates <= 4 bytes are returned in r0; other aggregates