| //===-- 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 |