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 | |