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