From 8332c68b452cfb1c62e6977db697a1b22aabad4a Mon Sep 17 00:00:00 2001 From: Akira Hatanaka Date: Tue, 11 Jun 2013 22:21:44 +0000 Subject: [PATCH] [mips] Add an IR transformation pass that optimizes calls to sqrt. The pass emits a call to sqrt that has attribute "read-none". This call will be converted to an ISD::FSQRT node during DAG construction, which will turn into a mips native sqrt instruction. llvm-svn: 183802 --- lib/Target/Mips/Mips.h | 2 +- lib/Target/Mips/MipsOptimizeMathLibCalls.cpp | 175 +++++++++++++++++++ lib/Target/Mips/MipsTargetMachine.cpp | 1 + test/CodeGen/Mips/optimize-fp-math.ll | 32 ++++ 4 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 lib/Target/Mips/MipsOptimizeMathLibCalls.cpp create mode 100644 test/CodeGen/Mips/optimize-fp-math.ll diff --git a/lib/Target/Mips/Mips.h b/lib/Target/Mips/Mips.h index 8c65bb4020b..b88c0d25471 100644 --- a/lib/Target/Mips/Mips.h +++ b/lib/Target/Mips/Mips.h @@ -28,7 +28,7 @@ namespace llvm { FunctionPass *createMipsJITCodeEmitterPass(MipsTargetMachine &TM, JITCodeEmitter &JCE); FunctionPass *createMipsConstantIslandPass(MipsTargetMachine &tm); - + FunctionPass *createMipsOptimizeMathLibCalls(MipsTargetMachine &TM); } // end namespace llvm; #endif diff --git a/lib/Target/Mips/MipsOptimizeMathLibCalls.cpp b/lib/Target/Mips/MipsOptimizeMathLibCalls.cpp new file mode 100644 index 00000000000..de3f09c3b54 --- /dev/null +++ b/lib/Target/Mips/MipsOptimizeMathLibCalls.cpp @@ -0,0 +1,175 @@ +//===---- MipsOptimizeMathLibCalls.cpp - Optimize math lib calls. ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass does an IR transformation which enables the backend to emit native +// math instructions. +// +//===----------------------------------------------------------------------===// + +#include "MipsTargetMachine.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Target/TargetLibraryInfo.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" + +using namespace llvm; + +static cl::opt DisableOpt("disable-mips-math-optimization", + cl::init(false), + cl::desc("MIPS: Disable math lib call " + "optimization."), cl::Hidden); + +namespace { + class MipsOptimizeMathLibCalls : public FunctionPass { + public: + static char ID; + + MipsOptimizeMathLibCalls(MipsTargetMachine &TM_) : + FunctionPass(ID), TM(TM_) {} + + virtual const char *getPassName() const { + return "MIPS: Optimize calls to math library functions."; + } + + virtual void getAnalysisUsage(AnalysisUsage &AU) const; + + virtual bool runOnFunction(Function &F); + + private: + /// Optimize calls to sqrt. + bool optimizeSQRT(CallInst *Call, Function *CalledFunc, + BasicBlock &CurrBB, + Function::iterator &BB); + + const TargetMachine &TM; + }; + + char MipsOptimizeMathLibCalls::ID = 0; +} + +FunctionPass *llvm::createMipsOptimizeMathLibCalls(MipsTargetMachine &TM) { + return new MipsOptimizeMathLibCalls(TM); +} + +void MipsOptimizeMathLibCalls::getAnalysisUsage(AnalysisUsage &AU) const { + AU.addRequired(); + FunctionPass::getAnalysisUsage(AU); +} + +bool MipsOptimizeMathLibCalls::runOnFunction(Function &F) { + if (DisableOpt) + return false; + + const MipsSubtarget &Subtarget = TM.getSubtarget(); + + if (Subtarget.inMips16Mode()) + return false; + + bool Changed = false; + Function::iterator CurrBB; + const TargetLibraryInfo *LibInfo = &getAnalysis(); + + for (Function::iterator BB = F.begin(), BE = F.end(); BB != BE;) { + CurrBB = BB++; + + for (BasicBlock::iterator II = CurrBB->begin(), IE = CurrBB->end(); + II != IE; ++II) { + CallInst *Call = dyn_cast(&*II); + Function *CalledFunc; + + if (!Call || !(CalledFunc = Call->getCalledFunction())) + continue; + + LibFunc::Func LibFunc; + Attribute A = CalledFunc->getAttributes() + .getAttribute(AttributeSet::FunctionIndex, "use-soft-float"); + + // Skip if function has "use-soft-float" attribute. + if ((A.isStringAttribute() && (A.getValueAsString() == "true")) || + TM.Options.UseSoftFloat) + continue; + + // Skip if function either has local linkage or is not a known library + // function. + if (CalledFunc->hasLocalLinkage() || !CalledFunc->hasName() || + !LibInfo->getLibFunc(CalledFunc->getName(), LibFunc)) + continue; + + switch (LibFunc) { + case LibFunc::sqrtf: + case LibFunc::sqrt: + if (optimizeSQRT(Call, CalledFunc, *CurrBB, BB)) + break; + continue; + default: + continue; + } + + Changed = true; + break; + } + } + + return Changed; +} + +bool MipsOptimizeMathLibCalls::optimizeSQRT(CallInst *Call, + Function *CalledFunc, + BasicBlock &CurrBB, + Function::iterator &BB) { + // There is no need to change the IR, since backend will emit sqrt + // instruction if the call has already been marked read-only. + if (Call->onlyReadsMemory()) + return false; + + // Do the following transformation: + // + // (before) + // dst = sqrt(src) + // + // (after) + // v0 = sqrt_noreadmem(src) # native sqrt instruction. + // if (v0 is a NaN) + // v1 = sqrt(src) # library call. + // dst = phi(v0, v1) + // + + // Move all instructions following Call to newly created block JoinBB. + // Create phi and replace all uses. + BasicBlock *JoinBB = llvm::SplitBlock(&CurrBB, Call->getNextNode(), this); + IRBuilder<> Builder(JoinBB, JoinBB->begin()); + PHINode *Phi = Builder.CreatePHI(Call->getType(), 2); + Call->replaceAllUsesWith(Phi); + + // Create basic block LibCallBB and insert a call to library function sqrt. + BasicBlock *LibCallBB = BasicBlock::Create(CurrBB.getContext(), "call.sqrt", + CurrBB.getParent(), JoinBB); + Builder.SetInsertPoint(LibCallBB); + Instruction *LibCall = Call->clone(); + Builder.Insert(LibCall); + Builder.CreateBr(JoinBB); + + // Add attribute "readnone" so that backend can use a native sqrt instruction + // for this call. Insert a FP compare instruction and a conditional branch + // at the end of CurrBB. + Call->addAttribute(AttributeSet::FunctionIndex, Attribute::ReadNone); + CurrBB.getTerminator()->eraseFromParent(); + Builder.SetInsertPoint(&CurrBB); + Value *FCmp = Builder.CreateFCmpOEQ(Call, Call); + Builder.CreateCondBr(FCmp, JoinBB, LibCallBB); + + // Add phi operands. + Phi->addIncoming(Call, &CurrBB); + Phi->addIncoming(LibCall, LibCallBB); + + BB = JoinBB; + return true; +} diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp index 89407351a07..9af2f1b201d 100644 --- a/lib/Target/Mips/MipsTargetMachine.cpp +++ b/lib/Target/Mips/MipsTargetMachine.cpp @@ -160,6 +160,7 @@ void MipsPassConfig::addIRPasses() { addPass(createMipsOs16(getMipsTargetMachine())); if (getMipsSubtarget().inMips16HardFloat()) addPass(createMips16HardFloat(getMipsTargetMachine())); + addPass(createMipsOptimizeMathLibCalls(getMipsTargetMachine())); } // Install an instruction selector pass using // the ISelDag to gen Mips code. diff --git a/test/CodeGen/Mips/optimize-fp-math.ll b/test/CodeGen/Mips/optimize-fp-math.ll new file mode 100644 index 00000000000..9348d3c8f12 --- /dev/null +++ b/test/CodeGen/Mips/optimize-fp-math.ll @@ -0,0 +1,32 @@ +; RUN: llc -march=mipsel < %s | FileCheck %s -check-prefix=32 +; RUN: llc -march=mips64el -mcpu=mips64 < %s | FileCheck %s -check-prefix=64 + +; 32: test_sqrtf_float_: +; 32: sqrt.s $f[[R0:[0-9]+]], $f{{[0-9]+}} +; 32: c.un.s $f[[R0]], $f[[R0]] +; 64: test_sqrtf_float_: +; 64: sqrt.s $f[[R0:[0-9]+]], $f{{[0-9]+}} +; 64: c.un.s $f[[R0]], $f[[R0]] + +define float @test_sqrtf_float_(float %a) { +entry: + %call = tail call float @sqrtf(float %a) + ret float %call +} + +declare float @sqrtf(float) + +; 32: test_sqrt_double_: +; 32: sqrt.d $f[[R0:[0-9]+]], $f{{[0-9]+}} +; 32: c.un.d $f[[R0]], $f[[R0]] +; 64: test_sqrt_double_: +; 64: sqrt.d $f[[R0:[0-9]+]], $f{{[0-9]+}} +; 64: c.un.d $f[[R0]], $f[[R0]] + +define double @test_sqrt_double_(double %a) { +entry: + %call = tail call double @sqrt(double %a) + ret double %call +} + +declare double @sqrt(double)