blob: 3c2426129e49a5d935a13e420a16dd5d11ef1408 [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"
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 {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000028 class Mips16HardFloat : public ModulePass {
29 public:
30 static char ID;
Reed Kotler2c4657d2013-05-14 02:00:24 +000031
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000032 Mips16HardFloat() : ModulePass(ID) {}
Reed Kotler2c4657d2013-05-14 02:00:24 +000033
Mehdi Amini117296c2016-10-01 02:56:57 +000034 StringRef getPassName() const override { return "MIPS16 Hard Float Pass"; }
Reed Kotler2c4657d2013-05-14 02:00:24 +000035
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000036 void getAnalysisUsage(AnalysisUsage &AU) const override {
37 AU.addRequired<TargetPassConfig>();
38 ModulePass::getAnalysisUsage(AU);
39 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000040
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000041 bool runOnModule(Module &M) override;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000042 };
43
Daniel Sandersd6cf3e02015-10-21 12:44:14 +000044 static void EmitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) {
45 std::vector<llvm::Type *> AsmArgTypes;
46 std::vector<llvm::Value *> AsmArgs;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000047
Daniel Sandersd6cf3e02015-10-21 12:44:14 +000048 llvm::FunctionType *AsmFTy =
49 llvm::FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false);
50 llvm::InlineAsm *IA =
51 llvm::InlineAsm::get(AsmFTy, AsmText, "", true,
52 /* IsAlignStack */ false, llvm::InlineAsm::AD_ATT);
53 CallInst::Create(IA, AsmArgs, "", BB);
54 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000055
56 char Mips16HardFloat::ID = 0;
Alexander Kornienkof00654e2015-06-23 09:49:53 +000057}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000058
Reed Kotler783c7942013-05-10 22:25:39 +000059//
60// Return types that matter for hard float are:
61// float, double, complex float, and complex double
62//
63enum FPReturnVariant {
64 FRet, DRet, CFRet, CDRet, NoFPRet
65};
66
67//
68// Determine which FP return type this function has
69//
70static FPReturnVariant whichFPReturnVariant(Type *T) {
71 switch (T->getTypeID()) {
72 case Type::FloatTyID:
73 return FRet;
74 case Type::DoubleTyID:
75 return DRet;
76 case Type::StructTyID:
77 if (T->getStructNumElements() != 2)
78 break;
79 if ((T->getContainedType(0)->isFloatTy()) &&
80 (T->getContainedType(1)->isFloatTy()))
81 return CFRet;
82 if ((T->getContainedType(0)->isDoubleTy()) &&
83 (T->getContainedType(1)->isDoubleTy()))
84 return CDRet;
85 break;
86 default:
87 break;
88 }
89 return NoFPRet;
90}
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)
95//
96enum FPParamVariant {
97 FSig, FFSig, FDSig,
98 DSig, DDSig, DFSig, NoSig
99};
100
101// which floating point parameter signature variant we are dealing with
102//
103typedef Type::TypeID TypeID;
104const Type::TypeID FloatTyID = Type::FloatTyID;
105const Type::TypeID DoubleTyID = Type::DoubleTyID;
106
107static FPParamVariant whichFPParamVariantNeeded(Function &F) {
108 switch (F.arg_size()) {
109 case 0:
110 return NoSig;
111 case 1:{
112 TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
113 switch (ArgTypeID) {
114 case FloatTyID:
115 return FSig;
116 case DoubleTyID:
117 return DSig;
118 default:
119 return NoSig;
120 }
121 }
122 default: {
123 TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
124 TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
125 switch(ArgTypeID0) {
126 case FloatTyID: {
127 switch (ArgTypeID1) {
128 case FloatTyID:
129 return FFSig;
130 case DoubleTyID:
131 return FDSig;
132 default:
133 return FSig;
134 }
135 }
136 case DoubleTyID: {
137 switch (ArgTypeID1) {
138 case FloatTyID:
139 return DFSig;
140 case DoubleTyID:
141 return DDSig;
142 default:
143 return DSig;
144 }
145 }
146 default:
147 return NoSig;
148 }
149 }
150 }
151 llvm_unreachable("can't get here");
152}
153
154// Figure out if we need float point based on the function parameters.
155// We need to move variables in and/or out of floating point
156// registers because of the ABI
157//
158static bool needsFPStubFromParams(Function &F) {
159 if (F.arg_size() >=1) {
160 Type *ArgType = F.getFunctionType()->getParamType(0);
161 switch (ArgType->getTypeID()) {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000162 case Type::FloatTyID:
163 case Type::DoubleTyID:
164 return true;
165 default:
166 break;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000167 }
168 }
169 return false;
170}
171
172static bool needsFPReturnHelper(Function &F) {
173 Type* RetType = F.getReturnType();
174 return whichFPReturnVariant(RetType) != NoFPRet;
175}
176
Craig Toppere3dcce92015-08-01 22:20:21 +0000177static bool needsFPReturnHelper(FunctionType &FT) {
Reed Kotler2500bd62013-12-18 23:57:48 +0000178 Type* RetType = FT.getReturnType();
179 return whichFPReturnVariant(RetType) != NoFPRet;
180}
181
Reed Kotler2c4657d2013-05-14 02:00:24 +0000182static bool needsFPHelperFromSig(Function &F) {
183 return needsFPStubFromParams(F) || needsFPReturnHelper(F);
184}
185
186//
187// We swap between FP and Integer registers to allow Mips16 and Mips32 to
188// interoperate
189//
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000190static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE,
191 bool ToFP) {
192 std::string MI = ToFP ? "mtc1 ": "mfc1 ";
193 std::string AsmText;
194
Reed Kotler2c4657d2013-05-14 02:00:24 +0000195 switch (PV) {
196 case FSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000197 AsmText += MI + "$$4, $$f12\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 FFSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000201 AsmText += MI + "$$4, $$f12\n";
202 AsmText += MI + "$$5, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000203 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000204
Reed Kotler2c4657d2013-05-14 02:00:24 +0000205 case FDSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000206 AsmText += MI + "$$4, $$f12\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000207 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000208 AsmText += MI + "$$6, $$f14\n";
209 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000210 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000211 AsmText += MI + "$$7, $$f14\n";
212 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000213 }
214 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000215
Reed Kotler2c4657d2013-05-14 02:00:24 +0000216 case DSig:
217 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000218 AsmText += MI + "$$4, $$f12\n";
219 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000220 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000221 AsmText += MI + "$$5, $$f12\n";
222 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000223 }
224 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000225
Reed Kotler2c4657d2013-05-14 02:00:24 +0000226 case DDSig:
227 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000228 AsmText += MI + "$$4, $$f12\n";
229 AsmText += MI + "$$5, $$f13\n";
230 AsmText += MI + "$$6, $$f14\n";
231 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000232 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000233 AsmText += MI + "$$5, $$f12\n";
234 AsmText += MI + "$$4, $$f13\n";
235 AsmText += MI + "$$7, $$f14\n";
236 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000237 }
238 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000239
Reed Kotler2c4657d2013-05-14 02:00:24 +0000240 case DFSig:
241 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000242 AsmText += MI + "$$4, $$f12\n";
243 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000244 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000245 AsmText += MI + "$$5, $$f12\n";
246 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000247 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000248 AsmText += MI + "$$6, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000249 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000250
Reed Kotler2c4657d2013-05-14 02:00:24 +0000251 case NoSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000252 break;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000253 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000254
255 return AsmText;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000256}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000257
Reed Kotler2c4657d2013-05-14 02:00:24 +0000258//
259// Make sure that we know we already need a stub for this function.
260// Having called needsFPHelperFromSig
261//
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000262static void assureFPCallStub(Function &F, Module *M,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000263 const MipsTargetMachine &TM) {
Reed Kotler2c4657d2013-05-14 02:00:24 +0000264 // for now we only need them for static relocation
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000265 if (TM.isPositionIndependent())
Reed Kotler2c4657d2013-05-14 02:00:24 +0000266 return;
267 LLVMContext &Context = M->getContext();
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000268 bool LE = TM.isLittleEndian();
Reed Kotler2c4657d2013-05-14 02:00:24 +0000269 std::string Name = F.getName();
270 std::string SectionName = ".mips16.call.fp." + Name;
Reed Kotler302ae6b2013-08-01 02:26:31 +0000271 std::string StubName = "__call_stub_fp_" + Name;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000272 //
273 // see if we already have the stub
274 //
275 Function *FStub = M->getFunction(StubName);
276 if (FStub && !FStub->isDeclaration()) return;
277 FStub = Function::Create(F.getFunctionType(),
278 Function::InternalLinkage, StubName, M);
279 FStub->addFnAttr("mips16_fp_stub");
280 FStub->addFnAttr(llvm::Attribute::Naked);
Reed Kotler302ae6b2013-08-01 02:26:31 +0000281 FStub->addFnAttr(llvm::Attribute::NoInline);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000282 FStub->addFnAttr(llvm::Attribute::NoUnwind);
283 FStub->addFnAttr("nomips16");
284 FStub->setSection(SectionName);
285 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000286 FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
287 FPParamVariant PV = whichFPParamVariantNeeded(F);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000288
289 std::string AsmText;
290 AsmText += ".set reorder\n";
291 AsmText += swapFPIntParams(PV, M, LE, true);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000292 if (RV != NoFPRet) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000293 AsmText += "move $$18, $$31\n";
294 AsmText += "jal " + Name + "\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000295 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000296 AsmText += "lui $$25, %hi(" + Name + ")\n";
297 AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000298 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000299
Reed Kotler2c4657d2013-05-14 02:00:24 +0000300 switch (RV) {
301 case FRet:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000302 AsmText += "mfc1 $$2, $$f0\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000303 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000304
Reed Kotler2c4657d2013-05-14 02:00:24 +0000305 case DRet:
306 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000307 AsmText += "mfc1 $$2, $$f0\n";
308 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000309 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000310 AsmText += "mfc1 $$3, $$f0\n";
311 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000312 }
313 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000314
Reed Kotler2c4657d2013-05-14 02:00:24 +0000315 case CFRet:
316 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000317 AsmText += "mfc1 $$2, $$f0\n";
318 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000319 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000320 AsmText += "mfc1 $$3, $$f0\n";
321 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000322 }
323 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000324
Reed Kotler2c4657d2013-05-14 02:00:24 +0000325 case CDRet:
326 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000327 AsmText += "mfc1 $$4, $$f2\n";
328 AsmText += "mfc1 $$5, $$f3\n";
329 AsmText += "mfc1 $$2, $$f0\n";
330 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000331
332 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000333 AsmText += "mfc1 $$5, $$f2\n";
334 AsmText += "mfc1 $$4, $$f3\n";
335 AsmText += "mfc1 $$3, $$f0\n";
336 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000337 }
338 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000339
Reed Kotler2c4657d2013-05-14 02:00:24 +0000340 case NoFPRet:
341 break;
342 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000343
Reed Kotler2c4657d2013-05-14 02:00:24 +0000344 if (RV != NoFPRet)
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000345 AsmText += "jr $$18\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000346 else
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000347 AsmText += "jr $$25\n";
348 EmitInlineAsm(Context, BB, AsmText);
349
Reed Kotler2c4657d2013-05-14 02:00:24 +0000350 new UnreachableInst(Context, BB);
351}
352
353//
Reed Kotler5fdadce2013-09-01 04:12:59 +0000354// Functions that are llvm intrinsics and don't need helpers.
Reed Kotlerd265e882013-08-11 21:30:27 +0000355//
Craig Topper26260942015-10-18 05:15:34 +0000356static const char *const IntrinsicInline[] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000357 "fabs", "fabsf",
358 "llvm.ceil.f32", "llvm.ceil.f64",
359 "llvm.copysign.f32", "llvm.copysign.f64",
360 "llvm.cos.f32", "llvm.cos.f64",
361 "llvm.exp.f32", "llvm.exp.f64",
362 "llvm.exp2.f32", "llvm.exp2.f64",
363 "llvm.fabs.f32", "llvm.fabs.f64",
364 "llvm.floor.f32", "llvm.floor.f64",
365 "llvm.fma.f32", "llvm.fma.f64",
366 "llvm.log.f32", "llvm.log.f64",
367 "llvm.log10.f32", "llvm.log10.f64",
368 "llvm.nearbyint.f32", "llvm.nearbyint.f64",
369 "llvm.pow.f32", "llvm.pow.f64",
370 "llvm.powi.f32", "llvm.powi.f64",
371 "llvm.rint.f32", "llvm.rint.f64",
372 "llvm.round.f32", "llvm.round.f64",
373 "llvm.sin.f32", "llvm.sin.f64",
374 "llvm.sqrt.f32", "llvm.sqrt.f64",
375 "llvm.trunc.f32", "llvm.trunc.f64",
376};
Reed Kotlerd265e882013-08-11 21:30:27 +0000377
Benjamin Kramerc9b7d472013-08-12 09:37:29 +0000378static bool isIntrinsicInline(Function *F) {
Benjamin Kramer502b9e12014-04-12 16:15:53 +0000379 return std::binary_search(std::begin(IntrinsicInline),
380 std::end(IntrinsicInline), F->getName());
Reed Kotlerd265e882013-08-11 21:30:27 +0000381}
382//
Reed Kotler783c7942013-05-10 22:25:39 +0000383// Returns of float, double and complex need to be handled with a helper
Reed Kotler515e9372013-05-16 02:17:42 +0000384// function.
Reed Kotler783c7942013-05-10 22:25:39 +0000385//
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000386static bool fixupFPReturnAndCall(Function &F, Module *M,
387 const MipsTargetMachine &TM) {
Reed Kotler783c7942013-05-10 22:25:39 +0000388 bool Modified = false;
389 LLVMContext &C = M->getContext();
390 Type *MyVoid = Type::getVoidTy(C);
Vasileios Kalintiris42db3ff2016-03-14 15:05:30 +0000391 for (auto &BB: F)
392 for (auto &I: BB) {
393 if (const ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
Reed Kotler783c7942013-05-10 22:25:39 +0000394 Value *RVal = RI->getReturnValue();
395 if (!RVal) continue;
396 //
397 // If there is a return value and it needs a helper function,
398 // figure out which one and add a call before the actual
399 // return to this helper. The purpose of the helper is to move
400 // floating point values from their soft float return mapping to
401 // where they would have been mapped to in floating point registers.
402 //
403 Type *T = RVal->getType();
404 FPReturnVariant RV = whichFPReturnVariant(T);
405 if (RV == NoFPRet) continue;
Craig Topper26260942015-10-18 05:15:34 +0000406 static const char *const Helper[NoFPRet] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000407 "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
408 "__mips16_ret_dc"
409 };
Reed Kotler783c7942013-05-10 22:25:39 +0000410 const char *Name = Helper[RV];
Reid Klecknerb5180542017-03-21 16:57:19 +0000411 AttributeList A;
Reed Kotler783c7942013-05-10 22:25:39 +0000412 Value *Params[] = {RVal};
413 Modified = true;
414 //
415 // These helper functions have a different calling ABI so
416 // this __Mips16RetHelper indicates that so that later
417 // during call setup, the proper call lowering to the helper
418 // functions will take place.
419 //
Reid Klecknerb5180542017-03-21 16:57:19 +0000420 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler783c7942013-05-10 22:25:39 +0000421 "__Mips16RetHelper");
Reid Klecknerb5180542017-03-21 16:57:19 +0000422 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler783c7942013-05-10 22:25:39 +0000423 Attribute::ReadNone);
Reid Klecknerb5180542017-03-21 16:57:19 +0000424 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler302ae6b2013-08-01 02:26:31 +0000425 Attribute::NoInline);
Serge Guelton59a2d7b2017-04-11 15:01:18 +0000426 Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T));
Vasileios Kalintiris42db3ff2016-03-14 15:05:30 +0000427 CallInst::Create(F, Params, "", &I);
428 } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
Manuel Jacob190577a2016-01-17 22:37:39 +0000429 FunctionType *FT = CI->getFunctionType();
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000430 Function *F_ = CI->getCalledFunction();
Manuel Jacob190577a2016-01-17 22:37:39 +0000431 if (needsFPReturnHelper(*FT) &&
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000432 !(F_ && isIntrinsicInline(F_))) {
433 Modified=true;
434 F.addFnAttr("saveS2");
435 }
436 if (F_ && !isIntrinsicInline(F_)) {
437 // pic mode calls are handled by already defined
438 // helper functions
439 if (needsFPReturnHelper(*F_)) {
Reed Kotler2500bd62013-12-18 23:57:48 +0000440 Modified=true;
441 F.addFnAttr("saveS2");
442 }
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000443 if (!TM.isPositionIndependent()) {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000444 if (needsFPHelperFromSig(*F_)) {
445 assureFPCallStub(*F_, M, TM);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000446 Modified=true;
447 }
448 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000449 }
Reed Kotler783c7942013-05-10 22:25:39 +0000450 }
451 }
452 return Modified;
453}
454
Reed Kotler515e9372013-05-16 02:17:42 +0000455static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000456 const MipsTargetMachine &TM) {
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000457 bool PicMode = TM.isPositionIndependent();
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000458 bool LE = TM.isLittleEndian();
Reed Kotler515e9372013-05-16 02:17:42 +0000459 LLVMContext &Context = M->getContext();
460 std::string Name = F->getName();
461 std::string SectionName = ".mips16.fn." + Name;
462 std::string StubName = "__fn_stub_" + Name;
Reed Kotlera6ce7972013-09-25 20:58:50 +0000463 std::string LocalName = "$$__fn_local_" + Name;
Reed Kotler515e9372013-05-16 02:17:42 +0000464 Function *FStub = Function::Create
465 (F->getFunctionType(),
Reed Kotler302ae6b2013-08-01 02:26:31 +0000466 Function::InternalLinkage, StubName, M);
Reed Kotler515e9372013-05-16 02:17:42 +0000467 FStub->addFnAttr("mips16_fp_stub");
468 FStub->addFnAttr(llvm::Attribute::Naked);
469 FStub->addFnAttr(llvm::Attribute::NoUnwind);
Reed Kotler302ae6b2013-08-01 02:26:31 +0000470 FStub->addFnAttr(llvm::Attribute::NoInline);
Reed Kotler515e9372013-05-16 02:17:42 +0000471 FStub->addFnAttr("nomips16");
472 FStub->setSection(SectionName);
473 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000474
475 std::string AsmText;
Reed Kotler515e9372013-05-16 02:17:42 +0000476 if (PicMode) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000477 AsmText += ".set noreorder\n";
478 AsmText += ".cpload $$25\n";
479 AsmText += ".set reorder\n";
480 AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n";
481 AsmText += "la $$25, " + LocalName + "\n";
482 } else
483 AsmText += "la $$25, " + Name + "\n";
484 AsmText += swapFPIntParams(PV, M, LE, false);
485 AsmText += "jr $$25\n";
486 AsmText += LocalName + " = " + Name + "\n";
487 EmitInlineAsm(Context, BB, AsmText);
488
Reed Kotler515e9372013-05-16 02:17:42 +0000489 new UnreachableInst(FStub->getContext(), BB);
490}
491
Reed Kotlerc03807a2013-08-30 19:40:56 +0000492//
493// remove the use-soft-float attribute
494//
495static void removeUseSoftFloat(Function &F) {
Reid Kleckneree4930b2017-05-02 22:07:37 +0000496 AttrBuilder B;
Reed Kotlerc03807a2013-08-30 19:40:56 +0000497 DEBUG(errs() << "removing -use-soft-float\n");
Reid Kleckneree4930b2017-05-02 22:07:37 +0000498 B.addAttribute("use-soft-float", "false");
499 F.removeAttributes(AttributeList::FunctionIndex, B);
Reed Kotlerc03807a2013-08-30 19:40:56 +0000500 if (F.hasFnAttribute("use-soft-float")) {
501 DEBUG(errs() << "still has -use-soft-float\n");
502 }
Reid Kleckneree4930b2017-05-02 22:07:37 +0000503 F.addAttributes(AttributeList::FunctionIndex, B);
Reed Kotlerc03807a2013-08-30 19:40:56 +0000504}
505
Reed Kotler783c7942013-05-10 22:25:39 +0000506
507//
508// This pass only makes sense when the underlying chip has floating point but
509// we are compiling as mips16.
510// For all mips16 functions (that are not stubs we have already generated), or
511// declared via attributes as nomips16, we must:
512// 1) fixup all returns of float, double, single and double complex
513// by calling a helper function before the actual return.
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000514// 2) generate helper functions (stubs) that can be called by mips32
515// functions that will move parameters passed normally passed in
516// floating point
Reed Kotler515e9372013-05-16 02:17:42 +0000517// registers the soft float equivalents.
Reed Kotler783c7942013-05-10 22:25:39 +0000518// 3) in the case of static relocation, generate helper functions so that
519// mips16 functions can call extern functions of unknown type (mips16 or
Reed Kotler515e9372013-05-16 02:17:42 +0000520// mips32).
Reed Kotler783c7942013-05-10 22:25:39 +0000521// 4) TBD. For pic, calls to extern functions of unknown type are handled by
522// predefined helper functions in libc but this work is currently done
523// during call lowering but it should be moved here in the future.
524//
525bool Mips16HardFloat::runOnModule(Module &M) {
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +0000526 auto &TM = static_cast<const MipsTargetMachine &>(
527 getAnalysis<TargetPassConfig>().getTM<TargetMachine>());
Reed Kotler783c7942013-05-10 22:25:39 +0000528 DEBUG(errs() << "Run on Module Mips16HardFloat\n");
529 bool Modified = false;
530 for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
Reed Kotlerc03807a2013-08-30 19:40:56 +0000531 if (F->hasFnAttribute("nomips16") &&
532 F->hasFnAttribute("use-soft-float")) {
533 removeUseSoftFloat(*F);
534 continue;
535 }
Reed Kotler783c7942013-05-10 22:25:39 +0000536 if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
537 F->hasFnAttribute("nomips16")) continue;
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000538 Modified |= fixupFPReturnAndCall(*F, &M, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000539 FPParamVariant V = whichFPParamVariantNeeded(*F);
540 if (V != NoSig) {
541 Modified = true;
Duncan P. N. Exon Smith78691482015-10-20 00:15:20 +0000542 createFPFnStub(&*F, &M, V, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000543 }
Reed Kotler783c7942013-05-10 22:25:39 +0000544 }
545 return Modified;
546}
547
Reed Kotler783c7942013-05-10 22:25:39 +0000548
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +0000549ModulePass *llvm::createMips16HardFloatPass() {
550 return new Mips16HardFloat();
Reed Kotler783c7942013-05-10 22:25:39 +0000551}