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