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 3006c3fb27SDimitry 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 4406c3fb27SDimitry 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: 6606c3fb27SDimitry Andric ARCTargetCodeGenInfo(CodeGenTypes &CGT) 6706c3fb27SDimitry Andric : TargetCodeGenInfo(std::make_unique<ARCABIInfo>(CGT)) {} 6806c3fb27SDimitry Andric }; 6906c3fb27SDimitry Andric 7006c3fb27SDimitry Andric 7106c3fb27SDimitry Andric ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { 7206c3fb27SDimitry Andric return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) : 7306c3fb27SDimitry Andric getNaturalAlignIndirect(Ty, false); 7406c3fb27SDimitry Andric } 7506c3fb27SDimitry Andric 7606c3fb27SDimitry 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 84*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 9106c3fb27SDimitry 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 14106c3fb27SDimitry 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> 15606c3fb27SDimitry Andric CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) { 15706c3fb27SDimitry Andric return std::make_unique<ARCTargetCodeGenInfo>(CGM.getTypes()); 15806c3fb27SDimitry Andric } 159