blob: 5a394fe02f16c6d69d9fd78c61132b74ef66ef50 [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
Mehdi Amini117296c2016-10-01 02:56:57 +000033 StringRef getPassName() const override { return "MIPS16 Hard Float Pass"; }
Reed Kotler2c4657d2013-05-14 02:00:24 +000034
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000035 bool runOnModule(Module &M) override;
36
37 protected:
38 const MipsTargetMachine &TM;
39 };
40
Daniel Sandersd6cf3e02015-10-21 12:44:14 +000041 static void EmitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) {
42 std::vector<llvm::Type *> AsmArgTypes;
43 std::vector<llvm::Value *> AsmArgs;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000044
Daniel Sandersd6cf3e02015-10-21 12:44:14 +000045 llvm::FunctionType *AsmFTy =
46 llvm::FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false);
47 llvm::InlineAsm *IA =
48 llvm::InlineAsm::get(AsmFTy, AsmText, "", true,
49 /* IsAlignStack */ false, llvm::InlineAsm::AD_ATT);
50 CallInst::Create(IA, AsmArgs, "", BB);
51 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000052
53 char Mips16HardFloat::ID = 0;
Alexander Kornienkof00654e2015-06-23 09:49:53 +000054}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000055
Reed Kotler783c7942013-05-10 22:25:39 +000056//
57// Return types that matter for hard float are:
58// float, double, complex float, and complex double
59//
60enum FPReturnVariant {
61 FRet, DRet, CFRet, CDRet, NoFPRet
62};
63
64//
65// Determine which FP return type this function has
66//
67static FPReturnVariant whichFPReturnVariant(Type *T) {
68 switch (T->getTypeID()) {
69 case Type::FloatTyID:
70 return FRet;
71 case Type::DoubleTyID:
72 return DRet;
73 case Type::StructTyID:
74 if (T->getStructNumElements() != 2)
75 break;
76 if ((T->getContainedType(0)->isFloatTy()) &&
77 (T->getContainedType(1)->isFloatTy()))
78 return CFRet;
79 if ((T->getContainedType(0)->isDoubleTy()) &&
80 (T->getContainedType(1)->isDoubleTy()))
81 return CDRet;
82 break;
83 default:
84 break;
85 }
86 return NoFPRet;
87}
88
89//
Reed Kotler2c4657d2013-05-14 02:00:24 +000090// Parameter type that matter are float, (float, float), (float, double),
91// double, (double, double), (double, float)
92//
93enum FPParamVariant {
94 FSig, FFSig, FDSig,
95 DSig, DDSig, DFSig, NoSig
96};
97
98// which floating point parameter signature variant we are dealing with
99//
100typedef Type::TypeID TypeID;
101const Type::TypeID FloatTyID = Type::FloatTyID;
102const Type::TypeID DoubleTyID = Type::DoubleTyID;
103
104static FPParamVariant whichFPParamVariantNeeded(Function &F) {
105 switch (F.arg_size()) {
106 case 0:
107 return NoSig;
108 case 1:{
109 TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
110 switch (ArgTypeID) {
111 case FloatTyID:
112 return FSig;
113 case DoubleTyID:
114 return DSig;
115 default:
116 return NoSig;
117 }
118 }
119 default: {
120 TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
121 TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
122 switch(ArgTypeID0) {
123 case FloatTyID: {
124 switch (ArgTypeID1) {
125 case FloatTyID:
126 return FFSig;
127 case DoubleTyID:
128 return FDSig;
129 default:
130 return FSig;
131 }
132 }
133 case DoubleTyID: {
134 switch (ArgTypeID1) {
135 case FloatTyID:
136 return DFSig;
137 case DoubleTyID:
138 return DDSig;
139 default:
140 return DSig;
141 }
142 }
143 default:
144 return NoSig;
145 }
146 }
147 }
148 llvm_unreachable("can't get here");
149}
150
151// Figure out if we need float point based on the function parameters.
152// We need to move variables in and/or out of floating point
153// registers because of the ABI
154//
155static 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
183//
184// We swap between FP and Integer registers to allow Mips16 and Mips32 to
185// interoperate
186//
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000187static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE,
188 bool ToFP) {
189 std::string MI = ToFP ? "mtc1 ": "mfc1 ";
190 std::string AsmText;
191
Reed Kotler2c4657d2013-05-14 02:00:24 +0000192 switch (PV) {
193 case FSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000194 AsmText += MI + "$$4, $$f12\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000195 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000196
Reed Kotler2c4657d2013-05-14 02:00:24 +0000197 case FFSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000198 AsmText += MI + "$$4, $$f12\n";
199 AsmText += MI + "$$5, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000200 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000201
Reed Kotler2c4657d2013-05-14 02:00:24 +0000202 case FDSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000203 AsmText += MI + "$$4, $$f12\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000204 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000205 AsmText += MI + "$$6, $$f14\n";
206 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000207 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000208 AsmText += MI + "$$7, $$f14\n";
209 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000210 }
211 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000212
Reed Kotler2c4657d2013-05-14 02:00:24 +0000213 case DSig:
214 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000215 AsmText += MI + "$$4, $$f12\n";
216 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000217 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000218 AsmText += MI + "$$5, $$f12\n";
219 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000220 }
221 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000222
Reed Kotler2c4657d2013-05-14 02:00:24 +0000223 case DDSig:
224 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000225 AsmText += MI + "$$4, $$f12\n";
226 AsmText += MI + "$$5, $$f13\n";
227 AsmText += MI + "$$6, $$f14\n";
228 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000229 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000230 AsmText += MI + "$$5, $$f12\n";
231 AsmText += MI + "$$4, $$f13\n";
232 AsmText += MI + "$$7, $$f14\n";
233 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000234 }
235 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000236
Reed Kotler2c4657d2013-05-14 02:00:24 +0000237 case DFSig:
238 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000239 AsmText += MI + "$$4, $$f12\n";
240 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000241 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000242 AsmText += MI + "$$5, $$f12\n";
243 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000244 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000245 AsmText += MI + "$$6, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000246 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000247
Reed Kotler2c4657d2013-05-14 02:00:24 +0000248 case NoSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000249 break;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000250 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000251
252 return AsmText;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000253}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000254
Reed Kotler2c4657d2013-05-14 02:00:24 +0000255//
256// Make sure that we know we already need a stub for this function.
257// Having called needsFPHelperFromSig
258//
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000259static void assureFPCallStub(Function &F, Module *M,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000260 const MipsTargetMachine &TM) {
Reed Kotler2c4657d2013-05-14 02:00:24 +0000261 // for now we only need them for static relocation
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000262 if (TM.isPositionIndependent())
Reed Kotler2c4657d2013-05-14 02:00:24 +0000263 return;
264 LLVMContext &Context = M->getContext();
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000265 bool LE = TM.isLittleEndian();
Reed Kotler2c4657d2013-05-14 02:00:24 +0000266 std::string Name = F.getName();
267 std::string SectionName = ".mips16.call.fp." + Name;
Reed Kotler302ae6b2013-08-01 02:26:31 +0000268 std::string StubName = "__call_stub_fp_" + Name;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000269 //
270 // see if we already have the stub
271 //
272 Function *FStub = M->getFunction(StubName);
273 if (FStub && !FStub->isDeclaration()) return;
274 FStub = Function::Create(F.getFunctionType(),
275 Function::InternalLinkage, StubName, M);
276 FStub->addFnAttr("mips16_fp_stub");
277 FStub->addFnAttr(llvm::Attribute::Naked);
Reed Kotler302ae6b2013-08-01 02:26:31 +0000278 FStub->addFnAttr(llvm::Attribute::NoInline);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000279 FStub->addFnAttr(llvm::Attribute::NoUnwind);
280 FStub->addFnAttr("nomips16");
281 FStub->setSection(SectionName);
282 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000283 FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
284 FPParamVariant PV = whichFPParamVariantNeeded(F);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000285
286 std::string AsmText;
287 AsmText += ".set reorder\n";
288 AsmText += swapFPIntParams(PV, M, LE, true);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000289 if (RV != NoFPRet) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000290 AsmText += "move $$18, $$31\n";
291 AsmText += "jal " + Name + "\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000292 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000293 AsmText += "lui $$25, %hi(" + Name + ")\n";
294 AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000295 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000296
Reed Kotler2c4657d2013-05-14 02:00:24 +0000297 switch (RV) {
298 case FRet:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000299 AsmText += "mfc1 $$2, $$f0\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000300 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000301
Reed Kotler2c4657d2013-05-14 02:00:24 +0000302 case DRet:
303 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000304 AsmText += "mfc1 $$2, $$f0\n";
305 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000306 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000307 AsmText += "mfc1 $$3, $$f0\n";
308 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000309 }
310 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000311
Reed Kotler2c4657d2013-05-14 02:00:24 +0000312 case CFRet:
313 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000314 AsmText += "mfc1 $$2, $$f0\n";
315 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000316 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000317 AsmText += "mfc1 $$3, $$f0\n";
318 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000319 }
320 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000321
Reed Kotler2c4657d2013-05-14 02:00:24 +0000322 case CDRet:
323 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000324 AsmText += "mfc1 $$4, $$f2\n";
325 AsmText += "mfc1 $$5, $$f3\n";
326 AsmText += "mfc1 $$2, $$f0\n";
327 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000328
329 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000330 AsmText += "mfc1 $$5, $$f2\n";
331 AsmText += "mfc1 $$4, $$f3\n";
332 AsmText += "mfc1 $$3, $$f0\n";
333 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000334 }
335 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000336
Reed Kotler2c4657d2013-05-14 02:00:24 +0000337 case NoFPRet:
338 break;
339 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000340
Reed Kotler2c4657d2013-05-14 02:00:24 +0000341 if (RV != NoFPRet)
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000342 AsmText += "jr $$18\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000343 else
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000344 AsmText += "jr $$25\n";
345 EmitInlineAsm(Context, BB, AsmText);
346
Reed Kotler2c4657d2013-05-14 02:00:24 +0000347 new UnreachableInst(Context, BB);
348}
349
350//
Reed Kotler5fdadce2013-09-01 04:12:59 +0000351// Functions that are llvm intrinsics and don't need helpers.
Reed Kotlerd265e882013-08-11 21:30:27 +0000352//
Craig Topper26260942015-10-18 05:15:34 +0000353static const char *const IntrinsicInline[] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000354 "fabs", "fabsf",
355 "llvm.ceil.f32", "llvm.ceil.f64",
356 "llvm.copysign.f32", "llvm.copysign.f64",
357 "llvm.cos.f32", "llvm.cos.f64",
358 "llvm.exp.f32", "llvm.exp.f64",
359 "llvm.exp2.f32", "llvm.exp2.f64",
360 "llvm.fabs.f32", "llvm.fabs.f64",
361 "llvm.floor.f32", "llvm.floor.f64",
362 "llvm.fma.f32", "llvm.fma.f64",
363 "llvm.log.f32", "llvm.log.f64",
364 "llvm.log10.f32", "llvm.log10.f64",
365 "llvm.nearbyint.f32", "llvm.nearbyint.f64",
366 "llvm.pow.f32", "llvm.pow.f64",
367 "llvm.powi.f32", "llvm.powi.f64",
368 "llvm.rint.f32", "llvm.rint.f64",
369 "llvm.round.f32", "llvm.round.f64",
370 "llvm.sin.f32", "llvm.sin.f64",
371 "llvm.sqrt.f32", "llvm.sqrt.f64",
372 "llvm.trunc.f32", "llvm.trunc.f64",
373};
Reed Kotlerd265e882013-08-11 21:30:27 +0000374
Benjamin Kramerc9b7d472013-08-12 09:37:29 +0000375static bool isIntrinsicInline(Function *F) {
Benjamin Kramer502b9e12014-04-12 16:15:53 +0000376 return std::binary_search(std::begin(IntrinsicInline),
377 std::end(IntrinsicInline), F->getName());
Reed Kotlerd265e882013-08-11 21:30:27 +0000378}
379//
Reed Kotler783c7942013-05-10 22:25:39 +0000380// Returns of float, double and complex need to be handled with a helper
Reed Kotler515e9372013-05-16 02:17:42 +0000381// function.
Reed Kotler783c7942013-05-10 22:25:39 +0000382//
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000383static bool fixupFPReturnAndCall(Function &F, Module *M,
384 const MipsTargetMachine &TM) {
Reed Kotler783c7942013-05-10 22:25:39 +0000385 bool Modified = false;
386 LLVMContext &C = M->getContext();
387 Type *MyVoid = Type::getVoidTy(C);
Vasileios Kalintiris42db3ff2016-03-14 15:05:30 +0000388 for (auto &BB: F)
389 for (auto &I: BB) {
390 if (const ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
Reed Kotler783c7942013-05-10 22:25:39 +0000391 Value *RVal = RI->getReturnValue();
392 if (!RVal) continue;
393 //
394 // If there is a return value and it needs a helper function,
395 // figure out which one and add a call before the actual
396 // return to this helper. The purpose of the helper is to move
397 // floating point values from their soft float return mapping to
398 // where they would have been mapped to in floating point registers.
399 //
400 Type *T = RVal->getType();
401 FPReturnVariant RV = whichFPReturnVariant(T);
402 if (RV == NoFPRet) continue;
Craig Topper26260942015-10-18 05:15:34 +0000403 static const char *const Helper[NoFPRet] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000404 "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
405 "__mips16_ret_dc"
406 };
Reed Kotler783c7942013-05-10 22:25:39 +0000407 const char *Name = Helper[RV];
Reid Klecknerb5180542017-03-21 16:57:19 +0000408 AttributeList A;
Reed Kotler783c7942013-05-10 22:25:39 +0000409 Value *Params[] = {RVal};
410 Modified = true;
411 //
412 // These helper functions have a different calling ABI so
413 // this __Mips16RetHelper indicates that so that later
414 // during call setup, the proper call lowering to the helper
415 // functions will take place.
416 //
Reid Klecknerb5180542017-03-21 16:57:19 +0000417 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler783c7942013-05-10 22:25:39 +0000418 "__Mips16RetHelper");
Reid Klecknerb5180542017-03-21 16:57:19 +0000419 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler783c7942013-05-10 22:25:39 +0000420 Attribute::ReadNone);
Reid Klecknerb5180542017-03-21 16:57:19 +0000421 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler302ae6b2013-08-01 02:26:31 +0000422 Attribute::NoInline);
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000423 Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T));
Vasileios Kalintiris42db3ff2016-03-14 15:05:30 +0000424 CallInst::Create(F, Params, "", &I);
425 } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
Manuel Jacob190577a2016-01-17 22:37:39 +0000426 FunctionType *FT = CI->getFunctionType();
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000427 Function *F_ = CI->getCalledFunction();
Manuel Jacob190577a2016-01-17 22:37:39 +0000428 if (needsFPReturnHelper(*FT) &&
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000429 !(F_ && isIntrinsicInline(F_))) {
430 Modified=true;
431 F.addFnAttr("saveS2");
432 }
433 if (F_ && !isIntrinsicInline(F_)) {
434 // pic mode calls are handled by already defined
435 // helper functions
436 if (needsFPReturnHelper(*F_)) {
Reed Kotler2500bd62013-12-18 23:57:48 +0000437 Modified=true;
438 F.addFnAttr("saveS2");
439 }
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000440 if (!TM.isPositionIndependent()) {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000441 if (needsFPHelperFromSig(*F_)) {
442 assureFPCallStub(*F_, M, TM);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000443 Modified=true;
444 }
445 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000446 }
Reed Kotler783c7942013-05-10 22:25:39 +0000447 }
448 }
449 return Modified;
450}
451
Reed Kotler515e9372013-05-16 02:17:42 +0000452static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000453 const MipsTargetMachine &TM) {
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000454 bool PicMode = TM.isPositionIndependent();
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000455 bool LE = TM.isLittleEndian();
Reed Kotler515e9372013-05-16 02:17:42 +0000456 LLVMContext &Context = M->getContext();
457 std::string Name = F->getName();
458 std::string SectionName = ".mips16.fn." + Name;
459 std::string StubName = "__fn_stub_" + Name;
Reed Kotlera6ce7972013-09-25 20:58:50 +0000460 std::string LocalName = "$$__fn_local_" + Name;
Reed Kotler515e9372013-05-16 02:17:42 +0000461 Function *FStub = Function::Create
462 (F->getFunctionType(),
Reed Kotler302ae6b2013-08-01 02:26:31 +0000463 Function::InternalLinkage, StubName, M);
Reed Kotler515e9372013-05-16 02:17:42 +0000464 FStub->addFnAttr("mips16_fp_stub");
465 FStub->addFnAttr(llvm::Attribute::Naked);
466 FStub->addFnAttr(llvm::Attribute::NoUnwind);
Reed Kotler302ae6b2013-08-01 02:26:31 +0000467 FStub->addFnAttr(llvm::Attribute::NoInline);
Reed Kotler515e9372013-05-16 02:17:42 +0000468 FStub->addFnAttr("nomips16");
469 FStub->setSection(SectionName);
470 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000471
472 std::string AsmText;
Reed Kotler515e9372013-05-16 02:17:42 +0000473 if (PicMode) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000474 AsmText += ".set noreorder\n";
475 AsmText += ".cpload $$25\n";
476 AsmText += ".set reorder\n";
477 AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n";
478 AsmText += "la $$25, " + LocalName + "\n";
479 } else
480 AsmText += "la $$25, " + Name + "\n";
481 AsmText += swapFPIntParams(PV, M, LE, false);
482 AsmText += "jr $$25\n";
483 AsmText += LocalName + " = " + Name + "\n";
484 EmitInlineAsm(Context, BB, AsmText);
485
Reed Kotler515e9372013-05-16 02:17:42 +0000486 new UnreachableInst(FStub->getContext(), BB);
487}
488
Reed Kotlerc03807a2013-08-30 19:40:56 +0000489//
490// remove the use-soft-float attribute
491//
492static void removeUseSoftFloat(Function &F) {
Reid Kleckneree4930b2017-05-02 22:07:37 +0000493 AttrBuilder B;
Reed Kotlerc03807a2013-08-30 19:40:56 +0000494 DEBUG(errs() << "removing -use-soft-float\n");
Reid Kleckneree4930b2017-05-02 22:07:37 +0000495 B.addAttribute("use-soft-float", "false");
496 F.removeAttributes(AttributeList::FunctionIndex, B);
Reed Kotlerc03807a2013-08-30 19:40:56 +0000497 if (F.hasFnAttribute("use-soft-float")) {
498 DEBUG(errs() << "still has -use-soft-float\n");
499 }
Reid Kleckneree4930b2017-05-02 22:07:37 +0000500 F.addAttributes(AttributeList::FunctionIndex, B);
Reed Kotlerc03807a2013-08-30 19:40:56 +0000501}
502
Reed Kotler783c7942013-05-10 22:25:39 +0000503
504//
505// This pass only makes sense when the underlying chip has floating point but
506// we are compiling as mips16.
507// For all mips16 functions (that are not stubs we have already generated), or
508// declared via attributes as nomips16, we must:
509// 1) fixup all returns of float, double, single and double complex
510// by calling a helper function before the actual return.
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000511// 2) generate helper functions (stubs) that can be called by mips32
512// functions that will move parameters passed normally passed in
513// floating point
Reed Kotler515e9372013-05-16 02:17:42 +0000514// registers the soft float equivalents.
Reed Kotler783c7942013-05-10 22:25:39 +0000515// 3) in the case of static relocation, generate helper functions so that
516// mips16 functions can call extern functions of unknown type (mips16 or
Reed Kotler515e9372013-05-16 02:17:42 +0000517// mips32).
Reed Kotler783c7942013-05-10 22:25:39 +0000518// 4) TBD. For pic, calls to extern functions of unknown type are handled by
519// predefined helper functions in libc but this work is currently done
520// during call lowering but it should be moved here in the future.
521//
522bool Mips16HardFloat::runOnModule(Module &M) {
523 DEBUG(errs() << "Run on Module Mips16HardFloat\n");
524 bool Modified = false;
525 for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
Reed Kotlerc03807a2013-08-30 19:40:56 +0000526 if (F->hasFnAttribute("nomips16") &&
527 F->hasFnAttribute("use-soft-float")) {
528 removeUseSoftFloat(*F);
529 continue;
530 }
Reed Kotler783c7942013-05-10 22:25:39 +0000531 if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
532 F->hasFnAttribute("nomips16")) continue;
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000533 Modified |= fixupFPReturnAndCall(*F, &M, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000534 FPParamVariant V = whichFPParamVariantNeeded(*F);
535 if (V != NoSig) {
536 Modified = true;
Duncan P. N. Exon Smith78691482015-10-20 00:15:20 +0000537 createFPFnStub(&*F, &M, V, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000538 }
Reed Kotler783c7942013-05-10 22:25:39 +0000539 }
540 return Modified;
541}
542
Reed Kotler783c7942013-05-10 22:25:39 +0000543
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000544ModulePass *llvm::createMips16HardFloatPass(MipsTargetMachine &TM) {
Reed Kotler783c7942013-05-10 22:25:39 +0000545 return new Mips16HardFloat(TM);
546}