| //===-- MVETailPredUtils.h - Tail predication utility functions -*- C++-*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file contains utility functions for low overhead and tail predicated | |
| // loops, shared between the ARMLowOverheadLoops pass and anywhere else that | |
| // needs them. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H | |
| #define LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H | |
| #include "llvm/CodeGen/MachineInstr.h" | |
| #include "llvm/CodeGen/MachineInstrBuilder.h" | |
| #include "llvm/CodeGen/MachineOperand.h" | |
| #include "llvm/CodeGen/TargetInstrInfo.h" | |
| namespace llvm { | |
| static inline unsigned VCTPOpcodeToLSTP(unsigned Opcode, bool IsDoLoop) { | |
| switch (Opcode) { | |
| default: | |
| llvm_unreachable("unhandled vctp opcode"); | |
| break; | |
| case ARM::MVE_VCTP8: | |
| return IsDoLoop ? ARM::MVE_DLSTP_8 : ARM::MVE_WLSTP_8; | |
| case ARM::MVE_VCTP16: | |
| return IsDoLoop ? ARM::MVE_DLSTP_16 : ARM::MVE_WLSTP_16; | |
| case ARM::MVE_VCTP32: | |
| return IsDoLoop ? ARM::MVE_DLSTP_32 : ARM::MVE_WLSTP_32; | |
| case ARM::MVE_VCTP64: | |
| return IsDoLoop ? ARM::MVE_DLSTP_64 : ARM::MVE_WLSTP_64; | |
| } | |
| return 0; | |
| } | |
| static inline unsigned getTailPredVectorWidth(unsigned Opcode) { | |
| switch (Opcode) { | |
| default: | |
| llvm_unreachable("unhandled vctp opcode"); | |
| case ARM::MVE_VCTP8: | |
| return 16; | |
| case ARM::MVE_VCTP16: | |
| return 8; | |
| case ARM::MVE_VCTP32: | |
| return 4; | |
| case ARM::MVE_VCTP64: | |
| return 2; | |
| } | |
| return 0; | |
| } | |
| static inline bool isVCTP(const MachineInstr *MI) { | |
| switch (MI->getOpcode()) { | |
| default: | |
| break; | |
| case ARM::MVE_VCTP8: | |
| case ARM::MVE_VCTP16: | |
| case ARM::MVE_VCTP32: | |
| case ARM::MVE_VCTP64: | |
| return true; | |
| } | |
| return false; | |
| } | |
| static inline bool isDoLoopStart(const MachineInstr &MI) { | |
| return MI.getOpcode() == ARM::t2DoLoopStart || | |
| MI.getOpcode() == ARM::t2DoLoopStartTP; | |
| } | |
| static inline bool isWhileLoopStart(const MachineInstr &MI) { | |
| return MI.getOpcode() == ARM::t2WhileLoopStart || | |
| MI.getOpcode() == ARM::t2WhileLoopStartLR || | |
| MI.getOpcode() == ARM::t2WhileLoopStartTP; | |
| } | |
| static inline bool isLoopStart(const MachineInstr &MI) { | |
| return isDoLoopStart(MI) || isWhileLoopStart(MI); | |
| } | |
| // Return the TargetBB stored in a t2WhileLoopStartLR/t2WhileLoopStartTP. | |
| inline MachineBasicBlock *getWhileLoopStartTargetBB(const MachineInstr &MI) { | |
| assert(isWhileLoopStart(MI) && "Expected WhileLoopStart!"); | |
| unsigned Op = MI.getOpcode() == ARM::t2WhileLoopStartTP ? 3 : 2; | |
| return MI.getOperand(Op).getMBB(); | |
| } | |
| // WhileLoopStart holds the exit block, so produce a subs Op0, Op1, 0 and then a | |
| // beq that branches to the exit branch. | |
| // If UseCmp is true, this will create a t2CMP instead of a t2SUBri, meaning the | |
| // value of LR into the loop will not be setup. This is used if the LR setup is | |
| // done via another means (via a t2DoLoopStart, for example). | |
| inline void RevertWhileLoopStartLR(MachineInstr *MI, const TargetInstrInfo *TII, | |
| unsigned BrOpc = ARM::t2Bcc, | |
| bool UseCmp = false) { | |
| MachineBasicBlock *MBB = MI->getParent(); | |
| assert((MI->getOpcode() == ARM::t2WhileLoopStartLR || | |
| MI->getOpcode() == ARM::t2WhileLoopStartTP) && | |
| "Only expected a t2WhileLoopStartLR/TP in RevertWhileLoopStartLR!"); | |
| // Subs/Cmp | |
| if (UseCmp) { | |
| MachineInstrBuilder MIB = | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(ARM::t2CMPri)); | |
| MIB.add(MI->getOperand(1)); | |
| MIB.addImm(0); | |
| MIB.addImm(ARMCC::AL); | |
| MIB.addReg(ARM::NoRegister); | |
| } else { | |
| MachineInstrBuilder MIB = | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(ARM::t2SUBri)); | |
| MIB.add(MI->getOperand(0)); | |
| MIB.add(MI->getOperand(1)); | |
| MIB.addImm(0); | |
| MIB.addImm(ARMCC::AL); | |
| MIB.addReg(ARM::NoRegister); | |
| MIB.addReg(ARM::CPSR, RegState::Define); | |
| } | |
| // Branch | |
| MachineInstrBuilder MIB = | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(BrOpc)); | |
| MIB.addMBB(getWhileLoopStartTargetBB(*MI)); // branch target | |
| MIB.addImm(ARMCC::EQ); // condition code | |
| MIB.addReg(ARM::CPSR); | |
| MI->eraseFromParent(); | |
| } | |
| inline void RevertDoLoopStart(MachineInstr *MI, const TargetInstrInfo *TII) { | |
| MachineBasicBlock *MBB = MI->getParent(); | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(ARM::tMOVr)) | |
| .add(MI->getOperand(0)) | |
| .add(MI->getOperand(1)) | |
| .add(predOps(ARMCC::AL)); | |
| MI->eraseFromParent(); | |
| } | |
| inline void RevertLoopDec(MachineInstr *MI, const TargetInstrInfo *TII, | |
| bool SetFlags = false) { | |
| MachineBasicBlock *MBB = MI->getParent(); | |
| MachineInstrBuilder MIB = | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(ARM::t2SUBri)); | |
| MIB.add(MI->getOperand(0)); | |
| MIB.add(MI->getOperand(1)); | |
| MIB.add(MI->getOperand(2)); | |
| MIB.addImm(ARMCC::AL); | |
| MIB.addReg(0); | |
| if (SetFlags) { | |
| MIB.addReg(ARM::CPSR); | |
| MIB->getOperand(5).setIsDef(true); | |
| } else | |
| MIB.addReg(0); | |
| MI->eraseFromParent(); | |
| } | |
| // Generate a subs, or sub and cmp, and a branch instead of an LE. | |
| inline void RevertLoopEnd(MachineInstr *MI, const TargetInstrInfo *TII, | |
| unsigned BrOpc = ARM::t2Bcc, bool SkipCmp = false) { | |
| MachineBasicBlock *MBB = MI->getParent(); | |
| // Create cmp | |
| if (!SkipCmp) { | |
| MachineInstrBuilder MIB = | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(ARM::t2CMPri)); | |
| MIB.add(MI->getOperand(0)); | |
| MIB.addImm(0); | |
| MIB.addImm(ARMCC::AL); | |
| MIB.addReg(ARM::NoRegister); | |
| } | |
| // Create bne | |
| MachineInstrBuilder MIB = | |
| BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(BrOpc)); | |
| MIB.add(MI->getOperand(1)); // branch target | |
| MIB.addImm(ARMCC::NE); // condition code | |
| MIB.addReg(ARM::CPSR); | |
| MI->eraseFromParent(); | |
| } | |
| } // end namespace llvm | |
| #endif // LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H |