10b57cec5SDimitry Andric //===-- ARMOptimizeBarriersPass - two DMBs without a memory access in between,
20b57cec5SDimitry Andric //removed one -===//
30b57cec5SDimitry Andric //
40b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
50b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
60b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
70b57cec5SDimitry Andric //
80b57cec5SDimitry Andric //===------------------------------------------------------------------------------------------===//
90b57cec5SDimitry Andric
100b57cec5SDimitry Andric #include "ARM.h"
110b57cec5SDimitry Andric #include "ARMInstrInfo.h"
120b57cec5SDimitry Andric #include "ARMMachineFunctionInfo.h"
130b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
140b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
150b57cec5SDimitry Andric using namespace llvm;
160b57cec5SDimitry Andric
170b57cec5SDimitry Andric #define DEBUG_TYPE "double barriers"
180b57cec5SDimitry Andric
190b57cec5SDimitry Andric STATISTIC(NumDMBsRemoved, "Number of DMBs removed");
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric namespace {
220b57cec5SDimitry Andric class ARMOptimizeBarriersPass : public MachineFunctionPass {
230b57cec5SDimitry Andric public:
240b57cec5SDimitry Andric static char ID;
ARMOptimizeBarriersPass()250b57cec5SDimitry Andric ARMOptimizeBarriersPass() : MachineFunctionPass(ID) {}
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &Fn) override;
280b57cec5SDimitry Andric
getRequiredProperties() const290b57cec5SDimitry Andric MachineFunctionProperties getRequiredProperties() const override {
300b57cec5SDimitry Andric return MachineFunctionProperties().set(
310b57cec5SDimitry Andric MachineFunctionProperties::Property::NoVRegs);
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric
getPassName() const340b57cec5SDimitry Andric StringRef getPassName() const override { return "optimise barriers pass"; }
350b57cec5SDimitry Andric };
360b57cec5SDimitry Andric char ARMOptimizeBarriersPass::ID = 0;
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric // Returns whether the instruction can safely move past a DMB instruction
400b57cec5SDimitry Andric // The current implementation allows this iif MI does not have any possible
410b57cec5SDimitry Andric // memory access
CanMovePastDMB(const MachineInstr * MI)420b57cec5SDimitry Andric static bool CanMovePastDMB(const MachineInstr *MI) {
430b57cec5SDimitry Andric return !(MI->mayLoad() ||
440b57cec5SDimitry Andric MI->mayStore() ||
450b57cec5SDimitry Andric MI->hasUnmodeledSideEffects() ||
460b57cec5SDimitry Andric MI->isCall() ||
470b57cec5SDimitry Andric MI->isReturn());
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric
runOnMachineFunction(MachineFunction & MF)500b57cec5SDimitry Andric bool ARMOptimizeBarriersPass::runOnMachineFunction(MachineFunction &MF) {
510b57cec5SDimitry Andric if (skipFunction(MF.getFunction()))
520b57cec5SDimitry Andric return false;
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric // Vector to store the DMBs we will remove after the first iteration
550b57cec5SDimitry Andric std::vector<MachineInstr *> ToRemove;
560b57cec5SDimitry Andric // DMBType is the Imm value of the first operand. It determines whether it's a
570b57cec5SDimitry Andric // DMB ish, dmb sy, dmb osh, etc
580b57cec5SDimitry Andric int64_t DMBType = -1;
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric // Find a dmb. If we can move it until the next dmb, tag the second one for
610b57cec5SDimitry Andric // removal
620b57cec5SDimitry Andric for (auto &MBB : MF) {
630b57cec5SDimitry Andric // Will be true when we have seen a DMB, and not seen any instruction since
640b57cec5SDimitry Andric // that cannot move past a DMB
650b57cec5SDimitry Andric bool IsRemovableNextDMB = false;
660b57cec5SDimitry Andric for (auto &MI : MBB) {
670b57cec5SDimitry Andric if (MI.getOpcode() == ARM::DMB) {
680b57cec5SDimitry Andric if (IsRemovableNextDMB) {
690b57cec5SDimitry Andric // If the Imm of this DMB is the same as that of the last DMB, we can
700b57cec5SDimitry Andric // tag this second DMB for removal
710b57cec5SDimitry Andric if (MI.getOperand(0).getImm() == DMBType) {
720b57cec5SDimitry Andric ToRemove.push_back(&MI);
730b57cec5SDimitry Andric } else {
740b57cec5SDimitry Andric // If it has a different DMBType, we cannot remove it, but will scan
750b57cec5SDimitry Andric // for the next DMB, recording this DMB's type as last seen DMB type
760b57cec5SDimitry Andric DMBType = MI.getOperand(0).getImm();
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric } else {
790b57cec5SDimitry Andric // After we see a DMB, a next one is removable
800b57cec5SDimitry Andric IsRemovableNextDMB = true;
810b57cec5SDimitry Andric DMBType = MI.getOperand(0).getImm();
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric } else if (!CanMovePastDMB(&MI)) {
840b57cec5SDimitry Andric // If we find an instruction unable to pass past a DMB, a next DMB is
850b57cec5SDimitry Andric // not removable
860b57cec5SDimitry Andric IsRemovableNextDMB = false;
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric }
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric bool Changed = false;
910b57cec5SDimitry Andric // Remove the tagged DMB
92*bdd1243dSDimitry Andric for (auto *MI : ToRemove) {
930b57cec5SDimitry Andric MI->eraseFromParent();
940b57cec5SDimitry Andric ++NumDMBsRemoved;
950b57cec5SDimitry Andric Changed = true;
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric
980b57cec5SDimitry Andric return Changed;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric /// createARMOptimizeBarriersPass - Returns an instance of the remove double
1020b57cec5SDimitry Andric /// barriers
1030b57cec5SDimitry Andric /// pass.
createARMOptimizeBarriersPass()1040b57cec5SDimitry Andric FunctionPass *llvm::createARMOptimizeBarriersPass() {
1050b57cec5SDimitry Andric return new ARMOptimizeBarriersPass();
1060b57cec5SDimitry Andric }
107