1//===-- AlphaLLRP.cpp - Alpha Load Load Replay Trap elimination pass. -- --===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Here we check for potential replay traps introduced by the spiller
11// We also align some branch targets if we can do so for free.
12//
13//===----------------------------------------------------------------------===//
14
15#define DEBUG_TYPE "alpha-nops"
16#include "Alpha.h"
17#include "llvm/CodeGen/MachineFunctionPass.h"
18#include "llvm/CodeGen/MachineInstrBuilder.h"
19#include "llvm/Target/TargetMachine.h"
20#include "llvm/Target/TargetInstrInfo.h"
21#include "llvm/ADT/SetOperations.h"
22#include "llvm/ADT/Statistic.h"
23#include "llvm/Support/CommandLine.h"
24using namespace llvm;
25
26STATISTIC(nopintro, "Number of nops inserted");
27STATISTIC(nopalign, "Number of nops inserted for alignment");
28
29namespace {
30  cl::opt<bool>
31  AlignAll("alpha-align-all", cl::Hidden,
32                   cl::desc("Align all blocks"));
33
34  struct AlphaLLRPPass : public MachineFunctionPass {
35    /// Target machine description which we query for reg. names, data
36    /// layout, etc.
37    ///
38    AlphaTargetMachine &TM;
39
40    static char ID;
41    AlphaLLRPPass(AlphaTargetMachine &tm)
42      : MachineFunctionPass(ID), TM(tm) { }
43
44    virtual const char *getPassName() const {
45      return "Alpha NOP inserter";
46    }
47
48    bool runOnMachineFunction(MachineFunction &F) {
49      const TargetInstrInfo *TII = F.getTarget().getInstrInfo();
50      bool Changed = false;
51      MachineInstr* prev[3] = {0,0,0};
52      DebugLoc dl;
53      unsigned count = 0;
54      for (MachineFunction::iterator FI = F.begin(), FE = F.end();
55           FI != FE; ++FI) {
56        MachineBasicBlock& MBB = *FI;
57        bool ub = false;
58        for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
59          if (count%4 == 0)
60            prev[0] = prev[1] = prev[2] = 0; //Slots cleared at fetch boundary
61          ++count;
62          MachineInstr *MI = I++;
63          switch (MI->getOpcode()) {
64          case Alpha::LDQ:  case Alpha::LDL:
65          case Alpha::LDWU: case Alpha::LDBU:
66          case Alpha::LDT: case Alpha::LDS:
67          case Alpha::STQ:  case Alpha::STL:
68          case Alpha::STW:  case Alpha::STB:
69          case Alpha::STT: case Alpha::STS:
70           if (MI->getOperand(2).getReg() == Alpha::R30) {
71             if (prev[0] &&
72                 prev[0]->getOperand(2).getReg() == MI->getOperand(2).getReg()&&
73                 prev[0]->getOperand(1).getImm() == MI->getOperand(1).getImm()){
74               prev[0] = prev[1];
75               prev[1] = prev[2];
76               prev[2] = 0;
77               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
78                 .addReg(Alpha::R31)
79                 .addReg(Alpha::R31);
80               Changed = true; nopintro += 1;
81               count += 1;
82             } else if (prev[1]
83                        && prev[1]->getOperand(2).getReg() ==
84                        MI->getOperand(2).getReg()
85                        && prev[1]->getOperand(1).getImm() ==
86                        MI->getOperand(1).getImm()) {
87               prev[0] = prev[2];
88               prev[1] = prev[2] = 0;
89               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
90                 .addReg(Alpha::R31)
91                 .addReg(Alpha::R31);
92               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
93                 .addReg(Alpha::R31)
94                 .addReg(Alpha::R31);
95               Changed = true; nopintro += 2;
96               count += 2;
97             } else if (prev[2]
98                        && prev[2]->getOperand(2).getReg() ==
99                        MI->getOperand(2).getReg()
100                        && prev[2]->getOperand(1).getImm() ==
101                        MI->getOperand(1).getImm()) {
102               prev[0] = prev[1] = prev[2] = 0;
103               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
104                 .addReg(Alpha::R31).addReg(Alpha::R31);
105               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
106                 .addReg(Alpha::R31).addReg(Alpha::R31);
107               BuildMI(MBB, MI, dl, TII->get(Alpha::BISr), Alpha::R31)
108                 .addReg(Alpha::R31).addReg(Alpha::R31);
109               Changed = true; nopintro += 3;
110               count += 3;
111             }
112             prev[0] = prev[1];
113             prev[1] = prev[2];
114             prev[2] = MI;
115             break;
116           }
117           prev[0] = prev[1];
118           prev[1] = prev[2];
119           prev[2] = 0;
120           break;
121          case Alpha::ALTENT:
122          case Alpha::MEMLABEL:
123          case Alpha::PCLABEL:
124            --count;
125            break;
126          case Alpha::BR:
127          case Alpha::JMP:
128            ub = true;
129            //fall through
130          default:
131            prev[0] = prev[1];
132            prev[1] = prev[2];
133            prev[2] = 0;
134            break;
135          }
136        }
137        if (ub || AlignAll) {
138          //we can align stuff for free at this point
139          while (count % 4) {
140            BuildMI(MBB, MBB.end(), dl, TII->get(Alpha::BISr), Alpha::R31)
141              .addReg(Alpha::R31).addReg(Alpha::R31);
142            ++count;
143            ++nopalign;
144            prev[0] = prev[1];
145            prev[1] = prev[2];
146            prev[2] = 0;
147          }
148        }
149      }
150      return Changed;
151    }
152  };
153  char AlphaLLRPPass::ID = 0;
154} // end of anonymous namespace
155
156FunctionPass *llvm::createAlphaLLRPPass(AlphaTargetMachine &tm) {
157  return new AlphaLLRPPass(tm);
158}
159