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