blob: 682ea5c4ed7f1d22e4883312665d9769f221d454 [file] [log] [blame]
Eugene Zelenko79220eae2017-08-03 22:12:30 +00001//===- Mips16HardFloat.cpp for Mips16 Hard Float --------------------------===//
Reed Kotler783c7942013-05-10 22:25:39 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines a pass needed for Mips16 Hard Float
11//
12//===----------------------------------------------------------------------===//
13
Benjamin Kramer16132e62015-03-23 18:07:13 +000014#include "MipsTargetMachine.h"
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000015#include "llvm/CodeGen/TargetPassConfig.h"
Reed Kotler783c7942013-05-10 22:25:39 +000016#include "llvm/IR/Module.h"
Chandler Carruth8a8cd2b2014-01-07 11:48:04 +000017#include "llvm/IR/Value.h"
Reed Kotler783c7942013-05-10 22:25:39 +000018#include "llvm/Support/Debug.h"
Benjamin Kramer16132e62015-03-23 18:07:13 +000019#include "llvm/Support/raw_ostream.h"
Reed Kotlerd265e882013-08-11 21:30:27 +000020#include <algorithm>
Reed Kotler783c7942013-05-10 22:25:39 +000021#include <string>
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000022
Benjamin Kramera52f6962015-03-09 15:50:58 +000023using namespace llvm;
Reed Kotler783c7942013-05-10 22:25:39 +000024
Chandler Carruth84e68b22014-04-22 02:41:26 +000025#define DEBUG_TYPE "mips16-hard-float"
26
Reed Kotler2c4657d2013-05-14 02:00:24 +000027namespace {
Eugene Zelenko79220eae2017-08-03 22:12:30 +000028
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000029 class Mips16HardFloat : public ModulePass {
30 public:
31 static char ID;
Reed Kotler2c4657d2013-05-14 02:00:24 +000032
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000033 Mips16HardFloat() : ModulePass(ID) {}
Reed Kotler2c4657d2013-05-14 02:00:24 +000034
Mehdi Amini117296c2016-10-01 02:56:57 +000035 StringRef getPassName() const override { return "MIPS16 Hard Float Pass"; }
Reed Kotler2c4657d2013-05-14 02:00:24 +000036
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000037 void getAnalysisUsage(AnalysisUsage &AU) const override {
38 AU.addRequired<TargetPassConfig>();
39 ModulePass::getAnalysisUsage(AU);
40 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000041
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000042 bool runOnModule(Module &M) override;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000043 };
44
Eugene Zelenko79220eae2017-08-03 22:12:30 +000045} // end anonymous namespace
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000046
Eugene Zelenko79220eae2017-08-03 22:12:30 +000047static void EmitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) {
48 std::vector<Type *> AsmArgTypes;
49 std::vector<Value *> AsmArgs;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000050
Eugene Zelenko79220eae2017-08-03 22:12:30 +000051 FunctionType *AsmFTy =
52 FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false);
53 InlineAsm *IA = InlineAsm::get(AsmFTy, AsmText, "", true,
54 /* IsAlignStack */ false, InlineAsm::AD_ATT);
55 CallInst::Create(IA, AsmArgs, "", BB);
Alexander Kornienkof00654e2015-06-23 09:49:53 +000056}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000057
Eugene Zelenko79220eae2017-08-03 22:12:30 +000058char Mips16HardFloat::ID = 0;
59
Reed Kotler783c7942013-05-10 22:25:39 +000060//
61// Return types that matter for hard float are:
62// float, double, complex float, and complex double
63//
64enum FPReturnVariant {
65 FRet, DRet, CFRet, CDRet, NoFPRet
66};
67
68//
69// Determine which FP return type this function has
70//
71static FPReturnVariant whichFPReturnVariant(Type *T) {
72 switch (T->getTypeID()) {
73 case Type::FloatTyID:
74 return FRet;
75 case Type::DoubleTyID:
76 return DRet;
77 case Type::StructTyID:
78 if (T->getStructNumElements() != 2)
79 break;
80 if ((T->getContainedType(0)->isFloatTy()) &&
81 (T->getContainedType(1)->isFloatTy()))
82 return CFRet;
83 if ((T->getContainedType(0)->isDoubleTy()) &&
84 (T->getContainedType(1)->isDoubleTy()))
85 return CDRet;
86 break;
87 default:
88 break;
89 }
90 return NoFPRet;
91}
92
Reed Kotler2c4657d2013-05-14 02:00:24 +000093// Parameter type that matter are float, (float, float), (float, double),
94// double, (double, double), (double, float)
Reed Kotler2c4657d2013-05-14 02:00:24 +000095enum FPParamVariant {
96 FSig, FFSig, FDSig,
97 DSig, DDSig, DFSig, NoSig
98};
99
100// which floating point parameter signature variant we are dealing with
Eugene Zelenko79220eae2017-08-03 22:12:30 +0000101using TypeID = Type::TypeID;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000102const Type::TypeID FloatTyID = Type::FloatTyID;
103const Type::TypeID DoubleTyID = Type::DoubleTyID;
104
105static FPParamVariant whichFPParamVariantNeeded(Function &F) {
106 switch (F.arg_size()) {
107 case 0:
108 return NoSig;
109 case 1:{
110 TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
111 switch (ArgTypeID) {
112 case FloatTyID:
113 return FSig;
114 case DoubleTyID:
115 return DSig;
116 default:
117 return NoSig;
118 }
119 }
120 default: {
121 TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
122 TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
123 switch(ArgTypeID0) {
124 case FloatTyID: {
125 switch (ArgTypeID1) {
126 case FloatTyID:
127 return FFSig;
128 case DoubleTyID:
129 return FDSig;
130 default:
131 return FSig;
132 }
133 }
134 case DoubleTyID: {
135 switch (ArgTypeID1) {
136 case FloatTyID:
137 return DFSig;
138 case DoubleTyID:
139 return DDSig;
140 default:
141 return DSig;
142 }
143 }
144 default:
145 return NoSig;
146 }
147 }
148 }
149 llvm_unreachable("can't get here");
150}
151
152// Figure out if we need float point based on the function parameters.
153// We need to move variables in and/or out of floating point
154// registers because of the ABI
Reed Kotler2c4657d2013-05-14 02:00:24 +0000155static bool needsFPStubFromParams(Function &F) {
156 if (F.arg_size() >=1) {
157 Type *ArgType = F.getFunctionType()->getParamType(0);
158 switch (ArgType->getTypeID()) {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000159 case Type::FloatTyID:
160 case Type::DoubleTyID:
161 return true;
162 default:
163 break;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000164 }
165 }
166 return false;
167}
168
169static bool needsFPReturnHelper(Function &F) {
170 Type* RetType = F.getReturnType();
171 return whichFPReturnVariant(RetType) != NoFPRet;
172}
173
Craig Toppere3dcce92015-08-01 22:20:21 +0000174static bool needsFPReturnHelper(FunctionType &FT) {
Reed Kotler2500bd62013-12-18 23:57:48 +0000175 Type* RetType = FT.getReturnType();
176 return whichFPReturnVariant(RetType) != NoFPRet;
177}
178
Reed Kotler2c4657d2013-05-14 02:00:24 +0000179static bool needsFPHelperFromSig(Function &F) {
180 return needsFPStubFromParams(F) || needsFPReturnHelper(F);
181}
182
Reed Kotler2c4657d2013-05-14 02:00:24 +0000183// We swap between FP and Integer registers to allow Mips16 and Mips32 to
184// interoperate
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000185static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE,
186 bool ToFP) {
187 std::string MI = ToFP ? "mtc1 ": "mfc1 ";
188 std::string AsmText;
189
Reed Kotler2c4657d2013-05-14 02:00:24 +0000190 switch (PV) {
191 case FSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000192 AsmText += MI + "$$4, $$f12\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000193 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000194
Reed Kotler2c4657d2013-05-14 02:00:24 +0000195 case FFSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000196 AsmText += MI + "$$4, $$f12\n";
197 AsmText += MI + "$$5, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000198 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000199
Reed Kotler2c4657d2013-05-14 02:00:24 +0000200 case FDSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000201 AsmText += MI + "$$4, $$f12\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000202 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000203 AsmText += MI + "$$6, $$f14\n";
204 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000205 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000206 AsmText += MI + "$$7, $$f14\n";
207 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000208 }
209 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000210
Reed Kotler2c4657d2013-05-14 02:00:24 +0000211 case DSig:
212 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000213 AsmText += MI + "$$4, $$f12\n";
214 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000215 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000216 AsmText += MI + "$$5, $$f12\n";
217 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000218 }
219 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000220
Reed Kotler2c4657d2013-05-14 02:00:24 +0000221 case DDSig:
222 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000223 AsmText += MI + "$$4, $$f12\n";
224 AsmText += MI + "$$5, $$f13\n";
225 AsmText += MI + "$$6, $$f14\n";
226 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000227 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000228 AsmText += MI + "$$5, $$f12\n";
229 AsmText += MI + "$$4, $$f13\n";
230 AsmText += MI + "$$7, $$f14\n";
231 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000232 }
233 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000234
Reed Kotler2c4657d2013-05-14 02:00:24 +0000235 case DFSig:
236 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000237 AsmText += MI + "$$4, $$f12\n";
238 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000239 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000240 AsmText += MI + "$$5, $$f12\n";
241 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000242 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000243 AsmText += MI + "$$6, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000244 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000245
Reed Kotler2c4657d2013-05-14 02:00:24 +0000246 case NoSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000247 break;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000248 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000249
250 return AsmText;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000251}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000252
Reed Kotler2c4657d2013-05-14 02:00:24 +0000253// Make sure that we know we already need a stub for this function.
254// Having called needsFPHelperFromSig
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000255static void assureFPCallStub(Function &F, Module *M,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000256 const MipsTargetMachine &TM) {
Reed Kotler2c4657d2013-05-14 02:00:24 +0000257 // for now we only need them for static relocation
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000258 if (TM.isPositionIndependent())
Reed Kotler2c4657d2013-05-14 02:00:24 +0000259 return;
260 LLVMContext &Context = M->getContext();
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000261 bool LE = TM.isLittleEndian();
Reed Kotler2c4657d2013-05-14 02:00:24 +0000262 std::string Name = F.getName();
263 std::string SectionName = ".mips16.call.fp." + Name;
Reed Kotler302ae6b2013-08-01 02:26:31 +0000264 std::string StubName = "__call_stub_fp_" + Name;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000265 //
266 // see if we already have the stub
267 //
268 Function *FStub = M->getFunction(StubName);
269 if (FStub && !FStub->isDeclaration()) return;
270 FStub = Function::Create(F.getFunctionType(),
271 Function::InternalLinkage, StubName, M);
272 FStub->addFnAttr("mips16_fp_stub");
Eugene Zelenko79220eae2017-08-03 22:12:30 +0000273 FStub->addFnAttr(Attribute::Naked);
274 FStub->addFnAttr(Attribute::NoInline);
275 FStub->addFnAttr(Attribute::NoUnwind);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000276 FStub->addFnAttr("nomips16");
277 FStub->setSection(SectionName);
278 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000279 FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
280 FPParamVariant PV = whichFPParamVariantNeeded(F);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000281
282 std::string AsmText;
283 AsmText += ".set reorder\n";
284 AsmText += swapFPIntParams(PV, M, LE, true);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000285 if (RV != NoFPRet) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000286 AsmText += "move $$18, $$31\n";
287 AsmText += "jal " + Name + "\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000288 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000289 AsmText += "lui $$25, %hi(" + Name + ")\n";
290 AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000291 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000292
Reed Kotler2c4657d2013-05-14 02:00:24 +0000293 switch (RV) {
294 case FRet:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000295 AsmText += "mfc1 $$2, $$f0\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000296 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000297
Reed Kotler2c4657d2013-05-14 02:00:24 +0000298 case DRet:
299 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000300 AsmText += "mfc1 $$2, $$f0\n";
301 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000302 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000303 AsmText += "mfc1 $$3, $$f0\n";
304 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000305 }
306 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000307
Reed Kotler2c4657d2013-05-14 02:00:24 +0000308 case CFRet:
309 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000310 AsmText += "mfc1 $$2, $$f0\n";
311 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000312 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000313 AsmText += "mfc1 $$3, $$f0\n";
314 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000315 }
316 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000317
Reed Kotler2c4657d2013-05-14 02:00:24 +0000318 case CDRet:
319 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000320 AsmText += "mfc1 $$4, $$f2\n";
321 AsmText += "mfc1 $$5, $$f3\n";
322 AsmText += "mfc1 $$2, $$f0\n";
323 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000324
325 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000326 AsmText += "mfc1 $$5, $$f2\n";
327 AsmText += "mfc1 $$4, $$f3\n";
328 AsmText += "mfc1 $$3, $$f0\n";
329 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000330 }
331 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000332
Reed Kotler2c4657d2013-05-14 02:00:24 +0000333 case NoFPRet:
334 break;
335 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000336
Reed Kotler2c4657d2013-05-14 02:00:24 +0000337 if (RV != NoFPRet)
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000338 AsmText += "jr $$18\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000339 else
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000340 AsmText += "jr $$25\n";
341 EmitInlineAsm(Context, BB, AsmText);
342
Reed Kotler2c4657d2013-05-14 02:00:24 +0000343 new UnreachableInst(Context, BB);
344}
345
Reed Kotler5fdadce2013-09-01 04:12:59 +0000346// Functions that are llvm intrinsics and don't need helpers.
Craig Topper26260942015-10-18 05:15:34 +0000347static const char *const IntrinsicInline[] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000348 "fabs", "fabsf",
349 "llvm.ceil.f32", "llvm.ceil.f64",
350 "llvm.copysign.f32", "llvm.copysign.f64",
351 "llvm.cos.f32", "llvm.cos.f64",
352 "llvm.exp.f32", "llvm.exp.f64",
353 "llvm.exp2.f32", "llvm.exp2.f64",
354 "llvm.fabs.f32", "llvm.fabs.f64",
355 "llvm.floor.f32", "llvm.floor.f64",
356 "llvm.fma.f32", "llvm.fma.f64",
357 "llvm.log.f32", "llvm.log.f64",
358 "llvm.log10.f32", "llvm.log10.f64",
359 "llvm.nearbyint.f32", "llvm.nearbyint.f64",
360 "llvm.pow.f32", "llvm.pow.f64",
361 "llvm.powi.f32", "llvm.powi.f64",
362 "llvm.rint.f32", "llvm.rint.f64",
363 "llvm.round.f32", "llvm.round.f64",
364 "llvm.sin.f32", "llvm.sin.f64",
365 "llvm.sqrt.f32", "llvm.sqrt.f64",
366 "llvm.trunc.f32", "llvm.trunc.f64",
367};
Reed Kotlerd265e882013-08-11 21:30:27 +0000368
Benjamin Kramerc9b7d472013-08-12 09:37:29 +0000369static bool isIntrinsicInline(Function *F) {
Benjamin Kramer502b9e12014-04-12 16:15:53 +0000370 return std::binary_search(std::begin(IntrinsicInline),
371 std::end(IntrinsicInline), F->getName());
Reed Kotlerd265e882013-08-11 21:30:27 +0000372}
Eugene Zelenko79220eae2017-08-03 22:12:30 +0000373
Reed Kotler783c7942013-05-10 22:25:39 +0000374// Returns of float, double and complex need to be handled with a helper
Reed Kotler515e9372013-05-16 02:17:42 +0000375// function.
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000376static bool fixupFPReturnAndCall(Function &F, Module *M,
377 const MipsTargetMachine &TM) {
Reed Kotler783c7942013-05-10 22:25:39 +0000378 bool Modified = false;
379 LLVMContext &C = M->getContext();
380 Type *MyVoid = Type::getVoidTy(C);
Vasileios Kalintiris42db3ff2016-03-14 15:05:30 +0000381 for (auto &BB: F)
382 for (auto &I: BB) {
383 if (const ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
Reed Kotler783c7942013-05-10 22:25:39 +0000384 Value *RVal = RI->getReturnValue();
385 if (!RVal) continue;
386 //
387 // If there is a return value and it needs a helper function,
388 // figure out which one and add a call before the actual
389 // return to this helper. The purpose of the helper is to move
390 // floating point values from their soft float return mapping to
391 // where they would have been mapped to in floating point registers.
392 //
393 Type *T = RVal->getType();
394 FPReturnVariant RV = whichFPReturnVariant(T);
395 if (RV == NoFPRet) continue;
Craig Topper26260942015-10-18 05:15:34 +0000396 static const char *const Helper[NoFPRet] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000397 "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
398 "__mips16_ret_dc"
399 };
Reed Kotler783c7942013-05-10 22:25:39 +0000400 const char *Name = Helper[RV];
Reid Klecknerb5180542017-03-21 16:57:19 +0000401 AttributeList A;
Reed Kotler783c7942013-05-10 22:25:39 +0000402 Value *Params[] = {RVal};
403 Modified = true;
404 //
405 // These helper functions have a different calling ABI so
406 // this __Mips16RetHelper indicates that so that later
407 // during call setup, the proper call lowering to the helper
408 // functions will take place.
409 //
Reid Klecknerb5180542017-03-21 16:57:19 +0000410 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler783c7942013-05-10 22:25:39 +0000411 "__Mips16RetHelper");
Reid Klecknerb5180542017-03-21 16:57:19 +0000412 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler783c7942013-05-10 22:25:39 +0000413 Attribute::ReadNone);
Reid Klecknerb5180542017-03-21 16:57:19 +0000414 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler302ae6b2013-08-01 02:26:31 +0000415 Attribute::NoInline);
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000416 Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T));
Vasileios Kalintiris42db3ff2016-03-14 15:05:30 +0000417 CallInst::Create(F, Params, "", &I);
418 } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
Manuel Jacob190577a2016-01-17 22:37:39 +0000419 FunctionType *FT = CI->getFunctionType();
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000420 Function *F_ = CI->getCalledFunction();
Manuel Jacob190577a2016-01-17 22:37:39 +0000421 if (needsFPReturnHelper(*FT) &&
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000422 !(F_ && isIntrinsicInline(F_))) {
423 Modified=true;
424 F.addFnAttr("saveS2");
425 }
426 if (F_ && !isIntrinsicInline(F_)) {
427 // pic mode calls are handled by already defined
428 // helper functions
429 if (needsFPReturnHelper(*F_)) {
Reed Kotler2500bd62013-12-18 23:57:48 +0000430 Modified=true;
431 F.addFnAttr("saveS2");
432 }
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000433 if (!TM.isPositionIndependent()) {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000434 if (needsFPHelperFromSig(*F_)) {
435 assureFPCallStub(*F_, M, TM);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000436 Modified=true;
437 }
438 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000439 }
Reed Kotler783c7942013-05-10 22:25:39 +0000440 }
441 }
442 return Modified;
443}
444
Reed Kotler515e9372013-05-16 02:17:42 +0000445static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000446 const MipsTargetMachine &TM) {
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000447 bool PicMode = TM.isPositionIndependent();
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000448 bool LE = TM.isLittleEndian();
Reed Kotler515e9372013-05-16 02:17:42 +0000449 LLVMContext &Context = M->getContext();
450 std::string Name = F->getName();
451 std::string SectionName = ".mips16.fn." + Name;
452 std::string StubName = "__fn_stub_" + Name;
Reed Kotlera6ce7972013-09-25 20:58:50 +0000453 std::string LocalName = "$$__fn_local_" + Name;
Reed Kotler515e9372013-05-16 02:17:42 +0000454 Function *FStub = Function::Create
455 (F->getFunctionType(),
Reed Kotler302ae6b2013-08-01 02:26:31 +0000456 Function::InternalLinkage, StubName, M);
Reed Kotler515e9372013-05-16 02:17:42 +0000457 FStub->addFnAttr("mips16_fp_stub");
Eugene Zelenko79220eae2017-08-03 22:12:30 +0000458 FStub->addFnAttr(Attribute::Naked);
459 FStub->addFnAttr(Attribute::NoUnwind);
460 FStub->addFnAttr(Attribute::NoInline);
Reed Kotler515e9372013-05-16 02:17:42 +0000461 FStub->addFnAttr("nomips16");
462 FStub->setSection(SectionName);
463 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000464
465 std::string AsmText;
Reed Kotler515e9372013-05-16 02:17:42 +0000466 if (PicMode) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000467 AsmText += ".set noreorder\n";
468 AsmText += ".cpload $$25\n";
469 AsmText += ".set reorder\n";
470 AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n";
471 AsmText += "la $$25, " + LocalName + "\n";
472 } else
473 AsmText += "la $$25, " + Name + "\n";
474 AsmText += swapFPIntParams(PV, M, LE, false);
475 AsmText += "jr $$25\n";
476 AsmText += LocalName + " = " + Name + "\n";
477 EmitInlineAsm(Context, BB, AsmText);
478
Reed Kotler515e9372013-05-16 02:17:42 +0000479 new UnreachableInst(FStub->getContext(), BB);
480}
481
Reed Kotlerc03807a2013-08-30 19:40:56 +0000482// remove the use-soft-float attribute
Reed Kotlerc03807a2013-08-30 19:40:56 +0000483static void removeUseSoftFloat(Function &F) {
Reid Kleckneree4930b2017-05-02 22:07:37 +0000484 AttrBuilder B;
Reed Kotlerc03807a2013-08-30 19:40:56 +0000485 DEBUG(errs() << "removing -use-soft-float\n");
Reid Kleckneree4930b2017-05-02 22:07:37 +0000486 B.addAttribute("use-soft-float", "false");
487 F.removeAttributes(AttributeList::FunctionIndex, B);
Reed Kotlerc03807a2013-08-30 19:40:56 +0000488 if (F.hasFnAttribute("use-soft-float")) {
489 DEBUG(errs() << "still has -use-soft-float\n");
490 }
Reid Kleckneree4930b2017-05-02 22:07:37 +0000491 F.addAttributes(AttributeList::FunctionIndex, B);
Reed Kotlerc03807a2013-08-30 19:40:56 +0000492}
493
Reed Kotler783c7942013-05-10 22:25:39 +0000494// This pass only makes sense when the underlying chip has floating point but
495// we are compiling as mips16.
496// For all mips16 functions (that are not stubs we have already generated), or
497// declared via attributes as nomips16, we must:
498// 1) fixup all returns of float, double, single and double complex
499// by calling a helper function before the actual return.
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000500// 2) generate helper functions (stubs) that can be called by mips32
501// functions that will move parameters passed normally passed in
502// floating point
Reed Kotler515e9372013-05-16 02:17:42 +0000503// registers the soft float equivalents.
Reed Kotler783c7942013-05-10 22:25:39 +0000504// 3) in the case of static relocation, generate helper functions so that
505// mips16 functions can call extern functions of unknown type (mips16 or
Reed Kotler515e9372013-05-16 02:17:42 +0000506// mips32).
Reed Kotler783c7942013-05-10 22:25:39 +0000507// 4) TBD. For pic, calls to extern functions of unknown type are handled by
508// predefined helper functions in libc but this work is currently done
509// during call lowering but it should be moved here in the future.
Reed Kotler783c7942013-05-10 22:25:39 +0000510bool Mips16HardFloat::runOnModule(Module &M) {
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +0000511 auto &TM = static_cast<const MipsTargetMachine &>(
512 getAnalysis<TargetPassConfig>().getTM<TargetMachine>());
Reed Kotler783c7942013-05-10 22:25:39 +0000513 DEBUG(errs() << "Run on Module Mips16HardFloat\n");
514 bool Modified = false;
515 for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
Reed Kotlerc03807a2013-08-30 19:40:56 +0000516 if (F->hasFnAttribute("nomips16") &&
517 F->hasFnAttribute("use-soft-float")) {
518 removeUseSoftFloat(*F);
519 continue;
520 }
Reed Kotler783c7942013-05-10 22:25:39 +0000521 if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
522 F->hasFnAttribute("nomips16")) continue;
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000523 Modified |= fixupFPReturnAndCall(*F, &M, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000524 FPParamVariant V = whichFPParamVariantNeeded(*F);
525 if (V != NoSig) {
526 Modified = true;
Duncan P. N. Exon Smith78691482015-10-20 00:15:20 +0000527 createFPFnStub(&*F, &M, V, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000528 }
Reed Kotler783c7942013-05-10 22:25:39 +0000529 }
530 return Modified;
531}
532
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +0000533ModulePass *llvm::createMips16HardFloatPass() {
534 return new Mips16HardFloat();
Reed Kotler783c7942013-05-10 22:25:39 +0000535}