Reed Kotler | 4609091 | 2013-05-10 22:25:39 +0000 | [diff] [blame^] | 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 | // |
| 22 | // Return types that matter for hard float are: |
| 23 | // float, double, complex float, and complex double |
| 24 | // |
| 25 | enum FPReturnVariant { |
| 26 | FRet, DRet, CFRet, CDRet, NoFPRet |
| 27 | }; |
| 28 | |
| 29 | // |
| 30 | // Determine which FP return type this function has |
| 31 | // |
| 32 | static FPReturnVariant whichFPReturnVariant(Type *T) { |
| 33 | switch (T->getTypeID()) { |
| 34 | case Type::FloatTyID: |
| 35 | return FRet; |
| 36 | case Type::DoubleTyID: |
| 37 | return DRet; |
| 38 | case Type::StructTyID: |
| 39 | if (T->getStructNumElements() != 2) |
| 40 | break; |
| 41 | if ((T->getContainedType(0)->isFloatTy()) && |
| 42 | (T->getContainedType(1)->isFloatTy())) |
| 43 | return CFRet; |
| 44 | if ((T->getContainedType(0)->isDoubleTy()) && |
| 45 | (T->getContainedType(1)->isDoubleTy())) |
| 46 | return CDRet; |
| 47 | break; |
| 48 | default: |
| 49 | break; |
| 50 | } |
| 51 | return NoFPRet; |
| 52 | } |
| 53 | |
| 54 | // |
| 55 | // Returns of float, double and complex need to be handled with a helper |
| 56 | // function. The "AndCal" part is coming in a later patch. |
| 57 | // |
| 58 | static bool fixupFPReturnAndCall |
| 59 | (Function &F, Module *M, const MipsSubtarget &Subtarget) { |
| 60 | bool Modified = false; |
| 61 | LLVMContext &C = M->getContext(); |
| 62 | Type *MyVoid = Type::getVoidTy(C); |
| 63 | for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) |
| 64 | for (BasicBlock::iterator I = BB->begin(), E = BB->end(); |
| 65 | I != E; ++I) { |
| 66 | Instruction &Inst = *I; |
| 67 | if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) { |
| 68 | Value *RVal = RI->getReturnValue(); |
| 69 | if (!RVal) continue; |
| 70 | // |
| 71 | // If there is a return value and it needs a helper function, |
| 72 | // figure out which one and add a call before the actual |
| 73 | // return to this helper. The purpose of the helper is to move |
| 74 | // floating point values from their soft float return mapping to |
| 75 | // where they would have been mapped to in floating point registers. |
| 76 | // |
| 77 | Type *T = RVal->getType(); |
| 78 | FPReturnVariant RV = whichFPReturnVariant(T); |
| 79 | if (RV == NoFPRet) continue; |
| 80 | static const char* Helper[NoFPRet] = |
| 81 | {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc", |
| 82 | "__mips16_ret_dc"}; |
| 83 | const char *Name = Helper[RV]; |
| 84 | AttributeSet A; |
| 85 | Value *Params[] = {RVal}; |
| 86 | Modified = true; |
| 87 | // |
| 88 | // These helper functions have a different calling ABI so |
| 89 | // this __Mips16RetHelper indicates that so that later |
| 90 | // during call setup, the proper call lowering to the helper |
| 91 | // functions will take place. |
| 92 | // |
| 93 | A = A.addAttribute(C, AttributeSet::FunctionIndex, |
| 94 | "__Mips16RetHelper"); |
| 95 | A = A.addAttribute(C, AttributeSet::FunctionIndex, |
| 96 | Attribute::ReadNone); |
| 97 | Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL)); |
| 98 | CallInst::Create(F, Params, "", &Inst ); |
| 99 | } |
| 100 | } |
| 101 | return Modified; |
| 102 | } |
| 103 | |
| 104 | namespace llvm { |
| 105 | |
| 106 | // |
| 107 | // This pass only makes sense when the underlying chip has floating point but |
| 108 | // we are compiling as mips16. |
| 109 | // For all mips16 functions (that are not stubs we have already generated), or |
| 110 | // declared via attributes as nomips16, we must: |
| 111 | // 1) fixup all returns of float, double, single and double complex |
| 112 | // by calling a helper function before the actual return. |
| 113 | // 2) generate helper functions (stubs) that can be called by mips32 functions |
| 114 | // that will move parameters passed normally passed in floating point |
| 115 | // registers the soft float equivalents. (Coming in a later patch). |
| 116 | // 3) in the case of static relocation, generate helper functions so that |
| 117 | // mips16 functions can call extern functions of unknown type (mips16 or |
| 118 | // mips32). (Coming in a later patch). |
| 119 | // 4) TBD. For pic, calls to extern functions of unknown type are handled by |
| 120 | // predefined helper functions in libc but this work is currently done |
| 121 | // during call lowering but it should be moved here in the future. |
| 122 | // |
| 123 | bool Mips16HardFloat::runOnModule(Module &M) { |
| 124 | DEBUG(errs() << "Run on Module Mips16HardFloat\n"); |
| 125 | bool Modified = false; |
| 126 | for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { |
| 127 | if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") || |
| 128 | F->hasFnAttribute("nomips16")) continue; |
| 129 | Modified |= fixupFPReturnAndCall(*F, &M, Subtarget); |
| 130 | } |
| 131 | return Modified; |
| 132 | } |
| 133 | |
| 134 | char Mips16HardFloat::ID = 0; |
| 135 | |
| 136 | } |
| 137 | |
| 138 | ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) { |
| 139 | return new Mips16HardFloat(TM); |
| 140 | } |
| 141 | |