//===- 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(CGT)) {} }; ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) : getNaturalAlignIndirect(Ty, 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), /*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->getAs(); 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 EnumType *EnumTy = Ty->getAs()) Ty = EnumTy->getDecl()->getIntegerType(); auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32; if (isAggregateTypeForABI(Ty)) { // Structures with flexible arrays are always indirect. if (RT && RT->getDecl()->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 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()) 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 CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) { return std::make_unique(CGM.getTypes()); }