xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/Targets/ARC.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===- ARC.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 // ARC ABI implementation.
1606c3fb27SDimitry Andric namespace {
1706c3fb27SDimitry Andric 
1806c3fb27SDimitry Andric class ARCABIInfo : public DefaultABIInfo {
1906c3fb27SDimitry Andric   struct CCState {
2006c3fb27SDimitry Andric     unsigned FreeRegs;
2106c3fb27SDimitry Andric   };
2206c3fb27SDimitry Andric 
2306c3fb27SDimitry Andric public:
2406c3fb27SDimitry Andric   using DefaultABIInfo::DefaultABIInfo;
2506c3fb27SDimitry Andric 
2606c3fb27SDimitry Andric private:
27*0fca6ea1SDimitry Andric   RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty,
28*0fca6ea1SDimitry Andric                    AggValueSlot Slot) const override;
2906c3fb27SDimitry Andric 
updateState(const ABIArgInfo & Info,QualType Ty,CCState & State) const3006c3fb27SDimitry Andric   void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const {
3106c3fb27SDimitry Andric     if (!State.FreeRegs)
3206c3fb27SDimitry Andric       return;
3306c3fb27SDimitry Andric     if (Info.isIndirect() && Info.getInReg())
3406c3fb27SDimitry Andric       State.FreeRegs--;
3506c3fb27SDimitry Andric     else if (Info.isDirect() && Info.getInReg()) {
3606c3fb27SDimitry Andric       unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32;
3706c3fb27SDimitry Andric       if (sz < State.FreeRegs)
3806c3fb27SDimitry Andric         State.FreeRegs -= sz;
3906c3fb27SDimitry Andric       else
4006c3fb27SDimitry Andric         State.FreeRegs = 0;
4106c3fb27SDimitry Andric     }
4206c3fb27SDimitry Andric   }
4306c3fb27SDimitry Andric 
computeInfo(CGFunctionInfo & FI) const4406c3fb27SDimitry Andric   void computeInfo(CGFunctionInfo &FI) const override {
4506c3fb27SDimitry Andric     CCState State;
4606c3fb27SDimitry Andric     // ARC uses 8 registers to pass arguments.
4706c3fb27SDimitry Andric     State.FreeRegs = 8;
4806c3fb27SDimitry Andric 
4906c3fb27SDimitry Andric     if (!getCXXABI().classifyReturnType(FI))
5006c3fb27SDimitry Andric       FI.getReturnInfo() = classifyReturnType(FI.getReturnType());
5106c3fb27SDimitry Andric     updateState(FI.getReturnInfo(), FI.getReturnType(), State);
5206c3fb27SDimitry Andric     for (auto &I : FI.arguments()) {
5306c3fb27SDimitry Andric       I.info = classifyArgumentType(I.type, State.FreeRegs);
5406c3fb27SDimitry Andric       updateState(I.info, I.type, State);
5506c3fb27SDimitry Andric     }
5606c3fb27SDimitry Andric   }
5706c3fb27SDimitry Andric 
5806c3fb27SDimitry Andric   ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const;
5906c3fb27SDimitry Andric   ABIArgInfo getIndirectByValue(QualType Ty) const;
6006c3fb27SDimitry Andric   ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const;
6106c3fb27SDimitry Andric   ABIArgInfo classifyReturnType(QualType RetTy) const;
6206c3fb27SDimitry Andric };
6306c3fb27SDimitry Andric 
6406c3fb27SDimitry Andric class ARCTargetCodeGenInfo : public TargetCodeGenInfo {
6506c3fb27SDimitry Andric public:
ARCTargetCodeGenInfo(CodeGenTypes & CGT)6606c3fb27SDimitry Andric   ARCTargetCodeGenInfo(CodeGenTypes &CGT)
6706c3fb27SDimitry Andric       : TargetCodeGenInfo(std::make_unique<ARCABIInfo>(CGT)) {}
6806c3fb27SDimitry Andric };
6906c3fb27SDimitry Andric 
7006c3fb27SDimitry Andric 
getIndirectByRef(QualType Ty,bool HasFreeRegs) const7106c3fb27SDimitry Andric ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const {
7206c3fb27SDimitry Andric   return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) :
7306c3fb27SDimitry Andric                        getNaturalAlignIndirect(Ty, false);
7406c3fb27SDimitry Andric }
7506c3fb27SDimitry Andric 
getIndirectByValue(QualType Ty) const7606c3fb27SDimitry Andric ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const {
7706c3fb27SDimitry Andric   // Compute the byval alignment.
7806c3fb27SDimitry Andric   const unsigned MinABIStackAlignInBytes = 4;
7906c3fb27SDimitry Andric   unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8;
8006c3fb27SDimitry Andric   return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true,
8106c3fb27SDimitry Andric                                  TypeAlign > MinABIStackAlignInBytes);
8206c3fb27SDimitry Andric }
8306c3fb27SDimitry Andric 
EmitVAArg(CodeGenFunction & CGF,Address VAListAddr,QualType Ty,AggValueSlot Slot) const84*0fca6ea1SDimitry Andric RValue ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr,
85*0fca6ea1SDimitry Andric                              QualType Ty, AggValueSlot Slot) const {
8606c3fb27SDimitry Andric   return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false,
8706c3fb27SDimitry Andric                           getContext().getTypeInfoInChars(Ty),
88*0fca6ea1SDimitry Andric                           CharUnits::fromQuantity(4), true, Slot);
8906c3fb27SDimitry Andric }
9006c3fb27SDimitry Andric 
classifyArgumentType(QualType Ty,uint8_t FreeRegs) const9106c3fb27SDimitry Andric ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty,
9206c3fb27SDimitry Andric                                             uint8_t FreeRegs) const {
9306c3fb27SDimitry Andric   // Handle the generic C++ ABI.
9406c3fb27SDimitry Andric   const RecordType *RT = Ty->getAs<RecordType>();
9506c3fb27SDimitry Andric   if (RT) {
9606c3fb27SDimitry Andric     CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI());
9706c3fb27SDimitry Andric     if (RAA == CGCXXABI::RAA_Indirect)
9806c3fb27SDimitry Andric       return getIndirectByRef(Ty, FreeRegs > 0);
9906c3fb27SDimitry Andric 
10006c3fb27SDimitry Andric     if (RAA == CGCXXABI::RAA_DirectInMemory)
10106c3fb27SDimitry Andric       return getIndirectByValue(Ty);
10206c3fb27SDimitry Andric   }
10306c3fb27SDimitry Andric 
10406c3fb27SDimitry Andric   // Treat an enum type as its underlying type.
10506c3fb27SDimitry Andric   if (const EnumType *EnumTy = Ty->getAs<EnumType>())
10606c3fb27SDimitry Andric     Ty = EnumTy->getDecl()->getIntegerType();
10706c3fb27SDimitry Andric 
10806c3fb27SDimitry Andric   auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32;
10906c3fb27SDimitry Andric 
11006c3fb27SDimitry Andric   if (isAggregateTypeForABI(Ty)) {
11106c3fb27SDimitry Andric     // Structures with flexible arrays are always indirect.
11206c3fb27SDimitry Andric     if (RT && RT->getDecl()->hasFlexibleArrayMember())
11306c3fb27SDimitry Andric       return getIndirectByValue(Ty);
11406c3fb27SDimitry Andric 
11506c3fb27SDimitry Andric     // Ignore empty structs/unions.
11606c3fb27SDimitry Andric     if (isEmptyRecord(getContext(), Ty, true))
11706c3fb27SDimitry Andric       return ABIArgInfo::getIgnore();
11806c3fb27SDimitry Andric 
11906c3fb27SDimitry Andric     llvm::LLVMContext &LLVMContext = getVMContext();
12006c3fb27SDimitry Andric 
12106c3fb27SDimitry Andric     llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext);
12206c3fb27SDimitry Andric     SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32);
12306c3fb27SDimitry Andric     llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements);
12406c3fb27SDimitry Andric 
12506c3fb27SDimitry Andric     return FreeRegs >= SizeInRegs ?
12606c3fb27SDimitry Andric         ABIArgInfo::getDirectInReg(Result) :
12706c3fb27SDimitry Andric         ABIArgInfo::getDirect(Result, 0, nullptr, false);
12806c3fb27SDimitry Andric   }
12906c3fb27SDimitry Andric 
13006c3fb27SDimitry Andric   if (const auto *EIT = Ty->getAs<BitIntType>())
13106c3fb27SDimitry Andric     if (EIT->getNumBits() > 64)
13206c3fb27SDimitry Andric       return getIndirectByValue(Ty);
13306c3fb27SDimitry Andric 
13406c3fb27SDimitry Andric   return isPromotableIntegerTypeForABI(Ty)
13506c3fb27SDimitry Andric              ? (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty)
13606c3fb27SDimitry Andric                                        : ABIArgInfo::getExtend(Ty))
13706c3fb27SDimitry Andric              : (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg()
13806c3fb27SDimitry Andric                                        : ABIArgInfo::getDirect());
13906c3fb27SDimitry Andric }
14006c3fb27SDimitry Andric 
classifyReturnType(QualType RetTy) const14106c3fb27SDimitry Andric ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const {
14206c3fb27SDimitry Andric   if (RetTy->isAnyComplexType())
14306c3fb27SDimitry Andric     return ABIArgInfo::getDirectInReg();
14406c3fb27SDimitry Andric 
14506c3fb27SDimitry Andric   // Arguments of size > 4 registers are indirect.
14606c3fb27SDimitry Andric   auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32;
14706c3fb27SDimitry Andric   if (RetSize > 4)
14806c3fb27SDimitry Andric     return getIndirectByRef(RetTy, /*HasFreeRegs*/ true);
14906c3fb27SDimitry Andric 
15006c3fb27SDimitry Andric   return DefaultABIInfo::classifyReturnType(RetTy);
15106c3fb27SDimitry Andric }
15206c3fb27SDimitry Andric 
15306c3fb27SDimitry Andric } // End anonymous namespace.
15406c3fb27SDimitry Andric 
15506c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
createARCTargetCodeGenInfo(CodeGenModule & CGM)15606c3fb27SDimitry Andric CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) {
15706c3fb27SDimitry Andric   return std::make_unique<ARCTargetCodeGenInfo>(CGM.getTypes());
15806c3fb27SDimitry Andric }
159