1//===- CSKY.cpp -----------------------------------------------------------===//
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 "ABIInfoImpl.h"
10#include "TargetInfo.h"
11
12using namespace clang;
13using namespace clang::CodeGen;
14
15//===----------------------------------------------------------------------===//
16// CSKY ABI Implementation
17//===----------------------------------------------------------------------===//
18namespace {
19class CSKYABIInfo : public DefaultABIInfo {
20 static const int NumArgGPRs = 4;
21 static const int NumArgFPRs = 4;
22
23 static const unsigned XLen = 32;
24 unsigned FLen;
25
26public:
27 CSKYABIInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
28 : DefaultABIInfo(CGT), FLen(FLen) {}
29
30 void computeInfo(CGFunctionInfo &FI) const override;
31 ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
32 int &ArgFPRsLeft,
33 bool isReturnType = false) const;
34 ABIArgInfo classifyReturnType(QualType RetTy) const;
35
36 Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
37 QualType Ty) const override;
38};
39
40} // end anonymous namespace
41
42void CSKYABIInfo::computeInfo(CGFunctionInfo &FI) const {
43 QualType RetTy = FI.getReturnType();
44 if (!getCXXABI().classifyReturnType(FI))
45 FI.getReturnInfo() = classifyReturnType(RetTy);
46
47 bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
48
49 // We must track the number of GPRs used in order to conform to the CSKY
50 // ABI, as integer scalars passed in registers should have signext/zeroext
51 // when promoted.
52 int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
53 int ArgFPRsLeft = FLen ? NumArgFPRs : 0;
54
55 for (auto &ArgInfo : FI.arguments()) {
56 ArgInfo.info = classifyArgumentType(Ty: ArgInfo.type, ArgGPRsLeft, ArgFPRsLeft);
57 }
58}
59
60Address CSKYABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
61 QualType Ty) const {
62 CharUnits SlotSize = CharUnits::fromQuantity(Quantity: XLen / 8);
63
64 // Empty records are ignored for parameter passing purposes.
65 if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true)) {
66 return Address(CGF.Builder.CreateLoad(Addr: VAListAddr),
67 CGF.ConvertTypeForMem(T: Ty), SlotSize);
68 }
69
70 auto TInfo = getContext().getTypeInfoInChars(T: Ty);
71
72 return emitVoidPtrVAArg(CGF, VAListAddr, ValueTy: Ty, IsIndirect: false, ValueInfo: TInfo, SlotSizeAndAlign: SlotSize,
73 /*AllowHigherAlign=*/true);
74}
75
76ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
77 int &ArgFPRsLeft,
78 bool isReturnType) const {
79 assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
80 Ty = useFirstFieldIfTransparentUnion(Ty);
81
82 // Structures with either a non-trivial destructor or a non-trivial
83 // copy constructor are always passed indirectly.
84 if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(T: Ty, CXXABI&: getCXXABI())) {
85 if (ArgGPRsLeft)
86 ArgGPRsLeft -= 1;
87 return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
88 CGCXXABI::RAA_DirectInMemory);
89 }
90
91 // Ignore empty structs/unions.
92 if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true))
93 return ABIArgInfo::getIgnore();
94
95 if (!Ty->getAsUnionType())
96 if (const Type *SeltTy = isSingleElementStruct(T: Ty, Context&: getContext()))
97 return ABIArgInfo::getDirect(T: CGT.ConvertType(T: QualType(SeltTy, 0)));
98
99 uint64_t Size = getContext().getTypeSize(T: Ty);
100 // Pass floating point values via FPRs if possible.
101 if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size &&
102 ArgFPRsLeft) {
103 ArgFPRsLeft--;
104 return ABIArgInfo::getDirect();
105 }
106
107 // Complex types for the hard float ABI must be passed direct rather than
108 // using CoerceAndExpand.
109 if (Ty->isComplexType() && FLen && !isReturnType) {
110 QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
111 if (getContext().getTypeSize(T: EltTy) <= FLen) {
112 ArgFPRsLeft -= 2;
113 return ABIArgInfo::getDirect();
114 }
115 }
116
117 if (!isAggregateTypeForABI(T: Ty)) {
118 // Treat an enum type as its underlying type.
119 if (const EnumType *EnumTy = Ty->getAs<EnumType>())
120 Ty = EnumTy->getDecl()->getIntegerType();
121
122 // All integral types are promoted to XLen width, unless passed on the
123 // stack.
124 if (Size < XLen && Ty->isIntegralOrEnumerationType())
125 return ABIArgInfo::getExtend(Ty);
126
127 if (const auto *EIT = Ty->getAs<BitIntType>()) {
128 if (EIT->getNumBits() < XLen)
129 return ABIArgInfo::getExtend(Ty);
130 }
131
132 return ABIArgInfo::getDirect();
133 }
134
135 // For argument type, the first 4*XLen parts of aggregate will be passed
136 // in registers, and the rest will be passed in stack.
137 // So we can coerce to integers directly and let backend handle it correctly.
138 // For return type, aggregate which <= 2*XLen will be returned in registers.
139 // Otherwise, aggregate will be returned indirectly.
140 if (!isReturnType || (isReturnType && Size <= 2 * XLen)) {
141 if (Size <= XLen) {
142 return ABIArgInfo::getDirect(
143 T: llvm::IntegerType::get(C&: getVMContext(), NumBits: XLen));
144 } else {
145 return ABIArgInfo::getDirect(T: llvm::ArrayType::get(
146 ElementType: llvm::IntegerType::get(C&: getVMContext(), NumBits: XLen), NumElements: (Size + 31) / XLen));
147 }
148 }
149 return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
150}
151
152ABIArgInfo CSKYABIInfo::classifyReturnType(QualType RetTy) const {
153 if (RetTy->isVoidType())
154 return ABIArgInfo::getIgnore();
155
156 int ArgGPRsLeft = 2;
157 int ArgFPRsLeft = FLen ? 1 : 0;
158
159 // The rules for return and argument types are the same, so defer to
160 // classifyArgumentType.
161 return classifyArgumentType(Ty: RetTy, ArgGPRsLeft, ArgFPRsLeft, isReturnType: true);
162}
163
164namespace {
165class CSKYTargetCodeGenInfo : public TargetCodeGenInfo {
166public:
167 CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
168 : TargetCodeGenInfo(std::make_unique<CSKYABIInfo>(args&: CGT, args&: FLen)) {}
169};
170} // end anonymous namespace
171
172std::unique_ptr<TargetCodeGenInfo>
173CodeGen::createCSKYTargetCodeGenInfo(CodeGenModule &CGM, unsigned FLen) {
174 return std::make_unique<CSKYTargetCodeGenInfo>(args&: CGM.getTypes(), args&: FLen);
175}
176

source code of clang/lib/CodeGen/Targets/CSKY.cpp