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
VCTPOpcodeToLSTP(unsigned Opcode,bool IsDoLoop)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
getTailPredVectorWidth(unsigned Opcode)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
isVCTP(const MachineInstr * MI)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
isLoopStart(MachineInstr & MI)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
RevertDoLoopStart(MachineInstr * MI,const TargetInstrInfo * TII)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