LLVM API Documentation

Mips16HardFloat.cpp
Go to the documentation of this file.
00001 //===---- Mips16HardFloat.cpp for Mips16 Hard Float               --------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 // This file defines a pass needed for Mips16 Hard Float
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "Mips16HardFloat.h"
00015 #include "llvm/IR/Module.h"
00016 #include "llvm/IR/Value.h"
00017 #include "llvm/Support/Debug.h"
00018 #include "llvm/Support/raw_ostream.h"
00019 #include <algorithm>
00020 #include <string>
00021 
00022 #define DEBUG_TYPE "mips16-hard-float"
00023 
00024 static void inlineAsmOut
00025   (LLVMContext &C, StringRef AsmString, BasicBlock *BB ) {
00026   std::vector<llvm::Type *> AsmArgTypes;
00027   std::vector<llvm::Value*> AsmArgs;
00028   llvm::FunctionType *AsmFTy =
00029     llvm::FunctionType::get(Type::getVoidTy(C),
00030                             AsmArgTypes, false);
00031   llvm::InlineAsm *IA =
00032     llvm::InlineAsm::get(AsmFTy, AsmString, "", true,
00033                          /* IsAlignStack */ false,
00034                          llvm::InlineAsm::AD_ATT);
00035   CallInst::Create(IA, AsmArgs, "", BB);
00036 }
00037 
00038 namespace {
00039 
00040 class InlineAsmHelper {
00041   LLVMContext &C;
00042   BasicBlock *BB;
00043 public:
00044   InlineAsmHelper(LLVMContext &C_, BasicBlock *BB_) :
00045     C(C_), BB(BB_) {
00046   }
00047 
00048   void Out(StringRef AsmString) {
00049     inlineAsmOut(C, AsmString, BB);
00050   }
00051 
00052 };
00053 }
00054 //
00055 // Return types that matter for hard float are:
00056 // float, double, complex float, and complex double
00057 //
00058 enum FPReturnVariant {
00059   FRet, DRet, CFRet, CDRet, NoFPRet
00060 };
00061 
00062 //
00063 // Determine which FP return type this function has
00064 //
00065 static FPReturnVariant whichFPReturnVariant(Type *T) {
00066   switch (T->getTypeID()) {
00067   case Type::FloatTyID:
00068     return FRet;
00069   case Type::DoubleTyID:
00070     return DRet;
00071   case Type::StructTyID:
00072     if (T->getStructNumElements() != 2)
00073       break;
00074     if ((T->getContainedType(0)->isFloatTy()) &&
00075         (T->getContainedType(1)->isFloatTy()))
00076       return CFRet;
00077     if ((T->getContainedType(0)->isDoubleTy()) &&
00078         (T->getContainedType(1)->isDoubleTy()))
00079       return CDRet;
00080     break;
00081   default:
00082     break;
00083   }
00084   return NoFPRet;
00085 }
00086 
00087 //
00088 // Parameter type that matter are float, (float, float), (float, double),
00089 // double, (double, double), (double, float)
00090 //
00091 enum FPParamVariant {
00092   FSig, FFSig, FDSig,
00093   DSig, DDSig, DFSig, NoSig
00094 };
00095 
00096 // which floating point parameter signature variant we are dealing with
00097 //
00098 typedef Type::TypeID TypeID;
00099 const Type::TypeID FloatTyID = Type::FloatTyID;
00100 const Type::TypeID DoubleTyID = Type::DoubleTyID;
00101 
00102 static FPParamVariant whichFPParamVariantNeeded(Function &F) {
00103   switch (F.arg_size()) {
00104   case 0:
00105     return NoSig;
00106   case 1:{
00107     TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
00108     switch (ArgTypeID) {
00109     case FloatTyID:
00110       return FSig;
00111     case DoubleTyID:
00112       return DSig;
00113     default:
00114       return NoSig;
00115     }
00116   }
00117   default: {
00118     TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
00119     TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
00120     switch(ArgTypeID0) {
00121     case FloatTyID: {
00122       switch (ArgTypeID1) {
00123       case FloatTyID:
00124         return FFSig;
00125       case DoubleTyID:
00126         return FDSig;
00127       default:
00128         return FSig;
00129       }
00130     }
00131     case DoubleTyID: {
00132       switch (ArgTypeID1) {
00133       case FloatTyID:
00134         return DFSig;
00135       case DoubleTyID:
00136         return DDSig;
00137       default:
00138         return DSig;
00139       }
00140     }
00141     default:
00142       return NoSig;
00143     }
00144   }
00145   }
00146   llvm_unreachable("can't get here");
00147 }
00148 
00149 // Figure out if we need float point based on the function parameters.
00150 // We need to move variables in and/or out of floating point
00151 // registers because of the ABI
00152 //
00153 static bool needsFPStubFromParams(Function &F) {
00154   if (F.arg_size() >=1) {
00155     Type *ArgType = F.getFunctionType()->getParamType(0);
00156     switch (ArgType->getTypeID()) {
00157       case Type::FloatTyID:
00158       case Type::DoubleTyID:
00159         return true;
00160       default:
00161         break;
00162     }
00163   }
00164   return false;
00165 }
00166 
00167 static bool needsFPReturnHelper(Function &F) {
00168   Type* RetType = F.getReturnType();
00169   return whichFPReturnVariant(RetType) != NoFPRet;
00170 }
00171 
00172 static bool needsFPReturnHelper(const FunctionType &FT) {
00173   Type* RetType = FT.getReturnType();
00174   return whichFPReturnVariant(RetType) != NoFPRet;
00175 }
00176 
00177 static bool needsFPHelperFromSig(Function &F) {
00178   return needsFPStubFromParams(F) || needsFPReturnHelper(F);
00179 }
00180 
00181 //
00182 // We swap between FP and Integer registers to allow Mips16 and Mips32 to
00183 // interoperate
00184 //
00185 
00186 static void swapFPIntParams
00187   (FPParamVariant PV, Module *M, InlineAsmHelper &IAH,
00188    bool LE, bool ToFP) {
00189   //LLVMContext &Context = M->getContext();
00190   std::string MI = ToFP? "mtc1 ": "mfc1 ";
00191   switch (PV) {
00192   case FSig:
00193     IAH.Out(MI + "$$4,$$f12");
00194     break;
00195   case FFSig:
00196     IAH.Out(MI +"$$4,$$f12");
00197     IAH.Out(MI + "$$5,$$f14");
00198     break;
00199   case FDSig:
00200     IAH.Out(MI + "$$4,$$f12");
00201     if (LE) {
00202       IAH.Out(MI + "$$6,$$f14");
00203       IAH.Out(MI + "$$7,$$f15");
00204     } else {
00205       IAH.Out(MI + "$$7,$$f14");
00206       IAH.Out(MI + "$$6,$$f15");
00207     }
00208     break;
00209   case DSig:
00210     if (LE) {
00211       IAH.Out(MI + "$$4,$$f12");
00212       IAH.Out(MI + "$$5,$$f13");
00213     } else {
00214       IAH.Out(MI + "$$5,$$f12");
00215       IAH.Out(MI + "$$4,$$f13");
00216     }
00217     break;
00218   case DDSig:
00219     if (LE) {
00220       IAH.Out(MI + "$$4,$$f12");
00221       IAH.Out(MI + "$$5,$$f13");
00222       IAH.Out(MI + "$$6,$$f14");
00223       IAH.Out(MI + "$$7,$$f15");
00224     } else {
00225       IAH.Out(MI + "$$5,$$f12");
00226       IAH.Out(MI + "$$4,$$f13");
00227       IAH.Out(MI + "$$7,$$f14");
00228       IAH.Out(MI + "$$6,$$f15");
00229     }
00230     break;
00231   case DFSig:
00232     if (LE) {
00233       IAH.Out(MI + "$$4,$$f12");
00234       IAH.Out(MI + "$$5,$$f13");
00235     } else {
00236       IAH.Out(MI + "$$5,$$f12");
00237       IAH.Out(MI + "$$4,$$f13");
00238     }
00239     IAH.Out(MI + "$$6,$$f14");
00240     break;
00241   case NoSig:
00242     return;
00243   }
00244 }
00245 //
00246 // Make sure that we know we already need a stub for this function.
00247 // Having called needsFPHelperFromSig
00248 //
00249 static void assureFPCallStub(Function &F, Module *M,
00250                              const MipsSubtarget &Subtarget) {
00251   // for now we only need them for static relocation
00252   if (Subtarget.getRelocationModel() == Reloc::PIC_)
00253     return;
00254   LLVMContext &Context = M->getContext();
00255   bool LE = Subtarget.isLittle();
00256   std::string Name = F.getName();
00257   std::string SectionName = ".mips16.call.fp." + Name;
00258   std::string StubName = "__call_stub_fp_" + Name;
00259   //
00260   // see if we already have the stub
00261   //
00262   Function *FStub = M->getFunction(StubName);
00263   if (FStub && !FStub->isDeclaration()) return;
00264   FStub = Function::Create(F.getFunctionType(),
00265                            Function::InternalLinkage, StubName, M);
00266   FStub->addFnAttr("mips16_fp_stub");
00267   FStub->addFnAttr(llvm::Attribute::Naked);
00268   FStub->addFnAttr(llvm::Attribute::NoInline);
00269   FStub->addFnAttr(llvm::Attribute::NoUnwind);
00270   FStub->addFnAttr("nomips16");
00271   FStub->setSection(SectionName);
00272   BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
00273   InlineAsmHelper IAH(Context, BB);
00274   IAH.Out(".set reorder");
00275   FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
00276   FPParamVariant PV = whichFPParamVariantNeeded(F);
00277   swapFPIntParams(PV, M, IAH, LE, true);
00278   if (RV != NoFPRet) {
00279     IAH.Out("move $$18, $$31");
00280     IAH.Out("jal " + Name);
00281   } else {
00282     IAH.Out("lui  $$25,%hi(" + Name + ")");
00283     IAH.Out("addiu  $$25,$$25,%lo(" + Name + ")" );
00284   }
00285   switch (RV) {
00286   case FRet:
00287     IAH.Out("mfc1 $$2,$$f0");
00288     break;
00289   case DRet:
00290     if (LE) {
00291       IAH.Out("mfc1 $$2,$$f0");
00292       IAH.Out("mfc1 $$3,$$f1");
00293     } else {
00294       IAH.Out("mfc1 $$3,$$f0");
00295       IAH.Out("mfc1 $$2,$$f1");
00296     }
00297     break;
00298   case CFRet:
00299     if (LE) {
00300     IAH.Out("mfc1 $$2,$$f0");
00301     IAH.Out("mfc1 $$3,$$f2");
00302     } else {
00303       IAH.Out("mfc1 $$3,$$f0");
00304       IAH.Out("mfc1 $$3,$$f2");
00305     }
00306     break;
00307   case CDRet:
00308     if (LE) {
00309       IAH.Out("mfc1 $$4,$$f2");
00310       IAH.Out("mfc1 $$5,$$f3");
00311       IAH.Out("mfc1 $$2,$$f0");
00312       IAH.Out("mfc1 $$3,$$f1");
00313 
00314     } else {
00315       IAH.Out("mfc1 $$5,$$f2");
00316       IAH.Out("mfc1 $$4,$$f3");
00317       IAH.Out("mfc1 $$3,$$f0");
00318       IAH.Out("mfc1 $$2,$$f1");
00319     }
00320     break;
00321   case NoFPRet:
00322     break;
00323   }
00324   if (RV != NoFPRet)
00325     IAH.Out("jr $$18");
00326   else
00327     IAH.Out("jr $$25");
00328   new UnreachableInst(Context, BB);
00329 }
00330 
00331 //
00332 // Functions that are llvm intrinsics and don't need helpers.
00333 //
00334 static const char *IntrinsicInline[] =
00335   {"fabs",
00336    "fabsf",
00337    "llvm.ceil.f32", "llvm.ceil.f64",
00338    "llvm.copysign.f32", "llvm.copysign.f64",
00339    "llvm.cos.f32", "llvm.cos.f64",
00340    "llvm.exp.f32", "llvm.exp.f64",
00341    "llvm.exp2.f32", "llvm.exp2.f64",
00342    "llvm.fabs.f32", "llvm.fabs.f64",
00343    "llvm.floor.f32", "llvm.floor.f64",
00344    "llvm.fma.f32", "llvm.fma.f64",
00345    "llvm.log.f32", "llvm.log.f64",
00346    "llvm.log10.f32", "llvm.log10.f64",
00347    "llvm.nearbyint.f32", "llvm.nearbyint.f64",
00348    "llvm.pow.f32", "llvm.pow.f64",
00349    "llvm.powi.f32", "llvm.powi.f64",
00350    "llvm.rint.f32", "llvm.rint.f64",
00351    "llvm.round.f32", "llvm.round.f64",
00352    "llvm.sin.f32", "llvm.sin.f64",
00353    "llvm.sqrt.f32", "llvm.sqrt.f64",
00354    "llvm.trunc.f32", "llvm.trunc.f64",
00355   };
00356 
00357 static bool isIntrinsicInline(Function *F) {
00358   return std::binary_search(std::begin(IntrinsicInline),
00359                             std::end(IntrinsicInline), F->getName());
00360 }
00361 //
00362 // Returns of float, double and complex need to be handled with a helper
00363 // function.
00364 //
00365 static bool fixupFPReturnAndCall
00366   (Function &F, Module *M,  const MipsSubtarget &Subtarget) {
00367   bool Modified = false;
00368   LLVMContext &C = M->getContext();
00369   Type *MyVoid = Type::getVoidTy(C);
00370   for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
00371     for (BasicBlock::iterator I = BB->begin(), E = BB->end();
00372          I != E; ++I) {
00373       Instruction &Inst = *I;
00374       if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) {
00375         Value *RVal = RI->getReturnValue();
00376         if (!RVal) continue;
00377         //
00378         // If there is a return value and it needs a helper function,
00379         // figure out which one and add a call before the actual
00380         // return to this helper. The purpose of the helper is to move
00381         // floating point values from their soft float return mapping to
00382         // where they would have been mapped to in floating point registers.
00383         //
00384         Type *T = RVal->getType();
00385         FPReturnVariant RV = whichFPReturnVariant(T);
00386         if (RV == NoFPRet) continue;
00387         static const char* Helper[NoFPRet] =
00388           {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
00389            "__mips16_ret_dc"};
00390         const char *Name = Helper[RV];
00391         AttributeSet A;
00392         Value *Params[] = {RVal};
00393         Modified = true;
00394         //
00395         // These helper functions have a different calling ABI so
00396         // this __Mips16RetHelper indicates that so that later
00397         // during call setup, the proper call lowering to the helper
00398         // functions will take place.
00399         //
00400         A = A.addAttribute(C, AttributeSet::FunctionIndex,
00401                            "__Mips16RetHelper");
00402         A = A.addAttribute(C, AttributeSet::FunctionIndex,
00403                            Attribute::ReadNone);
00404         A = A.addAttribute(C, AttributeSet::FunctionIndex,
00405                            Attribute::NoInline);
00406         Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL));
00407         CallInst::Create(F, Params, "", &Inst );
00408       } else if (const CallInst *CI = dyn_cast<CallInst>(I)) {
00409           const Value* V = CI->getCalledValue();
00410           const Type* T = nullptr;
00411           if (V) T = V->getType();
00412           const PointerType *PFT=nullptr;
00413           if (T) PFT = dyn_cast<PointerType>(T);
00414           const FunctionType *FT=nullptr;
00415           if (PFT) FT = dyn_cast<FunctionType>(PFT->getElementType());
00416           Function *F_ =  CI->getCalledFunction();
00417           if (FT && needsFPReturnHelper(*FT) &&
00418               !(F_ && isIntrinsicInline(F_))) {
00419             Modified=true;
00420             F.addFnAttr("saveS2");
00421           }
00422           if (F_ && !isIntrinsicInline(F_)) {
00423           // pic mode calls are handled by already defined
00424           // helper functions
00425             if (needsFPReturnHelper(*F_)) {
00426               Modified=true;
00427               F.addFnAttr("saveS2");
00428             }
00429             if (Subtarget.getRelocationModel() != Reloc::PIC_ ) {
00430               if (needsFPHelperFromSig(*F_)) {
00431                 assureFPCallStub(*F_, M, Subtarget);
00432                 Modified=true;
00433               }
00434             }
00435           }
00436       }
00437     }
00438   return Modified;
00439 }
00440 
00441 static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
00442                   const MipsSubtarget &Subtarget ) {
00443   bool PicMode = Subtarget.getRelocationModel() == Reloc::PIC_;
00444   bool LE = Subtarget.isLittle();
00445   LLVMContext &Context = M->getContext();
00446   std::string Name = F->getName();
00447   std::string SectionName = ".mips16.fn." + Name;
00448   std::string StubName = "__fn_stub_" + Name;
00449   std::string LocalName = "$$__fn_local_" + Name;
00450   Function *FStub = Function::Create
00451     (F->getFunctionType(),
00452      Function::InternalLinkage, StubName, M);
00453   FStub->addFnAttr("mips16_fp_stub");
00454   FStub->addFnAttr(llvm::Attribute::Naked);
00455   FStub->addFnAttr(llvm::Attribute::NoUnwind);
00456   FStub->addFnAttr(llvm::Attribute::NoInline);
00457   FStub->addFnAttr("nomips16");
00458   FStub->setSection(SectionName);
00459   BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
00460   InlineAsmHelper IAH(Context, BB);
00461   IAH.Out(" .set  macro");
00462   if (PicMode) {
00463     IAH.Out(".set noreorder");
00464     IAH.Out(".cpload  $$25");
00465     IAH.Out(".set reorder");
00466     IAH.Out(".reloc 0,R_MIPS_NONE," + Name);
00467     IAH.Out("la $$25," + LocalName);
00468   }
00469   else {
00470     IAH.Out(".set reorder");
00471     IAH.Out("la $$25," + Name);
00472   }
00473   swapFPIntParams(PV, M, IAH, LE, false);
00474   IAH.Out("jr $$25");
00475   IAH.Out(LocalName + " = " + Name);
00476   new UnreachableInst(FStub->getContext(), BB);
00477 }
00478 
00479 //
00480 // remove the use-soft-float attribute
00481 //
00482 static void removeUseSoftFloat(Function &F) {
00483   AttributeSet A;
00484   DEBUG(errs() << "removing -use-soft-float\n");
00485   A = A.addAttribute(F.getContext(), AttributeSet::FunctionIndex,
00486                      "use-soft-float", "false");
00487   F.removeAttributes(AttributeSet::FunctionIndex, A);
00488   if (F.hasFnAttribute("use-soft-float")) {
00489     DEBUG(errs() << "still has -use-soft-float\n");
00490   }
00491   F.addAttributes(AttributeSet::FunctionIndex, A);
00492 }
00493 
00494 namespace llvm {
00495 
00496 //
00497 // This pass only makes sense when the underlying chip has floating point but
00498 // we are compiling as mips16.
00499 // For all mips16 functions (that are not stubs we have already generated), or
00500 // declared via attributes as nomips16, we must:
00501 //    1) fixup all returns of float, double, single and double complex
00502 //       by calling a helper function before the actual return.
00503 //    2) generate helper functions (stubs) that can be called by mips32
00504 //       functions that will move parameters passed normally passed in
00505 //       floating point
00506 //       registers the soft float equivalents.
00507 //    3) in the case of static relocation, generate helper functions so that
00508 //       mips16 functions can call extern functions of unknown type (mips16 or
00509 //       mips32).
00510 //    4) TBD. For pic, calls to extern functions of unknown type are handled by
00511 //       predefined helper functions in libc but this work is currently done
00512 //       during call lowering but it should be moved here in the future.
00513 //
00514 bool Mips16HardFloat::runOnModule(Module &M) {
00515   DEBUG(errs() << "Run on Module Mips16HardFloat\n");
00516   bool Modified = false;
00517   for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
00518     if (F->hasFnAttribute("nomips16") &&
00519         F->hasFnAttribute("use-soft-float")) {
00520       removeUseSoftFloat(*F);
00521       continue;
00522     }
00523     if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
00524         F->hasFnAttribute("nomips16")) continue;
00525     Modified |= fixupFPReturnAndCall(*F, &M, Subtarget);
00526     FPParamVariant V = whichFPParamVariantNeeded(*F);
00527     if (V != NoSig) {
00528       Modified = true;
00529       createFPFnStub(F, &M, V, Subtarget);
00530     }
00531   }
00532   return Modified;
00533 }
00534 
00535 char Mips16HardFloat::ID = 0;
00536 
00537 }
00538 
00539 ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) {
00540   return new Mips16HardFloat(TM);
00541 }
00542