1 //===-- AArch64CondBrTuning.cpp --- Conditional branch tuning for AArch64 -===//
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 a pass that transforms CBZ/CBNZ/TBZ/TBNZ instructions
10 /// into a conditional branch (B.cond), when the NZCV flags can be set for
11 /// "free". This is preferred on targets that have more flexibility when
12 /// scheduling B.cond instructions as compared to CBZ/CBNZ/TBZ/TBNZ (assuming
13 /// all other variables are equal). This can also reduce register pressure.
17 /// 1) add w8, w0, w1 -> cmn w0, w1 ; CMN is an alias of ADDS.
18 /// cbz w8, .LBB_2 -> b.eq .LBB0_2
20 /// 2) add w8, w0, w1 -> adds w8, w0, w1 ; w8 has multiple uses.
21 /// cbz w8, .LBB1_2 -> b.eq .LBB1_2
23 /// 3) sub w8, w0, w1 -> subs w8, w0, w1 ; w8 has multiple uses.
24 /// tbz w8, #31, .LBB6_2 -> b.pl .LBB6_2
26 //===----------------------------------------------------------------------===//
29 #include "AArch64Subtarget.h"
30 #include "llvm/CodeGen/MachineFunction.h"
31 #include "llvm/CodeGen/MachineFunctionPass.h"
32 #include "llvm/CodeGen/MachineInstrBuilder.h"
33 #include "llvm/CodeGen/MachineRegisterInfo.h"
34 #include "llvm/CodeGen/Passes.h"
35 #include "llvm/CodeGen/TargetInstrInfo.h"
36 #include "llvm/CodeGen/TargetRegisterInfo.h"
37 #include "llvm/CodeGen/TargetSubtargetInfo.h"
38 #include "llvm/Support/Debug.h"
39 #include "llvm/Support/raw_ostream.h"
43 #define DEBUG_TYPE "aarch64-cond-br-tuning"
44 #define AARCH64_CONDBR_TUNING_NAME "AArch64 Conditional Branch Tuning"
47 class AArch64CondBrTuning
: public MachineFunctionPass
{
48 const AArch64InstrInfo
*TII
;
49 const TargetRegisterInfo
*TRI
;
51 MachineRegisterInfo
*MRI
;
55 AArch64CondBrTuning() : MachineFunctionPass(ID
) {
56 initializeAArch64CondBrTuningPass(*PassRegistry::getPassRegistry());
58 void getAnalysisUsage(AnalysisUsage
&AU
) const override
;
59 bool runOnMachineFunction(MachineFunction
&MF
) override
;
60 StringRef
getPassName() const override
{ return AARCH64_CONDBR_TUNING_NAME
; }
63 MachineInstr
*getOperandDef(const MachineOperand
&MO
);
64 MachineInstr
*convertToFlagSetting(MachineInstr
&MI
, bool IsFlagSetting
,
66 MachineInstr
*convertToCondBr(MachineInstr
&MI
);
67 bool tryToTuneBranch(MachineInstr
&MI
, MachineInstr
&DefMI
);
69 } // end anonymous namespace
71 char AArch64CondBrTuning::ID
= 0;
73 INITIALIZE_PASS(AArch64CondBrTuning
, "aarch64-cond-br-tuning",
74 AARCH64_CONDBR_TUNING_NAME
, false, false)
76 void AArch64CondBrTuning::getAnalysisUsage(AnalysisUsage
&AU
) const {
78 MachineFunctionPass::getAnalysisUsage(AU
);
81 MachineInstr
*AArch64CondBrTuning::getOperandDef(const MachineOperand
&MO
) {
82 if (!MO
.getReg().isVirtual())
84 return MRI
->getUniqueVRegDef(MO
.getReg());
87 MachineInstr
*AArch64CondBrTuning::convertToFlagSetting(MachineInstr
&MI
,
90 // If this is already the flag setting version of the instruction (e.g., SUBS)
91 // just make sure the implicit-def of NZCV isn't marked dead.
93 for (MachineOperand
&MO
: MI
.implicit_operands())
94 if (MO
.isReg() && MO
.isDead() && MO
.getReg() == AArch64::NZCV
)
98 unsigned NewOpc
= TII
->convertToFlagSettingOpc(MI
.getOpcode());
99 Register NewDestReg
= MI
.getOperand(0).getReg();
100 if (MRI
->hasOneNonDBGUse(MI
.getOperand(0).getReg()))
101 NewDestReg
= Is64Bit
? AArch64::XZR
: AArch64::WZR
;
103 MachineInstrBuilder MIB
= BuildMI(*MI
.getParent(), MI
, MI
.getDebugLoc(),
104 TII
->get(NewOpc
), NewDestReg
);
105 for (const MachineOperand
&MO
: llvm::drop_begin(MI
.operands()))
111 MachineInstr
*AArch64CondBrTuning::convertToCondBr(MachineInstr
&MI
) {
112 AArch64CC::CondCode CC
;
113 MachineBasicBlock
*TargetMBB
= TII
->getBranchDestBlock(MI
);
114 switch (MI
.getOpcode()) {
116 llvm_unreachable("Unexpected opcode!");
135 return BuildMI(*MI
.getParent(), MI
, MI
.getDebugLoc(), TII
->get(AArch64::Bcc
))
140 bool AArch64CondBrTuning::tryToTuneBranch(MachineInstr
&MI
,
141 MachineInstr
&DefMI
) {
142 // We don't want NZCV bits live across blocks.
143 if (MI
.getParent() != DefMI
.getParent())
146 bool IsFlagSetting
= true;
147 unsigned MIOpc
= MI
.getOpcode();
148 MachineInstr
*NewCmp
= nullptr, *NewBr
= nullptr;
149 switch (DefMI
.getOpcode()) {
152 case AArch64::ADDWri
:
153 case AArch64::ADDWrr
:
154 case AArch64::ADDWrs
:
155 case AArch64::ADDWrx
:
156 case AArch64::ANDWri
:
157 case AArch64::ANDWrr
:
158 case AArch64::ANDWrs
:
159 case AArch64::BICWrr
:
160 case AArch64::BICWrs
:
161 case AArch64::SUBWri
:
162 case AArch64::SUBWrr
:
163 case AArch64::SUBWrs
:
164 case AArch64::SUBWrx
:
165 IsFlagSetting
= false;
167 case AArch64::ADDSWri
:
168 case AArch64::ADDSWrr
:
169 case AArch64::ADDSWrs
:
170 case AArch64::ADDSWrx
:
171 case AArch64::ANDSWri
:
172 case AArch64::ANDSWrr
:
173 case AArch64::ANDSWrs
:
174 case AArch64::BICSWrr
:
175 case AArch64::BICSWrs
:
176 case AArch64::SUBSWri
:
177 case AArch64::SUBSWrr
:
178 case AArch64::SUBSWrs
:
179 case AArch64::SUBSWrx
:
182 llvm_unreachable("Unexpected opcode!");
188 // Check to see if the TBZ/TBNZ is checking the sign bit.
189 if ((MIOpc
== AArch64::TBZW
|| MIOpc
== AArch64::TBNZW
) &&
190 MI
.getOperand(1).getImm() != 31)
193 // There must not be any instruction between DefMI and MI that clobbers or
195 if (isNZCVTouchedInInstructionRange(DefMI
, MI
, TRI
))
197 LLVM_DEBUG(dbgs() << " Replacing instructions:\n ");
198 LLVM_DEBUG(DefMI
.print(dbgs()));
199 LLVM_DEBUG(dbgs() << " ");
200 LLVM_DEBUG(MI
.print(dbgs()));
202 NewCmp
= convertToFlagSetting(DefMI
, IsFlagSetting
, /*Is64Bit=*/false);
203 NewBr
= convertToCondBr(MI
);
208 case AArch64::ADDXri
:
209 case AArch64::ADDXrr
:
210 case AArch64::ADDXrs
:
211 case AArch64::ADDXrx
:
212 case AArch64::ANDXri
:
213 case AArch64::ANDXrr
:
214 case AArch64::ANDXrs
:
215 case AArch64::BICXrr
:
216 case AArch64::BICXrs
:
217 case AArch64::SUBXri
:
218 case AArch64::SUBXrr
:
219 case AArch64::SUBXrs
:
220 case AArch64::SUBXrx
:
221 IsFlagSetting
= false;
223 case AArch64::ADDSXri
:
224 case AArch64::ADDSXrr
:
225 case AArch64::ADDSXrs
:
226 case AArch64::ADDSXrx
:
227 case AArch64::ANDSXri
:
228 case AArch64::ANDSXrr
:
229 case AArch64::ANDSXrs
:
230 case AArch64::BICSXrr
:
231 case AArch64::BICSXrs
:
232 case AArch64::SUBSXri
:
233 case AArch64::SUBSXrr
:
234 case AArch64::SUBSXrs
:
235 case AArch64::SUBSXrx
:
238 llvm_unreachable("Unexpected opcode!");
243 case AArch64::TBNZX
: {
244 // Check to see if the TBZ/TBNZ is checking the sign bit.
245 if ((MIOpc
== AArch64::TBZX
|| MIOpc
== AArch64::TBNZX
) &&
246 MI
.getOperand(1).getImm() != 63)
248 // There must not be any instruction between DefMI and MI that clobbers or
250 if (isNZCVTouchedInInstructionRange(DefMI
, MI
, TRI
))
252 LLVM_DEBUG(dbgs() << " Replacing instructions:\n ");
253 LLVM_DEBUG(DefMI
.print(dbgs()));
254 LLVM_DEBUG(dbgs() << " ");
255 LLVM_DEBUG(MI
.print(dbgs()));
257 NewCmp
= convertToFlagSetting(DefMI
, IsFlagSetting
, /*Is64Bit=*/true);
258 NewBr
= convertToCondBr(MI
);
264 (void)NewCmp
; (void)NewBr
;
265 assert(NewCmp
&& NewBr
&& "Expected new instructions.");
267 LLVM_DEBUG(dbgs() << " with instruction:\n ");
268 LLVM_DEBUG(NewCmp
->print(dbgs()));
269 LLVM_DEBUG(dbgs() << " ");
270 LLVM_DEBUG(NewBr
->print(dbgs()));
272 // If this was a flag setting version of the instruction, we use the original
273 // instruction by just clearing the dead marked on the implicit-def of NCZV.
274 // Therefore, we should not erase this instruction.
276 DefMI
.eraseFromParent();
277 MI
.eraseFromParent();
281 bool AArch64CondBrTuning::runOnMachineFunction(MachineFunction
&MF
) {
282 if (skipFunction(MF
.getFunction()))
286 dbgs() << "********** AArch64 Conditional Branch Tuning **********\n"
287 << "********** Function: " << MF
.getName() << '\n');
289 TII
= static_cast<const AArch64InstrInfo
*>(MF
.getSubtarget().getInstrInfo());
290 TRI
= MF
.getSubtarget().getRegisterInfo();
291 MRI
= &MF
.getRegInfo();
293 bool Changed
= false;
294 for (MachineBasicBlock
&MBB
: MF
) {
295 bool LocalChange
= false;
296 for (MachineInstr
&MI
: MBB
.terminators()) {
297 switch (MI
.getOpcode()) {
308 MachineInstr
*DefMI
= getOperandDef(MI
.getOperand(0));
309 LocalChange
= (DefMI
&& tryToTuneBranch(MI
, *DefMI
));
312 // If the optimization was successful, we can't optimize any other
313 // branches because doing so would clobber the NZCV flags.
323 FunctionPass
*llvm::createAArch64CondBrTuning() {
324 return new AArch64CondBrTuning();