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
12 using namespace clang;
13 using namespace clang::CodeGen;
14
15 //===----------------------------------------------------------------------===//
16 // CSKY ABI Implementation
17 //===----------------------------------------------------------------------===//
18 namespace {
19 class 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
26 public:
CSKYABIInfo(CodeGen::CodeGenTypes & CGT,unsigned FLen)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 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
37 AggValueSlot Slot) const override;
38 };
39
40 } // end anonymous namespace
41
computeInfo(CGFunctionInfo & FI) const42 void 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(ArgInfo.type, ArgGPRsLeft, ArgFPRsLeft);
57 }
58 }
59
EmitVAArg(CodeGenFunction & CGF,Address VAListAddr,QualType Ty,AggValueSlot Slot) const60 RValue CSKYABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
61 QualType Ty, AggValueSlot Slot) const {
62 CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8);
63
64 // Empty records are ignored for parameter passing purposes.
65 if (isEmptyRecord(getContext(), Ty, true))
66 return Slot.asRValue();
67
68 auto TInfo = getContext().getTypeInfoInChars(Ty);
69
70 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, false, TInfo, SlotSize,
71 /*AllowHigherAlign=*/true, Slot);
72 }
73
classifyArgumentType(QualType Ty,int & ArgGPRsLeft,int & ArgFPRsLeft,bool isReturnType) const74 ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
75 int &ArgFPRsLeft,
76 bool isReturnType) const {
77 assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
78 Ty = useFirstFieldIfTransparentUnion(Ty);
79
80 // Structures with either a non-trivial destructor or a non-trivial
81 // copy constructor are always passed indirectly.
82 if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
83 if (ArgGPRsLeft)
84 ArgGPRsLeft -= 1;
85 return getNaturalAlignIndirect(
86 Ty, /*AddrSpace=*/getDataLayout().getAllocaAddrSpace(),
87 /*ByVal=*/RAA == CGCXXABI::RAA_DirectInMemory);
88 }
89
90 // Ignore empty structs/unions.
91 if (isEmptyRecord(getContext(), Ty, true))
92 return ABIArgInfo::getIgnore();
93
94 if (!Ty->getAsUnionType())
95 if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
96 return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
97
98 uint64_t Size = getContext().getTypeSize(Ty);
99 // Pass floating point values via FPRs if possible.
100 if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size &&
101 ArgFPRsLeft) {
102 ArgFPRsLeft--;
103 return ABIArgInfo::getDirect();
104 }
105
106 // Complex types for the hard float ABI must be passed direct rather than
107 // using CoerceAndExpand.
108 if (Ty->isComplexType() && FLen && !isReturnType) {
109 QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
110 if (getContext().getTypeSize(EltTy) <= FLen) {
111 ArgFPRsLeft -= 2;
112 return ABIArgInfo::getDirect();
113 }
114 }
115
116 if (!isAggregateTypeForABI(Ty)) {
117 // Treat an enum type as its underlying type.
118 if (const EnumType *EnumTy = Ty->getAs<EnumType>())
119 Ty = EnumTy->getDecl()->getIntegerType();
120
121 // All integral types are promoted to XLen width, unless passed on the
122 // stack.
123 if (Size < XLen && Ty->isIntegralOrEnumerationType())
124 return ABIArgInfo::getExtend(Ty);
125
126 if (const auto *EIT = Ty->getAs<BitIntType>()) {
127 if (EIT->getNumBits() < XLen)
128 return ABIArgInfo::getExtend(Ty);
129 }
130
131 return ABIArgInfo::getDirect();
132 }
133
134 // For argument type, the first 4*XLen parts of aggregate will be passed
135 // in registers, and the rest will be passed in stack.
136 // So we can coerce to integers directly and let backend handle it correctly.
137 // For return type, aggregate which <= 2*XLen will be returned in registers.
138 // Otherwise, aggregate will be returned indirectly.
139 if (!isReturnType || (isReturnType && Size <= 2 * XLen)) {
140 if (Size <= XLen) {
141 return ABIArgInfo::getDirect(
142 llvm::IntegerType::get(getVMContext(), XLen));
143 } else {
144 return ABIArgInfo::getDirect(llvm::ArrayType::get(
145 llvm::IntegerType::get(getVMContext(), XLen), (Size + 31) / XLen));
146 }
147 }
148 return getNaturalAlignIndirect(Ty, getDataLayout().getAllocaAddrSpace(),
149 /*ByVal=*/false);
150 }
151
classifyReturnType(QualType RetTy) const152 ABIArgInfo 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(RetTy, ArgGPRsLeft, ArgFPRsLeft, true);
162 }
163
164 namespace {
165 class CSKYTargetCodeGenInfo : public TargetCodeGenInfo {
166 public:
CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes & CGT,unsigned FLen)167 CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
168 : TargetCodeGenInfo(std::make_unique<CSKYABIInfo>(CGT, FLen)) {}
169 };
170 } // end anonymous namespace
171
172 std::unique_ptr<TargetCodeGenInfo>
createCSKYTargetCodeGenInfo(CodeGenModule & CGM,unsigned FLen)173 CodeGen::createCSKYTargetCodeGenInfo(CodeGenModule &CGM, unsigned FLen) {
174 return std::make_unique<CSKYTargetCodeGenInfo>(CGM.getTypes(), FLen);
175 }
176