//===--- SwiftCallingConv.cpp - Lowering for the Swift calling convention -===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // Implementation of the abstract lowering for the Swift calling convention. // //===----------------------------------------------------------------------===// #include "clang/CodeGen/SwiftCallingConv.h" #include "ABIInfo.h" #include "CodeGenModule.h" #include "TargetInfo.h" #include "clang/Basic/TargetInfo.h" #include using namespace clang; using namespace CodeGen; using namespace swiftcall; static const SwiftABIInfo &getSwiftABIInfo(CodeGenModule &CGM) { return CGM.getTargetCodeGenInfo().getSwiftABIInfo(); } static bool isPowerOf2(unsigned n) { return n == (n & -n); } /// Given two types with the same size, try to find a common type. static llvm::Type *getCommonType(llvm::Type *first, llvm::Type *second) { assert(first != second); // Allow pointers to merge with integers, but prefer the integer type. if (first->isIntegerTy()) { if (second->isPointerTy()) return first; } else if (first->isPointerTy()) { if (second->isIntegerTy()) return second; if (second->isPointerTy()) return first; // Allow two vectors to be merged (given that they have the same size). // This assumes that we never have two different vector register sets. } else if (auto firstVecTy = dyn_cast(first)) { if (auto secondVecTy = dyn_cast(second)) { if (auto commonTy = getCommonType(firstVecTy->getElementType(), secondVecTy->getElementType())) { return (commonTy == firstVecTy->getElementType() ? first : second); } } } return nullptr; } static CharUnits getTypeStoreSize(CodeGenModule &CGM, llvm::Type *type) { return CharUnits::fromQuantity(CGM.getDataLayout().getTypeStoreSize(type)); } static CharUnits getTypeAllocSize(CodeGenModule &CGM, llvm::Type *type) { return CharUnits::fromQuantity(CGM.getDataLayout().getTypeAllocSize(type)); } void SwiftAggLowering::addTypedData(QualType type, CharUnits begin) { // Deal with various aggregate types as special cases: // Record types. if (auto recType = type->getAs()) { addTypedData(recType->getDecl(), begin); // Array types. } else if (type->isArrayType()) { // Incomplete array types (flexible array members?) don't provide // data to lay out, and the other cases shouldn't be possible. auto arrayType = CGM.getContext().getAsConstantArrayType(type); if (!arrayType) return; QualType eltType = arrayType->getElementType(); auto eltSize = CGM.getContext().getTypeSizeInChars(eltType); for (uint64_t i = 0, e = arrayType->getZExtSize(); i != e; ++i) { addTypedData(eltType, begin + i * eltSize); } // Complex types. } else if (auto complexType = type->getAs()) { auto eltType = complexType->getElementType(); auto eltSize = CGM.getContext().getTypeSizeInChars(eltType); auto eltLLVMType = CGM.getTypes().ConvertType(eltType); addTypedData(eltLLVMType, begin, begin + eltSize); addTypedData(eltLLVMType, begin + eltSize, begin + 2 * eltSize); // Member pointer types. } else if (type->getAs()) { // Just add it all as opaque. addOpaqueData(begin, begin + CGM.getContext().getTypeSizeInChars(type)); // Atomic types. } else if (const auto *atomicType = type->getAs()) { auto valueType = atomicType->getValueType(); auto atomicSize = CGM.getContext().getTypeSizeInChars(atomicType); auto valueSize = CGM.getContext().getTypeSizeInChars(valueType); addTypedData(atomicType->getValueType(), begin); // Add atomic padding. auto atomicPadding = atomicSize - valueSize; if (atomicPadding > CharUnits::Zero()) addOpaqueData(begin + valueSize, begin + atomicSize); // Everything else is scalar and should not convert as an LLVM aggregate. } else { // We intentionally convert as !ForMem because we want to preserve // that a type was an i1. auto *llvmType = CGM.getTypes().ConvertType(type); addTypedData(llvmType, begin); } } void SwiftAggLowering::addTypedData(const RecordDecl *record, CharUnits begin) { addTypedData(record, begin, CGM.getContext().getASTRecordLayout(record)); } void SwiftAggLowering::addTypedData(const RecordDecl *record, CharUnits begin, const ASTRecordLayout &layout) { // Unions are a special case. if (record->isUnion()) { for (auto *field : record->fields()) { if (field->isBitField()) { addBitFieldData(field, begin, 0); } else { addTypedData(field->getType(), begin); } } return; } // Note that correctness does not rely on us adding things in // their actual order of layout; it's just somewhat more efficient // for the builder. // With that in mind, add "early" C++ data. auto cxxRecord = dyn_cast(record); if (cxxRecord) { // - a v-table pointer, if the class adds its own if (layout.hasOwnVFPtr()) { addTypedData(CGM.Int8PtrTy, begin); } // - non-virtual bases for (auto &baseSpecifier : cxxRecord->bases()) { if (baseSpecifier.isVirtual()) continue; auto baseRecord = baseSpecifier.getType()->getAsCXXRecordDecl(); addTypedData(baseRecord, begin + layout.getBaseClassOffset(baseRecord)); } // - a vbptr if the class adds its own if (layout.hasOwnVBPtr()) { addTypedData(CGM.Int8PtrTy, begin + layout.getVBPtrOffset()); } } // Add fields. for (auto *field : record->fields()) { auto fieldOffsetInBits = layout.getFieldOffset(field->getFieldIndex()); if (field->isBitField()) { addBitFieldData(field, begin, fieldOffsetInBits); } else { addTypedData(field->getType(), begin + CGM.getContext().toCharUnitsFromBits(fieldOffsetInBits)); } } // Add "late" C++ data: if (cxxRecord) { // - virtual bases for (auto &vbaseSpecifier : cxxRecord->vbases()) { auto baseRecord = vbaseSpecifier.getType()->getAsCXXRecordDecl(); addTypedData(baseRecord, begin + layout.getVBaseClassOffset(baseRecord)); } } } void SwiftAggLowering::addBitFieldData(const FieldDecl *bitfield, CharUnits recordBegin, uint64_t bitfieldBitBegin) { assert(bitfield->isBitField()); auto &ctx = CGM.getContext(); auto width = bitfield->getBitWidthValue(ctx); // We can ignore zero-width bit-fields. if (width == 0) return; // toCharUnitsFromBits rounds down. CharUnits bitfieldByteBegin = ctx.toCharUnitsFromBits(bitfieldBitBegin); // Find the offset of the last byte that is partially occupied by the // bit-field; since we otherwise expect exclusive ends, the end is the // next byte. uint64_t bitfieldBitLast = bitfieldBitBegin + width - 1; CharUnits bitfieldByteEnd = ctx.toCharUnitsFromBits(bitfieldBitLast) + CharUnits::One(); addOpaqueData(recordBegin + bitfieldByteBegin, recordBegin + bitfieldByteEnd); } void SwiftAggLowering::addTypedData(llvm::Type *type, CharUnits begin) { assert(type && "didn't provide type for typed data"); addTypedData(type, begin, begin + getTypeStoreSize(CGM, type)); } void SwiftAggLowering::addTypedData(llvm::Type *type, CharUnits begin, CharUnits end) { assert(type && "didn't provide type for typed data"); assert(getTypeStoreSize(CGM, type) == end - begin); // Legalize vector types. if (auto vecTy = dyn_cast(type)) { SmallVector componentTys; legalizeVectorType(CGM, end - begin, vecTy, componentTys); assert(componentTys.size() >= 1); // Walk the initial components. for (size_t i = 0, e = componentTys.size(); i != e - 1; ++i) { llvm::Type *componentTy = componentTys[i]; auto componentSize = getTypeStoreSize(CGM, componentTy); assert(componentSize < end - begin); addLegalTypedData(componentTy, begin, begin + componentSize); begin += componentSize; } return addLegalTypedData(componentTys.back(), begin, end); } // Legalize integer types. if (auto intTy = dyn_cast(type)) { if (!isLegalIntegerType(CGM, intTy)) return addOpaqueData(begin, end); } // All other types should be legal. return addLegalTypedData(type, begin, end); } void SwiftAggLowering::addLegalTypedData(llvm::Type *type, CharUnits begin, CharUnits end) { // Require the type to be naturally aligned. if (!begin.isZero() && !begin.isMultipleOf(getNaturalAlignment(CGM, type))) { // Try splitting vector types. if (auto vecTy = dyn_cast(type)) { auto split = splitLegalVectorType(CGM, end - begin, vecTy); auto eltTy = split.first; auto numElts = split.second; auto eltSize = (end - begin) / numElts; assert(eltSize == getTypeStoreSize(CGM, eltTy)); for (size_t i = 0, e = numElts; i != e; ++i) { addLegalTypedData(eltTy, begin, begin + eltSize); begin += eltSize; } assert(begin == end); return; } return addOpaqueData(begin, end); } addEntry(type, begin, end); } void SwiftAggLowering::addEntry(llvm::Type *type, CharUnits begin, CharUnits end) { assert((!type || (!isa(type) && !isa(type))) && "cannot add aggregate-typed data"); assert(!type || begin.isMultipleOf(getNaturalAlignment(CGM, type))); // Fast path: we can just add entries to the end. if (Entries.empty() || Entries.back().End <= begin) { Entries.push_back({begin, end, type}); return; } // Find the first existing entry that ends after the start of the new data. // TODO: do a binary search if Entries is big enough for it to matter. size_t index = Entries.size() - 1; while (index != 0) { if (Entries[index - 1].End <= begin) break; --index; } // The entry ends after the start of the new data. // If the entry starts after the end of the new data, there's no conflict. if (Entries[index].Begin >= end) { // This insertion is potentially O(n), but the way we generally build // these layouts makes that unlikely to matter: we'd need a union of // several very large types. Entries.insert(Entries.begin() + index, {begin, end, type}); return; } // Otherwise, the ranges overlap. The new range might also overlap // with later ranges. restartAfterSplit: // Simplest case: an exact overlap. if (Entries[index].Begin == begin && Entries[index].End == end) { // If the types match exactly, great. if (Entries[index].Type == type) return; // If either type is opaque, make the entry opaque and return. if (Entries[index].Type == nullptr) { return; } else if (type == nullptr) { Entries[index].Type = nullptr; return; } // If they disagree in an ABI-agnostic way, just resolve the conflict // arbitrarily. if (auto entryType = getCommonType(Entries[index].Type, type)) { Entries[index].Type = entryType; return; } // Otherwise, make the entry opaque. Entries[index].Type = nullptr; return; } // Okay, we have an overlapping conflict of some sort. // If we have a vector type, split it. if (auto vecTy = dyn_cast_or_null(type)) { auto eltTy = vecTy->getElementType(); CharUnits eltSize = (end - begin) / cast(vecTy)->getNumElements(); assert(eltSize == getTypeStoreSize(CGM, eltTy)); for (unsigned i = 0, e = cast(vecTy)->getNumElements(); i != e; ++i) { addEntry(eltTy, begin, begin + eltSize); begin += eltSize; } assert(begin == end); return; } // If the entry is a vector type, split it and try again. if (Entries[index].Type && Entries[index].Type->isVectorTy()) { splitVectorEntry(index); goto restartAfterSplit; } // Okay, we have no choice but to make the existing entry opaque. Entries[index].Type = nullptr; // Stretch the start of the entry to the beginning of the range. if (begin < Entries[index].Begin) { Entries[index].Begin = begin; assert(index == 0 || begin >= Entries[index - 1].End); } // Stretch the end of the entry to the end of the range; but if we run // into the start of the next entry, just leave the range there and repeat. while (end > Entries[index].End) { assert(Entries[index].Type == nullptr); // If the range doesn't overlap the next entry, we're done. if (index == Entries.size() - 1 || end <= Entries[index + 1].Begin) { Entries[index].End = end; break; } // Otherwise, stretch to the start of the next entry. Entries[index].End = Entries[index + 1].Begin; // Continue with the next entry. index++; // This entry needs to be made opaque if it is not already. if (Entries[index].Type == nullptr) continue; // Split vector entries unless we completely subsume them. if (Entries[index].Type->isVectorTy() && end < Entries[index].End) { splitVectorEntry(index); } // Make the entry opaque. Entries[index].Type = nullptr; } } /// Replace the entry of vector type at offset 'index' with a sequence /// of its component vectors. void SwiftAggLowering::splitVectorEntry(unsigned index) { auto vecTy = cast(Entries[index].Type); auto split = splitLegalVectorType(CGM, Entries[index].getWidth(), vecTy); auto eltTy = split.first; CharUnits eltSize = getTypeStoreSize(CGM, eltTy); auto numElts = split.second; Entries.insert(Entries.begin() + index + 1, numElts - 1, StorageEntry()); CharUnits begin = Entries[index].Begin; for (unsigned i = 0; i != numElts; ++i) { unsigned idx = index + i; Entries[idx].Type = eltTy; Entries[idx].Begin = begin; Entries[idx].End = begin + eltSize; begin += eltSize; } } /// Given a power-of-two unit size, return the offset of the aligned unit /// of that size which contains the given offset. /// /// In other words, round down to the nearest multiple of the unit size. static CharUnits getOffsetAtStartOfUnit(CharUnits offset, CharUnits unitSize) { assert(isPowerOf2(unitSize.getQuantity())); auto unitMask = ~(unitSize.getQuantity() - 1); return CharUnits::fromQuantity(offset.getQuantity() & unitMask); } static bool areBytesInSameUnit(CharUnits first, CharUnits second, CharUnits chunkSize) { return getOffsetAtStartOfUnit(first, chunkSize) == getOffsetAtStartOfUnit(second, chunkSize); } static bool isMergeableEntryType(llvm::Type *type) { // Opaquely-typed memory is always mergeable. if (type == nullptr) return true; // Pointers and integers are always mergeable. In theory we should not // merge pointers, but (1) it doesn't currently matter in practice because // the chunk size is never greater than the size of a pointer and (2) // Swift IRGen uses integer types for a lot of things that are "really" // just storing pointers (like std::optional). If we ever have a // target that would otherwise combine pointers, we should put some effort // into fixing those cases in Swift IRGen and then call out pointer types // here. // Floating-point and vector types should never be merged. // Most such types are too large and highly-aligned to ever trigger merging // in practice, but it's important for the rule to cover at least 'half' // and 'float', as well as things like small vectors of 'i1' or 'i8'. return (!type->isFloatingPointTy() && !type->isVectorTy()); } bool SwiftAggLowering::shouldMergeEntries(const StorageEntry &first, const StorageEntry &second, CharUnits chunkSize) { // Only merge entries that overlap the same chunk. We test this first // despite being a bit more expensive because this is the condition that // tends to prevent merging. if (!areBytesInSameUnit(first.End - CharUnits::One(), second.Begin, chunkSize)) return false; return (isMergeableEntryType(first.Type) && isMergeableEntryType(second.Type)); } void SwiftAggLowering::finish() { if (Entries.empty()) { Finished = true; return; } // We logically split the layout down into a series of chunks of this size, // which is generally the size of a pointer. const CharUnits chunkSize = getMaximumVoluntaryIntegerSize(CGM); // First pass: if two entries should be merged, make them both opaque // and stretch one to meet the next. // Also, remember if there are any opaque entries. bool hasOpaqueEntries = (Entries[0].Type == nullptr); for (size_t i = 1, e = Entries.size(); i != e; ++i) { if (shouldMergeEntries(Entries[i - 1], Entries[i], chunkSize)) { Entries[i - 1].Type = nullptr; Entries[i].Type = nullptr; Entries[i - 1].End = Entries[i].Begin; hasOpaqueEntries = true; } else if (Entries[i].Type == nullptr) { hasOpaqueEntries = true; } } // The rest of the algorithm leaves non-opaque entries alone, so if we // have no opaque entries, we're done. if (!hasOpaqueEntries) { Finished = true; return; } // Okay, move the entries to a temporary and rebuild Entries. auto orig = std::move(Entries); assert(Entries.empty()); for (size_t i = 0, e = orig.size(); i != e; ++i) { // Just copy over non-opaque entries. if (orig[i].Type != nullptr) { Entries.push_back(orig[i]); continue; } // Scan forward to determine the full extent of the next opaque range. // We know from the first pass that only contiguous ranges will overlap // the same aligned chunk. auto begin = orig[i].Begin; auto end = orig[i].End; while (i + 1 != e && orig[i + 1].Type == nullptr && end == orig[i + 1].Begin) { end = orig[i + 1].End; i++; } // Add an entry per intersected chunk. do { // Find the smallest aligned storage unit in the maximal aligned // storage unit containing 'begin' that contains all the bytes in // the intersection between the range and this chunk. CharUnits localBegin = begin; CharUnits chunkBegin = getOffsetAtStartOfUnit(localBegin, chunkSize); CharUnits chunkEnd = chunkBegin + chunkSize; CharUnits localEnd = std::min(end, chunkEnd); // Just do a simple loop over ever-increasing unit sizes. CharUnits unitSize = CharUnits::One(); CharUnits unitBegin, unitEnd; for (; ; unitSize *= 2) { assert(unitSize <= chunkSize); unitBegin = getOffsetAtStartOfUnit(localBegin, unitSize); unitEnd = unitBegin + unitSize; if (unitEnd >= localEnd) break; } // Add an entry for this unit. auto entryTy = llvm::IntegerType::get(CGM.getLLVMContext(), CGM.getContext().toBits(unitSize)); Entries.push_back({unitBegin, unitEnd, entryTy}); // The next chunk starts where this chunk left off. begin = localEnd; } while (begin != end); } // Okay, finally finished. Finished = true; } void SwiftAggLowering::enumerateComponents(EnumerationCallback callback) const { assert(Finished && "haven't yet finished lowering"); for (auto &entry : Entries) { callback(entry.Begin, entry.End, entry.Type); } } std::pair SwiftAggLowering::getCoerceAndExpandTypes() const { assert(Finished && "haven't yet finished lowering"); auto &ctx = CGM.getLLVMContext(); if (Entries.empty()) { auto type = llvm::StructType::get(ctx); return { type, type }; } SmallVector elts; CharUnits lastEnd = CharUnits::Zero(); bool hasPadding = false; bool packed = false; for (auto &entry : Entries) { if (entry.Begin != lastEnd) { auto paddingSize = entry.Begin - lastEnd; assert(!paddingSize.isNegative()); auto padding = llvm::ArrayType::get(llvm::Type::getInt8Ty(ctx), paddingSize.getQuantity()); elts.push_back(padding); hasPadding = true; } if (!packed && !entry.Begin.isMultipleOf(CharUnits::fromQuantity( CGM.getDataLayout().getABITypeAlign(entry.Type)))) packed = true; elts.push_back(entry.Type); lastEnd = entry.Begin + getTypeAllocSize(CGM, entry.Type); assert(entry.End <= lastEnd); } // We don't need to adjust 'packed' to deal with possible tail padding // because we never do that kind of access through the coercion type. auto coercionType = llvm::StructType::get(ctx, elts, packed); llvm::Type *unpaddedType = coercionType; if (hasPadding) { elts.clear(); for (auto &entry : Entries) { elts.push_back(entry.Type); } if (elts.size() == 1) { unpaddedType = elts[0]; } else { unpaddedType = llvm::StructType::get(ctx, elts, /*packed*/ false); } } else if (Entries.size() == 1) { unpaddedType = Entries[0].Type; } return { coercionType, unpaddedType }; } bool SwiftAggLowering::shouldPassIndirectly(bool asReturnValue) const { assert(Finished && "haven't yet finished lowering"); // Empty types don't need to be passed indirectly. if (Entries.empty()) return false; // Avoid copying the array of types when there's just a single element. if (Entries.size() == 1) { return getSwiftABIInfo(CGM).shouldPassIndirectly(Entries.back().Type, asReturnValue); } SmallVector componentTys; componentTys.reserve(Entries.size()); for (auto &entry : Entries) { componentTys.push_back(entry.Type); } return getSwiftABIInfo(CGM).shouldPassIndirectly(componentTys, asReturnValue); } bool swiftcall::shouldPassIndirectly(CodeGenModule &CGM, ArrayRef componentTys, bool asReturnValue) { return getSwiftABIInfo(CGM).shouldPassIndirectly(componentTys, asReturnValue); } CharUnits swiftcall::getMaximumVoluntaryIntegerSize(CodeGenModule &CGM) { // Currently always the size of an ordinary pointer. return CGM.getContext().toCharUnitsFromBits( CGM.getContext().getTargetInfo().getPointerWidth(LangAS::Default)); } CharUnits swiftcall::getNaturalAlignment(CodeGenModule &CGM, llvm::Type *type) { // For Swift's purposes, this is always just the store size of the type // rounded up to a power of 2. auto size = (unsigned long long) getTypeStoreSize(CGM, type).getQuantity(); size = llvm::bit_ceil(size); assert(CGM.getDataLayout().getABITypeAlign(type) <= size); return CharUnits::fromQuantity(size); } bool swiftcall::isLegalIntegerType(CodeGenModule &CGM, llvm::IntegerType *intTy) { auto size = intTy->getBitWidth(); switch (size) { case 1: case 8: case 16: case 32: case 64: // Just assume that the above are always legal. return true; case 128: return CGM.getContext().getTargetInfo().hasInt128Type(); default: return false; } } bool swiftcall::isLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize, llvm::VectorType *vectorTy) { return isLegalVectorType( CGM, vectorSize, vectorTy->getElementType(), cast(vectorTy)->getNumElements()); } bool swiftcall::isLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize, llvm::Type *eltTy, unsigned numElts) { assert(numElts > 1 && "illegal vector length"); return getSwiftABIInfo(CGM).isLegalVectorType(vectorSize, eltTy, numElts); } std::pair swiftcall::splitLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize, llvm::VectorType *vectorTy) { auto numElts = cast(vectorTy)->getNumElements(); auto eltTy = vectorTy->getElementType(); // Try to split the vector type in half. if (numElts >= 4 && isPowerOf2(numElts)) { if (isLegalVectorType(CGM, vectorSize / 2, eltTy, numElts / 2)) return {llvm::FixedVectorType::get(eltTy, numElts / 2), 2}; } return {eltTy, numElts}; } void swiftcall::legalizeVectorType(CodeGenModule &CGM, CharUnits origVectorSize, llvm::VectorType *origVectorTy, llvm::SmallVectorImpl &components) { // If it's already a legal vector type, use it. if (isLegalVectorType(CGM, origVectorSize, origVectorTy)) { components.push_back(origVectorTy); return; } // Try to split the vector into legal subvectors. auto numElts = cast(origVectorTy)->getNumElements(); auto eltTy = origVectorTy->getElementType(); assert(numElts != 1); // The largest size that we're still considering making subvectors of. // Always a power of 2. unsigned logCandidateNumElts = llvm::Log2_32(numElts); unsigned candidateNumElts = 1U << logCandidateNumElts; assert(candidateNumElts <= numElts && candidateNumElts * 2 > numElts); // Minor optimization: don't check the legality of this exact size twice. if (candidateNumElts == numElts) { logCandidateNumElts--; candidateNumElts >>= 1; } CharUnits eltSize = (origVectorSize / numElts); CharUnits candidateSize = eltSize * candidateNumElts; // The sensibility of this algorithm relies on the fact that we never // have a legal non-power-of-2 vector size without having the power of 2 // also be legal. while (logCandidateNumElts > 0) { assert(candidateNumElts == 1U << logCandidateNumElts); assert(candidateNumElts <= numElts); assert(candidateSize == eltSize * candidateNumElts); // Skip illegal vector sizes. if (!isLegalVectorType(CGM, candidateSize, eltTy, candidateNumElts)) { logCandidateNumElts--; candidateNumElts /= 2; candidateSize /= 2; continue; } // Add the right number of vectors of this size. auto numVecs = numElts >> logCandidateNumElts; components.append(numVecs, llvm::FixedVectorType::get(eltTy, candidateNumElts)); numElts -= (numVecs << logCandidateNumElts); if (numElts == 0) return; // It's possible that the number of elements remaining will be legal. // This can happen with e.g. <7 x float> when <3 x float> is legal. // This only needs to be separately checked if it's not a power of 2. if (numElts > 2 && !isPowerOf2(numElts) && isLegalVectorType(CGM, eltSize * numElts, eltTy, numElts)) { components.push_back(llvm::FixedVectorType::get(eltTy, numElts)); return; } // Bring vecSize down to something no larger than numElts. do { logCandidateNumElts--; candidateNumElts /= 2; candidateSize /= 2; } while (candidateNumElts > numElts); } // Otherwise, just append a bunch of individual elements. components.append(numElts, eltTy); } bool swiftcall::mustPassRecordIndirectly(CodeGenModule &CGM, const RecordDecl *record) { // FIXME: should we not rely on the standard computation in Sema, just in // case we want to diverge from the platform ABI (e.g. on targets where // that uses the MSVC rule)? return !record->canPassInRegisters(); } static ABIArgInfo classifyExpandedType(SwiftAggLowering &lowering, bool forReturn, CharUnits alignmentForIndirect) { if (lowering.empty()) { return ABIArgInfo::getIgnore(); } else if (lowering.shouldPassIndirectly(forReturn)) { return ABIArgInfo::getIndirect(alignmentForIndirect, /*byval*/ false); } else { auto types = lowering.getCoerceAndExpandTypes(); return ABIArgInfo::getCoerceAndExpand(types.first, types.second); } } static ABIArgInfo classifyType(CodeGenModule &CGM, CanQualType type, bool forReturn) { if (auto recordType = dyn_cast(type)) { auto record = recordType->getDecl(); auto &layout = CGM.getContext().getASTRecordLayout(record); if (mustPassRecordIndirectly(CGM, record)) return ABIArgInfo::getIndirect(layout.getAlignment(), /*byval*/ false); SwiftAggLowering lowering(CGM); lowering.addTypedData(recordType->getDecl(), CharUnits::Zero(), layout); lowering.finish(); return classifyExpandedType(lowering, forReturn, layout.getAlignment()); } // Just assume that all of our target ABIs can support returning at least // two integer or floating-point values. if (isa(type)) { return (forReturn ? ABIArgInfo::getDirect() : ABIArgInfo::getExpand()); } // Vector types may need to be legalized. if (isa(type)) { SwiftAggLowering lowering(CGM); lowering.addTypedData(type, CharUnits::Zero()); lowering.finish(); CharUnits alignment = CGM.getContext().getTypeAlignInChars(type); return classifyExpandedType(lowering, forReturn, alignment); } // Member pointer types need to be expanded, but it's a simple form of // expansion that 'Direct' can handle. Note that CanBeFlattened should be // true for this to work. // 'void' needs to be ignored. if (type->isVoidType()) { return ABIArgInfo::getIgnore(); } // Everything else can be passed directly. return ABIArgInfo::getDirect(); } ABIArgInfo swiftcall::classifyReturnType(CodeGenModule &CGM, CanQualType type) { return classifyType(CGM, type, /*forReturn*/ true); } ABIArgInfo swiftcall::classifyArgumentType(CodeGenModule &CGM, CanQualType type) { return classifyType(CGM, type, /*forReturn*/ false); } void swiftcall::computeABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) { auto &retInfo = FI.getReturnInfo(); retInfo = classifyReturnType(CGM, FI.getReturnType()); for (unsigned i = 0, e = FI.arg_size(); i != e; ++i) { auto &argInfo = FI.arg_begin()[i]; argInfo.info = classifyArgumentType(CGM, argInfo.type); } } // Is swifterror lowered to a register by the target ABI. bool swiftcall::isSwiftErrorLoweredInRegister(CodeGenModule &CGM) { return getSwiftABIInfo(CGM).isSwiftErrorInRegister(); }