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 
20 using namespace llvm;
21 
22 #define DEBUG_TYPE "mips-os16"
23 
24 static cl::opt<std::string> Mips32FunctionMask(
25   "mips32-function-mask",
26   cl::init(""),
27   cl::desc("Force function to be mips32"),
28   cl::Hidden);
29 
30 namespace {
31   class MipsOs16 : public ModulePass {
32   public:
33     static char ID;
34 
MipsOs16()35     MipsOs16() : ModulePass(ID) {}
36 
getPassName() const37     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 //
needsFPFromSig(Function & F)49 static  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 //
needsFP(Function & F)73 static 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 
runOnModule(Module & M)109 bool 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 
createMipsOs16Pass()159 ModulePass *llvm::createMipsOs16Pass() { return new MipsOs16(); }
160