| 1 | //===---- MipsCCState.cpp - CCState with Mips specific extensions ---------===// |
| 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 "MipsCCState.h" |
| 10 | #include "MipsSubtarget.h" |
| 11 | #include "llvm/IR/Module.h" |
| 12 | |
| 13 | using namespace llvm; |
| 14 | |
| 15 | bool MipsCCState::isF128SoftLibCall(const char *CallSym) { |
| 16 | const char *const LibCalls[] = { |
| 17 | "__addtf3" , "__divtf3" , "__eqtf2" , "__extenddftf2" , |
| 18 | "__extendsftf2" , "__fixtfdi" , "__fixtfsi" , "__fixtfti" , |
| 19 | "__fixunstfdi" , "__fixunstfsi" , "__fixunstfti" , "__floatditf" , |
| 20 | "__floatsitf" , "__floattitf" , "__floatunditf" , "__floatunsitf" , |
| 21 | "__floatuntitf" , "__getf2" , "__gttf2" , "__letf2" , |
| 22 | "__lttf2" , "__multf3" , "__netf2" , "__powitf2" , |
| 23 | "__subtf3" , "__trunctfdf2" , "__trunctfsf2" , "__unordtf2" , |
| 24 | "ceill" , "copysignl" , "cosl" , "exp2l" , |
| 25 | "expl" , "floorl" , "fmal" , "fmaxl" , |
| 26 | "fmodl" , "log10l" , "log2l" , "logl" , |
| 27 | "nearbyintl" , "powl" , "rintl" , "roundl" , |
| 28 | "sinl" , "sqrtl" , "truncl" }; |
| 29 | |
| 30 | // Check that LibCalls is sorted alphabetically. |
| 31 | auto Comp = [](const char *S1, const char *S2) { return strcmp(s1: S1, s2: S2) < 0; }; |
| 32 | assert(llvm::is_sorted(LibCalls, Comp)); |
| 33 | return llvm::binary_search(Range: LibCalls, Value&: CallSym, C: Comp); |
| 34 | } |
| 35 | |
| 36 | /// This function returns true if Ty is fp128, {f128} or i128 which was |
| 37 | /// originally a fp128. |
| 38 | bool MipsCCState::originalTypeIsF128(const Type *Ty, const char *Func) { |
| 39 | if (Ty->isFP128Ty()) |
| 40 | return true; |
| 41 | |
| 42 | if (Ty->isStructTy() && Ty->getStructNumElements() == 1 && |
| 43 | Ty->getStructElementType(N: 0)->isFP128Ty()) |
| 44 | return true; |
| 45 | |
| 46 | // If the Ty is i128 and the function being called is a long double emulation |
| 47 | // routine, then the original type is f128. |
| 48 | // FIXME: This is unsound because these functions could be indirectly called |
| 49 | return (Func && Ty->isIntegerTy(Bitwidth: 128) && isF128SoftLibCall(CallSym: Func)); |
| 50 | } |
| 51 | |
| 52 | /// Return true if the original type was vXfXX. |
| 53 | bool MipsCCState::originalEVTTypeIsVectorFloat(EVT Ty) { |
| 54 | if (Ty.isVector() && Ty.getVectorElementType().isFloatingPoint()) |
| 55 | return true; |
| 56 | |
| 57 | return false; |
| 58 | } |
| 59 | |
| 60 | /// Return true if the original type was vXfXX / vXfXX. |
| 61 | bool MipsCCState::originalTypeIsVectorFloat(const Type *Ty) { |
| 62 | if (Ty->isVectorTy() && Ty->isFPOrFPVectorTy()) |
| 63 | return true; |
| 64 | |
| 65 | return false; |
| 66 | } |
| 67 | |
| 68 | MipsCCState::SpecialCallingConvType |
| 69 | MipsCCState::getSpecialCallingConvForCallee(const SDNode *Callee, |
| 70 | const MipsSubtarget &Subtarget) { |
| 71 | MipsCCState::SpecialCallingConvType SpecialCallingConv = NoSpecialCallingConv; |
| 72 | if (Subtarget.inMips16HardFloat()) { |
| 73 | if (const GlobalAddressSDNode *G = |
| 74 | dyn_cast<const GlobalAddressSDNode>(Val: Callee)) { |
| 75 | llvm::StringRef Sym = G->getGlobal()->getName(); |
| 76 | Function *F = G->getGlobal()->getParent()->getFunction(Name: Sym); |
| 77 | if (F && F->hasFnAttribute(Kind: "__Mips16RetHelper" )) { |
| 78 | SpecialCallingConv = Mips16RetHelperConv; |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | return SpecialCallingConv; |
| 83 | } |
| 84 | |
| 85 | void MipsCCState::PreAnalyzeCallResultForF128( |
| 86 | const SmallVectorImpl<ISD::InputArg> &Ins, |
| 87 | const Type *RetTy, const char *Call) { |
| 88 | for (unsigned i = 0; i < Ins.size(); ++i) { |
| 89 | OriginalArgWasF128.push_back( |
| 90 | Elt: originalTypeIsF128(Ty: RetTy, Func: Call)); |
| 91 | OriginalArgWasFloat.push_back(Elt: RetTy->isFloatingPointTy()); |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | /// Identify lowered values that originated from f128 or float arguments and |
| 96 | /// record this for use by RetCC_MipsN. |
| 97 | void MipsCCState::PreAnalyzeCallReturnForF128( |
| 98 | const SmallVectorImpl<ISD::OutputArg> &Outs, const Type *RetTy) { |
| 99 | for (unsigned i = 0; i < Outs.size(); ++i) { |
| 100 | OriginalArgWasF128.push_back( |
| 101 | Elt: originalTypeIsF128(Ty: RetTy, Func: nullptr)); |
| 102 | OriginalArgWasFloat.push_back( |
| 103 | Elt: RetTy->isFloatingPointTy()); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | /// Identify lower values that originated from vXfXX and record |
| 108 | /// this. |
| 109 | void MipsCCState::PreAnalyzeCallResultForVectorFloat( |
| 110 | const SmallVectorImpl<ISD::InputArg> &Ins, const Type *RetTy) { |
| 111 | for (unsigned i = 0; i < Ins.size(); ++i) { |
| 112 | OriginalRetWasFloatVector.push_back(Elt: originalTypeIsVectorFloat(Ty: RetTy)); |
| 113 | } |
| 114 | } |
| 115 | |
| 116 | /// Identify lowered values that originated from vXfXX arguments and record |
| 117 | /// this. |
| 118 | void MipsCCState::PreAnalyzeReturnForVectorFloat( |
| 119 | const SmallVectorImpl<ISD::OutputArg> &Outs) { |
| 120 | for (unsigned i = 0; i < Outs.size(); ++i) { |
| 121 | ISD::OutputArg Out = Outs[i]; |
| 122 | OriginalRetWasFloatVector.push_back( |
| 123 | Elt: originalEVTTypeIsVectorFloat(Ty: Out.ArgVT)); |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | void MipsCCState::PreAnalyzeReturnValue(EVT ArgVT) { |
| 128 | OriginalRetWasFloatVector.push_back(Elt: originalEVTTypeIsVectorFloat(Ty: ArgVT)); |
| 129 | } |
| 130 | |
| 131 | void MipsCCState::PreAnalyzeCallOperand(const Type *ArgTy, bool IsFixed, |
| 132 | const char *Func) { |
| 133 | OriginalArgWasF128.push_back(Elt: originalTypeIsF128(Ty: ArgTy, Func)); |
| 134 | OriginalArgWasFloat.push_back(Elt: ArgTy->isFloatingPointTy()); |
| 135 | OriginalArgWasFloatVector.push_back(Elt: ArgTy->isVectorTy()); |
| 136 | CallOperandIsFixed.push_back(Elt: IsFixed); |
| 137 | } |
| 138 | |
| 139 | /// Identify lowered values that originated from f128, float and sret to vXfXX |
| 140 | /// arguments and record this. |
| 141 | void MipsCCState::PreAnalyzeCallOperands( |
| 142 | const SmallVectorImpl<ISD::OutputArg> &Outs, |
| 143 | std::vector<TargetLowering::ArgListEntry> &FuncArgs, |
| 144 | const char *Func) { |
| 145 | for (unsigned i = 0; i < Outs.size(); ++i) { |
| 146 | TargetLowering::ArgListEntry FuncArg = FuncArgs[Outs[i].OrigArgIndex]; |
| 147 | |
| 148 | OriginalArgWasF128.push_back(Elt: originalTypeIsF128(Ty: FuncArg.Ty, Func)); |
| 149 | OriginalArgWasFloat.push_back(Elt: FuncArg.Ty->isFloatingPointTy()); |
| 150 | OriginalArgWasFloatVector.push_back(Elt: FuncArg.Ty->isVectorTy()); |
| 151 | CallOperandIsFixed.push_back(Elt: Outs[i].IsFixed); |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | void MipsCCState::PreAnalyzeFormalArgument(const Type *ArgTy, |
| 156 | ISD::ArgFlagsTy Flags) { |
| 157 | // SRet arguments cannot originate from f128 or {f128} returns so we just |
| 158 | // push false. We have to handle this specially since SRet arguments |
| 159 | // aren't mapped to an original argument. |
| 160 | if (Flags.isSRet()) { |
| 161 | OriginalArgWasF128.push_back(Elt: false); |
| 162 | OriginalArgWasFloat.push_back(Elt: false); |
| 163 | OriginalArgWasFloatVector.push_back(Elt: false); |
| 164 | return; |
| 165 | } |
| 166 | |
| 167 | OriginalArgWasF128.push_back(Elt: originalTypeIsF128(Ty: ArgTy, Func: nullptr)); |
| 168 | OriginalArgWasFloat.push_back(Elt: ArgTy->isFloatingPointTy()); |
| 169 | |
| 170 | // The MIPS vector ABI exhibits a corner case of sorts or quirk; if the |
| 171 | // first argument is actually an SRet pointer to a vector, then the next |
| 172 | // argument slot is $a2. |
| 173 | OriginalArgWasFloatVector.push_back(Elt: ArgTy->isVectorTy()); |
| 174 | } |
| 175 | |
| 176 | /// Identify lowered values that originated from f128, float and vXfXX arguments |
| 177 | /// and record this. |
| 178 | void MipsCCState::PreAnalyzeFormalArgumentsForF128( |
| 179 | const SmallVectorImpl<ISD::InputArg> &Ins) { |
| 180 | const MachineFunction &MF = getMachineFunction(); |
| 181 | for (unsigned i = 0; i < Ins.size(); ++i) { |
| 182 | Function::const_arg_iterator FuncArg = MF.getFunction().arg_begin(); |
| 183 | |
| 184 | // SRet arguments cannot originate from f128 or {f128} returns so we just |
| 185 | // push false. We have to handle this specially since SRet arguments |
| 186 | // aren't mapped to an original argument. |
| 187 | if (Ins[i].Flags.isSRet()) { |
| 188 | OriginalArgWasF128.push_back(Elt: false); |
| 189 | OriginalArgWasFloat.push_back(Elt: false); |
| 190 | OriginalArgWasFloatVector.push_back(Elt: false); |
| 191 | continue; |
| 192 | } |
| 193 | |
| 194 | assert(Ins[i].getOrigArgIndex() < MF.getFunction().arg_size()); |
| 195 | std::advance(i&: FuncArg, n: Ins[i].getOrigArgIndex()); |
| 196 | |
| 197 | OriginalArgWasF128.push_back( |
| 198 | Elt: originalTypeIsF128(Ty: FuncArg->getType(), Func: nullptr)); |
| 199 | OriginalArgWasFloat.push_back(Elt: FuncArg->getType()->isFloatingPointTy()); |
| 200 | |
| 201 | // The MIPS vector ABI exhibits a corner case of sorts or quirk; if the |
| 202 | // first argument is actually an SRet pointer to a vector, then the next |
| 203 | // argument slot is $a2. |
| 204 | OriginalArgWasFloatVector.push_back(Elt: FuncArg->getType()->isVectorTy()); |
| 205 | } |
| 206 | } |
| 207 | |