LLVM 23.0.0git
AArch64ConditionOptimizer.cpp
Go to the documentation of this file.
1//=- AArch64ConditionOptimizer.cpp - Remove useless comparisons for AArch64 -=//
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//
10// This pass tries to make consecutive comparisons of values use the same
11// operands to allow the CSE pass to remove duplicate instructions. It adjusts
12// comparisons with immediate values by converting between inclusive and
13// exclusive forms (GE <-> GT, LE <-> LT) and correcting immediate values to
14// make them equal.
15//
16// The pass handles:
17// * Cross-block: SUBS/ADDS followed by conditional branches
18// * Intra-block: CSINC conditional instructions
19//
20//
21// Consider the following example in C:
22//
23// if ((a < 5 && ...) || (a > 5 && ...)) {
24// ~~~~~ ~~~~~
25// ^ ^
26// x y
27//
28// Here both "x" and "y" expressions compare "a" with "5". When "x" evaluates
29// to "false", "y" can just check flags set by the first comparison. As a
30// result of the canonicalization employed by
31// SelectionDAGBuilder::visitSwitchCase, DAGCombine, and other target-specific
32// code, assembly ends up in the form that is not CSE friendly:
33//
34// ...
35// cmp w8, #4
36// b.gt .LBB0_3
37// ...
38// .LBB0_3:
39// cmp w8, #6
40// b.lt .LBB0_6
41// ...
42//
43// Same assembly after the pass:
44//
45// ...
46// cmp w8, #5
47// b.ge .LBB0_3
48// ...
49// .LBB0_3:
50// cmp w8, #5 // <-- CSE pass removes this instruction
51// b.le .LBB0_6
52// ...
53//
54// See optimizeCrossBlock() and optimizeIntraBlock() for implementation details.
55//
56// TODO: maybe handle TBNZ/TBZ the same way as CMP when used instead for "a < 0"
57// TODO: For cross-block:
58// - handle other conditional instructions (e.g. CSET)
59// - allow second branching to be anything if it doesn't require adjusting
60// TODO: For intra-block:
61// - handle CINC and CSET (CSINC aliases) as their conditions are inverted
62// compared to CSINC.
63// - handle other non-CSINC conditional instructions
64//
65//===----------------------------------------------------------------------===//
66
67#include "AArch64.h"
70#include "llvm/ADT/ArrayRef.h"
73#include "llvm/ADT/Statistic.h"
86#include "llvm/Pass.h"
87#include "llvm/Support/Debug.h"
90#include <cassert>
91#include <cstdlib>
92#include <tuple>
93
94using namespace llvm;
95
96#define DEBUG_TYPE "aarch64-condopt"
97
98STATISTIC(NumConditionsAdjusted, "Number of conditions adjusted");
99
100namespace {
101
102class AArch64ConditionOptimizer : public MachineFunctionPass {
103 const TargetInstrInfo *TII;
104 const TargetRegisterInfo *TRI;
105 MachineDominatorTree *DomTree;
107
108public:
109 // Stores immediate, compare instruction opcode and branch condition (in this
110 // order) of adjusted comparison.
111 using CmpInfo = std::tuple<int, unsigned, AArch64CC::CondCode>;
112
113 static char ID;
114
115 AArch64ConditionOptimizer() : MachineFunctionPass(ID) {}
116
117 void getAnalysisUsage(AnalysisUsage &AU) const override;
118 bool canAdjustCmp(MachineInstr &CmpMI);
119 bool registersMatch(MachineInstr *FirstMI, MachineInstr *SecondMI);
120 bool nzcvLivesOut(MachineBasicBlock *MBB);
121 MachineInstr *findSuitableCompare(MachineBasicBlock *MBB);
122 CmpInfo adjustCmp(MachineInstr *CmpMI, AArch64CC::CondCode Cmp);
123 void modifyCmp(MachineInstr *CmpMI, const CmpInfo &Info);
124 bool adjustTo(MachineInstr *CmpMI, AArch64CC::CondCode Cmp, MachineInstr *To,
125 int ToImm);
126 bool optimizeIntraBlock(MachineBasicBlock &MBB);
127 bool optimizeCrossBlock(MachineBasicBlock &HBB);
128 bool runOnMachineFunction(MachineFunction &MF) override;
129
130 StringRef getPassName() const override {
131 return "AArch64 Condition Optimizer";
132 }
133};
134
135} // end anonymous namespace
136
137char AArch64ConditionOptimizer::ID = 0;
138
139INITIALIZE_PASS_BEGIN(AArch64ConditionOptimizer, "aarch64-condopt",
140 "AArch64 CondOpt Pass", false, false)
142INITIALIZE_PASS_END(AArch64ConditionOptimizer, "aarch64-condopt",
143 "AArch64 CondOpt Pass", false, false)
144
146 return new AArch64ConditionOptimizer();
147}
148
149void AArch64ConditionOptimizer::getAnalysisUsage(AnalysisUsage &AU) const {
153}
154
155// Verify that the MI's immediate is adjustable and it only sets flags (pure
156// cmp)
157bool AArch64ConditionOptimizer::canAdjustCmp(MachineInstr &CmpMI) {
158 unsigned ShiftAmt = AArch64_AM::getShiftValue(CmpMI.getOperand(3).getImm());
159 if (!CmpMI.getOperand(2).isImm()) {
160 LLVM_DEBUG(dbgs() << "Immediate of cmp is symbolic, " << CmpMI << '\n');
161 return false;
162 } else if (CmpMI.getOperand(2).getImm() << ShiftAmt >= 0xfff) {
163 LLVM_DEBUG(dbgs() << "Immediate of cmp may be out of range, " << CmpMI
164 << '\n');
165 return false;
166 } else if (!MRI->use_nodbg_empty(CmpMI.getOperand(0).getReg())) {
167 LLVM_DEBUG(dbgs() << "Destination of cmp is not dead, " << CmpMI << '\n');
168 return false;
169 }
170
171 return true;
172}
173
174// Ensure both compare MIs use the same register, tracing through copies.
175bool AArch64ConditionOptimizer::registersMatch(MachineInstr *FirstMI,
176 MachineInstr *SecondMI) {
177 Register FirstReg = FirstMI->getOperand(1).getReg();
178 Register SecondReg = SecondMI->getOperand(1).getReg();
179 Register FirstCmpReg =
180 FirstReg.isVirtual() ? TRI->lookThruCopyLike(FirstReg, MRI) : FirstReg;
181 Register SecondCmpReg =
182 SecondReg.isVirtual() ? TRI->lookThruCopyLike(SecondReg, MRI) : SecondReg;
183 if (FirstCmpReg != SecondCmpReg) {
184 LLVM_DEBUG(dbgs() << "CMPs compare different registers\n");
185 return false;
186 }
187
188 return true;
189}
190
191// Check if NZCV lives out to any successor block.
192bool AArch64ConditionOptimizer::nzcvLivesOut(MachineBasicBlock *MBB) {
193 for (auto *SuccBB : MBB->successors()) {
194 if (SuccBB->isLiveIn(AArch64::NZCV)) {
195 LLVM_DEBUG(dbgs() << "NZCV live into successor "
196 << printMBBReference(*SuccBB) << " from "
197 << printMBBReference(*MBB) << '\n');
198 return true;
199 }
200 }
201 return false;
202}
203
204// Returns true if the opcode is a comparison instruction (CMP/CMN).
205static bool isCmpInstruction(unsigned Opc) {
206 switch (Opc) {
207 // cmp is an alias for SUBS with a dead destination register.
208 case AArch64::SUBSWri:
209 case AArch64::SUBSXri:
210 // cmp is an alias for ADDS with a dead destination register.
211 case AArch64::ADDSWri:
212 case AArch64::ADDSXri:
213 return true;
214 default:
215 return false;
216 }
217}
218
219static bool isCSINCInstruction(unsigned Opc) {
220 return Opc == AArch64::CSINCWr || Opc == AArch64::CSINCXr;
221}
222
223// Finds compare instruction that corresponds to supported types of branching.
224// Returns the instruction or nullptr on failures or detecting unsupported
225// instructions.
226MachineInstr *AArch64ConditionOptimizer::findSuitableCompare(
227 MachineBasicBlock *MBB) {
229 if (Term == MBB->end())
230 return nullptr;
231
232 if (Term->getOpcode() != AArch64::Bcc)
233 return nullptr;
234
235 // Since we may modify cmp of this MBB, make sure NZCV does not live out.
236 if (nzcvLivesOut(MBB))
237 return nullptr;
238
239 // Now find the instruction controlling the terminator.
240 for (MachineBasicBlock::iterator B = MBB->begin(), It = Term; It != B;) {
241 It = prev_nodbg(It, B);
242 MachineInstr &I = *It;
243 assert(!I.isTerminator() && "Spurious terminator");
244 // Check if there is any use of NZCV between CMP and Bcc.
245 if (I.readsRegister(AArch64::NZCV, /*TRI=*/nullptr))
246 return nullptr;
247
248 if (isCmpInstruction(I.getOpcode())) {
249 if (!canAdjustCmp(I)) {
250 return nullptr;
251 }
252 return &I;
253 }
254
255 if (I.modifiesRegister(AArch64::NZCV, /*TRI=*/nullptr))
256 return nullptr;
257 }
258 LLVM_DEBUG(dbgs() << "Flags not defined in " << printMBBReference(*MBB)
259 << '\n');
260 return nullptr;
261}
262
263// Changes opcode adds <-> subs considering register operand width.
264static int getComplementOpc(int Opc) {
265 switch (Opc) {
266 case AArch64::ADDSWri: return AArch64::SUBSWri;
267 case AArch64::ADDSXri: return AArch64::SUBSXri;
268 case AArch64::SUBSWri: return AArch64::ADDSWri;
269 case AArch64::SUBSXri: return AArch64::ADDSXri;
270 default:
271 llvm_unreachable("Unexpected opcode");
272 }
273}
274
275// Changes form of comparison inclusive <-> exclusive.
277 switch (Cmp) {
278 case AArch64CC::GT:
279 return AArch64CC::GE;
280 case AArch64CC::GE:
281 return AArch64CC::GT;
282 case AArch64CC::LT:
283 return AArch64CC::LE;
284 case AArch64CC::LE:
285 return AArch64CC::LT;
286 case AArch64CC::HI:
287 return AArch64CC::HS;
288 case AArch64CC::HS:
289 return AArch64CC::HI;
290 case AArch64CC::LO:
291 return AArch64CC::LS;
292 case AArch64CC::LS:
293 return AArch64CC::LO;
294 default:
295 llvm_unreachable("Unexpected condition code");
296 }
297}
298
299// Transforms GT -> GE, GE -> GT, LT -> LE, LE -> LT by updating comparison
300// operator and condition code.
301AArch64ConditionOptimizer::CmpInfo
302AArch64ConditionOptimizer::adjustCmp(MachineInstr *CmpMI,
304 unsigned Opc = CmpMI->getOpcode();
305
306 bool IsSigned = Cmp == AArch64CC::GT || Cmp == AArch64CC::GE ||
308
309 // CMN (compare with negative immediate) is an alias to ADDS (as
310 // "operand - negative" == "operand + positive")
311 bool Negative = (Opc == AArch64::ADDSWri || Opc == AArch64::ADDSXri);
312
313 int Correction = (Cmp == AArch64CC::GT || Cmp == AArch64CC::HI) ? 1 : -1;
314 // Negate Correction value for comparison with negative immediate (CMN).
315 if (Negative) {
316 Correction = -Correction;
317 }
318
319 const int OldImm = (int)CmpMI->getOperand(2).getImm();
320 const int NewImm = std::abs(OldImm + Correction);
321
322 // Bail out on cmn 0 (ADDS with immediate 0). It is a valid instruction but
323 // doesn't set flags in a way we can safely transform, so skip optimization.
324 if (OldImm == 0 && Negative)
325 return CmpInfo(OldImm, Opc, Cmp);
326
327 if ((OldImm == 1 && Negative && Correction == -1) ||
328 (OldImm == 0 && Correction == -1)) {
329 // If we change opcodes for unsigned comparisons, this means we did an
330 // unsigned wrap (e.g., 0 wrapping to 0xFFFFFFFF), so return the old cmp.
331 // Note: For signed comparisons, opcode changes (cmn 1 ↔ cmp 0) are valid.
332 if (!IsSigned)
333 return CmpInfo(OldImm, Opc, Cmp);
335 }
336
337 return CmpInfo(NewImm, Opc, getAdjustedCmp(Cmp));
338}
339
340// Applies changes to comparison instruction suggested by adjustCmp().
341void AArch64ConditionOptimizer::modifyCmp(MachineInstr *CmpMI,
342 const CmpInfo &Info) {
343 int Imm;
344 unsigned Opc;
346 std::tie(Imm, Opc, Cmp) = Info;
347
348 MachineBasicBlock *const MBB = CmpMI->getParent();
349
350 // Change immediate in comparison instruction (ADDS or SUBS).
351 BuildMI(*MBB, CmpMI, CmpMI->getDebugLoc(), TII->get(Opc))
352 .add(CmpMI->getOperand(0))
353 .add(CmpMI->getOperand(1))
354 .addImm(Imm)
355 .add(CmpMI->getOperand(3));
356 CmpMI->eraseFromParent();
357
358 // The fact that this comparison was picked ensures that it's related to the
359 // first terminator instruction.
360 MachineInstr &BrMI = *MBB->getFirstTerminator();
361
362 // Change condition in branch instruction.
363 BuildMI(*MBB, BrMI, BrMI.getDebugLoc(), TII->get(AArch64::Bcc))
364 .addImm(Cmp)
365 .add(BrMI.getOperand(1));
366 BrMI.eraseFromParent();
367
368 ++NumConditionsAdjusted;
369}
370
371// Parse a condition code returned by analyzeBranch, and compute the CondCode
372// corresponding to TBB.
373// Returns true if parsing was successful, otherwise false is returned.
375 // A normal br.cond simply has the condition code.
376 if (Cond[0].getImm() != -1) {
377 assert(Cond.size() == 1 && "Unknown Cond array format");
378 CC = (AArch64CC::CondCode)(int)Cond[0].getImm();
379 return true;
380 }
381 return false;
382}
383
384// Adjusts one cmp instruction to another one if result of adjustment will allow
385// CSE. Returns true if compare instruction was changed, otherwise false is
386// returned.
387bool AArch64ConditionOptimizer::adjustTo(MachineInstr *CmpMI,
388 AArch64CC::CondCode Cmp, MachineInstr *To, int ToImm)
389{
390 CmpInfo Info = adjustCmp(CmpMI, Cmp);
391 if (std::get<0>(Info) == ToImm && std::get<1>(Info) == To->getOpcode()) {
392 modifyCmp(CmpMI, Info);
393 return true;
394 }
395 return false;
396}
397
399 return Cmp == AArch64CC::GT || Cmp == AArch64CC::HI;
400}
401
403 return Cmp == AArch64CC::LT || Cmp == AArch64CC::LO;
404}
405
406// This function transforms two CMP+CSINC pairs within the same basic block
407// when both conditions are the same (GT/GT or LT/LT) and immediates differ
408// by 1.
409//
410// Example transformation:
411// cmp w8, #10
412// csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
413// cmp w8, #9
414// csinc w10, w0, w1, gt ; w10 = (w8 > 9) ? w0 : w1+1
415//
416// Into:
417// cmp w8, #10
418// csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
419// csinc w10, w0, w1, ge ; w10 = (w8 >= 10) ? w0 : w1+1
420//
421// The second CMP is eliminated, enabling CSE to remove the redundant
422// comparison.
423bool AArch64ConditionOptimizer::optimizeIntraBlock(MachineBasicBlock &MBB) {
424 MachineInstr *FirstCmp = nullptr;
425 MachineInstr *FirstCSINC = nullptr;
426 MachineInstr *SecondCmp = nullptr;
427 MachineInstr *SecondCSINC = nullptr;
428
429 // Find two CMP + CSINC pairs
430 for (MachineInstr &MI : MBB) {
431 if (isCmpInstruction(MI.getOpcode())) {
432 if (!FirstCmp) {
433 FirstCmp = &MI;
434 } else if (FirstCSINC && !SecondCmp) {
435 SecondCmp = &MI;
436 }
437 continue;
438 }
439
440 if (isCSINCInstruction(MI.getOpcode())) {
441 // Found a CSINC, ensure it comes after the corresponding comparison
442 if (FirstCmp && !FirstCSINC) {
443 FirstCSINC = &MI;
444 } else if (SecondCmp && !SecondCSINC) {
445 SecondCSINC = &MI;
446 }
447 }
448
449 if (SecondCSINC)
450 break;
451 }
452
453 if (!SecondCmp || !SecondCSINC) {
454 LLVM_DEBUG(dbgs() << "Didn't find two CMP+CSINC pairs\n");
455 return false;
456 }
457
458 // Since we may modify cmps in this MBB, make sure NZCV does not live out.
459 if (nzcvLivesOut(&MBB))
460 return false;
461
462 if (!registersMatch(FirstCmp, SecondCmp))
463 return false;
464
465 if (!canAdjustCmp(*FirstCmp) || !canAdjustCmp(*SecondCmp)) {
466 LLVM_DEBUG(dbgs() << "One or both CMPs are not pure\n");
467 return false;
468 }
469
470 // Check that nothing else modifies the flags between the first CMP and second
471 // conditional
472 for (auto It = std::next(MachineBasicBlock::iterator(FirstCmp));
473 It != std::next(MachineBasicBlock::iterator(SecondCSINC)); ++It) {
474 if (&*It != SecondCmp &&
475 It->modifiesRegister(AArch64::NZCV, /*TRI=*/nullptr)) {
476 LLVM_DEBUG(dbgs() << "Flags modified between CMPs by: " << *It << '\n');
477 return false;
478 }
479 }
480
481 // Check flags aren't read after second conditional within the same block
482 for (auto It = std::next(MachineBasicBlock::iterator(SecondCSINC));
483 It != MBB.end(); ++It) {
484 if (It->readsRegister(AArch64::NZCV, /*TRI=*/nullptr)) {
485 LLVM_DEBUG(dbgs() << "Flags read after second CSINC by: " << *It << '\n');
486 return false;
487 }
488 }
489
490 // Extract condition codes from both CSINCs (operand 3)
491 AArch64CC::CondCode FirstCond =
492 (AArch64CC::CondCode)(int)FirstCSINC->getOperand(3).getImm();
493 AArch64CC::CondCode SecondCond =
494 (AArch64CC::CondCode)(int)SecondCSINC->getOperand(3).getImm();
495
496 const int FirstImm = (int)FirstCmp->getOperand(2).getImm();
497 const int SecondImm = (int)SecondCmp->getOperand(2).getImm();
498
499 LLVM_DEBUG(dbgs() << "Comparing intra-block CSINCs: "
500 << AArch64CC::getCondCodeName(FirstCond) << " #" << FirstImm
501 << " and " << AArch64CC::getCondCodeName(SecondCond) << " #"
502 << SecondImm << '\n');
503
504 // Check if both conditions are the same (GT/GT, LT/LT, HI/HI, LO/LO)
505 // and immediates differ by 1.
506 if (FirstCond == SecondCond &&
507 (isGreaterThan(FirstCond) || isLessThan(FirstCond)) &&
508 std::abs(SecondImm - FirstImm) == 1) {
509 // Pick which comparison to adjust to match the other
510 // For GT/HI: adjust the one with smaller immediate
511 // For LT/LO: adjust the one with larger immediate
512 bool adjustFirst = (FirstImm < SecondImm);
513 if (isLessThan(FirstCond)) {
514 adjustFirst = !adjustFirst;
515 }
516
517 MachineInstr *CmpToAdjust = adjustFirst ? FirstCmp : SecondCmp;
518 MachineInstr *CSINCToAdjust = adjustFirst ? FirstCSINC : SecondCSINC;
519 AArch64CC::CondCode CondToAdjust = adjustFirst ? FirstCond : SecondCond;
520 int TargetImm = adjustFirst ? SecondImm : FirstImm;
521
522 CmpInfo AdjustedInfo = adjustCmp(CmpToAdjust, CondToAdjust);
523
524 if (std::get<0>(AdjustedInfo) == TargetImm &&
525 std::get<1>(AdjustedInfo) ==
526 (adjustFirst ? SecondCmp : FirstCmp)->getOpcode()) {
527 LLVM_DEBUG(dbgs() << "Successfully optimizing intra-block CSINC pair\n");
528
529 // Modify the selected CMP and CSINC
530 CmpToAdjust->getOperand(2).setImm(std::get<0>(AdjustedInfo));
531 CmpToAdjust->setDesc(TII->get(std::get<1>(AdjustedInfo)));
532 CSINCToAdjust->getOperand(3).setImm(std::get<2>(AdjustedInfo));
533
534 return true;
535 }
536 }
537
538 return false;
539}
540
541// Optimize across blocks
542bool AArch64ConditionOptimizer::optimizeCrossBlock(MachineBasicBlock &HBB) {
544 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
545 if (TII->analyzeBranch(HBB, TBB, FBB, HeadCond)) {
546 return false;
547 }
548
549 // Equivalence check is to skip loops.
550 if (!TBB || TBB == &HBB) {
551 return false;
552 }
553
555 MachineBasicBlock *TBB_TBB = nullptr, *TBB_FBB = nullptr;
556 if (TII->analyzeBranch(*TBB, TBB_TBB, TBB_FBB, TrueCond)) {
557 return false;
558 }
559
560 MachineInstr *HeadCmpMI = findSuitableCompare(&HBB);
561 if (!HeadCmpMI) {
562 return false;
563 }
564
565 MachineInstr *TrueCmpMI = findSuitableCompare(TBB);
566 if (!TrueCmpMI) {
567 return false;
568 }
569
570 if (!registersMatch(HeadCmpMI, TrueCmpMI)) {
571 return false;
572 }
573
574 AArch64CC::CondCode HeadCmp;
575 if (HeadCond.empty() || !parseCond(HeadCond, HeadCmp)) {
576 return false;
577 }
578
579 AArch64CC::CondCode TrueCmp;
580 if (TrueCond.empty() || !parseCond(TrueCond, TrueCmp)) {
581 return false;
582 }
583
584 const int HeadImm = (int)HeadCmpMI->getOperand(2).getImm();
585 const int TrueImm = (int)TrueCmpMI->getOperand(2).getImm();
586
587 int HeadImmTrueValue = HeadImm;
588 int TrueImmTrueValue = TrueImm;
589
590 LLVM_DEBUG(dbgs() << "Head branch:\n");
591 LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(HeadCmp)
592 << '\n');
593 LLVM_DEBUG(dbgs() << "\timmediate: " << HeadImm << '\n');
594
595 LLVM_DEBUG(dbgs() << "True branch:\n");
596 LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(TrueCmp)
597 << '\n');
598 LLVM_DEBUG(dbgs() << "\timmediate: " << TrueImm << '\n');
599
600 unsigned Opc = HeadCmpMI->getOpcode();
601 if (Opc == AArch64::ADDSWri || Opc == AArch64::ADDSXri)
602 HeadImmTrueValue = -HeadImmTrueValue;
603
604 Opc = TrueCmpMI->getOpcode();
605 if (Opc == AArch64::ADDSWri || Opc == AArch64::ADDSXri)
606 TrueImmTrueValue = -TrueImmTrueValue;
607
608 if (((isGreaterThan(HeadCmp) && isLessThan(TrueCmp)) ||
609 (isLessThan(HeadCmp) && isGreaterThan(TrueCmp))) &&
610 std::abs(TrueImmTrueValue - HeadImmTrueValue) == 2) {
611 // This branch transforms machine instructions that correspond to
612 //
613 // 1) (a > {TrueImm} && ...) || (a < {HeadImm} && ...)
614 // 2) (a < {TrueImm} && ...) || (a > {HeadImm} && ...)
615 //
616 // into
617 //
618 // 1) (a >= {NewImm} && ...) || (a <= {NewImm} && ...)
619 // 2) (a <= {NewImm} && ...) || (a >= {NewImm} && ...)
620
621 CmpInfo HeadCmpInfo = adjustCmp(HeadCmpMI, HeadCmp);
622 CmpInfo TrueCmpInfo = adjustCmp(TrueCmpMI, TrueCmp);
623 if (std::get<0>(HeadCmpInfo) == std::get<0>(TrueCmpInfo) &&
624 std::get<1>(HeadCmpInfo) == std::get<1>(TrueCmpInfo)) {
625 modifyCmp(HeadCmpMI, HeadCmpInfo);
626 modifyCmp(TrueCmpMI, TrueCmpInfo);
627 return true;
628 }
629 } else if (((isGreaterThan(HeadCmp) && isGreaterThan(TrueCmp)) ||
630 (isLessThan(HeadCmp) && isLessThan(TrueCmp))) &&
631 std::abs(TrueImmTrueValue - HeadImmTrueValue) == 1) {
632 // This branch transforms machine instructions that correspond to
633 //
634 // 1) (a > {TrueImm} && ...) || (a > {HeadImm} && ...)
635 // 2) (a < {TrueImm} && ...) || (a < {HeadImm} && ...)
636 //
637 // into
638 //
639 // 1) (a <= {NewImm} && ...) || (a > {NewImm} && ...)
640 // 2) (a < {NewImm} && ...) || (a >= {NewImm} && ...)
641
642 // GT -> GE transformation increases immediate value, so picking the
643 // smaller one; LT -> LE decreases immediate value so invert the choice.
644 bool adjustHeadCond = (HeadImmTrueValue < TrueImmTrueValue);
645 if (isLessThan(HeadCmp)) {
646 adjustHeadCond = !adjustHeadCond;
647 }
648
649 if (adjustHeadCond) {
650 return adjustTo(HeadCmpMI, HeadCmp, TrueCmpMI, TrueImm);
651 } else {
652 return adjustTo(TrueCmpMI, TrueCmp, HeadCmpMI, HeadImm);
653 }
654 }
655 // Other transformation cases almost never occur due to generation of < or >
656 // comparisons instead of <= and >=.
657
658 return false;
659}
660
661bool AArch64ConditionOptimizer::runOnMachineFunction(MachineFunction &MF) {
662 LLVM_DEBUG(dbgs() << "********** AArch64 Conditional Compares **********\n"
663 << "********** Function: " << MF.getName() << '\n');
664 if (skipFunction(MF.getFunction()))
665 return false;
666
669 DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
670 MRI = &MF.getRegInfo();
671
672 bool Changed = false;
673
674 // Visit blocks in dominator tree pre-order. The pre-order enables multiple
675 // cmp-conversions from the same head block.
676 // Note that updateDomTree() modifies the children of the DomTree node
677 // currently being visited. The df_iterator supports that; it doesn't look at
678 // child_begin() / child_end() until after a node has been visited.
679 for (MachineDomTreeNode *I : depth_first(DomTree)) {
680 MachineBasicBlock *HBB = I->getBlock();
681 Changed |= optimizeIntraBlock(*HBB);
682 Changed |= optimizeCrossBlock(*HBB);
683 }
684
685 return Changed;
686}
unsigned const MachineRegisterInfo * MRI
static int getComplementOpc(int Opc)
static bool isGreaterThan(AArch64CC::CondCode Cmp)
static AArch64CC::CondCode getAdjustedCmp(AArch64CC::CondCode Cmp)
static bool isCSINCInstruction(unsigned Opc)
static bool isLessThan(AArch64CC::CondCode Cmp)
static bool isCmpInstruction(unsigned Opc)
static bool parseCond(ArrayRef< MachineOperand > Cond, AArch64CC::CondCode &CC)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file builds on the ADT/GraphTraits.h file to build generic depth first graph iterator.
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
const SmallVectorImpl< MachineOperand > MachineBasicBlock * TBB
const SmallVectorImpl< MachineOperand > & Cond
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:114
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
Definition VPlanSLP.cpp:247
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl< MachineOperand > &Cond, bool AllowModify) const override
Analyze the branching code at the end of MBB, returning true if it cannot be understood (e....
LLVM_ABI iterator getFirstTerminator()
Returns an iterator to the first terminator instruction of this basic block.
iterator_range< succ_iterator > successors()
MachineInstrBundleIterator< MachineInstr > iterator
Analysis pass which computes a MachineDominatorTree.
DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to compute a normal dominat...
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineBasicBlock * getParent() const
LLVM_ABI void setDesc(const MCInstrDesc &TID)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
const MachineOperand & getOperand(unsigned i) const
void setImm(int64_t immVal)
int64_t getImm() const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
TargetInstrInfo - Interface to description of machine instruction set.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetRegisterInfo * getRegisterInfo() const =0
Return the target's register information.
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
static const char * getCondCodeName(CondCode Code)
static unsigned getShiftValue(unsigned Imm)
getShiftValue - Extract the shift value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:207
FunctionPass * createAArch64ConditionOptimizerPass()
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
DomTreeNodeBase< MachineBasicBlock > MachineDomTreeNode
iterator_range< df_iterator< T > > depth_first(const T &G)
IterT prev_nodbg(IterT It, IterT Begin, bool SkipPseudoOp=true)
Decrement It, then continue decrementing it while it points to a debug instruction.
LLVM_ABI Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.