xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/Targets/CSKY.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===- CSKY.cpp -----------------------------------------------------------===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric 
906c3fb27SDimitry Andric #include "ABIInfoImpl.h"
1006c3fb27SDimitry Andric #include "TargetInfo.h"
1106c3fb27SDimitry Andric 
1206c3fb27SDimitry Andric using namespace clang;
1306c3fb27SDimitry Andric using namespace clang::CodeGen;
1406c3fb27SDimitry Andric 
1506c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1606c3fb27SDimitry Andric // CSKY ABI Implementation
1706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1806c3fb27SDimitry Andric namespace {
1906c3fb27SDimitry Andric class CSKYABIInfo : public DefaultABIInfo {
2006c3fb27SDimitry Andric   static const int NumArgGPRs = 4;
2106c3fb27SDimitry Andric   static const int NumArgFPRs = 4;
2206c3fb27SDimitry Andric 
2306c3fb27SDimitry Andric   static const unsigned XLen = 32;
2406c3fb27SDimitry Andric   unsigned FLen;
2506c3fb27SDimitry Andric 
2606c3fb27SDimitry Andric public:
2706c3fb27SDimitry Andric   CSKYABIInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
2806c3fb27SDimitry Andric       : DefaultABIInfo(CGT), FLen(FLen) {}
2906c3fb27SDimitry Andric 
3006c3fb27SDimitry Andric   void computeInfo(CGFunctionInfo &FI) const override;
3106c3fb27SDimitry Andric   ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
3206c3fb27SDimitry Andric                                   int &ArgFPRsLeft,
3306c3fb27SDimitry Andric                                   bool isReturnType = false) const;
3406c3fb27SDimitry Andric   ABIArgInfo classifyReturnType(QualType RetTy) const;
3506c3fb27SDimitry Andric 
36*0fca6ea1SDimitry Andric   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
37*0fca6ea1SDimitry Andric                    AggValueSlot Slot) const override;
3806c3fb27SDimitry Andric };
3906c3fb27SDimitry Andric 
4006c3fb27SDimitry Andric } // end anonymous namespace
4106c3fb27SDimitry Andric 
4206c3fb27SDimitry Andric void CSKYABIInfo::computeInfo(CGFunctionInfo &FI) const {
4306c3fb27SDimitry Andric   QualType RetTy = FI.getReturnType();
4406c3fb27SDimitry Andric   if (!getCXXABI().classifyReturnType(FI))
4506c3fb27SDimitry Andric     FI.getReturnInfo() = classifyReturnType(RetTy);
4606c3fb27SDimitry Andric 
4706c3fb27SDimitry Andric   bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect;
4806c3fb27SDimitry Andric 
4906c3fb27SDimitry Andric   // We must track the number of GPRs used in order to conform to the CSKY
5006c3fb27SDimitry Andric   // ABI, as integer scalars passed in registers should have signext/zeroext
5106c3fb27SDimitry Andric   // when promoted.
5206c3fb27SDimitry Andric   int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs;
5306c3fb27SDimitry Andric   int ArgFPRsLeft = FLen ? NumArgFPRs : 0;
5406c3fb27SDimitry Andric 
5506c3fb27SDimitry Andric   for (auto &ArgInfo : FI.arguments()) {
5606c3fb27SDimitry Andric     ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft, ArgFPRsLeft);
5706c3fb27SDimitry Andric   }
5806c3fb27SDimitry Andric }
5906c3fb27SDimitry Andric 
60*0fca6ea1SDimitry Andric RValue CSKYABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
61*0fca6ea1SDimitry Andric                               QualType Ty, AggValueSlot Slot) const {
6206c3fb27SDimitry Andric   CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8);
6306c3fb27SDimitry Andric 
6406c3fb27SDimitry Andric   // Empty records are ignored for parameter passing purposes.
65*0fca6ea1SDimitry Andric   if (isEmptyRecord(getContext(), Ty, true))
66*0fca6ea1SDimitry Andric     return Slot.asRValue();
6706c3fb27SDimitry Andric 
6806c3fb27SDimitry Andric   auto TInfo = getContext().getTypeInfoInChars(Ty);
6906c3fb27SDimitry Andric 
7006c3fb27SDimitry Andric   return emitVoidPtrVAArg(CGF, VAListAddr, Ty, false, TInfo, SlotSize,
71*0fca6ea1SDimitry Andric                           /*AllowHigherAlign=*/true, Slot);
7206c3fb27SDimitry Andric }
7306c3fb27SDimitry Andric 
7406c3fb27SDimitry Andric ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft,
7506c3fb27SDimitry Andric                                              int &ArgFPRsLeft,
7606c3fb27SDimitry Andric                                              bool isReturnType) const {
7706c3fb27SDimitry Andric   assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow");
7806c3fb27SDimitry Andric   Ty = useFirstFieldIfTransparentUnion(Ty);
7906c3fb27SDimitry Andric 
8006c3fb27SDimitry Andric   // Structures with either a non-trivial destructor or a non-trivial
8106c3fb27SDimitry Andric   // copy constructor are always passed indirectly.
8206c3fb27SDimitry Andric   if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) {
8306c3fb27SDimitry Andric     if (ArgGPRsLeft)
8406c3fb27SDimitry Andric       ArgGPRsLeft -= 1;
8506c3fb27SDimitry Andric     return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA ==
8606c3fb27SDimitry Andric                                            CGCXXABI::RAA_DirectInMemory);
8706c3fb27SDimitry Andric   }
8806c3fb27SDimitry Andric 
8906c3fb27SDimitry Andric   // Ignore empty structs/unions.
9006c3fb27SDimitry Andric   if (isEmptyRecord(getContext(), Ty, true))
9106c3fb27SDimitry Andric     return ABIArgInfo::getIgnore();
9206c3fb27SDimitry Andric 
9306c3fb27SDimitry Andric   if (!Ty->getAsUnionType())
9406c3fb27SDimitry Andric     if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
9506c3fb27SDimitry Andric       return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
9606c3fb27SDimitry Andric 
9706c3fb27SDimitry Andric   uint64_t Size = getContext().getTypeSize(Ty);
9806c3fb27SDimitry Andric   // Pass floating point values via FPRs if possible.
9906c3fb27SDimitry Andric   if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size &&
10006c3fb27SDimitry Andric       ArgFPRsLeft) {
10106c3fb27SDimitry Andric     ArgFPRsLeft--;
10206c3fb27SDimitry Andric     return ABIArgInfo::getDirect();
10306c3fb27SDimitry Andric   }
10406c3fb27SDimitry Andric 
10506c3fb27SDimitry Andric   // Complex types for the hard float ABI must be passed direct rather than
10606c3fb27SDimitry Andric   // using CoerceAndExpand.
10706c3fb27SDimitry Andric   if (Ty->isComplexType() && FLen && !isReturnType) {
10806c3fb27SDimitry Andric     QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
10906c3fb27SDimitry Andric     if (getContext().getTypeSize(EltTy) <= FLen) {
11006c3fb27SDimitry Andric       ArgFPRsLeft -= 2;
11106c3fb27SDimitry Andric       return ABIArgInfo::getDirect();
11206c3fb27SDimitry Andric     }
11306c3fb27SDimitry Andric   }
11406c3fb27SDimitry Andric 
11506c3fb27SDimitry Andric   if (!isAggregateTypeForABI(Ty)) {
11606c3fb27SDimitry Andric     // Treat an enum type as its underlying type.
11706c3fb27SDimitry Andric     if (const EnumType *EnumTy = Ty->getAs<EnumType>())
11806c3fb27SDimitry Andric       Ty = EnumTy->getDecl()->getIntegerType();
11906c3fb27SDimitry Andric 
12006c3fb27SDimitry Andric     // All integral types are promoted to XLen width, unless passed on the
12106c3fb27SDimitry Andric     // stack.
12206c3fb27SDimitry Andric     if (Size < XLen && Ty->isIntegralOrEnumerationType())
12306c3fb27SDimitry Andric       return ABIArgInfo::getExtend(Ty);
12406c3fb27SDimitry Andric 
12506c3fb27SDimitry Andric     if (const auto *EIT = Ty->getAs<BitIntType>()) {
12606c3fb27SDimitry Andric       if (EIT->getNumBits() < XLen)
12706c3fb27SDimitry Andric         return ABIArgInfo::getExtend(Ty);
12806c3fb27SDimitry Andric     }
12906c3fb27SDimitry Andric 
13006c3fb27SDimitry Andric     return ABIArgInfo::getDirect();
13106c3fb27SDimitry Andric   }
13206c3fb27SDimitry Andric 
13306c3fb27SDimitry Andric   // For argument type, the first 4*XLen parts of aggregate will be passed
13406c3fb27SDimitry Andric   // in registers, and the rest will be passed in stack.
13506c3fb27SDimitry Andric   // So we can coerce to integers directly and let backend handle it correctly.
13606c3fb27SDimitry Andric   // For return type, aggregate which <= 2*XLen will be returned in registers.
13706c3fb27SDimitry Andric   // Otherwise, aggregate will be returned indirectly.
13806c3fb27SDimitry Andric   if (!isReturnType || (isReturnType && Size <= 2 * XLen)) {
13906c3fb27SDimitry Andric     if (Size <= XLen) {
14006c3fb27SDimitry Andric       return ABIArgInfo::getDirect(
14106c3fb27SDimitry Andric           llvm::IntegerType::get(getVMContext(), XLen));
14206c3fb27SDimitry Andric     } else {
14306c3fb27SDimitry Andric       return ABIArgInfo::getDirect(llvm::ArrayType::get(
14406c3fb27SDimitry Andric           llvm::IntegerType::get(getVMContext(), XLen), (Size + 31) / XLen));
14506c3fb27SDimitry Andric     }
14606c3fb27SDimitry Andric   }
14706c3fb27SDimitry Andric   return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
14806c3fb27SDimitry Andric }
14906c3fb27SDimitry Andric 
15006c3fb27SDimitry Andric ABIArgInfo CSKYABIInfo::classifyReturnType(QualType RetTy) const {
15106c3fb27SDimitry Andric   if (RetTy->isVoidType())
15206c3fb27SDimitry Andric     return ABIArgInfo::getIgnore();
15306c3fb27SDimitry Andric 
15406c3fb27SDimitry Andric   int ArgGPRsLeft = 2;
15506c3fb27SDimitry Andric   int ArgFPRsLeft = FLen ? 1 : 0;
15606c3fb27SDimitry Andric 
15706c3fb27SDimitry Andric   // The rules for return and argument types are the same, so defer to
15806c3fb27SDimitry Andric   // classifyArgumentType.
15906c3fb27SDimitry Andric   return classifyArgumentType(RetTy, ArgGPRsLeft, ArgFPRsLeft, true);
16006c3fb27SDimitry Andric }
16106c3fb27SDimitry Andric 
16206c3fb27SDimitry Andric namespace {
16306c3fb27SDimitry Andric class CSKYTargetCodeGenInfo : public TargetCodeGenInfo {
16406c3fb27SDimitry Andric public:
16506c3fb27SDimitry Andric   CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
16606c3fb27SDimitry Andric       : TargetCodeGenInfo(std::make_unique<CSKYABIInfo>(CGT, FLen)) {}
16706c3fb27SDimitry Andric };
16806c3fb27SDimitry Andric } // end anonymous namespace
16906c3fb27SDimitry Andric 
17006c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
17106c3fb27SDimitry Andric CodeGen::createCSKYTargetCodeGenInfo(CodeGenModule &CGM, unsigned FLen) {
17206c3fb27SDimitry Andric   return std::make_unique<CSKYTargetCodeGenInfo>(CGM.getTypes(), FLen);
17306c3fb27SDimitry Andric }
174