LLVM  4.0.0
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 #include "MipsTargetMachine.h"
15 #include "llvm/IR/Module.h"
16 #include "llvm/IR/Value.h"
17 #include "llvm/Support/Debug.h"
19 #include <algorithm>
20 #include <string>
21 
22 using namespace llvm;
23 
24 #define DEBUG_TYPE "mips16-hard-float"
25 
26 namespace {
27  class Mips16HardFloat : public ModulePass {
28  public:
29  static char ID;
30 
32 
33  StringRef getPassName() const override { return "MIPS16 Hard Float Pass"; }
34 
35  bool runOnModule(Module &M) override;
36 
37  protected:
38  const MipsTargetMachine &TM;
39  };
40 
41  static void EmitInlineAsm(LLVMContext &C, BasicBlock *BB, StringRef AsmText) {
42  std::vector<llvm::Type *> AsmArgTypes;
43  std::vector<llvm::Value *> AsmArgs;
44 
45  llvm::FunctionType *AsmFTy =
46  llvm::FunctionType::get(Type::getVoidTy(C), AsmArgTypes, false);
47  llvm::InlineAsm *IA =
48  llvm::InlineAsm::get(AsmFTy, AsmText, "", true,
49  /* IsAlignStack */ false, llvm::InlineAsm::AD_ATT);
50  CallInst::Create(IA, AsmArgs, "", BB);
51  }
52 
53  char Mips16HardFloat::ID = 0;
54 }
55 
56 //
57 // Return types that matter for hard float are:
58 // float, double, complex float, and complex double
59 //
62 };
63 
64 //
65 // Determine which FP return type this function has
66 //
68  switch (T->getTypeID()) {
69  case Type::FloatTyID:
70  return FRet;
71  case Type::DoubleTyID:
72  return DRet;
73  case Type::StructTyID:
74  if (T->getStructNumElements() != 2)
75  break;
76  if ((T->getContainedType(0)->isFloatTy()) &&
77  (T->getContainedType(1)->isFloatTy()))
78  return CFRet;
79  if ((T->getContainedType(0)->isDoubleTy()) &&
80  (T->getContainedType(1)->isDoubleTy()))
81  return CDRet;
82  break;
83  default:
84  break;
85  }
86  return NoFPRet;
87 }
88 
89 //
90 // Parameter type that matter are float, (float, float), (float, double),
91 // double, (double, double), (double, float)
92 //
96 };
97 
98 // which floating point parameter signature variant we are dealing with
99 //
103 
105  switch (F.arg_size()) {
106  case 0:
107  return NoSig;
108  case 1:{
109  TypeID ArgTypeID = F.getFunctionType()->getParamType(0)->getTypeID();
110  switch (ArgTypeID) {
111  case FloatTyID:
112  return FSig;
113  case DoubleTyID:
114  return DSig;
115  default:
116  return NoSig;
117  }
118  }
119  default: {
120  TypeID ArgTypeID0 = F.getFunctionType()->getParamType(0)->getTypeID();
121  TypeID ArgTypeID1 = F.getFunctionType()->getParamType(1)->getTypeID();
122  switch(ArgTypeID0) {
123  case FloatTyID: {
124  switch (ArgTypeID1) {
125  case FloatTyID:
126  return FFSig;
127  case DoubleTyID:
128  return FDSig;
129  default:
130  return FSig;
131  }
132  }
133  case DoubleTyID: {
134  switch (ArgTypeID1) {
135  case FloatTyID:
136  return DFSig;
137  case DoubleTyID:
138  return DDSig;
139  default:
140  return DSig;
141  }
142  }
143  default:
144  return NoSig;
145  }
146  }
147  }
148  llvm_unreachable("can't get here");
149 }
150 
151 // Figure out if we need float point based on the function parameters.
152 // We need to move variables in and/or out of floating point
153 // registers because of the ABI
154 //
156  if (F.arg_size() >=1) {
157  Type *ArgType = F.getFunctionType()->getParamType(0);
158  switch (ArgType->getTypeID()) {
159  case Type::FloatTyID:
160  case Type::DoubleTyID:
161  return true;
162  default:
163  break;
164  }
165  }
166  return false;
167 }
168 
170  Type* RetType = F.getReturnType();
171  return whichFPReturnVariant(RetType) != NoFPRet;
172 }
173 
175  Type* RetType = FT.getReturnType();
176  return whichFPReturnVariant(RetType) != NoFPRet;
177 }
178 
181 }
182 
183 //
184 // We swap between FP and Integer registers to allow Mips16 and Mips32 to
185 // interoperate
186 //
187 static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE,
188  bool ToFP) {
189  std::string MI = ToFP ? "mtc1 ": "mfc1 ";
190  std::string AsmText;
191 
192  switch (PV) {
193  case FSig:
194  AsmText += MI + "$$4, $$f12\n";
195  break;
196 
197  case FFSig:
198  AsmText += MI + "$$4, $$f12\n";
199  AsmText += MI + "$$5, $$f14\n";
200  break;
201 
202  case FDSig:
203  AsmText += MI + "$$4, $$f12\n";
204  if (LE) {
205  AsmText += MI + "$$6, $$f14\n";
206  AsmText += MI + "$$7, $$f15\n";
207  } else {
208  AsmText += MI + "$$7, $$f14\n";
209  AsmText += MI + "$$6, $$f15\n";
210  }
211  break;
212 
213  case DSig:
214  if (LE) {
215  AsmText += MI + "$$4, $$f12\n";
216  AsmText += MI + "$$5, $$f13\n";
217  } else {
218  AsmText += MI + "$$5, $$f12\n";
219  AsmText += MI + "$$4, $$f13\n";
220  }
221  break;
222 
223  case DDSig:
224  if (LE) {
225  AsmText += MI + "$$4, $$f12\n";
226  AsmText += MI + "$$5, $$f13\n";
227  AsmText += MI + "$$6, $$f14\n";
228  AsmText += MI + "$$7, $$f15\n";
229  } else {
230  AsmText += MI + "$$5, $$f12\n";
231  AsmText += MI + "$$4, $$f13\n";
232  AsmText += MI + "$$7, $$f14\n";
233  AsmText += MI + "$$6, $$f15\n";
234  }
235  break;
236 
237  case DFSig:
238  if (LE) {
239  AsmText += MI + "$$4, $$f12\n";
240  AsmText += MI + "$$5, $$f13\n";
241  } else {
242  AsmText += MI + "$$5, $$f12\n";
243  AsmText += MI + "$$4, $$f13\n";
244  }
245  AsmText += MI + "$$6, $$f14\n";
246  break;
247 
248  case NoSig:
249  break;
250  }
251 
252  return AsmText;
253 }
254 
255 //
256 // Make sure that we know we already need a stub for this function.
257 // Having called needsFPHelperFromSig
258 //
260  const MipsTargetMachine &TM) {
261  // for now we only need them for static relocation
262  if (TM.isPositionIndependent())
263  return;
265  bool LE = TM.isLittleEndian();
266  std::string Name = F.getName();
267  std::string SectionName = ".mips16.call.fp." + Name;
268  std::string StubName = "__call_stub_fp_" + Name;
269  //
270  // see if we already have the stub
271  //
272  Function *FStub = M->getFunction(StubName);
273  if (FStub && !FStub->isDeclaration()) return;
274  FStub = Function::Create(F.getFunctionType(),
275  Function::InternalLinkage, StubName, M);
276  FStub->addFnAttr("mips16_fp_stub");
277  FStub->addFnAttr(llvm::Attribute::Naked);
278  FStub->addFnAttr(llvm::Attribute::NoInline);
279  FStub->addFnAttr(llvm::Attribute::NoUnwind);
280  FStub->addFnAttr("nomips16");
281  FStub->setSection(SectionName);
282  BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
285 
286  std::string AsmText;
287  AsmText += ".set reorder\n";
288  AsmText += swapFPIntParams(PV, M, LE, true);
289  if (RV != NoFPRet) {
290  AsmText += "move $$18, $$31\n";
291  AsmText += "jal " + Name + "\n";
292  } else {
293  AsmText += "lui $$25, %hi(" + Name + ")\n";
294  AsmText += "addiu $$25, $$25, %lo(" + Name + ")\n";
295  }
296 
297  switch (RV) {
298  case FRet:
299  AsmText += "mfc1 $$2, $$f0\n";
300  break;
301 
302  case DRet:
303  if (LE) {
304  AsmText += "mfc1 $$2, $$f0\n";
305  AsmText += "mfc1 $$3, $$f1\n";
306  } else {
307  AsmText += "mfc1 $$3, $$f0\n";
308  AsmText += "mfc1 $$2, $$f1\n";
309  }
310  break;
311 
312  case CFRet:
313  if (LE) {
314  AsmText += "mfc1 $$2, $$f0\n";
315  AsmText += "mfc1 $$3, $$f2\n";
316  } else {
317  AsmText += "mfc1 $$3, $$f0\n";
318  AsmText += "mfc1 $$3, $$f2\n";
319  }
320  break;
321 
322  case CDRet:
323  if (LE) {
324  AsmText += "mfc1 $$4, $$f2\n";
325  AsmText += "mfc1 $$5, $$f3\n";
326  AsmText += "mfc1 $$2, $$f0\n";
327  AsmText += "mfc1 $$3, $$f1\n";
328 
329  } else {
330  AsmText += "mfc1 $$5, $$f2\n";
331  AsmText += "mfc1 $$4, $$f3\n";
332  AsmText += "mfc1 $$3, $$f0\n";
333  AsmText += "mfc1 $$2, $$f1\n";
334  }
335  break;
336 
337  case NoFPRet:
338  break;
339  }
340 
341  if (RV != NoFPRet)
342  AsmText += "jr $$18\n";
343  else
344  AsmText += "jr $$25\n";
345  EmitInlineAsm(Context, BB, AsmText);
346 
347  new UnreachableInst(Context, BB);
348 }
349 
350 //
351 // Functions that are llvm intrinsics and don't need helpers.
352 //
353 static const char *const IntrinsicInline[] = {
354  "fabs", "fabsf",
355  "llvm.ceil.f32", "llvm.ceil.f64",
356  "llvm.copysign.f32", "llvm.copysign.f64",
357  "llvm.cos.f32", "llvm.cos.f64",
358  "llvm.exp.f32", "llvm.exp.f64",
359  "llvm.exp2.f32", "llvm.exp2.f64",
360  "llvm.fabs.f32", "llvm.fabs.f64",
361  "llvm.floor.f32", "llvm.floor.f64",
362  "llvm.fma.f32", "llvm.fma.f64",
363  "llvm.log.f32", "llvm.log.f64",
364  "llvm.log10.f32", "llvm.log10.f64",
365  "llvm.nearbyint.f32", "llvm.nearbyint.f64",
366  "llvm.pow.f32", "llvm.pow.f64",
367  "llvm.powi.f32", "llvm.powi.f64",
368  "llvm.rint.f32", "llvm.rint.f64",
369  "llvm.round.f32", "llvm.round.f64",
370  "llvm.sin.f32", "llvm.sin.f64",
371  "llvm.sqrt.f32", "llvm.sqrt.f64",
372  "llvm.trunc.f32", "llvm.trunc.f64",
373 };
374 
375 static bool isIntrinsicInline(Function *F) {
376  return std::binary_search(std::begin(IntrinsicInline),
378 }
379 //
380 // Returns of float, double and complex need to be handled with a helper
381 // function.
382 //
384  const MipsTargetMachine &TM) {
385  bool Modified = false;
386  LLVMContext &C = M->getContext();
387  Type *MyVoid = Type::getVoidTy(C);
388  for (auto &BB: F)
389  for (auto &I: BB) {
390  if (const ReturnInst *RI = dyn_cast<ReturnInst>(&I)) {
391  Value *RVal = RI->getReturnValue();
392  if (!RVal) continue;
393  //
394  // If there is a return value and it needs a helper function,
395  // figure out which one and add a call before the actual
396  // return to this helper. The purpose of the helper is to move
397  // floating point values from their soft float return mapping to
398  // where they would have been mapped to in floating point registers.
399  //
400  Type *T = RVal->getType();
402  if (RV == NoFPRet) continue;
403  static const char *const Helper[NoFPRet] = {
404  "__mips16_ret_sf", "__mips16_ret_df", "__mips16_ret_sc",
405  "__mips16_ret_dc"
406  };
407  const char *Name = Helper[RV];
408  AttributeSet A;
409  Value *Params[] = {RVal};
410  Modified = true;
411  //
412  // These helper functions have a different calling ABI so
413  // this __Mips16RetHelper indicates that so that later
414  // during call setup, the proper call lowering to the helper
415  // functions will take place.
416  //
418  "__Mips16RetHelper");
420  Attribute::ReadNone);
422  Attribute::NoInline);
423  Value *F = (M->getOrInsertFunction(Name, A, MyVoid, T, nullptr));
424  CallInst::Create(F, Params, "", &I);
425  } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
426  FunctionType *FT = CI->getFunctionType();
427  Function *F_ = CI->getCalledFunction();
428  if (needsFPReturnHelper(*FT) &&
429  !(F_ && isIntrinsicInline(F_))) {
430  Modified=true;
431  F.addFnAttr("saveS2");
432  }
433  if (F_ && !isIntrinsicInline(F_)) {
434  // pic mode calls are handled by already defined
435  // helper functions
436  if (needsFPReturnHelper(*F_)) {
437  Modified=true;
438  F.addFnAttr("saveS2");
439  }
440  if (!TM.isPositionIndependent()) {
441  if (needsFPHelperFromSig(*F_)) {
442  assureFPCallStub(*F_, M, TM);
443  Modified=true;
444  }
445  }
446  }
447  }
448  }
449  return Modified;
450 }
451 
453  const MipsTargetMachine &TM) {
454  bool PicMode = TM.isPositionIndependent();
455  bool LE = TM.isLittleEndian();
457  std::string Name = F->getName();
458  std::string SectionName = ".mips16.fn." + Name;
459  std::string StubName = "__fn_stub_" + Name;
460  std::string LocalName = "$$__fn_local_" + Name;
461  Function *FStub = Function::Create
462  (F->getFunctionType(),
463  Function::InternalLinkage, StubName, M);
464  FStub->addFnAttr("mips16_fp_stub");
465  FStub->addFnAttr(llvm::Attribute::Naked);
466  FStub->addFnAttr(llvm::Attribute::NoUnwind);
467  FStub->addFnAttr(llvm::Attribute::NoInline);
468  FStub->addFnAttr("nomips16");
469  FStub->setSection(SectionName);
470  BasicBlock *BB = BasicBlock::Create(Context, "entry", FStub);
471 
472  std::string AsmText;
473  if (PicMode) {
474  AsmText += ".set noreorder\n";
475  AsmText += ".cpload $$25\n";
476  AsmText += ".set reorder\n";
477  AsmText += ".reloc 0, R_MIPS_NONE, " + Name + "\n";
478  AsmText += "la $$25, " + LocalName + "\n";
479  } else
480  AsmText += "la $$25, " + Name + "\n";
481  AsmText += swapFPIntParams(PV, M, LE, false);
482  AsmText += "jr $$25\n";
483  AsmText += LocalName + " = " + Name + "\n";
484  EmitInlineAsm(Context, BB, AsmText);
485 
486  new UnreachableInst(FStub->getContext(), BB);
487 }
488 
489 //
490 // remove the use-soft-float attribute
491 //
493  AttributeSet A;
494  DEBUG(errs() << "removing -use-soft-float\n");
496  "use-soft-float", "false");
498  if (F.hasFnAttribute("use-soft-float")) {
499  DEBUG(errs() << "still has -use-soft-float\n");
500  }
502 }
503 
504 
505 //
506 // This pass only makes sense when the underlying chip has floating point but
507 // we are compiling as mips16.
508 // For all mips16 functions (that are not stubs we have already generated), or
509 // declared via attributes as nomips16, we must:
510 // 1) fixup all returns of float, double, single and double complex
511 // by calling a helper function before the actual return.
512 // 2) generate helper functions (stubs) that can be called by mips32
513 // functions that will move parameters passed normally passed in
514 // floating point
515 // registers the soft float equivalents.
516 // 3) in the case of static relocation, generate helper functions so that
517 // mips16 functions can call extern functions of unknown type (mips16 or
518 // mips32).
519 // 4) TBD. For pic, calls to extern functions of unknown type are handled by
520 // predefined helper functions in libc but this work is currently done
521 // during call lowering but it should be moved here in the future.
522 //
523 bool Mips16HardFloat::runOnModule(Module &M) {
524  DEBUG(errs() << "Run on Module Mips16HardFloat\n");
525  bool Modified = false;
526  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
527  if (F->hasFnAttribute("nomips16") &&
528  F->hasFnAttribute("use-soft-float")) {
530  continue;
531  }
532  if (F->isDeclaration() || F->hasFnAttribute("mips16_fp_stub") ||
533  F->hasFnAttribute("nomips16")) continue;
534  Modified |= fixupFPReturnAndCall(*F, &M, TM);
536  if (V != NoSig) {
537  Modified = true;
538  createFPFnStub(&*F, &M, V, TM);
539  }
540  }
541  return Modified;
542 }
543 
544 
546  return new Mips16HardFloat(TM);
547 }
Return a value (possibly void), from a function.
const_iterator end(StringRef path)
Get end iterator over path.
Definition: Path.cpp:241
raw_ostream & errs()
This returns a reference to a raw_ostream for standard error.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
Definition: Function.cpp:226
LLVMContext & Context
static bool needsFPReturnHelper(Function &F)
unsigned getStructNumElements() const
Definition: DerivedTypes.h:305
A Module instance is used to store all the information related to an LLVM module. ...
Definition: Module.h:52
2: 32-bit floating point type
Definition: Type.h:58
static void removeUseSoftFloat(Function &F)
Type::TypeID TypeID
FPParamVariant
This class represents a function call, abstracting a target machine's calling convention.
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
Definition: Type.h:148
const_iterator begin(StringRef path)
Get begin iterator over path.
Definition: Path.cpp:233
Type * getReturnType() const
Returns the type of the ret val.
Definition: Function.cpp:238
13: Structures
Definition: Type.h:72
size_t arg_size() const
Definition: Function.cpp:327
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:191
void removeAttributes(unsigned i, AttributeSet Attrs)
removes the attributes from the list of attributes.
Definition: Function.cpp:394
static bool needsFPHelperFromSig(Function &F)
TypeID
Definitions of all of the base types for the Type system.
Definition: Type.h:54
void addAttributes(unsigned i, AttributeSet Attrs)
adds the attributes to the list of attributes.
Definition: Function.cpp:376
static bool needsFPStubFromParams(Function &F)
static FPReturnVariant whichFPReturnVariant(Type *T)
Class to represent function types.
Definition: DerivedTypes.h:102
#define F(x, y, z)
Definition: MD5.cpp:51
const Type::TypeID FloatTyID
FPReturnVariant
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Definition: Type.cpp:291
TypeID getTypeID() const
Return the type id for the type.
Definition: Type.h:136
static bool isIntrinsicInline(Function *F)
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
Function * getFunction(StringRef Name) const
Look up the specified function in the module symbol table.
Definition: Module.cpp:196
static void assureFPCallStub(Function &F, Module *M, const MipsTargetMachine &TM)
Type * getParamType(unsigned i) const
Parameter type accessors.
Definition: DerivedTypes.h:133
Constant * getOrInsertFunction(StringRef Name, FunctionType *T, AttributeSet AttributeList)
Look up the specified function in the module symbol table.
Definition: Module.cpp:123
LLVM Basic Block Representation.
Definition: BasicBlock.h:51
static bool fixupFPReturnAndCall(Function &F, Module *M, const MipsTargetMachine &TM)
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:45
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:48
AttributeSet addAttribute(LLVMContext &C, unsigned Index, Attribute::AttrKind Kind) const
Add an attribute to the attribute set at the given index.
Definition: Attributes.cpp:753
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
Definition: Type.h:316
This function has undefined behavior.
static void createFPFnStub(Function *F, Module *M, FPParamVariant PV, const MipsTargetMachine &TM)
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
Definition: Type.h:145
static Type * getVoidTy(LLVMContext &C)
Definition: Type.cpp:154
bool isPositionIndependent() const
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:93
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
ModulePass * createMips16HardFloatPass(MipsTargetMachine &TM)
Iterator for intrusive lists based on ilist_node.
static CallInst * Create(Value *Func, ArrayRef< Value * > Args, ArrayRef< OperandBundleDef > Bundles=None, const Twine &NameStr="", Instruction *InsertBefore=nullptr)
Module.h This file contains the declarations for the Module class.
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:230
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
static FPParamVariant whichFPParamVariantNeeded(Function &F)
iterator end()
Definition: Module.h:537
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
Definition: Function.h:226
static const char *const IntrinsicInline[]
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition: Globals.cpp:188
#define I(x, y, z)
Definition: MD5.cpp:54
FunctionType * getFunctionType() const
Returns the FunctionType for me.
Definition: Function.cpp:230
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:235
iterator begin()
Definition: Module.h:535
Rename collisions when linking (static functions).
Definition: GlobalValue.h:56
const char SectionName[]
Definition: AMDGPUPTNote.h:24
static InlineAsm * get(FunctionType *Ty, StringRef AsmString, StringRef Constraints, bool hasSideEffects, bool isAlignStack=false, AsmDialect asmDialect=AD_ATT)
InlineAsm::get - Return the specified uniqued inline asm string.
Definition: InlineAsm.cpp:27
3: 64-bit floating point type
Definition: Type.h:59
Type * getReturnType() const
Definition: DerivedTypes.h:123
const Type::TypeID DoubleTyID
LLVM Value Representation.
Definition: Value.h:71
#define DEBUG(X)
Definition: Debug.h:100
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
Definition: Function.h:182
static cl::opt< bool > Mips16HardFloat("mips16-hard-float", cl::NotHidden, cl::desc("Enable mips16 hard float."), cl::init(false))
IRTranslator LLVM IR MI
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:47
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, const Twine &N="", Module *M=nullptr)
Definition: Function.h:117
static GCRegistry::Add< ErlangGC > A("erlang","erlang-compatible garbage collector")
void setSection(StringRef S)
Change the section for this global.
Definition: Globals.cpp:173
static std::string swapFPIntParams(FPParamVariant PV, Module *M, bool LE, bool ToFP)
LLVMContext & getContext() const
Get the global data context.
Definition: Module.h:222