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