llvm.org GIT mirror llvm / a935926
[globalisel][combiner] Make the CombinerChangeObserver a MachineFunction::Delegate Summary: This allows us to register it with the MachineFunction delegate and be notified automatically about erasure and creation of instructions. However, we still need explicit notification for modifications such as those caused by setReg() or replaceRegWith(). There is a catch with this though. The notification for creation is delivered before any operands can be added. While appropriate for scheduling combiner work. This is unfortunate for debug output since an opcode by itself doesn't provide sufficient information on what happened. As a result, the work list remembers the instructions (when debug output is requested) and emits a more complete dump later. Another nit is that the MachineFunction::Delegate provides const pointers which is inconvenient since we want to use it to schedule future modification. To resolve this GISelWorkList now has an optional pointer to the MachineFunction which describes the scope of the work it is permitted to schedule. If a given MachineInstr* is in this function then it is permitted to schedule work to be performed on the MachineInstr's. An alternative to this would be to remove the const from the MachineFunction::Delegate interface, however delegates are not permitted to modify the MachineInstr's they receive. In addition to this, the observer has three interface changes. * erasedInstr() is now erasingInstr() to indicate it is about to be erased but still exists at the moment. * changingInstr() and changedInstr() have been added to report changes before and after they are made. This allows us to trace the changes in the debug output. * As a convenience changingAllUsesOfReg() and finishedChangingAllUsesOfReg() will report changingInstr() and changedInstr() for each use of a given register. This is primarily useful for changes caused by MachineRegisterInfo::replaceRegWith() With this in place, both combine rules have been updated to report their changes to the observer. Finally, make some cosmetic changes to the debug output and make Combiner and CombinerHelp Reviewers: aditya_nandakumar, bogner, volkan, rtereshin, javed.absar Reviewed By: aditya_nandakumar Subscribers: mgorny, rovka, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D52947 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@349167 91177308-0d34-0410-b5e6-96231b3b80d8 Daniel Sanders 1 year, 10 months ago
11 changed file(s) with 253 addition(s) and 74 deletion(s). Raw diff Collapse all Expand all
None //== llvm/CodeGen/GlobalISel/CombinerHelper.h -------------- -*- C++ -*-==//
0 //===-- llvm/CodeGen/GlobalISel/CombinerHelper.h --------------*- C++ -*-===//
11 //
22 // The LLVM Compiler Infrastructure
33 //
2323 class MachineIRBuilder;
2424 class MachineRegisterInfo;
2525 class MachineInstr;
26 class MachineOperand;
2627
2728 class CombinerHelper {
2829 MachineIRBuilder &Builder;
2930 MachineRegisterInfo &MRI;
3031 GISelChangeObserver &Observer;
3132
32 void scheduleForVisit(MachineInstr &MI);
33
3433 public:
3534 CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B);
35
36 /// MachineRegisterInfo::replaceRegWith() and inform the observer of the changes
37 void replaceRegWith(MachineRegisterInfo &MRI, unsigned FromReg, unsigned ToReg) const;
38
39 /// Replace a single register operand with a new register and inform the
40 /// observer of the changes.
41 void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp,
42 unsigned ToReg) const;
3643
3744 /// If \p MI is COPY, try to combine it.
3845 /// Returns true if MI changed.
4242 /// illegal ops that are created.
4343 bool LegalizeIllegalOps; // TODO: Make use of this.
4444 const LegalizerInfo *LInfo;
45
46 /// Attempt to combine instructions using MI as the root.
47 ///
48 /// Use Observer to report the creation, modification, and erasure of
49 /// instructions. GISelChangeObserver will automatically report certain
50 /// kinds of operations. These operations are:
51 /// * Instructions that are newly inserted into the MachineFunction
52 /// * Instructions that are erased from the MachineFunction.
53 ///
54 /// However, it is important to report instruction modification and this is
55 /// not automatic.
4556 virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
4657 MachineIRBuilder &B) const = 0;
4758 };
None //== ----- llvm/CodeGen/GlobalISel/GISelChangeObserver.h ---------------------
1 //== //
0 //===----- llvm/CodeGen/GlobalISel/GISelChangeObserver.h ------------------===//
21 //
32 // The LLVM Compiler Infrastructure
43 //
1413 #ifndef LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H
1514 #define LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H
1615
16 #include "llvm/ADT/SmallPtrSet.h"
17
1718 namespace llvm {
19 class MachineInstr;
20 class MachineRegisterInfo;
21
1822 /// Abstract class that contains various methods for clients to notify about
1923 /// changes. This should be the preferred way for APIs to notify changes.
2024 /// Typically calling erasingInstr/createdInstr multiple times should not affect
2125 /// the result. The observer would likely need to check if it was already
2226 /// notified earlier (consider using GISelWorkList).
23 class MachineInstr;
2427 class GISelChangeObserver {
28 SmallPtrSet ChangingAllUsesOfReg;
29
2530 public:
2631 virtual ~GISelChangeObserver() {}
2732
2833 /// An instruction is about to be erased.
29 virtual void erasingInstr(MachineInstr &MI) = 0;
34 virtual void erasingInstr(const MachineInstr &MI) = 0;
3035 /// An instruction was created and inserted into the function.
31 virtual void createdInstr(MachineInstr &MI) = 0;
36 virtual void createdInstr(const MachineInstr &MI) = 0;
3237 /// This instruction is about to be mutated in some way.
33 virtual void changingInstr(MachineInstr &MI) = 0;
38 virtual void changingInstr(const MachineInstr &MI) = 0;
3439 /// This instruction was mutated in some way.
35 virtual void changedInstr(MachineInstr &MI) = 0;
40 virtual void changedInstr(const MachineInstr &MI) = 0;
41
42 /// All the instructions using the given register are being changed.
43 /// For convenience, finishedChangingAllUsesOfReg() will report the completion
44 /// of the changes. The use list may change between this call and
45 /// finishedChangingAllUsesOfReg().
46 void changingAllUsesOfReg(const MachineRegisterInfo &MRI, unsigned Reg);
47 /// All instructions reported as changing by changingAllUsesOfReg() have
48 /// finished being changed.
49 void finishedChangingAllUsesOfReg();
50
3651 };
3752
3853 } // namespace llvm
1717
1818 class MachineInstr;
1919
20 // Worklist which mostly works similar to InstCombineWorkList, but on MachineInstrs.
21 // The main difference with something like a SetVector is that erasing an element doesn't
22 // move all elements over one place - instead just nulls out the element of the vector.
23 // FIXME: Does it make sense to factor out common code with the instcombinerWorkList?
20 // Worklist which mostly works similar to InstCombineWorkList, but on
21 // MachineInstrs. The main difference with something like a SetVector is that
22 // erasing an element doesn't move all elements over one place - instead just
23 // nulls out the element of the vector.
24 //
25 // This worklist operates on instructions within a particular function. This is
26 // important for acquiring the rights to modify/replace instructions a
27 // GISelChangeObserver reports as the observer doesn't have the right to make
28 // changes to the instructions it sees so we use our access to the
29 // MachineFunction to establish that it's ok to add a given instruction to the
30 // worklist.
31 //
32 // FIXME: Does it make sense to factor out common code with the
33 // instcombinerWorkList?
2434 template
2535 class GISelWorkList {
26 SmallVector Worklist;
27 DenseMap WorklistMap;
36 MachineFunction *MF;
37 SmallVector Worklist;
38 DenseMap WorklistMap;
2839
2940 public:
30 GISelWorkList() = default;
41 GISelWorkList(MachineFunction *MF) : MF(MF) {}
3142
3243 bool empty() const { return WorklistMap.empty(); }
3344
3445 unsigned size() const { return WorklistMap.size(); }
3546
36 /// Add - Add the specified instruction to the worklist if it isn't already
37 /// in it.
47 /// Add the specified instruction to the worklist if it isn't already in it.
3848 void insert(MachineInstr *I) {
39 if (WorklistMap.try_emplace(I, Worklist.size()).second) {
40 Worklist.push_back(I);
49 // It would be safe to add this instruction to the worklist regardless but
50 // for consistency with the const version, check that the instruction we're
51 // adding would have been accepted if we were given a const pointer instead.
52 insert(const_cast(I));
53 }
54
55 void insert(const MachineInstr *I) {
56 // Confirm we'd be able to find the non-const pointer we want to schedule if
57 // we wanted to. We have the right to schedule work that may modify any
58 // instruction in MF.
59 assert(I->getParent() && "Expected parent BB");
60 assert(I->getParent()->getParent() && "Expected parent function");
61 assert((!MF || I->getParent()->getParent() == MF) &&
62 "Expected parent function to be current function or not given");
63
64 // But don't actually do the search since we can derive it from the const
65 // pointer.
66 MachineInstr *NonConstI = const_cast(I);
67 if (WorklistMap.try_emplace(NonConstI, Worklist.size()).second) {
68 Worklist.push_back(NonConstI);
4169 }
4270 }
4371
44 /// Remove - remove I from the worklist if it exists.
45 void remove(MachineInstr *I) {
72 /// Remove I from the worklist if it exists.
73 void remove(const MachineInstr *I) {
4674 auto It = WorklistMap.find(I);
4775 if (It == WorklistMap.end()) return; // Not in worklist.
4876
22 GlobalISel.cpp
33 Combiner.cpp
44 CombinerHelper.cpp
5 GISelChangeObserver.cpp
56 IRTranslator.cpp
67 InstructionSelect.cpp
78 InstructionSelector.cpp
None //===-- lib/CodeGen/GlobalISel/GICombiner.cpp -----------------------===//
0 //===-- lib/CodeGen/GlobalISel/Combiner.cpp -------------------------------===//
11 //
22 // The LLVM Compiler Infrastructure
33 //
2828 namespace {
2929 /// This class acts as the glue the joins the CombinerHelper to the overall
3030 /// Combine algorithm. The CombinerHelper is intended to report the
31 /// modifications it makes to the MIR to the CombinerChangeObserver and the
31 /// modifications it makes to the MIR to the GISelChangeObserver and the
3232 /// observer subclass will act on these events. In this case, instruction
3333 /// erasure will cancel any future visits to the erased instruction and
3434 /// instruction creation will schedule that instruction for a future visit.
3535 /// Other Combiner implementations may require more complex behaviour from
36 /// their CombinerChangeObserver subclass.
37 class WorkListMaintainer : public GISelChangeObserver {
36 /// their GISelChangeObserver subclass.
37 class WorkListMaintainer : public GISelChangeObserver,
38 public MachineFunction::Delegate {
3839 using WorkListTy = GISelWorkList<512>;
40 MachineFunction &MF;
3941 WorkListTy &WorkList;
42 /// The instructions that have been created but we want to report once they
43 /// have their operands. This is only maintained if debug output is requested.
44 SmallPtrSet CreatedInstrs;
4045
4146 public:
42 WorkListMaintainer(WorkListTy &WorkList) : WorkList(WorkList) {}
43 virtual ~WorkListMaintainer() {}
47 WorkListMaintainer(MachineFunction &MF, WorkListTy &WorkList)
48 : GISelChangeObserver(), MF(MF), WorkList(WorkList) {
49 MF.setDelegate(this);
50 }
51 virtual ~WorkListMaintainer() {
52 MF.resetDelegate(this);
53 }
4454
45 void erasingInstr(MachineInstr &MI) override {
55 void erasingInstr(const MachineInstr &MI) override {
4656 LLVM_DEBUG(dbgs() << "Erased: " << MI << "\n");
4757 WorkList.remove(&MI);
4858 }
49 void createdInstr(MachineInstr &MI) override {
50 LLVM_DEBUG(dbgs() << "Created: " << MI << "\n");
59 void createdInstr(const MachineInstr &MI) override {
60 LLVM_DEBUG(dbgs() << "Creating: " << MI << "\n");
61 WorkList.insert(&MI);
62 LLVM_DEBUG(CreatedInstrs.insert(&MI));
63 }
64 void changingInstr(const MachineInstr &MI) override {
65 LLVM_DEBUG(dbgs() << "Changing: " << MI << "\n");
5166 WorkList.insert(&MI);
5267 }
53 void changingInstr(MachineInstr &MI) override {
54 LLVM_DEBUG(dbgs() << "Changing: " << MI << "\n");
55 WorkList.remove(&MI);
68 void changedInstr(const MachineInstr &MI) override {
69 LLVM_DEBUG(dbgs() << "Changed: " << MI << "\n");
70 WorkList.insert(&MI);
5671 }
57 // Currently changed conservatively assumes erased.
58 void changedInstr(MachineInstr &MI) override {
59 LLVM_DEBUG(dbgs() << "Changed: " << MI << "\n");
60 WorkList.remove(&MI);
72
73 void reportFullyCreatedInstrs() {
74 LLVM_DEBUG(for (const auto *MI
75 : CreatedInstrs) {
76 dbgs() << "Created: ";
77 MI->print(dbgs());
78 });
79 LLVM_DEBUG(CreatedInstrs.clear());
80 }
81
82 void MF_HandleInsertion(const MachineInstr &MI) override {
83 createdInstr(MI);
84 }
85 void MF_HandleRemoval(const MachineInstr &MI) override {
86 erasingInstr(MI);
6187 }
6288 };
6389 }
89115 // insert with list bottom up, so while we pop_back_val, we'll traverse top
90116 // down RPOT.
91117 Changed = false;
92 GISelWorkList<512> WorkList;
93 WorkListMaintainer Observer(WorkList);
118 GISelWorkList<512> WorkList(&MF);
119 WorkListMaintainer Observer(MF, WorkList);
94120 for (MachineBasicBlock *MBB : post_order(&MF)) {
95121 if (MBB->empty())
96122 continue;
109135 // Main Loop. Process the instructions here.
110136 while (!WorkList.empty()) {
111137 MachineInstr *CurrInst = WorkList.pop_back_val();
112 LLVM_DEBUG(dbgs() << "Try combining " << *CurrInst << "\n";);
138 LLVM_DEBUG(dbgs() << "\nTry combining " << *CurrInst;);
113139 Changed |= CInfo.combine(Observer, *CurrInst, Builder);
140 Observer.reportFullyCreatedInstrs();
114141 }
115142 MFChanged |= Changed;
116143 } while (Changed);
None //== ---lib/CodeGen/GlobalISel/GICombinerHelper.cpp --------------------- == //
0 //===-- lib/CodeGen/GlobalISel/GICombinerHelper.cpp -----------------------===//
11 //
22 // The LLVM Compiler Infrastructure
33 //
1414 #include "llvm/CodeGen/MachineRegisterInfo.h"
1515 #include "llvm/CodeGen/TargetInstrInfo.h"
1616
17 #define DEBUG_TYPE "gi-combine"
17 #define DEBUG_TYPE "gi-combiner"
1818
1919 using namespace llvm;
2020
2222 MachineIRBuilder &B)
2323 : Builder(B), MRI(Builder.getMF().getRegInfo()), Observer(Observer) {}
2424
25 void CombinerHelper::scheduleForVisit(MachineInstr &MI) {
26 Observer.createdInstr(MI);
25 void CombinerHelper::replaceRegWith(MachineRegisterInfo &MRI, unsigned FromReg,
26 unsigned ToReg) const {
27 Observer.changingAllUsesOfReg(MRI, FromReg);
28
29 if (MRI.constrainRegAttrs(ToReg, FromReg))
30 MRI.replaceRegWith(FromReg, ToReg);
31 else
32 Builder.buildCopy(ToReg, FromReg);
33
34 Observer.finishedChangingAllUsesOfReg();
35 }
36
37 void CombinerHelper::replaceRegOpWith(MachineRegisterInfo &MRI,
38 MachineOperand &FromRegOp,
39 unsigned ToReg) const {
40 assert(FromRegOp.getParent() && "Expected an operand in an MI");
41 Observer.changingInstr(*FromRegOp.getParent());
42
43 FromRegOp.setReg(ToReg);
44
45 Observer.changedInstr(*FromRegOp.getParent());
2746 }
2847
2948 bool CombinerHelper::tryCombineCopy(MachineInstr &MI) {
3756 // a(sx) = COPY b(sx) -> Replace all uses of a with b.
3857 if (DstTy.isValid() && SrcTy.isValid() && DstTy == SrcTy) {
3958 MI.eraseFromParent();
40 MRI.replaceRegWith(DstReg, SrcReg);
59 replaceRegWith(MRI, DstReg, SrcReg);
4160 return true;
4261 }
4362 return false;
190209 // type since by definition the result of an extend is larger.
191210 assert(Preferred.Ty != LoadValueTy && "Extending to same type?");
192211
212 LLVM_DEBUG(dbgs() << "Preferred use is: " << *Preferred.MI);
213
193214 // Rewrite the load to the chosen extending load.
194215 unsigned ChosenDstReg = Preferred.MI->getOperand(0).getReg();
216 Observer.changingInstr(MI);
195217 MI.setDesc(
196218 Builder.getTII().get(Preferred.ExtendOpcode == TargetOpcode::G_SEXT
197219 ? TargetOpcode::G_SEXTLOAD
210232 if (UseMI->getOpcode() == Preferred.ExtendOpcode ||
211233 UseMI->getOpcode() == TargetOpcode::G_ANYEXT) {
212234 unsigned UseDstReg = UseMI->getOperand(0).getReg();
213 unsigned UseSrcReg = UseMI->getOperand(1).getReg();
235 MachineOperand &UseSrcMO = UseMI->getOperand(1);
214236 const LLT &UseDstTy = MRI.getType(UseDstReg);
215237 if (UseDstReg != ChosenDstReg) {
216238 if (Preferred.Ty == UseDstTy) {
223245 // rewrites to:
224246 // %2:_(s32) = G_SEXTLOAD ...
225247 // ... = ... %2(s32)
226 MRI.replaceRegWith(UseDstReg, ChosenDstReg);
248 replaceRegWith(MRI, UseDstReg, ChosenDstReg);
227249 ScheduleForErase.push_back(UseMO.getParent());
228250 } else if (Preferred.Ty.getSizeInBits() < UseDstTy.getSizeInBits()) {
229251 // If the preferred size is smaller, then keep the extend but extend
236258 // %2:_(s32) = G_SEXTLOAD ...
237259 // %3:_(s64) = G_ANYEXT %2:_(s32)
238260 // ... = ... %3(s64)
239 MRI.replaceRegWith(UseSrcReg, ChosenDstReg);
261 replaceRegOpWith(MRI, UseSrcMO, ChosenDstReg);
240262 } else {
241263 // If the preferred size is large, then insert a truncate. For
242264 // example:
283305
284306 MachineInstr *PreviouslyEmitted = EmittedInsns.lookup(InsertIntoBB);
285307 if (PreviouslyEmitted) {
308 Observer.changingInstr(*UseMO->getParent());
286309 UseMO->setReg(PreviouslyEmitted->getOperand(0).getReg());
310 Observer.changedInstr(*UseMO->getParent());
287311 continue;
288312 }
289313
291315 unsigned NewDstReg = MRI.cloneVirtualRegister(MI.getOperand(0).getReg());
292316 MachineInstr *NewMI = Builder.buildTrunc(NewDstReg, ChosenDstReg);
293317 EmittedInsns[InsertIntoBB] = NewMI;
294 UseMO->setReg(NewDstReg);
295 Observer.createdInstr(*NewMI);
318 replaceRegOpWith(MRI, *UseMO, NewDstReg);
296319 }
297320 for (auto &EraseMI : ScheduleForErase) {
298321 Observer.erasingInstr(*EraseMI);
299322 EraseMI->eraseFromParent();
300323 }
301324 MI.getOperand(0).setReg(ChosenDstReg);
325 Observer.changedInstr(MI);
302326
303327 return true;
304328 }
0 //===-- lib/CodeGen/GlobalISel/GISelChangeObserver.cpp --------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file constains common code to combine machine functions at generic
10 // level.
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
14 #include "llvm/CodeGen/MachineRegisterInfo.h"
15
16 using namespace llvm;
17
18 void GISelChangeObserver::changingAllUsesOfReg(
19 const MachineRegisterInfo &MRI, unsigned Reg) {
20 for (auto &ChangingMI : MRI.use_instructions(Reg)) {
21 changingInstr(ChangingMI);
22 ChangingAllUsesOfReg.insert(&ChangingMI);
23 }
24 }
25
26 void GISelChangeObserver::finishedChangingAllUsesOfReg() {
27 for (auto *ChangedMI : ChangingAllUsesOfReg)
28 changedInstr(*ChangedMI);
29 }
30
8080 LegalizerWorkListManager(InstListTy &Insts, ArtifactListTy &Arts)
8181 : InstList(Insts), ArtifactList(Arts) {}
8282
83 void createdInstr(MachineInstr &MI) override {
83 void createdInstr(const MachineInstr &MI) override {
8484 // Only legalize pre-isel generic instructions.
8585 // Legalization process could generate Target specific pseudo
8686 // instructions with generic types. Don't record them
9393 LLVM_DEBUG(dbgs() << ".. .. New MI: " << MI);
9494 }
9595
96 void erasingInstr(MachineInstr &MI) override {
96 void erasingInstr(const MachineInstr &MI) override {
9797 LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI);
9898 InstList.remove(&MI);
9999 ArtifactList.remove(&MI);
100100 }
101101
102 void changingInstr(MachineInstr &MI) override {
102 void changingInstr(const MachineInstr &MI) override {
103103 LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI);
104104 }
105105
106 void changedInstr(MachineInstr &MI) override {
106 void changedInstr(const MachineInstr &MI) override {
107107 // When insts change, we want to revisit them to legalize them again.
108108 // We'll consider them the same as created.
109109 LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI);
125125 MachineRegisterInfo &MRI = MF.getRegInfo();
126126
127127 // Populate Insts
128 InstListTy InstList;
129 ArtifactListTy ArtifactList;
128 InstListTy InstList(&MF);
129 ArtifactListTy ArtifactList(&MF);
130130 ReversePostOrderTraversal RPOT(&MF);
131131 // Perform legalization bottom up so we can DCE as we legalize.
132132 // Traverse BB in RPOT and within each basic block, add insts top down,
0 # RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - | FileCheck %s
1 # RUN: llc -O0 -run-pass=aarch64-prelegalizer-combiner -global-isel %s -o - \
2 # RUN: -debug-only=aarch64-prelegalizer-combiner,gi-combiner 2>&1 >/dev/null \
3 # RUN: | FileCheck %s --check-prefix=CHECK-WORKLIST
14
25 --- |
36 target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
101104 ; CHECK: $w1 = COPY [[T6]](s32)
102105 $w0 = COPY %3
103106 $w1 = COPY %9
107
108 # Check that we report the correct modifications to the observer. This acts as
109 # a test of the debug output and a test.
110 #
111 # CHECK-WORKLIST-LABEL: Generic MI Combiner for: multiple_copies
112 # CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0) :: (load 1 from %ir.addr)
113 # CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8)
114 # CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr)
115 # CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_
116 # CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[NEW1:%[0-9]+]]:_, [[IN4]]:_
117 # CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_
118 # CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[NEW2:%[0-9]+]]:_, [[IN6]]:_
119 # CHECK-WORKLIST-DAG: Erased: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8)
120 # CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr)
121 # CHECK-WORKLIST-DAG: Created: [[NEW1]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
122 # CHECK-WORKLIST-DAG: Created: [[NEW2]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
123 # CHECK-WORKLIST: Try combining
104124 ...
105125
106126 ---
156176 %0:_(p0) = COPY $x0
157177 %1:_(s32) = COPY $w1
158178 %2:_(s8) = G_LOAD %0 :: (load 1 from %ir.addr)
159 %3:_(s32) = G_SEXT %2
160 %4:_(s32) = G_CONSTANT i32 1
161 %5:_(s1) = G_ICMP intpred(ne), %1:_(s32), %4:_
162 G_BRCOND %5:_(s1), %bb.1
179 %3:_(s32) = G_CONSTANT i32 1
180 %4:_(s1) = G_ICMP intpred(ne), %1:_(s32), %3:_
181 G_BRCOND %4:_(s1), %bb.1
163182 G_BR %bb.2.else
164183 bb.1.if:
165184 ; CHECK: bb.1.if:
166185 successors: %bb.3(0x80000000)
167 %10:_(s8) = G_CONSTANT i8 1
186 %5:_(s8) = G_CONSTANT i8 1
168187 ; CHECK: [[T1:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
169 %6:_(s8) = G_ADD %2, %10
188 %6:_(s8) = G_ADD %2, %5
170189 ; CHECK: [[T2:%[0-9]+]]:_(s8) = G_ADD [[T1]], {{.*}}
171190 G_BR %bb.3.exit
172191 bb.2.else:
173192 ; CHECK: bb.2.else:
174193 successors: %bb.3(0x80000000)
175 %11:_(s8) = G_CONSTANT i8 1
194 %7:_(s8) = G_CONSTANT i8 1
176195 ; CHECK: [[T3:%[0-9]+]]:_(s8) = G_TRUNC [[T0]](s32)
177 %7:_(s8) = G_SUB %2, %11
196 %8:_(s8) = G_SUB %2, %7
178197 ; CHECK: [[T4:%[0-9]+]]:_(s8) = G_SUB [[T3]], {{.*}}
179198 G_BR %bb.3.exit
180199 bb.3.exit:
181200 ; CHECK: bb.3.exit:
182 %8:_(s8) = G_PHI %6:_(s8), %bb.1, %7:_(s8), %bb.2
201 %9:_(s8) = G_PHI %6:_(s8), %bb.1, %8:_(s8), %bb.2
183202 ; CHECK: [[T5:%[0-9]+]]:_(s8) = G_PHI [[T2]](s8), %bb.1, [[T4]](s8)
184 %9:_(s32) = G_ZEXT %8
203 %10:_(s32) = G_SEXT %2
204 %11:_(s32) = G_ZEXT %9
185205 ; CHECK: [[T6:%[0-9]+]]:_(s32) = G_ZEXT [[T5]](s8)
186206 ; CHECK: $w0 = COPY [[T0]](s32)
187207 ; CHECK: $w1 = COPY [[T6]](s32)
188 $w0 = COPY %3
189 $w1 = COPY %9
208 $w0 = COPY %10
209 $w1 = COPY %11
210 # CHECK-WORKLIST-LABEL: Generic MI Combiner for: sink_to_phi_nondominating
211 # CHECK-WORKLIST: Try combining [[IN0:%[0-9]+]]:_(s8) = G_LOAD [[IN1:%[0-9]+]]:_(p0) :: (load 1 from %ir.addr)
212 # CHECK-WORKLIST: Preferred use is: [[IN2:%[0-9]+]]:_(s32) = G_SEXT [[IN0]]:_(s8)
213 # CHECK-WORKLIST-DAG: Changing: [[IN0]]:_(s8) = G_LOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr)
214 # CHECK-WORKLIST-DAG: Creating: G_TRUNC
215 # CHECK-WORKLIST-DAG: Changing: [[IN3:%[0-9]+]]:_(s8) = G_ADD [[IN0]]:_, [[IN4:%[0-9]+]]:_
216 # CHECK-WORKLIST-DAG: Changed: [[IN3]]:_(s8) = G_ADD [[OUT1:%[0-9]+]]:_, [[IN4]]:_
217 # CHECK-WORKLIST-DAG: Creating: G_TRUNC
218 # CHECK-WORKLIST-DAG: Changing: [[IN5:%[0-9]+]]:_(s8) = G_SUB [[IN0]]:_, [[IN6:%[0-9]+]]:_
219 # CHECK-WORKLIST-DAG: Changed: [[IN5]]:_(s8) = G_SUB [[OUT2:%[0-9]+]]:_, [[IN6]]:_
220 # CHECK-WORKLIST-DAG: Erased: [[IN2]]:_(s32) = G_SEXT [[IN0]]:_(s8)
221 # CHECK-WORKLIST-DAG: Changed: [[IN2]]:_(s32) = G_SEXTLOAD [[IN1]]:_(p0) :: (load 1 from %ir.addr)
222 # CHECK-WORKLIST-DAG: Created: [[OUT1]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
223 # CHECK-WORKLIST-DAG: Created: [[OUT2]]:_(s8) = G_TRUNC [[IN2]]:_(s32)
224 # CHECK-WORKLIST: Try combining
190225 ...
191226
192227 ---
1212
1313 class DummyGISelObserver : public GISelChangeObserver {
1414 public:
15 void changingInstr(MachineInstr &MI) override {}
16 void changedInstr(MachineInstr &MI) override {}
17 void createdInstr(MachineInstr &MI) override {}
18 void erasingInstr(MachineInstr &MI) override {}
15 void changingInstr(const MachineInstr &MI) override {}
16 void changedInstr(const MachineInstr &MI) override {}
17 void createdInstr(const MachineInstr &MI) override {}
18 void erasingInstr(const MachineInstr &MI) override {}
1919 };
2020
2121 // Test CTTZ expansion when CTTZ_ZERO_UNDEF is legal or custom,