1//===-- MVEVPTBlockPass.cpp - Insert MVE VPT blocks -----------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ARM.h"
10#include "ARMMachineFunctionInfo.h"
11#include "ARMSubtarget.h"
12#include "MCTargetDesc/ARMBaseInfo.h"
13#include "Thumb2InstrInfo.h"
14#include "llvm/ADT/SmallSet.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/Statistic.h"
17#include "llvm/ADT/StringRef.h"
18#include "llvm/CodeGen/MachineBasicBlock.h"
19#include "llvm/CodeGen/MachineFunction.h"
20#include "llvm/CodeGen/MachineFunctionPass.h"
21#include "llvm/CodeGen/MachineInstr.h"
22#include "llvm/CodeGen/MachineInstrBuilder.h"
23#include "llvm/CodeGen/MachineInstrBundle.h"
24#include "llvm/CodeGen/MachineOperand.h"
25#include "llvm/CodeGen/ReachingDefAnalysis.h"
26#include "llvm/IR/DebugLoc.h"
27#include "llvm/MC/MCInstrDesc.h"
28#include "llvm/Support/Debug.h"
29#include <cassert>
30#include <new>
31
32using namespace llvm;
33
34#define DEBUG_TYPE "arm-mve-vpt"
35
36namespace {
37  class MVEVPTBlock : public MachineFunctionPass {
38  public:
39    static char ID;
40
41    MVEVPTBlock() : MachineFunctionPass(ID) {}
42
43    bool runOnMachineFunction(MachineFunction &Fn) override;
44
45    void getAnalysisUsage(AnalysisUsage &AU) const override {
46      AU.setPreservesCFG();
47      AU.addRequired<ReachingDefAnalysis>();
48      MachineFunctionPass::getAnalysisUsage(AU);
49    }
50
51    MachineFunctionProperties getRequiredProperties() const override {
52      return MachineFunctionProperties().set(
53          MachineFunctionProperties::Property::NoVRegs).set(
54          MachineFunctionProperties::Property::TracksLiveness);
55    }
56
57    StringRef getPassName() const override {
58      return "MVE VPT block insertion pass";
59    }
60
61  private:
62    bool InsertVPTBlocks(MachineBasicBlock &MBB);
63
64    const Thumb2InstrInfo *TII = nullptr;
65    ReachingDefAnalysis *RDA = nullptr;
66  };
67
68  char MVEVPTBlock::ID = 0;
69
70} // end anonymous namespace
71
72INITIALIZE_PASS(MVEVPTBlock, DEBUG_TYPE, "ARM MVE VPT block pass", false, false)
73
74static MachineInstr *findVCMPToFoldIntoVPST(MachineInstr *MI,
75                                            ReachingDefAnalysis *RDA,
76                                            unsigned &NewOpcode) {
77  // First, search backwards to the instruction that defines VPR
78  auto *Def = RDA->getReachingMIDef(MI, ARM::VPR);
79  if (!Def)
80    return nullptr;
81
82  // Now check that Def is a VCMP
83  if (!(NewOpcode = VCMPOpcodeToVPT(Def->getOpcode())))
84    return nullptr;
85
86  // Check that Def's operands are not defined between the VCMP and MI, i.e.
87  // check that they have the same reaching def.
88  if (!RDA->hasSameReachingDef(Def, MI, Def->getOperand(1).getReg()) ||
89      !RDA->hasSameReachingDef(Def, MI, Def->getOperand(2).getReg()))
90    return nullptr;
91
92  return Def;
93}
94
95bool MVEVPTBlock::InsertVPTBlocks(MachineBasicBlock &Block) {
96  bool Modified = false;
97  MachineBasicBlock::instr_iterator MBIter = Block.instr_begin();
98  MachineBasicBlock::instr_iterator EndIter = Block.instr_end();
99  SmallSet<MachineInstr *, 4> RemovedVCMPs;
100
101  while (MBIter != EndIter) {
102    MachineInstr *MI = &*MBIter;
103    unsigned PredReg = 0;
104    DebugLoc dl = MI->getDebugLoc();
105
106    ARMVCC::VPTCodes Pred = getVPTInstrPredicate(*MI, PredReg);
107
108    // The idea of the predicate is that None, Then and Else are for use when
109    // handling assembly language: they correspond to the three possible
110    // suffixes "", "t" and "e" on the mnemonic. So when instructions are read
111    // from assembly source or disassembled from object code, you expect to see
112    // a mixture whenever there's a long VPT block. But in code generation, we
113    // hope we'll never generate an Else as input to this pass.
114    assert(Pred != ARMVCC::Else && "VPT block pass does not expect Else preds");
115
116    if (Pred == ARMVCC::None) {
117      ++MBIter;
118      continue;
119    }
120
121    LLVM_DEBUG(dbgs() << "VPT block created for: "; MI->dump());
122    int VPTInstCnt = 1;
123    ARMVCC::VPTCodes NextPred;
124
125    // Look at subsequent instructions, checking if they can be in the same VPT
126    // block.
127    ++MBIter;
128    while (MBIter != EndIter && VPTInstCnt < 4) {
129      NextPred = getVPTInstrPredicate(*MBIter, PredReg);
130      assert(NextPred != ARMVCC::Else &&
131             "VPT block pass does not expect Else preds");
132      if (NextPred != Pred)
133        break;
134      LLVM_DEBUG(dbgs() << "  adding : "; MBIter->dump());
135      ++VPTInstCnt;
136      ++MBIter;
137    };
138
139    unsigned BlockMask = getARMVPTBlockMask(VPTInstCnt);
140
141    // Search back for a VCMP that can be folded to create a VPT, or else create
142    // a VPST directly
143    MachineInstrBuilder MIBuilder;
144    unsigned NewOpcode;
145    MachineInstr *VCMP = findVCMPToFoldIntoVPST(MI, RDA, NewOpcode);
146    if (VCMP) {
147      LLVM_DEBUG(dbgs() << "  folding VCMP into VPST: "; VCMP->dump());
148      MIBuilder = BuildMI(Block, MI, dl, TII->get(NewOpcode));
149      MIBuilder.addImm(BlockMask);
150      MIBuilder.add(VCMP->getOperand(1));
151      MIBuilder.add(VCMP->getOperand(2));
152      MIBuilder.add(VCMP->getOperand(3));
153      // We delay removing the actual VCMP instruction by saving it to a list
154      // and deleting all instructions in this list in one go after we have
155      // created the VPT blocks. We do this in order not to invalidate the
156      // ReachingDefAnalysis that is queried by 'findVCMPToFoldIntoVPST'.
157      RemovedVCMPs.insert(VCMP);
158    } else {
159      MIBuilder = BuildMI(Block, MI, dl, TII->get(ARM::MVE_VPST));
160      MIBuilder.addImm(BlockMask);
161    }
162
163    finalizeBundle(
164        Block, MachineBasicBlock::instr_iterator(MIBuilder.getInstr()), MBIter);
165
166    Modified = true;
167  }
168
169  for (auto *I : RemovedVCMPs)
170    I->eraseFromParent();
171
172  return Modified;
173}
174
175bool MVEVPTBlock::runOnMachineFunction(MachineFunction &Fn) {
176  if (skipFunction(Fn.getFunction()))
177    return false;
178
179  const ARMSubtarget &STI =
180      static_cast<const ARMSubtarget &>(Fn.getSubtarget());
181
182  if (!STI.isThumb2() || !STI.hasMVEIntegerOps())
183    return false;
184
185  TII = static_cast<const Thumb2InstrInfo *>(STI.getInstrInfo());
186  RDA = &getAnalysis<ReachingDefAnalysis>();
187
188  LLVM_DEBUG(dbgs() << "********** ARM MVE VPT BLOCKS **********\n"
189                    << "********** Function: " << Fn.getName() << '\n');
190
191  bool Modified = false;
192  for (MachineBasicBlock &MBB : Fn)
193    Modified |= InsertVPTBlocks(MBB);
194
195  LLVM_DEBUG(dbgs() << "**************************************\n");
196  return Modified;
197}
198
199/// createMVEVPTBlock - Returns an instance of the MVE VPT block
200/// insertion pass.
201FunctionPass *llvm::createMVEVPTBlockPass() { return new MVEVPTBlock(); }
202