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 Andricstatic 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 Andricstatic 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 Andricbool 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 AndricModulePass *llvm::createMipsOs16Pass() { return new MipsOs16(); } 161