xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/Targets/CSKY.cpp (revision b64c5a0ace59af62eff52bfe110a521dc73c937b)
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       : 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 
42 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 
60 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 
74 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(Ty, /*ByVal=*/RAA ==
86                                            CGCXXABI::RAA_DirectInMemory);
87   }
88 
89   // Ignore empty structs/unions.
90   if (isEmptyRecord(getContext(), Ty, true))
91     return ABIArgInfo::getIgnore();
92 
93   if (!Ty->getAsUnionType())
94     if (const Type *SeltTy = isSingleElementStruct(Ty, getContext()))
95       return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0)));
96 
97   uint64_t Size = getContext().getTypeSize(Ty);
98   // Pass floating point values via FPRs if possible.
99   if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size &&
100       ArgFPRsLeft) {
101     ArgFPRsLeft--;
102     return ABIArgInfo::getDirect();
103   }
104 
105   // Complex types for the hard float ABI must be passed direct rather than
106   // using CoerceAndExpand.
107   if (Ty->isComplexType() && FLen && !isReturnType) {
108     QualType EltTy = Ty->castAs<ComplexType>()->getElementType();
109     if (getContext().getTypeSize(EltTy) <= FLen) {
110       ArgFPRsLeft -= 2;
111       return ABIArgInfo::getDirect();
112     }
113   }
114 
115   if (!isAggregateTypeForABI(Ty)) {
116     // Treat an enum type as its underlying type.
117     if (const EnumType *EnumTy = Ty->getAs<EnumType>())
118       Ty = EnumTy->getDecl()->getIntegerType();
119 
120     // All integral types are promoted to XLen width, unless passed on the
121     // stack.
122     if (Size < XLen && Ty->isIntegralOrEnumerationType())
123       return ABIArgInfo::getExtend(Ty);
124 
125     if (const auto *EIT = Ty->getAs<BitIntType>()) {
126       if (EIT->getNumBits() < XLen)
127         return ABIArgInfo::getExtend(Ty);
128     }
129 
130     return ABIArgInfo::getDirect();
131   }
132 
133   // For argument type, the first 4*XLen parts of aggregate will be passed
134   // in registers, and the rest will be passed in stack.
135   // So we can coerce to integers directly and let backend handle it correctly.
136   // For return type, aggregate which <= 2*XLen will be returned in registers.
137   // Otherwise, aggregate will be returned indirectly.
138   if (!isReturnType || (isReturnType && Size <= 2 * XLen)) {
139     if (Size <= XLen) {
140       return ABIArgInfo::getDirect(
141           llvm::IntegerType::get(getVMContext(), XLen));
142     } else {
143       return ABIArgInfo::getDirect(llvm::ArrayType::get(
144           llvm::IntegerType::get(getVMContext(), XLen), (Size + 31) / XLen));
145     }
146   }
147   return getNaturalAlignIndirect(Ty, /*ByVal=*/false);
148 }
149 
150 ABIArgInfo CSKYABIInfo::classifyReturnType(QualType RetTy) const {
151   if (RetTy->isVoidType())
152     return ABIArgInfo::getIgnore();
153 
154   int ArgGPRsLeft = 2;
155   int ArgFPRsLeft = FLen ? 1 : 0;
156 
157   // The rules for return and argument types are the same, so defer to
158   // classifyArgumentType.
159   return classifyArgumentType(RetTy, ArgGPRsLeft, ArgFPRsLeft, true);
160 }
161 
162 namespace {
163 class CSKYTargetCodeGenInfo : public TargetCodeGenInfo {
164 public:
165   CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen)
166       : TargetCodeGenInfo(std::make_unique<CSKYABIInfo>(CGT, FLen)) {}
167 };
168 } // end anonymous namespace
169 
170 std::unique_ptr<TargetCodeGenInfo>
171 CodeGen::createCSKYTargetCodeGenInfo(CodeGenModule &CGM, unsigned FLen) {
172   return std::make_unique<CSKYTargetCodeGenInfo>(CGM.getTypes(), FLen);
173 }
174