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