xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Mips/MipsOs16.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===---- MipsOs16.cpp for Mips Option -Os16                       --------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines an optimization phase for the MIPS target.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "Mips.h"
140b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
150b57cec5SDimitry Andric #include "llvm/IR/Module.h"
16*81ad6265SDimitry Andric #include "llvm/Pass.h"
170b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
180b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
190b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric using namespace llvm;
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #define DEBUG_TYPE "mips-os16"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric static cl::opt<std::string> Mips32FunctionMask(
260b57cec5SDimitry Andric   "mips32-function-mask",
270b57cec5SDimitry Andric   cl::init(""),
280b57cec5SDimitry Andric   cl::desc("Force function to be mips32"),
290b57cec5SDimitry Andric   cl::Hidden);
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric namespace {
320b57cec5SDimitry Andric   class MipsOs16 : public ModulePass {
330b57cec5SDimitry Andric   public:
340b57cec5SDimitry Andric     static char ID;
350b57cec5SDimitry Andric 
MipsOs16()360b57cec5SDimitry Andric     MipsOs16() : ModulePass(ID) {}
370b57cec5SDimitry Andric 
getPassName() const380b57cec5SDimitry Andric     StringRef getPassName() const override { return "MIPS Os16 Optimization"; }
390b57cec5SDimitry Andric 
400b57cec5SDimitry Andric     bool runOnModule(Module &M) override;
410b57cec5SDimitry Andric   };
420b57cec5SDimitry Andric 
430b57cec5SDimitry Andric   char MipsOs16::ID = 0;
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric // Figure out if we need float point based on the function signature.
470b57cec5SDimitry Andric // We need to move variables in and/or out of floating point
480b57cec5SDimitry Andric // registers because of the ABI
490b57cec5SDimitry Andric //
needsFPFromSig(Function & F)500b57cec5SDimitry Andric static  bool needsFPFromSig(Function &F) {
510b57cec5SDimitry Andric   Type* RetType = F.getReturnType();
520b57cec5SDimitry Andric   switch (RetType->getTypeID()) {
530b57cec5SDimitry Andric   case Type::FloatTyID:
540b57cec5SDimitry Andric   case Type::DoubleTyID:
550b57cec5SDimitry Andric     return true;
560b57cec5SDimitry Andric   default:
570b57cec5SDimitry Andric     ;
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric   if (F.arg_size() >=1) {
600b57cec5SDimitry Andric     Argument &Arg = *F.arg_begin();
610b57cec5SDimitry Andric     switch (Arg.getType()->getTypeID()) {
620b57cec5SDimitry Andric     case Type::FloatTyID:
630b57cec5SDimitry Andric     case Type::DoubleTyID:
640b57cec5SDimitry Andric       return true;
650b57cec5SDimitry Andric     default:
660b57cec5SDimitry Andric       ;
670b57cec5SDimitry Andric     }
680b57cec5SDimitry Andric   }
690b57cec5SDimitry Andric   return false;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric // Figure out if the function will need floating point operations
730b57cec5SDimitry Andric //
needsFP(Function & F)740b57cec5SDimitry Andric static bool needsFP(Function &F) {
750b57cec5SDimitry Andric   if (needsFPFromSig(F))
760b57cec5SDimitry Andric     return true;
770b57cec5SDimitry Andric   for (Function::const_iterator BB = F.begin(), E = F.end(); BB != E; ++BB)
780b57cec5SDimitry Andric     for (BasicBlock::const_iterator I = BB->begin(), E = BB->end();
790b57cec5SDimitry Andric          I != E; ++I) {
800b57cec5SDimitry Andric       const Instruction &Inst = *I;
810b57cec5SDimitry Andric       switch (Inst.getOpcode()) {
820b57cec5SDimitry Andric       case Instruction::FAdd:
830b57cec5SDimitry Andric       case Instruction::FSub:
840b57cec5SDimitry Andric       case Instruction::FMul:
850b57cec5SDimitry Andric       case Instruction::FDiv:
860b57cec5SDimitry Andric       case Instruction::FRem:
870b57cec5SDimitry Andric       case Instruction::FPToUI:
880b57cec5SDimitry Andric       case Instruction::FPToSI:
890b57cec5SDimitry Andric       case Instruction::UIToFP:
900b57cec5SDimitry Andric       case Instruction::SIToFP:
910b57cec5SDimitry Andric       case Instruction::FPTrunc:
920b57cec5SDimitry Andric       case Instruction::FPExt:
930b57cec5SDimitry Andric       case Instruction::FCmp:
940b57cec5SDimitry Andric         return true;
950b57cec5SDimitry Andric       default:
960b57cec5SDimitry Andric         ;
970b57cec5SDimitry Andric       }
980b57cec5SDimitry Andric       if (const CallInst *CI = dyn_cast<CallInst>(I)) {
990b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "Working on call"
1000b57cec5SDimitry Andric                           << "\n");
1010b57cec5SDimitry Andric         Function &F_ =  *CI->getCalledFunction();
1020b57cec5SDimitry Andric         if (needsFPFromSig(F_))
1030b57cec5SDimitry Andric           return true;
1040b57cec5SDimitry Andric       }
1050b57cec5SDimitry Andric     }
1060b57cec5SDimitry Andric   return false;
1070b57cec5SDimitry Andric }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric 
runOnModule(Module & M)1100b57cec5SDimitry Andric bool MipsOs16::runOnModule(Module &M) {
1110b57cec5SDimitry Andric   bool usingMask = Mips32FunctionMask.length() > 0;
1120b57cec5SDimitry Andric   bool doneUsingMask = false; // this will make it stop repeating
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Run on Module MipsOs16 \n"
1150b57cec5SDimitry Andric                     << Mips32FunctionMask << "\n");
1160b57cec5SDimitry Andric   if (usingMask)
1170b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "using mask \n" << Mips32FunctionMask << "\n");
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   unsigned int functionIndex = 0;
1200b57cec5SDimitry Andric   bool modified = false;
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   for (auto &F : M) {
1230b57cec5SDimitry Andric     if (F.isDeclaration())
1240b57cec5SDimitry Andric       continue;
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Working on " << F.getName() << "\n");
1270b57cec5SDimitry Andric     if (usingMask) {
1280b57cec5SDimitry Andric       if (!doneUsingMask) {
1290b57cec5SDimitry Andric         if (functionIndex == Mips32FunctionMask.length())
1300b57cec5SDimitry Andric           functionIndex = 0;
1310b57cec5SDimitry Andric         switch (Mips32FunctionMask[functionIndex]) {
1320b57cec5SDimitry Andric         case '1':
1330b57cec5SDimitry Andric           LLVM_DEBUG(dbgs() << "mask forced mips32: " << F.getName() << "\n");
1340b57cec5SDimitry Andric           F.addFnAttr("nomips16");
1350b57cec5SDimitry Andric           break;
1360b57cec5SDimitry Andric         case '.':
1370b57cec5SDimitry Andric           doneUsingMask = true;
1380b57cec5SDimitry Andric           break;
1390b57cec5SDimitry Andric         default:
1400b57cec5SDimitry Andric           break;
1410b57cec5SDimitry Andric         }
1420b57cec5SDimitry Andric         functionIndex++;
1430b57cec5SDimitry Andric       }
1440b57cec5SDimitry Andric     }
1450b57cec5SDimitry Andric     else {
1460b57cec5SDimitry Andric       if (needsFP(F)) {
1470b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "os16 forced mips32: " << F.getName() << "\n");
1480b57cec5SDimitry Andric         F.addFnAttr("nomips16");
1490b57cec5SDimitry Andric       }
1500b57cec5SDimitry Andric       else {
1510b57cec5SDimitry Andric         LLVM_DEBUG(dbgs() << "os16 forced mips16: " << F.getName() << "\n");
1520b57cec5SDimitry Andric         F.addFnAttr("mips16");
1530b57cec5SDimitry Andric       }
1540b57cec5SDimitry Andric     }
1550b57cec5SDimitry Andric   }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   return modified;
1580b57cec5SDimitry Andric }
1590b57cec5SDimitry Andric 
createMipsOs16Pass()1600b57cec5SDimitry Andric ModulePass *llvm::createMipsOs16Pass() { return new MipsOs16(); }
161