| 1 | //===- TargetInfo.cpp - Target ABI information ----------------------------===// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "llvm/ABI/TargetInfo.h" |
| 10 | #include "llvm/Support/Casting.h" |
| 11 | #include <algorithm> |
| 12 | #include <cstdint> |
| 13 | |
| 14 | using namespace llvm::abi; |
| 15 | using llvm::dyn_cast; |
| 16 | |
| 17 | bool TargetInfo::isAggregateTypeForABI(const Type *Ty) const { |
| 18 | // Atomic values use the evaluation kind of their underlying value type. |
| 19 | if (const auto *AT = dyn_cast<AtomicType>(Val: Ty)) |
| 20 | return isAggregateTypeForABI(Ty: AT->getValueType()); |
| 21 | |
| 22 | // Check for fundamental scalar types. |
| 23 | if (Ty->isInteger() || Ty->isFloat() || Ty->isPointer() || Ty->isVector()) |
| 24 | return false; |
| 25 | |
| 26 | // A matrix type is modeled as an array but lowers to a single flattened |
| 27 | // vector and has scalar evaluation kind in classic CodeGen, so it is not an |
| 28 | // aggregate for ABI purposes. |
| 29 | if (const auto *AT = dyn_cast<ArrayType>(Val: Ty)) |
| 30 | if (AT->isMatrixType()) |
| 31 | return false; |
| 32 | |
| 33 | // Everything else is treated as aggregate. |
| 34 | return true; |
| 35 | } |
| 36 | |
| 37 | bool TargetInfo::isPromotableInteger(const IntegerType *IT) const { |
| 38 | // TODO: The threshold should be the target's int size rather than a |
| 39 | // hardcoded 32. |
| 40 | unsigned BitWidth = IT->getSizeInBits().getFixedValue(); |
| 41 | return BitWidth < 32; |
| 42 | } |
| 43 | |
| 44 | ArgInfo TargetInfo::getNaturalAlignIndirect(const Type *Ty, bool ByVal) const { |
| 45 | return ArgInfo::getIndirect(Align: Ty->getAlignment(), ByVal); |
| 46 | } |
| 47 | |
| 48 | RecordArgABI TargetInfo::getRecordArgABI(const RecordType *RT) const { |
| 49 | if (RT && !RT->canPassInRegisters()) |
| 50 | return RAA_Indirect; |
| 51 | return RAA_Default; |
| 52 | } |
| 53 | |
| 54 | RecordArgABI TargetInfo::getRecordArgABI(const Type *Ty) const { |
| 55 | // TODO: When Microsoft ABI is supported, CXX records may need different |
| 56 | // handling here (see MicrosoftCXXABI::getRecordArgABI in Clang). |
| 57 | const RecordType *RT = dyn_cast<RecordType>(Val: Ty); |
| 58 | if (!RT) |
| 59 | return RAA_Default; |
| 60 | return getRecordArgABI(RT); |
| 61 | } |
| 62 | |
| 63 | const Type *TargetInfo::useFirstFieldIfTransparentUnion(const Type *Ty) const { |
| 64 | if (const auto *RT = dyn_cast<RecordType>(Val: Ty)) { |
| 65 | if (RT->isUnion() && RT->isTransparentUnion()) { |
| 66 | auto Fields = RT->getFields(); |
| 67 | assert(!Fields.empty() && "transparent union cannot be empty" ); |
| 68 | return Fields.front().FieldType; |
| 69 | } |
| 70 | } |
| 71 | return Ty; |
| 72 | } |
| 73 | |
| 74 | bool TargetInfo::maybeCommonClassifyReturnType(FunctionInfo &FI) const { |
| 75 | const abi::Type *Ty = FI.getReturnType(); |
| 76 | |
| 77 | // TODO: When Microsoft ABI is supported, CXX records may need different |
| 78 | // handling here (see MicrosoftCXXABI::classifyReturnType in Clang). |
| 79 | if (const auto *RT = llvm::dyn_cast<abi::RecordType>(Val: Ty)) { |
| 80 | if (!RT->canPassInRegisters()) { |
| 81 | // A record that cannot pass in registers (e.g. a non-trivial copy/dtor) |
| 82 | // is returned indirectly with ByVal=false. This is the RAA path and is |
| 83 | // distinct from getIndirectReturnResult (plain aggregates), which uses |
| 84 | // ByVal=true. |
| 85 | FI.getReturnInfo() = |
| 86 | ArgInfo::getIndirect(Align: RT->getAlignment(), /*ByVal=*/false); |
| 87 | return true; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | return false; |
| 92 | } |
| 93 | |
| 94 | namespace { |
| 95 | |
| 96 | bool isEmptyRecordForHA(const Type *Ty) { |
| 97 | const auto *RT = dyn_cast<RecordType>(Val: Ty); |
| 98 | return RT && RT->isEmpty(); |
| 99 | } |
| 100 | |
| 101 | } // namespace |
| 102 | |
| 103 | bool TargetInfo::isHomogeneousAggregate(const Type *Ty, const Type *&Base, |
| 104 | uint64_t &Members) const { |
| 105 | bool isMatrixHA = getABICompatInfo().IsMatrixHA; |
| 106 | if (const auto *AT = dyn_cast<ArrayType>(Val: Ty)) { |
| 107 | if (!isMatrixHA && AT->isMatrixType()) |
| 108 | return false; |
| 109 | uint64_t NElements = AT->getNumElements(); |
| 110 | if (NElements == 0) |
| 111 | return false; |
| 112 | if (!isHomogeneousAggregate(Ty: AT->getElementType(), Base, Members)) |
| 113 | return false; |
| 114 | Members *= NElements; |
| 115 | } else if (const auto *RT = dyn_cast<RecordType>(Val: Ty)) { |
| 116 | if (RT->hasFlexibleArrayMember()) |
| 117 | return false; |
| 118 | |
| 119 | Members = 0; |
| 120 | |
| 121 | // If this is a C++ record, check bases and ABI-specific restrictions. |
| 122 | if (RT->isCXXRecord()) { |
| 123 | if (!isPermittedToBeHomogeneousAggregate(RT)) |
| 124 | return false; |
| 125 | |
| 126 | for (const FieldInfo &BaseField : RT->getBaseClasses()) { |
| 127 | if (isEmptyRecordForHA(Ty: BaseField.FieldType)) |
| 128 | continue; |
| 129 | |
| 130 | uint64_t FldMembers = 0; |
| 131 | if (!isHomogeneousAggregate(Ty: BaseField.FieldType, Base, Members&: FldMembers)) |
| 132 | return false; |
| 133 | |
| 134 | Members += FldMembers; |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | for (const FieldInfo &FD : RT->getFields()) { |
| 139 | // Ignore (non-zero arrays of) empty records. |
| 140 | const Type *FT = FD.FieldType; |
| 141 | while (const auto *AT = dyn_cast<ArrayType>(Val: FT)) { |
| 142 | // Don't drill down to the element type of a matrix type here. |
| 143 | // That should fall through to the element isHomogeneousAggregate check. |
| 144 | if (AT->isMatrixType()) |
| 145 | break; |
| 146 | if (AT->getNumElements() == 0) |
| 147 | return false; |
| 148 | FT = AT->getElementType(); |
| 149 | } |
| 150 | if (isEmptyRecordForHA(Ty: FT)) |
| 151 | continue; |
| 152 | |
| 153 | if (isZeroLengthBitfieldPermittedInHomogeneousAggregate() && |
| 154 | FD.IsBitField && FD.BitFieldWidth == 0) |
| 155 | continue; |
| 156 | |
| 157 | uint64_t FldMembers = 0; |
| 158 | if (!isHomogeneousAggregate(Ty: FD.FieldType, Base, Members&: FldMembers)) |
| 159 | return false; |
| 160 | |
| 161 | Members = |
| 162 | RT->isUnion() ? std::max(a: Members, b: FldMembers) : Members + FldMembers; |
| 163 | } |
| 164 | |
| 165 | if (!Base) |
| 166 | return false; |
| 167 | |
| 168 | // Ensure there is no padding. |
| 169 | if (Base->getTypeAllocSize() * Members != Ty->getTypeAllocSize()) |
| 170 | return false; |
| 171 | } else { |
| 172 | Members = 1; |
| 173 | const Type *ElemTy = Ty; |
| 174 | if (const auto *CT = dyn_cast<ComplexType>(Val: Ty)) { |
| 175 | Members = 2; |
| 176 | ElemTy = CT->getElementType(); |
| 177 | } |
| 178 | |
| 179 | // Most ABIs only support float, double, and some vector type widths. |
| 180 | if (!isHomogeneousAggregateBaseType(Ty: ElemTy)) |
| 181 | return false; |
| 182 | |
| 183 | // The base type must be the same for all members. Types that agree in both |
| 184 | // total size and mode (float vs. vector) are treated as equivalent here. |
| 185 | if (!Base) { |
| 186 | Base = ElemTy; |
| 187 | // If it's a non-power-of-2 vector, its ABI size is already a power-of-2, |
| 188 | // so widen it explicitly to match Clang. |
| 189 | if (const auto *VT = dyn_cast<VectorType>(Val: Base)) { |
| 190 | assert(VT->isFixedLength() && |
| 191 | "scalable vectors are never homogeneous aggregates" ); |
| 192 | uint64_t EltSize = |
| 193 | VT->getElementType()->getSizeInBits().getFixedValue(); |
| 194 | unsigned NumElements = |
| 195 | VT->getTypeAllocSize().getFixedValue() * 8 / EltSize; |
| 196 | if (NumElements != VT->getNumElements().getKnownMinValue()) |
| 197 | Base = TB.getVectorType(ElementType: VT->getElementType(), |
| 198 | NumElements: ElementCount::getFixed(MinVal: NumElements), |
| 199 | Align: VT->getAlignment()); |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | if (Base->isVector() != ElemTy->isVector() || |
| 204 | Base->getTypeAllocSize() != ElemTy->getTypeAllocSize()) |
| 205 | return false; |
| 206 | } |
| 207 | return Members > 0 && isHomogeneousAggregateSmallEnough(Base, Members); |
| 208 | } |
| 209 | |