|  | //===- ARC.cpp ------------------------------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "ABIInfoImpl.h" | 
|  | #include "TargetInfo.h" | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace clang::CodeGen; | 
|  |  | 
|  | // ARC ABI implementation. | 
|  | namespace { | 
|  |  | 
|  | class ARCABIInfo : public DefaultABIInfo { | 
|  | struct CCState { | 
|  | unsigned FreeRegs; | 
|  | }; | 
|  |  | 
|  | public: | 
|  | using DefaultABIInfo::DefaultABIInfo; | 
|  |  | 
|  | private: | 
|  | RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, | 
|  | AggValueSlot Slot) const override; | 
|  |  | 
|  | void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const { | 
|  | if (!State.FreeRegs) | 
|  | return; | 
|  | if (Info.isIndirect() && Info.getInReg()) | 
|  | State.FreeRegs--; | 
|  | else if (Info.isDirect() && Info.getInReg()) { | 
|  | unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32; | 
|  | if (sz < State.FreeRegs) | 
|  | State.FreeRegs -= sz; | 
|  | else | 
|  | State.FreeRegs = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | void computeInfo(CGFunctionInfo &FI) const override { | 
|  | CCState State; | 
|  | // ARC uses 8 registers to pass arguments. | 
|  | State.FreeRegs = 8; | 
|  |  | 
|  | if (!getCXXABI().classifyReturnType(FI)) | 
|  | FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); | 
|  | updateState(FI.getReturnInfo(), FI.getReturnType(), State); | 
|  | for (auto &I : FI.arguments()) { | 
|  | I.info = classifyArgumentType(I.type, State.FreeRegs); | 
|  | updateState(I.info, I.type, State); | 
|  | } | 
|  | } | 
|  |  | 
|  | ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const; | 
|  | ABIArgInfo getIndirectByValue(QualType Ty) const; | 
|  | ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const; | 
|  | ABIArgInfo classifyReturnType(QualType RetTy) const; | 
|  | }; | 
|  |  | 
|  | class ARCTargetCodeGenInfo : public TargetCodeGenInfo { | 
|  | public: | 
|  | ARCTargetCodeGenInfo(CodeGenTypes &CGT) | 
|  | : TargetCodeGenInfo(std::make_unique<ARCABIInfo>(CGT)) {} | 
|  | }; | 
|  |  | 
|  |  | 
|  | ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { | 
|  | return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) | 
|  | : getNaturalAlignIndirect( | 
|  | Ty, getDataLayout().getAllocaAddrSpace(), false); | 
|  | } | 
|  |  | 
|  | ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const { | 
|  | // Compute the byval alignment. | 
|  | const unsigned MinABIStackAlignInBytes = 4; | 
|  | unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; | 
|  | return ABIArgInfo::getIndirect( | 
|  | CharUnits::fromQuantity(4), | 
|  | /*AddrSpace=*/getDataLayout().getAllocaAddrSpace(), | 
|  | /*ByVal=*/true, TypeAlign > MinABIStackAlignInBytes); | 
|  | } | 
|  |  | 
|  | RValue ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, | 
|  | QualType Ty, AggValueSlot Slot) const { | 
|  | return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, | 
|  | getContext().getTypeInfoInChars(Ty), | 
|  | CharUnits::fromQuantity(4), true, Slot); | 
|  | } | 
|  |  | 
|  | ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty, | 
|  | uint8_t FreeRegs) const { | 
|  | // Handle the generic C++ ABI. | 
|  | const RecordType *RT = Ty->getAsCanonical<RecordType>(); | 
|  | if (RT) { | 
|  | CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); | 
|  | if (RAA == CGCXXABI::RAA_Indirect) | 
|  | return getIndirectByRef(Ty, FreeRegs > 0); | 
|  |  | 
|  | if (RAA == CGCXXABI::RAA_DirectInMemory) | 
|  | return getIndirectByValue(Ty); | 
|  | } | 
|  |  | 
|  | // Treat an enum type as its underlying type. | 
|  | if (const auto *ED = Ty->getAsEnumDecl()) | 
|  | Ty = ED->getIntegerType(); | 
|  |  | 
|  | auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32; | 
|  |  | 
|  | if (isAggregateTypeForABI(Ty)) { | 
|  | // Structures with flexible arrays are always indirect. | 
|  | if (RT && RT->getDecl()->getDefinitionOrSelf()->hasFlexibleArrayMember()) | 
|  | return getIndirectByValue(Ty); | 
|  |  | 
|  | // Ignore empty structs/unions. | 
|  | if (isEmptyRecord(getContext(), Ty, true)) | 
|  | return ABIArgInfo::getIgnore(); | 
|  |  | 
|  | llvm::LLVMContext &LLVMContext = getVMContext(); | 
|  |  | 
|  | llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); | 
|  | SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32); | 
|  | llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); | 
|  |  | 
|  | return FreeRegs >= SizeInRegs ? | 
|  | ABIArgInfo::getDirectInReg(Result) : | 
|  | ABIArgInfo::getDirect(Result, 0, nullptr, false); | 
|  | } | 
|  |  | 
|  | if (const auto *EIT = Ty->getAs<BitIntType>()) | 
|  | if (EIT->getNumBits() > 64) | 
|  | return getIndirectByValue(Ty); | 
|  |  | 
|  | return isPromotableIntegerTypeForABI(Ty) | 
|  | ? (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty) | 
|  | : ABIArgInfo::getExtend(Ty)) | 
|  | : (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg() | 
|  | : ABIArgInfo::getDirect()); | 
|  | } | 
|  |  | 
|  | ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const { | 
|  | if (RetTy->isAnyComplexType()) | 
|  | return ABIArgInfo::getDirectInReg(); | 
|  |  | 
|  | // Arguments of size > 4 registers are indirect. | 
|  | auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32; | 
|  | if (RetSize > 4) | 
|  | return getIndirectByRef(RetTy, /*HasFreeRegs*/ true); | 
|  |  | 
|  | return DefaultABIInfo::classifyReturnType(RetTy); | 
|  | } | 
|  |  | 
|  | } // End anonymous namespace. | 
|  |  | 
|  | std::unique_ptr<TargetCodeGenInfo> | 
|  | CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) { | 
|  | return std::make_unique<ARCTargetCodeGenInfo>(CGM.getTypes()); | 
|  | } |