1992cb984SSergei Barannikov //===- CSKY.cpp -----------------------------------------------------------===//
2992cb984SSergei Barannikov //
3992cb984SSergei Barannikov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4992cb984SSergei Barannikov // See https://llvm.org/LICENSE.txt for license information.
5992cb984SSergei Barannikov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6992cb984SSergei Barannikov //
7992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
8992cb984SSergei Barannikov
9992cb984SSergei Barannikov #include "ABIInfoImpl.h"
10992cb984SSergei Barannikov #include "TargetInfo.h"
11992cb984SSergei Barannikov
12992cb984SSergei Barannikov using namespace clang;
13992cb984SSergei Barannikov using namespace clang::CodeGen;
14992cb984SSergei Barannikov
15992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
16992cb984SSergei Barannikov // CSKY ABI Implementation
17992cb984SSergei Barannikov //===----------------------------------------------------------------------===//
18992cb984SSergei Barannikov namespace {
19992cb984SSergei Barannikov class CSKYABIInfo : public DefaultABIInfo {
20992cb984SSergei Barannikov static const int NumArgGPRs = 4;
21992cb984SSergei Barannikov static const int NumArgFPRs = 4;
22992cb984SSergei Barannikov
23992cb984SSergei Barannikov static const unsigned XLen = 32;
24992cb984SSergei Barannikov unsigned FLen;
25992cb984SSergei Barannikov
26992cb984SSergei Barannikov public:
CSKYABIInfo(CodeGen::CodeGenTypes & CGT,unsigned FLen)27992cb984SSergei Barannikov CSKYABIInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
28992cb984SSergei Barannikov : DefaultABIInfo(CGT), FLen(FLen) {}
29992cb984SSergei Barannikov
30992cb984SSergei Barannikov void computeInfo(CGFunctionInfo &FI) const override;
31992cb984SSergei Barannikov ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
32992cb984SSergei Barannikov int &ArgFPRsLeft,
33992cb984SSergei Barannikov bool isReturnType = false) const;
34992cb984SSergei Barannikov ABIArgInfo classifyReturnType(QualType RetTy) const;
35992cb984SSergei Barannikov
36*6d973b45SMariya Podchishchaeva RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
37*6d973b45SMariya Podchishchaeva AggValueSlot Slot) const override;
38992cb984SSergei Barannikov };
39992cb984SSergei Barannikov
40992cb984SSergei Barannikov } // end anonymous namespace
41992cb984SSergei Barannikov
computeInfo(CGFunctionInfo & FI) const42992cb984SSergei Barannikov void CSKYABIInfo::computeInfo(CGFunctionInfo &FI) const {
43992cb984SSergei Barannikov QualType RetTy = FI.getReturnType();
44992cb984SSergei Barannikov if (!getCXXABI().classifyReturnType(FI))
45992cb984SSergei Barannikov FI.getReturnInfo() = classifyReturnType(RetTy);
46992cb984SSergei Barannikov
47992cb984SSergei Barannikov bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
48992cb984SSergei Barannikov
49992cb984SSergei Barannikov // We must track the number of GPRs used in order to conform to the CSKY
50992cb984SSergei Barannikov // ABI, as integer scalars passed in registers should have signext/zeroext
51992cb984SSergei Barannikov // when promoted.
52992cb984SSergei Barannikov int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
53992cb984SSergei Barannikov int ArgFPRsLeft = FLen ? NumArgFPRs : 0;
54992cb984SSergei Barannikov
55992cb984SSergei Barannikov for (auto &ArgInfo : FI.arguments()) {
56992cb984SSergei Barannikov ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft, ArgFPRsLeft);
57992cb984SSergei Barannikov }
58992cb984SSergei Barannikov }
59992cb984SSergei Barannikov
EmitVAArg(CodeGenFunction & CGF,Address VAListAddr,QualType Ty,AggValueSlot Slot) const60*6d973b45SMariya Podchishchaeva RValue CSKYABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
61*6d973b45SMariya Podchishchaeva QualType Ty, AggValueSlot Slot) const {
62992cb984SSergei Barannikov CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8);
63992cb984SSergei Barannikov
64992cb984SSergei Barannikov // Empty records are ignored for parameter passing purposes.
65*6d973b45SMariya Podchishchaeva if (isEmptyRecord(getContext(), Ty, true))
66*6d973b45SMariya Podchishchaeva return Slot.asRValue();
67992cb984SSergei Barannikov
68992cb984SSergei Barannikov auto TInfo = getContext().getTypeInfoInChars(Ty);
69992cb984SSergei Barannikov
70992cb984SSergei Barannikov return emitVoidPtrVAArg(CGF, VAListAddr, Ty, false, TInfo, SlotSize,
71*6d973b45SMariya Podchishchaeva /*AllowHigherAlign=*/true, Slot);
72992cb984SSergei Barannikov }
73992cb984SSergei Barannikov
classifyArgumentType(QualType Ty,int & ArgGPRsLeft,int & ArgFPRsLeft,bool isReturnType) const74992cb984SSergei Barannikov ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
75992cb984SSergei Barannikov int &ArgFPRsLeft,
76992cb984SSergei Barannikov bool isReturnType) const {
77992cb984SSergei Barannikov assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
78992cb984SSergei Barannikov Ty = useFirstFieldIfTransparentUnion(Ty);
79992cb984SSergei Barannikov
80992cb984SSergei Barannikov // Structures with either a non-trivial destructor or a non-trivial
81992cb984SSergei Barannikov // copy constructor are always passed indirectly.
82992cb984SSergei Barannikov if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
83992cb984SSergei Barannikov if (ArgGPRsLeft)
84992cb984SSergei Barannikov ArgGPRsLeft -= 1;
85992cb984SSergei Barannikov return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
86992cb984SSergei Barannikov CGCXXABI::RAA_DirectInMemory);
87992cb984SSergei Barannikov }
88992cb984SSergei Barannikov
89992cb984SSergei Barannikov // Ignore empty structs/unions.
90992cb984SSergei Barannikov if (isEmptyRecord(getContext(), Ty, true))
91992cb984SSergei Barannikov return ABIArgInfo::getIgnore();
92992cb984SSergei Barannikov
93992cb984SSergei Barannikov if (!Ty->getAsUnionType())
94992cb984SSergei Barannikov if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
95992cb984SSergei Barannikov return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
96992cb984SSergei Barannikov
97992cb984SSergei Barannikov uint64_t Size = getContext().getTypeSize(Ty);
98992cb984SSergei Barannikov // Pass floating point values via FPRs if possible.
99992cb984SSergei Barannikov if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size &&
100992cb984SSergei Barannikov ArgFPRsLeft) {
101992cb984SSergei Barannikov ArgFPRsLeft--;
102992cb984SSergei Barannikov return ABIArgInfo::getDirect();
103992cb984SSergei Barannikov }
104992cb984SSergei Barannikov
105992cb984SSergei Barannikov // Complex types for the hard float ABI must be passed direct rather than
106992cb984SSergei Barannikov // using CoerceAndExpand.
107992cb984SSergei Barannikov if (Ty->isComplexType() && FLen && !isReturnType) {
108992cb984SSergei Barannikov QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
109992cb984SSergei Barannikov if (getContext().getTypeSize(EltTy) <= FLen) {
110992cb984SSergei Barannikov ArgFPRsLeft -= 2;
111992cb984SSergei Barannikov return ABIArgInfo::getDirect();
112992cb984SSergei Barannikov }
113992cb984SSergei Barannikov }
114992cb984SSergei Barannikov
115992cb984SSergei Barannikov if (!isAggregateTypeForABI(Ty)) {
116992cb984SSergei Barannikov // Treat an enum type as its underlying type.
117992cb984SSergei Barannikov if (const EnumType *EnumTy = Ty->getAs<EnumType>())
118992cb984SSergei Barannikov Ty = EnumTy->getDecl()->getIntegerType();
119992cb984SSergei Barannikov
120992cb984SSergei Barannikov // All integral types are promoted to XLen width, unless passed on the
121992cb984SSergei Barannikov // stack.
122992cb984SSergei Barannikov if (Size < XLen && Ty->isIntegralOrEnumerationType())
123992cb984SSergei Barannikov return ABIArgInfo::getExtend(Ty);
124992cb984SSergei Barannikov
125992cb984SSergei Barannikov if (const auto *EIT = Ty->getAs<BitIntType>()) {
126992cb984SSergei Barannikov if (EIT->getNumBits() < XLen)
127992cb984SSergei Barannikov return ABIArgInfo::getExtend(Ty);
128992cb984SSergei Barannikov }
129992cb984SSergei Barannikov
130992cb984SSergei Barannikov return ABIArgInfo::getDirect();
131992cb984SSergei Barannikov }
132992cb984SSergei Barannikov
133992cb984SSergei Barannikov // For argument type, the first 4*XLen parts of aggregate will be passed
134992cb984SSergei Barannikov // in registers, and the rest will be passed in stack.
135992cb984SSergei Barannikov // So we can coerce to integers directly and let backend handle it correctly.
136992cb984SSergei Barannikov // For return type, aggregate which <= 2*XLen will be returned in registers.
137992cb984SSergei Barannikov // Otherwise, aggregate will be returned indirectly.
138992cb984SSergei Barannikov if (!isReturnType || (isReturnType && Size <= 2 * XLen)) {
139992cb984SSergei Barannikov if (Size <= XLen) {
140992cb984SSergei Barannikov return ABIArgInfo::getDirect(
141992cb984SSergei Barannikov llvm::IntegerType::get(getVMContext(), XLen));
142992cb984SSergei Barannikov } else {
143992cb984SSergei Barannikov return ABIArgInfo::getDirect(llvm::ArrayType::get(
144992cb984SSergei Barannikov llvm::IntegerType::get(getVMContext(), XLen), (Size + 31) / XLen));
145992cb984SSergei Barannikov }
146992cb984SSergei Barannikov }
147992cb984SSergei Barannikov return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
148992cb984SSergei Barannikov }
149992cb984SSergei Barannikov
classifyReturnType(QualType RetTy) const150992cb984SSergei Barannikov ABIArgInfo CSKYABIInfo::classifyReturnType(QualType RetTy) const {
151992cb984SSergei Barannikov if (RetTy->isVoidType())
152992cb984SSergei Barannikov return ABIArgInfo::getIgnore();
153992cb984SSergei Barannikov
154992cb984SSergei Barannikov int ArgGPRsLeft = 2;
155992cb984SSergei Barannikov int ArgFPRsLeft = FLen ? 1 : 0;
156992cb984SSergei Barannikov
157992cb984SSergei Barannikov // The rules for return and argument types are the same, so defer to
158992cb984SSergei Barannikov // classifyArgumentType.
159992cb984SSergei Barannikov return classifyArgumentType(RetTy, ArgGPRsLeft, ArgFPRsLeft, true);
160992cb984SSergei Barannikov }
161992cb984SSergei Barannikov
162992cb984SSergei Barannikov namespace {
163992cb984SSergei Barannikov class CSKYTargetCodeGenInfo : public TargetCodeGenInfo {
164992cb984SSergei Barannikov public:
CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes & CGT,unsigned FLen)165992cb984SSergei Barannikov CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
166992cb984SSergei Barannikov : TargetCodeGenInfo(std::make_unique<CSKYABIInfo>(CGT, FLen)) {}
167992cb984SSergei Barannikov };
168992cb984SSergei Barannikov } // end anonymous namespace
169992cb984SSergei Barannikov
170992cb984SSergei Barannikov std::unique_ptr<TargetCodeGenInfo>
createCSKYTargetCodeGenInfo(CodeGenModule & CGM,unsigned FLen)171992cb984SSergei Barannikov CodeGen::createCSKYTargetCodeGenInfo(CodeGenModule &CGM, unsigned FLen) {
172992cb984SSergei Barannikov return std::make_unique<CSKYTargetCodeGenInfo>(CGM.getTypes(), FLen);
173992cb984SSergei Barannikov }
174