This is the first of three patches which creates stubs used for
[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 #define DEBUG_TYPE "mips16-hard-float"
15 #include "Mips16HardFloat.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/Support/Debug.h"
18 #include "llvm/Support/raw_ostream.h"
19 #include <string>
20
21 static void inlineAsmOut
22   (LLVMContext &C, StringRef AsmString, BasicBlock *BB ) {
23   std::vector<llvm::Type *> AsmArgTypes;
24   std::vector<llvm::Value*> AsmArgs;
25   llvm::FunctionType *AsmFTy =
26     llvm::FunctionType::get(Type::getVoidTy(C),
27                             AsmArgTypes, false);
28   llvm::InlineAsm *IA =
29     llvm::InlineAsm::get(AsmFTy, AsmString, "", true,
30                          /* IsAlignStack */ false,
31                          llvm::InlineAsm::AD_ATT);
32   CallInst::Create(IA, AsmArgs, "", BB);
33 }
34
35 namespace {
36
37 class InlineAsmHelper {
38   LLVMContext &C;
39   BasicBlock *BB;
40 public:
41   InlineAsmHelper(LLVMContext &C_, BasicBlock *BB_) :
42     C(C_), BB(BB_) {
43   }
44
45   void Out(StringRef AsmString) {
46     inlineAsmOut(C, AsmString, BB);
47   }
48
49 };
50 }
51 //
52 // Return types that matter for hard float are:
53 // float, double, complex float, and complex double
54 //
55 enum FPReturnVariant {
56   FRet, DRet, CFRet, CDRet, NoFPRet
57 };
58
59 //
60 // Determine which FP return type this function has
61 //
62 static FPReturnVariant whichFPReturnVariant(Type *T) {
63   switch (T->getTypeID()) {
64   case Type::FloatTyID:
65     return FRet;
66   case Type::DoubleTyID:
67     return DRet;
68   case Type::StructTyID:
69     if (T->getStructNumElements() != 2)
70       break;
71     if ((T->getContainedType(0)->isFloatTy()) &&
72         (T->getContainedType(1)->isFloatTy()))
73       return CFRet;
74     if ((T->getContainedType(0)->isDoubleTy()) &&
75         (T->getContainedType(1)->isDoubleTy()))
76       return CDRet;
77     break;
78   default:
79     break;
80   }
81   return NoFPRet;
82 }
83
84 //
85 // Parameter type that matter are float, (float, float), (float, double),
86 // double, (double, double), (double, float)
87 //
88 enum FPParamVariant {
89   FSig, FFSig, FDSig,
90   DSig, DDSig, DFSig, NoSig
91 };
92
93 // which floating point parameter signature variant we are dealing with
94 //
95 typedef Type::TypeID TypeID;
96 const Type::TypeID FloatTyID = Type::FloatTyID;
97 const Type::TypeID DoubleTyID = Type::DoubleTyID;
98
99 static FPParamVariant whichFPParamVariantNeeded(Function &F) {
100   switch (F.arg_size()) {
101   case 0:
102     return NoSig;
103   case 1:{
104     TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
105     switch (ArgTypeID) {
106     case FloatTyID:
107       return FSig;
108     case DoubleTyID:
109       return DSig;
110     default:
111       return NoSig;
112     }
113   }
114   default: {
115     TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
116     TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
117     switch(ArgTypeID0) {
118     case FloatTyID: {
119       switch (ArgTypeID1) {
120       case FloatTyID:
121         return FFSig;
122       case DoubleTyID:
123         return FDSig;
124       default:
125         return FSig;
126       }
127     }
128     case DoubleTyID: {
129       switch (ArgTypeID1) {
130       case FloatTyID:
131         return DFSig;
132       case DoubleTyID:
133         return DDSig;
134       default:
135         return DSig;
136       }
137     }
138     default:
139       return NoSig;
140     }
141   }
142   }
143   llvm_unreachable("can't get here");
144 }
145
146 // Figure out if we need float point based on the function parameters.
147 // We need to move variables in and/or out of floating point
148 // registers because of the ABI
149 //
150 static bool needsFPStubFromParams(Function &F) {
151   if (F.arg_size() >=1) {
152     Type *ArgType = F.getFunctionType()->getParamType(0);
153     switch (ArgType->getTypeID()) {
154       case Type::FloatTyID:
155       case Type::DoubleTyID:
156         return true;
157       default:
158         break;
159     }
160   }
161   return false;
162 }
163
164 static bool needsFPReturnHelper(Function &F) {
165   Type* RetType = F.getReturnType();
166   return whichFPReturnVariant(RetType) != NoFPRet;
167 }
168
169 static bool needsFPHelperFromSig(Function &F) {
170   return needsFPStubFromParams(F) || needsFPReturnHelper(F);
171 }
172
173 //
174 // We swap between FP and Integer registers to allow Mips16 and Mips32 to
175 // interoperate
176 //
177
178 void swapFPIntParams(FPParamVariant PV, Module *M, InlineAsmHelper &IAH,
179                bool LE, bool ToFP) {
180   //LLVMContext &Context = M->getContext();
181   std::string MI = ToFP? "mtc1 ": "mfc1 ";
182   switch (PV) {
183   case FSig:
184     IAH.Out(MI + "$$4,$$f12");
185     break;
186   case FFSig:
187     IAH.Out(MI +"$$4,$$f12");
188     IAH.Out(MI + "$$5,$$f14");
189     break;
190   case FDSig:
191     IAH.Out(MI + "$$4,$$f12");
192     if (LE) {
193       IAH.Out(MI + "$$6,$$f14");
194       IAH.Out(MI + "$$7,$$f15");
195     } else {
196       IAH.Out(MI + "$$7,$$f14");
197       IAH.Out(MI + "$$6,$$f15");
198     }
199     break;
200   case DSig:
201     if (LE) {
202       IAH.Out(MI + "$$4,$$f12");
203       IAH.Out(MI + "$$5,$$f13");
204     } else {
205       IAH.Out(MI + "$$5,$$f12");
206       IAH.Out(MI + "$$4,$$f13");
207     }
208     break;
209   case DDSig:
210     if (LE) {
211       IAH.Out(MI + "$$4,$$f12");
212       IAH.Out(MI + "$$5,$$f13");
213       IAH.Out(MI + "$$6,$$f14");
214       IAH.Out(MI + "$$7,$$f15");
215     } else {
216       IAH.Out(MI + "$$5,$$f12");
217       IAH.Out(MI + "$$4,$$f13");
218       IAH.Out(MI + "$$7,$$f14");
219       IAH.Out(MI + "$$6,$$f15");
220     }
221     break;
222   case DFSig:
223     if (LE) {
224       IAH.Out(MI + "$$4,$$f12");
225       IAH.Out(MI + "$$5,$$f13");
226     } else {
227       IAH.Out(MI + "$$5,$$f12");
228       IAH.Out(MI + "$$4,$$f13");
229     }
230     IAH.Out(MI + "$$6,$$f14");
231     break;
232   case NoSig:
233     return;
234   }
235 }
236 //
237 // Make sure that we know we already need a stub for this function.
238 // Having called needsFPHelperFromSig
239 //
240 void assureFPCallStub(Function &F, Module *M,  const MipsSubtarget &Subtarget){
241   // for now we only need them for static relocation
242   if (!Subtarget.getRelocationModel() == Reloc::PIC_)
243     return;
244   LLVMContext &Context = M->getContext();
245   bool LE = Subtarget.isLittle();
246   std::string Name = F.getName();
247   std::string SectionName = ".mips16.call.fp." + Name;
248   std::string StubName = "__call_stub_" + Name;
249   //
250   // see if we already have the stub
251   //
252   Function *FStub = M->getFunction(StubName);
253   if (FStub && !FStub->isDeclaration()) return;
254   FStub = Function::Create(F.getFunctionType(),
255                            Function::InternalLinkage, StubName, M);
256   FStub->addFnAttr("mips16_fp_stub");
257   FStub->addFnAttr(llvm::Attribute::Naked);
258   FStub->addFnAttr(llvm::Attribute::NoUnwind);
259   FStub->addFnAttr("nomips16");
260   FStub->setSection(SectionName);
261   BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
262   InlineAsmHelper IAH(Context, BB);
263   FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
264   FPParamVariant PV = whichFPParamVariantNeeded(F);
265   swapFPIntParams(PV, M, IAH, LE, true);
266   if (RV != NoFPRet) {
267     IAH.Out("move $$18, $$31");
268     IAH.Out("jal " + Name);
269   } else {
270     IAH.Out("lui  $$25,%hi(" + Name + ")");
271     IAH.Out("addiu  $$25,$$25,%lo(" + Name + ")" );
272   }
273   switch (RV) {
274   case FRet:
275     IAH.Out("mfc1 $$2,$$f0");
276     break;
277   case DRet:
278     if (LE) {
279       IAH.Out("mfc1 $$2,$$f0");
280       IAH.Out("mfc1 $$3,$$f1");
281     } else {
282       IAH.Out("mfc1 $$3,$$f0");
283       IAH.Out("mfc1 $$2,$$f1");
284     }
285     break;
286   case CFRet:
287     if (LE) {
288     IAH.Out("mfc1 $$2,$$f0");
289     IAH.Out("mfc1 $$3,$$f2");
290     } else {
291       IAH.Out("mfc1 $$3,$$f0");
292       IAH.Out("mfc1 $$3,$$f2");
293     }
294     break;
295   case CDRet:
296     if (LE) {
297       IAH.Out("mfc1 $$4,$$f2");
298       IAH.Out("mfc1 $$5,$$f3");
299       IAH.Out("mfc1 $$2,$$f0");
300       IAH.Out("mfc1 $$3,$$f1");
301
302     } else {
303       IAH.Out("mfc1 $$5,$$f2");
304       IAH.Out("mfc1 $$4,$$f3");
305       IAH.Out("mfc1 $$3,$$f0");
306       IAH.Out("mfc1 $$2,$$f1");
307     }
308     break;
309   case NoFPRet:
310     break;
311   }
312   if (RV != NoFPRet)
313     IAH.Out("jr $$18");
314   else
315     IAH.Out("jr $$25");
316   new UnreachableInst(Context, BB);
317 }
318
319 //
320 // Returns of float, double and complex need to be handled with a helper
321 // function. The "AndCal" part is coming in a later patch.
322 //
323 static bool fixupFPReturnAndCall
324   (Function &F, Module *M,  const MipsSubtarget &Subtarget) {
325   bool Modified = false;
326   LLVMContext &C = M->getContext();
327   Type *MyVoid = Type::getVoidTy(C);
328   for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
329     for (BasicBlock::iterator I = BB->begin(), E = BB->end();
330          I != E; ++I) {
331       Instruction &Inst = *I;
332       if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) {
333         Value *RVal = RI->getReturnValue();
334         if (!RVal) continue;
335         //
336         // If there is a return value and it needs a helper function,
337         // figure out which one and add a call before the actual
338         // return to this helper. The purpose of the helper is to move
339         // floating point values from their soft float return mapping to
340         // where they would have been mapped to in floating point registers.
341         //
342         Type *T = RVal->getType();
343         FPReturnVariant RV = whichFPReturnVariant(T);
344         if (RV == NoFPRet) continue;
345         static const char* Helper[NoFPRet] =
346           {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
347            "__mips16_ret_dc"};
348         const char *Name = Helper[RV];
349         AttributeSet A;
350         Value *Params[] = {RVal};
351         Modified = true;
352         //
353         // These helper functions have a different calling ABI so
354         // this __Mips16RetHelper indicates that so that later
355         // during call setup, the proper call lowering to the helper
356         // functions will take place.
357         //
358         A = A.addAttribute(C, AttributeSet::FunctionIndex,
359                            "__Mips16RetHelper");
360         A = A.addAttribute(C, AttributeSet::FunctionIndex,
361                            Attribute::ReadNone);
362         Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL));
363         CallInst::Create(F, Params, "", &Inst );
364       } else if (const CallInst *CI = dyn_cast<CallInst>(I)) {
365           // pic mode calls are handled by already defined
366           // helper functions
367           if (Subtarget.getRelocationModel() != Reloc::PIC_ ) {
368             Function *F_ =  CI->getCalledFunction();
369             if (F_ && needsFPHelperFromSig(*F_)) {
370               assureFPCallStub(*F_, M, Subtarget);
371               Modified=true;
372             }
373           }
374       }
375     }
376   return Modified;
377 }
378
379 namespace llvm {
380
381 //
382 // This pass only makes sense when the underlying chip has floating point but
383 // we are compiling as mips16.
384 // For all mips16 functions (that are not stubs we have already generated), or
385 // declared via attributes as nomips16, we must:
386 //    1) fixup all returns of float, double, single and double complex
387 //       by calling a helper function before the actual return.
388 //    2) generate helper functions (stubs) that can be called by mips32 functions
389 //       that will move parameters passed normally passed in floating point
390 //       registers the soft float equivalents. (Coming in a later patch).
391 //    3) in the case of static relocation, generate helper functions so that
392 //       mips16 functions can call extern functions of unknown type (mips16 or
393 //       mips32). (Coming in a later patch).
394 //    4) TBD. For pic, calls to extern functions of unknown type are handled by
395 //       predefined helper functions in libc but this work is currently done
396 //       during call lowering but it should be moved here in the future.
397 //
398 bool Mips16HardFloat::runOnModule(Module &M) {
399   DEBUG(errs() << "Run on Module Mips16HardFloat\n");
400   bool Modified = false;
401   for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
402     if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
403         F->hasFnAttribute("nomips16")) continue;
404     Modified |= fixupFPReturnAndCall(*F, &M, Subtarget);
405   }
406   return Modified;
407 }
408
409 char Mips16HardFloat::ID = 0;
410
411 }
412
413 ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) {
414   return new Mips16HardFloat(TM);
415 }
416