1 //===- ARC.cpp ------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ABIInfoImpl.h" 10 #include "TargetInfo.h" 11 12 using namespace clang; 13 using namespace clang::CodeGen; 14 15 // ARC ABI implementation. 16 namespace { 17 18 class ARCABIInfo : public DefaultABIInfo { 19 struct CCState { 20 unsigned FreeRegs; 21 }; 22 23 public: 24 using DefaultABIInfo::DefaultABIInfo; 25 26 private: 27 RValue EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, 28 AggValueSlot Slot) const override; 29 30 void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const { 31 if (!State.FreeRegs) 32 return; 33 if (Info.isIndirect() && Info.getInReg()) 34 State.FreeRegs--; 35 else if (Info.isDirect() && Info.getInReg()) { 36 unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32; 37 if (sz < State.FreeRegs) 38 State.FreeRegs -= sz; 39 else 40 State.FreeRegs = 0; 41 } 42 } 43 44 void computeInfo(CGFunctionInfo &FI) const override { 45 CCState State; 46 // ARC uses 8 registers to pass arguments. 47 State.FreeRegs = 8; 48 49 if (!getCXXABI().classifyReturnType(FI)) 50 FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); 51 updateState(FI.getReturnInfo(), FI.getReturnType(), State); 52 for (auto &I : FI.arguments()) { 53 I.info = classifyArgumentType(I.type, State.FreeRegs); 54 updateState(I.info, I.type, State); 55 } 56 } 57 58 ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const; 59 ABIArgInfo getIndirectByValue(QualType Ty) const; 60 ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const; 61 ABIArgInfo classifyReturnType(QualType RetTy) const; 62 }; 63 64 class ARCTargetCodeGenInfo : public TargetCodeGenInfo { 65 public: 66 ARCTargetCodeGenInfo(CodeGenTypes &CGT) 67 : TargetCodeGenInfo(std::make_unique<ARCABIInfo>(CGT)) {} 68 }; 69 70 71 ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { 72 return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) 73 : getNaturalAlignIndirect( 74 Ty, getDataLayout().getAllocaAddrSpace(), false); 75 } 76 77 ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const { 78 // Compute the byval alignment. 79 const unsigned MinABIStackAlignInBytes = 4; 80 unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; 81 return ABIArgInfo::getIndirect( 82 CharUnits::fromQuantity(4), 83 /*AddrSpace=*/getDataLayout().getAllocaAddrSpace(), 84 /*ByVal=*/true, TypeAlign > MinABIStackAlignInBytes); 85 } 86 87 RValue ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 88 QualType Ty, AggValueSlot Slot) const { 89 return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, 90 getContext().getTypeInfoInChars(Ty), 91 CharUnits::fromQuantity(4), true, Slot); 92 } 93 94 ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty, 95 uint8_t FreeRegs) const { 96 // Handle the generic C++ ABI. 97 const RecordType *RT = Ty->getAs<RecordType>(); 98 if (RT) { 99 CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); 100 if (RAA == CGCXXABI::RAA_Indirect) 101 return getIndirectByRef(Ty, FreeRegs > 0); 102 103 if (RAA == CGCXXABI::RAA_DirectInMemory) 104 return getIndirectByValue(Ty); 105 } 106 107 // Treat an enum type as its underlying type. 108 if (const EnumType *EnumTy = Ty->getAs<EnumType>()) 109 Ty = EnumTy->getDecl()->getIntegerType(); 110 111 auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32; 112 113 if (isAggregateTypeForABI(Ty)) { 114 // Structures with flexible arrays are always indirect. 115 if (RT && RT->getDecl()->hasFlexibleArrayMember()) 116 return getIndirectByValue(Ty); 117 118 // Ignore empty structs/unions. 119 if (isEmptyRecord(getContext(), Ty, true)) 120 return ABIArgInfo::getIgnore(); 121 122 llvm::LLVMContext &LLVMContext = getVMContext(); 123 124 llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); 125 SmallVector<llvm::Type *, 3> Elements(SizeInRegs, Int32); 126 llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); 127 128 return FreeRegs >= SizeInRegs ? 129 ABIArgInfo::getDirectInReg(Result) : 130 ABIArgInfo::getDirect(Result, 0, nullptr, false); 131 } 132 133 if (const auto *EIT = Ty->getAs<BitIntType>()) 134 if (EIT->getNumBits() > 64) 135 return getIndirectByValue(Ty); 136 137 return isPromotableIntegerTypeForABI(Ty) 138 ? (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty) 139 : ABIArgInfo::getExtend(Ty)) 140 : (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg() 141 : ABIArgInfo::getDirect()); 142 } 143 144 ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const { 145 if (RetTy->isAnyComplexType()) 146 return ABIArgInfo::getDirectInReg(); 147 148 // Arguments of size > 4 registers are indirect. 149 auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32; 150 if (RetSize > 4) 151 return getIndirectByRef(RetTy, /*HasFreeRegs*/ true); 152 153 return DefaultABIInfo::classifyReturnType(RetTy); 154 } 155 156 } // End anonymous namespace. 157 158 std::unique_ptr<TargetCodeGenInfo> 159 CodeGen::createARCTargetCodeGenInfo(CodeGenModule &CGM) { 160 return std::make_unique<ARCTargetCodeGenInfo>(CGM.getTypes()); 161 } 162