Index: clang/include/clang/AST/ASTContext.h =================================================================== --- clang/include/clang/AST/ASTContext.h +++ clang/include/clang/AST/ASTContext.h @@ -253,9 +253,11 @@ mutable llvm::DenseMap ObjCLayouts; - /// A cache from types to size and alignment information. using TypeInfoMap = llvm::DenseMap; + /// A cache from types to size and ABI-specified alignment information. mutable TypeInfoMap MemoizedTypeInfo; + /// /// A cache from types to size and preferred alignment information. + mutable TypeInfoMap MemoizedPreferredTypeInfo; /// A cache from types to unadjusted alignment information. Only ARM and /// AArch64 targets need this information, keeping it separate prevents @@ -2040,7 +2042,8 @@ private: CanQualType getFromTargetType(unsigned Type) const; - TypeInfo getTypeInfoImpl(const Type *T) const; + TypeInfo getTypeInfoImpl(const Type *T, + bool NeedsPreferredAlignment = false) const; //===--------------------------------------------------------------------===// // Type Predicates. @@ -2083,8 +2086,14 @@ const llvm::fltSemantics &getFloatTypeSemantics(QualType T) const; /// Get the size and alignment of the specified complete type in bits. - TypeInfo getTypeInfo(const Type *T) const; - TypeInfo getTypeInfo(QualType T) const { return getTypeInfo(T.getTypePtr()); } + /// Set "NeedsPreferredAlignment" as true to return the preferred alignment + /// when allocating memory for a variable on the stack or in global/thread + /// local memory. Otherwise, return the ABI-specified alignment. + TypeInfo getTypeInfo(const Type *T, + bool NeedsPreferredAlignment = false) const; + TypeInfo getTypeInfo(QualType T, bool NeedsPreferredAlignment = false) const { + return getTypeInfo(T.getTypePtr(), NeedsPreferredAlignment); + } /// Get default simd alignment of the specified complete type in bits. unsigned getOpenMPDefaultSimdAlign(QualType T) const; @@ -2119,10 +2128,23 @@ return getTypeSizeInCharsIfKnown(QualType(Ty, 0)); } - /// Return the ABI-specified alignment of a (complete) type \p T, in - /// bits. - unsigned getTypeAlign(QualType T) const { return getTypeInfo(T).Align; } - unsigned getTypeAlign(const Type *T) const { return getTypeInfo(T).Align; } + /// Returns the bitwidth of \p T, an SVE type attributed with + /// 'arm_sve_vector_bits'. Should only be called if T->isVLST(). + unsigned getBitwidthForAttributedSveType(const Type *T) const; + + /// Set "NeedsPreferredAlignment" as true to return the preferred alignment + /// of a complete type \p T only when allocating memory for a variable on the + /// the stack or in global/thread local memory. + /// Otherwise, return the ABI-specified alignment of a (complete) type \p T, + /// in bits. + unsigned getTypeAlign(QualType T, + bool NeedsPreferredAlignment = false) const { + return getTypeInfo(T, NeedsPreferredAlignment).Align; + } + unsigned getTypeAlign(const Type *T, + bool NeedsPreferredAlignment = false) const { + return getTypeInfo(T, NeedsPreferredAlignment).Align; + } /// Return the ABI-specified natural alignment of a (complete) type \p T, /// before alignment adjustments, in bits. @@ -2134,15 +2156,24 @@ } unsigned getTypeUnadjustedAlign(const Type *T) const; - /// Return the ABI-specified alignment of a type, in bits, or 0 if - /// the type is incomplete and we cannot determine the alignment (for - /// example, from alignment attributes). - unsigned getTypeAlignIfKnown(QualType T) const; - - /// Return the ABI-specified alignment of a (complete) type \p T, in - /// characters. - CharUnits getTypeAlignInChars(QualType T) const; - CharUnits getTypeAlignInChars(const Type *T) const; + /// Set "NeedsPreferredAlignment" as true to return the preferred alignment + /// of a complete type \p T only when allocating memory for a variable on the + /// the stack or in global/thread local memory. Otherwise, return the + /// ABI-specified alignment of a (complete) type \p T, in bits. Return 0 if + /// the type is incomplete and we cannot determine the alignment (for example, + /// from alignment attributes). + unsigned getTypeAlignIfKnown(QualType T, + bool NeedsPreferredAlignment = false) const; + + /// Set "NeedsPreferredAlignment" as true to return the preferred alignment + /// of a complete type \p T only when allocating memory for a variable on the + /// the stack or in global/thread local memory. + /// Otherwise, return the ABI-specified alignment of a (complete) type \p T, + /// in characters. + CharUnits getTypeAlignInChars(QualType T, + bool NeedsPreferredAlignment = false) const; + CharUnits getTypeAlignInChars(const Type *T, + bool NeedsPreferredAlignment = false) const; /// getTypeUnadjustedAlignInChars - Return the ABI-specified alignment of a type, /// in characters, before alignment adjustments. This method does not work on @@ -2154,8 +2185,14 @@ // type is a record, its data size is returned. std::pair getTypeInfoDataSizeInChars(QualType T) const; - std::pair getTypeInfoInChars(const Type *T) const; - std::pair getTypeInfoInChars(QualType T) const; + /// Get the size and alignment of the specified complete type in characters. + /// Set "NeedsPreferredAlignment" as true to return the preferred alignment + /// when allocating memory for a variable on the stack or in global/thread + /// local memory. Otherwise, return the ABI-specified alignment. + std::pair + getTypeInfoInChars(const Type *T, bool NeedsPreferredAlignment = false) const; + std::pair + getTypeInfoInChars(QualType T, bool NeedsPreferredAlignment = false) const; /// Determine if the alignment the type has was required using an /// alignment attribute. Index: clang/lib/AST/ASTContext.cpp =================================================================== --- clang/lib/AST/ASTContext.cpp +++ clang/lib/AST/ASTContext.cpp @@ -1796,11 +1796,11 @@ /// getConstantArrayInfoInChars - Performing the computation in CharUnits /// instead of in bits prevents overflowing the uint64_t for some large arrays. -std::pair -static getConstantArrayInfoInChars(const ASTContext &Context, - const ConstantArrayType *CAT) { - std::pair EltInfo = - Context.getTypeInfoInChars(CAT->getElementType()); +std::pair static getConstantArrayInfoInChars( + const ASTContext &Context, const ConstantArrayType *CAT, + bool NeedsPreferredAlignment) { + std::pair EltInfo = Context.getTypeInfoInChars( + CAT->getElementType(), NeedsPreferredAlignment); uint64_t Size = CAT->getSize().getZExtValue(); assert((Size == 0 || static_cast(EltInfo.first.getQuantity()) <= (uint64_t)(-1)/Size) && @@ -1815,17 +1815,18 @@ } std::pair -ASTContext::getTypeInfoInChars(const Type *T) const { +ASTContext::getTypeInfoInChars(const Type *T, + bool NeedsPreferredAlignment) const { if (const auto *CAT = dyn_cast(T)) - return getConstantArrayInfoInChars(*this, CAT); - TypeInfo Info = getTypeInfo(T); + return getConstantArrayInfoInChars(*this, CAT, NeedsPreferredAlignment); + TypeInfo Info = getTypeInfo(T, NeedsPreferredAlignment); return std::make_pair(toCharUnitsFromBits(Info.Width), toCharUnitsFromBits(Info.Align)); } std::pair -ASTContext::getTypeInfoInChars(QualType T) const { - return getTypeInfoInChars(T.getTypePtr()); +ASTContext::getTypeInfoInChars(QualType T, bool NeedsPreferredAlignment) const { + return getTypeInfoInChars(T.getTypePtr(), NeedsPreferredAlignment); } bool ASTContext::isAlignmentRequired(const Type *T) const { @@ -1836,7 +1837,8 @@ return isAlignmentRequired(T.getTypePtr()); } -unsigned ASTContext::getTypeAlignIfKnown(QualType T) const { +unsigned ASTContext::getTypeAlignIfKnown(QualType T, + bool NeedsPreferredAlignment) const { // An alignment on a typedef overrides anything else. if (const auto *TT = T->getAs()) if (unsigned Align = TT->getDecl()->getMaxAlignment()) @@ -1845,7 +1847,7 @@ // If we have an (array of) complete type, we're done. T = getBaseElementType(T); if (!T->isIncompleteType()) - return getTypeAlign(T); + return getTypeAlign(T, NeedsPreferredAlignment); // If we had an array type, its element type might be a typedef // type with an alignment attribute. @@ -1860,28 +1862,44 @@ return 0; } -TypeInfo ASTContext::getTypeInfo(const Type *T) const { - TypeInfoMap::iterator I = MemoizedTypeInfo.find(T); - if (I != MemoizedTypeInfo.end()) - return I->second; +TypeInfo ASTContext::getTypeInfo(const Type *T, + bool NeedsPreferredAlignment) const { + auto getTypeInfo = [&](auto &TIMap) { + TypeInfoMap::iterator I = TIMap.find(T); + if (I != TIMap.end()) + return I->second; - // This call can invalidate MemoizedTypeInfo[T], so we need a second lookup. - TypeInfo TI = getTypeInfoImpl(T); - MemoizedTypeInfo[T] = TI; - return TI; + // This call can invalidate MemoizedTypeInfo[T], so we need a second lookup. + TypeInfo TI = getTypeInfoImpl(T, NeedsPreferredAlignment); + TIMap[T] = TI; + return TI; + }; + + return NeedsPreferredAlignment ? getTypeInfo(MemoizedPreferredTypeInfo) + : getTypeInfo(MemoizedTypeInfo); } /// getTypeInfoImpl - Return the size of the specified type, in bits. This /// method does not work on incomplete types. /// +/// Set "NeedsPreferredAlignment" as true only when allocating memory for a +/// variable on the stack or in global/thread local memory. The preferred +/// alignment applies only to a complete object. +/// /// FIXME: Pointers into different addr spaces could have different sizes and /// alignment requirements: getPointerInfo should take an AddrSpace, this /// should take a QualType, &c. -TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { +TypeInfo ASTContext::getTypeInfoImpl(const Type *T, + bool NeedsPreferredAlignment) const { uint64_t Width = 0; unsigned Align = 8; bool AlignIsRequired = false; unsigned AS = 0; + + auto setAlign = [&](unsigned PreferredAlignment, unsigned Alignment) { + Align = NeedsPreferredAlignment ? PreferredAlignment : Alignment; + }; + switch (T->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -1889,8 +1907,9 @@ #define DEPENDENT_TYPE(Class, Base) case Type::Class: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) \ case Type::Class: \ - assert(!T->isDependentType() && "should not see dependent types here"); \ - return getTypeInfo(cast(T)->desugar().getTypePtr()); + assert(!T->isDependentType() && "should not see dependent types here"); \ + return getTypeInfo(cast(T)->desugar().getTypePtr(), \ + NeedsPreferredAlignment); #include "clang/AST/TypeNodes.inc" llvm_unreachable("Should not see dependent types"); @@ -1909,7 +1928,8 @@ if (const auto *CAT = dyn_cast(T)) Size = CAT->getSize().getZExtValue(); - TypeInfo EltInfo = getTypeInfo(cast(T)->getElementType()); + TypeInfo EltInfo = getTypeInfo(cast(T)->getElementType(), + NeedsPreferredAlignment); assert((Size == 0 || EltInfo.Width <= (uint64_t)(-1) / Size) && "Overflow in array type bit size evaluation"); Width = EltInfo.Width * Size; @@ -1924,7 +1944,8 @@ case Type::ExtVector: case Type::Vector: { const auto *VT = cast(T); - TypeInfo EltInfo = getTypeInfo(VT->getElementType()); + TypeInfo EltInfo = + getTypeInfo(VT->getElementType(), NeedsPreferredAlignment); Width = EltInfo.Width * VT->getNumElements(); Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. @@ -1949,7 +1970,8 @@ case Type::ConstantMatrix: { const auto *MT = cast(T); - TypeInfo ElementInfo = getTypeInfo(MT->getElementType()); + TypeInfo ElementInfo = + getTypeInfo(MT->getElementType(), NeedsPreferredAlignment); // The internal layout of a matrix value is implementation defined. // Initially be ABI compatible with arrays with respect to alignment and // size. @@ -2081,17 +2103,17 @@ break; case BuiltinType::Double: Width = Target->getDoubleWidth(); - Align = Target->getDoubleAlign(); + setAlign(Width, Target->getDoubleAlign()); break; case BuiltinType::LongDouble: if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && (Target->getLongDoubleWidth() != AuxTarget->getLongDoubleWidth() || Target->getLongDoubleAlign() != AuxTarget->getLongDoubleAlign())) { Width = AuxTarget->getLongDoubleWidth(); - Align = AuxTarget->getLongDoubleAlign(); + setAlign(Width, AuxTarget->getLongDoubleAlign()); } else { Width = Target->getLongDoubleWidth(); - Align = Target->getLongDoubleAlign(); + setAlign(Width, Target->getLongDoubleAlign()); } break; case BuiltinType::Float128: @@ -2186,16 +2208,19 @@ case Type::Complex: { // Complex types have the same alignment as their elements, but twice the // size. - TypeInfo EltInfo = getTypeInfo(cast(T)->getElementType()); + TypeInfo EltInfo = getTypeInfo(cast(T)->getElementType(), + NeedsPreferredAlignment); Width = EltInfo.Width * 2; Align = EltInfo.Align; break; } case Type::ObjCObject: - return getTypeInfo(cast(T)->getBaseType().getTypePtr()); + return getTypeInfo(cast(T)->getBaseType().getTypePtr(), + NeedsPreferredAlignment); case Type::Adjusted: case Type::Decayed: - return getTypeInfo(cast(T)->getAdjustedType().getTypePtr()); + return getTypeInfo(cast(T)->getAdjustedType().getTypePtr(), + NeedsPreferredAlignment); case Type::ObjCInterface: { const auto *ObjCI = cast(T); if (ObjCI->getDecl()->isInvalidDecl()) { @@ -2230,7 +2255,8 @@ if (const auto *ET = dyn_cast(TT)) { const EnumDecl *ED = ET->getDecl(); TypeInfo Info = - getTypeInfo(ED->getIntegerType()->getUnqualifiedDesugaredType()); + getTypeInfo(ED->getIntegerType()->getUnqualifiedDesugaredType(), + NeedsPreferredAlignment); if (unsigned AttrAlign = ED->getMaxAlignment()) { Info.Align = AttrAlign; Info.AlignIsRequired = true; @@ -2242,36 +2268,43 @@ const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = getASTRecordLayout(RD); Width = toBits(Layout.getSize()); - Align = toBits(Layout.getAlignment()); + setAlign(toBits(Layout.getPreferredAlignment()), + toBits(Layout.getAlignment())); AlignIsRequired = RD->hasAttr(); break; } case Type::SubstTemplateTypeParm: - return getTypeInfo(cast(T)-> - getReplacementType().getTypePtr()); + return getTypeInfo( + cast(T)->getReplacementType().getTypePtr(), + NeedsPreferredAlignment); case Type::Auto: case Type::DeducedTemplateSpecialization: { const auto *A = cast(T); assert(!A->getDeducedType().isNull() && "cannot request the size of an undeduced or dependent auto type"); - return getTypeInfo(A->getDeducedType().getTypePtr()); + return getTypeInfo(A->getDeducedType().getTypePtr(), + NeedsPreferredAlignment); } case Type::Paren: - return getTypeInfo(cast(T)->getInnerType().getTypePtr()); + return getTypeInfo(cast(T)->getInnerType().getTypePtr(), + NeedsPreferredAlignment); case Type::MacroQualified: return getTypeInfo( - cast(T)->getUnderlyingType().getTypePtr()); + cast(T)->getUnderlyingType().getTypePtr(), + NeedsPreferredAlignment); case Type::ObjCTypeParam: - return getTypeInfo(cast(T)->desugar().getTypePtr()); + return getTypeInfo(cast(T)->desugar().getTypePtr(), + NeedsPreferredAlignment); case Type::Typedef: { const TypedefNameDecl *Typedef = cast(T)->getDecl(); - TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr(), + NeedsPreferredAlignment); // If the typedef has an aligned attribute on it, it overrides any computed // alignment we have. This violates the GCC documentation (which says that // attribute(aligned) can only round up) but matches its implementation. @@ -2287,15 +2320,18 @@ } case Type::Elaborated: - return getTypeInfo(cast(T)->getNamedType().getTypePtr()); + return getTypeInfo(cast(T)->getNamedType().getTypePtr(), + NeedsPreferredAlignment); case Type::Attributed: return getTypeInfo( - cast(T)->getEquivalentType().getTypePtr()); + cast(T)->getEquivalentType().getTypePtr(), + NeedsPreferredAlignment); case Type::Atomic: { // Start with the base type information. - TypeInfo Info = getTypeInfo(cast(T)->getValueType()); + TypeInfo Info = getTypeInfo(cast(T)->getValueType(), + NeedsPreferredAlignment); Width = Info.Width; Align = Info.Align; @@ -2380,13 +2416,17 @@ return getTypeInfoInChars(T).first; } -/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in -/// characters. This method does not work on incomplete types. -CharUnits ASTContext::getTypeAlignInChars(QualType T) const { - return toCharUnitsFromBits(getTypeAlign(T)); +/// getTypeAlignInChars - Set "NeedsPreferredAlignment" as true to return the +/// preferred alignment of a complete type \p T only when allocating memory for +/// a variable on the the stack or in global/thread local memory. Otherwise, +/// return the ABI-specified alignment of a (complete) type \p T, in characters. +CharUnits ASTContext::getTypeAlignInChars(QualType T, + bool NeedsPreferredAlignment) const { + return toCharUnitsFromBits(getTypeAlign(T, NeedsPreferredAlignment)); } -CharUnits ASTContext::getTypeAlignInChars(const Type *T) const { - return toCharUnitsFromBits(getTypeAlign(T)); +CharUnits ASTContext::getTypeAlignInChars(const Type *T, + bool NeedsPreferredAlignment) const { + return toCharUnitsFromBits(getTypeAlign(T, NeedsPreferredAlignment)); } /// getTypeUnadjustedAlignInChars - Return the ABI-specified alignment of a @@ -2458,7 +2498,8 @@ /// to a global variable of the specified type. unsigned ASTContext::getAlignOfGlobalVar(QualType T) const { uint64_t TypeSize = getTypeSize(T.getTypePtr()); - return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign(TypeSize)); + return std::max(getTypeAlign(T, true /* NeedsPreferredAlignment */), + getTargetInfo().getMinGlobalAlign(TypeSize)); } /// getAlignOfGlobalVarInChars - Return the alignment in characters that Index: clang/lib/CodeGen/CGExprCXX.cpp =================================================================== --- clang/lib/CodeGen/CGExprCXX.cpp +++ clang/lib/CodeGen/CGExprCXX.cpp @@ -1570,7 +1570,8 @@ llvm::Value *allocSize = EmitCXXNewAllocSize(*this, E, minElements, numElements, allocSizeWithoutCookie); - CharUnits allocAlign = getContext().getTypeAlignInChars(allocType); + CharUnits allocAlign = getContext().getTypeAlignInChars( + allocType, true /* NeedsPreferredAlignment */); // Emit the allocation call. If the allocator is a global placement // operator, just "inline" it directly. @@ -1820,8 +1821,9 @@ // Pass the alignment if the delete function has an align_val_t parameter. if (Params.Alignment) { QualType AlignValType = *ParamTypeIt++; - CharUnits DeleteTypeAlign = getContext().toCharUnitsFromBits( - getContext().getTypeAlignIfKnown(DeleteTy)); + CharUnits DeleteTypeAlign = + getContext().toCharUnitsFromBits(getContext().getTypeAlignIfKnown( + DeleteTy, true /* NeedsPreferredAlignment */)); llvm::Value *Align = llvm::ConstantInt::get(ConvertType(AlignValType), DeleteTypeAlign.getQuantity()); DeleteArgs.add(RValue::get(Align), AlignValType); Index: clang/lib/CodeGen/ItaniumCXXABI.cpp =================================================================== --- clang/lib/CodeGen/ItaniumCXXABI.cpp +++ clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -2111,7 +2111,8 @@ // The array cookie is a size_t; pad that up to the element alignment. // The cookie is actually right-justified in that space. return std::max(CharUnits::fromQuantity(CGM.SizeSizeInBytes), - CGM.getContext().getTypeAlignInChars(elementType)); + CGM.getContext().getTypeAlignInChars( + elementType, true /* NeedsPreferredAlignment */)); } Address ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, @@ -2127,8 +2128,9 @@ CharUnits SizeSize = CGF.getSizeSize(); // The size of the cookie. - CharUnits CookieSize = - std::max(SizeSize, Ctx.getTypeAlignInChars(ElementType)); + CharUnits CookieSize = std::max( + SizeSize, + Ctx.getTypeAlignInChars(ElementType, true /* NeedsPreferredAlignment */)); assert(CookieSize == getArrayCookieSizeImpl(ElementType)); // Compute an offset to the cookie. Index: clang/lib/CodeGen/TargetInfo.cpp =================================================================== --- clang/lib/CodeGen/TargetInfo.cpp +++ clang/lib/CodeGen/TargetInfo.cpp @@ -349,7 +349,8 @@ /// /// \param IsIndirect - Values of this type are passed indirectly. /// \param ValueInfo - The size and alignment of this type, generally -/// computed with getContext().getTypeInfoInChars(ValueTy). +/// computed with getContext().getTypeInfoInChars(ValueTy, +/// NeedsPreferredAlignment). /// \param SlotSizeAndAlign - The size and alignment of a stack slot. /// Each argument will be allocated to a multiple of this number of /// slots, and all the slots will be aligned to this value. @@ -4512,8 +4513,6 @@ if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); - // TODO: Evaluate if AIX power alignment rule would have an impact on the - // alignment here. if (isAggregateTypeForABI(RetTy)) return getNaturalAlignIndirect(RetTy); @@ -4530,8 +4529,6 @@ if (Ty->isVectorType()) llvm::report_fatal_error("vector type is not supported on AIX yet"); - // TODO: Evaluate if AIX power alignment rule would have an impact on the - // alignment here. if (isAggregateTypeForABI(Ty)) { // Records with non-trivial destructors/copy-constructors should not be // passed by value. Index: clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/PaddingChecker.cpp @@ -248,8 +248,8 @@ FieldInfo RetVal; RetVal.Field = FD; auto &Ctx = FD->getASTContext(); - std::tie(RetVal.Size, RetVal.Align) = - Ctx.getTypeInfoInChars(FD->getType()); + std::tie(RetVal.Size, RetVal.Align) = Ctx.getTypeInfoInChars( + FD->getType(), true /* NeedsPreferredAlignment */); assert(llvm::isPowerOf2_64(RetVal.Align.getQuantity())); if (auto Max = FD->getMaxAlignment()) RetVal.Align = std::max(Ctx.toCharUnitsFromBits(Max), RetVal.Align); Index: clang/test/CodeGen/aix-alignment.c =================================================================== --- /dev/null +++ clang/test/CodeGen/aix-alignment.c @@ -0,0 +1,41 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_cc1 -triple powerpc-unknown-aix -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=AIX,AIX32 +// RUN: %clang_cc1 -triple powerpc64-unknown-aix -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=AIX,AIX64 + +// AIX: @d = global double 0.000000e+00, align 8 +double d; + +typedef struct { + double d; + int i; +} StructDouble; + +// AIX: @d1 = global %struct.StructDouble zeroinitializer, align 8 +StructDouble d1; + +// AIX: double @retDouble(double %x) +// AIX: %x.addr = alloca double, align 8 +// AIX: store double %x, double* %x.addr, align 8 +// AIX: load double, double* %x.addr, align 8 +// AIX: ret double %0 +double retDouble(double x) { return x; } + +// AIX32: define void @bar(%struct.StructDouble* noalias sret align 4 %agg.result, %struct.StructDouble* byval(%struct.StructDouble) align 4 %x) +// AIX64: define void @bar(%struct.StructDouble* noalias sret align 4 %agg.result, %struct.StructDouble* byval(%struct.StructDouble) align 8 %x) +// AIX: %0 = bitcast %struct.StructDouble* %agg.result to i8* +// AIX: %1 = bitcast %struct.StructDouble* %x to i8* +// AIX32: call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %0, i8* align 4 %1, i32 16, i1 false) +// AIX64: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 8 %1, i64 16, i1 false) +StructDouble bar(StructDouble x) { return x; } + +// AIX: define void @foo(double* %out, double* %in) +// AIX32: %0 = load double*, double** %in.addr, align 4 +// AIX64: %0 = load double*, double** %in.addr, align 8 +// AIX: %1 = load double, double* %0, align 4 +// AIX: %mul = fmul double %1, 2.000000e+00 +// AIX32: %2 = load double*, double** %out.addr, align 4 +// AIX64: %2 = load double*, double** %out.addr, align 8 +// AIX: store double %mul, double* %2, align 4 +void foo(double *out, double *in) { *out = *in * 2; } Index: clang/test/CodeGenCXX/aix-alignment.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/aix-alignment.cpp @@ -0,0 +1,30 @@ +// REQUIRES: powerpc-registered-target +// RUN: %clang_cc1 -triple powerpc-unknown-aix \ +// RUN: -emit-llvm -o - -x c++ %s | \ +// RUN: FileCheck %s --check-prefixes=AIX,AIX32 +// RUN: %clang_cc1 -triple powerpc64-unknown-aix \ +// RUN: -emit-llvm -o - %s -x c++| \ +// RUN: FileCheck %s --check-prefixes=AIX,AIX64 + +struct B { + double d; + ~B() {} +}; + +// AIX32: %call = call noalias nonnull i8* @_Znam(i32 8) +// AIX64: %call = call noalias nonnull i8* @_Znam(i64 8) +B *allocBp() { return new B[0]; } + +typedef struct D { + double d; + int i; + + ~D(){}; +} D; + +// AIX: define void @_Z3foo1D(%struct.D* noalias sret align 4 %agg.result, %struct.D* %x) +// AIX: %1 = bitcast %struct.D* %agg.result to i8* +// AIX: %2 = bitcast %struct.D* %x to i8* +// AIX32 call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %1, i8* align 4 %2, i32 16, i1 false) +// AIX64: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 %2, i64 16, i1 false) +D foo(D x) { return x; }