]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/Target/Mips/Mips16HardFloat.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / Target / Mips / Mips16HardFloat.cpp
1 //===- 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
14 #include "MipsTargetMachine.h"
15 #include "llvm/CodeGen/TargetPassConfig.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/IR/Value.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/raw_ostream.h"
20 #include <algorithm>
21 #include <string>
22
23 using namespace llvm;
24
25 #define DEBUG_TYPE "mips16-hard-float"
26
27 namespace {
28
29   class Mips16HardFloat : public ModulePass {
30   public:
31     static char ID;
32
33     Mips16HardFloat() : ModulePass(ID) {}
34
35     StringRef getPassName() const override { return "MIPS16 Hard Float Pass"; }
36
37     void getAnalysisUsage(AnalysisUsage &AU) const override {
38       AU.addRequired<TargetPassConfig>();
39       ModulePass::getAnalysisUsage(AU);
40     }
41
42     bool runOnModule(Module &M) override;
43   };
44
45 } // end anonymous namespace
46
47 static void EmitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) {
48   std::vector<Type *> AsmArgTypes;
49   std::vector<Value *> AsmArgs;
50
51   FunctionType *AsmFTy =
52       FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false);
53   InlineAsm *IA = InlineAsm::get(AsmFTy, AsmText, "", true,
54                                  /* IsAlignStack */ false, InlineAsm::AD_ATT);
55   CallInst::Create(IA, AsmArgs, "", BB);
56 }
57
58 char Mips16HardFloat::ID = 0;
59
60 //
61 // Return types that matter for hard float are:
62 // float, double, complex float, and complex double
63 //
64 enum FPReturnVariant {
65   FRet, DRet, CFRet, CDRet, NoFPRet
66 };
67
68 //
69 // Determine which FP return type this function has
70 //
71 static FPReturnVariant whichFPReturnVariant(Type *T) {
72   switch (T->getTypeID()) {
73   case Type::FloatTyID:
74     return FRet;
75   case Type::DoubleTyID:
76     return DRet;
77   case Type::StructTyID:
78     if (T->getStructNumElements() != 2)
79       break;
80     if ((T->getContainedType(0)->isFloatTy()) &&
81         (T->getContainedType(1)->isFloatTy()))
82       return CFRet;
83     if ((T->getContainedType(0)->isDoubleTy()) &&
84         (T->getContainedType(1)->isDoubleTy()))
85       return CDRet;
86     break;
87   default:
88     break;
89   }
90   return NoFPRet;
91 }
92
93 // Parameter type that matter are float, (float, float), (float, double),
94 // double, (double, double), (double, float)
95 enum FPParamVariant {
96   FSig, FFSig, FDSig,
97   DSig, DDSig, DFSig, NoSig
98 };
99
100 // which floating point parameter signature variant we are dealing with
101 using TypeID = Type::TypeID;
102 const Type::TypeID FloatTyID = Type::FloatTyID;
103 const Type::TypeID DoubleTyID = Type::DoubleTyID;
104
105 static FPParamVariant whichFPParamVariantNeeded(Function &F) {
106   switch (F.arg_size()) {
107   case 0:
108     return NoSig;
109   case 1:{
110     TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
111     switch (ArgTypeID) {
112     case FloatTyID:
113       return FSig;
114     case DoubleTyID:
115       return DSig;
116     default:
117       return NoSig;
118     }
119   }
120   default: {
121     TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
122     TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
123     switch(ArgTypeID0) {
124     case FloatTyID: {
125       switch (ArgTypeID1) {
126       case FloatTyID:
127         return FFSig;
128       case DoubleTyID:
129         return FDSig;
130       default:
131         return FSig;
132       }
133     }
134     case DoubleTyID: {
135       switch (ArgTypeID1) {
136       case FloatTyID:
137         return DFSig;
138       case DoubleTyID:
139         return DDSig;
140       default:
141         return DSig;
142       }
143     }
144     default:
145       return NoSig;
146     }
147   }
148   }
149   llvm_unreachable("can't get here");
150 }
151
152 // Figure out if we need float point based on the function parameters.
153 // We need to move variables in and/or out of floating point
154 // registers because of the ABI
155 static bool needsFPStubFromParams(Function &F) {
156   if (F.arg_size() >=1) {
157     Type *ArgType = F.getFunctionType()->getParamType(0);
158     switch (ArgType->getTypeID()) {
159     case Type::FloatTyID:
160     case Type::DoubleTyID:
161       return true;
162     default:
163       break;
164     }
165   }
166   return false;
167 }
168
169 static bool needsFPReturnHelper(Function &F) {
170   Type* RetType = F.getReturnType();
171   return whichFPReturnVariant(RetType) != NoFPRet;
172 }
173
174 static bool needsFPReturnHelper(FunctionType &FT) {
175   Type* RetType = FT.getReturnType();
176   return whichFPReturnVariant(RetType) != NoFPRet;
177 }
178
179 static bool needsFPHelperFromSig(Function &F) {
180   return needsFPStubFromParams(F) || needsFPReturnHelper(F);
181 }
182
183 // We swap between FP and Integer registers to allow Mips16 and Mips32 to
184 // interoperate
185 static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE,
186                                    bool ToFP) {
187   std::string MI = ToFP ? "mtc1 ": "mfc1 ";
188   std::string AsmText;
189
190   switch (PV) {
191   case FSig:
192     AsmText += MI + "$$4, $$f12\n";
193     break;
194
195   case FFSig:
196     AsmText += MI + "$$4, $$f12\n";
197     AsmText += MI + "$$5, $$f14\n";
198     break;
199
200   case FDSig:
201     AsmText += MI + "$$4, $$f12\n";
202     if (LE) {
203       AsmText += MI + "$$6, $$f14\n";
204       AsmText += MI + "$$7, $$f15\n";
205     } else {
206       AsmText += MI + "$$7, $$f14\n";
207       AsmText += MI + "$$6, $$f15\n";
208     }
209     break;
210
211   case DSig:
212     if (LE) {
213       AsmText += MI + "$$4, $$f12\n";
214       AsmText += MI + "$$5, $$f13\n";
215     } else {
216       AsmText += MI + "$$5, $$f12\n";
217       AsmText += MI + "$$4, $$f13\n";
218     }
219     break;
220
221   case DDSig:
222     if (LE) {
223       AsmText += MI + "$$4, $$f12\n";
224       AsmText += MI + "$$5, $$f13\n";
225       AsmText += MI + "$$6, $$f14\n";
226       AsmText += MI + "$$7, $$f15\n";
227     } else {
228       AsmText += MI + "$$5, $$f12\n";
229       AsmText += MI + "$$4, $$f13\n";
230       AsmText += MI + "$$7, $$f14\n";
231       AsmText += MI + "$$6, $$f15\n";
232     }
233     break;
234
235   case DFSig:
236     if (LE) {
237       AsmText += MI + "$$4, $$f12\n";
238       AsmText += MI + "$$5, $$f13\n";
239     } else {
240       AsmText += MI + "$$5, $$f12\n";
241       AsmText += MI + "$$4, $$f13\n";
242     }
243     AsmText += MI + "$$6, $$f14\n";
244     break;
245
246   case NoSig:
247     break;
248   }
249
250   return AsmText;
251 }
252
253 // Make sure that we know we already need a stub for this function.
254 // Having called needsFPHelperFromSig
255 static void assureFPCallStub(Function &F, Module *M,
256                              const MipsTargetMachine &TM) {
257   // for now we only need them for static relocation
258   if (TM.isPositionIndependent())
259     return;
260   LLVMContext &Context = M->getContext();
261   bool LE = TM.isLittleEndian();
262   std::string Name = F.getName();
263   std::string SectionName = ".mips16.call.fp." + Name;
264   std::string StubName = "__call_stub_fp_" + Name;
265   //
266   // see if we already have the stub
267   //
268   Function *FStub = M->getFunction(StubName);
269   if (FStub && !FStub->isDeclaration()) return;
270   FStub = Function::Create(F.getFunctionType(),
271                            Function::InternalLinkage, StubName, M);
272   FStub->addFnAttr("mips16_fp_stub");
273   FStub->addFnAttr(Attribute::Naked);
274   FStub->addFnAttr(Attribute::NoInline);
275   FStub->addFnAttr(Attribute::NoUnwind);
276   FStub->addFnAttr("nomips16");
277   FStub->setSection(SectionName);
278   BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
279   FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
280   FPParamVariant PV = whichFPParamVariantNeeded(F);
281
282   std::string AsmText;
283   AsmText += ".set reorder\n";
284   AsmText += swapFPIntParams(PV, M, LE, true);
285   if (RV != NoFPRet) {
286     AsmText += "move $$18, $$31\n";
287     AsmText += "jal " + Name + "\n";
288   } else {
289     AsmText += "lui  $$25, %hi(" + Name + ")\n";
290     AsmText += "addiu  $$25, $$25, %lo(" + Name + ")\n";
291   }
292
293   switch (RV) {
294   case FRet:
295     AsmText += "mfc1 $$2, $$f0\n";
296     break;
297
298   case DRet:
299     if (LE) {
300       AsmText += "mfc1 $$2, $$f0\n";
301       AsmText += "mfc1 $$3, $$f1\n";
302     } else {
303       AsmText += "mfc1 $$3, $$f0\n";
304       AsmText += "mfc1 $$2, $$f1\n";
305     }
306     break;
307
308   case CFRet:
309     if (LE) {
310       AsmText += "mfc1 $$2, $$f0\n";
311       AsmText += "mfc1 $$3, $$f2\n";
312     } else {
313       AsmText += "mfc1 $$3, $$f0\n";
314       AsmText += "mfc1 $$3, $$f2\n";
315     }
316     break;
317
318   case CDRet:
319     if (LE) {
320       AsmText += "mfc1 $$4, $$f2\n";
321       AsmText += "mfc1 $$5, $$f3\n";
322       AsmText += "mfc1 $$2, $$f0\n";
323       AsmText += "mfc1 $$3, $$f1\n";
324
325     } else {
326       AsmText += "mfc1 $$5, $$f2\n";
327       AsmText += "mfc1 $$4, $$f3\n";
328       AsmText += "mfc1 $$3, $$f0\n";
329       AsmText += "mfc1 $$2, $$f1\n";
330     }
331     break;
332
333   case NoFPRet:
334     break;
335   }
336
337   if (RV != NoFPRet)
338     AsmText += "jr $$18\n";
339   else
340     AsmText += "jr $$25\n";
341   EmitInlineAsm(Context, BB, AsmText);
342
343   new UnreachableInst(Context, BB);
344 }
345
346 // Functions that are llvm intrinsics and don't need helpers.
347 static const char *const IntrinsicInline[] = {
348   "fabs", "fabsf",
349   "llvm.ceil.f32", "llvm.ceil.f64",
350   "llvm.copysign.f32", "llvm.copysign.f64",
351   "llvm.cos.f32", "llvm.cos.f64",
352   "llvm.exp.f32", "llvm.exp.f64",
353   "llvm.exp2.f32", "llvm.exp2.f64",
354   "llvm.fabs.f32", "llvm.fabs.f64",
355   "llvm.floor.f32", "llvm.floor.f64",
356   "llvm.fma.f32", "llvm.fma.f64",
357   "llvm.log.f32", "llvm.log.f64",
358   "llvm.log10.f32", "llvm.log10.f64",
359   "llvm.nearbyint.f32", "llvm.nearbyint.f64",
360   "llvm.pow.f32", "llvm.pow.f64",
361   "llvm.powi.f32", "llvm.powi.f64",
362   "llvm.rint.f32", "llvm.rint.f64",
363   "llvm.round.f32", "llvm.round.f64",
364   "llvm.sin.f32", "llvm.sin.f64",
365   "llvm.sqrt.f32", "llvm.sqrt.f64",
366   "llvm.trunc.f32", "llvm.trunc.f64",
367 };
368
369 static bool isIntrinsicInline(Function *F) {
370   return std::binary_search(std::begin(IntrinsicInline),
371                             std::end(IntrinsicInline), F->getName());
372 }
373
374 // Returns of float, double and complex need to be handled with a helper
375 // function.
376 static bool fixupFPReturnAndCall(Function &F, Module *M,
377                                  const MipsTargetMachine &TM) {
378   bool Modified = false;
379   LLVMContext &C = M->getContext();
380   Type *MyVoid = Type::getVoidTy(C);
381   for (auto &BB: F)
382     for (auto &I: BB) {
383       if (const ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
384         Value *RVal = RI->getReturnValue();
385         if (!RVal) continue;
386         //
387         // If there is a return value and it needs a helper function,
388         // figure out which one and add a call before the actual
389         // return to this helper. The purpose of the helper is to move
390         // floating point values from their soft float return mapping to
391         // where they would have been mapped to in floating point registers.
392         //
393         Type *T = RVal->getType();
394         FPReturnVariant RV = whichFPReturnVariant(T);
395         if (RV == NoFPRet) continue;
396         static const char *const Helper[NoFPRet] = {
397           "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
398           "__mips16_ret_dc"
399         };
400         const char *Name = Helper[RV];
401         AttributeList A;
402         Value *Params[] = {RVal};
403         Modified = true;
404         //
405         // These helper functions have a different calling ABI so
406         // this __Mips16RetHelper indicates that so that later
407         // during call setup, the proper call lowering to the helper
408         // functions will take place.
409         //
410         A = A.addAttribute(C, AttributeList::FunctionIndex,
411                            "__Mips16RetHelper");
412         A = A.addAttribute(C, AttributeList::FunctionIndex,
413                            Attribute::ReadNone);
414         A = A.addAttribute(C, AttributeList::FunctionIndex,
415                            Attribute::NoInline);
416         Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T));
417         CallInst::Create(F, Params, "", &I);
418       } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
419         FunctionType *FT = CI->getFunctionType();
420         Function *F_ =  CI->getCalledFunction();
421         if (needsFPReturnHelper(*FT) &&
422             !(F_ && isIntrinsicInline(F_))) {
423           Modified=true;
424           F.addFnAttr("saveS2");
425         }
426         if (F_ && !isIntrinsicInline(F_)) {
427           // pic mode calls are handled by already defined
428           // helper functions
429           if (needsFPReturnHelper(*F_)) {
430             Modified=true;
431             F.addFnAttr("saveS2");
432           }
433           if (!TM.isPositionIndependent()) {
434             if (needsFPHelperFromSig(*F_)) {
435               assureFPCallStub(*F_, M, TM);
436               Modified=true;
437             }
438           }
439         }
440       }
441     }
442   return Modified;
443 }
444
445 static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
446                            const MipsTargetMachine &TM) {
447   bool PicMode = TM.isPositionIndependent();
448   bool LE = TM.isLittleEndian();
449   LLVMContext &Context = M->getContext();
450   std::string Name = F->getName();
451   std::string SectionName = ".mips16.fn." + Name;
452   std::string StubName = "__fn_stub_" + Name;
453   std::string LocalName = "$$__fn_local_" + Name;
454   Function *FStub = Function::Create
455     (F->getFunctionType(),
456      Function::InternalLinkage, StubName, M);
457   FStub->addFnAttr("mips16_fp_stub");
458   FStub->addFnAttr(Attribute::Naked);
459   FStub->addFnAttr(Attribute::NoUnwind);
460   FStub->addFnAttr(Attribute::NoInline);
461   FStub->addFnAttr("nomips16");
462   FStub->setSection(SectionName);
463   BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
464
465   std::string AsmText;
466   if (PicMode) {
467     AsmText += ".set noreorder\n";
468     AsmText += ".cpload $$25\n";
469     AsmText += ".set reorder\n";
470     AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n";
471     AsmText += "la $$25, " + LocalName + "\n";
472   } else
473     AsmText += "la $$25, " + Name + "\n";
474   AsmText += swapFPIntParams(PV, M, LE, false);
475   AsmText += "jr $$25\n";
476   AsmText += LocalName + " = " + Name + "\n";
477   EmitInlineAsm(Context, BB, AsmText);
478
479   new UnreachableInst(FStub->getContext(), BB);
480 }
481
482 // remove the use-soft-float attribute
483 static void removeUseSoftFloat(Function &F) {
484   AttrBuilder B;
485   LLVM_DEBUG(errs() << "removing -use-soft-float\n");
486   B.addAttribute("use-soft-float", "false");
487   F.removeAttributes(AttributeList::FunctionIndex, B);
488   if (F.hasFnAttribute("use-soft-float")) {
489     LLVM_DEBUG(errs() << "still has -use-soft-float\n");
490   }
491   F.addAttributes(AttributeList::FunctionIndex, B);
492 }
493
494 // This pass only makes sense when the underlying chip has floating point but
495 // we are compiling as mips16.
496 // For all mips16 functions (that are not stubs we have already generated), or
497 // declared via attributes as nomips16, we must:
498 //    1) fixup all returns of float, double, single and double complex
499 //       by calling a helper function before the actual return.
500 //    2) generate helper functions (stubs) that can be called by mips32
501 //       functions that will move parameters passed normally passed in
502 //       floating point
503 //       registers the soft float equivalents.
504 //    3) in the case of static relocation, generate helper functions so that
505 //       mips16 functions can call extern functions of unknown type (mips16 or
506 //       mips32).
507 //    4) TBD. For pic, calls to extern functions of unknown type are handled by
508 //       predefined helper functions in libc but this work is currently done
509 //       during call lowering but it should be moved here in the future.
510 bool Mips16HardFloat::runOnModule(Module &M) {
511   auto &TM = static_cast<const MipsTargetMachine &>(
512       getAnalysis<TargetPassConfig>().getTM<TargetMachine>());
513   LLVM_DEBUG(errs() << "Run on Module Mips16HardFloat\n");
514   bool Modified = false;
515   for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
516     if (F->hasFnAttribute("nomips16") &&
517         F->hasFnAttribute("use-soft-float")) {
518       removeUseSoftFloat(*F);
519       continue;
520     }
521     if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
522         F->hasFnAttribute("nomips16")) continue;
523     Modified |= fixupFPReturnAndCall(*F, &M, TM);
524     FPParamVariant V = whichFPParamVariantNeeded(*F);
525     if (V != NoSig) {
526       Modified = true;
527       createFPFnStub(&*F, &M, V, TM);
528     }
529   }
530   return Modified;
531 }
532
533 ModulePass *llvm::createMips16HardFloatPass() {
534   return new Mips16HardFloat();
535 }