summaryrefslogtreecommitdiff
path: root/lib/Transforms/Scalar/SimplifyHalfPowrLibCalls.cpp
blob: f8828842e0d426a40ad154298843f4556bb0289b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
//===- SimplifyHalfPowrLibCalls.cpp - Optimize specific half_powr calls ---===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple pass that applies an experimental
// transformation on calls to specific functions.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "simplify-libcalls-halfpowr"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Target/TargetData.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
using namespace llvm;

namespace {
  /// This pass optimizes well half_powr function calls.
  ///
  class SimplifyHalfPowrLibCalls : public FunctionPass {
    const TargetData *TD;
  public:
    static char ID; // Pass identification
    SimplifyHalfPowrLibCalls() : FunctionPass(&ID) {}

    bool runOnFunction(Function &F);

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    }

    Instruction *
    InlineHalfPowrs(const std::vector<Instruction *> &HalfPowrs,
                    Instruction *InsertPt);
  };
  char SimplifyHalfPowrLibCalls::ID = 0;
} // end anonymous namespace.

INITIALIZE_PASS(SimplifyHalfPowrLibCalls, "simplify-libcalls-halfpowr",
                "Simplify half_powr library calls", false, false);

// Public interface to the Simplify HalfPowr LibCalls pass.
FunctionPass *llvm::createSimplifyHalfPowrLibCallsPass() {
  return new SimplifyHalfPowrLibCalls(); 
}

/// InlineHalfPowrs - Inline a sequence of adjacent half_powr calls, rearranging
/// their control flow to better facilitate subsequent optimization.
Instruction *
SimplifyHalfPowrLibCalls::
InlineHalfPowrs(const std::vector<Instruction *> &HalfPowrs,
                Instruction *InsertPt) {
  std::vector<BasicBlock *> Bodies;
  BasicBlock *NewBlock = 0;

  for (unsigned i = 0, e = HalfPowrs.size(); i != e; ++i) {
    CallInst *Call = cast<CallInst>(HalfPowrs[i]);
    Function *Callee = Call->getCalledFunction();

    // Minimally sanity-check the CFG of half_powr to ensure that it contains
    // the kind of code we expect.  If we're running this pass, we have
    // reason to believe it will be what we expect.
    Function::iterator I = Callee->begin();
    BasicBlock *Prologue = I++;
    if (I == Callee->end()) break;
    BasicBlock *SubnormalHandling = I++;
    if (I == Callee->end()) break;
    BasicBlock *Body = I++;
    if (I != Callee->end()) break;
    if (SubnormalHandling->getSinglePredecessor() != Prologue)
      break;
    BranchInst *PBI = dyn_cast<BranchInst>(Prologue->getTerminator());
    if (!PBI || !PBI->isConditional())
      break;
    BranchInst *SNBI = dyn_cast<BranchInst>(SubnormalHandling->getTerminator());
    if (!SNBI || SNBI->isConditional())
      break;
    if (!isa<ReturnInst>(Body->getTerminator()))
      break;

    Instruction *NextInst = llvm::next(BasicBlock::iterator(Call));

    // Inline the call, taking care of what code ends up where.
    NewBlock = SplitBlock(NextInst->getParent(), NextInst, this);

    InlineFunctionInfo IFI(0, TD);
    bool B = InlineFunction(Call, IFI);
    assert(B && "half_powr didn't inline?"); B=B;

    BasicBlock *NewBody = NewBlock->getSinglePredecessor();
    assert(NewBody);
    Bodies.push_back(NewBody);
  }

  if (!NewBlock)
    return InsertPt;

  // Put the code for all the bodies into one block, to facilitate
  // subsequent optimization.
  (void)SplitEdge(NewBlock->getSinglePredecessor(), NewBlock, this);
  for (unsigned i = 0, e = Bodies.size(); i != e; ++i) {
    BasicBlock *Body = Bodies[i];
    Instruction *FNP = Body->getFirstNonPHI();
    // Splice the insts from body into NewBlock.
    NewBlock->getInstList().splice(NewBlock->begin(), Body->getInstList(),
                                   FNP, Body->getTerminator());
  }

  return NewBlock->begin();
}

/// runOnFunction - Top level algorithm.
///
bool SimplifyHalfPowrLibCalls::runOnFunction(Function &F) {
  TD = getAnalysisIfAvailable<TargetData>();
  
  bool Changed = false;
  std::vector<Instruction *> HalfPowrs;
  for (Function::iterator BB = F.begin(), E = F.end(); BB != E; ++BB) {
    for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I) {
      // Look for calls.
      bool IsHalfPowr = false;
      if (CallInst *CI = dyn_cast<CallInst>(I)) {
        // Look for direct calls and calls to non-external functions.
        Function *Callee = CI->getCalledFunction();
        if (Callee && Callee->hasExternalLinkage()) {
          // Look for calls with well-known names.
          if (Callee->getName() == "__half_powrf4")
            IsHalfPowr = true;
        }
      }
      if (IsHalfPowr)
        HalfPowrs.push_back(I);
      // We're looking for sequences of up to three such calls, which we'll
      // simplify as a group.
      if ((!IsHalfPowr && !HalfPowrs.empty()) || HalfPowrs.size() == 3) {
        I = InlineHalfPowrs(HalfPowrs, I);
        E = I->getParent()->end();
        HalfPowrs.clear();
        Changed = true;
      }
    }
    assert(HalfPowrs.empty() && "Block had no terminator!");
  }

  return Changed;
}