1*e8d8bef9SDimitry Andric //===-- MVETailPredUtils.h - Tail predication utility functions -*- C++-*-===// 2*e8d8bef9SDimitry Andric // 3*e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*e8d8bef9SDimitry Andric // 7*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8*e8d8bef9SDimitry Andric // 9*e8d8bef9SDimitry Andric // This file contains utility functions for low overhead and tail predicated 10*e8d8bef9SDimitry Andric // loops, shared between the ARMLowOverheadLoops pass and anywhere else that 11*e8d8bef9SDimitry Andric // needs them. 12*e8d8bef9SDimitry Andric // 13*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 14*e8d8bef9SDimitry Andric 15*e8d8bef9SDimitry Andric #ifndef LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H 16*e8d8bef9SDimitry Andric #define LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H 17*e8d8bef9SDimitry Andric 18*e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 19*e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 20*e8d8bef9SDimitry Andric #include "llvm/CodeGen/MachineOperand.h" 21*e8d8bef9SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 22*e8d8bef9SDimitry Andric 23*e8d8bef9SDimitry Andric namespace llvm { 24*e8d8bef9SDimitry Andric 25*e8d8bef9SDimitry Andric static inline unsigned VCTPOpcodeToLSTP(unsigned Opcode, bool IsDoLoop) { 26*e8d8bef9SDimitry Andric switch (Opcode) { 27*e8d8bef9SDimitry Andric default: 28*e8d8bef9SDimitry Andric llvm_unreachable("unhandled vctp opcode"); 29*e8d8bef9SDimitry Andric break; 30*e8d8bef9SDimitry Andric case ARM::MVE_VCTP8: 31*e8d8bef9SDimitry Andric return IsDoLoop ? ARM::MVE_DLSTP_8 : ARM::MVE_WLSTP_8; 32*e8d8bef9SDimitry Andric case ARM::MVE_VCTP16: 33*e8d8bef9SDimitry Andric return IsDoLoop ? ARM::MVE_DLSTP_16 : ARM::MVE_WLSTP_16; 34*e8d8bef9SDimitry Andric case ARM::MVE_VCTP32: 35*e8d8bef9SDimitry Andric return IsDoLoop ? ARM::MVE_DLSTP_32 : ARM::MVE_WLSTP_32; 36*e8d8bef9SDimitry Andric case ARM::MVE_VCTP64: 37*e8d8bef9SDimitry Andric return IsDoLoop ? ARM::MVE_DLSTP_64 : ARM::MVE_WLSTP_64; 38*e8d8bef9SDimitry Andric } 39*e8d8bef9SDimitry Andric return 0; 40*e8d8bef9SDimitry Andric } 41*e8d8bef9SDimitry Andric 42*e8d8bef9SDimitry Andric static inline unsigned getTailPredVectorWidth(unsigned Opcode) { 43*e8d8bef9SDimitry Andric switch (Opcode) { 44*e8d8bef9SDimitry Andric default: 45*e8d8bef9SDimitry Andric llvm_unreachable("unhandled vctp opcode"); 46*e8d8bef9SDimitry Andric case ARM::MVE_VCTP8: 47*e8d8bef9SDimitry Andric return 16; 48*e8d8bef9SDimitry Andric case ARM::MVE_VCTP16: 49*e8d8bef9SDimitry Andric return 8; 50*e8d8bef9SDimitry Andric case ARM::MVE_VCTP32: 51*e8d8bef9SDimitry Andric return 4; 52*e8d8bef9SDimitry Andric case ARM::MVE_VCTP64: 53*e8d8bef9SDimitry Andric return 2; 54*e8d8bef9SDimitry Andric } 55*e8d8bef9SDimitry Andric return 0; 56*e8d8bef9SDimitry Andric } 57*e8d8bef9SDimitry Andric 58*e8d8bef9SDimitry Andric static inline bool isVCTP(const MachineInstr *MI) { 59*e8d8bef9SDimitry Andric switch (MI->getOpcode()) { 60*e8d8bef9SDimitry Andric default: 61*e8d8bef9SDimitry Andric break; 62*e8d8bef9SDimitry Andric case ARM::MVE_VCTP8: 63*e8d8bef9SDimitry Andric case ARM::MVE_VCTP16: 64*e8d8bef9SDimitry Andric case ARM::MVE_VCTP32: 65*e8d8bef9SDimitry Andric case ARM::MVE_VCTP64: 66*e8d8bef9SDimitry Andric return true; 67*e8d8bef9SDimitry Andric } 68*e8d8bef9SDimitry Andric return false; 69*e8d8bef9SDimitry Andric } 70*e8d8bef9SDimitry Andric 71*e8d8bef9SDimitry Andric static inline bool isLoopStart(MachineInstr &MI) { 72*e8d8bef9SDimitry Andric return MI.getOpcode() == ARM::t2DoLoopStart || 73*e8d8bef9SDimitry Andric MI.getOpcode() == ARM::t2DoLoopStartTP || 74*e8d8bef9SDimitry Andric MI.getOpcode() == ARM::t2WhileLoopStart; 75*e8d8bef9SDimitry Andric } 76*e8d8bef9SDimitry Andric 77*e8d8bef9SDimitry Andric // WhileLoopStart holds the exit block, so produce a cmp lr, 0 and then a 78*e8d8bef9SDimitry Andric // beq that branches to the exit branch. 79*e8d8bef9SDimitry Andric inline void RevertWhileLoopStart(MachineInstr *MI, const TargetInstrInfo *TII, 80*e8d8bef9SDimitry Andric unsigned BrOpc = ARM::t2Bcc) { 81*e8d8bef9SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 82*e8d8bef9SDimitry Andric 83*e8d8bef9SDimitry Andric // Cmp 84*e8d8bef9SDimitry Andric MachineInstrBuilder MIB = 85*e8d8bef9SDimitry Andric BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(ARM::t2CMPri)); 86*e8d8bef9SDimitry Andric MIB.add(MI->getOperand(0)); 87*e8d8bef9SDimitry Andric MIB.addImm(0); 88*e8d8bef9SDimitry Andric MIB.addImm(ARMCC::AL); 89*e8d8bef9SDimitry Andric MIB.addReg(ARM::NoRegister); 90*e8d8bef9SDimitry Andric 91*e8d8bef9SDimitry Andric // Branch 92*e8d8bef9SDimitry Andric MIB = BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(BrOpc)); 93*e8d8bef9SDimitry Andric MIB.add(MI->getOperand(1)); // branch target 94*e8d8bef9SDimitry Andric MIB.addImm(ARMCC::EQ); // condition code 95*e8d8bef9SDimitry Andric MIB.addReg(ARM::CPSR); 96*e8d8bef9SDimitry Andric 97*e8d8bef9SDimitry Andric MI->eraseFromParent(); 98*e8d8bef9SDimitry Andric } 99*e8d8bef9SDimitry Andric 100*e8d8bef9SDimitry Andric inline void RevertDoLoopStart(MachineInstr *MI, const TargetInstrInfo *TII) { 101*e8d8bef9SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 102*e8d8bef9SDimitry Andric BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(ARM::tMOVr)) 103*e8d8bef9SDimitry Andric .add(MI->getOperand(0)) 104*e8d8bef9SDimitry Andric .add(MI->getOperand(1)) 105*e8d8bef9SDimitry Andric .add(predOps(ARMCC::AL)); 106*e8d8bef9SDimitry Andric 107*e8d8bef9SDimitry Andric MI->eraseFromParent(); 108*e8d8bef9SDimitry Andric } 109*e8d8bef9SDimitry Andric 110*e8d8bef9SDimitry Andric inline void RevertLoopDec(MachineInstr *MI, const TargetInstrInfo *TII, 111*e8d8bef9SDimitry Andric bool SetFlags = false) { 112*e8d8bef9SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 113*e8d8bef9SDimitry Andric 114*e8d8bef9SDimitry Andric MachineInstrBuilder MIB = 115*e8d8bef9SDimitry Andric BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(ARM::t2SUBri)); 116*e8d8bef9SDimitry Andric MIB.add(MI->getOperand(0)); 117*e8d8bef9SDimitry Andric MIB.add(MI->getOperand(1)); 118*e8d8bef9SDimitry Andric MIB.add(MI->getOperand(2)); 119*e8d8bef9SDimitry Andric MIB.addImm(ARMCC::AL); 120*e8d8bef9SDimitry Andric MIB.addReg(0); 121*e8d8bef9SDimitry Andric 122*e8d8bef9SDimitry Andric if (SetFlags) { 123*e8d8bef9SDimitry Andric MIB.addReg(ARM::CPSR); 124*e8d8bef9SDimitry Andric MIB->getOperand(5).setIsDef(true); 125*e8d8bef9SDimitry Andric } else 126*e8d8bef9SDimitry Andric MIB.addReg(0); 127*e8d8bef9SDimitry Andric 128*e8d8bef9SDimitry Andric MI->eraseFromParent(); 129*e8d8bef9SDimitry Andric } 130*e8d8bef9SDimitry Andric 131*e8d8bef9SDimitry Andric // Generate a subs, or sub and cmp, and a branch instead of an LE. 132*e8d8bef9SDimitry Andric inline void RevertLoopEnd(MachineInstr *MI, const TargetInstrInfo *TII, 133*e8d8bef9SDimitry Andric unsigned BrOpc = ARM::t2Bcc, bool SkipCmp = false) { 134*e8d8bef9SDimitry Andric MachineBasicBlock *MBB = MI->getParent(); 135*e8d8bef9SDimitry Andric 136*e8d8bef9SDimitry Andric // Create cmp 137*e8d8bef9SDimitry Andric if (!SkipCmp) { 138*e8d8bef9SDimitry Andric MachineInstrBuilder MIB = 139*e8d8bef9SDimitry Andric BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(ARM::t2CMPri)); 140*e8d8bef9SDimitry Andric MIB.add(MI->getOperand(0)); 141*e8d8bef9SDimitry Andric MIB.addImm(0); 142*e8d8bef9SDimitry Andric MIB.addImm(ARMCC::AL); 143*e8d8bef9SDimitry Andric MIB.addReg(ARM::NoRegister); 144*e8d8bef9SDimitry Andric } 145*e8d8bef9SDimitry Andric 146*e8d8bef9SDimitry Andric // Create bne 147*e8d8bef9SDimitry Andric MachineInstrBuilder MIB = 148*e8d8bef9SDimitry Andric BuildMI(*MBB, MI, MI->getDebugLoc(), TII->get(BrOpc)); 149*e8d8bef9SDimitry Andric MIB.add(MI->getOperand(1)); // branch target 150*e8d8bef9SDimitry Andric MIB.addImm(ARMCC::NE); // condition code 151*e8d8bef9SDimitry Andric MIB.addReg(ARM::CPSR); 152*e8d8bef9SDimitry Andric MI->eraseFromParent(); 153*e8d8bef9SDimitry Andric } 154*e8d8bef9SDimitry Andric 155*e8d8bef9SDimitry Andric } // end namespace llvm 156*e8d8bef9SDimitry Andric 157*e8d8bef9SDimitry Andric #endif // LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H 158