1 //===---- Mips16HardFloat.cpp for Mips16 Hard Float --------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines a pass needed for Mips16 Hard Float
12 //===----------------------------------------------------------------------===//
14 #define DEBUG_TYPE "mips16-hard-float"
15 #include "Mips16HardFloat.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/IR/Value.h"
18 #include "llvm/Support/Debug.h"
19 #include "llvm/Support/raw_ostream.h"
23 static void inlineAsmOut
24 (LLVMContext &C, StringRef AsmString, BasicBlock *BB ) {
25 std::vector<llvm::Type *> AsmArgTypes;
26 std::vector<llvm::Value*> AsmArgs;
27 llvm::FunctionType *AsmFTy =
28 llvm::FunctionType::get(Type::getVoidTy(C),
31 llvm::InlineAsm::get(AsmFTy, AsmString, "", true,
32 /* IsAlignStack */ false,
33 llvm::InlineAsm::AD_ATT);
34 CallInst::Create(IA, AsmArgs, "", BB);
39 class InlineAsmHelper {
43 InlineAsmHelper(LLVMContext &C_, BasicBlock *BB_) :
47 void Out(StringRef AsmString) {
48 inlineAsmOut(C, AsmString, BB);
54 // Return types that matter for hard float are:
55 // float, double, complex float, and complex double
57 enum FPReturnVariant {
58 FRet, DRet, CFRet, CDRet, NoFPRet
62 // Determine which FP return type this function has
64 static FPReturnVariant whichFPReturnVariant(Type *T) {
65 switch (T->getTypeID()) {
68 case Type::DoubleTyID:
70 case Type::StructTyID:
71 if (T->getStructNumElements() != 2)
73 if ((T->getContainedType(0)->isFloatTy()) &&
74 (T->getContainedType(1)->isFloatTy()))
76 if ((T->getContainedType(0)->isDoubleTy()) &&
77 (T->getContainedType(1)->isDoubleTy()))
87 // Parameter type that matter are float, (float, float), (float, double),
88 // double, (double, double), (double, float)
92 DSig, DDSig, DFSig, NoSig
95 // which floating point parameter signature variant we are dealing with
97 typedef Type::TypeID TypeID;
98 const Type::TypeID FloatTyID = Type::FloatTyID;
99 const Type::TypeID DoubleTyID = Type::DoubleTyID;
101 static FPParamVariant whichFPParamVariantNeeded(Function &F) {
102 switch (F.arg_size()) {
106 TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
117 TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
118 TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
121 switch (ArgTypeID1) {
131 switch (ArgTypeID1) {
145 llvm_unreachable("can't get here");
148 // Figure out if we need float point based on the function parameters.
149 // We need to move variables in and/or out of floating point
150 // registers because of the ABI
152 static bool needsFPStubFromParams(Function &F) {
153 if (F.arg_size() >=1) {
154 Type *ArgType = F.getFunctionType()->getParamType(0);
155 switch (ArgType->getTypeID()) {
156 case Type::FloatTyID:
157 case Type::DoubleTyID:
166 static bool needsFPReturnHelper(Function &F) {
167 Type* RetType = F.getReturnType();
168 return whichFPReturnVariant(RetType) != NoFPRet;
171 static bool needsFPReturnHelper(const FunctionType &FT) {
172 Type* RetType = FT.getReturnType();
173 return whichFPReturnVariant(RetType) != NoFPRet;
176 static bool needsFPHelperFromSig(Function &F) {
177 return needsFPStubFromParams(F) || needsFPReturnHelper(F);
181 // We swap between FP and Integer registers to allow Mips16 and Mips32 to
185 static void swapFPIntParams
186 (FPParamVariant PV, Module *M, InlineAsmHelper &IAH,
187 bool LE, bool ToFP) {
188 //LLVMContext &Context = M->getContext();
189 std::string MI = ToFP? "mtc1 ": "mfc1 ";
192 IAH.Out(MI + "$$4,$$f12");
195 IAH.Out(MI +"$$4,$$f12");
196 IAH.Out(MI + "$$5,$$f14");
199 IAH.Out(MI + "$$4,$$f12");
201 IAH.Out(MI + "$$6,$$f14");
202 IAH.Out(MI + "$$7,$$f15");
204 IAH.Out(MI + "$$7,$$f14");
205 IAH.Out(MI + "$$6,$$f15");
210 IAH.Out(MI + "$$4,$$f12");
211 IAH.Out(MI + "$$5,$$f13");
213 IAH.Out(MI + "$$5,$$f12");
214 IAH.Out(MI + "$$4,$$f13");
219 IAH.Out(MI + "$$4,$$f12");
220 IAH.Out(MI + "$$5,$$f13");
221 IAH.Out(MI + "$$6,$$f14");
222 IAH.Out(MI + "$$7,$$f15");
224 IAH.Out(MI + "$$5,$$f12");
225 IAH.Out(MI + "$$4,$$f13");
226 IAH.Out(MI + "$$7,$$f14");
227 IAH.Out(MI + "$$6,$$f15");
232 IAH.Out(MI + "$$4,$$f12");
233 IAH.Out(MI + "$$5,$$f13");
235 IAH.Out(MI + "$$5,$$f12");
236 IAH.Out(MI + "$$4,$$f13");
238 IAH.Out(MI + "$$6,$$f14");
245 // Make sure that we know we already need a stub for this function.
246 // Having called needsFPHelperFromSig
248 static void assureFPCallStub(Function &F, Module *M,
249 const MipsSubtarget &Subtarget) {
250 // for now we only need them for static relocation
251 if (Subtarget.getRelocationModel() == Reloc::PIC_)
253 LLVMContext &Context = M->getContext();
254 bool LE = Subtarget.isLittle();
255 std::string Name = F.getName();
256 std::string SectionName = ".mips16.call.fp." + Name;
257 std::string StubName = "__call_stub_fp_" + Name;
259 // see if we already have the stub
261 Function *FStub = M->getFunction(StubName);
262 if (FStub && !FStub->isDeclaration()) return;
263 FStub = Function::Create(F.getFunctionType(),
264 Function::InternalLinkage, StubName, M);
265 FStub->addFnAttr("mips16_fp_stub");
266 FStub->addFnAttr(llvm::Attribute::Naked);
267 FStub->addFnAttr(llvm::Attribute::NoInline);
268 FStub->addFnAttr(llvm::Attribute::NoUnwind);
269 FStub->addFnAttr("nomips16");
270 FStub->setSection(SectionName);
271 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
272 InlineAsmHelper IAH(Context, BB);
273 IAH.Out(".set reorder");
274 FPReturnVariant RV = whichFPReturnVariant(FStub->getReturnType());
275 FPParamVariant PV = whichFPParamVariantNeeded(F);
276 swapFPIntParams(PV, M, IAH, LE, true);
278 IAH.Out("move $$18, $$31");
279 IAH.Out("jal " + Name);
281 IAH.Out("lui $$25,%hi(" + Name + ")");
282 IAH.Out("addiu $$25,$$25,%lo(" + Name + ")" );
286 IAH.Out("mfc1 $$2,$$f0");
290 IAH.Out("mfc1 $$2,$$f0");
291 IAH.Out("mfc1 $$3,$$f1");
293 IAH.Out("mfc1 $$3,$$f0");
294 IAH.Out("mfc1 $$2,$$f1");
299 IAH.Out("mfc1 $$2,$$f0");
300 IAH.Out("mfc1 $$3,$$f2");
302 IAH.Out("mfc1 $$3,$$f0");
303 IAH.Out("mfc1 $$3,$$f2");
308 IAH.Out("mfc1 $$4,$$f2");
309 IAH.Out("mfc1 $$5,$$f3");
310 IAH.Out("mfc1 $$2,$$f0");
311 IAH.Out("mfc1 $$3,$$f1");
314 IAH.Out("mfc1 $$5,$$f2");
315 IAH.Out("mfc1 $$4,$$f3");
316 IAH.Out("mfc1 $$3,$$f0");
317 IAH.Out("mfc1 $$2,$$f1");
327 new UnreachableInst(Context, BB);
331 // Functions that are llvm intrinsics and don't need helpers.
333 static const char *IntrinsicInline[] =
336 "llvm.ceil.f32", "llvm.ceil.f64",
337 "llvm.copysign.f32", "llvm.copysign.f64",
338 "llvm.cos.f32", "llvm.cos.f64",
339 "llvm.exp.f32", "llvm.exp.f64",
340 "llvm.exp2.f32", "llvm.exp2.f64",
341 "llvm.fabs.f32", "llvm.fabs.f64",
342 "llvm.floor.f32", "llvm.floor.f64",
343 "llvm.fma.f32", "llvm.fma.f64",
344 "llvm.log.f32", "llvm.log.f64",
345 "llvm.log10.f32", "llvm.log10.f64",
346 "llvm.nearbyint.f32", "llvm.nearbyint.f64",
347 "llvm.pow.f32", "llvm.pow.f64",
348 "llvm.powi.f32", "llvm.powi.f64",
349 "llvm.rint.f32", "llvm.rint.f64",
350 "llvm.round.f32", "llvm.round.f64",
351 "llvm.sin.f32", "llvm.sin.f64",
352 "llvm.sqrt.f32", "llvm.sqrt.f64",
353 "llvm.trunc.f32", "llvm.trunc.f64",
356 static bool isIntrinsicInline(Function *F) {
357 return std::binary_search(std::begin(IntrinsicInline),
358 std::end(IntrinsicInline), F->getName());
361 // Returns of float, double and complex need to be handled with a helper
364 static bool fixupFPReturnAndCall
365 (Function &F, Module *M, const MipsSubtarget &Subtarget) {
366 bool Modified = false;
367 LLVMContext &C = M->getContext();
368 Type *MyVoid = Type::getVoidTy(C);
369 for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
370 for (BasicBlock::iterator I = BB->begin(), E = BB->end();
372 Instruction &Inst = *I;
373 if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) {
374 Value *RVal = RI->getReturnValue();
377 // If there is a return value and it needs a helper function,
378 // figure out which one and add a call before the actual
379 // return to this helper. The purpose of the helper is to move
380 // floating point values from their soft float return mapping to
381 // where they would have been mapped to in floating point registers.
383 Type *T = RVal->getType();
384 FPReturnVariant RV = whichFPReturnVariant(T);
385 if (RV == NoFPRet) continue;
386 static const char* Helper[NoFPRet] =
387 {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
389 const char *Name = Helper[RV];
391 Value *Params[] = {RVal};
394 // These helper functions have a different calling ABI so
395 // this __Mips16RetHelper indicates that so that later
396 // during call setup, the proper call lowering to the helper
397 // functions will take place.
399 A = A.addAttribute(C, AttributeSet::FunctionIndex,
400 "__Mips16RetHelper");
401 A = A.addAttribute(C, AttributeSet::FunctionIndex,
402 Attribute::ReadNone);
403 A = A.addAttribute(C, AttributeSet::FunctionIndex,
404 Attribute::NoInline);
405 Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL));
406 CallInst::Create(F, Params, "", &Inst );
407 } else if (const CallInst *CI = dyn_cast<CallInst>(I)) {
408 const Value* V = CI->getCalledValue();
410 if (V) T = V->getType();
411 const PointerType *PFT=0;
412 if (T) PFT = dyn_cast<PointerType>(T);
413 const FunctionType *FT=0;
414 if (PFT) FT = dyn_cast<FunctionType>(PFT->getElementType());
415 Function *F_ = CI->getCalledFunction();
416 if (FT && needsFPReturnHelper(*FT) &&
417 !(F_ && isIntrinsicInline(F_))) {
419 F.addFnAttr("saveS2");
421 if (F_ && !isIntrinsicInline(F_)) {
422 // pic mode calls are handled by already defined
424 if (needsFPReturnHelper(*F_)) {
426 F.addFnAttr("saveS2");
428 if (Subtarget.getRelocationModel() != Reloc::PIC_ ) {
429 if (needsFPHelperFromSig(*F_)) {
430 assureFPCallStub(*F_, M, Subtarget);
440 static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
441 const MipsSubtarget &Subtarget ) {
442 bool PicMode = Subtarget.getRelocationModel() == Reloc::PIC_;
443 bool LE = Subtarget.isLittle();
444 LLVMContext &Context = M->getContext();
445 std::string Name = F->getName();
446 std::string SectionName = ".mips16.fn." + Name;
447 std::string StubName = "__fn_stub_" + Name;
448 std::string LocalName = "$$__fn_local_" + Name;
449 Function *FStub = Function::Create
450 (F->getFunctionType(),
451 Function::InternalLinkage, StubName, M);
452 FStub->addFnAttr("mips16_fp_stub");
453 FStub->addFnAttr(llvm::Attribute::Naked);
454 FStub->addFnAttr(llvm::Attribute::NoUnwind);
455 FStub->addFnAttr(llvm::Attribute::NoInline);
456 FStub->addFnAttr("nomips16");
457 FStub->setSection(SectionName);
458 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
459 InlineAsmHelper IAH(Context, BB);
460 IAH.Out(" .set macro");
462 IAH.Out(".set noreorder");
463 IAH.Out(".cpload $$25");
464 IAH.Out(".set reorder");
465 IAH.Out(".reloc 0,R_MIPS_NONE," + Name);
466 IAH.Out("la $$25," + LocalName);
469 IAH.Out(".set reorder");
470 IAH.Out("la $$25," + Name);
472 swapFPIntParams(PV, M, IAH, LE, false);
474 IAH.Out(LocalName + " = " + Name);
475 new UnreachableInst(FStub->getContext(), BB);
479 // remove the use-soft-float attribute
481 static void removeUseSoftFloat(Function &F) {
483 DEBUG(errs() << "removing -use-soft-float\n");
484 A = A.addAttribute(F.getContext(), AttributeSet::FunctionIndex,
485 "use-soft-float", "false");
486 F.removeAttributes(AttributeSet::FunctionIndex, A);
487 if (F.hasFnAttribute("use-soft-float")) {
488 DEBUG(errs() << "still has -use-soft-float\n");
490 F.addAttributes(AttributeSet::FunctionIndex, A);
496 // This pass only makes sense when the underlying chip has floating point but
497 // we are compiling as mips16.
498 // For all mips16 functions (that are not stubs we have already generated), or
499 // declared via attributes as nomips16, we must:
500 // 1) fixup all returns of float, double, single and double complex
501 // by calling a helper function before the actual return.
502 // 2) generate helper functions (stubs) that can be called by mips32
503 // functions that will move parameters passed normally passed in
505 // registers the soft float equivalents.
506 // 3) in the case of static relocation, generate helper functions so that
507 // mips16 functions can call extern functions of unknown type (mips16 or
509 // 4) TBD. For pic, calls to extern functions of unknown type are handled by
510 // predefined helper functions in libc but this work is currently done
511 // during call lowering but it should be moved here in the future.
513 bool Mips16HardFloat::runOnModule(Module &M) {
514 DEBUG(errs() << "Run on Module Mips16HardFloat\n");
515 bool Modified = false;
516 for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
517 if (F->hasFnAttribute("nomips16") &&
518 F->hasFnAttribute("use-soft-float")) {
519 removeUseSoftFloat(*F);
522 if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
523 F->hasFnAttribute("nomips16")) continue;
524 Modified |= fixupFPReturnAndCall(*F, &M, Subtarget);
525 FPParamVariant V = whichFPParamVariantNeeded(*F);
528 createFPFnStub(F, &M, V, Subtarget);
534 char Mips16HardFloat::ID = 0;
538 ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) {
539 return new Mips16HardFloat(TM);