blob: b2bc7e74c706d5a2f9a2a5cc246e2c3687baa0cc [file] [log] [blame]
Reed Kotler783c7942013-05-10 22:25:39 +00001//===---- Mips16HardFloat.cpp for Mips16 Hard Float --------===//
2//
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"
Reed Kotler783c7942013-05-10 22:25:39 +000015#include "llvm/IR/Module.h"
Chandler Carruth8a8cd2b2014-01-07 11:48:04 +000016#include "llvm/IR/Value.h"
Reed Kotler783c7942013-05-10 22:25:39 +000017#include "llvm/Support/Debug.h"
Benjamin Kramer16132e62015-03-23 18:07:13 +000018#include "llvm/Support/raw_ostream.h"
Reed Kotlerd265e882013-08-11 21:30:27 +000019#include <algorithm>
Reed Kotler783c7942013-05-10 22:25:39 +000020#include <string>
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000021
Benjamin Kramera52f6962015-03-09 15:50:58 +000022using namespace llvm;
Reed Kotler783c7942013-05-10 22:25:39 +000023
Chandler Carruth84e68b22014-04-22 02:41:26 +000024#define DEBUG_TYPE "mips16-hard-float"
25
Reed Kotler2c4657d2013-05-14 02:00:24 +000026namespace {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000027 class Mips16HardFloat : public ModulePass {
28 public:
29 static char ID;
Reed Kotler2c4657d2013-05-14 02:00:24 +000030
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000031 Mips16HardFloat(MipsTargetMachine &TM_) : ModulePass(ID), TM(TM_) {}
Reed Kotler2c4657d2013-05-14 02:00:24 +000032
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000033 const char *getPassName() const override {
34 return "MIPS16 Hard Float Pass";
35 }
Reed Kotler2c4657d2013-05-14 02:00:24 +000036
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000037 bool runOnModule(Module &M) override;
38
39 protected:
40 const MipsTargetMachine &TM;
41 };
42
Daniel Sandersd6cf3e02015-10-21 12:44:14 +000043 static void EmitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) {
44 std::vector<llvm::Type *> AsmArgTypes;
45 std::vector<llvm::Value *> AsmArgs;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000046
Daniel Sandersd6cf3e02015-10-21 12:44:14 +000047 llvm::FunctionType *AsmFTy =
48 llvm::FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false);
49 llvm::InlineAsm *IA =
50 llvm::InlineAsm::get(AsmFTy, AsmText, "", true,
51 /* IsAlignStack */ false, llvm::InlineAsm::AD_ATT);
52 CallInst::Create(IA, AsmArgs, "", BB);
53 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000054
55 char Mips16HardFloat::ID = 0;
Alexander Kornienkof00654e2015-06-23 09:49:53 +000056}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000057
Reed Kotler783c7942013-05-10 22:25:39 +000058//
59// Return types that matter for hard float are:
60// float, double, complex float, and complex double
61//
62enum FPReturnVariant {
63 FRet, DRet, CFRet, CDRet, NoFPRet
64};
65
66//
67// Determine which FP return type this function has
68//
69static FPReturnVariant whichFPReturnVariant(Type *T) {
70 switch (T->getTypeID()) {
71 case Type::FloatTyID:
72 return FRet;
73 case Type::DoubleTyID:
74 return DRet;
75 case Type::StructTyID:
76 if (T->getStructNumElements() != 2)
77 break;
78 if ((T->getContainedType(0)->isFloatTy()) &&
79 (T->getContainedType(1)->isFloatTy()))
80 return CFRet;
81 if ((T->getContainedType(0)->isDoubleTy()) &&
82 (T->getContainedType(1)->isDoubleTy()))
83 return CDRet;
84 break;
85 default:
86 break;
87 }
88 return NoFPRet;
89}
90
91//
Reed Kotler2c4657d2013-05-14 02:00:24 +000092// Parameter type that matter are float, (float, float), (float, double),
93// double, (double, double), (double, float)
94//
95enum FPParamVariant {
96 FSig, FFSig, FDSig,
97 DSig, DDSig, DFSig, NoSig
98};
99
100// which floating point parameter signature variant we are dealing with
101//
102typedef Type::TypeID TypeID;
103const Type::TypeID FloatTyID = Type::FloatTyID;
104const Type::TypeID DoubleTyID = Type::DoubleTyID;
105
106static FPParamVariant whichFPParamVariantNeeded(Function &F) {
107 switch (F.arg_size()) {
108 case 0:
109 return NoSig;
110 case 1:{
111 TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
112 switch (ArgTypeID) {
113 case FloatTyID:
114 return FSig;
115 case DoubleTyID:
116 return DSig;
117 default:
118 return NoSig;
119 }
120 }
121 default: {
122 TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
123 TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
124 switch(ArgTypeID0) {
125 case FloatTyID: {
126 switch (ArgTypeID1) {
127 case FloatTyID:
128 return FFSig;
129 case DoubleTyID:
130 return FDSig;
131 default:
132 return FSig;
133 }
134 }
135 case DoubleTyID: {
136 switch (ArgTypeID1) {
137 case FloatTyID:
138 return DFSig;
139 case DoubleTyID:
140 return DDSig;
141 default:
142 return DSig;
143 }
144 }
145 default:
146 return NoSig;
147 }
148 }
149 }
150 llvm_unreachable("can't get here");
151}
152
153// Figure out if we need float point based on the function parameters.
154// We need to move variables in and/or out of floating point
155// registers because of the ABI
156//
157static bool needsFPStubFromParams(Function &F) {
158 if (F.arg_size() >=1) {
159 Type *ArgType = F.getFunctionType()->getParamType(0);
160 switch (ArgType->getTypeID()) {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000161 case Type::FloatTyID:
162 case Type::DoubleTyID:
163 return true;
164 default:
165 break;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000166 }
167 }
168 return false;
169}
170
171static bool needsFPReturnHelper(Function &F) {
172 Type* RetType = F.getReturnType();
173 return whichFPReturnVariant(RetType) != NoFPRet;
174}
175
Craig Toppere3dcce92015-08-01 22:20:21 +0000176static bool needsFPReturnHelper(FunctionType &FT) {
Reed Kotler2500bd62013-12-18 23:57:48 +0000177 Type* RetType = FT.getReturnType();
178 return whichFPReturnVariant(RetType) != NoFPRet;
179}
180
Reed Kotler2c4657d2013-05-14 02:00:24 +0000181static bool needsFPHelperFromSig(Function &F) {
182 return needsFPStubFromParams(F) || needsFPReturnHelper(F);
183}
184
185//
186// We swap between FP and Integer registers to allow Mips16 and Mips32 to
187// interoperate
188//
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000189static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE,
190 bool ToFP) {
191 std::string MI = ToFP ? "mtc1 ": "mfc1 ";
192 std::string AsmText;
193
Reed Kotler2c4657d2013-05-14 02:00:24 +0000194 switch (PV) {
195 case FSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000196 AsmText += MI + "$$4, $$f12\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000197 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000198
Reed Kotler2c4657d2013-05-14 02:00:24 +0000199 case FFSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000200 AsmText += MI + "$$4, $$f12\n";
201 AsmText += MI + "$$5, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000202 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000203
Reed Kotler2c4657d2013-05-14 02:00:24 +0000204 case FDSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000205 AsmText += MI + "$$4, $$f12\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000206 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000207 AsmText += MI + "$$6, $$f14\n";
208 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000209 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000210 AsmText += MI + "$$7, $$f14\n";
211 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000212 }
213 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000214
Reed Kotler2c4657d2013-05-14 02:00:24 +0000215 case DSig:
216 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000217 AsmText += MI + "$$4, $$f12\n";
218 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000219 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000220 AsmText += MI + "$$5, $$f12\n";
221 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000222 }
223 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000224
Reed Kotler2c4657d2013-05-14 02:00:24 +0000225 case DDSig:
226 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000227 AsmText += MI + "$$4, $$f12\n";
228 AsmText += MI + "$$5, $$f13\n";
229 AsmText += MI + "$$6, $$f14\n";
230 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000231 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000232 AsmText += MI + "$$5, $$f12\n";
233 AsmText += MI + "$$4, $$f13\n";
234 AsmText += MI + "$$7, $$f14\n";
235 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000236 }
237 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000238
Reed Kotler2c4657d2013-05-14 02:00:24 +0000239 case DFSig:
240 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000241 AsmText += MI + "$$4, $$f12\n";
242 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000243 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000244 AsmText += MI + "$$5, $$f12\n";
245 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000246 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000247 AsmText += MI + "$$6, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000248 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000249
Reed Kotler2c4657d2013-05-14 02:00:24 +0000250 case NoSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000251 break;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000252 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000253
254 return AsmText;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000255}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000256
Reed Kotler2c4657d2013-05-14 02:00:24 +0000257//
258// Make sure that we know we already need a stub for this function.
259// Having called needsFPHelperFromSig
260//
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000261static void assureFPCallStub(Function &F, Module *M,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000262 const MipsTargetMachine &TM) {
Reed Kotler2c4657d2013-05-14 02:00:24 +0000263 // for now we only need them for static relocation
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000264 if (TM.getRelocationModel() == Reloc::PIC_)
Reed Kotler2c4657d2013-05-14 02:00:24 +0000265 return;
266 LLVMContext &Context = M->getContext();
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000267 bool LE = TM.isLittleEndian();
Reed Kotler2c4657d2013-05-14 02:00:24 +0000268 std::string Name = F.getName();
269 std::string SectionName = ".mips16.call.fp." + Name;
Reed Kotler302ae6b2013-08-01 02:26:31 +0000270 std::string StubName = "__call_stub_fp_" + Name;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000271 //
272 // see if we already have the stub
273 //
274 Function *FStub = M->getFunction(StubName);
275 if (FStub && !FStub->isDeclaration()) return;
276 FStub = Function::Create(F.getFunctionType(),
277 Function::InternalLinkage, StubName, M);
278 FStub->addFnAttr("mips16_fp_stub");
279 FStub->addFnAttr(llvm::Attribute::Naked);
Reed Kotler302ae6b2013-08-01 02:26:31 +0000280 FStub->addFnAttr(llvm::Attribute::NoInline);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000281 FStub->addFnAttr(llvm::Attribute::NoUnwind);
282 FStub->addFnAttr("nomips16");
283 FStub->setSection(SectionName);
284 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000285 FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
286 FPParamVariant PV = whichFPParamVariantNeeded(F);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000287
288 std::string AsmText;
289 AsmText += ".set reorder\n";
290 AsmText += swapFPIntParams(PV, M, LE, true);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000291 if (RV != NoFPRet) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000292 AsmText += "move $$18, $$31\n";
293 AsmText += "jal " + Name + "\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000294 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000295 AsmText += "lui $$25, %hi(" + Name + ")\n";
296 AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000297 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000298
Reed Kotler2c4657d2013-05-14 02:00:24 +0000299 switch (RV) {
300 case FRet:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000301 AsmText += "mfc1 $$2, $$f0\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000302 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000303
Reed Kotler2c4657d2013-05-14 02:00:24 +0000304 case DRet:
305 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000306 AsmText += "mfc1 $$2, $$f0\n";
307 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000308 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000309 AsmText += "mfc1 $$3, $$f0\n";
310 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000311 }
312 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000313
Reed Kotler2c4657d2013-05-14 02:00:24 +0000314 case CFRet:
315 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000316 AsmText += "mfc1 $$2, $$f0\n";
317 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000318 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000319 AsmText += "mfc1 $$3, $$f0\n";
320 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000321 }
322 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000323
Reed Kotler2c4657d2013-05-14 02:00:24 +0000324 case CDRet:
325 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000326 AsmText += "mfc1 $$4, $$f2\n";
327 AsmText += "mfc1 $$5, $$f3\n";
328 AsmText += "mfc1 $$2, $$f0\n";
329 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000330
331 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000332 AsmText += "mfc1 $$5, $$f2\n";
333 AsmText += "mfc1 $$4, $$f3\n";
334 AsmText += "mfc1 $$3, $$f0\n";
335 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000336 }
337 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000338
Reed Kotler2c4657d2013-05-14 02:00:24 +0000339 case NoFPRet:
340 break;
341 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000342
Reed Kotler2c4657d2013-05-14 02:00:24 +0000343 if (RV != NoFPRet)
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000344 AsmText += "jr $$18\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000345 else
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000346 AsmText += "jr $$25\n";
347 EmitInlineAsm(Context, BB, AsmText);
348
Reed Kotler2c4657d2013-05-14 02:00:24 +0000349 new UnreachableInst(Context, BB);
350}
351
352//
Reed Kotler5fdadce2013-09-01 04:12:59 +0000353// Functions that are llvm intrinsics and don't need helpers.
Reed Kotlerd265e882013-08-11 21:30:27 +0000354//
Craig Topper26260942015-10-18 05:15:34 +0000355static const char *const IntrinsicInline[] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000356 "fabs", "fabsf",
357 "llvm.ceil.f32", "llvm.ceil.f64",
358 "llvm.copysign.f32", "llvm.copysign.f64",
359 "llvm.cos.f32", "llvm.cos.f64",
360 "llvm.exp.f32", "llvm.exp.f64",
361 "llvm.exp2.f32", "llvm.exp2.f64",
362 "llvm.fabs.f32", "llvm.fabs.f64",
363 "llvm.floor.f32", "llvm.floor.f64",
364 "llvm.fma.f32", "llvm.fma.f64",
365 "llvm.log.f32", "llvm.log.f64",
366 "llvm.log10.f32", "llvm.log10.f64",
367 "llvm.nearbyint.f32", "llvm.nearbyint.f64",
368 "llvm.pow.f32", "llvm.pow.f64",
369 "llvm.powi.f32", "llvm.powi.f64",
370 "llvm.rint.f32", "llvm.rint.f64",
371 "llvm.round.f32", "llvm.round.f64",
372 "llvm.sin.f32", "llvm.sin.f64",
373 "llvm.sqrt.f32", "llvm.sqrt.f64",
374 "llvm.trunc.f32", "llvm.trunc.f64",
375};
Reed Kotlerd265e882013-08-11 21:30:27 +0000376
Benjamin Kramerc9b7d472013-08-12 09:37:29 +0000377static bool isIntrinsicInline(Function *F) {
Benjamin Kramer502b9e12014-04-12 16:15:53 +0000378 return std::binary_search(std::begin(IntrinsicInline),
379 std::end(IntrinsicInline), F->getName());
Reed Kotlerd265e882013-08-11 21:30:27 +0000380}
381//
Reed Kotler783c7942013-05-10 22:25:39 +0000382// Returns of float, double and complex need to be handled with a helper
Reed Kotler515e9372013-05-16 02:17:42 +0000383// function.
Reed Kotler783c7942013-05-10 22:25:39 +0000384//
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000385static bool fixupFPReturnAndCall(Function &F, Module *M,
386 const MipsTargetMachine &TM) {
Reed Kotler783c7942013-05-10 22:25:39 +0000387 bool Modified = false;
388 LLVMContext &C = M->getContext();
389 Type *MyVoid = Type::getVoidTy(C);
390 for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
391 for (BasicBlock::iterator I = BB->begin(), E = BB->end();
392 I != E; ++I) {
393 Instruction &Inst = *I;
394 if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) {
395 Value *RVal = RI->getReturnValue();
396 if (!RVal) continue;
397 //
398 // If there is a return value and it needs a helper function,
399 // figure out which one and add a call before the actual
400 // return to this helper. The purpose of the helper is to move
401 // floating point values from their soft float return mapping to
402 // where they would have been mapped to in floating point registers.
403 //
404 Type *T = RVal->getType();
405 FPReturnVariant RV = whichFPReturnVariant(T);
406 if (RV == NoFPRet) continue;
Craig Topper26260942015-10-18 05:15:34 +0000407 static const char *const Helper[NoFPRet] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000408 "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
409 "__mips16_ret_dc"
410 };
Reed Kotler783c7942013-05-10 22:25:39 +0000411 const char *Name = Helper[RV];
412 AttributeSet A;
413 Value *Params[] = {RVal};
414 Modified = true;
415 //
416 // These helper functions have a different calling ABI so
417 // this __Mips16RetHelper indicates that so that later
418 // during call setup, the proper call lowering to the helper
419 // functions will take place.
420 //
421 A = A.addAttribute(C, AttributeSet::FunctionIndex,
422 "__Mips16RetHelper");
423 A = A.addAttribute(C, AttributeSet::FunctionIndex,
424 Attribute::ReadNone);
Reed Kotler302ae6b2013-08-01 02:26:31 +0000425 A = A.addAttribute(C, AttributeSet::FunctionIndex,
426 Attribute::NoInline);
Reid Kleckner343c3952014-11-20 23:51:47 +0000427 Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, nullptr));
Reed Kotler783c7942013-05-10 22:25:39 +0000428 CallInst::Create(F, Params, "", &Inst );
Reed Kotler2c4657d2013-05-14 02:00:24 +0000429 } else if (const CallInst *CI = dyn_cast<CallInst>(I)) {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000430 const Value* V = CI->getCalledValue();
Craig Toppere3dcce92015-08-01 22:20:21 +0000431 Type* T = nullptr;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000432 if (V) T = V->getType();
Craig Toppere3dcce92015-08-01 22:20:21 +0000433 PointerType *PFT = nullptr;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000434 if (T) PFT = dyn_cast<PointerType>(T);
Craig Toppere3dcce92015-08-01 22:20:21 +0000435 FunctionType *FT = nullptr;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000436 if (PFT) FT = dyn_cast<FunctionType>(PFT->getElementType());
437 Function *F_ = CI->getCalledFunction();
438 if (FT && needsFPReturnHelper(*FT) &&
439 !(F_ && isIntrinsicInline(F_))) {
440 Modified=true;
441 F.addFnAttr("saveS2");
442 }
443 if (F_ && !isIntrinsicInline(F_)) {
444 // pic mode calls are handled by already defined
445 // helper functions
446 if (needsFPReturnHelper(*F_)) {
Reed Kotler2500bd62013-12-18 23:57:48 +0000447 Modified=true;
448 F.addFnAttr("saveS2");
449 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000450 if (TM.getRelocationModel() != Reloc::PIC_ ) {
451 if (needsFPHelperFromSig(*F_)) {
452 assureFPCallStub(*F_, M, TM);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000453 Modified=true;
454 }
455 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000456 }
Reed Kotler783c7942013-05-10 22:25:39 +0000457 }
458 }
459 return Modified;
460}
461
Reed Kotler515e9372013-05-16 02:17:42 +0000462static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000463 const MipsTargetMachine &TM) {
464 bool PicMode = TM.getRelocationModel() == Reloc::PIC_;
465 bool LE = TM.isLittleEndian();
Reed Kotler515e9372013-05-16 02:17:42 +0000466 LLVMContext &Context = M->getContext();
467 std::string Name = F->getName();
468 std::string SectionName = ".mips16.fn." + Name;
469 std::string StubName = "__fn_stub_" + Name;
Reed Kotlera6ce7972013-09-25 20:58:50 +0000470 std::string LocalName = "$$__fn_local_" + Name;
Reed Kotler515e9372013-05-16 02:17:42 +0000471 Function *FStub = Function::Create
472 (F->getFunctionType(),
Reed Kotler302ae6b2013-08-01 02:26:31 +0000473 Function::InternalLinkage, StubName, M);
Reed Kotler515e9372013-05-16 02:17:42 +0000474 FStub->addFnAttr("mips16_fp_stub");
475 FStub->addFnAttr(llvm::Attribute::Naked);
476 FStub->addFnAttr(llvm::Attribute::NoUnwind);
Reed Kotler302ae6b2013-08-01 02:26:31 +0000477 FStub->addFnAttr(llvm::Attribute::NoInline);
Reed Kotler515e9372013-05-16 02:17:42 +0000478 FStub->addFnAttr("nomips16");
479 FStub->setSection(SectionName);
480 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000481
482 std::string AsmText;
Reed Kotler515e9372013-05-16 02:17:42 +0000483 if (PicMode) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000484 AsmText += ".set noreorder\n";
485 AsmText += ".cpload $$25\n";
486 AsmText += ".set reorder\n";
487 AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n";
488 AsmText += "la $$25, " + LocalName + "\n";
489 } else
490 AsmText += "la $$25, " + Name + "\n";
491 AsmText += swapFPIntParams(PV, M, LE, false);
492 AsmText += "jr $$25\n";
493 AsmText += LocalName + " = " + Name + "\n";
494 EmitInlineAsm(Context, BB, AsmText);
495
Reed Kotler515e9372013-05-16 02:17:42 +0000496 new UnreachableInst(FStub->getContext(), BB);
497}
498
Reed Kotlerc03807a2013-08-30 19:40:56 +0000499//
500// remove the use-soft-float attribute
501//
502static void removeUseSoftFloat(Function &F) {
503 AttributeSet A;
504 DEBUG(errs() << "removing -use-soft-float\n");
505 A = A.addAttribute(F.getContext(), AttributeSet::FunctionIndex,
506 "use-soft-float", "false");
507 F.removeAttributes(AttributeSet::FunctionIndex, A);
508 if (F.hasFnAttribute("use-soft-float")) {
509 DEBUG(errs() << "still has -use-soft-float\n");
510 }
511 F.addAttributes(AttributeSet::FunctionIndex, A);
512}
513
Reed Kotler783c7942013-05-10 22:25:39 +0000514
515//
516// This pass only makes sense when the underlying chip has floating point but
517// we are compiling as mips16.
518// For all mips16 functions (that are not stubs we have already generated), or
519// declared via attributes as nomips16, we must:
520// 1) fixup all returns of float, double, single and double complex
521// by calling a helper function before the actual return.
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000522// 2) generate helper functions (stubs) that can be called by mips32
523// functions that will move parameters passed normally passed in
524// floating point
Reed Kotler515e9372013-05-16 02:17:42 +0000525// registers the soft float equivalents.
Reed Kotler783c7942013-05-10 22:25:39 +0000526// 3) in the case of static relocation, generate helper functions so that
527// mips16 functions can call extern functions of unknown type (mips16 or
Reed Kotler515e9372013-05-16 02:17:42 +0000528// mips32).
Reed Kotler783c7942013-05-10 22:25:39 +0000529// 4) TBD. For pic, calls to extern functions of unknown type are handled by
530// predefined helper functions in libc but this work is currently done
531// during call lowering but it should be moved here in the future.
532//
533bool Mips16HardFloat::runOnModule(Module &M) {
534 DEBUG(errs() << "Run on Module Mips16HardFloat\n");
535 bool Modified = false;
536 for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
Reed Kotlerc03807a2013-08-30 19:40:56 +0000537 if (F->hasFnAttribute("nomips16") &&
538 F->hasFnAttribute("use-soft-float")) {
539 removeUseSoftFloat(*F);
540 continue;
541 }
Reed Kotler783c7942013-05-10 22:25:39 +0000542 if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
543 F->hasFnAttribute("nomips16")) continue;
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000544 Modified |= fixupFPReturnAndCall(*F, &M, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000545 FPParamVariant V = whichFPParamVariantNeeded(*F);
546 if (V != NoSig) {
547 Modified = true;
Duncan P. N. Exon Smith78691482015-10-20 00:15:20 +0000548 createFPFnStub(&*F, &M, V, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000549 }
Reed Kotler783c7942013-05-10 22:25:39 +0000550 }
551 return Modified;
552}
553
Reed Kotler783c7942013-05-10 22:25:39 +0000554
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000555ModulePass *llvm::createMips16HardFloatPass(MipsTargetMachine &TM) {
Reed Kotler783c7942013-05-10 22:25:39 +0000556 return new Mips16HardFloat(TM);
557}