1//===---- MipsOs16.cpp for Mips Option -Os16                       --------===//
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 an optimization phase for the MIPS target.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/IR/Instructions.h"
15#include "Mips.h"
16#include "llvm/IR/Module.h"
17#include "llvm/Support/CommandLine.h"
18#include "llvm/Support/Debug.h"
19#include "llvm/Support/raw_ostream.h"
20
21using namespace llvm;
22
23#define DEBUG_TYPE "mips-os16"
24
25static cl::opt<std::string> Mips32FunctionMask(
26  "mips32-function-mask",
27  cl::init(""),
28  cl::desc("Force function to be mips32"),
29  cl::Hidden);
30
31namespace {
32  class MipsOs16 : public ModulePass {
33  public:
34    static char ID;
35
36    MipsOs16() : ModulePass(ID) {}
37
38    const char *getPassName() const override {
39      return "MIPS Os16 Optimization";
40    }
41
42    bool runOnModule(Module &M) override;
43  };
44
45  char MipsOs16::ID = 0;
46}
47
48// Figure out if we need float point based on the function signature.
49// We need to move variables in and/or out of floating point
50// registers because of the ABI
51//
52static  bool needsFPFromSig(Function &F) {
53  Type* RetType = F.getReturnType();
54  switch (RetType->getTypeID()) {
55  case Type::FloatTyID:
56  case Type::DoubleTyID:
57    return true;
58  default:
59    ;
60  }
61  if (F.arg_size() >=1) {
62    Argument &Arg = F.getArgumentList().front();
63    switch (Arg.getType()->getTypeID()) {
64    case Type::FloatTyID:
65    case Type::DoubleTyID:
66      return true;
67    default:
68      ;
69    }
70  }
71  return false;
72}
73
74// Figure out if the function will need floating point operations
75//
76static bool needsFP(Function &F) {
77  if (needsFPFromSig(F))
78    return true;
79  for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
80    for (BasicBlock::const_iterator I = BB->begin(), E = BB->end();
81         I != E; ++I) {
82      const Instruction &Inst = *I;
83      switch (Inst.getOpcode()) {
84      case Instruction::FAdd:
85      case Instruction::FSub:
86      case Instruction::FMul:
87      case Instruction::FDiv:
88      case Instruction::FRem:
89      case Instruction::FPToUI:
90      case Instruction::FPToSI:
91      case Instruction::UIToFP:
92      case Instruction::SIToFP:
93      case Instruction::FPTrunc:
94      case Instruction::FPExt:
95      case Instruction::FCmp:
96        return true;
97      default:
98        ;
99      }
100      if (const CallInst *CI = dyn_cast<CallInst>(I)) {
101        DEBUG(dbgs() << "Working on call" << "\n");
102        Function &F_ =  *CI->getCalledFunction();
103        if (needsFPFromSig(F_))
104          return true;
105      }
106    }
107  return false;
108}
109
110
111bool MipsOs16::runOnModule(Module &M) {
112  bool usingMask = Mips32FunctionMask.length() > 0;
113  bool doneUsingMask = false; // this will make it stop repeating
114  DEBUG(dbgs() << "Run on Module MipsOs16 \n" << Mips32FunctionMask << "\n");
115  if (usingMask)
116    DEBUG(dbgs() << "using mask \n" << Mips32FunctionMask << "\n");
117  unsigned int functionIndex = 0;
118  bool modified = false;
119  for (Module::iterator F = M.begin(), E = M.end(); F != E; ++F) {
120    if (F->isDeclaration()) continue;
121    DEBUG(dbgs() << "Working on " << F->getName() << "\n");
122    if (usingMask) {
123      if (!doneUsingMask) {
124        if (functionIndex == Mips32FunctionMask.length())
125          functionIndex = 0;
126        switch (Mips32FunctionMask[functionIndex]) {
127        case '1':
128          DEBUG(dbgs() << "mask forced mips32: " << F->getName() << "\n");
129          F->addFnAttr("nomips16");
130          break;
131        case '.':
132          doneUsingMask = true;
133          break;
134        default:
135          break;
136        }
137        functionIndex++;
138      }
139    }
140    else {
141      if (needsFP(*F)) {
142        DEBUG(dbgs() << "os16 forced mips32: " << F->getName() << "\n");
143        F->addFnAttr("nomips16");
144      }
145      else {
146        DEBUG(dbgs() << "os16 forced mips16: " << F->getName() << "\n");
147        F->addFnAttr("mips16");
148      }
149    }
150  }
151  return modified;
152}
153
154ModulePass *llvm::createMipsOs16Pass(MipsTargetMachine &TM) {
155  return new MipsOs16;
156}
157