1*06c3fb27SDimitry Andric //===- Mips.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 //===----------------------------------------------------------------------===// 16*06c3fb27SDimitry Andric // MIPS ABI Implementation. This works for both little-endian and 17*06c3fb27SDimitry Andric // big-endian variants. 18*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 19*06c3fb27SDimitry Andric 20*06c3fb27SDimitry Andric namespace { 21*06c3fb27SDimitry Andric class MipsABIInfo : public ABIInfo { 22*06c3fb27SDimitry Andric bool IsO32; 23*06c3fb27SDimitry Andric const unsigned MinABIStackAlignInBytes, StackAlignInBytes; 24*06c3fb27SDimitry Andric void CoerceToIntArgs(uint64_t TySize, 25*06c3fb27SDimitry Andric SmallVectorImpl<llvm::Type *> &ArgList) const; 26*06c3fb27SDimitry Andric llvm::Type* HandleAggregates(QualType Ty, uint64_t TySize) const; 27*06c3fb27SDimitry Andric llvm::Type* returnAggregateInRegs(QualType RetTy, uint64_t Size) const; 28*06c3fb27SDimitry Andric llvm::Type* getPaddingType(uint64_t Align, uint64_t Offset) const; 29*06c3fb27SDimitry Andric public: 30*06c3fb27SDimitry Andric MipsABIInfo(CodeGenTypes &CGT, bool _IsO32) : 31*06c3fb27SDimitry Andric ABIInfo(CGT), IsO32(_IsO32), MinABIStackAlignInBytes(IsO32 ? 4 : 8), 32*06c3fb27SDimitry Andric StackAlignInBytes(IsO32 ? 8 : 16) {} 33*06c3fb27SDimitry Andric 34*06c3fb27SDimitry Andric ABIArgInfo classifyReturnType(QualType RetTy) const; 35*06c3fb27SDimitry Andric ABIArgInfo classifyArgumentType(QualType RetTy, uint64_t &Offset) const; 36*06c3fb27SDimitry Andric void computeInfo(CGFunctionInfo &FI) const override; 37*06c3fb27SDimitry Andric Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 38*06c3fb27SDimitry Andric QualType Ty) const override; 39*06c3fb27SDimitry Andric ABIArgInfo extendType(QualType Ty) const; 40*06c3fb27SDimitry Andric }; 41*06c3fb27SDimitry Andric 42*06c3fb27SDimitry Andric class MIPSTargetCodeGenInfo : public TargetCodeGenInfo { 43*06c3fb27SDimitry Andric unsigned SizeOfUnwindException; 44*06c3fb27SDimitry Andric public: 45*06c3fb27SDimitry Andric MIPSTargetCodeGenInfo(CodeGenTypes &CGT, bool IsO32) 46*06c3fb27SDimitry Andric : TargetCodeGenInfo(std::make_unique<MipsABIInfo>(CGT, IsO32)), 47*06c3fb27SDimitry Andric SizeOfUnwindException(IsO32 ? 24 : 32) {} 48*06c3fb27SDimitry Andric 49*06c3fb27SDimitry Andric int getDwarfEHStackPointer(CodeGen::CodeGenModule &CGM) const override { 50*06c3fb27SDimitry Andric return 29; 51*06c3fb27SDimitry Andric } 52*06c3fb27SDimitry Andric 53*06c3fb27SDimitry Andric void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, 54*06c3fb27SDimitry Andric CodeGen::CodeGenModule &CGM) const override { 55*06c3fb27SDimitry Andric const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); 56*06c3fb27SDimitry Andric if (!FD) return; 57*06c3fb27SDimitry Andric llvm::Function *Fn = cast<llvm::Function>(GV); 58*06c3fb27SDimitry Andric 59*06c3fb27SDimitry Andric if (FD->hasAttr<MipsLongCallAttr>()) 60*06c3fb27SDimitry Andric Fn->addFnAttr("long-call"); 61*06c3fb27SDimitry Andric else if (FD->hasAttr<MipsShortCallAttr>()) 62*06c3fb27SDimitry Andric Fn->addFnAttr("short-call"); 63*06c3fb27SDimitry Andric 64*06c3fb27SDimitry Andric // Other attributes do not have a meaning for declarations. 65*06c3fb27SDimitry Andric if (GV->isDeclaration()) 66*06c3fb27SDimitry Andric return; 67*06c3fb27SDimitry Andric 68*06c3fb27SDimitry Andric if (FD->hasAttr<Mips16Attr>()) { 69*06c3fb27SDimitry Andric Fn->addFnAttr("mips16"); 70*06c3fb27SDimitry Andric } 71*06c3fb27SDimitry Andric else if (FD->hasAttr<NoMips16Attr>()) { 72*06c3fb27SDimitry Andric Fn->addFnAttr("nomips16"); 73*06c3fb27SDimitry Andric } 74*06c3fb27SDimitry Andric 75*06c3fb27SDimitry Andric if (FD->hasAttr<MicroMipsAttr>()) 76*06c3fb27SDimitry Andric Fn->addFnAttr("micromips"); 77*06c3fb27SDimitry Andric else if (FD->hasAttr<NoMicroMipsAttr>()) 78*06c3fb27SDimitry Andric Fn->addFnAttr("nomicromips"); 79*06c3fb27SDimitry Andric 80*06c3fb27SDimitry Andric const MipsInterruptAttr *Attr = FD->getAttr<MipsInterruptAttr>(); 81*06c3fb27SDimitry Andric if (!Attr) 82*06c3fb27SDimitry Andric return; 83*06c3fb27SDimitry Andric 84*06c3fb27SDimitry Andric const char *Kind; 85*06c3fb27SDimitry Andric switch (Attr->getInterrupt()) { 86*06c3fb27SDimitry Andric case MipsInterruptAttr::eic: Kind = "eic"; break; 87*06c3fb27SDimitry Andric case MipsInterruptAttr::sw0: Kind = "sw0"; break; 88*06c3fb27SDimitry Andric case MipsInterruptAttr::sw1: Kind = "sw1"; break; 89*06c3fb27SDimitry Andric case MipsInterruptAttr::hw0: Kind = "hw0"; break; 90*06c3fb27SDimitry Andric case MipsInterruptAttr::hw1: Kind = "hw1"; break; 91*06c3fb27SDimitry Andric case MipsInterruptAttr::hw2: Kind = "hw2"; break; 92*06c3fb27SDimitry Andric case MipsInterruptAttr::hw3: Kind = "hw3"; break; 93*06c3fb27SDimitry Andric case MipsInterruptAttr::hw4: Kind = "hw4"; break; 94*06c3fb27SDimitry Andric case MipsInterruptAttr::hw5: Kind = "hw5"; break; 95*06c3fb27SDimitry Andric } 96*06c3fb27SDimitry Andric 97*06c3fb27SDimitry Andric Fn->addFnAttr("interrupt", Kind); 98*06c3fb27SDimitry Andric 99*06c3fb27SDimitry Andric } 100*06c3fb27SDimitry Andric 101*06c3fb27SDimitry Andric bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, 102*06c3fb27SDimitry Andric llvm::Value *Address) const override; 103*06c3fb27SDimitry Andric 104*06c3fb27SDimitry Andric unsigned getSizeOfUnwindException() const override { 105*06c3fb27SDimitry Andric return SizeOfUnwindException; 106*06c3fb27SDimitry Andric } 107*06c3fb27SDimitry Andric }; 108*06c3fb27SDimitry Andric } 109*06c3fb27SDimitry Andric 110*06c3fb27SDimitry Andric void MipsABIInfo::CoerceToIntArgs( 111*06c3fb27SDimitry Andric uint64_t TySize, SmallVectorImpl<llvm::Type *> &ArgList) const { 112*06c3fb27SDimitry Andric llvm::IntegerType *IntTy = 113*06c3fb27SDimitry Andric llvm::IntegerType::get(getVMContext(), MinABIStackAlignInBytes * 8); 114*06c3fb27SDimitry Andric 115*06c3fb27SDimitry Andric // Add (TySize / MinABIStackAlignInBytes) args of IntTy. 116*06c3fb27SDimitry Andric for (unsigned N = TySize / (MinABIStackAlignInBytes * 8); N; --N) 117*06c3fb27SDimitry Andric ArgList.push_back(IntTy); 118*06c3fb27SDimitry Andric 119*06c3fb27SDimitry Andric // If necessary, add one more integer type to ArgList. 120*06c3fb27SDimitry Andric unsigned R = TySize % (MinABIStackAlignInBytes * 8); 121*06c3fb27SDimitry Andric 122*06c3fb27SDimitry Andric if (R) 123*06c3fb27SDimitry Andric ArgList.push_back(llvm::IntegerType::get(getVMContext(), R)); 124*06c3fb27SDimitry Andric } 125*06c3fb27SDimitry Andric 126*06c3fb27SDimitry Andric // In N32/64, an aligned double precision floating point field is passed in 127*06c3fb27SDimitry Andric // a register. 128*06c3fb27SDimitry Andric llvm::Type* MipsABIInfo::HandleAggregates(QualType Ty, uint64_t TySize) const { 129*06c3fb27SDimitry Andric SmallVector<llvm::Type*, 8> ArgList, IntArgList; 130*06c3fb27SDimitry Andric 131*06c3fb27SDimitry Andric if (IsO32) { 132*06c3fb27SDimitry Andric CoerceToIntArgs(TySize, ArgList); 133*06c3fb27SDimitry Andric return llvm::StructType::get(getVMContext(), ArgList); 134*06c3fb27SDimitry Andric } 135*06c3fb27SDimitry Andric 136*06c3fb27SDimitry Andric if (Ty->isComplexType()) 137*06c3fb27SDimitry Andric return CGT.ConvertType(Ty); 138*06c3fb27SDimitry Andric 139*06c3fb27SDimitry Andric const RecordType *RT = Ty->getAs<RecordType>(); 140*06c3fb27SDimitry Andric 141*06c3fb27SDimitry Andric // Unions/vectors are passed in integer registers. 142*06c3fb27SDimitry Andric if (!RT || !RT->isStructureOrClassType()) { 143*06c3fb27SDimitry Andric CoerceToIntArgs(TySize, ArgList); 144*06c3fb27SDimitry Andric return llvm::StructType::get(getVMContext(), ArgList); 145*06c3fb27SDimitry Andric } 146*06c3fb27SDimitry Andric 147*06c3fb27SDimitry Andric const RecordDecl *RD = RT->getDecl(); 148*06c3fb27SDimitry Andric const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); 149*06c3fb27SDimitry Andric assert(!(TySize % 8) && "Size of structure must be multiple of 8."); 150*06c3fb27SDimitry Andric 151*06c3fb27SDimitry Andric uint64_t LastOffset = 0; 152*06c3fb27SDimitry Andric unsigned idx = 0; 153*06c3fb27SDimitry Andric llvm::IntegerType *I64 = llvm::IntegerType::get(getVMContext(), 64); 154*06c3fb27SDimitry Andric 155*06c3fb27SDimitry Andric // Iterate over fields in the struct/class and check if there are any aligned 156*06c3fb27SDimitry Andric // double fields. 157*06c3fb27SDimitry Andric for (RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); 158*06c3fb27SDimitry Andric i != e; ++i, ++idx) { 159*06c3fb27SDimitry Andric const QualType Ty = i->getType(); 160*06c3fb27SDimitry Andric const BuiltinType *BT = Ty->getAs<BuiltinType>(); 161*06c3fb27SDimitry Andric 162*06c3fb27SDimitry Andric if (!BT || BT->getKind() != BuiltinType::Double) 163*06c3fb27SDimitry Andric continue; 164*06c3fb27SDimitry Andric 165*06c3fb27SDimitry Andric uint64_t Offset = Layout.getFieldOffset(idx); 166*06c3fb27SDimitry Andric if (Offset % 64) // Ignore doubles that are not aligned. 167*06c3fb27SDimitry Andric continue; 168*06c3fb27SDimitry Andric 169*06c3fb27SDimitry Andric // Add ((Offset - LastOffset) / 64) args of type i64. 170*06c3fb27SDimitry Andric for (unsigned j = (Offset - LastOffset) / 64; j > 0; --j) 171*06c3fb27SDimitry Andric ArgList.push_back(I64); 172*06c3fb27SDimitry Andric 173*06c3fb27SDimitry Andric // Add double type. 174*06c3fb27SDimitry Andric ArgList.push_back(llvm::Type::getDoubleTy(getVMContext())); 175*06c3fb27SDimitry Andric LastOffset = Offset + 64; 176*06c3fb27SDimitry Andric } 177*06c3fb27SDimitry Andric 178*06c3fb27SDimitry Andric CoerceToIntArgs(TySize - LastOffset, IntArgList); 179*06c3fb27SDimitry Andric ArgList.append(IntArgList.begin(), IntArgList.end()); 180*06c3fb27SDimitry Andric 181*06c3fb27SDimitry Andric return llvm::StructType::get(getVMContext(), ArgList); 182*06c3fb27SDimitry Andric } 183*06c3fb27SDimitry Andric 184*06c3fb27SDimitry Andric llvm::Type *MipsABIInfo::getPaddingType(uint64_t OrigOffset, 185*06c3fb27SDimitry Andric uint64_t Offset) const { 186*06c3fb27SDimitry Andric if (OrigOffset + MinABIStackAlignInBytes > Offset) 187*06c3fb27SDimitry Andric return nullptr; 188*06c3fb27SDimitry Andric 189*06c3fb27SDimitry Andric return llvm::IntegerType::get(getVMContext(), (Offset - OrigOffset) * 8); 190*06c3fb27SDimitry Andric } 191*06c3fb27SDimitry Andric 192*06c3fb27SDimitry Andric ABIArgInfo 193*06c3fb27SDimitry Andric MipsABIInfo::classifyArgumentType(QualType Ty, uint64_t &Offset) const { 194*06c3fb27SDimitry Andric Ty = useFirstFieldIfTransparentUnion(Ty); 195*06c3fb27SDimitry Andric 196*06c3fb27SDimitry Andric uint64_t OrigOffset = Offset; 197*06c3fb27SDimitry Andric uint64_t TySize = getContext().getTypeSize(Ty); 198*06c3fb27SDimitry Andric uint64_t Align = getContext().getTypeAlign(Ty) / 8; 199*06c3fb27SDimitry Andric 200*06c3fb27SDimitry Andric Align = std::clamp(Align, (uint64_t)MinABIStackAlignInBytes, 201*06c3fb27SDimitry Andric (uint64_t)StackAlignInBytes); 202*06c3fb27SDimitry Andric unsigned CurrOffset = llvm::alignTo(Offset, Align); 203*06c3fb27SDimitry Andric Offset = CurrOffset + llvm::alignTo(TySize, Align * 8) / 8; 204*06c3fb27SDimitry Andric 205*06c3fb27SDimitry Andric if (isAggregateTypeForABI(Ty) || Ty->isVectorType()) { 206*06c3fb27SDimitry Andric // Ignore empty aggregates. 207*06c3fb27SDimitry Andric if (TySize == 0) 208*06c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 209*06c3fb27SDimitry Andric 210*06c3fb27SDimitry Andric if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { 211*06c3fb27SDimitry Andric Offset = OrigOffset + MinABIStackAlignInBytes; 212*06c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty, RAA == CGCXXABI::RAA_DirectInMemory); 213*06c3fb27SDimitry Andric } 214*06c3fb27SDimitry Andric 215*06c3fb27SDimitry Andric // If we have reached here, aggregates are passed directly by coercing to 216*06c3fb27SDimitry Andric // another structure type. Padding is inserted if the offset of the 217*06c3fb27SDimitry Andric // aggregate is unaligned. 218*06c3fb27SDimitry Andric ABIArgInfo ArgInfo = 219*06c3fb27SDimitry Andric ABIArgInfo::getDirect(HandleAggregates(Ty, TySize), 0, 220*06c3fb27SDimitry Andric getPaddingType(OrigOffset, CurrOffset)); 221*06c3fb27SDimitry Andric ArgInfo.setInReg(true); 222*06c3fb27SDimitry Andric return ArgInfo; 223*06c3fb27SDimitry Andric } 224*06c3fb27SDimitry Andric 225*06c3fb27SDimitry Andric // Treat an enum type as its underlying type. 226*06c3fb27SDimitry Andric if (const EnumType *EnumTy = Ty->getAs<EnumType>()) 227*06c3fb27SDimitry Andric Ty = EnumTy->getDecl()->getIntegerType(); 228*06c3fb27SDimitry Andric 229*06c3fb27SDimitry Andric // Make sure we pass indirectly things that are too large. 230*06c3fb27SDimitry Andric if (const auto *EIT = Ty->getAs<BitIntType>()) 231*06c3fb27SDimitry Andric if (EIT->getNumBits() > 128 || 232*06c3fb27SDimitry Andric (EIT->getNumBits() > 64 && 233*06c3fb27SDimitry Andric !getContext().getTargetInfo().hasInt128Type())) 234*06c3fb27SDimitry Andric return getNaturalAlignIndirect(Ty); 235*06c3fb27SDimitry Andric 236*06c3fb27SDimitry Andric // All integral types are promoted to the GPR width. 237*06c3fb27SDimitry Andric if (Ty->isIntegralOrEnumerationType()) 238*06c3fb27SDimitry Andric return extendType(Ty); 239*06c3fb27SDimitry Andric 240*06c3fb27SDimitry Andric return ABIArgInfo::getDirect( 241*06c3fb27SDimitry Andric nullptr, 0, IsO32 ? nullptr : getPaddingType(OrigOffset, CurrOffset)); 242*06c3fb27SDimitry Andric } 243*06c3fb27SDimitry Andric 244*06c3fb27SDimitry Andric llvm::Type* 245*06c3fb27SDimitry Andric MipsABIInfo::returnAggregateInRegs(QualType RetTy, uint64_t Size) const { 246*06c3fb27SDimitry Andric const RecordType *RT = RetTy->getAs<RecordType>(); 247*06c3fb27SDimitry Andric SmallVector<llvm::Type*, 8> RTList; 248*06c3fb27SDimitry Andric 249*06c3fb27SDimitry Andric if (RT && RT->isStructureOrClassType()) { 250*06c3fb27SDimitry Andric const RecordDecl *RD = RT->getDecl(); 251*06c3fb27SDimitry Andric const ASTRecordLayout &Layout = getContext().getASTRecordLayout(RD); 252*06c3fb27SDimitry Andric unsigned FieldCnt = Layout.getFieldCount(); 253*06c3fb27SDimitry Andric 254*06c3fb27SDimitry Andric // N32/64 returns struct/classes in floating point registers if the 255*06c3fb27SDimitry Andric // following conditions are met: 256*06c3fb27SDimitry Andric // 1. The size of the struct/class is no larger than 128-bit. 257*06c3fb27SDimitry Andric // 2. The struct/class has one or two fields all of which are floating 258*06c3fb27SDimitry Andric // point types. 259*06c3fb27SDimitry Andric // 3. The offset of the first field is zero (this follows what gcc does). 260*06c3fb27SDimitry Andric // 261*06c3fb27SDimitry Andric // Any other composite results are returned in integer registers. 262*06c3fb27SDimitry Andric // 263*06c3fb27SDimitry Andric if (FieldCnt && (FieldCnt <= 2) && !Layout.getFieldOffset(0)) { 264*06c3fb27SDimitry Andric RecordDecl::field_iterator b = RD->field_begin(), e = RD->field_end(); 265*06c3fb27SDimitry Andric for (; b != e; ++b) { 266*06c3fb27SDimitry Andric const BuiltinType *BT = b->getType()->getAs<BuiltinType>(); 267*06c3fb27SDimitry Andric 268*06c3fb27SDimitry Andric if (!BT || !BT->isFloatingPoint()) 269*06c3fb27SDimitry Andric break; 270*06c3fb27SDimitry Andric 271*06c3fb27SDimitry Andric RTList.push_back(CGT.ConvertType(b->getType())); 272*06c3fb27SDimitry Andric } 273*06c3fb27SDimitry Andric 274*06c3fb27SDimitry Andric if (b == e) 275*06c3fb27SDimitry Andric return llvm::StructType::get(getVMContext(), RTList, 276*06c3fb27SDimitry Andric RD->hasAttr<PackedAttr>()); 277*06c3fb27SDimitry Andric 278*06c3fb27SDimitry Andric RTList.clear(); 279*06c3fb27SDimitry Andric } 280*06c3fb27SDimitry Andric } 281*06c3fb27SDimitry Andric 282*06c3fb27SDimitry Andric CoerceToIntArgs(Size, RTList); 283*06c3fb27SDimitry Andric return llvm::StructType::get(getVMContext(), RTList); 284*06c3fb27SDimitry Andric } 285*06c3fb27SDimitry Andric 286*06c3fb27SDimitry Andric ABIArgInfo MipsABIInfo::classifyReturnType(QualType RetTy) const { 287*06c3fb27SDimitry Andric uint64_t Size = getContext().getTypeSize(RetTy); 288*06c3fb27SDimitry Andric 289*06c3fb27SDimitry Andric if (RetTy->isVoidType()) 290*06c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 291*06c3fb27SDimitry Andric 292*06c3fb27SDimitry Andric // O32 doesn't treat zero-sized structs differently from other structs. 293*06c3fb27SDimitry Andric // However, N32/N64 ignores zero sized return values. 294*06c3fb27SDimitry Andric if (!IsO32 && Size == 0) 295*06c3fb27SDimitry Andric return ABIArgInfo::getIgnore(); 296*06c3fb27SDimitry Andric 297*06c3fb27SDimitry Andric if (isAggregateTypeForABI(RetTy) || RetTy->isVectorType()) { 298*06c3fb27SDimitry Andric if (Size <= 128) { 299*06c3fb27SDimitry Andric if (RetTy->isAnyComplexType()) 300*06c3fb27SDimitry Andric return ABIArgInfo::getDirect(); 301*06c3fb27SDimitry Andric 302*06c3fb27SDimitry Andric // O32 returns integer vectors in registers and N32/N64 returns all small 303*06c3fb27SDimitry Andric // aggregates in registers. 304*06c3fb27SDimitry Andric if (!IsO32 || 305*06c3fb27SDimitry Andric (RetTy->isVectorType() && !RetTy->hasFloatingRepresentation())) { 306*06c3fb27SDimitry Andric ABIArgInfo ArgInfo = 307*06c3fb27SDimitry Andric ABIArgInfo::getDirect(returnAggregateInRegs(RetTy, Size)); 308*06c3fb27SDimitry Andric ArgInfo.setInReg(true); 309*06c3fb27SDimitry Andric return ArgInfo; 310*06c3fb27SDimitry Andric } 311*06c3fb27SDimitry Andric } 312*06c3fb27SDimitry Andric 313*06c3fb27SDimitry Andric return getNaturalAlignIndirect(RetTy); 314*06c3fb27SDimitry Andric } 315*06c3fb27SDimitry Andric 316*06c3fb27SDimitry Andric // Treat an enum type as its underlying type. 317*06c3fb27SDimitry Andric if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) 318*06c3fb27SDimitry Andric RetTy = EnumTy->getDecl()->getIntegerType(); 319*06c3fb27SDimitry Andric 320*06c3fb27SDimitry Andric // Make sure we pass indirectly things that are too large. 321*06c3fb27SDimitry Andric if (const auto *EIT = RetTy->getAs<BitIntType>()) 322*06c3fb27SDimitry Andric if (EIT->getNumBits() > 128 || 323*06c3fb27SDimitry Andric (EIT->getNumBits() > 64 && 324*06c3fb27SDimitry Andric !getContext().getTargetInfo().hasInt128Type())) 325*06c3fb27SDimitry Andric return getNaturalAlignIndirect(RetTy); 326*06c3fb27SDimitry Andric 327*06c3fb27SDimitry Andric if (isPromotableIntegerTypeForABI(RetTy)) 328*06c3fb27SDimitry Andric return ABIArgInfo::getExtend(RetTy); 329*06c3fb27SDimitry Andric 330*06c3fb27SDimitry Andric if ((RetTy->isUnsignedIntegerOrEnumerationType() || 331*06c3fb27SDimitry Andric RetTy->isSignedIntegerOrEnumerationType()) && Size == 32 && !IsO32) 332*06c3fb27SDimitry Andric return ABIArgInfo::getSignExtend(RetTy); 333*06c3fb27SDimitry Andric 334*06c3fb27SDimitry Andric return ABIArgInfo::getDirect(); 335*06c3fb27SDimitry Andric } 336*06c3fb27SDimitry Andric 337*06c3fb27SDimitry Andric void MipsABIInfo::computeInfo(CGFunctionInfo &FI) const { 338*06c3fb27SDimitry Andric ABIArgInfo &RetInfo = FI.getReturnInfo(); 339*06c3fb27SDimitry Andric if (!getCXXABI().classifyReturnType(FI)) 340*06c3fb27SDimitry Andric RetInfo = classifyReturnType(FI.getReturnType()); 341*06c3fb27SDimitry Andric 342*06c3fb27SDimitry Andric // Check if a pointer to an aggregate is passed as a hidden argument. 343*06c3fb27SDimitry Andric uint64_t Offset = RetInfo.isIndirect() ? MinABIStackAlignInBytes : 0; 344*06c3fb27SDimitry Andric 345*06c3fb27SDimitry Andric for (auto &I : FI.arguments()) 346*06c3fb27SDimitry Andric I.info = classifyArgumentType(I.type, Offset); 347*06c3fb27SDimitry Andric } 348*06c3fb27SDimitry Andric 349*06c3fb27SDimitry Andric Address MipsABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, 350*06c3fb27SDimitry Andric QualType OrigTy) const { 351*06c3fb27SDimitry Andric QualType Ty = OrigTy; 352*06c3fb27SDimitry Andric 353*06c3fb27SDimitry Andric // Integer arguments are promoted to 32-bit on O32 and 64-bit on N32/N64. 354*06c3fb27SDimitry Andric // Pointers are also promoted in the same way but this only matters for N32. 355*06c3fb27SDimitry Andric unsigned SlotSizeInBits = IsO32 ? 32 : 64; 356*06c3fb27SDimitry Andric unsigned PtrWidth = getTarget().getPointerWidth(LangAS::Default); 357*06c3fb27SDimitry Andric bool DidPromote = false; 358*06c3fb27SDimitry Andric if ((Ty->isIntegerType() && 359*06c3fb27SDimitry Andric getContext().getIntWidth(Ty) < SlotSizeInBits) || 360*06c3fb27SDimitry Andric (Ty->isPointerType() && PtrWidth < SlotSizeInBits)) { 361*06c3fb27SDimitry Andric DidPromote = true; 362*06c3fb27SDimitry Andric Ty = getContext().getIntTypeForBitwidth(SlotSizeInBits, 363*06c3fb27SDimitry Andric Ty->isSignedIntegerType()); 364*06c3fb27SDimitry Andric } 365*06c3fb27SDimitry Andric 366*06c3fb27SDimitry Andric auto TyInfo = getContext().getTypeInfoInChars(Ty); 367*06c3fb27SDimitry Andric 368*06c3fb27SDimitry Andric // The alignment of things in the argument area is never larger than 369*06c3fb27SDimitry Andric // StackAlignInBytes. 370*06c3fb27SDimitry Andric TyInfo.Align = 371*06c3fb27SDimitry Andric std::min(TyInfo.Align, CharUnits::fromQuantity(StackAlignInBytes)); 372*06c3fb27SDimitry Andric 373*06c3fb27SDimitry Andric // MinABIStackAlignInBytes is the size of argument slots on the stack. 374*06c3fb27SDimitry Andric CharUnits ArgSlotSize = CharUnits::fromQuantity(MinABIStackAlignInBytes); 375*06c3fb27SDimitry Andric 376*06c3fb27SDimitry Andric Address Addr = emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, 377*06c3fb27SDimitry Andric TyInfo, ArgSlotSize, /*AllowHigherAlign*/ true); 378*06c3fb27SDimitry Andric 379*06c3fb27SDimitry Andric 380*06c3fb27SDimitry Andric // If there was a promotion, "unpromote" into a temporary. 381*06c3fb27SDimitry Andric // TODO: can we just use a pointer into a subset of the original slot? 382*06c3fb27SDimitry Andric if (DidPromote) { 383*06c3fb27SDimitry Andric Address Temp = CGF.CreateMemTemp(OrigTy, "vaarg.promotion-temp"); 384*06c3fb27SDimitry Andric llvm::Value *Promoted = CGF.Builder.CreateLoad(Addr); 385*06c3fb27SDimitry Andric 386*06c3fb27SDimitry Andric // Truncate down to the right width. 387*06c3fb27SDimitry Andric llvm::Type *IntTy = (OrigTy->isIntegerType() ? Temp.getElementType() 388*06c3fb27SDimitry Andric : CGF.IntPtrTy); 389*06c3fb27SDimitry Andric llvm::Value *V = CGF.Builder.CreateTrunc(Promoted, IntTy); 390*06c3fb27SDimitry Andric if (OrigTy->isPointerType()) 391*06c3fb27SDimitry Andric V = CGF.Builder.CreateIntToPtr(V, Temp.getElementType()); 392*06c3fb27SDimitry Andric 393*06c3fb27SDimitry Andric CGF.Builder.CreateStore(V, Temp); 394*06c3fb27SDimitry Andric Addr = Temp; 395*06c3fb27SDimitry Andric } 396*06c3fb27SDimitry Andric 397*06c3fb27SDimitry Andric return Addr; 398*06c3fb27SDimitry Andric } 399*06c3fb27SDimitry Andric 400*06c3fb27SDimitry Andric ABIArgInfo MipsABIInfo::extendType(QualType Ty) const { 401*06c3fb27SDimitry Andric int TySize = getContext().getTypeSize(Ty); 402*06c3fb27SDimitry Andric 403*06c3fb27SDimitry Andric // MIPS64 ABI requires unsigned 32 bit integers to be sign extended. 404*06c3fb27SDimitry Andric if (Ty->isUnsignedIntegerOrEnumerationType() && TySize == 32) 405*06c3fb27SDimitry Andric return ABIArgInfo::getSignExtend(Ty); 406*06c3fb27SDimitry Andric 407*06c3fb27SDimitry Andric return ABIArgInfo::getExtend(Ty); 408*06c3fb27SDimitry Andric } 409*06c3fb27SDimitry Andric 410*06c3fb27SDimitry Andric bool 411*06c3fb27SDimitry Andric MIPSTargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, 412*06c3fb27SDimitry Andric llvm::Value *Address) const { 413*06c3fb27SDimitry Andric // This information comes from gcc's implementation, which seems to 414*06c3fb27SDimitry Andric // as canonical as it gets. 415*06c3fb27SDimitry Andric 416*06c3fb27SDimitry Andric // Everything on MIPS is 4 bytes. Double-precision FP registers 417*06c3fb27SDimitry Andric // are aliased to pairs of single-precision FP registers. 418*06c3fb27SDimitry Andric llvm::Value *Four8 = llvm::ConstantInt::get(CGF.Int8Ty, 4); 419*06c3fb27SDimitry Andric 420*06c3fb27SDimitry Andric // 0-31 are the general purpose registers, $0 - $31. 421*06c3fb27SDimitry Andric // 32-63 are the floating-point registers, $f0 - $f31. 422*06c3fb27SDimitry Andric // 64 and 65 are the multiply/divide registers, $hi and $lo. 423*06c3fb27SDimitry Andric // 66 is the (notional, I think) register for signal-handler return. 424*06c3fb27SDimitry Andric AssignToArrayRange(CGF.Builder, Address, Four8, 0, 65); 425*06c3fb27SDimitry Andric 426*06c3fb27SDimitry Andric // 67-74 are the floating-point status registers, $fcc0 - $fcc7. 427*06c3fb27SDimitry Andric // They are one bit wide and ignored here. 428*06c3fb27SDimitry Andric 429*06c3fb27SDimitry Andric // 80-111 are the coprocessor 0 registers, $c0r0 - $c0r31. 430*06c3fb27SDimitry Andric // (coprocessor 1 is the FP unit) 431*06c3fb27SDimitry Andric // 112-143 are the coprocessor 2 registers, $c2r0 - $c2r31. 432*06c3fb27SDimitry Andric // 144-175 are the coprocessor 3 registers, $c3r0 - $c3r31. 433*06c3fb27SDimitry Andric // 176-181 are the DSP accumulator registers. 434*06c3fb27SDimitry Andric AssignToArrayRange(CGF.Builder, Address, Four8, 80, 181); 435*06c3fb27SDimitry Andric return false; 436*06c3fb27SDimitry Andric } 437*06c3fb27SDimitry Andric 438*06c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo> 439*06c3fb27SDimitry Andric CodeGen::createMIPSTargetCodeGenInfo(CodeGenModule &CGM, bool IsOS32) { 440*06c3fb27SDimitry Andric return std::make_unique<MIPSTargetCodeGenInfo>(CGM.getTypes(), IsOS32); 441*06c3fb27SDimitry Andric } 442