1 //===-- MVETailPredUtils.h - Tail predication utility functions -*- C++-*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file contains utility functions for low overhead and tail predicated
10 // loops, shared between the ARMLowOverheadLoops pass and anywhere else that
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H
16 #define LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H
18 #include "llvm/CodeGen/MachineInstr.h"
19 #include "llvm/CodeGen/MachineInstrBuilder.h"
20 #include "llvm/CodeGen/MachineOperand.h"
21 #include "llvm/CodeGen/TargetInstrInfo.h"
25 static inline unsigned VCTPOpcodeToLSTP(unsigned Opcode
, bool IsDoLoop
) {
28 llvm_unreachable("unhandled vctp opcode");
31 return IsDoLoop
? ARM::MVE_DLSTP_8
: ARM::MVE_WLSTP_8
;
33 return IsDoLoop
? ARM::MVE_DLSTP_16
: ARM::MVE_WLSTP_16
;
35 return IsDoLoop
? ARM::MVE_DLSTP_32
: ARM::MVE_WLSTP_32
;
37 return IsDoLoop
? ARM::MVE_DLSTP_64
: ARM::MVE_WLSTP_64
;
42 static inline unsigned getTailPredVectorWidth(unsigned Opcode
) {
45 llvm_unreachable("unhandled vctp opcode");
58 static inline bool isVCTP(const MachineInstr
*MI
) {
59 switch (MI
->getOpcode()) {
71 static inline bool isDoLoopStart(const MachineInstr
&MI
) {
72 return MI
.getOpcode() == ARM::t2DoLoopStart
||
73 MI
.getOpcode() == ARM::t2DoLoopStartTP
;
76 static inline bool isWhileLoopStart(const MachineInstr
&MI
) {
77 return MI
.getOpcode() == ARM::t2WhileLoopStart
||
78 MI
.getOpcode() == ARM::t2WhileLoopStartLR
||
79 MI
.getOpcode() == ARM::t2WhileLoopStartTP
;
82 static inline bool isLoopStart(const MachineInstr
&MI
) {
83 return isDoLoopStart(MI
) || isWhileLoopStart(MI
);
86 // Return the TargetBB stored in a t2WhileLoopStartLR/t2WhileLoopStartTP.
87 inline MachineBasicBlock
*getWhileLoopStartTargetBB(const MachineInstr
&MI
) {
88 assert(isWhileLoopStart(MI
) && "Expected WhileLoopStart!");
89 unsigned Op
= MI
.getOpcode() == ARM::t2WhileLoopStartTP
? 3 : 2;
90 return MI
.getOperand(Op
).getMBB();
93 // WhileLoopStart holds the exit block, so produce a subs Op0, Op1, 0 and then a
94 // beq that branches to the exit branch.
95 // If UseCmp is true, this will create a t2CMP instead of a t2SUBri, meaning the
96 // value of LR into the loop will not be setup. This is used if the LR setup is
97 // done via another means (via a t2DoLoopStart, for example).
98 inline void RevertWhileLoopStartLR(MachineInstr
*MI
, const TargetInstrInfo
*TII
,
99 unsigned BrOpc
= ARM::t2Bcc
,
100 bool UseCmp
= false) {
101 MachineBasicBlock
*MBB
= MI
->getParent();
102 assert((MI
->getOpcode() == ARM::t2WhileLoopStartLR
||
103 MI
->getOpcode() == ARM::t2WhileLoopStartTP
) &&
104 "Only expected a t2WhileLoopStartLR/TP in RevertWhileLoopStartLR!");
108 MachineInstrBuilder MIB
=
109 BuildMI(*MBB
, MI
, MI
->getDebugLoc(), TII
->get(ARM::t2CMPri
));
110 MIB
.add(MI
->getOperand(1));
112 MIB
.addImm(ARMCC::AL
);
113 MIB
.addReg(ARM::NoRegister
);
115 MachineInstrBuilder MIB
=
116 BuildMI(*MBB
, MI
, MI
->getDebugLoc(), TII
->get(ARM::t2SUBri
));
117 MIB
.add(MI
->getOperand(0));
118 MIB
.add(MI
->getOperand(1));
120 MIB
.addImm(ARMCC::AL
);
121 MIB
.addReg(ARM::NoRegister
);
122 MIB
.addReg(ARM::CPSR
, RegState::Define
);
126 MachineInstrBuilder MIB
=
127 BuildMI(*MBB
, MI
, MI
->getDebugLoc(), TII
->get(BrOpc
));
128 MIB
.addMBB(getWhileLoopStartTargetBB(*MI
)); // branch target
129 MIB
.addImm(ARMCC::EQ
); // condition code
130 MIB
.addReg(ARM::CPSR
);
132 MI
->eraseFromParent();
135 inline void RevertDoLoopStart(MachineInstr
*MI
, const TargetInstrInfo
*TII
) {
136 MachineBasicBlock
*MBB
= MI
->getParent();
137 BuildMI(*MBB
, MI
, MI
->getDebugLoc(), TII
->get(ARM::tMOVr
))
138 .add(MI
->getOperand(0))
139 .add(MI
->getOperand(1))
140 .add(predOps(ARMCC::AL
));
142 MI
->eraseFromParent();
145 inline void RevertLoopDec(MachineInstr
*MI
, const TargetInstrInfo
*TII
,
146 bool SetFlags
= false) {
147 MachineBasicBlock
*MBB
= MI
->getParent();
149 MachineInstrBuilder MIB
=
150 BuildMI(*MBB
, MI
, MI
->getDebugLoc(), TII
->get(ARM::t2SUBri
));
151 MIB
.add(MI
->getOperand(0));
152 MIB
.add(MI
->getOperand(1));
153 MIB
.add(MI
->getOperand(2));
154 MIB
.addImm(ARMCC::AL
);
158 MIB
.addReg(ARM::CPSR
);
159 MIB
->getOperand(5).setIsDef(true);
163 MI
->eraseFromParent();
166 // Generate a subs, or sub and cmp, and a branch instead of an LE.
167 inline void RevertLoopEnd(MachineInstr
*MI
, const TargetInstrInfo
*TII
,
168 unsigned BrOpc
= ARM::t2Bcc
, bool SkipCmp
= false) {
169 MachineBasicBlock
*MBB
= MI
->getParent();
173 MachineInstrBuilder MIB
=
174 BuildMI(*MBB
, MI
, MI
->getDebugLoc(), TII
->get(ARM::t2CMPri
));
175 MIB
.add(MI
->getOperand(0));
177 MIB
.addImm(ARMCC::AL
);
178 MIB
.addReg(ARM::NoRegister
);
182 MachineInstrBuilder MIB
=
183 BuildMI(*MBB
, MI
, MI
->getDebugLoc(), TII
->get(BrOpc
));
184 MIB
.add(MI
->getOperand(1)); // branch target
185 MIB
.addImm(ARMCC::NE
); // condition code
186 MIB
.addReg(ARM::CPSR
);
187 MI
->eraseFromParent();
190 } // end namespace llvm
192 #endif // LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H