1//===-- ARMOptimizeBarriersPass - two DMBs without a memory access in between,
2//removed one -===//
3//
4//                     The LLVM Compiler Infrastructure
5//
6// This file is distributed under the University of Illinois Open Source
7// License. See LICENSE.TXT for details.
8//
9//===------------------------------------------------------------------------------------------===//
10
11#include "ARM.h"
12#include "ARMMachineFunctionInfo.h"
13#include "ARMInstrInfo.h"
14#include "llvm/ADT/Statistic.h"
15#include "llvm/CodeGen/MachineFunctionPass.h"
16using namespace llvm;
17
18#define DEBUG_TYPE "double barriers"
19
20STATISTIC(NumDMBsRemoved, "Number of DMBs removed");
21
22namespace {
23class ARMOptimizeBarriersPass : public MachineFunctionPass {
24public:
25  static char ID;
26  ARMOptimizeBarriersPass() : MachineFunctionPass(ID) {}
27
28  bool runOnMachineFunction(MachineFunction &Fn) override;
29
30  const char *getPassName() const override {
31    return "optimise barriers pass";
32  }
33
34private:
35};
36char ARMOptimizeBarriersPass::ID = 0;
37}
38
39// Returns whether the instruction can safely move past a DMB instruction
40// The current implementation allows this iif MI does not have any possible
41// memory access
42static bool CanMovePastDMB(const MachineInstr *MI) {
43  return !(MI->mayLoad() ||
44          MI->mayStore() ||
45          MI->hasUnmodeledSideEffects() ||
46          MI->isCall() ||
47          MI->isReturn());
48}
49
50bool ARMOptimizeBarriersPass::runOnMachineFunction(MachineFunction &MF) {
51  // Vector to store the DMBs we will remove after the first iteration
52  std::vector<MachineInstr *> ToRemove;
53  // DMBType is the Imm value of the first operand. It determines whether it's a
54  // DMB ish, dmb sy, dmb osh, etc
55  int64_t DMBType = -1;
56
57  // Find a dmb. If we can move it until the next dmb, tag the second one for
58  // removal
59  for (auto &MBB : MF) {
60    // Will be true when we have seen a DMB, and not seen any instruction since
61    // that cannot move past a DMB
62    bool IsRemovableNextDMB = false;
63    for (auto &MI : MBB) {
64      if (MI.getOpcode() == ARM::DMB) {
65        if (IsRemovableNextDMB) {
66          // If the Imm of this DMB is the same as that of the last DMB, we can
67          // tag this second DMB for removal
68          if (MI.getOperand(0).getImm() == DMBType) {
69            ToRemove.push_back(&MI);
70          } else {
71            // If it has a different DMBType, we cannot remove it, but will scan
72            // for the next DMB, recording this DMB's type as last seen DMB type
73            DMBType = MI.getOperand(0).getImm();
74          }
75        } else {
76          // After we see a DMB, a next one is removable
77          IsRemovableNextDMB = true;
78          DMBType = MI.getOperand(0).getImm();
79        }
80      } else if (!CanMovePastDMB(&MI)) {
81        // If we find an instruction unable to pass past a DMB, a next DMB is
82        // not removable
83        IsRemovableNextDMB = false;
84      }
85    }
86  }
87  // Remove the tagged DMB
88  for (auto MI : ToRemove) {
89    MI->eraseFromParent();
90    ++NumDMBsRemoved;
91  }
92
93  return NumDMBsRemoved > 0;
94}
95
96/// createARMOptimizeBarriersPass - Returns an instance of the remove double
97/// barriers
98/// pass.
99FunctionPass *llvm::createARMOptimizeBarriersPass() {
100  return new ARMOptimizeBarriersPass();
101}
102