diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -3377,22 +3377,18 @@ return false; } -/// ContainsFloatAtOffset - Return true if the specified LLVM IR type has a -/// float member at the specified offset. For example, {int,{float}} has a -/// float at offset 4. It is conservatively correct for this routine to return -/// false. -static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset, - const llvm::DataLayout &TD) { - // Base case if we find a float. - if (IROffset == 0 && IRType->isFloatTy()) - return true; +/// getTypeAtOffset - Return a first class type at the specified offset. +static llvm::Type *getTypeAtOffset(llvm::Type *IRType, unsigned IROffset, + const llvm::DataLayout &TD) { + if (IROffset == 0 && IRType->isFirstClassType()) + return IRType; // If this is a struct, recurse into the field at the specified offset. if (llvm::StructType *STy = dyn_cast(IRType)) { const llvm::StructLayout *SL = TD.getStructLayout(STy); unsigned Elt = SL->getElementContainingOffset(IROffset); IROffset -= SL->getElementOffset(Elt); - return ContainsFloatAtOffset(STy->getElementType(Elt), IROffset, TD); + return getTypeAtOffset(STy->getElementType(Elt), IROffset, TD); } // If this is an array, recurse into the field at the specified offset. @@ -3400,40 +3396,10 @@ llvm::Type *EltTy = ATy->getElementType(); unsigned EltSize = TD.getTypeAllocSize(EltTy); IROffset -= IROffset/EltSize*EltSize; - return ContainsFloatAtOffset(EltTy, IROffset, TD); + return getTypeAtOffset(EltTy, IROffset, TD); } - return false; -} - -/// ContainsHalfAtOffset - Return true if the specified LLVM IR type has a -/// half member at the specified offset. For example, {int,{half}} has a -/// half at offset 4. It is conservatively correct for this routine to return -/// false. -/// FIXME: Merge with ContainsFloatAtOffset -static bool ContainsHalfAtOffset(llvm::Type *IRType, unsigned IROffset, - const llvm::DataLayout &TD) { - // Base case if we find a float. - if (IROffset == 0 && IRType->isHalfTy()) - return true; - - // If this is a struct, recurse into the field at the specified offset. - if (llvm::StructType *STy = dyn_cast(IRType)) { - const llvm::StructLayout *SL = TD.getStructLayout(STy); - unsigned Elt = SL->getElementContainingOffset(IROffset); - IROffset -= SL->getElementOffset(Elt); - return ContainsHalfAtOffset(STy->getElementType(Elt), IROffset, TD); - } - - // If this is an array, recurse into the field at the specified offset. - if (llvm::ArrayType *ATy = dyn_cast(IRType)) { - llvm::Type *EltTy = ATy->getElementType(); - unsigned EltSize = TD.getTypeAllocSize(EltTy); - IROffset -= IROffset / EltSize * EltSize; - return ContainsHalfAtOffset(EltTy, IROffset, TD); - } - - return false; + return nullptr; } /// GetSSETypeAtOffset - Return a type that will be passed by the backend in the @@ -3441,40 +3407,33 @@ llvm::Type *X86_64ABIInfo:: GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset, QualType SourceTy, unsigned SourceOffset) const { - // If the high 32 bits are not used, we have three choices. Single half, - // single float or two halfs. - if (BitsContainNoUserData(SourceTy, SourceOffset * 8 + 32, - SourceOffset * 8 + 64, getContext())) { - if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout())) - return llvm::Type::getFloatTy(getVMContext()); - if (ContainsHalfAtOffset(IRType, IROffset + 2, getDataLayout())) - return llvm::FixedVectorType::get(llvm::Type::getHalfTy(getVMContext()), - 2); - - return llvm::Type::getHalfTy(getVMContext()); - } - - // We want to pass as <2 x float> if the LLVM IR type contains a float at - // offset+0 and offset+4. Walk the LLVM IR type to find out if this is the - // case. - if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout()) && - ContainsFloatAtOffset(IRType, IROffset + 4, getDataLayout())) - return llvm::FixedVectorType::get(llvm::Type::getFloatTy(getVMContext()), - 2); - - // We want to pass as <4 x half> if the LLVM IR type contains a half at - // offset+0, +2, +4. Walk the LLVM IR type to find out if this is the case. - if (ContainsHalfAtOffset(IRType, IROffset, getDataLayout()) && - ContainsHalfAtOffset(IRType, IROffset + 2, getDataLayout()) && - ContainsHalfAtOffset(IRType, IROffset + 4, getDataLayout())) - return llvm::FixedVectorType::get(llvm::Type::getHalfTy(getVMContext()), 4); - - // We want to pass as <4 x half> if the LLVM IR type contains a mix of float - // and half. - // FIXME: Do we have a better representation for the mixed type? - if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout()) || - ContainsFloatAtOffset(IRType, IROffset + 4, getDataLayout())) - return llvm::FixedVectorType::get(llvm::Type::getHalfTy(getVMContext()), 4); + const llvm::DataLayout &TD = getDataLayout(); + llvm::Type *T0 = getTypeAtOffset(IRType, IROffset, TD); + if (T0->isDoubleTy()) + return T0; + + // Find the next floating point, the minimum offset is 2 bytes (half type). + unsigned NextFP = (TD.getTypeSizeInBits(T0) + 15) / 16 * 2; + llvm::Type *T1 = getTypeAtOffset(IRType, IROffset + NextFP, TD); + if (T1 == nullptr) { + if (NextFP == 2) + T1 = getTypeAtOffset(IRType, IROffset + 4, TD); + if (T1 == nullptr) + return T0; + } + + if (T0->isFloatTy() && T1->isFloatTy()) + return llvm::FixedVectorType::get(T0, 2); + + if (T0->isHalfTy() && T1->isHalfTy()) { + llvm::Type *T3 = getTypeAtOffset(IRType, IROffset + 4, TD); + if (T3 == nullptr) + return llvm::FixedVectorType::get(T0, 2); + return llvm::FixedVectorType::get(T0, 4); + } + + if (T0->isHalfTy() || T1->isHalfTy()) + return llvm::FixedVectorType::get(T0, 4); return llvm::Type::getDoubleTy(getVMContext()); } diff --git a/clang/test/CodeGen/X86/avx512fp16-abi.c b/clang/test/CodeGen/X86/avx512fp16-abi.c --- a/clang/test/CodeGen/X86/avx512fp16-abi.c +++ b/clang/test/CodeGen/X86/avx512fp16-abi.c @@ -147,3 +147,13 @@ x.e = e; return x; } + +struct float2 { + struct {}; + float a; + float b; +}; + +float pr51813(floata s) { + return s.a; +}