Mips16HardFloat.cpp revision c673f9c6fecb0f828845ada7ea5458f66f896283
1110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg//===---- Mips16HardFloat.cpp for Mips16 Hard Float --------===// 2110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg// 3110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg// The LLVM Compiler Infrastructure 41bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg// 5110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg// This file is distributed under the University of Illinois Open Source 6110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg// License. See LICENSE.TXT for details. 7110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg// 8110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg//===----------------------------------------------------------------------===// 936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// 1036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// This file defines a pass needed for Mips16 Hard Float 1136b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// 1236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines//===----------------------------------------------------------------------===// 1336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines 1436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#define DEBUG_TYPE "mips16-hard-float" 15110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg#include "Mips16HardFloat.h" 1636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/IR/Module.h" 171bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg#include "llvm/Support/Debug.h" 1836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines#include "llvm/Support/raw_ostream.h" 191bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg#include <algorithm> 20110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg#include <string> 211bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg 2236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hinesstatic void inlineAsmOut 231bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg (LLVMContext &C, StringRef AsmString, BasicBlock *BB ) { 2436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines std::vector<llvm::Type *> AsmArgTypes; 251bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg std::vector<llvm::Value*> AsmArgs; 261bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg llvm::FunctionType *AsmFTy = 27a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg llvm::FunctionType::get(Type::getVoidTy(C), 2836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines AsmArgTypes, false); 29a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg llvm::InlineAsm *IA = 3036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines llvm::InlineAsm::get(AsmFTy, AsmString, "", true, 31a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg /* IsAlignStack */ false, 32a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg llvm::InlineAsm::AD_ATT); 3336b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines CallInst::Create(IA, AsmArgs, "", BB); 346a24c7d4e78ade068e60cbb95adb5021014ba0b7Hans Wennborg} 356a24c7d4e78ade068e60cbb95adb5021014ba0b7Hans Wennborg 366a24c7d4e78ade068e60cbb95adb5021014ba0b7Hans Wennborgnamespace { 37110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg 38110b5209d92f224050f2755539bda8f1d801f94bHans Wennborgclass InlineAsmHelper { 391bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg LLVMContext &C; 401bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg BasicBlock *BB; 411bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborgpublic: 4236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines InlineAsmHelper(LLVMContext &C_, BasicBlock *BB_) : 43110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg C(C_), BB(BB_) { 4436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines } 45110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg 461bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg void Out(StringRef AsmString) { 471bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg inlineAsmOut(C, AsmString, BB); 48110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg } 491bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg 501bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg}; 511bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg} 5236b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// 531bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg// Return types that matter for hard float are: 5436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// float, double, complex float, and complex double 551bcff6cffa30c2fdcf0eac80ef9551429b38f25dHans Wennborg// 56a22ff961db47ffff4f1e795d810aa102edb9b79bReid Klecknerenum FPReturnVariant { 57a22ff961db47ffff4f1e795d810aa102edb9b79bReid Kleckner FRet, DRet, CFRet, CDRet, NoFPRet 5836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines}; 59a22ff961db47ffff4f1e795d810aa102edb9b79bReid Kleckner 6036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines// 61a22ff961db47ffff4f1e795d810aa102edb9b79bReid Kleckner// Determine which FP return type this function has 62a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg// 63a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborgstatic FPReturnVariant whichFPReturnVariant(Type *T) { 64a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg switch (T->getTypeID()) { 65a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg case Type::FloatTyID: 66a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg return FRet; 67a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg case Type::DoubleTyID: 6836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines return DRet; 69a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg case Type::StructTyID: 7036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines if (T->getStructNumElements() != 2) 71a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg break; 72a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg if ((T->getContainedType(0)->isFloatTy()) && 73a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg (T->getContainedType(1)->isFloatTy())) 7436b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines return CFRet; 75a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg if ((T->getContainedType(0)->isDoubleTy()) && 7636b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines (T->getContainedType(1)->isDoubleTy())) 77a7d9a5d64a89ef8532fcf38cc8a57960d48e283eHans Wennborg return CDRet; 7836b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines break; 7936b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines default: 8036b56886974eae4f9c5ebc96befd3e7bfe5de338Stephen Hines break; 816a24c7d4e78ade068e60cbb95adb5021014ba0b7Hans Wennborg } 826a24c7d4e78ade068e60cbb95adb5021014ba0b7Hans Wennborg return NoFPRet; 83110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg} 84110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg 85110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg// 86110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg// Parameter type that matter are float, (float, float), (float, double), 87110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg// double, (double, double), (double, float) 88110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg// 89110b5209d92f224050f2755539bda8f1d801f94bHans Wennborgenum FPParamVariant { 90110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg FSig, FFSig, FDSig, 91110b5209d92f224050f2755539bda8f1d801f94bHans Wennborg DSig, DDSig, DFSig, NoSig 92}; 93 94// which floating point parameter signature variant we are dealing with 95// 96typedef Type::TypeID TypeID; 97const Type::TypeID FloatTyID = Type::FloatTyID; 98const Type::TypeID DoubleTyID = Type::DoubleTyID; 99 100static FPParamVariant whichFPParamVariantNeeded(Function &F) { 101 switch (F.arg_size()) { 102 case 0: 103 return NoSig; 104 case 1:{ 105 TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID(); 106 switch (ArgTypeID) { 107 case FloatTyID: 108 return FSig; 109 case DoubleTyID: 110 return DSig; 111 default: 112 return NoSig; 113 } 114 } 115 default: { 116 TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID(); 117 TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID(); 118 switch(ArgTypeID0) { 119 case FloatTyID: { 120 switch (ArgTypeID1) { 121 case FloatTyID: 122 return FFSig; 123 case DoubleTyID: 124 return FDSig; 125 default: 126 return FSig; 127 } 128 } 129 case DoubleTyID: { 130 switch (ArgTypeID1) { 131 case FloatTyID: 132 return DFSig; 133 case DoubleTyID: 134 return DDSig; 135 default: 136 return DSig; 137 } 138 } 139 default: 140 return NoSig; 141 } 142 } 143 } 144 llvm_unreachable("can't get here"); 145} 146 147// Figure out if we need float point based on the function parameters. 148// We need to move variables in and/or out of floating point 149// registers because of the ABI 150// 151static bool needsFPStubFromParams(Function &F) { 152 if (F.arg_size() >=1) { 153 Type *ArgType = F.getFunctionType()->getParamType(0); 154 switch (ArgType->getTypeID()) { 155 case Type::FloatTyID: 156 case Type::DoubleTyID: 157 return true; 158 default: 159 break; 160 } 161 } 162 return false; 163} 164 165static bool needsFPReturnHelper(Function &F) { 166 Type* RetType = F.getReturnType(); 167 return whichFPReturnVariant(RetType) != NoFPRet; 168} 169 170static bool needsFPHelperFromSig(Function &F) { 171 return needsFPStubFromParams(F) || needsFPReturnHelper(F); 172} 173 174// 175// We swap between FP and Integer registers to allow Mips16 and Mips32 to 176// interoperate 177// 178 179static void swapFPIntParams 180 (FPParamVariant PV, Module *M, InlineAsmHelper &IAH, 181 bool LE, bool ToFP) { 182 //LLVMContext &Context = M->getContext(); 183 std::string MI = ToFP? "mtc1 ": "mfc1 "; 184 switch (PV) { 185 case FSig: 186 IAH.Out(MI + "$$4,$$f12"); 187 break; 188 case FFSig: 189 IAH.Out(MI +"$$4,$$f12"); 190 IAH.Out(MI + "$$5,$$f14"); 191 break; 192 case FDSig: 193 IAH.Out(MI + "$$4,$$f12"); 194 if (LE) { 195 IAH.Out(MI + "$$6,$$f14"); 196 IAH.Out(MI + "$$7,$$f15"); 197 } else { 198 IAH.Out(MI + "$$7,$$f14"); 199 IAH.Out(MI + "$$6,$$f15"); 200 } 201 break; 202 case DSig: 203 if (LE) { 204 IAH.Out(MI + "$$4,$$f12"); 205 IAH.Out(MI + "$$5,$$f13"); 206 } else { 207 IAH.Out(MI + "$$5,$$f12"); 208 IAH.Out(MI + "$$4,$$f13"); 209 } 210 break; 211 case DDSig: 212 if (LE) { 213 IAH.Out(MI + "$$4,$$f12"); 214 IAH.Out(MI + "$$5,$$f13"); 215 IAH.Out(MI + "$$6,$$f14"); 216 IAH.Out(MI + "$$7,$$f15"); 217 } else { 218 IAH.Out(MI + "$$5,$$f12"); 219 IAH.Out(MI + "$$4,$$f13"); 220 IAH.Out(MI + "$$7,$$f14"); 221 IAH.Out(MI + "$$6,$$f15"); 222 } 223 break; 224 case DFSig: 225 if (LE) { 226 IAH.Out(MI + "$$4,$$f12"); 227 IAH.Out(MI + "$$5,$$f13"); 228 } else { 229 IAH.Out(MI + "$$5,$$f12"); 230 IAH.Out(MI + "$$4,$$f13"); 231 } 232 IAH.Out(MI + "$$6,$$f14"); 233 break; 234 case NoSig: 235 return; 236 } 237} 238// 239// Make sure that we know we already need a stub for this function. 240// Having called needsFPHelperFromSig 241// 242static void assureFPCallStub(Function &F, Module *M, 243 const MipsSubtarget &Subtarget){ 244 // for now we only need them for static relocation 245 if (Subtarget.getRelocationModel() == Reloc::PIC_) 246 return; 247 LLVMContext &Context = M->getContext(); 248 bool LE = Subtarget.isLittle(); 249 std::string Name = F.getName(); 250 std::string SectionName = ".mips16.call.fp." + Name; 251 std::string StubName = "__call_stub_fp_" + Name; 252 // 253 // see if we already have the stub 254 // 255 Function *FStub = M->getFunction(StubName); 256 if (FStub && !FStub->isDeclaration()) return; 257 FStub = Function::Create(F.getFunctionType(), 258 Function::InternalLinkage, StubName, M); 259 FStub->addFnAttr("mips16_fp_stub"); 260 FStub->addFnAttr(llvm::Attribute::Naked); 261 FStub->addFnAttr(llvm::Attribute::NoInline); 262 FStub->addFnAttr(llvm::Attribute::NoUnwind); 263 FStub->addFnAttr("nomips16"); 264 FStub->setSection(SectionName); 265 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub); 266 InlineAsmHelper IAH(Context, BB); 267 IAH.Out(".set reorder"); 268 FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType()); 269 FPParamVariant PV = whichFPParamVariantNeeded(F); 270 swapFPIntParams(PV, M, IAH, LE, true); 271 if (RV != NoFPRet) { 272 IAH.Out("move $$18, $$31"); 273 IAH.Out("jal " + Name); 274 } else { 275 IAH.Out("lui $$25,%hi(" + Name + ")"); 276 IAH.Out("addiu $$25,$$25,%lo(" + Name + ")" ); 277 } 278 switch (RV) { 279 case FRet: 280 IAH.Out("mfc1 $$2,$$f0"); 281 break; 282 case DRet: 283 if (LE) { 284 IAH.Out("mfc1 $$2,$$f0"); 285 IAH.Out("mfc1 $$3,$$f1"); 286 } else { 287 IAH.Out("mfc1 $$3,$$f0"); 288 IAH.Out("mfc1 $$2,$$f1"); 289 } 290 break; 291 case CFRet: 292 if (LE) { 293 IAH.Out("mfc1 $$2,$$f0"); 294 IAH.Out("mfc1 $$3,$$f2"); 295 } else { 296 IAH.Out("mfc1 $$3,$$f0"); 297 IAH.Out("mfc1 $$3,$$f2"); 298 } 299 break; 300 case CDRet: 301 if (LE) { 302 IAH.Out("mfc1 $$4,$$f2"); 303 IAH.Out("mfc1 $$5,$$f3"); 304 IAH.Out("mfc1 $$2,$$f0"); 305 IAH.Out("mfc1 $$3,$$f1"); 306 307 } else { 308 IAH.Out("mfc1 $$5,$$f2"); 309 IAH.Out("mfc1 $$4,$$f3"); 310 IAH.Out("mfc1 $$3,$$f0"); 311 IAH.Out("mfc1 $$2,$$f1"); 312 } 313 break; 314 case NoFPRet: 315 break; 316 } 317 if (RV != NoFPRet) 318 IAH.Out("jr $$18"); 319 else 320 IAH.Out("jr $$25"); 321 new UnreachableInst(Context, BB); 322} 323 324// 325// Functions that are inline intrinsics don't need helpers. 326// 327static const char *IntrinsicInline[] = 328 {"fabs", "llvm.powi.f64"}; 329 330static bool isIntrinsicInline(Function *F) { 331 return std::binary_search( 332 IntrinsicInline, array_endof(IntrinsicInline), 333 F->getName()); 334} 335// 336// Returns of float, double and complex need to be handled with a helper 337// function. 338// 339static bool fixupFPReturnAndCall 340 (Function &F, Module *M, const MipsSubtarget &Subtarget) { 341 bool Modified = false; 342 LLVMContext &C = M->getContext(); 343 Type *MyVoid = Type::getVoidTy(C); 344 for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) 345 for (BasicBlock::iterator I = BB->begin(), E = BB->end(); 346 I != E; ++I) { 347 Instruction &Inst = *I; 348 if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) { 349 Value *RVal = RI->getReturnValue(); 350 if (!RVal) continue; 351 // 352 // If there is a return value and it needs a helper function, 353 // figure out which one and add a call before the actual 354 // return to this helper. The purpose of the helper is to move 355 // floating point values from their soft float return mapping to 356 // where they would have been mapped to in floating point registers. 357 // 358 Type *T = RVal->getType(); 359 FPReturnVariant RV = whichFPReturnVariant(T); 360 if (RV == NoFPRet) continue; 361 static const char* Helper[NoFPRet] = 362 {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc", 363 "__mips16_ret_dc"}; 364 const char *Name = Helper[RV]; 365 AttributeSet A; 366 Value *Params[] = {RVal}; 367 Modified = true; 368 // 369 // These helper functions have a different calling ABI so 370 // this __Mips16RetHelper indicates that so that later 371 // during call setup, the proper call lowering to the helper 372 // functions will take place. 373 // 374 A = A.addAttribute(C, AttributeSet::FunctionIndex, 375 "__Mips16RetHelper"); 376 A = A.addAttribute(C, AttributeSet::FunctionIndex, 377 Attribute::ReadNone); 378 A = A.addAttribute(C, AttributeSet::FunctionIndex, 379 Attribute::NoInline); 380 Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL)); 381 CallInst::Create(F, Params, "", &Inst ); 382 } else if (const CallInst *CI = dyn_cast<CallInst>(I)) { 383 // pic mode calls are handled by already defined 384 // helper functions 385 if (Subtarget.getRelocationModel() != Reloc::PIC_ ) { 386 Function *F_ = CI->getCalledFunction(); 387 if (F_ && !isIntrinsicInline(F_) && needsFPHelperFromSig(*F_)) { 388 assureFPCallStub(*F_, M, Subtarget); 389 Modified=true; 390 } 391 } 392 } 393 } 394 return Modified; 395} 396 397static void createFPFnStub(Function *F, Module *M, FPParamVariant PV, 398 const MipsSubtarget &Subtarget ) { 399 bool PicMode = Subtarget.getRelocationModel() == Reloc::PIC_; 400 bool LE = Subtarget.isLittle(); 401 LLVMContext &Context = M->getContext(); 402 std::string Name = F->getName(); 403 std::string SectionName = ".mips16.fn." + Name; 404 std::string StubName = "__fn_stub_" + Name; 405 std::string LocalName = "__fn_local_" + Name; 406 Function *FStub = Function::Create 407 (F->getFunctionType(), 408 Function::InternalLinkage, StubName, M); 409 FStub->addFnAttr("mips16_fp_stub"); 410 FStub->addFnAttr(llvm::Attribute::Naked); 411 FStub->addFnAttr(llvm::Attribute::NoUnwind); 412 FStub->addFnAttr(llvm::Attribute::NoInline); 413 FStub->addFnAttr("nomips16"); 414 FStub->setSection(SectionName); 415 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub); 416 InlineAsmHelper IAH(Context, BB); 417 IAH.Out(" .set macro"); 418 if (PicMode) { 419 IAH.Out(".set noreorder"); 420 IAH.Out(".cpload $$2"); 421 IAH.Out(".set reorder"); 422 IAH.Out(".reloc 0,R_MIPS_NONE," + Name); 423 IAH.Out("la $$25," + LocalName); 424 } 425 else 426 IAH.Out("la $$25, " + Name); 427 swapFPIntParams(PV, M, IAH, LE, false); 428 IAH.Out("jr $$25"); 429 IAH.Out(LocalName + " = " + Name); 430 new UnreachableInst(FStub->getContext(), BB); 431} 432 433// 434// remove the use-soft-float attribute 435// 436static void removeUseSoftFloat(Function &F) { 437 AttributeSet A; 438 DEBUG(errs() << "removing -use-soft-float\n"); 439 A = A.addAttribute(F.getContext(), AttributeSet::FunctionIndex, 440 "use-soft-float", "false"); 441 F.removeAttributes(AttributeSet::FunctionIndex, A); 442 if (F.hasFnAttribute("use-soft-float")) { 443 DEBUG(errs() << "still has -use-soft-float\n"); 444 } 445 F.addAttributes(AttributeSet::FunctionIndex, A); 446} 447 448namespace llvm { 449 450// 451// This pass only makes sense when the underlying chip has floating point but 452// we are compiling as mips16. 453// For all mips16 functions (that are not stubs we have already generated), or 454// declared via attributes as nomips16, we must: 455// 1) fixup all returns of float, double, single and double complex 456// by calling a helper function before the actual return. 457// 2) generate helper functions (stubs) that can be called by mips32 functions 458// that will move parameters passed normally passed in floating point 459// registers the soft float equivalents. 460// 3) in the case of static relocation, generate helper functions so that 461// mips16 functions can call extern functions of unknown type (mips16 or 462// mips32). 463// 4) TBD. For pic, calls to extern functions of unknown type are handled by 464// predefined helper functions in libc but this work is currently done 465// during call lowering but it should be moved here in the future. 466// 467bool Mips16HardFloat::runOnModule(Module &M) { 468 DEBUG(errs() << "Run on Module Mips16HardFloat\n"); 469 bool Modified = false; 470 for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) { 471 if (F->hasFnAttribute("nomips16") && 472 F->hasFnAttribute("use-soft-float")) { 473 removeUseSoftFloat(*F); 474 continue; 475 } 476 if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") || 477 F->hasFnAttribute("nomips16")) continue; 478 Modified |= fixupFPReturnAndCall(*F, &M, Subtarget); 479 FPParamVariant V = whichFPParamVariantNeeded(*F); 480 if (V != NoSig) { 481 Modified = true; 482 createFPFnStub(F, &M, V, Subtarget); 483 } 484 } 485 return Modified; 486} 487 488char Mips16HardFloat::ID = 0; 489 490} 491 492ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) { 493 return new Mips16HardFloat(TM); 494} 495 496