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/Support/Debug.h"
18 #include "llvm/Support/raw_ostream.h"
22 static void inlineAsmOut
23 (LLVMContext &C, StringRef AsmString, BasicBlock *BB ) {
24 std::vector<llvm::Type *> AsmArgTypes;
25 std::vector<llvm::Value*> AsmArgs;
26 llvm::FunctionType *AsmFTy =
27 llvm::FunctionType::get(Type::getVoidTy(C),
30 llvm::InlineAsm::get(AsmFTy, AsmString, "", true,
31 /* IsAlignStack */ false,
32 llvm::InlineAsm::AD_ATT);
33 CallInst::Create(IA, AsmArgs, "", BB);
38 class InlineAsmHelper {
42 InlineAsmHelper(LLVMContext &C_, BasicBlock *BB_) :
46 void Out(StringRef AsmString) {
47 inlineAsmOut(C, AsmString, BB);
53 // Return types that matter for hard float are:
54 // float, double, complex float, and complex double
56 enum FPReturnVariant {
57 FRet, DRet, CFRet, CDRet, NoFPRet
61 // Determine which FP return type this function has
63 static FPReturnVariant whichFPReturnVariant(Type *T) {
64 switch (T->getTypeID()) {
67 case Type::DoubleTyID:
69 case Type::StructTyID:
70 if (T->getStructNumElements() != 2)
72 if ((T->getContainedType(0)->isFloatTy()) &&
73 (T->getContainedType(1)->isFloatTy()))
75 if ((T->getContainedType(0)->isDoubleTy()) &&
76 (T->getContainedType(1)->isDoubleTy()))
86 // Parameter type that matter are float, (float, float), (float, double),
87 // double, (double, double), (double, float)
91 DSig, DDSig, DFSig, NoSig
94 // which floating point parameter signature variant we are dealing with
96 typedef Type::TypeID TypeID;
97 const Type::TypeID FloatTyID = Type::FloatTyID;
98 const Type::TypeID DoubleTyID = Type::DoubleTyID;
100 static FPParamVariant whichFPParamVariantNeeded(Function &F) {
101 switch (F.arg_size()) {
105 TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
116 TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
117 TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
120 switch (ArgTypeID1) {
130 switch (ArgTypeID1) {
144 llvm_unreachable("can't get here");
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
151 static 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:
165 static bool needsFPReturnHelper(Function &F) {
166 Type* RetType = F.getReturnType();
167 return whichFPReturnVariant(RetType) != NoFPRet;
170 static bool needsFPHelperFromSig(Function &F) {
171 return needsFPStubFromParams(F) || needsFPReturnHelper(F);
175 // We swap between FP and Integer registers to allow Mips16 and Mips32 to
179 static 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 ";
186 IAH.Out(MI + "$$4,$$f12");
189 IAH.Out(MI +"$$4,$$f12");
190 IAH.Out(MI + "$$5,$$f14");
193 IAH.Out(MI + "$$4,$$f12");
195 IAH.Out(MI + "$$6,$$f14");
196 IAH.Out(MI + "$$7,$$f15");
198 IAH.Out(MI + "$$7,$$f14");
199 IAH.Out(MI + "$$6,$$f15");
204 IAH.Out(MI + "$$4,$$f12");
205 IAH.Out(MI + "$$5,$$f13");
207 IAH.Out(MI + "$$5,$$f12");
208 IAH.Out(MI + "$$4,$$f13");
213 IAH.Out(MI + "$$4,$$f12");
214 IAH.Out(MI + "$$5,$$f13");
215 IAH.Out(MI + "$$6,$$f14");
216 IAH.Out(MI + "$$7,$$f15");
218 IAH.Out(MI + "$$5,$$f12");
219 IAH.Out(MI + "$$4,$$f13");
220 IAH.Out(MI + "$$7,$$f14");
221 IAH.Out(MI + "$$6,$$f15");
226 IAH.Out(MI + "$$4,$$f12");
227 IAH.Out(MI + "$$5,$$f13");
229 IAH.Out(MI + "$$5,$$f12");
230 IAH.Out(MI + "$$4,$$f13");
232 IAH.Out(MI + "$$6,$$f14");
239 // Make sure that we know we already need a stub for this function.
240 // Having called needsFPHelperFromSig
242 static 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_)
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;
253 // see if we already have the stub
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);
272 IAH.Out("move $$18, $$31");
273 IAH.Out("jal " + Name);
275 IAH.Out("lui $$25,%hi(" + Name + ")");
276 IAH.Out("addiu $$25,$$25,%lo(" + Name + ")" );
280 IAH.Out("mfc1 $$2,$$f0");
284 IAH.Out("mfc1 $$2,$$f0");
285 IAH.Out("mfc1 $$3,$$f1");
287 IAH.Out("mfc1 $$3,$$f0");
288 IAH.Out("mfc1 $$2,$$f1");
293 IAH.Out("mfc1 $$2,$$f0");
294 IAH.Out("mfc1 $$3,$$f2");
296 IAH.Out("mfc1 $$3,$$f0");
297 IAH.Out("mfc1 $$3,$$f2");
302 IAH.Out("mfc1 $$4,$$f2");
303 IAH.Out("mfc1 $$5,$$f3");
304 IAH.Out("mfc1 $$2,$$f0");
305 IAH.Out("mfc1 $$3,$$f1");
308 IAH.Out("mfc1 $$5,$$f2");
309 IAH.Out("mfc1 $$4,$$f3");
310 IAH.Out("mfc1 $$3,$$f0");
311 IAH.Out("mfc1 $$2,$$f1");
321 new UnreachableInst(Context, BB);
325 // Functions that are llvm intrinsics and don't need helpers.
327 static const char *IntrinsicInline[] =
330 "llvm.ceil.f32", "llvm.ceil.f64",
331 "llvm.copysign.f32", "llvm.copysign.f64",
332 "llvm.cos.f32", "llvm.cos.f64",
333 "llvm.exp.f32", "llvm.exp.f64",
334 "llvm.exp2.f32", "llvm.exp2.f64",
335 "llvm.fabs.f32", "llvm.fabs.f64",
336 "llvm.floor.f32", "llvm.floor.f64",
337 "llvm.fma.f32", "llvm.fma.f64",
338 "llvm.log.f32", "llvm.log.f64",
339 "llvm.log10.f32", "llvm.log10.f64",
340 "llvm.nearbyint.f32", "llvm.nearbyint.f64",
341 "llvm.pow.f32", "llvm.pow.f64",
342 "llvm.powi.f32", "llvm.powi.f64",
343 "llvm.rint.f32", "llvm.rint.f64",
344 "llvm.round.f32", "llvm.round.f64",
345 "llvm.sin.f32", "llvm.sin.f64",
346 "llvm.sqrt.f32", "llvm.sqrt.f64",
347 "llvm.trunc.f32", "llvm.trunc.f64",
350 static bool isIntrinsicInline(Function *F) {
351 return std::binary_search(
352 IntrinsicInline, array_endof(IntrinsicInline),
356 // Returns of float, double and complex need to be handled with a helper
359 static bool fixupFPReturnAndCall
360 (Function &F, Module *M, const MipsSubtarget &Subtarget) {
361 bool Modified = false;
362 LLVMContext &C = M->getContext();
363 Type *MyVoid = Type::getVoidTy(C);
364 for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
365 for (BasicBlock::iterator I = BB->begin(), E = BB->end();
367 Instruction &Inst = *I;
368 if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) {
369 Value *RVal = RI->getReturnValue();
372 // If there is a return value and it needs a helper function,
373 // figure out which one and add a call before the actual
374 // return to this helper. The purpose of the helper is to move
375 // floating point values from their soft float return mapping to
376 // where they would have been mapped to in floating point registers.
378 Type *T = RVal->getType();
379 FPReturnVariant RV = whichFPReturnVariant(T);
380 if (RV == NoFPRet) continue;
381 static const char* Helper[NoFPRet] =
382 {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
384 const char *Name = Helper[RV];
386 Value *Params[] = {RVal};
389 // These helper functions have a different calling ABI so
390 // this __Mips16RetHelper indicates that so that later
391 // during call setup, the proper call lowering to the helper
392 // functions will take place.
394 A = A.addAttribute(C, AttributeSet::FunctionIndex,
395 "__Mips16RetHelper");
396 A = A.addAttribute(C, AttributeSet::FunctionIndex,
397 Attribute::ReadNone);
398 A = A.addAttribute(C, AttributeSet::FunctionIndex,
399 Attribute::NoInline);
400 Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, NULL));
401 CallInst::Create(F, Params, "", &Inst );
402 } else if (const CallInst *CI = dyn_cast<CallInst>(I)) {
403 Function *F_ = CI->getCalledFunction();
404 if (F_ && !isIntrinsicInline(F_)) {
405 // pic mode calls are handled by already defined
407 if (needsFPReturnHelper(*F_)) {
409 F.addFnAttr("saveS2");
411 if (Subtarget.getRelocationModel() != Reloc::PIC_ ) {
412 if (needsFPHelperFromSig(*F_)) {
413 assureFPCallStub(*F_, M, Subtarget);
423 static void createFPFnStub(Function *F, Module *M, FPParamVariant PV,
424 const MipsSubtarget &Subtarget ) {
425 bool PicMode = Subtarget.getRelocationModel() == Reloc::PIC_;
426 bool LE = Subtarget.isLittle();
427 LLVMContext &Context = M->getContext();
428 std::string Name = F->getName();
429 std::string SectionName = ".mips16.fn." + Name;
430 std::string StubName = "__fn_stub_" + Name;
431 std::string LocalName = "$$__fn_local_" + Name;
432 Function *FStub = Function::Create
433 (F->getFunctionType(),
434 Function::InternalLinkage, StubName, M);
435 FStub->addFnAttr("mips16_fp_stub");
436 FStub->addFnAttr(llvm::Attribute::Naked);
437 FStub->addFnAttr(llvm::Attribute::NoUnwind);
438 FStub->addFnAttr(llvm::Attribute::NoInline);
439 FStub->addFnAttr("nomips16");
440 FStub->setSection(SectionName);
441 BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
442 InlineAsmHelper IAH(Context, BB);
443 IAH.Out(" .set macro");
445 IAH.Out(".set noreorder");
446 IAH.Out(".cpload $$25");
447 IAH.Out(".set reorder");
448 IAH.Out(".reloc 0,R_MIPS_NONE," + Name);
449 IAH.Out("la $$25," + LocalName);
452 IAH.Out(".set reorder");
453 IAH.Out("la $$25," + Name);
455 swapFPIntParams(PV, M, IAH, LE, false);
457 IAH.Out(LocalName + " = " + Name);
458 new UnreachableInst(FStub->getContext(), BB);
462 // remove the use-soft-float attribute
464 static void removeUseSoftFloat(Function &F) {
466 DEBUG(errs() << "removing -use-soft-float\n");
467 A = A.addAttribute(F.getContext(), AttributeSet::FunctionIndex,
468 "use-soft-float", "false");
469 F.removeAttributes(AttributeSet::FunctionIndex, A);
470 if (F.hasFnAttribute("use-soft-float")) {
471 DEBUG(errs() << "still has -use-soft-float\n");
473 F.addAttributes(AttributeSet::FunctionIndex, A);
479 // This pass only makes sense when the underlying chip has floating point but
480 // we are compiling as mips16.
481 // For all mips16 functions (that are not stubs we have already generated), or
482 // declared via attributes as nomips16, we must:
483 // 1) fixup all returns of float, double, single and double complex
484 // by calling a helper function before the actual return.
485 // 2) generate helper functions (stubs) that can be called by mips32 functions
486 // that will move parameters passed normally passed in floating point
487 // registers the soft float equivalents.
488 // 3) in the case of static relocation, generate helper functions so that
489 // mips16 functions can call extern functions of unknown type (mips16 or
491 // 4) TBD. For pic, calls to extern functions of unknown type are handled by
492 // predefined helper functions in libc but this work is currently done
493 // during call lowering but it should be moved here in the future.
495 bool Mips16HardFloat::runOnModule(Module &M) {
496 DEBUG(errs() << "Run on Module Mips16HardFloat\n");
497 bool Modified = false;
498 for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
499 if (F->hasFnAttribute("nomips16") &&
500 F->hasFnAttribute("use-soft-float")) {
501 removeUseSoftFloat(*F);
504 if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
505 F->hasFnAttribute("nomips16")) continue;
506 Modified |= fixupFPReturnAndCall(*F, &M, Subtarget);
507 FPParamVariant V = whichFPParamVariantNeeded(*F);
510 createFPFnStub(F, &M, V, Subtarget);
516 char Mips16HardFloat::ID = 0;
520 ModulePass *llvm::createMips16HardFloat(MipsTargetMachine &TM) {
521 return new Mips16HardFloat(TM);