summaryrefslogtreecommitdiff
path: root/lib/Target/SparcV9/SparcV9PeepholeOpts.cpp
blob: 778ced253210ace25d723293b60014c9a2663092 (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
158
159
160
161
162
163
//===-- SparcV9PeepholeOpts.cpp -------------------------------------------===//
// 
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
// 
//===----------------------------------------------------------------------===//
// 
// Support for performing several peephole opts in one or a few passes over the
// machine code of a method.
//
//===----------------------------------------------------------------------===//

#include "SparcV9Internals.h"
#include "llvm/BasicBlock.h"
#include "llvm/Pass.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/STLExtras.h"

namespace llvm {

//************************* Internal Functions *****************************/

static inline void
DeleteInstruction(MachineBasicBlock& mvec,
                  MachineBasicBlock::iterator& BBI,
                  const TargetMachine& target) {
  // Check if this instruction is in a delay slot of its predecessor.
  if (BBI != mvec.begin()) {
      const TargetInstrInfo& mii = *target.getInstrInfo();
      MachineBasicBlock::iterator predMI = prior(BBI);
      if (unsigned ndelay = mii.getNumDelaySlots(predMI->getOpcode())) {
        // This instruction is in a delay slot of its predecessor, so
        // replace it with a nop. By replacing in place, we save having
        // to update the I-I maps.
        // 
        assert(ndelay == 1 && "Not yet handling multiple-delay-slot targets");
        BBI->replace(V9::NOP, 0);
        return;
      }
  }
  
  // The instruction is not in a delay slot, so we can simply erase it.
  mvec.erase(BBI);
  BBI = mvec.end();
}

//******************* Individual Peephole Optimizations ********************/

//----------------------------------------------------------------------------
// Function: IsUselessCopy
// Decide whether a machine instruction is a redundant copy:
// -- ADD    with g0 and result and operand are identical, or
// -- OR     with g0 and result and operand are identical, or
// -- FMOVS or FMOVD and result and operand are identical.
// Other cases are possible but very rare that they would be useless copies,
// so it's not worth analyzing them.
//----------------------------------------------------------------------------

static bool IsUselessCopy(const TargetMachine &target, const MachineInstr* MI) {
  if (MI->getOpcode() == V9::FMOVS || MI->getOpcode() == V9::FMOVD) {
    return (// both operands are allocated to the same register
            MI->getOperand(0).getReg() ==  MI->getOperand(1).getReg());
  } else if (MI->getOpcode() == V9::ADDr || MI->getOpcode() == V9::ORr ||
             MI->getOpcode() == V9::ADDi || MI->getOpcode() == V9::ORi) {
    unsigned srcWithDestReg;
    
    for (srcWithDestReg = 0; srcWithDestReg < 2; ++srcWithDestReg)
      if (MI->getOperand(srcWithDestReg).hasAllocatedReg() &&
          MI->getOperand(srcWithDestReg).getReg()
          == MI->getOperand(2).getReg())
        break;
    
    if (srcWithDestReg == 2)
      return false;
    else {
      // else source and dest are allocated to the same register
      unsigned otherOp = 1 - srcWithDestReg;
      return (// either operand otherOp is register %g0
              (MI->getOperand(otherOp).hasAllocatedReg() &&
               MI->getOperand(otherOp).getReg() ==
               target.getRegInfo()->getZeroRegNum()) ||
              
              // or operand otherOp == 0
              (MI->getOperand(otherOp).getType()
               == MachineOperand::MO_SignExtendedImmed &&
               MI->getOperand(otherOp).getImmedValue() == 0));
    }
  }
  else
    return false;
}

inline bool
RemoveUselessCopies(MachineBasicBlock& mvec,
                    MachineBasicBlock::iterator& BBI,
                    const TargetMachine& target) {
  if (IsUselessCopy(target, BBI)) {
    DeleteInstruction(mvec, BBI, target);
    return true;
  }
  return false;
}


//************************ Class Implementations **************************/

class PeepholeOpts: public BasicBlockPass {
  const TargetMachine &target;
  bool visit(MachineBasicBlock& mvec,
             MachineBasicBlock::iterator BBI) const;
public:
  PeepholeOpts(const TargetMachine &TM): target(TM) { }
  bool runOnBasicBlock(BasicBlock &BB); // apply this pass to each BB
  virtual const char *getPassName() const { return "Peephole Optimization"; }

  // getAnalysisUsage - this pass preserves the CFG
  void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.setPreservesCFG();
  }
};

// Apply a list of peephole optimizations to this machine instruction
// within its local context.  They are allowed to delete MI or any
// instruction before MI, but not 
//
bool PeepholeOpts::visit(MachineBasicBlock& mvec,
                         MachineBasicBlock::iterator BBI) const {
  // Remove redundant copy instructions
  return RemoveUselessCopies(mvec, BBI, target);
}


bool PeepholeOpts::runOnBasicBlock(BasicBlock &BB) {
  // Get the machine instructions for this BB
  // FIXME: MachineBasicBlock::get() is deprecated, hence inlining the function
  const Function *F = BB.getParent();
  MachineFunction &MF = MachineFunction::get(F);
  MachineBasicBlock *MBB = NULL;
  for (MachineFunction::iterator I = MF.begin(), E = MF.end(); I != E; ++I)
    if (I->getBasicBlock() == &BB)
      MBB = I;

  assert(MBB && "MachineBasicBlock object not found for specified block!");
  MachineBasicBlock &mvec = *MBB;

  for (MachineBasicBlock::iterator I = mvec.begin(), E = mvec.end(); I != E; )
    visit(mvec, I++);

  return true;
}

/// createPeepholeOptsPass - Public entry point for peephole optimization
///
FunctionPass* createPeepholeOptsPass(const TargetMachine &TM) {
  return new PeepholeOpts(TM);
}

} // End llvm namespace