Removed an unnamed namespace and forgot to make two of the functions inside
[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 static void swapFPIntParams
179   (FPParamVariant PV, Module *M, InlineAsmHelper &IAH,
180    bool LE, bool ToFP) {
181   //LLVMContext &Context = M->getContext();
182   std::string MI = ToFP? "mtc1 ": "mfc1 ";
183   switch (PV) {
184   case FSig:
185     IAH.Out(MI + "$$4,$$f12");
186     break;
187   case FFSig:
188     IAH.Out(MI +"$$4,$$f12");
189     IAH.Out(MI + "$$5,$$f14");
190     break;
191   case FDSig:
192     IAH.Out(MI + "$$4,$$f12");
193     if (LE) {
194       IAH.Out(MI + "$$6,$$f14");
195       IAH.Out(MI + "$$7,$$f15");
196     } else {
197       IAH.Out(MI + "$$7,$$f14");
198       IAH.Out(MI + "$$6,$$f15");
199     }
200     break;
201   case DSig:
202     if (LE) {
203       IAH.Out(MI + "$$4,$$f12");
204       IAH.Out(MI + "$$5,$$f13");
205     } else {
206       IAH.Out(MI + "$$5,$$f12");
207       IAH.Out(MI + "$$4,$$f13");
208     }
209     break;
210   case DDSig:
211     if (LE) {
212       IAH.Out(MI + "$$4,$$f12");
213       IAH.Out(MI + "$$5,$$f13");
214       IAH.Out(MI + "$$6,$$f14");
215       IAH.Out(MI + "$$7,$$f15");
216     } else {
217       IAH.Out(MI + "$$5,$$f12");
218       IAH.Out(MI + "$$4,$$f13");
219       IAH.Out(MI + "$$7,$$f14");
220       IAH.Out(MI + "$$6,$$f15");
221     }
222     break;
223   case DFSig:
224     if (LE) {
225       IAH.Out(MI + "$$4,$$f12");
226       IAH.Out(MI + "$$5,$$f13");
227     } else {
228       IAH.Out(MI + "$$5,$$f12");
229       IAH.Out(MI + "$$4,$$f13");
230     }
231     IAH.Out(MI + "$$6,$$f14");
232     break;
233   case NoSig:
234     return;
235   }
236 }
237 //
238 // Make sure that we know we already need a stub for this function.
239 // Having called needsFPHelperFromSig
240 //
241 static void assureFPCallStub(Function &F, Module *M,  
242                              const MipsSubtarget &Subtarget){
243   // for now we only need them for static relocation
244   if (!Subtarget.getRelocationModel() == Reloc::PIC_)
245     return;
246   LLVMContext &Context = M->getContext();
247   bool LE = Subtarget.isLittle();
248   std::string Name = F.getName();
249   std::string SectionName = ".mips16.call.fp." + Name;
250   std::string StubName = "__call_stub_" + Name;
251   //
252   // see if we already have the stub
253   //
254   Function *FStub = M->getFunction(StubName);
255   if (FStub && !FStub->isDeclaration()) return;
256   FStub = Function::Create(F.getFunctionType(),
257                            Function::InternalLinkage, StubName, M);
258   FStub->addFnAttr("mips16_fp_stub");
259   FStub->addFnAttr(llvm::Attribute::Naked);
260   FStub->addFnAttr(llvm::Attribute::NoUnwind);
261   FStub->addFnAttr("nomips16");
262   FStub->setSection(SectionName);
263   BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
264   InlineAsmHelper IAH(Context, BB);
265   FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
266   FPParamVariant PV = whichFPParamVariantNeeded(F);
267   swapFPIntParams(PV, M, IAH, LE, true);
268   if (RV != NoFPRet) {
269     IAH.Out("move $$18, $$31");
270     IAH.Out("jal " + Name);
271   } else {
272     IAH.Out("lui  $$25,%hi(" + Name + ")");
273     IAH.Out("addiu  $$25,$$25,%lo(" + Name + ")" );
274   }
275   switch (RV) {
276   case FRet:
277     IAH.Out("mfc1 $$2,$$f0");
278     break;
279   case DRet:
280     if (LE) {
281       IAH.Out("mfc1 $$2,$$f0");
282       IAH.Out("mfc1 $$3,$$f1");
283     } else {
284       IAH.Out("mfc1 $$3,$$f0");
285       IAH.Out("mfc1 $$2,$$f1");
286     }
287     break;
288   case CFRet:
289     if (LE) {
290     IAH.Out("mfc1 $$2,$$f0");
291     IAH.Out("mfc1 $$3,$$f2");
292     } else {
293       IAH.Out("mfc1 $$3,$$f0");
294       IAH.Out("mfc1 $$3,$$f2");
295     }
296     break;
297   case CDRet:
298     if (LE) {
299       IAH.Out("mfc1 $$4,$$f2");
300       IAH.Out("mfc1 $$5,$$f3");
301       IAH.Out("mfc1 $$2,$$f0");
302       IAH.Out("mfc1 $$3,$$f1");
303
304     } else {
305       IAH.Out("mfc1 $$5,$$f2");
306       IAH.Out("mfc1 $$4,$$f3");
307       IAH.Out("mfc1 $$3,$$f0");
308       IAH.Out("mfc1 $$2,$$f1");
309     }
310     break;
311   case NoFPRet:
312     break;
313   }
314   if (RV != NoFPRet)
315     IAH.Out("jr $$18");
316   else
317     IAH.Out("jr $$25");
318   new UnreachableInst(Context, BB);
319 }
320
321 //
322 // Returns of float, double and complex need to be handled with a helper
323 // function. The "AndCal" part is coming in a later patch.
324 //
325 static bool fixupFPReturnAndCall
326   (Function &F, Module *M,  const MipsSubtarget &Subtarget) {
327   bool Modified = false;
328   LLVMContext &C = M->getContext();
329   Type *MyVoid = Type::getVoidTy(C);
330   for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
331     for (BasicBlock::iterator I = BB->begin(), E = BB->end();
332          I != E; ++I) {
333       Instruction &Inst = *I;
334       if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) {
335         Value *RVal = RI->getReturnValue();
336         if (!RVal) continue;
337         //
338         // If there is a return value and it needs a helper function,
339         // figure out which one and add a call before the actual
340         // return to this helper. The purpose of the helper is to move
341         // floating point values from their soft float return mapping to
342         // where they would have been mapped to in floating point registers.
343         //
344         Type *T = RVal->getType();
345         FPReturnVariant RV = whichFPReturnVariant(T);
346         if (RV == NoFPRet) continue;
347         static const char* Helper[NoFPRet] =
348           {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
349            "__mips16_ret_dc"};
350         const char *Name = Helper[RV];
351         AttributeSet A;
352         Value *Params[] = {RVal};
353         Modified = true;
354         //
355         // These helper functions have a different calling ABI so
356         // this __Mips16RetHelper indicates that so that later
357         // during call setup, the proper call lowering to the helper
358         // functions will take place.
359         //
360         A = A.addAttribute(C, AttributeSet::FunctionIndex,
361                            "__Mips16RetHelper");
362         A = A.addAttribute(C, AttributeSet::FunctionIndex,
363                            Attribute::ReadNone);
364         Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL));
365         CallInst::Create(F, Params, "", &Inst );
366       } else if (const CallInst *CI = dyn_cast<CallInst>(I)) {
367           // pic mode calls are handled by already defined
368           // helper functions
369           if (Subtarget.getRelocationModel() != Reloc::PIC_ ) {
370             Function *F_ =  CI->getCalledFunction();
371             if (F_ && needsFPHelperFromSig(*F_)) {
372               assureFPCallStub(*F_, M, Subtarget);
373               Modified=true;
374             }
375           }
376       }
377     }
378   return Modified;
379 }
380
381 namespace llvm {
382
383 //
384 // This pass only makes sense when the underlying chip has floating point but
385 // we are compiling as mips16.
386 // For all mips16 functions (that are not stubs we have already generated), or
387 // declared via attributes as nomips16, we must:
388 //    1) fixup all returns of float, double, single and double complex
389 //       by calling a helper function before the actual return.
390 //    2) generate helper functions (stubs) that can be called by mips32 functions
391 //       that will move parameters passed normally passed in floating point
392 //       registers the soft float equivalents. (Coming in a later patch).
393 //    3) in the case of static relocation, generate helper functions so that
394 //       mips16 functions can call extern functions of unknown type (mips16 or
395 //       mips32). (Coming in a later patch).
396 //    4) TBD. For pic, calls to extern functions of unknown type are handled by
397 //       predefined helper functions in libc but this work is currently done
398 //       during call lowering but it should be moved here in the future.
399 //
400 bool Mips16HardFloat::runOnModule(Module &M) {
401   DEBUG(errs() << "Run on Module Mips16HardFloat\n");
402   bool Modified = false;
403   for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
404     if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
405         F->hasFnAttribute("nomips16")) continue;
406     Modified |= fixupFPReturnAndCall(*F, &M, Subtarget);
407   }
408   return Modified;
409 }
410
411 char Mips16HardFloat::ID = 0;
412
413 }
414
415 ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) {
416   return new Mips16HardFloat(TM);
417 }
418