xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/Targets/ARC.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===- ARC.cpp ------------------------------------------------------------===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric 
9*06c3fb27SDimitry Andric #include "ABIInfoImpl.h"
10*06c3fb27SDimitry Andric #include "TargetInfo.h"
11*06c3fb27SDimitry Andric 
12*06c3fb27SDimitry Andric using namespace clang;
13*06c3fb27SDimitry Andric using namespace clang::CodeGen;
14*06c3fb27SDimitry Andric 
15*06c3fb27SDimitry Andric // ARC ABI implementation.
16*06c3fb27SDimitry Andric namespace {
17*06c3fb27SDimitry Andric 
18*06c3fb27SDimitry Andric class ARCABIInfo : public DefaultABIInfo {
19*06c3fb27SDimitry Andric   struct CCState {
20*06c3fb27SDimitry Andric     unsigned FreeRegs;
21*06c3fb27SDimitry Andric   };
22*06c3fb27SDimitry Andric 
23*06c3fb27SDimitry Andric public:
24*06c3fb27SDimitry Andric   using DefaultABIInfo::DefaultABIInfo;
25*06c3fb27SDimitry Andric 
26*06c3fb27SDimitry Andric private:
27*06c3fb27SDimitry Andric   Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
28*06c3fb27SDimitry Andric                     QualType Ty) const override;
29*06c3fb27SDimitry Andric 
30*06c3fb27SDimitry Andric   void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const {
31*06c3fb27SDimitry Andric     if (!State.FreeRegs)
32*06c3fb27SDimitry Andric       return;
33*06c3fb27SDimitry Andric     if (Info.isIndirect() && Info.getInReg())
34*06c3fb27SDimitry Andric       State.FreeRegs--;
35*06c3fb27SDimitry Andric     else if (Info.isDirect() && Info.getInReg()) {
36*06c3fb27SDimitry Andric       unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32;
37*06c3fb27SDimitry Andric       if (sz < State.FreeRegs)
38*06c3fb27SDimitry Andric         State.FreeRegs -= sz;
39*06c3fb27SDimitry Andric       else
40*06c3fb27SDimitry Andric         State.FreeRegs = 0;
41*06c3fb27SDimitry Andric     }
42*06c3fb27SDimitry Andric   }
43*06c3fb27SDimitry Andric 
44*06c3fb27SDimitry Andric   void computeInfo(CGFunctionInfo &FI) const override {
45*06c3fb27SDimitry Andric     CCState State;
46*06c3fb27SDimitry Andric     // ARC uses 8 registers to pass arguments.
47*06c3fb27SDimitry Andric     State.FreeRegs = 8;
48*06c3fb27SDimitry Andric 
49*06c3fb27SDimitry Andric     if (!getCXXABI().classifyReturnType(FI))
50*06c3fb27SDimitry Andric       FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
51*06c3fb27SDimitry Andric     updateState(FI.getReturnInfo(), FI.getReturnType(), State);
52*06c3fb27SDimitry Andric     for (auto &I : FI.arguments()) {
53*06c3fb27SDimitry Andric       I.info = classifyArgumentType(I.type, State.FreeRegs);
54*06c3fb27SDimitry Andric       updateState(I.info, I.type, State);
55*06c3fb27SDimitry Andric     }
56*06c3fb27SDimitry Andric   }
57*06c3fb27SDimitry Andric 
58*06c3fb27SDimitry Andric   ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const;
59*06c3fb27SDimitry Andric   ABIArgInfo getIndirectByValue(QualType Ty) const;
60*06c3fb27SDimitry Andric   ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const;
61*06c3fb27SDimitry Andric   ABIArgInfo classifyReturnType(QualType RetTy) const;
62*06c3fb27SDimitry Andric };
63*06c3fb27SDimitry Andric 
64*06c3fb27SDimitry Andric class ARCTargetCodeGenInfo : public TargetCodeGenInfo {
65*06c3fb27SDimitry Andric public:
66*06c3fb27SDimitry Andric   ARCTargetCodeGenInfo(CodeGenTypes &CGT)
67*06c3fb27SDimitry Andric       : TargetCodeGenInfo(std::make_unique<ARCABIInfo>(CGT)) {}
68*06c3fb27SDimitry Andric };
69*06c3fb27SDimitry Andric 
70*06c3fb27SDimitry Andric 
71*06c3fb27SDimitry Andric ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const {
72*06c3fb27SDimitry Andric   return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) :
73*06c3fb27SDimitry Andric                        getNaturalAlignIndirect(Ty, false);
74*06c3fb27SDimitry Andric }
75*06c3fb27SDimitry Andric 
76*06c3fb27SDimitry Andric ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const {
77*06c3fb27SDimitry Andric   // Compute the byval alignment.
78*06c3fb27SDimitry Andric   const unsigned MinABIStackAlignInBytes = 4;
79*06c3fb27SDimitry Andric   unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
80*06c3fb27SDimitry Andric   return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true,
81*06c3fb27SDimitry Andric                                  TypeAlign > MinABIStackAlignInBytes);
82*06c3fb27SDimitry Andric }
83*06c3fb27SDimitry Andric 
84*06c3fb27SDimitry Andric Address ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
85*06c3fb27SDimitry Andric                               QualType Ty) const {
86*06c3fb27SDimitry Andric   return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
87*06c3fb27SDimitry Andric                           getContext().getTypeInfoInChars(Ty),
88*06c3fb27SDimitry Andric                           CharUnits::fromQuantity(4), true);
89*06c3fb27SDimitry Andric }
90*06c3fb27SDimitry Andric 
91*06c3fb27SDimitry Andric ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty,
92*06c3fb27SDimitry Andric                                             uint8_t FreeRegs) const {
93*06c3fb27SDimitry Andric   // Handle the generic C++ ABI.
94*06c3fb27SDimitry Andric   const RecordType *RT = Ty->getAs<RecordType>();
95*06c3fb27SDimitry Andric   if (RT) {
96*06c3fb27SDimitry Andric     CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
97*06c3fb27SDimitry Andric     if (RAA == CGCXXABI::RAA_Indirect)
98*06c3fb27SDimitry Andric       return getIndirectByRef(Ty, FreeRegs > 0);
99*06c3fb27SDimitry Andric 
100*06c3fb27SDimitry Andric     if (RAA == CGCXXABI::RAA_DirectInMemory)
101*06c3fb27SDimitry Andric       return getIndirectByValue(Ty);
102*06c3fb27SDimitry Andric   }
103*06c3fb27SDimitry Andric 
104*06c3fb27SDimitry Andric   // Treat an enum type as its underlying type.
105*06c3fb27SDimitry Andric   if (const EnumType *EnumTy = Ty->getAs<EnumType>())
106*06c3fb27SDimitry Andric     Ty = EnumTy->getDecl()->getIntegerType();
107*06c3fb27SDimitry Andric 
108*06c3fb27SDimitry Andric   auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32;
109*06c3fb27SDimitry Andric 
110*06c3fb27SDimitry Andric   if (isAggregateTypeForABI(Ty)) {
111*06c3fb27SDimitry Andric     // Structures with flexible arrays are always indirect.
112*06c3fb27SDimitry Andric     if (RT && RT->getDecl()->hasFlexibleArrayMember())
113*06c3fb27SDimitry Andric       return getIndirectByValue(Ty);
114*06c3fb27SDimitry Andric 
115*06c3fb27SDimitry Andric     // Ignore empty structs/unions.
116*06c3fb27SDimitry Andric     if (isEmptyRecord(getContext(), Ty, true))
117*06c3fb27SDimitry Andric       return ABIArgInfo::getIgnore();
118*06c3fb27SDimitry Andric 
119*06c3fb27SDimitry Andric     llvm::LLVMContext &LLVMContext = getVMContext();
120*06c3fb27SDimitry Andric 
121*06c3fb27SDimitry Andric     llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
122*06c3fb27SDimitry Andric     SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32);
123*06c3fb27SDimitry Andric     llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
124*06c3fb27SDimitry Andric 
125*06c3fb27SDimitry Andric     return FreeRegs >= SizeInRegs ?
126*06c3fb27SDimitry Andric         ABIArgInfo::getDirectInReg(Result) :
127*06c3fb27SDimitry Andric         ABIArgInfo::getDirect(Result, 0, nullptr, false);
128*06c3fb27SDimitry Andric   }
129*06c3fb27SDimitry Andric 
130*06c3fb27SDimitry Andric   if (const auto *EIT = Ty->getAs<BitIntType>())
131*06c3fb27SDimitry Andric     if (EIT->getNumBits() > 64)
132*06c3fb27SDimitry Andric       return getIndirectByValue(Ty);
133*06c3fb27SDimitry Andric 
134*06c3fb27SDimitry Andric   return isPromotableIntegerTypeForABI(Ty)
135*06c3fb27SDimitry Andric              ? (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty)
136*06c3fb27SDimitry Andric                                        : ABIArgInfo::getExtend(Ty))
137*06c3fb27SDimitry Andric              : (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg()
138*06c3fb27SDimitry Andric                                        : ABIArgInfo::getDirect());
139*06c3fb27SDimitry Andric }
140*06c3fb27SDimitry Andric 
141*06c3fb27SDimitry Andric ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const {
142*06c3fb27SDimitry Andric   if (RetTy->isAnyComplexType())
143*06c3fb27SDimitry Andric     return ABIArgInfo::getDirectInReg();
144*06c3fb27SDimitry Andric 
145*06c3fb27SDimitry Andric   // Arguments of size > 4 registers are indirect.
146*06c3fb27SDimitry Andric   auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32;
147*06c3fb27SDimitry Andric   if (RetSize > 4)
148*06c3fb27SDimitry Andric     return getIndirectByRef(RetTy, /*HasFreeRegs*/ true);
149*06c3fb27SDimitry Andric 
150*06c3fb27SDimitry Andric   return DefaultABIInfo::classifyReturnType(RetTy);
151*06c3fb27SDimitry Andric }
152*06c3fb27SDimitry Andric 
153*06c3fb27SDimitry Andric } // End anonymous namespace.
154*06c3fb27SDimitry Andric 
155*06c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
156*06c3fb27SDimitry Andric CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) {
157*06c3fb27SDimitry Andric   return std::make_unique<ARCTargetCodeGenInfo>(CGM.getTypes());
158*06c3fb27SDimitry Andric }
159