Home | History | Annotate | Download | only in Mips
      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_fp_" + 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::NoInline);
    261   FStub->addFnAttr(llvm::Attribute::NoUnwind);
    262   FStub->addFnAttr("nomips16");
    263   FStub->setSection(SectionName);
    264   BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
    265   InlineAsmHelper IAH(Context, BB);
    266   IAH.Out(".set reorder");
    267   FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
    268   FPParamVariant PV = whichFPParamVariantNeeded(F);
    269   swapFPIntParams(PV, M, IAH, LE, true);
    270   if (RV != NoFPRet) {
    271     IAH.Out("move $$18, $$31");
    272     IAH.Out("jal " + Name);
    273   } else {
    274     IAH.Out("lui  $$25,%hi(" + Name + ")");
    275     IAH.Out("addiu  $$25,$$25,%lo(" + Name + ")" );
    276   }
    277   switch (RV) {
    278   case FRet:
    279     IAH.Out("mfc1 $$2,$$f0");
    280     break;
    281   case DRet:
    282     if (LE) {
    283       IAH.Out("mfc1 $$2,$$f0");
    284       IAH.Out("mfc1 $$3,$$f1");
    285     } else {
    286       IAH.Out("mfc1 $$3,$$f0");
    287       IAH.Out("mfc1 $$2,$$f1");
    288     }
    289     break;
    290   case CFRet:
    291     if (LE) {
    292     IAH.Out("mfc1 $$2,$$f0");
    293     IAH.Out("mfc1 $$3,$$f2");
    294     } else {
    295       IAH.Out("mfc1 $$3,$$f0");
    296       IAH.Out("mfc1 $$3,$$f2");
    297     }
    298     break;
    299   case CDRet:
    300     if (LE) {
    301       IAH.Out("mfc1 $$4,$$f2");
    302       IAH.Out("mfc1 $$5,$$f3");
    303       IAH.Out("mfc1 $$2,$$f0");
    304       IAH.Out("mfc1 $$3,$$f1");
    305 
    306     } else {
    307       IAH.Out("mfc1 $$5,$$f2");
    308       IAH.Out("mfc1 $$4,$$f3");
    309       IAH.Out("mfc1 $$3,$$f0");
    310       IAH.Out("mfc1 $$2,$$f1");
    311     }
    312     break;
    313   case NoFPRet:
    314     break;
    315   }
    316   if (RV != NoFPRet)
    317     IAH.Out("jr $$18");
    318   else
    319     IAH.Out("jr $$25");
    320   new UnreachableInst(Context, BB);
    321 }
    322 
    323 //
    324 // Returns of float, double and complex need to be handled with a helper
    325 // function.
    326 //
    327 static bool fixupFPReturnAndCall
    328   (Function &F, Module *M,  const MipsSubtarget &Subtarget) {
    329   bool Modified = false;
    330   LLVMContext &C = M->getContext();
    331   Type *MyVoid = Type::getVoidTy(C);
    332   for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
    333     for (BasicBlock::iterator I = BB->begin(), E = BB->end();
    334          I != E; ++I) {
    335       Instruction &Inst = *I;
    336       if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) {
    337         Value *RVal = RI->getReturnValue();
    338         if (!RVal) continue;
    339         //
    340         // If there is a return value and it needs a helper function,
    341         // figure out which one and add a call before the actual
    342         // return to this helper. The purpose of the helper is to move
    343         // floating point values from their soft float return mapping to
    344         // where they would have been mapped to in floating point registers.
    345         //
    346         Type *T = RVal->getType();
    347         FPReturnVariant RV = whichFPReturnVariant(T);
    348         if (RV == NoFPRet) continue;
    349         static const char* Helper[NoFPRet] =
    350           {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
    351            "__mips16_ret_dc"};
    352         const char *Name = Helper[RV];
    353         AttributeSet A;
    354         Value *Params[] = {RVal};
    355         Modified = true;
    356         //
    357         // These helper functions have a different calling ABI so
    358         // this __Mips16RetHelper indicates that so that later
    359         // during call setup, the proper call lowering to the helper
    360         // functions will take place.
    361         //
    362         A = A.addAttribute(C, AttributeSet::FunctionIndex,
    363                            "__Mips16RetHelper");
    364         A = A.addAttribute(C, AttributeSet::FunctionIndex,
    365                            Attribute::ReadNone);
    366         A = A.addAttribute(C, AttributeSet::FunctionIndex,
    367                            Attribute::NoInline);
    368         Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL));
    369         CallInst::Create(F, Params, "", &Inst );
    370       } else if (const CallInst *CI = dyn_cast<CallInst>(I)) {
    371           // pic mode calls are handled by already defined
    372           // helper functions
    373           if (Subtarget.getRelocationModel() != Reloc::PIC_ ) {
    374             Function *F_ =  CI->getCalledFunction();
    375             if (F_ && needsFPHelperFromSig(*F_)) {
    376               assureFPCallStub(*F_, M, Subtarget);
    377               Modified=true;
    378             }
    379           }
    380       }
    381     }
    382   return Modified;
    383 }
    384 
    385 static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
    386                   const MipsSubtarget &Subtarget ) {
    387   bool PicMode = Subtarget.getRelocationModel() == Reloc::PIC_;
    388   bool LE = Subtarget.isLittle();
    389   LLVMContext &Context = M->getContext();
    390   std::string Name = F->getName();
    391   std::string SectionName = ".mips16.fn." + Name;
    392   std::string StubName = "__fn_stub_" + Name;
    393   std::string LocalName = "__fn_local_" + Name;
    394   Function *FStub = Function::Create
    395     (F->getFunctionType(),
    396      Function::InternalLinkage, StubName, M);
    397   FStub->addFnAttr("mips16_fp_stub");
    398   FStub->addFnAttr(llvm::Attribute::Naked);
    399   FStub->addFnAttr(llvm::Attribute::NoUnwind);
    400   FStub->addFnAttr(llvm::Attribute::NoInline);
    401   FStub->addFnAttr("nomips16");
    402   FStub->setSection(SectionName);
    403   BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
    404   InlineAsmHelper IAH(Context, BB);
    405   IAH.Out(" .set  macro");
    406   if (PicMode) {
    407     IAH.Out(".set noreorder");
    408     IAH.Out(".cpload  $$2");
    409     IAH.Out(".set reorder");
    410     IAH.Out(".reloc 0,R_MIPS_NONE," + Name);
    411     IAH.Out("la $$25," + LocalName);
    412   }
    413   else
    414     IAH.Out("la $$25, " + Name);
    415   swapFPIntParams(PV, M, IAH, LE, false);
    416   IAH.Out("jr $$25");
    417   IAH.Out(LocalName + " = " + Name);
    418   new UnreachableInst(FStub->getContext(), BB);
    419 }
    420 
    421 namespace llvm {
    422 
    423 //
    424 // This pass only makes sense when the underlying chip has floating point but
    425 // we are compiling as mips16.
    426 // For all mips16 functions (that are not stubs we have already generated), or
    427 // declared via attributes as nomips16, we must:
    428 //    1) fixup all returns of float, double, single and double complex
    429 //       by calling a helper function before the actual return.
    430 //    2) generate helper functions (stubs) that can be called by mips32 functions
    431 //       that will move parameters passed normally passed in floating point
    432 //       registers the soft float equivalents.
    433 //    3) in the case of static relocation, generate helper functions so that
    434 //       mips16 functions can call extern functions of unknown type (mips16 or
    435 //       mips32).
    436 //    4) TBD. For pic, calls to extern functions of unknown type are handled by
    437 //       predefined helper functions in libc but this work is currently done
    438 //       during call lowering but it should be moved here in the future.
    439 //
    440 bool Mips16HardFloat::runOnModule(Module &M) {
    441   DEBUG(errs() << "Run on Module Mips16HardFloat\n");
    442   bool Modified = false;
    443   for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
    444     if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
    445         F->hasFnAttribute("nomips16")) continue;
    446     Modified |= fixupFPReturnAndCall(*F, &M, Subtarget);
    447     FPParamVariant V = whichFPParamVariantNeeded(*F);
    448     if (V != NoSig) {
    449       Modified = true;
    450       createFPFnStub(F, &M, V, Subtarget);
    451     }
    452   }
    453   return Modified;
    454 }
    455 
    456 char Mips16HardFloat::ID = 0;
    457 
    458 }
    459 
    460 ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) {
    461   return new Mips16HardFloat(TM);
    462 }
    463 
    464