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