/src/llvm-project/clang/lib/CodeGen/Targets/CSKY.cpp
Line | Count | Source (jump to first uncovered line) |
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: |
27 | | CSKYABIInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen) |
28 | 0 | : 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 | | |
42 | 0 | void CSKYABIInfo::computeInfo(CGFunctionInfo &FI) const { |
43 | 0 | QualType RetTy = FI.getReturnType(); |
44 | 0 | if (!getCXXABI().classifyReturnType(FI)) |
45 | 0 | FI.getReturnInfo() = classifyReturnType(RetTy); |
46 | |
|
47 | 0 | 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 | 0 | int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs; |
53 | 0 | int ArgFPRsLeft = FLen ? NumArgFPRs : 0; |
54 | |
|
55 | 0 | for (auto &ArgInfo : FI.arguments()) { |
56 | 0 | ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft, ArgFPRsLeft); |
57 | 0 | } |
58 | 0 | } |
59 | | |
60 | | Address CSKYABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, |
61 | 0 | QualType Ty) const { |
62 | 0 | CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8); |
63 | | |
64 | | // Empty records are ignored for parameter passing purposes. |
65 | 0 | if (isEmptyRecord(getContext(), Ty, true)) { |
66 | 0 | return Address(CGF.Builder.CreateLoad(VAListAddr), |
67 | 0 | CGF.ConvertTypeForMem(Ty), SlotSize); |
68 | 0 | } |
69 | | |
70 | 0 | auto TInfo = getContext().getTypeInfoInChars(Ty); |
71 | |
|
72 | 0 | return emitVoidPtrVAArg(CGF, VAListAddr, Ty, false, TInfo, SlotSize, |
73 | 0 | /*AllowHigherAlign=*/true); |
74 | 0 | } |
75 | | |
76 | | ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft, |
77 | | int &ArgFPRsLeft, |
78 | 0 | bool isReturnType) const { |
79 | 0 | assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); |
80 | 0 | Ty = useFirstFieldIfTransparentUnion(Ty); |
81 | | |
82 | | // Structures with either a non-trivial destructor or a non-trivial |
83 | | // copy constructor are always passed indirectly. |
84 | 0 | if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { |
85 | 0 | if (ArgGPRsLeft) |
86 | 0 | ArgGPRsLeft -= 1; |
87 | 0 | return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == |
88 | 0 | CGCXXABI::RAA_DirectInMemory); |
89 | 0 | } |
90 | | |
91 | | // Ignore empty structs/unions. |
92 | 0 | if (isEmptyRecord(getContext(), Ty, true)) |
93 | 0 | return ABIArgInfo::getIgnore(); |
94 | | |
95 | 0 | if (!Ty->getAsUnionType()) |
96 | 0 | if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) |
97 | 0 | return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); |
98 | | |
99 | 0 | uint64_t Size = getContext().getTypeSize(Ty); |
100 | | // Pass floating point values via FPRs if possible. |
101 | 0 | if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size && |
102 | 0 | ArgFPRsLeft) { |
103 | 0 | ArgFPRsLeft--; |
104 | 0 | return ABIArgInfo::getDirect(); |
105 | 0 | } |
106 | | |
107 | | // Complex types for the hard float ABI must be passed direct rather than |
108 | | // using CoerceAndExpand. |
109 | 0 | if (Ty->isComplexType() && FLen && !isReturnType) { |
110 | 0 | QualType EltTy = Ty->castAs<ComplexType>()->getElementType(); |
111 | 0 | if (getContext().getTypeSize(EltTy) <= FLen) { |
112 | 0 | ArgFPRsLeft -= 2; |
113 | 0 | return ABIArgInfo::getDirect(); |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | 0 | if (!isAggregateTypeForABI(Ty)) { |
118 | | // Treat an enum type as its underlying type. |
119 | 0 | if (const EnumType *EnumTy = Ty->getAs<EnumType>()) |
120 | 0 | Ty = EnumTy->getDecl()->getIntegerType(); |
121 | | |
122 | | // All integral types are promoted to XLen width, unless passed on the |
123 | | // stack. |
124 | 0 | if (Size < XLen && Ty->isIntegralOrEnumerationType()) |
125 | 0 | return ABIArgInfo::getExtend(Ty); |
126 | | |
127 | 0 | if (const auto *EIT = Ty->getAs<BitIntType>()) { |
128 | 0 | if (EIT->getNumBits() < XLen) |
129 | 0 | return ABIArgInfo::getExtend(Ty); |
130 | 0 | } |
131 | | |
132 | 0 | return ABIArgInfo::getDirect(); |
133 | 0 | } |
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 | 0 | if (!isReturnType || (isReturnType && Size <= 2 * XLen)) { |
141 | 0 | if (Size <= XLen) { |
142 | 0 | return ABIArgInfo::getDirect( |
143 | 0 | llvm::IntegerType::get(getVMContext(), XLen)); |
144 | 0 | } else { |
145 | 0 | return ABIArgInfo::getDirect(llvm::ArrayType::get( |
146 | 0 | llvm::IntegerType::get(getVMContext(), XLen), (Size + 31) / XLen)); |
147 | 0 | } |
148 | 0 | } |
149 | 0 | return getNaturalAlignIndirect(Ty, /*ByVal=*/false); |
150 | 0 | } |
151 | | |
152 | 0 | ABIArgInfo CSKYABIInfo::classifyReturnType(QualType RetTy) const { |
153 | 0 | if (RetTy->isVoidType()) |
154 | 0 | return ABIArgInfo::getIgnore(); |
155 | | |
156 | 0 | int ArgGPRsLeft = 2; |
157 | 0 | int ArgFPRsLeft = FLen ? 1 : 0; |
158 | | |
159 | | // The rules for return and argument types are the same, so defer to |
160 | | // classifyArgumentType. |
161 | 0 | return classifyArgumentType(RetTy, ArgGPRsLeft, ArgFPRsLeft, true); |
162 | 0 | } |
163 | | |
164 | | namespace { |
165 | | class CSKYTargetCodeGenInfo : public TargetCodeGenInfo { |
166 | | public: |
167 | | CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen) |
168 | 0 | : TargetCodeGenInfo(std::make_unique<CSKYABIInfo>(CGT, FLen)) {} |
169 | | }; |
170 | | } // end anonymous namespace |
171 | | |
172 | | std::unique_ptr<TargetCodeGenInfo> |
173 | 0 | CodeGen::createCSKYTargetCodeGenInfo(CodeGenModule &CGM, unsigned FLen) { |
174 | 0 | return std::make_unique<CSKYTargetCodeGenInfo>(CGM.getTypes(), FLen); |
175 | 0 | } |