175 lines
6.2 KiB
C++
175 lines
6.2 KiB
C++
//===- CSKY.cpp -----------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "ABIInfoImpl.h"
|
|
#include "TargetInfo.h"
|
|
|
|
using namespace clang;
|
|
using namespace clang::CodeGen;
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// CSKY ABI Implementation
|
|
//===----------------------------------------------------------------------===//
|
|
namespace {
|
|
class CSKYABIInfo : public DefaultABIInfo {
|
|
static const int NumArgGPRs = 4;
|
|
static const int NumArgFPRs = 4;
|
|
|
|
static const unsigned XLen = 32;
|
|
unsigned FLen;
|
|
|
|
public:
|
|
CSKYABIInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
|
|
: DefaultABIInfo(CGT), FLen(FLen) {}
|
|
|
|
void computeInfo(CGFunctionInfo &FI) const override;
|
|
ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
|
|
int &ArgFPRsLeft,
|
|
bool isReturnType = false) const;
|
|
ABIArgInfo classifyReturnType(QualType RetTy) const;
|
|
|
|
Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|
QualType Ty) const override;
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
void CSKYABIInfo::computeInfo(CGFunctionInfo &FI) const {
|
|
QualType RetTy = FI.getReturnType();
|
|
if (!getCXXABI().classifyReturnType(FI))
|
|
FI.getReturnInfo() = classifyReturnType(RetTy);
|
|
|
|
bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
|
|
|
|
// We must track the number of GPRs used in order to conform to the CSKY
|
|
// ABI, as integer scalars passed in registers should have signext/zeroext
|
|
// when promoted.
|
|
int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
|
|
int ArgFPRsLeft = FLen ? NumArgFPRs : 0;
|
|
|
|
for (auto &ArgInfo : FI.arguments()) {
|
|
ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft, ArgFPRsLeft);
|
|
}
|
|
}
|
|
|
|
Address CSKYABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
|
|
QualType Ty) const {
|
|
CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8);
|
|
|
|
// Empty records are ignored for parameter passing purposes.
|
|
if (isEmptyRecord(getContext(), Ty, true)) {
|
|
return Address(CGF.Builder.CreateLoad(VAListAddr),
|
|
CGF.ConvertTypeForMem(Ty), SlotSize);
|
|
}
|
|
|
|
auto TInfo = getContext().getTypeInfoInChars(Ty);
|
|
|
|
return emitVoidPtrVAArg(CGF, VAListAddr, Ty, false, TInfo, SlotSize,
|
|
/*AllowHigherAlign=*/true);
|
|
}
|
|
|
|
ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
|
|
int &ArgFPRsLeft,
|
|
bool isReturnType) const {
|
|
assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
|
|
Ty = useFirstFieldIfTransparentUnion(Ty);
|
|
|
|
// Structures with either a non-trivial destructor or a non-trivial
|
|
// copy constructor are always passed indirectly.
|
|
if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
|
|
if (ArgGPRsLeft)
|
|
ArgGPRsLeft -= 1;
|
|
return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
|
|
CGCXXABI::RAA_DirectInMemory);
|
|
}
|
|
|
|
// Ignore empty structs/unions.
|
|
if (isEmptyRecord(getContext(), Ty, true))
|
|
return ABIArgInfo::getIgnore();
|
|
|
|
if (!Ty->getAsUnionType())
|
|
if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
|
|
return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
|
|
|
|
uint64_t Size = getContext().getTypeSize(Ty);
|
|
// Pass floating point values via FPRs if possible.
|
|
if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size &&
|
|
ArgFPRsLeft) {
|
|
ArgFPRsLeft--;
|
|
return ABIArgInfo::getDirect();
|
|
}
|
|
|
|
// Complex types for the hard float ABI must be passed direct rather than
|
|
// using CoerceAndExpand.
|
|
if (Ty->isComplexType() && FLen && !isReturnType) {
|
|
QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
|
|
if (getContext().getTypeSize(EltTy) <= FLen) {
|
|
ArgFPRsLeft -= 2;
|
|
return ABIArgInfo::getDirect();
|
|
}
|
|
}
|
|
|
|
if (!isAggregateTypeForABI(Ty)) {
|
|
// Treat an enum type as its underlying type.
|
|
if (const EnumType *EnumTy = Ty->getAs<EnumType>())
|
|
Ty = EnumTy->getDecl()->getIntegerType();
|
|
|
|
// All integral types are promoted to XLen width, unless passed on the
|
|
// stack.
|
|
if (Size < XLen && Ty->isIntegralOrEnumerationType())
|
|
return ABIArgInfo::getExtend(Ty);
|
|
|
|
if (const auto *EIT = Ty->getAs<BitIntType>()) {
|
|
if (EIT->getNumBits() < XLen)
|
|
return ABIArgInfo::getExtend(Ty);
|
|
}
|
|
|
|
return ABIArgInfo::getDirect();
|
|
}
|
|
|
|
// For argument type, the first 4*XLen parts of aggregate will be passed
|
|
// in registers, and the rest will be passed in stack.
|
|
// So we can coerce to integers directly and let backend handle it correctly.
|
|
// For return type, aggregate which <= 2*XLen will be returned in registers.
|
|
// Otherwise, aggregate will be returned indirectly.
|
|
if (!isReturnType || (isReturnType && Size <= 2 * XLen)) {
|
|
if (Size <= XLen) {
|
|
return ABIArgInfo::getDirect(
|
|
llvm::IntegerType::get(getVMContext(), XLen));
|
|
} else {
|
|
return ABIArgInfo::getDirect(llvm::ArrayType::get(
|
|
llvm::IntegerType::get(getVMContext(), XLen), (Size + 31) / XLen));
|
|
}
|
|
}
|
|
return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
|
|
}
|
|
|
|
ABIArgInfo CSKYABIInfo::classifyReturnType(QualType RetTy) const {
|
|
if (RetTy->isVoidType())
|
|
return ABIArgInfo::getIgnore();
|
|
|
|
int ArgGPRsLeft = 2;
|
|
int ArgFPRsLeft = FLen ? 1 : 0;
|
|
|
|
// The rules for return and argument types are the same, so defer to
|
|
// classifyArgumentType.
|
|
return classifyArgumentType(RetTy, ArgGPRsLeft, ArgFPRsLeft, true);
|
|
}
|
|
|
|
namespace {
|
|
class CSKYTargetCodeGenInfo : public TargetCodeGenInfo {
|
|
public:
|
|
CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
|
|
: TargetCodeGenInfo(std::make_unique<CSKYABIInfo>(CGT, FLen)) {}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
std::unique_ptr<TargetCodeGenInfo>
|
|
CodeGen::createCSKYTargetCodeGenInfo(CodeGenModule &CGM, unsigned FLen) {
|
|
return std::make_unique<CSKYTargetCodeGenInfo>(CGM.getTypes(), FLen);
|
|
}
|