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 isDoLoopStart(const MachineInstr &MI) { |
72 | return MI.getOpcode() == ARM::t2DoLoopStart || |
73 | MI.getOpcode() == ARM::t2DoLoopStartTP; |
74 | } |
75 | |
76 | static inline bool isWhileLoopStart(const MachineInstr &MI) { |
77 | return MI.getOpcode() == ARM::t2WhileLoopStart || |
78 | MI.getOpcode() == ARM::t2WhileLoopStartLR || |
79 | MI.getOpcode() == ARM::t2WhileLoopStartTP; |
80 | } |
81 | |
82 | static inline bool isLoopStart(const MachineInstr &MI) { |
83 | return isDoLoopStart(MI) || isWhileLoopStart(MI); |
84 | } |
85 | |
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(i: Op).getMBB(); |
91 | } |
92 | |
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!" ); |
105 | |
106 | // Subs/Cmp |
107 | if (UseCmp) { |
108 | MachineInstrBuilder MIB = |
109 | BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: TII->get(Opcode: ARM::t2CMPri)); |
110 | MIB.add(MO: MI->getOperand(i: 1)); |
111 | MIB.addImm(Val: 0); |
112 | MIB.addImm(Val: ARMCC::AL); |
113 | MIB.addReg(RegNo: ARM::NoRegister); |
114 | } else { |
115 | MachineInstrBuilder MIB = |
116 | BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: TII->get(Opcode: ARM::t2SUBri)); |
117 | MIB.add(MO: MI->getOperand(i: 0)); |
118 | MIB.add(MO: MI->getOperand(i: 1)); |
119 | MIB.addImm(Val: 0); |
120 | MIB.addImm(Val: ARMCC::AL); |
121 | MIB.addReg(RegNo: ARM::NoRegister); |
122 | MIB.addReg(RegNo: ARM::CPSR, flags: RegState::Define); |
123 | } |
124 | |
125 | // Branch |
126 | MachineInstrBuilder MIB = |
127 | BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: TII->get(Opcode: BrOpc)); |
128 | MIB.addMBB(MBB: getWhileLoopStartTargetBB(MI: *MI)); // branch target |
129 | MIB.addImm(Val: ARMCC::EQ); // condition code |
130 | MIB.addReg(RegNo: ARM::CPSR); |
131 | |
132 | MI->eraseFromParent(); |
133 | } |
134 | |
135 | inline void RevertDoLoopStart(MachineInstr *MI, const TargetInstrInfo *TII) { |
136 | MachineBasicBlock *MBB = MI->getParent(); |
137 | BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: TII->get(Opcode: ARM::tMOVr)) |
138 | .add(MO: MI->getOperand(i: 0)) |
139 | .add(MO: MI->getOperand(i: 1)) |
140 | .add(MOs: predOps(Pred: ARMCC::AL)); |
141 | |
142 | MI->eraseFromParent(); |
143 | } |
144 | |
145 | inline void RevertLoopDec(MachineInstr *MI, const TargetInstrInfo *TII, |
146 | bool SetFlags = false) { |
147 | MachineBasicBlock *MBB = MI->getParent(); |
148 | |
149 | MachineInstrBuilder MIB = |
150 | BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: TII->get(Opcode: ARM::t2SUBri)); |
151 | MIB.add(MO: MI->getOperand(i: 0)); |
152 | MIB.add(MO: MI->getOperand(i: 1)); |
153 | MIB.add(MO: MI->getOperand(i: 2)); |
154 | MIB.addImm(Val: ARMCC::AL); |
155 | MIB.addReg(RegNo: 0); |
156 | |
157 | if (SetFlags) { |
158 | MIB.addReg(RegNo: ARM::CPSR); |
159 | MIB->getOperand(i: 5).setIsDef(true); |
160 | } else |
161 | MIB.addReg(RegNo: 0); |
162 | |
163 | MI->eraseFromParent(); |
164 | } |
165 | |
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(); |
170 | |
171 | // Create cmp |
172 | if (!SkipCmp) { |
173 | MachineInstrBuilder MIB = |
174 | BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: TII->get(Opcode: ARM::t2CMPri)); |
175 | MIB.add(MO: MI->getOperand(i: 0)); |
176 | MIB.addImm(Val: 0); |
177 | MIB.addImm(Val: ARMCC::AL); |
178 | MIB.addReg(RegNo: ARM::NoRegister); |
179 | } |
180 | |
181 | // Create bne |
182 | MachineInstrBuilder MIB = |
183 | BuildMI(BB&: *MBB, I: MI, MIMD: MI->getDebugLoc(), MCID: TII->get(Opcode: BrOpc)); |
184 | MIB.add(MO: MI->getOperand(i: 1)); // branch target |
185 | MIB.addImm(Val: ARMCC::NE); // condition code |
186 | MIB.addReg(RegNo: ARM::CPSR); |
187 | MI->eraseFromParent(); |
188 | } |
189 | |
190 | } // end namespace llvm |
191 | |
192 | #endif // LLVM_LIB_TARGET_ARM_MVETAILPREDUTILS_H |
193 | |