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