1//===- LoongArch.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// LoongArch ABI Implementation. Documented at
16// https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html
17//
18//===----------------------------------------------------------------------===//
19
20namespace {
21class LoongArchABIInfo : public DefaultABIInfo {
22private:
23 // Size of the integer ('r') registers in bits.
24 unsigned GRLen;
25 // Size of the floating point ('f') registers in bits.
26 unsigned FRLen;
27 // Number of general-purpose argument registers.
28 static const int NumGARs = 8;
29 // Number of floating-point argument registers.
30 static const int NumFARs = 8;
31 bool detectFARsEligibleStructHelper(QualType Ty, CharUnits CurOff,
32 llvm::Type *&Field1Ty,
33 CharUnits &Field1Off,
34 llvm::Type *&Field2Ty,
35 CharUnits &Field2Off) const;
36
37public:
38 LoongArchABIInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen, unsigned FRLen)
39 : DefaultABIInfo(CGT), GRLen(GRLen), FRLen(FRLen) {}
40
41 void computeInfo(CGFunctionInfo &FI) const override;
42
43 ABIArgInfo classifyArgumentType(QualType Ty, bool IsFixed, int &GARsLeft,
44 int &FARsLeft) const;
45 ABIArgInfo classifyReturnType(QualType RetTy) const;
46
47 Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
48 QualType Ty) const override;
49
50 ABIArgInfo extendType(QualType Ty) const;
51
52 bool detectFARsEligibleStruct(QualType Ty, llvm::Type *&Field1Ty,
53 CharUnits &Field1Off, llvm::Type *&Field2Ty,
54 CharUnits &Field2Off, int &NeededArgGPRs,
55 int &NeededArgFPRs) const;
56 ABIArgInfo coerceAndExpandFARsEligibleStruct(llvm::Type *Field1Ty,
57 CharUnits Field1Off,
58 llvm::Type *Field2Ty,
59 CharUnits Field2Off) const;
60};
61} // end anonymous namespace
62
63void LoongArchABIInfo::computeInfo(CGFunctionInfo &FI) const {
64 QualType RetTy = FI.getReturnType();
65 if (!getCXXABI().classifyReturnType(FI))
66 FI.getReturnInfo() = classifyReturnType(RetTy);
67
68 // IsRetIndirect is true if classifyArgumentType indicated the value should
69 // be passed indirect, or if the type size is a scalar greater than 2*GRLen
70 // and not a complex type with elements <= FRLen. e.g. fp128 is passed direct
71 // in LLVM IR, relying on the backend lowering code to rewrite the argument
72 // list and pass indirectly on LA32.
73 bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
74 if (!IsRetIndirect && RetTy->isScalarType() &&
75 getContext().getTypeSize(T: RetTy) > (2 * GRLen)) {
76 if (RetTy->isComplexType() && FRLen) {
77 QualType EltTy = RetTy->castAs<ComplexType>()->getElementType();
78 IsRetIndirect = getContext().getTypeSize(T: EltTy) > FRLen;
79 } else {
80 // This is a normal scalar > 2*GRLen, such as fp128 on LA32.
81 IsRetIndirect = true;
82 }
83 }
84
85 // We must track the number of GARs and FARs used in order to conform to the
86 // LoongArch ABI. As GAR usage is different for variadic arguments, we must
87 // also track whether we are examining a vararg or not.
88 int GARsLeft = IsRetIndirect ? NumGARs - 1 : NumGARs;
89 int FARsLeft = FRLen ? NumFARs : 0;
90 int NumFixedArgs = FI.getNumRequiredArgs();
91
92 int ArgNum = 0;
93 for (auto &ArgInfo : FI.arguments()) {
94 ArgInfo.info = classifyArgumentType(
95 Ty: ArgInfo.type, /*IsFixed=*/ArgNum < NumFixedArgs, GARsLeft, FARsLeft);
96 ArgNum++;
97 }
98}
99
100// Returns true if the struct is a potential candidate to be passed in FARs (and
101// GARs). If this function returns true, the caller is responsible for checking
102// that if there is only a single field then that field is a float.
103bool LoongArchABIInfo::detectFARsEligibleStructHelper(
104 QualType Ty, CharUnits CurOff, llvm::Type *&Field1Ty, CharUnits &Field1Off,
105 llvm::Type *&Field2Ty, CharUnits &Field2Off) const {
106 bool IsInt = Ty->isIntegralOrEnumerationType();
107 bool IsFloat = Ty->isRealFloatingType();
108
109 if (IsInt || IsFloat) {
110 uint64_t Size = getContext().getTypeSize(T: Ty);
111 if (IsInt && Size > GRLen)
112 return false;
113 // Can't be eligible if larger than the FP registers. Half precision isn't
114 // currently supported on LoongArch and the ABI hasn't been confirmed, so
115 // default to the integer ABI in that case.
116 if (IsFloat && (Size > FRLen || Size < 32))
117 return false;
118 // Can't be eligible if an integer type was already found (int+int pairs
119 // are not eligible).
120 if (IsInt && Field1Ty && Field1Ty->isIntegerTy())
121 return false;
122 if (!Field1Ty) {
123 Field1Ty = CGT.ConvertType(T: Ty);
124 Field1Off = CurOff;
125 return true;
126 }
127 if (!Field2Ty) {
128 Field2Ty = CGT.ConvertType(T: Ty);
129 Field2Off = CurOff;
130 return true;
131 }
132 return false;
133 }
134
135 if (auto CTy = Ty->getAs<ComplexType>()) {
136 if (Field1Ty)
137 return false;
138 QualType EltTy = CTy->getElementType();
139 if (getContext().getTypeSize(T: EltTy) > FRLen)
140 return false;
141 Field1Ty = CGT.ConvertType(T: EltTy);
142 Field1Off = CurOff;
143 Field2Ty = Field1Ty;
144 Field2Off = Field1Off + getContext().getTypeSizeInChars(T: EltTy);
145 return true;
146 }
147
148 if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(T: Ty)) {
149 uint64_t ArraySize = ATy->getZExtSize();
150 QualType EltTy = ATy->getElementType();
151 // Non-zero-length arrays of empty records make the struct ineligible to be
152 // passed via FARs in C++.
153 if (const auto *RTy = EltTy->getAs<RecordType>()) {
154 if (ArraySize != 0 && isa<CXXRecordDecl>(RTy->getDecl()) &&
155 isEmptyRecord(Context&: getContext(), T: EltTy, AllowArrays: true, AsIfNoUniqueAddr: true))
156 return false;
157 }
158 CharUnits EltSize = getContext().getTypeSizeInChars(T: EltTy);
159 for (uint64_t i = 0; i < ArraySize; ++i) {
160 if (!detectFARsEligibleStructHelper(Ty: EltTy, CurOff, Field1Ty, Field1Off,
161 Field2Ty, Field2Off))
162 return false;
163 CurOff += EltSize;
164 }
165 return true;
166 }
167
168 if (const auto *RTy = Ty->getAs<RecordType>()) {
169 // Structures with either a non-trivial destructor or a non-trivial
170 // copy constructor are not eligible for the FP calling convention.
171 if (getRecordArgABI(T: Ty, CXXABI&: CGT.getCXXABI()))
172 return false;
173 const RecordDecl *RD = RTy->getDecl();
174 if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true, AsIfNoUniqueAddr: true) &&
175 (!RD->isUnion() || !isa<CXXRecordDecl>(Val: RD)))
176 return true;
177 // Unions aren't eligible unless they're empty in C (which is caught above).
178 if (RD->isUnion())
179 return false;
180 const ASTRecordLayout &Layout = getContext().getASTRecordLayout(D: RD);
181 // If this is a C++ record, check the bases first.
182 if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(Val: RD)) {
183 for (const CXXBaseSpecifier &B : CXXRD->bases()) {
184 const auto *BDecl =
185 cast<CXXRecordDecl>(Val: B.getType()->castAs<RecordType>()->getDecl());
186 if (!detectFARsEligibleStructHelper(
187 Ty: B.getType(), CurOff: CurOff + Layout.getBaseClassOffset(Base: BDecl),
188 Field1Ty, Field1Off, Field2Ty, Field2Off))
189 return false;
190 }
191 }
192 for (const FieldDecl *FD : RD->fields()) {
193 QualType QTy = FD->getType();
194 if (FD->isBitField()) {
195 unsigned BitWidth = FD->getBitWidthValue(Ctx: getContext());
196 // Zero-width bitfields are ignored.
197 if (BitWidth == 0)
198 continue;
199 // Allow a bitfield with a type greater than GRLen as long as the
200 // bitwidth is GRLen or less.
201 if (getContext().getTypeSize(T: QTy) > GRLen && BitWidth <= GRLen) {
202 QTy = getContext().getIntTypeForBitwidth(DestWidth: GRLen, Signed: false);
203 }
204 }
205
206 if (!detectFARsEligibleStructHelper(
207 Ty: QTy,
208 CurOff: CurOff + getContext().toCharUnitsFromBits(
209 BitSize: Layout.getFieldOffset(FieldNo: FD->getFieldIndex())),
210 Field1Ty, Field1Off, Field2Ty, Field2Off))
211 return false;
212 }
213 return Field1Ty != nullptr;
214 }
215
216 return false;
217}
218
219// Determine if a struct is eligible to be passed in FARs (and GARs) (i.e., when
220// flattened it contains a single fp value, fp+fp, or int+fp of appropriate
221// size). If so, NeededFARs and NeededGARs are incremented appropriately.
222bool LoongArchABIInfo::detectFARsEligibleStruct(
223 QualType Ty, llvm::Type *&Field1Ty, CharUnits &Field1Off,
224 llvm::Type *&Field2Ty, CharUnits &Field2Off, int &NeededGARs,
225 int &NeededFARs) const {
226 Field1Ty = nullptr;
227 Field2Ty = nullptr;
228 NeededGARs = 0;
229 NeededFARs = 0;
230 if (!detectFARsEligibleStructHelper(Ty, CurOff: CharUnits::Zero(), Field1Ty,
231 Field1Off, Field2Ty, Field2Off))
232 return false;
233 if (!Field1Ty)
234 return false;
235 // Not really a candidate if we have a single int but no float.
236 if (Field1Ty && !Field2Ty && !Field1Ty->isFloatingPointTy())
237 return false;
238 if (Field1Ty && Field1Ty->isFloatingPointTy())
239 NeededFARs++;
240 else if (Field1Ty)
241 NeededGARs++;
242 if (Field2Ty && Field2Ty->isFloatingPointTy())
243 NeededFARs++;
244 else if (Field2Ty)
245 NeededGARs++;
246 return true;
247}
248
249// Call getCoerceAndExpand for the two-element flattened struct described by
250// Field1Ty, Field1Off, Field2Ty, Field2Off. This method will create an
251// appropriate coerceToType and unpaddedCoerceToType.
252ABIArgInfo LoongArchABIInfo::coerceAndExpandFARsEligibleStruct(
253 llvm::Type *Field1Ty, CharUnits Field1Off, llvm::Type *Field2Ty,
254 CharUnits Field2Off) const {
255 SmallVector<llvm::Type *, 3> CoerceElts;
256 SmallVector<llvm::Type *, 2> UnpaddedCoerceElts;
257 if (!Field1Off.isZero())
258 CoerceElts.push_back(Elt: llvm::ArrayType::get(
259 ElementType: llvm::Type::getInt8Ty(C&: getVMContext()), NumElements: Field1Off.getQuantity()));
260
261 CoerceElts.push_back(Elt: Field1Ty);
262 UnpaddedCoerceElts.push_back(Elt: Field1Ty);
263
264 if (!Field2Ty) {
265 return ABIArgInfo::getCoerceAndExpand(
266 coerceToType: llvm::StructType::get(Context&: getVMContext(), Elements: CoerceElts, isPacked: !Field1Off.isZero()),
267 unpaddedCoerceToType: UnpaddedCoerceElts[0]);
268 }
269
270 CharUnits Field2Align =
271 CharUnits::fromQuantity(Quantity: getDataLayout().getABITypeAlign(Ty: Field2Ty));
272 CharUnits Field1End =
273 Field1Off +
274 CharUnits::fromQuantity(Quantity: getDataLayout().getTypeStoreSize(Ty: Field1Ty));
275 CharUnits Field2OffNoPadNoPack = Field1End.alignTo(Align: Field2Align);
276
277 CharUnits Padding = CharUnits::Zero();
278 if (Field2Off > Field2OffNoPadNoPack)
279 Padding = Field2Off - Field2OffNoPadNoPack;
280 else if (Field2Off != Field2Align && Field2Off > Field1End)
281 Padding = Field2Off - Field1End;
282
283 bool IsPacked = !Field2Off.isMultipleOf(N: Field2Align);
284
285 if (!Padding.isZero())
286 CoerceElts.push_back(Elt: llvm::ArrayType::get(
287 ElementType: llvm::Type::getInt8Ty(C&: getVMContext()), NumElements: Padding.getQuantity()));
288
289 CoerceElts.push_back(Elt: Field2Ty);
290 UnpaddedCoerceElts.push_back(Elt: Field2Ty);
291
292 return ABIArgInfo::getCoerceAndExpand(
293 coerceToType: llvm::StructType::get(Context&: getVMContext(), Elements: CoerceElts, isPacked: IsPacked),
294 unpaddedCoerceToType: llvm::StructType::get(Context&: getVMContext(), Elements: UnpaddedCoerceElts, isPacked: IsPacked));
295}
296
297ABIArgInfo LoongArchABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
298 int &GARsLeft,
299 int &FARsLeft) const {
300 assert(GARsLeft <= NumGARs && "GAR tracking underflow");
301 Ty = useFirstFieldIfTransparentUnion(Ty);
302
303 // Structures with either a non-trivial destructor or a non-trivial
304 // copy constructor are always passed indirectly.
305 if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(T: Ty, CXXABI&: getCXXABI())) {
306 if (GARsLeft)
307 GARsLeft -= 1;
308 return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
309 CGCXXABI::RAA_DirectInMemory);
310 }
311
312 uint64_t Size = getContext().getTypeSize(T: Ty);
313
314 // Ignore empty struct or union whose size is zero, e.g. `struct { }` in C or
315 // `struct { int a[0]; }` in C++. In C++, `struct { }` is empty but it's size
316 // is 1 byte and g++ doesn't ignore it; clang++ matches this behaviour.
317 if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true) && Size == 0)
318 return ABIArgInfo::getIgnore();
319
320 // Pass floating point values via FARs if possible.
321 if (IsFixed && Ty->isFloatingType() && !Ty->isComplexType() &&
322 FRLen >= Size && FARsLeft) {
323 FARsLeft--;
324 return ABIArgInfo::getDirect();
325 }
326
327 // Complex types for the *f or *d ABI must be passed directly rather than
328 // using CoerceAndExpand.
329 if (IsFixed && Ty->isComplexType() && FRLen && FARsLeft >= 2) {
330 QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
331 if (getContext().getTypeSize(T: EltTy) <= FRLen) {
332 FARsLeft -= 2;
333 return ABIArgInfo::getDirect();
334 }
335 }
336
337 if (IsFixed && FRLen && Ty->isStructureOrClassType()) {
338 llvm::Type *Field1Ty = nullptr;
339 llvm::Type *Field2Ty = nullptr;
340 CharUnits Field1Off = CharUnits::Zero();
341 CharUnits Field2Off = CharUnits::Zero();
342 int NeededGARs = 0;
343 int NeededFARs = 0;
344 bool IsCandidate = detectFARsEligibleStruct(
345 Ty, Field1Ty, Field1Off, Field2Ty, Field2Off, NeededGARs, NeededFARs);
346 if (IsCandidate && NeededGARs <= GARsLeft && NeededFARs <= FARsLeft) {
347 GARsLeft -= NeededGARs;
348 FARsLeft -= NeededFARs;
349 return coerceAndExpandFARsEligibleStruct(Field1Ty, Field1Off, Field2Ty,
350 Field2Off);
351 }
352 }
353
354 uint64_t NeededAlign = getContext().getTypeAlign(T: Ty);
355 // Determine the number of GARs needed to pass the current argument
356 // according to the ABI. 2*GRLen-aligned varargs are passed in "aligned"
357 // register pairs, so may consume 3 registers.
358 int NeededGARs = 1;
359 if (!IsFixed && NeededAlign == 2 * GRLen)
360 NeededGARs = 2 + (GARsLeft % 2);
361 else if (Size > GRLen && Size <= 2 * GRLen)
362 NeededGARs = 2;
363
364 if (NeededGARs > GARsLeft)
365 NeededGARs = GARsLeft;
366
367 GARsLeft -= NeededGARs;
368
369 if (!isAggregateTypeForABI(T: Ty) && !Ty->isVectorType()) {
370 // Treat an enum type as its underlying type.
371 if (const EnumType *EnumTy = Ty->getAs<EnumType>())
372 Ty = EnumTy->getDecl()->getIntegerType();
373
374 // All integral types are promoted to GRLen width.
375 if (Size < GRLen && Ty->isIntegralOrEnumerationType())
376 return extendType(Ty);
377
378 if (const auto *EIT = Ty->getAs<BitIntType>()) {
379 if (EIT->getNumBits() < GRLen)
380 return extendType(Ty);
381 if (EIT->getNumBits() > 128 ||
382 (!getContext().getTargetInfo().hasInt128Type() &&
383 EIT->getNumBits() > 64))
384 return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
385 }
386
387 return ABIArgInfo::getDirect();
388 }
389
390 // Aggregates which are <= 2*GRLen will be passed in registers if possible,
391 // so coerce to integers.
392 if (Size <= 2 * GRLen) {
393 // Use a single GRLen int if possible, 2*GRLen if 2*GRLen alignment is
394 // required, and a 2-element GRLen array if only GRLen alignment is
395 // required.
396 if (Size <= GRLen) {
397 return ABIArgInfo::getDirect(
398 T: llvm::IntegerType::get(C&: getVMContext(), NumBits: GRLen));
399 }
400 if (getContext().getTypeAlign(T: Ty) == 2 * GRLen) {
401 return ABIArgInfo::getDirect(
402 T: llvm::IntegerType::get(C&: getVMContext(), NumBits: 2 * GRLen));
403 }
404 return ABIArgInfo::getDirect(
405 T: llvm::ArrayType::get(ElementType: llvm::IntegerType::get(C&: getVMContext(), NumBits: GRLen), NumElements: 2));
406 }
407 return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
408}
409
410ABIArgInfo LoongArchABIInfo::classifyReturnType(QualType RetTy) const {
411 if (RetTy->isVoidType())
412 return ABIArgInfo::getIgnore();
413 // The rules for return and argument types are the same, so defer to
414 // classifyArgumentType.
415 int GARsLeft = 2;
416 int FARsLeft = FRLen ? 2 : 0;
417 return classifyArgumentType(Ty: RetTy, /*IsFixed=*/true, GARsLeft, FARsLeft);
418}
419
420Address LoongArchABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
421 QualType Ty) const {
422 CharUnits SlotSize = CharUnits::fromQuantity(Quantity: GRLen / 8);
423
424 // Empty records are ignored for parameter passing purposes.
425 if (isEmptyRecord(Context&: getContext(), T: Ty, AllowArrays: true))
426 return Address(CGF.Builder.CreateLoad(Addr: VAListAddr),
427 CGF.ConvertTypeForMem(T: Ty), SlotSize);
428
429 auto TInfo = getContext().getTypeInfoInChars(T: Ty);
430
431 // Arguments bigger than 2*GRLen bytes are passed indirectly.
432 return emitVoidPtrVAArg(CGF, VAListAddr, ValueTy: Ty,
433 /*IsIndirect=*/TInfo.Width > 2 * SlotSize, ValueInfo: TInfo,
434 SlotSizeAndAlign: SlotSize,
435 /*AllowHigherAlign=*/true);
436}
437
438ABIArgInfo LoongArchABIInfo::extendType(QualType Ty) const {
439 int TySize = getContext().getTypeSize(T: Ty);
440 // LA64 ABI requires unsigned 32 bit integers to be sign extended.
441 if (GRLen == 64 && Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32)
442 return ABIArgInfo::getSignExtend(Ty);
443 return ABIArgInfo::getExtend(Ty);
444}
445
446namespace {
447class LoongArchTargetCodeGenInfo : public TargetCodeGenInfo {
448public:
449 LoongArchTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned GRLen,
450 unsigned FRLen)
451 : TargetCodeGenInfo(
452 std::make_unique<LoongArchABIInfo>(args&: CGT, args&: GRLen, args&: FRLen)) {}
453};
454} // namespace
455
456std::unique_ptr<TargetCodeGenInfo>
457CodeGen::createLoongArchTargetCodeGenInfo(CodeGenModule &CGM, unsigned GRLen,
458 unsigned FLen) {
459 return std::make_unique<LoongArchTargetCodeGenInfo>(args&: CGM.getTypes(), args&: GRLen,
460 args&: FLen);
461}
462

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