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 std::binary_search(first: std::begin(arr: LibCalls), last: std::end(arr: LibCalls), val: CallSym, |
34 | comp: Comp); |
35 | } |
36 | |
37 | /// This function returns true if Ty is fp128, {f128} or i128 which was |
38 | /// originally a fp128. |
39 | bool MipsCCState::originalTypeIsF128(const Type *Ty, const char *Func) { |
40 | if (Ty->isFP128Ty()) |
41 | return true; |
42 | |
43 | if (Ty->isStructTy() && Ty->getStructNumElements() == 1 && |
44 | Ty->getStructElementType(N: 0)->isFP128Ty()) |
45 | return true; |
46 | |
47 | // If the Ty is i128 and the function being called is a long double emulation |
48 | // routine, then the original type is f128. |
49 | // FIXME: This is unsound because these functions could be indirectly called |
50 | return (Func && Ty->isIntegerTy(Bitwidth: 128) && isF128SoftLibCall(CallSym: Func)); |
51 | } |
52 | |
53 | /// Return true if the original type was vXfXX. |
54 | bool MipsCCState::originalEVTTypeIsVectorFloat(EVT Ty) { |
55 | if (Ty.isVector() && Ty.getVectorElementType().isFloatingPoint()) |
56 | return true; |
57 | |
58 | return false; |
59 | } |
60 | |
61 | /// Return true if the original type was vXfXX / vXfXX. |
62 | bool MipsCCState::originalTypeIsVectorFloat(const Type *Ty) { |
63 | if (Ty->isVectorTy() && Ty->isFPOrFPVectorTy()) |
64 | return true; |
65 | |
66 | return false; |
67 | } |
68 | |
69 | MipsCCState::SpecialCallingConvType |
70 | MipsCCState::getSpecialCallingConvForCallee(const SDNode *Callee, |
71 | const MipsSubtarget &Subtarget) { |
72 | MipsCCState::SpecialCallingConvType SpecialCallingConv = NoSpecialCallingConv; |
73 | if (Subtarget.inMips16HardFloat()) { |
74 | if (const GlobalAddressSDNode *G = |
75 | dyn_cast<const GlobalAddressSDNode>(Val: Callee)) { |
76 | llvm::StringRef Sym = G->getGlobal()->getName(); |
77 | Function *F = G->getGlobal()->getParent()->getFunction(Name: Sym); |
78 | if (F && F->hasFnAttribute(Kind: "__Mips16RetHelper" )) { |
79 | SpecialCallingConv = Mips16RetHelperConv; |
80 | } |
81 | } |
82 | } |
83 | return SpecialCallingConv; |
84 | } |
85 | |
86 | void MipsCCState::PreAnalyzeCallResultForF128( |
87 | const SmallVectorImpl<ISD::InputArg> &Ins, |
88 | const Type *RetTy, const char *Call) { |
89 | for (unsigned i = 0; i < Ins.size(); ++i) { |
90 | OriginalArgWasF128.push_back( |
91 | Elt: originalTypeIsF128(Ty: RetTy, Func: Call)); |
92 | OriginalArgWasFloat.push_back(Elt: RetTy->isFloatingPointTy()); |
93 | } |
94 | } |
95 | |
96 | /// Identify lowered values that originated from f128 or float arguments and |
97 | /// record this for use by RetCC_MipsN. |
98 | void MipsCCState::PreAnalyzeReturnForF128( |
99 | const SmallVectorImpl<ISD::OutputArg> &Outs) { |
100 | const MachineFunction &MF = getMachineFunction(); |
101 | for (unsigned i = 0; i < Outs.size(); ++i) { |
102 | OriginalArgWasF128.push_back( |
103 | Elt: originalTypeIsF128(Ty: MF.getFunction().getReturnType(), Func: nullptr)); |
104 | OriginalArgWasFloat.push_back( |
105 | Elt: MF.getFunction().getReturnType()->isFloatingPointTy()); |
106 | } |
107 | } |
108 | |
109 | /// Identify lower values that originated from vXfXX and record |
110 | /// this. |
111 | void MipsCCState::PreAnalyzeCallResultForVectorFloat( |
112 | const SmallVectorImpl<ISD::InputArg> &Ins, const Type *RetTy) { |
113 | for (unsigned i = 0; i < Ins.size(); ++i) { |
114 | OriginalRetWasFloatVector.push_back(Elt: originalTypeIsVectorFloat(Ty: RetTy)); |
115 | } |
116 | } |
117 | |
118 | /// Identify lowered values that originated from vXfXX arguments and record |
119 | /// this. |
120 | void MipsCCState::PreAnalyzeReturnForVectorFloat( |
121 | const SmallVectorImpl<ISD::OutputArg> &Outs) { |
122 | for (unsigned i = 0; i < Outs.size(); ++i) { |
123 | ISD::OutputArg Out = Outs[i]; |
124 | OriginalRetWasFloatVector.push_back( |
125 | Elt: originalEVTTypeIsVectorFloat(Ty: Out.ArgVT)); |
126 | } |
127 | } |
128 | |
129 | void MipsCCState::PreAnalyzeReturnValue(EVT ArgVT) { |
130 | OriginalRetWasFloatVector.push_back(Elt: originalEVTTypeIsVectorFloat(Ty: ArgVT)); |
131 | } |
132 | |
133 | void MipsCCState::PreAnalyzeCallOperand(const Type *ArgTy, bool IsFixed, |
134 | const char *Func) { |
135 | OriginalArgWasF128.push_back(Elt: originalTypeIsF128(Ty: ArgTy, Func)); |
136 | OriginalArgWasFloat.push_back(Elt: ArgTy->isFloatingPointTy()); |
137 | OriginalArgWasFloatVector.push_back(Elt: ArgTy->isVectorTy()); |
138 | CallOperandIsFixed.push_back(Elt: IsFixed); |
139 | } |
140 | |
141 | /// Identify lowered values that originated from f128, float and sret to vXfXX |
142 | /// arguments and record this. |
143 | void MipsCCState::PreAnalyzeCallOperands( |
144 | const SmallVectorImpl<ISD::OutputArg> &Outs, |
145 | std::vector<TargetLowering::ArgListEntry> &FuncArgs, |
146 | const char *Func) { |
147 | for (unsigned i = 0; i < Outs.size(); ++i) { |
148 | TargetLowering::ArgListEntry FuncArg = FuncArgs[Outs[i].OrigArgIndex]; |
149 | |
150 | OriginalArgWasF128.push_back(Elt: originalTypeIsF128(Ty: FuncArg.Ty, Func)); |
151 | OriginalArgWasFloat.push_back(Elt: FuncArg.Ty->isFloatingPointTy()); |
152 | OriginalArgWasFloatVector.push_back(Elt: FuncArg.Ty->isVectorTy()); |
153 | CallOperandIsFixed.push_back(Elt: Outs[i].IsFixed); |
154 | } |
155 | } |
156 | |
157 | void MipsCCState::PreAnalyzeFormalArgument(const Type *ArgTy, |
158 | ISD::ArgFlagsTy Flags) { |
159 | // SRet arguments cannot originate from f128 or {f128} returns so we just |
160 | // push false. We have to handle this specially since SRet arguments |
161 | // aren't mapped to an original argument. |
162 | if (Flags.isSRet()) { |
163 | OriginalArgWasF128.push_back(Elt: false); |
164 | OriginalArgWasFloat.push_back(Elt: false); |
165 | OriginalArgWasFloatVector.push_back(Elt: false); |
166 | return; |
167 | } |
168 | |
169 | OriginalArgWasF128.push_back(Elt: originalTypeIsF128(Ty: ArgTy, Func: nullptr)); |
170 | OriginalArgWasFloat.push_back(Elt: ArgTy->isFloatingPointTy()); |
171 | |
172 | // The MIPS vector ABI exhibits a corner case of sorts or quirk; if the |
173 | // first argument is actually an SRet pointer to a vector, then the next |
174 | // argument slot is $a2. |
175 | OriginalArgWasFloatVector.push_back(Elt: ArgTy->isVectorTy()); |
176 | } |
177 | |
178 | /// Identify lowered values that originated from f128, float and vXfXX arguments |
179 | /// and record this. |
180 | void MipsCCState::PreAnalyzeFormalArgumentsForF128( |
181 | const SmallVectorImpl<ISD::InputArg> &Ins) { |
182 | const MachineFunction &MF = getMachineFunction(); |
183 | for (unsigned i = 0; i < Ins.size(); ++i) { |
184 | Function::const_arg_iterator FuncArg = MF.getFunction().arg_begin(); |
185 | |
186 | // SRet arguments cannot originate from f128 or {f128} returns so we just |
187 | // push false. We have to handle this specially since SRet arguments |
188 | // aren't mapped to an original argument. |
189 | if (Ins[i].Flags.isSRet()) { |
190 | OriginalArgWasF128.push_back(Elt: false); |
191 | OriginalArgWasFloat.push_back(Elt: false); |
192 | OriginalArgWasFloatVector.push_back(Elt: false); |
193 | continue; |
194 | } |
195 | |
196 | assert(Ins[i].getOrigArgIndex() < MF.getFunction().arg_size()); |
197 | std::advance(i&: FuncArg, n: Ins[i].getOrigArgIndex()); |
198 | |
199 | OriginalArgWasF128.push_back( |
200 | Elt: originalTypeIsF128(Ty: FuncArg->getType(), Func: nullptr)); |
201 | OriginalArgWasFloat.push_back(Elt: FuncArg->getType()->isFloatingPointTy()); |
202 | |
203 | // The MIPS vector ABI exhibits a corner case of sorts or quirk; if the |
204 | // first argument is actually an SRet pointer to a vector, then the next |
205 | // argument slot is $a2. |
206 | OriginalArgWasFloatVector.push_back(Elt: FuncArg->getType()->isVectorTy()); |
207 | } |
208 | } |
209 | |