xref: /freebsd/contrib/llvm-project/llvm/lib/Target/ARM/MVETailPredUtils.h (revision e8d8bef961a50d4dc22501cde4fb9fb0be1b2532)
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