aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/Alpha/AlphaLLRP.cpp
blob: 0c51bc554be949e8d2893577a3a1acf436115f11 (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
//===-- AlphaLLRP.cpp - Alpha Load Load Replay Trap elimination pass. -- --===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Here we check for potential replay traps introduced by the spiller
// We also align some branch targets if we can do so for free.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "alpha-nops"
#include "Alpha.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/CommandLine.h"
using namespace llvm;

STATISTIC(nopintro, "Number of nops inserted");
STATISTIC(nopalign, "Number of nops inserted for alignment");

namespace {
  cl::opt<bool>
  AlignAll("alpha-align-all", cl::Hidden,
                   cl::desc("Align all blocks"));

  struct AlphaLLRPPass : public MachineFunctionPass {
    /// Target machine description which we query for reg. names, data
    /// layout, etc.
    ///
    AlphaTargetMachine &TM;

    static char ID;
    AlphaLLRPPass(AlphaTargetMachine &tm) 
      : MachineFunctionPass(&ID), TM(tm) { }

    virtual const char *getPassName() const {
      return "Alpha NOP inserter";
    }

    bool runOnMachineFunction(MachineFunction &F) {
      const TargetInstrInfo *TII = F.getTarget().getInstrInfo();
      bool Changed = false;
      MachineInstr* prev[3] = {0,0,0};
      DebugLoc dl = DebugLoc::getUnknownLoc();
      unsigned count = 0;
      for (MachineFunction::iterator FI = F.begin(), FE = F.end();
           FI != FE; ++FI) {
        MachineBasicBlock& MBB = *FI;
        bool ub = false;
        for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
          if (count%4 == 0)
            prev[0] = prev[1] = prev[2] = 0; //Slots cleared at fetch boundary
          ++count;
          MachineInstr *MI = I++;
          switch (MI->getOpcode()) {
          case Alpha::LDQ:  case Alpha::LDL:
          case Alpha::LDWU: case Alpha::LDBU:
          case Alpha::LDT: case Alpha::LDS:
          case Alpha::STQ:  case Alpha::STL:
          case Alpha::STW:  case Alpha::STB:
          case Alpha::STT: case Alpha::STS:
           if (MI->getOperand(2).getReg() == Alpha::R30) {
             if (prev[0] && 
                 prev[0]->getOperand(2).getReg() == MI->getOperand(2).getReg()&&
                 prev[0]->getOperand(1).getImm() == MI->getOperand(1).getImm()){
               prev[0] = prev[1];
               prev[1] = prev[2];
               prev[2] = 0;
               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
                 .addReg(Alpha::R31)
                 .addReg(Alpha::R31); 
               Changed = true; nopintro += 1;
               count += 1;
             } else if (prev[1] 
                        && prev[1]->getOperand(2).getReg() == 
                        MI->getOperand(2).getReg()
                        && prev[1]->getOperand(1).getImm() == 
                        MI->getOperand(1).getImm()) {
               prev[0] = prev[2];
               prev[1] = prev[2] = 0;
               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
                 .addReg(Alpha::R31)
                 .addReg(Alpha::R31); 
               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
                 .addReg(Alpha::R31)
                 .addReg(Alpha::R31);
               Changed = true; nopintro += 2;
               count += 2;
             } else if (prev[2] 
                        && prev[2]->getOperand(2).getReg() == 
                        MI->getOperand(2).getReg()
                        && prev[2]->getOperand(1).getImm() == 
                        MI->getOperand(1).getImm()) {
               prev[0] = prev[1] = prev[2] = 0;
               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
                 .addReg(Alpha::R31).addReg(Alpha::R31);
               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
                 .addReg(Alpha::R31).addReg(Alpha::R31);
               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
                 .addReg(Alpha::R31).addReg(Alpha::R31);
               Changed = true; nopintro += 3;
               count += 3;
             }
             prev[0] = prev[1];
             prev[1] = prev[2];
             prev[2] = MI;
             break;
           }
           prev[0] = prev[1];
           prev[1] = prev[2];
           prev[2] = 0;
           break;
          case Alpha::ALTENT:
          case Alpha::MEMLABEL:
          case Alpha::PCLABEL:
            --count;
            break;
          case Alpha::BR:
          case Alpha::JMP:
            ub = true;
            //fall through
          default:
            prev[0] = prev[1];
            prev[1] = prev[2];
            prev[2] = 0;
            break;
          }
        }
        if (ub || AlignAll) {
          //we can align stuff for free at this point
          while (count % 4) {
            BuildMI(MBB, MBB.end(), dl, TII->get(Alpha::BISr), Alpha::R31)
              .addReg(Alpha::R31).addReg(Alpha::R31);
            ++count;
            ++nopalign;
            prev[0] = prev[1];
            prev[1] = prev[2];
            prev[2] = 0;
          }
        }
      }
      return Changed;
    }
  };
  char AlphaLLRPPass::ID = 0;
} // end of anonymous namespace

FunctionPass *llvm::createAlphaLLRPPass(AlphaTargetMachine &tm) {
  return new AlphaLLRPPass(tm);
}