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