LLVM API Documentation

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Mips16HardFloat.cpp
Go to the documentation of this file.
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"
19 #include <algorithm>
20 #include <string>
21 
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),
28  AsmArgTypes, false);
29  llvm::InlineAsm *IA =
30  llvm::InlineAsm::get(AsmFTy, AsmString, "", true,
31  /* IsAlignStack */ false,
33  CallInst::Create(IA, AsmArgs, "", BB);
34 }
35 
36 namespace {
37 
38 class InlineAsmHelper {
39  LLVMContext &C;
40  BasicBlock *BB;
41 public:
42  InlineAsmHelper(LLVMContext &C_, BasicBlock *BB_) :
43  C(C_), BB(BB_) {
44  }
45 
46  void Out(StringRef AsmString) {
47  inlineAsmOut(C, AsmString, BB);
48  }
49 
50 };
51 }
52 //
53 // Return types that matter for hard float are:
54 // float, double, complex float, and complex double
55 //
58 };
59 
60 //
61 // Determine which FP return type this function has
62 //
64  switch (T->getTypeID()) {
65  case Type::FloatTyID:
66  return FRet;
67  case Type::DoubleTyID:
68  return DRet;
69  case Type::StructTyID:
70  if (T->getStructNumElements() != 2)
71  break;
72  if ((T->getContainedType(0)->isFloatTy()) &&
73  (T->getContainedType(1)->isFloatTy()))
74  return CFRet;
75  if ((T->getContainedType(0)->isDoubleTy()) &&
76  (T->getContainedType(1)->isDoubleTy()))
77  return CDRet;
78  break;
79  default:
80  break;
81  }
82  return NoFPRet;
83 }
84 
85 //
86 // Parameter type that matter are float, (float, float), (float, double),
87 // double, (double, double), (double, float)
88 //
92 };
93 
94 // which floating point parameter signature variant we are dealing with
95 //
99 
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 //
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 
166  Type* RetType = F.getReturnType();
167  return whichFPReturnVariant(RetType) != NoFPRet;
168 }
169 
172 }
173 
174 //
175 // We swap between FP and Integer registers to allow Mips16 and Mips32 to
176 // interoperate
177 //
178 
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 ";
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 //
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_)
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");
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");
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 llvm intrinsics and don't need helpers.
326 //
327 static const char *IntrinsicInline[] =
328  {"fabs",
329  "fabsf",
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",
348  };
349 
350 static bool isIntrinsicInline(Function *F) {
351  return std::binary_search(
352  IntrinsicInline, array_endof(IntrinsicInline),
353  F->getName());
354 }
355 //
356 // Returns of float, double and complex need to be handled with a helper
357 // function.
358 //
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();
366  I != E; ++I) {
367  Instruction &Inst = *I;
368  if (const ReturnInst *RI = dyn_cast<ReturnInst>(I)) {
369  Value *RVal = RI->getReturnValue();
370  if (!RVal) continue;
371  //
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.
377  //
378  Type *T = RVal->getType();
380  if (RV == NoFPRet) continue;
381  static const char* Helper[NoFPRet] =
382  {"__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
383  "__mips16_ret_dc"};
384  const char *Name = Helper[RV];
385  AttributeSet A;
386  Value *Params[] = {RVal};
387  Modified = true;
388  //
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.
393  //
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  // pic mode calls are handled by already defined
404  // helper functions
405  if (Subtarget.getRelocationModel() != Reloc::PIC_ ) {
406  Function *F_ = CI->getCalledFunction();
407  if (F_ && !isIntrinsicInline(F_) && needsFPHelperFromSig(*F_)) {
408  assureFPCallStub(*F_, M, Subtarget);
409  Modified=true;
410  }
411  }
412  }
413  }
414  return Modified;
415 }
416 
418  const MipsSubtarget &Subtarget ) {
419  bool PicMode = Subtarget.getRelocationModel() == Reloc::PIC_;
420  bool LE = Subtarget.isLittle();
421  LLVMContext &Context = M->getContext();
422  std::string Name = F->getName();
423  std::string SectionName = ".mips16.fn." + Name;
424  std::string StubName = "__fn_stub_" + Name;
425  std::string LocalName = "$$__fn_local_" + Name;
426  Function *FStub = Function::Create
427  (F->getFunctionType(),
428  Function::InternalLinkage, StubName, M);
429  FStub->addFnAttr("mips16_fp_stub");
433  FStub->addFnAttr("nomips16");
434  FStub->setSection(SectionName);
435  BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
436  InlineAsmHelper IAH(Context, BB);
437  IAH.Out(" .set macro");
438  if (PicMode) {
439  IAH.Out(".set noreorder");
440  IAH.Out(".cpload $$25");
441  IAH.Out(".set reorder");
442  IAH.Out(".reloc 0,R_MIPS_NONE," + Name);
443  IAH.Out("la $$25," + LocalName);
444  }
445  else {
446  IAH.Out(".set reorder");
447  IAH.Out("la $$25," + Name);
448  }
449  swapFPIntParams(PV, M, IAH, LE, false);
450  IAH.Out("jr $$25");
451  IAH.Out(LocalName + " = " + Name);
452  new UnreachableInst(FStub->getContext(), BB);
453 }
454 
455 //
456 // remove the use-soft-float attribute
457 //
458 static void removeUseSoftFloat(Function &F) {
459  AttributeSet A;
460  DEBUG(errs() << "removing -use-soft-float\n");
461  A = A.addAttribute(F.getContext(), AttributeSet::FunctionIndex,
462  "use-soft-float", "false");
463  F.removeAttributes(AttributeSet::FunctionIndex, A);
464  if (F.hasFnAttribute("use-soft-float")) {
465  DEBUG(errs() << "still has -use-soft-float\n");
466  }
467  F.addAttributes(AttributeSet::FunctionIndex, A);
468 }
469 
470 namespace llvm {
471 
472 //
473 // This pass only makes sense when the underlying chip has floating point but
474 // we are compiling as mips16.
475 // For all mips16 functions (that are not stubs we have already generated), or
476 // declared via attributes as nomips16, we must:
477 // 1) fixup all returns of float, double, single and double complex
478 // by calling a helper function before the actual return.
479 // 2) generate helper functions (stubs) that can be called by mips32 functions
480 // that will move parameters passed normally passed in floating point
481 // registers the soft float equivalents.
482 // 3) in the case of static relocation, generate helper functions so that
483 // mips16 functions can call extern functions of unknown type (mips16 or
484 // mips32).
485 // 4) TBD. For pic, calls to extern functions of unknown type are handled by
486 // predefined helper functions in libc but this work is currently done
487 // during call lowering but it should be moved here in the future.
488 //
490  DEBUG(errs() << "Run on Module Mips16HardFloat\n");
491  bool Modified = false;
492  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
493  if (F->hasFnAttribute("nomips16") &&
494  F->hasFnAttribute("use-soft-float")) {
495  removeUseSoftFloat(*F);
496  continue;
497  }
498  if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
499  F->hasFnAttribute("nomips16")) continue;
500  Modified |= fixupFPReturnAndCall(*F, &M, Subtarget);
502  if (V != NoSig) {
503  Modified = true;
504  createFPFnStub(F, &M, V, Subtarget);
505  }
506  }
507  return Modified;
508 }
509 
510 char Mips16HardFloat::ID = 0;
511 
512 }
513 
515  return new Mips16HardFloat(TM);
516 }
517 
T * array_endof(T(&x)[N])
Definition: STLExtras.h:244
static void swapFPIntParams(FPParamVariant PV, Module *M, InlineAsmHelper &IAH, bool LE, bool ToFP)
raw_ostream & errs()
LLVMContext & getContext() const
Definition: Function.cpp:167
unsigned getStructNumElements() const
Definition: Type.cpp:198
static bool needsFPReturnHelper(Function &F)
The main container class for the LLVM Intermediate Representation.
Definition: Module.h:112
iterator end()
Definition: Function.h:397
static void removeUseSoftFloat(Function &F)
Type::TypeID TypeID
FPParamVariant
Reloc::Model getRelocationModel() const
bool isDoubleTy() const
isDoubleTy - Return true if this is 'double', a 64-bit IEEE fp type.
Definition: Type.h:149
Type * getReturnType() const
Definition: Function.cpp:179
void setSection(StringRef S)
Definition: GlobalValue.h:97
F(f)
Naked function.
Definition: Attributes.h:78
size_t arg_size() const
Definition: Function.cpp:248
StringRef getName() const
Definition: Value.cpp:167
iterator begin()
Definition: BasicBlock.h:193
ModulePass * createMips16HardFloat(MipsTargetMachine &TM)
#define llvm_unreachable(msg)
static bool needsFPHelperFromSig(Function &F)
TypeID
Definition: Type.h:53
void addFnAttr(Attribute::AttrKind N)
Add function attributes to this function.
Definition: Function.h:176
static bool needsFPStubFromParams(Function &F)
static FPReturnVariant whichFPReturnVariant(Type *T)
static const char * IntrinsicInline[]
const Type::TypeID FloatTyID
FPReturnVariant
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
Definition: Type.cpp:361
TypeID getTypeID() const
Definition: Type.h:137
void removeAttributes(unsigned i, AttributeSet attr)
removes the attributes from the list of attributes.
Definition: Function.cpp:296
iterator begin()
Definition: Function.h:395
static bool isIntrinsicInline(Function *F)
Function * getFunction(StringRef Name) const
Definition: Module.cpp:221
Type * getParamType(unsigned i) const
Parameter type accessors.
Definition: DerivedTypes.h:128
static cl::opt< bool > Mips16HardFloat("mips16-hard-float", cl::NotHidden, cl::desc("MIPS: mips16 hard float enable."), cl::init(false))
Constant * getOrInsertFunction(StringRef Name, FunctionType *T, AttributeSet AttributeList)
Definition: Module.cpp:138
LLVM Basic Block Representation.
Definition: BasicBlock.h:72
Type * getContainedType(unsigned i) const
Definition: Type.h:339
static void inlineAsmOut(LLVMContext &C, StringRef AsmString, BasicBlock *BB)
bool isFloatTy() const
isFloatTy - Return true if this is 'float', a 32-bit IEEE fp type.
Definition: Type.h:146
static bool fixupFPReturnAndCall(Function &F, Module *M, const MipsSubtarget &Subtarget)
Function doesn't unwind stack.
Definition: Attributes.h:90
iterator end()
Definition: BasicBlock.h:195
Type * getType() const
Definition: Value.h:111
bool isLittle() const
virtual bool runOnModule(Module &M)
static FPParamVariant whichFPParamVariantNeeded(Function &F)
AttributeSet addAttribute(LLVMContext &C, unsigned Index, Attribute::AttrKind Attr) const
Add an attribute to the attribute set at the given index. Since attribute sets are immutable...
Definition: Attributes.cpp:664
iterator end()
Definition: Module.h:533
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition: Function.h:200
bool isDeclaration() const
Definition: Globals.cpp:66
#define I(x, y, z)
Definition: MD5.cpp:54
FunctionType * getFunctionType() const
Definition: Function.cpp:171
iterator begin()
Definition: Module.h:531
static InlineAsm * get(FunctionType *Ty, StringRef AsmString, StringRef Constraints, bool hasSideEffects, bool isAlignStack=false, AsmDialect asmDialect=AD_ATT)
Definition: InlineAsm.cpp:28
const Type::TypeID DoubleTyID
LLVM Value Representation.
Definition: Value.h:66
static void createFPFnStub(Function *F, Module *M, FPParamVariant PV, const MipsSubtarget &Subtarget)
#define DEBUG(X)
Definition: Debug.h:97
void addAttributes(unsigned i, AttributeSet attrs)
adds the attributes to the list of attributes.
Definition: Function.cpp:290
static void assureFPCallStub(Function &F, Module *M, const MipsSubtarget &Subtarget)
LLVMContext & getContext() const
Definition: Module.h:249