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