//==-- SwiftCallingConv.h - Swift ABI lowering ------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Defines constants and types related to Swift ABI lowering. The same ABI
// lowering applies to both sync and async functions.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_CODEGEN_SWIFTCALLINGCONV_H
#define LLVM_CLANG_CODEGEN_SWIFTCALLINGCONV_H
#include "clang/AST/CanonicalType.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Type.h"
#include "llvm/Support/TrailingObjects.h"
#include <cassert>
namespace llvm {
class IntegerType;
class Type;
class StructType;
class VectorType;
}
namespace clang {
class FieldDecl;
class ASTRecordLayout;
namespace CodeGen {
class ABIArgInfo;
class CodeGenModule;
class CGFunctionInfo;
namespace swiftcall {
class SwiftAggLowering {
CodeGenModule &CGM;
struct StorageEntry {
CharUnits Begin;
CharUnits End;
llvm::Type *Type;
CharUnits getWidth() const {
return End - Begin;
}
};
SmallVector<StorageEntry, 4> Entries;
bool Finished = false;
public:
SwiftAggLowering(CodeGenModule &CGM) : CGM(CGM) {}
void addOpaqueData(CharUnits begin, CharUnits end) {
addEntry(nullptr, begin, end);
}
void addTypedData(QualType type, CharUnits begin);
void addTypedData(const RecordDecl *record, CharUnits begin);
void addTypedData(const RecordDecl *record, CharUnits begin,
const ASTRecordLayout &layout);
void addTypedData(llvm::Type *type, CharUnits begin);
void addTypedData(llvm::Type *type, CharUnits begin, CharUnits end);
void finish();
/// Does this lowering require passing any data?
bool empty() const {
assert(Finished && "didn't finish lowering before calling empty()");
return Entries.empty();
}
/// According to the target Swift ABI, should a value with this lowering
/// be passed indirectly?
///
/// Note that this decision is based purely on the data layout of the
/// value and does not consider whether the type is address-only,
/// must be passed indirectly to match a function abstraction pattern, or
/// anything else that is expected to be handled by high-level lowering.
///
/// \param asReturnValue - if true, answer whether it should be passed
/// indirectly as a return value; if false, answer whether it should be
/// passed indirectly as an argument
bool shouldPassIndirectly(bool asReturnValue) const;
using EnumerationCallback =
llvm::function_ref<void(CharUnits offset, CharUnits end, llvm::Type *type)>;
/// Enumerate the expanded components of this type.
///
/// The component types will always be legal vector, floating-point,
/// integer, or pointer types.
void enumerateComponents(EnumerationCallback callback) const;
/// Return the types for a coerce-and-expand operation.
///
/// The first type matches the memory layout of the data that's been
/// added to this structure, including explicit [N x i8] arrays for any
/// internal padding.
///
/// The second type removes any internal padding members and, if only
/// one element remains, is simply that element type.
std::pair<llvm::StructType*, llvm::Type*> getCoerceAndExpandTypes() const;
private:
void addBitFieldData(const FieldDecl *field, CharUnits begin,
uint64_t bitOffset);
void addLegalTypedData(llvm::Type *type, CharUnits begin, CharUnits end);
void addEntry(llvm::Type *type, CharUnits begin, CharUnits end);
void splitVectorEntry(unsigned index);
static bool shouldMergeEntries(const StorageEntry &first,
const StorageEntry &second,
CharUnits chunkSize);
};
/// Should an aggregate which expands to the given type sequence
/// be passed/returned indirectly under swiftcall?
bool shouldPassIndirectly(CodeGenModule &CGM,
ArrayRef<llvm::Type*> types,
bool asReturnValue);
/// Return the maximum voluntary integer size for the current target.
CharUnits getMaximumVoluntaryIntegerSize(CodeGenModule &CGM);
/// Return the Swift CC's notion of the natural alignment of a type.
CharUnits getNaturalAlignment(CodeGenModule &CGM, llvm::Type *type);
/// Is the given integer type "legal" for Swift's perspective on the
/// current platform?
bool isLegalIntegerType(CodeGenModule &CGM, llvm::IntegerType *type);
/// Is the given vector type "legal" for Swift's perspective on the
/// current platform?
bool isLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize,
llvm::VectorType *vectorTy);
bool isLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize,
llvm::Type *eltTy, unsigned numElts);
/// Minimally split a legal vector type.
std::pair<llvm::Type*, unsigned>
splitLegalVectorType(CodeGenModule &CGM, CharUnits vectorSize,
llvm::VectorType *vectorTy);
/// Turn a vector type in a sequence of legal component vector types.
///
/// The caller may assume that the sum of the data sizes of the resulting
/// types will equal the data size of the vector type.
void legalizeVectorType(CodeGenModule &CGM, CharUnits vectorSize,
llvm::VectorType *vectorTy,
llvm::SmallVectorImpl<llvm::Type*> &types);
/// Is the given record type required to be passed and returned indirectly
/// because of language restrictions?
///
/// This considers *only* mandatory indirectness due to language restrictions,
/// such as C++'s non-trivially-copyable types and Objective-C's __weak
/// references. A record for which this returns true may still be passed
/// indirectly for other reasons, such as being too large to fit in a
/// reasonable number of registers.
bool mustPassRecordIndirectly(CodeGenModule &CGM, const RecordDecl *record);
/// Classify the rules for how to return a particular type.
ABIArgInfo classifyReturnType(CodeGenModule &CGM, CanQualType type);
/// Classify the rules for how to pass a particular type.
ABIArgInfo classifyArgumentType(CodeGenModule &CGM, CanQualType type);
/// Compute the ABI information of a swiftcall function. This is a
/// private interface for Clang.
void computeABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI);
/// Is swifterror lowered to a register by the target ABI?
bool isSwiftErrorLoweredInRegister(CodeGenModule &CGM);
} // end namespace swiftcall
} // end namespace CodeGen
} // end namespace clang
#endif