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*7330f729Sjoergstatic 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*7330f729Sjoergstatic 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*7330f729Sjoergbool 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*7330f729SjoergModulePass *llvm::createMipsOs16Pass() { return new MipsOs16(); } 160