blob: e9a3c7ec4b190b8fb80dd0b28a0f58727762dba4 [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//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Reed Kotler783c7942013-05-10 22:25:39 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file defines a pass needed for Mips16 Hard Float
10//
11//===----------------------------------------------------------------------===//
12
Benjamin Kramer16132e62015-03-23 18:07:13 +000013#include "MipsTargetMachine.h"
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +000014#include "llvm/CodeGen/TargetPassConfig.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 {
Eugene Zelenko79220eae2017-08-03 22:12:30 +000027
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
Eugene Zelenko79220eae2017-08-03 22:12:30 +000044} // end anonymous namespace
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000045
Eugene Zelenko79220eae2017-08-03 22:12:30 +000046static void EmitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) {
47 std::vector<Type *> AsmArgTypes;
48 std::vector<Value *> AsmArgs;
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000049
Eugene Zelenko79220eae2017-08-03 22:12:30 +000050 FunctionType *AsmFTy =
51 FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false);
52 InlineAsm *IA = InlineAsm::get(AsmFTy, AsmText, "", true,
53 /* IsAlignStack */ false, InlineAsm::AD_ATT);
54 CallInst::Create(IA, AsmArgs, "", BB);
Alexander Kornienkof00654e2015-06-23 09:49:53 +000055}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +000056
Eugene Zelenko79220eae2017-08-03 22:12:30 +000057char Mips16HardFloat::ID = 0;
58
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;
James Y Knight62df5ee2019-01-10 16:07:20 +000076 case Type::StructTyID: {
77 StructType *ST = cast<StructType>(T);
78 if (ST->getNumElements() != 2)
Reed Kotler783c7942013-05-10 22:25:39 +000079 break;
James Y Knight62df5ee2019-01-10 16:07:20 +000080 if ((ST->getElementType(0)->isFloatTy()) &&
81 (ST->getElementType(1)->isFloatTy()))
Reed Kotler783c7942013-05-10 22:25:39 +000082 return CFRet;
James Y Knight62df5ee2019-01-10 16:07:20 +000083 if ((ST->getElementType(0)->isDoubleTy()) &&
84 (ST->getElementType(1)->isDoubleTy()))
Reed Kotler783c7942013-05-10 22:25:39 +000085 return CDRet;
86 break;
James Y Knight62df5ee2019-01-10 16:07:20 +000087 }
Reed Kotler783c7942013-05-10 22:25:39 +000088 default:
89 break;
90 }
91 return NoFPRet;
92}
93
Reed Kotler2c4657d2013-05-14 02:00:24 +000094// Parameter type that matter are float, (float, float), (float, double),
95// double, (double, double), (double, float)
Reed Kotler2c4657d2013-05-14 02:00:24 +000096enum FPParamVariant {
97 FSig, FFSig, FDSig,
98 DSig, DDSig, DFSig, NoSig
99};
100
101// which floating point parameter signature variant we are dealing with
Eugene Zelenko79220eae2017-08-03 22:12:30 +0000102using TypeID = Type::TypeID;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000103const 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
Reed Kotler2c4657d2013-05-14 02:00:24 +0000156static bool needsFPStubFromParams(Function &F) {
157 if (F.arg_size() >=1) {
158 Type *ArgType = F.getFunctionType()->getParamType(0);
159 switch (ArgType->getTypeID()) {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000160 case Type::FloatTyID:
161 case Type::DoubleTyID:
162 return true;
163 default:
164 break;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000165 }
166 }
167 return false;
168}
169
170static bool needsFPReturnHelper(Function &F) {
171 Type* RetType = F.getReturnType();
172 return whichFPReturnVariant(RetType) != NoFPRet;
173}
174
Craig Toppere3dcce92015-08-01 22:20:21 +0000175static bool needsFPReturnHelper(FunctionType &FT) {
Reed Kotler2500bd62013-12-18 23:57:48 +0000176 Type* RetType = FT.getReturnType();
177 return whichFPReturnVariant(RetType) != NoFPRet;
178}
179
Reed Kotler2c4657d2013-05-14 02:00:24 +0000180static bool needsFPHelperFromSig(Function &F) {
181 return needsFPStubFromParams(F) || needsFPReturnHelper(F);
182}
183
Reed Kotler2c4657d2013-05-14 02:00:24 +0000184// We swap between FP and Integer registers to allow Mips16 and Mips32 to
185// interoperate
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000186static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE,
187 bool ToFP) {
188 std::string MI = ToFP ? "mtc1 ": "mfc1 ";
189 std::string AsmText;
190
Reed Kotler2c4657d2013-05-14 02:00:24 +0000191 switch (PV) {
192 case FSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000193 AsmText += MI + "$$4, $$f12\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000194 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000195
Reed Kotler2c4657d2013-05-14 02:00:24 +0000196 case FFSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000197 AsmText += MI + "$$4, $$f12\n";
198 AsmText += MI + "$$5, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000199 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000200
Reed Kotler2c4657d2013-05-14 02:00:24 +0000201 case FDSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000202 AsmText += MI + "$$4, $$f12\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000203 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000204 AsmText += MI + "$$6, $$f14\n";
205 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000206 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000207 AsmText += MI + "$$7, $$f14\n";
208 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000209 }
210 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000211
Reed Kotler2c4657d2013-05-14 02:00:24 +0000212 case DSig:
213 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000214 AsmText += MI + "$$4, $$f12\n";
215 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000216 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000217 AsmText += MI + "$$5, $$f12\n";
218 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000219 }
220 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000221
Reed Kotler2c4657d2013-05-14 02:00:24 +0000222 case DDSig:
223 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000224 AsmText += MI + "$$4, $$f12\n";
225 AsmText += MI + "$$5, $$f13\n";
226 AsmText += MI + "$$6, $$f14\n";
227 AsmText += MI + "$$7, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000228 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000229 AsmText += MI + "$$5, $$f12\n";
230 AsmText += MI + "$$4, $$f13\n";
231 AsmText += MI + "$$7, $$f14\n";
232 AsmText += MI + "$$6, $$f15\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000233 }
234 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000235
Reed Kotler2c4657d2013-05-14 02:00:24 +0000236 case DFSig:
237 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000238 AsmText += MI + "$$4, $$f12\n";
239 AsmText += MI + "$$5, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000240 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000241 AsmText += MI + "$$5, $$f12\n";
242 AsmText += MI + "$$4, $$f13\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000243 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000244 AsmText += MI + "$$6, $$f14\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000245 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000246
Reed Kotler2c4657d2013-05-14 02:00:24 +0000247 case NoSig:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000248 break;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000249 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000250
251 return AsmText;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000252}
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000253
Reed Kotler2c4657d2013-05-14 02:00:24 +0000254// Make sure that we know we already need a stub for this function.
255// Having called needsFPHelperFromSig
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000256static void assureFPCallStub(Function &F, Module *M,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000257 const MipsTargetMachine &TM) {
Reed Kotler2c4657d2013-05-14 02:00:24 +0000258 // for now we only need them for static relocation
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000259 if (TM.isPositionIndependent())
Reed Kotler2c4657d2013-05-14 02:00:24 +0000260 return;
261 LLVMContext &Context = M->getContext();
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000262 bool LE = TM.isLittleEndian();
Reed Kotler2c4657d2013-05-14 02:00:24 +0000263 std::string Name = F.getName();
264 std::string SectionName = ".mips16.call.fp." + Name;
Reed Kotler302ae6b2013-08-01 02:26:31 +0000265 std::string StubName = "__call_stub_fp_" + Name;
Reed Kotler2c4657d2013-05-14 02:00:24 +0000266 //
267 // see if we already have the stub
268 //
269 Function *FStub = M->getFunction(StubName);
270 if (FStub && !FStub->isDeclaration()) return;
271 FStub = Function::Create(F.getFunctionType(),
272 Function::InternalLinkage, StubName, M);
273 FStub->addFnAttr("mips16_fp_stub");
Eugene Zelenko79220eae2017-08-03 22:12:30 +0000274 FStub->addFnAttr(Attribute::Naked);
275 FStub->addFnAttr(Attribute::NoInline);
276 FStub->addFnAttr(Attribute::NoUnwind);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000277 FStub->addFnAttr("nomips16");
278 FStub->setSection(SectionName);
279 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000280 FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
281 FPParamVariant PV = whichFPParamVariantNeeded(F);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000282
283 std::string AsmText;
284 AsmText += ".set reorder\n";
285 AsmText += swapFPIntParams(PV, M, LE, true);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000286 if (RV != NoFPRet) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000287 AsmText += "move $$18, $$31\n";
288 AsmText += "jal " + Name + "\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000289 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000290 AsmText += "lui $$25, %hi(" + Name + ")\n";
291 AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000292 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000293
Reed Kotler2c4657d2013-05-14 02:00:24 +0000294 switch (RV) {
295 case FRet:
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000296 AsmText += "mfc1 $$2, $$f0\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000297 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000298
Reed Kotler2c4657d2013-05-14 02:00:24 +0000299 case DRet:
300 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000301 AsmText += "mfc1 $$2, $$f0\n";
302 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000303 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000304 AsmText += "mfc1 $$3, $$f0\n";
305 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000306 }
307 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000308
Reed Kotler2c4657d2013-05-14 02:00:24 +0000309 case CFRet:
310 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000311 AsmText += "mfc1 $$2, $$f0\n";
312 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000313 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000314 AsmText += "mfc1 $$3, $$f0\n";
315 AsmText += "mfc1 $$3, $$f2\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000316 }
317 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000318
Reed Kotler2c4657d2013-05-14 02:00:24 +0000319 case CDRet:
320 if (LE) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000321 AsmText += "mfc1 $$4, $$f2\n";
322 AsmText += "mfc1 $$5, $$f3\n";
323 AsmText += "mfc1 $$2, $$f0\n";
324 AsmText += "mfc1 $$3, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000325
326 } else {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000327 AsmText += "mfc1 $$5, $$f2\n";
328 AsmText += "mfc1 $$4, $$f3\n";
329 AsmText += "mfc1 $$3, $$f0\n";
330 AsmText += "mfc1 $$2, $$f1\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000331 }
332 break;
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000333
Reed Kotler2c4657d2013-05-14 02:00:24 +0000334 case NoFPRet:
335 break;
336 }
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000337
Reed Kotler2c4657d2013-05-14 02:00:24 +0000338 if (RV != NoFPRet)
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000339 AsmText += "jr $$18\n";
Reed Kotler2c4657d2013-05-14 02:00:24 +0000340 else
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000341 AsmText += "jr $$25\n";
342 EmitInlineAsm(Context, BB, AsmText);
343
Reed Kotler2c4657d2013-05-14 02:00:24 +0000344 new UnreachableInst(Context, BB);
345}
346
Reed Kotler5fdadce2013-09-01 04:12:59 +0000347// Functions that are llvm intrinsics and don't need helpers.
Craig Topper26260942015-10-18 05:15:34 +0000348static const char *const IntrinsicInline[] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000349 "fabs", "fabsf",
350 "llvm.ceil.f32", "llvm.ceil.f64",
351 "llvm.copysign.f32", "llvm.copysign.f64",
352 "llvm.cos.f32", "llvm.cos.f64",
353 "llvm.exp.f32", "llvm.exp.f64",
354 "llvm.exp2.f32", "llvm.exp2.f64",
355 "llvm.fabs.f32", "llvm.fabs.f64",
356 "llvm.floor.f32", "llvm.floor.f64",
357 "llvm.fma.f32", "llvm.fma.f64",
358 "llvm.log.f32", "llvm.log.f64",
359 "llvm.log10.f32", "llvm.log10.f64",
360 "llvm.nearbyint.f32", "llvm.nearbyint.f64",
361 "llvm.pow.f32", "llvm.pow.f64",
362 "llvm.powi.f32", "llvm.powi.f64",
363 "llvm.rint.f32", "llvm.rint.f64",
364 "llvm.round.f32", "llvm.round.f64",
365 "llvm.sin.f32", "llvm.sin.f64",
366 "llvm.sqrt.f32", "llvm.sqrt.f64",
367 "llvm.trunc.f32", "llvm.trunc.f64",
368};
Reed Kotlerd265e882013-08-11 21:30:27 +0000369
Benjamin Kramerc9b7d472013-08-12 09:37:29 +0000370static bool isIntrinsicInline(Function *F) {
Benjamin Kramer502b9e12014-04-12 16:15:53 +0000371 return std::binary_search(std::begin(IntrinsicInline),
372 std::end(IntrinsicInline), F->getName());
Reed Kotlerd265e882013-08-11 21:30:27 +0000373}
Eugene Zelenko79220eae2017-08-03 22:12:30 +0000374
Reed Kotler783c7942013-05-10 22:25:39 +0000375// Returns of float, double and complex need to be handled with a helper
Reed Kotler515e9372013-05-16 02:17:42 +0000376// function.
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000377static bool fixupFPReturnAndCall(Function &F, Module *M,
378 const MipsTargetMachine &TM) {
Reed Kotler783c7942013-05-10 22:25:39 +0000379 bool Modified = false;
380 LLVMContext &C = M->getContext();
381 Type *MyVoid = Type::getVoidTy(C);
Vasileios Kalintiris42db3ff2016-03-14 15:05:30 +0000382 for (auto &BB: F)
383 for (auto &I: BB) {
384 if (const ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
Reed Kotler783c7942013-05-10 22:25:39 +0000385 Value *RVal = RI->getReturnValue();
386 if (!RVal) continue;
387 //
388 // If there is a return value and it needs a helper function,
389 // figure out which one and add a call before the actual
390 // return to this helper. The purpose of the helper is to move
391 // floating point values from their soft float return mapping to
392 // where they would have been mapped to in floating point registers.
393 //
394 Type *T = RVal->getType();
395 FPReturnVariant RV = whichFPReturnVariant(T);
396 if (RV == NoFPRet) continue;
Craig Topper26260942015-10-18 05:15:34 +0000397 static const char *const Helper[NoFPRet] = {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000398 "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
399 "__mips16_ret_dc"
400 };
Reed Kotler783c7942013-05-10 22:25:39 +0000401 const char *Name = Helper[RV];
Reid Klecknerb5180542017-03-21 16:57:19 +0000402 AttributeList A;
Reed Kotler783c7942013-05-10 22:25:39 +0000403 Value *Params[] = {RVal};
404 Modified = true;
405 //
406 // These helper functions have a different calling ABI so
407 // this __Mips16RetHelper indicates that so that later
408 // during call setup, the proper call lowering to the helper
409 // functions will take place.
410 //
Reid Klecknerb5180542017-03-21 16:57:19 +0000411 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler783c7942013-05-10 22:25:39 +0000412 "__Mips16RetHelper");
Reid Klecknerb5180542017-03-21 16:57:19 +0000413 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler783c7942013-05-10 22:25:39 +0000414 Attribute::ReadNone);
Reid Klecknerb5180542017-03-21 16:57:19 +0000415 A = A.addAttribute(C, AttributeList::FunctionIndex,
Reed Kotler302ae6b2013-08-01 02:26:31 +0000416 Attribute::NoInline);
James Y Knight13680222019-02-01 02:28:03 +0000417 FunctionCallee F = (M->getOrInsertFunction(Name, A, MyVoid, T));
Vasileios Kalintiris42db3ff2016-03-14 15:05:30 +0000418 CallInst::Create(F, Params, "", &I);
419 } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
Manuel Jacob190577a2016-01-17 22:37:39 +0000420 FunctionType *FT = CI->getFunctionType();
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000421 Function *F_ = CI->getCalledFunction();
Manuel Jacob190577a2016-01-17 22:37:39 +0000422 if (needsFPReturnHelper(*FT) &&
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000423 !(F_ && isIntrinsicInline(F_))) {
424 Modified=true;
425 F.addFnAttr("saveS2");
426 }
427 if (F_ && !isIntrinsicInline(F_)) {
428 // pic mode calls are handled by already defined
429 // helper functions
430 if (needsFPReturnHelper(*F_)) {
Reed Kotler2500bd62013-12-18 23:57:48 +0000431 Modified=true;
432 F.addFnAttr("saveS2");
433 }
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000434 if (!TM.isPositionIndependent()) {
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000435 if (needsFPHelperFromSig(*F_)) {
436 assureFPCallStub(*F_, M, TM);
Reed Kotler2c4657d2013-05-14 02:00:24 +0000437 Modified=true;
438 }
439 }
Vasileios Kalintiris6611eb32015-03-14 09:02:23 +0000440 }
Reed Kotler783c7942013-05-10 22:25:39 +0000441 }
442 }
443 return Modified;
444}
445
Reed Kotler515e9372013-05-16 02:17:42 +0000446static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000447 const MipsTargetMachine &TM) {
Rafael Espindolab30e66b2016-06-28 14:33:28 +0000448 bool PicMode = TM.isPositionIndependent();
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000449 bool LE = TM.isLittleEndian();
Reed Kotler515e9372013-05-16 02:17:42 +0000450 LLVMContext &Context = M->getContext();
451 std::string Name = F->getName();
452 std::string SectionName = ".mips16.fn." + Name;
453 std::string StubName = "__fn_stub_" + Name;
Reed Kotlera6ce7972013-09-25 20:58:50 +0000454 std::string LocalName = "$$__fn_local_" + Name;
Reed Kotler515e9372013-05-16 02:17:42 +0000455 Function *FStub = Function::Create
456 (F->getFunctionType(),
Reed Kotler302ae6b2013-08-01 02:26:31 +0000457 Function::InternalLinkage, StubName, M);
Reed Kotler515e9372013-05-16 02:17:42 +0000458 FStub->addFnAttr("mips16_fp_stub");
Eugene Zelenko79220eae2017-08-03 22:12:30 +0000459 FStub->addFnAttr(Attribute::Naked);
460 FStub->addFnAttr(Attribute::NoUnwind);
461 FStub->addFnAttr(Attribute::NoInline);
Reed Kotler515e9372013-05-16 02:17:42 +0000462 FStub->addFnAttr("nomips16");
463 FStub->setSection(SectionName);
464 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000465
466 std::string AsmText;
Reed Kotler515e9372013-05-16 02:17:42 +0000467 if (PicMode) {
Daniel Sandersd6cf3e02015-10-21 12:44:14 +0000468 AsmText += ".set noreorder\n";
469 AsmText += ".cpload $$25\n";
470 AsmText += ".set reorder\n";
471 AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n";
472 AsmText += "la $$25, " + LocalName + "\n";
473 } else
474 AsmText += "la $$25, " + Name + "\n";
475 AsmText += swapFPIntParams(PV, M, LE, false);
476 AsmText += "jr $$25\n";
477 AsmText += LocalName + " = " + Name + "\n";
478 EmitInlineAsm(Context, BB, AsmText);
479
Reed Kotler515e9372013-05-16 02:17:42 +0000480 new UnreachableInst(FStub->getContext(), BB);
481}
482
Reed Kotlerc03807a2013-08-30 19:40:56 +0000483// remove the use-soft-float attribute
Reed Kotlerc03807a2013-08-30 19:40:56 +0000484static void removeUseSoftFloat(Function &F) {
Reid Kleckneree4930b2017-05-02 22:07:37 +0000485 AttrBuilder B;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000486 LLVM_DEBUG(errs() << "removing -use-soft-float\n");
Reid Kleckneree4930b2017-05-02 22:07:37 +0000487 B.addAttribute("use-soft-float", "false");
488 F.removeAttributes(AttributeList::FunctionIndex, B);
Reed Kotlerc03807a2013-08-30 19:40:56 +0000489 if (F.hasFnAttribute("use-soft-float")) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000490 LLVM_DEBUG(errs() << "still has -use-soft-float\n");
Reed Kotlerc03807a2013-08-30 19:40:56 +0000491 }
Reid Kleckneree4930b2017-05-02 22:07:37 +0000492 F.addAttributes(AttributeList::FunctionIndex, B);
Reed Kotlerc03807a2013-08-30 19:40:56 +0000493}
494
Reed Kotler783c7942013-05-10 22:25:39 +0000495// This pass only makes sense when the underlying chip has floating point but
496// we are compiling as mips16.
497// For all mips16 functions (that are not stubs we have already generated), or
498// declared via attributes as nomips16, we must:
499// 1) fixup all returns of float, double, single and double complex
500// by calling a helper function before the actual return.
Reed Kotler4cdaa7d2014-02-14 19:16:39 +0000501// 2) generate helper functions (stubs) that can be called by mips32
502// functions that will move parameters passed normally passed in
503// floating point
Reed Kotler515e9372013-05-16 02:17:42 +0000504// registers the soft float equivalents.
Reed Kotler783c7942013-05-10 22:25:39 +0000505// 3) in the case of static relocation, generate helper functions so that
506// mips16 functions can call extern functions of unknown type (mips16 or
Reed Kotler515e9372013-05-16 02:17:42 +0000507// mips32).
Reed Kotler783c7942013-05-10 22:25:39 +0000508// 4) TBD. For pic, calls to extern functions of unknown type are handled by
509// predefined helper functions in libc but this work is currently done
510// during call lowering but it should be moved here in the future.
Reed Kotler783c7942013-05-10 22:25:39 +0000511bool Mips16HardFloat::runOnModule(Module &M) {
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +0000512 auto &TM = static_cast<const MipsTargetMachine &>(
513 getAnalysis<TargetPassConfig>().getTM<TargetMachine>());
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000514 LLVM_DEBUG(errs() << "Run on Module Mips16HardFloat\n");
Reed Kotler783c7942013-05-10 22:25:39 +0000515 bool Modified = false;
516 for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
Reed Kotlerc03807a2013-08-30 19:40:56 +0000517 if (F->hasFnAttribute("nomips16") &&
518 F->hasFnAttribute("use-soft-float")) {
519 removeUseSoftFloat(*F);
520 continue;
521 }
Reed Kotler783c7942013-05-10 22:25:39 +0000522 if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
523 F->hasFnAttribute("nomips16")) continue;
Eric Christopherd20ee0a2015-01-06 01:12:30 +0000524 Modified |= fixupFPReturnAndCall(*F, &M, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000525 FPParamVariant V = whichFPParamVariantNeeded(*F);
526 if (V != NoSig) {
527 Modified = true;
Duncan P. N. Exon Smith78691482015-10-20 00:15:20 +0000528 createFPFnStub(&*F, &M, V, TM);
Reed Kotler515e9372013-05-16 02:17:42 +0000529 }
Reed Kotler783c7942013-05-10 22:25:39 +0000530 }
531 return Modified;
532}
533
Francis Visoiu Mistrih8b617642017-05-18 17:21:13 +0000534ModulePass *llvm::createMips16HardFloatPass() {
535 return new Mips16HardFloat();
Reed Kotler783c7942013-05-10 22:25:39 +0000536}