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
93using namespace llvm;
94
95#define DEBUG_TYPE "aarch64-condopt"
96
97STATISTIC(NumConditionsAdjusted, "Number of conditions adjusted");
98
99namespace {
100
101/// Bundles the parameters needed to adjust a comparison instruction.
102struct CmpInfo {
103 int Imm;
104 unsigned Opc;
106};
107
108class AArch64ConditionOptimizer : public MachineFunctionPass {
109 const TargetInstrInfo *TII;
110 const TargetRegisterInfo *TRI;
111 MachineDominatorTree *DomTree;
112 const MachineRegisterInfo *MRI;
113
114public:
115 static char ID;
116
117 AArch64ConditionOptimizer() : MachineFunctionPass(ID) {}
118
119 void getAnalysisUsage(AnalysisUsage &AU) const override;
120 bool canAdjustCmp(MachineInstr &CmpMI);
121 bool registersMatch(MachineInstr *FirstMI, MachineInstr *SecondMI);
122 bool nzcvLivesOut(MachineBasicBlock *MBB);
123 MachineInstr *getBccTerminator(MachineBasicBlock *MBB);
124 MachineInstr *findAdjustableCmp(MachineInstr *CondMI);
125 CmpInfo getAdjustedCmpInfo(MachineInstr *CmpMI, AArch64CC::CondCode Cmp);
126 void modifyCmp(MachineInstr *CmpMI, const CmpInfo &Info);
127 bool adjustTo(MachineInstr *CmpMI, AArch64CC::CondCode Cmp, MachineInstr *To,
128 int ToImm);
129 bool optimizeIntraBlock(MachineBasicBlock &MBB);
130 bool optimizeCrossBlock(MachineBasicBlock &HBB);
131 bool runOnMachineFunction(MachineFunction &MF) override;
132
133 StringRef getPassName() const override {
134 return "AArch64 Condition Optimizer";
135 }
136};
137
138} // end anonymous namespace
139
140char AArch64ConditionOptimizer::ID = 0;
141
142INITIALIZE_PASS_BEGIN(AArch64ConditionOptimizer, "aarch64-condopt",
143 "AArch64 CondOpt Pass", false, false)
145INITIALIZE_PASS_END(AArch64ConditionOptimizer, "aarch64-condopt",
146 "AArch64 CondOpt Pass", false, false)
147
149 return new AArch64ConditionOptimizer();
150}
151
152void AArch64ConditionOptimizer::getAnalysisUsage(AnalysisUsage &AU) const {
156}
157
158// Verify that the MI's immediate is adjustable and it only sets flags (pure
159// cmp)
160bool AArch64ConditionOptimizer::canAdjustCmp(MachineInstr &CmpMI) {
161 unsigned ShiftAmt = AArch64_AM::getShiftValue(CmpMI.getOperand(3).getImm());
162 if (!CmpMI.getOperand(2).isImm()) {
163 LLVM_DEBUG(dbgs() << "Immediate of cmp is symbolic, " << CmpMI << '\n');
164 return false;
165 } else if (CmpMI.getOperand(2).getImm() << ShiftAmt >= 0xfff) {
166 LLVM_DEBUG(dbgs() << "Immediate of cmp may be out of range, " << CmpMI
167 << '\n');
168 return false;
169 } else if (!MRI->use_nodbg_empty(CmpMI.getOperand(0).getReg())) {
170 LLVM_DEBUG(dbgs() << "Destination of cmp is not dead, " << CmpMI << '\n');
171 return false;
172 }
173
174 return true;
175}
176
177// Ensure both compare MIs use the same register, tracing through copies.
178bool AArch64ConditionOptimizer::registersMatch(MachineInstr *FirstMI,
179 MachineInstr *SecondMI) {
180 Register FirstReg = FirstMI->getOperand(1).getReg();
181 Register SecondReg = SecondMI->getOperand(1).getReg();
182 Register FirstCmpReg =
183 FirstReg.isVirtual() ? TRI->lookThruCopyLike(FirstReg, MRI) : FirstReg;
184 Register SecondCmpReg =
185 SecondReg.isVirtual() ? TRI->lookThruCopyLike(SecondReg, MRI) : SecondReg;
186 if (FirstCmpReg != SecondCmpReg) {
187 LLVM_DEBUG(dbgs() << "CMPs compare different registers\n");
188 return false;
189 }
190
191 return true;
192}
193
194// Check if NZCV lives out to any successor block.
195bool AArch64ConditionOptimizer::nzcvLivesOut(MachineBasicBlock *MBB) {
196 for (auto *SuccBB : MBB->successors()) {
197 if (SuccBB->isLiveIn(AArch64::NZCV)) {
198 LLVM_DEBUG(dbgs() << "NZCV live into successor "
199 << printMBBReference(*SuccBB) << " from "
200 << printMBBReference(*MBB) << '\n');
201 return true;
202 }
203 }
204 return false;
205}
206
207// Returns true if the opcode is a comparison instruction (CMP/CMN).
208static bool isCmpInstruction(unsigned Opc) {
209 switch (Opc) {
210 // cmp is an alias for SUBS with a dead destination register.
211 case AArch64::SUBSWri:
212 case AArch64::SUBSXri:
213 // cmp is an alias for ADDS with a dead destination register.
214 case AArch64::ADDSWri:
215 case AArch64::ADDSXri:
216 return true;
217 default:
218 return false;
219 }
220}
221
222static bool isCSINCInstruction(unsigned Opc) {
223 return Opc == AArch64::CSINCWr || Opc == AArch64::CSINCXr;
224}
225
226// Returns the Bcc terminator if present, otherwise nullptr.
227MachineInstr *
228AArch64ConditionOptimizer::getBccTerminator(MachineBasicBlock *MBB) {
230 if (Term == MBB->end()) {
231 LLVM_DEBUG(dbgs() << "No terminator in " << printMBBReference(*MBB)
232 << '\n');
233 return nullptr;
234 }
235
236 if (Term->getOpcode() != AArch64::Bcc) {
237 LLVM_DEBUG(dbgs() << "Non-Bcc terminator in " << printMBBReference(*MBB)
238 << ": " << *Term);
239 return nullptr;
240 }
241
242 return &*Term;
243}
244
245// Find the CMP instruction controlling the given conditional instruction and
246// ensure it can be adjusted for CSE optimization. Searches backward from
247// CondMI, ensuring no NZCV interference. Returns nullptr if no suitable CMP
248// is found or if adjustments are not safe.
249MachineInstr *
250AArch64ConditionOptimizer::findAdjustableCmp(MachineInstr *CondMI) {
251 assert(CondMI && "CondMI cannot be null");
252 MachineBasicBlock *MBB = CondMI->getParent();
253
254 // Search backward from the conditional to find the instruction controlling
255 // it.
257 It = MachineBasicBlock::iterator(CondMI);
258 It != B;) {
259 It = prev_nodbg(It, B);
260 MachineInstr &I = *It;
261 assert(!I.isTerminator() && "Spurious terminator");
262 // Ensure there is no use of NZCV between CMP and conditional.
263 if (I.readsRegister(AArch64::NZCV, /*TRI=*/nullptr))
264 return nullptr;
265
266 if (isCmpInstruction(I.getOpcode())) {
267 if (!canAdjustCmp(I)) {
268 return nullptr;
269 }
270 return &I;
271 }
272
273 if (I.modifiesRegister(AArch64::NZCV, /*TRI=*/nullptr))
274 return nullptr;
275 }
276 LLVM_DEBUG(dbgs() << "Flags not defined in " << printMBBReference(*MBB)
277 << '\n');
278 return nullptr;
279}
280
281// Changes opcode adds <-> subs considering register operand width.
282static int getComplementOpc(int Opc) {
283 switch (Opc) {
284 case AArch64::ADDSWri: return AArch64::SUBSWri;
285 case AArch64::ADDSXri: return AArch64::SUBSXri;
286 case AArch64::SUBSWri: return AArch64::ADDSWri;
287 case AArch64::SUBSXri: return AArch64::ADDSXri;
288 default:
289 llvm_unreachable("Unexpected opcode");
290 }
291}
292
293// Changes form of comparison inclusive <-> exclusive.
295 switch (Cmp) {
296 case AArch64CC::GT:
297 return AArch64CC::GE;
298 case AArch64CC::GE:
299 return AArch64CC::GT;
300 case AArch64CC::LT:
301 return AArch64CC::LE;
302 case AArch64CC::LE:
303 return AArch64CC::LT;
304 case AArch64CC::HI:
305 return AArch64CC::HS;
306 case AArch64CC::HS:
307 return AArch64CC::HI;
308 case AArch64CC::LO:
309 return AArch64CC::LS;
310 case AArch64CC::LS:
311 return AArch64CC::LO;
312 default:
313 llvm_unreachable("Unexpected condition code");
314 }
315}
316
317// Returns the adjusted immediate, opcode, and condition code for switching
318// between inclusive/exclusive forms (GT <-> GE, LT <-> LE).
319CmpInfo AArch64ConditionOptimizer::getAdjustedCmpInfo(MachineInstr *CmpMI,
321 unsigned Opc = CmpMI->getOpcode();
322
323 bool IsSigned = Cmp == AArch64CC::GT || Cmp == AArch64CC::GE ||
325
326 // CMN (compare with negative immediate) is an alias to ADDS (as
327 // "operand - negative" == "operand + positive")
328 bool Negative = (Opc == AArch64::ADDSWri || Opc == AArch64::ADDSXri);
329
330 int Correction = (Cmp == AArch64CC::GT || Cmp == AArch64CC::HI) ? 1 : -1;
331 // Negate Correction value for comparison with negative immediate (CMN).
332 if (Negative) {
333 Correction = -Correction;
334 }
335
336 const int OldImm = (int)CmpMI->getOperand(2).getImm();
337 const int NewImm = std::abs(OldImm + Correction);
338
339 // Bail out on cmn 0 (ADDS with immediate 0). It is a valid instruction but
340 // doesn't set flags in a way we can safely transform, so skip optimization.
341 if (OldImm == 0 && Negative)
342 return {OldImm, Opc, Cmp};
343
344 if ((OldImm == 1 && Negative && Correction == -1) ||
345 (OldImm == 0 && Correction == -1)) {
346 // If we change opcodes for unsigned comparisons, this means we did an
347 // unsigned wrap (e.g., 0 wrapping to 0xFFFFFFFF), so return the old cmp.
348 // Note: For signed comparisons, opcode changes (cmn 1 ↔ cmp 0) are valid.
349 if (!IsSigned)
350 return {OldImm, Opc, Cmp};
352 }
353
354 return {NewImm, Opc, getAdjustedCmp(Cmp)};
355}
356
357// Applies changes to comparison instruction suggested by getAdjustedCmpInfo().
358void AArch64ConditionOptimizer::modifyCmp(MachineInstr *CmpMI,
359 const CmpInfo &Info) {
360 MachineBasicBlock *const MBB = CmpMI->getParent();
361
362 // Change immediate in comparison instruction (ADDS or SUBS).
363 BuildMI(*MBB, CmpMI, CmpMI->getDebugLoc(), TII->get(Info.Opc))
364 .add(CmpMI->getOperand(0))
365 .add(CmpMI->getOperand(1))
366 .addImm(Info.Imm)
367 .add(CmpMI->getOperand(3));
368 CmpMI->eraseFromParent();
369
370 // The fact that this comparison was picked ensures that it's related to the
371 // first terminator instruction.
372 MachineInstr &BrMI = *MBB->getFirstTerminator();
373
374 // Change condition in branch instruction.
375 BuildMI(*MBB, BrMI, BrMI.getDebugLoc(), TII->get(AArch64::Bcc))
376 .addImm(Info.CC)
377 .add(BrMI.getOperand(1));
378 BrMI.eraseFromParent();
379
380 ++NumConditionsAdjusted;
381}
382
383// Parse a condition code returned by analyzeBranch, and compute the CondCode
384// corresponding to TBB.
385// Returns true if parsing was successful, otherwise false is returned.
387 // A normal br.cond simply has the condition code.
388 if (Cond[0].getImm() != -1) {
389 assert(Cond.size() == 1 && "Unknown Cond array format");
390 CC = (AArch64CC::CondCode)(int)Cond[0].getImm();
391 return true;
392 }
393 return false;
394}
395
396// Adjusts one cmp instruction to another one if result of adjustment will allow
397// CSE. Returns true if compare instruction was changed, otherwise false is
398// returned.
399bool AArch64ConditionOptimizer::adjustTo(MachineInstr *CmpMI,
400 AArch64CC::CondCode Cmp, MachineInstr *To, int ToImm)
401{
402 CmpInfo Info = getAdjustedCmpInfo(CmpMI, Cmp);
403 if (Info.Imm == ToImm && Info.Opc == To->getOpcode()) {
404 modifyCmp(CmpMI, Info);
405 return true;
406 }
407 return false;
408}
409
411 return Cmp == AArch64CC::GT || Cmp == AArch64CC::HI;
412}
413
415 return Cmp == AArch64CC::LT || Cmp == AArch64CC::LO;
416}
417
418// This function transforms two CMP+CSINC pairs within the same basic block
419// when both conditions are the same (GT/GT or LT/LT) and immediates differ
420// by 1.
421//
422// Example transformation:
423// cmp w8, #10
424// csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
425// cmp w8, #9
426// csinc w10, w0, w1, gt ; w10 = (w8 > 9) ? w0 : w1+1
427//
428// Into:
429// cmp w8, #10
430// csinc w9, w0, w1, gt ; w9 = (w8 > 10) ? w0 : w1+1
431// csinc w10, w0, w1, ge ; w10 = (w8 >= 10) ? w0 : w1+1
432//
433// The second CMP is eliminated, enabling CSE to remove the redundant
434// comparison.
435bool AArch64ConditionOptimizer::optimizeIntraBlock(MachineBasicBlock &MBB) {
436 MachineInstr *FirstCSINC = nullptr;
437 MachineInstr *SecondCSINC = nullptr;
438
439 // Find two CSINC instructions
440 for (MachineInstr &MI : MBB) {
441 if (isCSINCInstruction(MI.getOpcode())) {
442 if (!FirstCSINC) {
443 FirstCSINC = &MI;
444 } else if (!SecondCSINC) {
445 SecondCSINC = &MI;
446 break; // Found both
447 }
448 }
449 }
450
451 if (!FirstCSINC || !SecondCSINC) {
452 return false;
453 }
454
455 // Since we may modify cmps in this MBB, make sure NZCV does not live out.
456 if (nzcvLivesOut(&MBB))
457 return false;
458
459 // Find the CMPs controlling each CSINC
460 MachineInstr *FirstCmpMI = findAdjustableCmp(FirstCSINC);
461 MachineInstr *SecondCmpMI = findAdjustableCmp(SecondCSINC);
462 if (!FirstCmpMI || !SecondCmpMI)
463 return false;
464
465 // Ensure we have two distinct CMPs
466 if (FirstCmpMI == SecondCmpMI) {
467 LLVM_DEBUG(dbgs() << "Both CSINCs already controlled by same CMP\n");
468 return false;
469 }
470
471 if (!registersMatch(FirstCmpMI, SecondCmpMI))
472 return false;
473
474 // Check that nothing else modifies the flags between the first CMP and second
475 // conditional
476 for (auto It = std::next(MachineBasicBlock::iterator(FirstCmpMI));
477 It != std::next(MachineBasicBlock::iterator(SecondCSINC)); ++It) {
478 if (&*It != SecondCmpMI &&
479 It->modifiesRegister(AArch64::NZCV, /*TRI=*/nullptr)) {
480 LLVM_DEBUG(dbgs() << "Flags modified between CMPs by: " << *It << '\n');
481 return false;
482 }
483 }
484
485 // Check flags aren't read after second conditional within the same block
486 for (auto It = std::next(MachineBasicBlock::iterator(SecondCSINC));
487 It != MBB.end(); ++It) {
488 if (It->readsRegister(AArch64::NZCV, /*TRI=*/nullptr)) {
489 LLVM_DEBUG(dbgs() << "Flags read after second CSINC by: " << *It << '\n');
490 return false;
491 }
492 }
493
494 // Extract condition codes from both CSINCs (operand 3)
495 AArch64CC::CondCode FirstCond =
496 (AArch64CC::CondCode)(int)FirstCSINC->getOperand(3).getImm();
497 AArch64CC::CondCode SecondCond =
498 (AArch64CC::CondCode)(int)SecondCSINC->getOperand(3).getImm();
499
500 const int FirstImm = (int)FirstCmpMI->getOperand(2).getImm();
501 const int SecondImm = (int)SecondCmpMI->getOperand(2).getImm();
502
503 LLVM_DEBUG(dbgs() << "Comparing intra-block CSINCs: "
504 << AArch64CC::getCondCodeName(FirstCond) << " #" << FirstImm
505 << " and " << AArch64CC::getCondCodeName(SecondCond) << " #"
506 << SecondImm << '\n');
507
508 // Check if both conditions are the same (GT/GT, LT/LT, HI/HI, LO/LO)
509 // and immediates differ by 1.
510 if (FirstCond == SecondCond &&
511 (isGreaterThan(FirstCond) || isLessThan(FirstCond)) &&
512 std::abs(SecondImm - FirstImm) == 1) {
513 // Pick which comparison to adjust to match the other
514 // For GT/HI: adjust the one with smaller immediate
515 // For LT/LO: adjust the one with larger immediate
516 bool adjustFirst = (FirstImm < SecondImm);
517 if (isLessThan(FirstCond)) {
518 adjustFirst = !adjustFirst;
519 }
520
521 MachineInstr *CmpToAdjust = adjustFirst ? FirstCmpMI : SecondCmpMI;
522 MachineInstr *CSINCToAdjust = adjustFirst ? FirstCSINC : SecondCSINC;
523 AArch64CC::CondCode CondToAdjust = adjustFirst ? FirstCond : SecondCond;
524 int TargetImm = adjustFirst ? SecondImm : FirstImm;
525
526 CmpInfo Adj = getAdjustedCmpInfo(CmpToAdjust, CondToAdjust);
527
528 if (Adj.Imm == TargetImm &&
529 Adj.Opc == (adjustFirst ? SecondCmpMI : FirstCmpMI)->getOpcode()) {
530 LLVM_DEBUG(dbgs() << "Successfully optimizing intra-block CSINC pair\n");
531
532 // Modify the selected CMP and CSINC
533 CmpToAdjust->getOperand(2).setImm(Adj.Imm);
534 CmpToAdjust->setDesc(TII->get(Adj.Opc));
535 CSINCToAdjust->getOperand(3).setImm(Adj.CC);
536
537 return true;
538 }
539 }
540
541 return false;
542}
543
544// Optimize across blocks
545bool AArch64ConditionOptimizer::optimizeCrossBlock(MachineBasicBlock &HBB) {
547 MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
548 if (TII->analyzeBranch(HBB, TBB, FBB, HeadCond)) {
549 return false;
550 }
551
552 // Equivalence check is to skip loops.
553 if (!TBB || TBB == &HBB) {
554 return false;
555 }
556
558 MachineBasicBlock *TBB_TBB = nullptr, *TBB_FBB = nullptr;
559 if (TII->analyzeBranch(*TBB, TBB_TBB, TBB_FBB, TrueCond)) {
560 return false;
561 }
562
563 MachineInstr *HeadBrMI = getBccTerminator(&HBB);
564 MachineInstr *TrueBrMI = getBccTerminator(TBB);
565 if (!HeadBrMI || !TrueBrMI)
566 return false;
567
568 // Since we may modify cmps in these blocks, make sure NZCV does not live out.
569 if (nzcvLivesOut(&HBB) || nzcvLivesOut(TBB))
570 return false;
571
572 MachineInstr *HeadCmpMI = findAdjustableCmp(HeadBrMI);
573 MachineInstr *TrueCmpMI = findAdjustableCmp(TrueBrMI);
574 if (!HeadCmpMI || !TrueCmpMI)
575 return false;
576
577 if (!registersMatch(HeadCmpMI, TrueCmpMI))
578 return false;
579
580 AArch64CC::CondCode HeadCmp;
581 if (HeadCond.empty() || !parseCond(HeadCond, HeadCmp)) {
582 return false;
583 }
584
585 AArch64CC::CondCode TrueCmp;
586 if (TrueCond.empty() || !parseCond(TrueCond, TrueCmp)) {
587 return false;
588 }
589
590 const int HeadImm = (int)HeadCmpMI->getOperand(2).getImm();
591 const int TrueImm = (int)TrueCmpMI->getOperand(2).getImm();
592
593 int HeadImmTrueValue = HeadImm;
594 int TrueImmTrueValue = TrueImm;
595
596 LLVM_DEBUG(dbgs() << "Head branch:\n");
597 LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(HeadCmp)
598 << '\n');
599 LLVM_DEBUG(dbgs() << "\timmediate: " << HeadImm << '\n');
600
601 LLVM_DEBUG(dbgs() << "True branch:\n");
602 LLVM_DEBUG(dbgs() << "\tcondition: " << AArch64CC::getCondCodeName(TrueCmp)
603 << '\n');
604 LLVM_DEBUG(dbgs() << "\timmediate: " << TrueImm << '\n');
605
606 unsigned Opc = HeadCmpMI->getOpcode();
607 if (Opc == AArch64::ADDSWri || Opc == AArch64::ADDSXri)
608 HeadImmTrueValue = -HeadImmTrueValue;
609
610 Opc = TrueCmpMI->getOpcode();
611 if (Opc == AArch64::ADDSWri || Opc == AArch64::ADDSXri)
612 TrueImmTrueValue = -TrueImmTrueValue;
613
614 if (((isGreaterThan(HeadCmp) && isLessThan(TrueCmp)) ||
615 (isLessThan(HeadCmp) && isGreaterThan(TrueCmp))) &&
616 std::abs(TrueImmTrueValue - HeadImmTrueValue) == 2) {
617 // This branch transforms machine instructions that correspond to
618 //
619 // 1) (a > {TrueImm} && ...) || (a < {HeadImm} && ...)
620 // 2) (a < {TrueImm} && ...) || (a > {HeadImm} && ...)
621 //
622 // into
623 //
624 // 1) (a >= {NewImm} && ...) || (a <= {NewImm} && ...)
625 // 2) (a <= {NewImm} && ...) || (a >= {NewImm} && ...)
626
627 CmpInfo HeadCmpInfo = getAdjustedCmpInfo(HeadCmpMI, HeadCmp);
628 CmpInfo TrueCmpInfo = getAdjustedCmpInfo(TrueCmpMI, TrueCmp);
629 if (HeadCmpInfo.Imm == TrueCmpInfo.Imm &&
630 HeadCmpInfo.Opc == TrueCmpInfo.Opc) {
631 modifyCmp(HeadCmpMI, HeadCmpInfo);
632 modifyCmp(TrueCmpMI, TrueCmpInfo);
633 return true;
634 }
635 } else if (((isGreaterThan(HeadCmp) && isGreaterThan(TrueCmp)) ||
636 (isLessThan(HeadCmp) && isLessThan(TrueCmp))) &&
637 std::abs(TrueImmTrueValue - HeadImmTrueValue) == 1) {
638 // This branch transforms machine instructions that correspond to
639 //
640 // 1) (a > {TrueImm} && ...) || (a > {HeadImm} && ...)
641 // 2) (a < {TrueImm} && ...) || (a < {HeadImm} && ...)
642 //
643 // into
644 //
645 // 1) (a <= {NewImm} && ...) || (a > {NewImm} && ...)
646 // 2) (a < {NewImm} && ...) || (a >= {NewImm} && ...)
647
648 // GT -> GE transformation increases immediate value, so picking the
649 // smaller one; LT -> LE decreases immediate value so invert the choice.
650 bool adjustHeadCond = (HeadImmTrueValue < TrueImmTrueValue);
651 if (isLessThan(HeadCmp)) {
652 adjustHeadCond = !adjustHeadCond;
653 }
654
655 if (adjustHeadCond) {
656 return adjustTo(HeadCmpMI, HeadCmp, TrueCmpMI, TrueImm);
657 } else {
658 return adjustTo(TrueCmpMI, TrueCmp, HeadCmpMI, HeadImm);
659 }
660 }
661 // Other transformation cases almost never occur due to generation of < or >
662 // comparisons instead of <= and >=.
663
664 return false;
665}
666
667bool AArch64ConditionOptimizer::runOnMachineFunction(MachineFunction &MF) {
668 LLVM_DEBUG(dbgs() << "********** AArch64 Conditional Compares **********\n"
669 << "********** Function: " << MF.getName() << '\n');
670 if (skipFunction(MF.getFunction()))
671 return false;
672
675 DomTree = &getAnalysis<MachineDominatorTreeWrapperPass>().getDomTree();
676 MRI = &MF.getRegInfo();
677
678 bool Changed = false;
679
680 // Visit blocks in dominator tree pre-order. The pre-order enables multiple
681 // cmp-conversions from the same head block.
682 // Note that updateDomTree() modifies the children of the DomTree node
683 // currently being visited. The df_iterator supports that; it doesn't look at
684 // child_begin() / child_end() until after a node has been visited.
685 for (MachineDomTreeNode *I : depth_first(DomTree)) {
686 MachineBasicBlock *HBB = I->getBlock();
687 Changed |= optimizeIntraBlock(*HBB);
688 Changed |= optimizeCrossBlock(*HBB);
689 }
690
691 return Changed;
692}
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
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.
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.
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
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.
bool use_nodbg_empty(Register RegNo) const
use_nodbg_empty - Return true if there are no non-Debug instructions using the specified register.
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
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.
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.