llvm.org GIT mirror llvm / 66f2370
[GISel]: Add support for CSEing continuously during GISel passes. https://reviews.llvm.org/D52803 This patch adds support to continuously CSE instructions during each of the GISel passes. It consists of a GISelCSEInfo analysis pass that can be used by the CSEMIRBuilder. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351283 91177308-0d34-0410-b5e6-96231b3b80d8 Aditya Nandakumar 1 year, 9 months ago
35 changed file(s) with 1676 addition(s) and 408 deletion(s). Raw diff Collapse all Expand all
0 //===- llvm/CodeGen/GlobalISel/CSEInfo.h ------------------*- C++ -*-===//
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 /// Provides analysis for continuously CSEing during GISel passes.
10 //
11 //===----------------------------------------------------------------------===//
12 #ifndef LLVM_CODEGEN_GLOBALISEL_CSEINFO_H
13 #define LLVM_CODEGEN_GLOBALISEL_CSEINFO_H
14
15 #include "llvm/ADT/FoldingSet.h"
16 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
17 #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"
18 #include "llvm/CodeGen/GlobalISel/Utils.h"
19 #include "llvm/CodeGen/MachineBasicBlock.h"
20 #include "llvm/CodeGen/MachineFunctionPass.h"
21 #include "llvm/IR/PassManager.h"
22 #include "llvm/Pass.h"
23 #include "llvm/Support/Allocator.h"
24
25 namespace llvm {
26
27 /// A class that wraps MachineInstrs and derives from FoldingSetNode in order to
28 /// be uniqued in a CSEMap. The tradeoff here is extra memory allocations for
29 /// UniqueMachineInstr vs making MachineInstr bigger.
30 class UniqueMachineInstr : public FoldingSetNode {
31 friend class GISelCSEInfo;
32 const MachineInstr *MI;
33 explicit UniqueMachineInstr(const MachineInstr *MI) : MI(MI) {}
34
35 public:
36 void Profile(FoldingSetNodeID &ID);
37 };
38
39 // Class representing some configuration that can be done during CSE analysis.
40 // Currently it only supports shouldCSE method that each pass can set.
41 class CSEConfig {
42 public:
43 virtual ~CSEConfig() = default;
44 // Hook for defining which Generic instructions should be CSEd.
45 // GISelCSEInfo currently only calls this hook when dealing with generic
46 // opcodes.
47 virtual bool shouldCSEOpc(unsigned Opc);
48 };
49
50 // TODO: Find a better place for this.
51 // Commonly used for O0 config.
52 class CSEConfigConstantOnly : public CSEConfig {
53 public:
54 virtual ~CSEConfigConstantOnly() = default;
55 virtual bool shouldCSEOpc(unsigned Opc) override;
56 };
57
58 /// The CSE Analysis object.
59 /// This installs itself as a delegate to the MachineFunction to track
60 /// new instructions as well as deletions. It however will not be able to
61 /// track instruction mutations. In such cases, recordNewInstruction should be
62 /// called (for eg inside MachineIRBuilder::recordInsertion).
63 /// Also because of how just the instruction can be inserted without adding any
64 /// operands to the instruction, instructions are uniqued and inserted lazily.
65 /// CSEInfo should assert when trying to enter an incomplete instruction into
66 /// the CSEMap. There is Opcode level granularity on which instructions can be
67 /// CSE'd and for now, only Generic instructions are CSEable.
68 class GISelCSEInfo : public GISelChangeObserver {
69 // Make it accessible only to CSEMIRBuilder.
70 friend class CSEMIRBuilder;
71
72 BumpPtrAllocator UniqueInstrAllocator;
73 FoldingSet CSEMap;
74 MachineRegisterInfo *MRI = nullptr;
75 MachineFunction *MF = nullptr;
76 std::unique_ptr CSEOpt;
77 /// Keep a cache of UniqueInstrs for each MachineInstr. In GISel,
78 /// often instructions are mutated (while their ID has completely changed).
79 /// Whenever mutation happens, invalidate the UniqueMachineInstr for the
80 /// MachineInstr
81 DenseMap InstrMapping;
82
83 /// Store instructions that are not fully formed in TemporaryInsts.
84 /// Also because CSE insertion happens lazily, we can remove insts from this
85 /// list and avoid inserting and then removing from the CSEMap.
86 GISelWorkList<8> TemporaryInsts;
87
88 // Only used in asserts.
89 DenseMap OpcodeHitTable;
90
91 bool isUniqueMachineInstValid(const UniqueMachineInstr &UMI) const;
92
93 void invalidateUniqueMachineInstr(UniqueMachineInstr *UMI);
94
95 UniqueMachineInstr *getNodeIfExists(FoldingSetNodeID &ID,
96 MachineBasicBlock *MBB, void *&InsertPos);
97
98 /// Allocate and construct a new UniqueMachineInstr for MI and return.
99 UniqueMachineInstr *getUniqueInstrForMI(const MachineInstr *MI);
100
101 void insertNode(UniqueMachineInstr *UMI, void *InsertPos = nullptr);
102
103 /// Get the MachineInstr(Unique) if it exists already in the CSEMap and the
104 /// same MachineBasicBlock.
105 MachineInstr *getMachineInstrIfExists(FoldingSetNodeID &ID,
106 MachineBasicBlock *MBB,
107 void *&InsertPos);
108
109 /// Use this method to allocate a new UniqueMachineInstr for MI and insert it
110 /// into the CSEMap. MI should return true for shouldCSE(MI->getOpcode())
111 void insertInstr(MachineInstr *MI, void *InsertPos = nullptr);
112
113 public:
114 GISelCSEInfo() = default;
115
116 virtual ~GISelCSEInfo();
117
118 void setMF(MachineFunction &MF);
119
120 /// Records a newly created inst in a list and lazily insert it to the CSEMap.
121 /// Sometimes, this method might be called with a partially constructed
122 /// MachineInstr,
123 // (right after BuildMI without adding any operands) - and in such cases,
124 // defer the hashing of the instruction to a later stage.
125 void recordNewInstruction(MachineInstr *MI);
126
127 /// Use this callback to inform CSE about a newly fully created instruction.
128 void handleRecordedInst(MachineInstr *MI);
129
130 /// Use this callback to insert all the recorded instructions. At this point,
131 /// all of these insts need to be fully constructed and should not be missing
132 /// any operands.
133 void handleRecordedInsts();
134
135 /// Remove this inst from the CSE map. If this inst has not been inserted yet,
136 /// it will be removed from the Tempinsts list if it exists.
137 void handleRemoveInst(MachineInstr *MI);
138
139 void releaseMemory();
140
141 void setCSEConfig(std::unique_ptr Opt) { CSEOpt = std::move(Opt); }
142
143 bool shouldCSE(unsigned Opc) const;
144
145 void analyze(MachineFunction &MF);
146
147 void countOpcodeHit(unsigned Opc);
148
149 void print();
150
151 // Observer API
152 void erasingInstr(MachineInstr &MI) override;
153 void createdInstr(MachineInstr &MI) override;
154 void changingInstr(MachineInstr &MI) override;
155 void changedInstr(MachineInstr &MI) override;
156 };
157
158 class TargetRegisterClass;
159 class RegisterBank;
160
161 // Simple builder class to easily profile properties about MIs.
162 class GISelInstProfileBuilder {
163 FoldingSetNodeID &ID;
164 const MachineRegisterInfo &MRI;
165
166 public:
167 GISelInstProfileBuilder(FoldingSetNodeID &ID, const MachineRegisterInfo &MRI)
168 : ID(ID), MRI(MRI) {}
169 // Profiling methods.
170 const GISelInstProfileBuilder &addNodeIDOpcode(unsigned Opc) const;
171 const GISelInstProfileBuilder &addNodeIDRegType(const LLT &Ty) const;
172 const GISelInstProfileBuilder &addNodeIDRegType(const unsigned) const;
173
174 const GISelInstProfileBuilder &
175 addNodeIDRegType(const TargetRegisterClass *RC) const;
176 const GISelInstProfileBuilder &addNodeIDRegType(const RegisterBank *RB) const;
177
178 const GISelInstProfileBuilder &addNodeIDRegNum(unsigned Reg) const;
179
180 const GISelInstProfileBuilder &addNodeIDImmediate(int64_t Imm) const;
181 const GISelInstProfileBuilder &
182 addNodeIDMBB(const MachineBasicBlock *MBB) const;
183
184 const GISelInstProfileBuilder &
185 addNodeIDMachineOperand(const MachineOperand &MO) const;
186
187 const GISelInstProfileBuilder &addNodeIDFlag(unsigned Flag) const;
188 const GISelInstProfileBuilder &addNodeID(const MachineInstr *MI) const;
189 };
190
191 /// Simple wrapper that does the following.
192 /// 1) Lazily evaluate the MachineFunction to compute CSEable instructions.
193 /// 2) Allows configuration of which instructions are CSEd through CSEConfig
194 /// object. Provides a method called get which takes a CSEConfig object.
195 class GISelCSEAnalysisWrapper {
196 GISelCSEInfo Info;
197 MachineFunction *MF = nullptr;
198 bool AlreadyComputed = false;
199
200 public:
201 /// Takes a CSEConfig object that defines what opcodes get CSEd.
202 /// If CSEConfig is already set, and the CSE Analysis has been preserved,
203 /// it will not use the new CSEOpt(use Recompute to force using the new
204 /// CSEOpt).
205 GISelCSEInfo &get(std::unique_ptr CSEOpt, bool ReCompute = false);
206 void setMF(MachineFunction &MFunc) { MF = &MFunc; }
207 void setComputed(bool Computed) { AlreadyComputed = Computed; }
208 void releaseMemory() { Info.releaseMemory(); }
209 };
210
211 /// The actual analysis pass wrapper.
212 class GISelCSEAnalysisWrapperPass : public MachineFunctionPass {
213 GISelCSEAnalysisWrapper Wrapper;
214
215 public:
216 static char ID;
217 GISelCSEAnalysisWrapperPass() : MachineFunctionPass(ID) {
218 initializeGISelCSEAnalysisWrapperPassPass(*PassRegistry::getPassRegistry());
219 }
220
221 void getAnalysisUsage(AnalysisUsage &AU) const override;
222
223 const GISelCSEAnalysisWrapper &getCSEWrapper() const { return Wrapper; }
224 GISelCSEAnalysisWrapper &getCSEWrapper() { return Wrapper; }
225
226 bool runOnMachineFunction(MachineFunction &MF) override;
227
228 void releaseMemory() override {
229 Wrapper.releaseMemory();
230 Wrapper.setComputed(false);
231 }
232 };
233
234 } // namespace llvm
235
236 #endif
0 //===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.h --*- C++ -*-==//
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 /// \file
9 /// This file implements a version of MachineIRBuilder which CSEs insts within
10 /// a MachineBasicBlock.
11 //===----------------------------------------------------------------------===//
12 #ifndef LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H
13 #define LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H
14
15 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
16 #include "llvm/CodeGen/GlobalISel/Utils.h"
17
18 namespace llvm {
19
20 /// Defines a builder that does CSE of MachineInstructions using GISelCSEInfo.
21 /// Eg usage.
22 ///
23 ///
24 /// GISelCSEInfo *Info =
25 /// &getAnalysis().getCSEInfo(); CSEMIRBuilder
26 /// CB(Builder.getState()); CB.setCSEInfo(Info); auto A = CB.buildConstant(s32,
27 /// 42); auto B = CB.buildConstant(s32, 42); assert(A == B); unsigned CReg =
28 /// MRI.createGenericVirtualRegister(s32); auto C = CB.buildConstant(CReg, 42);
29 /// assert(C->getOpcode() == TargetOpcode::COPY);
30 /// Explicitly passing in a register would materialize a copy if possible.
31 /// CSEMIRBuilder also does trivial constant folding for binary ops.
32 class CSEMIRBuilder : public MachineIRBuilder {
33
34 /// Returns true if A dominates B (within the same basic block).
35 /// Both iterators must be in the same basic block.
36 //
37 // TODO: Another approach for checking dominance is having two iterators and
38 // making them go towards each other until they meet or reach begin/end. Which
39 // approach is better? Should this even change dynamically? For G_CONSTANTS
40 // most of which will be at the top of the BB, the top down approach would be
41 // a better choice. Does IRTranslator placing constants at the beginning still
42 // make sense? Should this change based on Opcode?
43 bool dominates(MachineBasicBlock::const_iterator A,
44 MachineBasicBlock::const_iterator B) const;
45
46 /// For given ID, find a machineinstr in the CSE Map. If found, check if it
47 /// dominates the current insertion point and if not, move it just before the
48 /// current insertion point and return it. If not found, return Null
49 /// MachineInstrBuilder.
50 MachineInstrBuilder getDominatingInstrForID(FoldingSetNodeID &ID,
51 void *&NodeInsertPos);
52 /// Simple check if we can CSE (we have the CSEInfo) or if this Opcode is
53 /// safe to CSE.
54 bool canPerformCSEForOpc(unsigned Opc) const;
55
56 void profileDstOp(const DstOp &Op, GISelInstProfileBuilder &B) const;
57
58 void profileDstOps(ArrayRef Ops, GISelInstProfileBuilder &B) const {
59 for (const DstOp &Op : Ops)
60 profileDstOp(Op, B);
61 }
62
63 void profileSrcOp(const SrcOp &Op, GISelInstProfileBuilder &B) const;
64
65 void profileSrcOps(ArrayRef Ops, GISelInstProfileBuilder &B) const {
66 for (const SrcOp &Op : Ops)
67 profileSrcOp(Op, B);
68 }
69
70 void profileMBBOpcode(GISelInstProfileBuilder &B, unsigned Opc) const;
71
72 void profileEverything(unsigned Opc, ArrayRef DstOps,
73 ArrayRef SrcOps, Optional Flags,
74 GISelInstProfileBuilder &B) const;
75
76 // Takes a MachineInstrBuilder and inserts it into the CSEMap using the
77 // NodeInsertPos.
78 MachineInstrBuilder memoizeMI(MachineInstrBuilder MIB, void *NodeInsertPos);
79
80 // If we have can CSE an instruction, but still need to materialize to a VReg,
81 // we emit a copy from the CSE'd inst to the VReg.
82 MachineInstrBuilder generateCopiesIfRequired(ArrayRef DstOps,
83 MachineInstrBuilder &MIB);
84
85 // If we have can CSE an instruction, but still need to materialize to a VReg,
86 // check if we can generate copies. It's not possible to return a single MIB,
87 // while emitting copies to multiple vregs.
88 bool checkCopyToDefsPossible(ArrayRef DstOps);
89
90 public:
91 // Pull in base class constructors.
92 using MachineIRBuilder::MachineIRBuilder;
93 // Unhide buildInstr
94 MachineInstrBuilder buildInstr(unsigned Opc, ArrayRef DstOps,
95 ArrayRef SrcOps,
96 Optional Flag = None) override;
97 // Bring in the other overload from the base class.
98 using MachineIRBuilder::buildConstant;
99
100 MachineInstrBuilder buildConstant(const DstOp &Res,
101 const ConstantInt &Val) override;
102
103 // Bring in the other overload from the base class.
104 using MachineIRBuilder::buildFConstant;
105 MachineInstrBuilder buildFConstant(const DstOp &Res,
106 const ConstantFP &Val) override;
107 };
108 } // namespace llvm
109 #endif
2020 namespace llvm {
2121 class MachineRegisterInfo;
2222 class CombinerInfo;
23 class GISelCSEInfo;
2324 class TargetPassConfig;
2425 class MachineFunction;
2526
2728 public:
2829 Combiner(CombinerInfo &CombinerInfo, const TargetPassConfig *TPC);
2930
30 bool combineMachineInstrs(MachineFunction &MF);
31 /// If CSEInfo is not null, then the Combiner will setup observer for
32 /// CSEInfo and instantiate a CSEMIRBuilder. Pass nullptr if CSE is not
33 /// needed.
34 bool combineMachineInstrs(MachineFunction &MF, GISelCSEInfo *CSEInfo);
3135
3236 protected:
3337 CombinerInfo &CInfo;
3438
3539 MachineRegisterInfo *MRI = nullptr;
3640 const TargetPassConfig *TPC;
37 MachineIRBuilder Builder;
41 std::unique_ptr Builder;
3842 };
3943
4044 } // End namespace llvm.
1313 #include "llvm/CodeGen/GlobalISel/Utils.h"
1414
1515 namespace llvm {
16
17 static Optional ConstantFoldBinOp(unsigned Opcode, const unsigned Op1,
18 const unsigned Op2,
19 const MachineRegisterInfo &MRI) {
20 auto MaybeOp1Cst = getConstantVRegVal(Op1, MRI);
21 auto MaybeOp2Cst = getConstantVRegVal(Op2, MRI);
22 if (MaybeOp1Cst && MaybeOp2Cst) {
23 LLT Ty = MRI.getType(Op1);
24 APInt C1(Ty.getSizeInBits(), *MaybeOp1Cst, true);
25 APInt C2(Ty.getSizeInBits(), *MaybeOp2Cst, true);
26 switch (Opcode) {
27 default:
28 break;
29 case TargetOpcode::G_ADD:
30 return C1 + C2;
31 case TargetOpcode::G_AND:
32 return C1 & C2;
33 case TargetOpcode::G_ASHR:
34 return C1.ashr(C2);
35 case TargetOpcode::G_LSHR:
36 return C1.lshr(C2);
37 case TargetOpcode::G_MUL:
38 return C1 * C2;
39 case TargetOpcode::G_OR:
40 return C1 | C2;
41 case TargetOpcode::G_SHL:
42 return C1 << C2;
43 case TargetOpcode::G_SUB:
44 return C1 - C2;
45 case TargetOpcode::G_XOR:
46 return C1 ^ C2;
47 case TargetOpcode::G_UDIV:
48 if (!C2.getBoolValue())
49 break;
50 return C1.udiv(C2);
51 case TargetOpcode::G_SDIV:
52 if (!C2.getBoolValue())
53 break;
54 return C1.sdiv(C2);
55 case TargetOpcode::G_UREM:
56 if (!C2.getBoolValue())
57 break;
58 return C1.urem(C2);
59 case TargetOpcode::G_SREM:
60 if (!C2.getBoolValue())
61 break;
62 return C1.srem(C2);
63 }
64 }
65 return None;
66 }
6716
6817 /// An MIRBuilder which does trivial constant folding of binary ops.
6918 /// Calls to buildInstr will also try to constant fold binary ops.
1414 #define LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H
1515
1616 #include "llvm/ADT/SmallPtrSet.h"
17 #include "llvm/CodeGen/MachineFunction.h"
1718
1819 namespace llvm {
1920 class MachineInstr;
3132 virtual ~GISelChangeObserver() {}
3233
3334 /// An instruction is about to be erased.
34 virtual void erasingInstr(const MachineInstr &MI) = 0;
35 virtual void erasingInstr(MachineInstr &MI) = 0;
3536 /// An instruction was created and inserted into the function.
36 virtual void createdInstr(const MachineInstr &MI) = 0;
37 virtual void createdInstr(MachineInstr &MI) = 0;
3738 /// This instruction is about to be mutated in some way.
38 virtual void changingInstr(const MachineInstr &MI) = 0;
39 virtual void changingInstr(MachineInstr &MI) = 0;
3940 /// This instruction was mutated in some way.
40 virtual void changedInstr(const MachineInstr &MI) = 0;
41 virtual void changedInstr(MachineInstr &MI) = 0;
4142
4243 /// All the instructions using the given register are being changed.
4344 /// For convenience, finishedChangingAllUsesOfReg() will report the completion
5051
5152 };
5253
54 /// Simple wrapper observer that takes several observers, and calls
55 /// each one for each event. If there are multiple observers (say CSE,
56 /// Legalizer, Combiner), it's sufficient to register this to the machine
57 /// function as the delegate.
58 class GISelObserverWrapper : public MachineFunction::Delegate,
59 public GISelChangeObserver {
60 SmallVector Observers;
61
62 public:
63 GISelObserverWrapper() = default;
64 GISelObserverWrapper(ArrayRef Obs)
65 : Observers(Obs.begin(), Obs.end()) {}
66 // Adds an observer.
67 void addObserver(GISelChangeObserver *O) { Observers.push_back(O); }
68 // Removes an observer from the list and does nothing if observer is not
69 // present.
70 void removeObserver(GISelChangeObserver *O) {
71 auto It = std::find(Observers.begin(), Observers.end(), O);
72 if (It != Observers.end())
73 Observers.erase(It);
74 }
75 // API for Observer.
76 void erasingInstr(MachineInstr &MI) override {
77 for (auto &O : Observers)
78 O->erasingInstr(MI);
79 }
80 void createdInstr(MachineInstr &MI) override {
81 for (auto &O : Observers)
82 O->createdInstr(MI);
83 }
84 void changingInstr(MachineInstr &MI) override {
85 for (auto &O : Observers)
86 O->changingInstr(MI);
87 }
88 void changedInstr(MachineInstr &MI) override {
89 for (auto &O : Observers)
90 O->changedInstr(MI);
91 }
92 // API for MachineFunction::Delegate
93 void MF_HandleInsertion(MachineInstr &MI) override { createdInstr(MI); }
94 void MF_HandleRemoval(MachineInstr &MI) override { erasingInstr(MI); }
95 };
96
97 /// A simple RAII based CSEInfo installer.
98 /// Use this in a scope to install a delegate to the MachineFunction and reset
99 /// it at the end of the scope.
100 class RAIIDelegateInstaller {
101 MachineFunction &MF;
102 MachineFunction::Delegate *Delegate;
103
104 public:
105 RAIIDelegateInstaller(MachineFunction &MF, MachineFunction::Delegate *Del);
106 ~RAIIDelegateInstaller();
107 };
108
53109 } // namespace llvm
54110 #endif
1717
1818 namespace llvm {
1919
20 class MachineInstr;
2021 class MachineFunction;
2122
2223 // Worklist which mostly works similar to InstCombineWorkList, but on
2425 // erasing an element doesn't move all elements over one place - instead just
2526 // nulls out the element of the vector.
2627 //
27 // This worklist operates on instructions within a particular function. This is
28 // important for acquiring the rights to modify/replace instructions a
29 // GISelChangeObserver reports as the observer doesn't have the right to make
30 // changes to the instructions it sees so we use our access to the
31 // MachineFunction to establish that it's ok to add a given instruction to the
32 // worklist.
33 //
3428 // FIXME: Does it make sense to factor out common code with the
3529 // instcombinerWorkList?
3630 template
3731 class GISelWorkList {
38 MachineFunction *MF;
3932 SmallVector Worklist;
4033 DenseMap WorklistMap;
4134
4235 public:
43 GISelWorkList(MachineFunction *MF) : MF(MF) {}
36 GISelWorkList() {}
4437
4538 bool empty() const { return WorklistMap.empty(); }
4639
4841
4942 /// Add the specified instruction to the worklist if it isn't already in it.
5043 void insert(MachineInstr *I) {
51 // It would be safe to add this instruction to the worklist regardless but
52 // for consistency with the const version, check that the instruction we're
53 // adding would have been accepted if we were given a const pointer instead.
54 insert(const_cast(I));
55 }
56
57 void insert(const MachineInstr *I) {
58 // Confirm we'd be able to find the non-const pointer we want to schedule if
59 // we wanted to. We have the right to schedule work that may modify any
60 // instruction in MF.
61 assert(I->getParent() && "Expected parent BB");
62 assert(I->getParent()->getParent() && "Expected parent function");
63 assert((!MF || I->getParent()->getParent() == MF) &&
64 "Expected parent function to be current function or not given");
65
66 // But don't actually do the search since we can derive it from the const
67 // pointer.
68 MachineInstr *NonConstI = const_cast(I);
69 if (WorklistMap.try_emplace(NonConstI, Worklist.size()).second) {
70 Worklist.push_back(NonConstI);
71 }
44 if (WorklistMap.try_emplace(I, Worklist.size()).second)
45 Worklist.push_back(I);
7246 }
7347
7448 /// Remove I from the worklist if it exists.
8054 Worklist[It->second] = nullptr;
8155
8256 WorklistMap.erase(It);
57 }
58
59 void clear() {
60 Worklist.clear();
61 WorklistMap.clear();
8362 }
8463
8564 MachineInstr *pop_back_val() {
2020
2121 #include "llvm/ADT/DenseMap.h"
2222 #include "llvm/ADT/SmallVector.h"
23 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
23 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
2424 #include "llvm/CodeGen/GlobalISel/Types.h"
2525 #include "llvm/CodeGen/MachineFunctionPass.h"
26 #include "llvm/IR/Intrinsics.h"
2627 #include "llvm/Support/Allocator.h"
27 #include "llvm/IR/Intrinsics.h"
2828 #include
2929 #include
3030
443443 // I.e., compared to regular MIBuilder, this one also inserts the instruction
444444 // in the current block, it can creates block, etc., basically a kind of
445445 // IRBuilder, but for Machine IR.
446 MachineIRBuilder CurBuilder;
446 // CSEMIRBuilder CurBuilder;
447 std::unique_ptr CurBuilder;
447448
448449 // Builder set to the entry block (just after ABI lowering instructions). Used
449450 // as a convenient location for Constants.
450 MachineIRBuilder EntryBuilder;
451 // CSEMIRBuilder EntryBuilder;
452 std::unique_ptr EntryBuilder;
451453
452454 // The MachineFunction currently being translated.
453455 MachineFunction *MF;
4848 UnableToLegalize,
4949 };
5050
51 LegalizerHelper(MachineFunction &MF, GISelChangeObserver &Observer);
51 LegalizerHelper(MachineFunction &MF, GISelChangeObserver &Observer,
52 MachineIRBuilder &B);
5253 LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI,
53 GISelChangeObserver &Observer);
54 GISelChangeObserver &Observer, MachineIRBuilder &B);
5455
5556 /// Replace \p MI by a sequence of legal instructions that can implement the
5657 /// same operation. Note that this means \p MI may be deleted, so any iterator
8990
9091 /// Expose MIRBuilder so clients can set their own RecordInsertInstruction
9192 /// functions
92 MachineIRBuilder MIRBuilder;
93 MachineIRBuilder &MIRBuilder;
9394
9495 /// Expose LegalizerInfo so the clients can re-use.
9596 const LegalizerInfo &getLegalizerInfo() const { return LI; }
1313 #ifndef LLVM_CODEGEN_GLOBALISEL_MACHINEIRBUILDER_H
1414 #define LLVM_CODEGEN_GLOBALISEL_MACHINEIRBUILDER_H
1515
16 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
1617 #include "llvm/CodeGen/GlobalISel/Types.h"
1718
1819 #include "llvm/CodeGen/LowLevelType.h"
5152 /// @}
5253
5354 GISelChangeObserver *Observer;
55
56 GISelCSEInfo *CSEInfo;
5457 };
5558
5659 class DstOp {
8083 }
8184 }
8285
83 DstType getType() const { return Ty; }
84
8586 LLT getLLTTy(const MachineRegisterInfo &MRI) const {
8687 switch (Ty) {
8788 case DstType::Ty_RC:
9293 return MRI.getType(Reg);
9394 }
9495 llvm_unreachable("Unrecognised DstOp::DstType enum");
96 }
97
98 unsigned getReg() const {
99 assert(Ty == DstType::Ty_Reg && "Not a register");
100 return Reg;
101 }
102
103 const TargetRegisterClass *getRegClass() const {
104 switch (Ty) {
105 case DstType::Ty_RC:
106 return RC;
107 default:
108 llvm_unreachable("Not a RC Operand");
109 }
95110 }
96111
97112 DstType getDstOpKind() const { return Ty; }
219234
220235 /// Getter for MRI
221236 MachineRegisterInfo *getMRI() { return State.MRI; }
237 const MachineRegisterInfo *getMRI() const { return State.MRI; }
222238
223239 /// Getter for the State
224240 MachineIRBuilderState &getState() { return State; }
225241
226242 /// Getter for the basic block we currently build.
227 MachineBasicBlock &getMBB() {
243 const MachineBasicBlock &getMBB() const {
228244 assert(State.MBB && "MachineBasicBlock is not set");
229245 return *State.MBB;
230246 }
247
248 MachineBasicBlock &getMBB() {
249 return const_cast(
250 const_cast(this)->getMBB());
251 }
252
253 GISelCSEInfo *getCSEInfo() { return State.CSEInfo; }
254 const GISelCSEInfo *getCSEInfo() const { return State.CSEInfo; }
231255
232256 /// Current insertion point for new instructions.
233257 MachineBasicBlock::iterator getInsertPt() { return State.II; }
238262 void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II);
239263 /// @}
240264
265 void setCSEInfo(GISelCSEInfo *Info);
266
241267 /// \name Setters for the insertion point.
242268 /// @{
243269 /// Set the MachineFunction where to build instructions.
244 void setMF(MachineFunction &);
270 void setMF(MachineFunction &MF);
245271
246272 /// Set the insertion point to the end of \p MBB.
247273 /// \pre \p MBB must be contained by getMF().
533559 /// type.
534560 ///
535561 /// \return The newly created instruction.
536 MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val);
562 virtual MachineInstrBuilder buildConstant(const DstOp &Res,
563 const ConstantInt &Val);
537564
538565 /// Build and insert \p Res = G_CONSTANT \p Val
539566 ///
554581 /// \pre \p Res must be a generic virtual register with scalar type.
555582 ///
556583 /// \return The newly created instruction.
557 MachineInstrBuilder buildFConstant(const DstOp &Res, const ConstantFP &Val);
584 virtual MachineInstrBuilder buildFConstant(const DstOp &Res,
585 const ConstantFP &Val);
558586
559587 MachineInstrBuilder buildFConstant(const DstOp &Res, double Val);
560588
107107 /// fallback.
108108 void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU);
109109
110 Optional ConstantFoldBinOp(unsigned Opcode, const unsigned Op1,
111 const unsigned Op2,
112 const MachineRegisterInfo &MRI);
110113 } // End namespace llvm.
111114 #endif
371371
372372 public:
373373 virtual ~Delegate() = default;
374 virtual void MF_HandleInsertion(const MachineInstr &MI) = 0;
375 virtual void MF_HandleRemoval(const MachineInstr &MI) = 0;
374 /// Callback after an insertion. This should not modify the MI directly.
375 virtual void MF_HandleInsertion(MachineInstr &MI) = 0;
376 /// Callback before a removal. This should not modify the MI directly.
377 virtual void MF_HandleRemoval(MachineInstr &MI) = 0;
376378 };
377379
378380 private:
379381 Delegate *TheDelegate = nullptr;
380382
381383 // Callbacks for insertion and removal.
382 void handleInsertion(const MachineInstr &MI);
383 void handleRemoval(const MachineInstr &MI);
384 void handleInsertion(MachineInstr &MI);
385 void handleRemoval(MachineInstr &MI);
384386 friend struct ilist_traits;
385387
386388 public:
198198 void initializeLegacyLICMPassPass(PassRegistry&);
199199 void initializeLegacyLoopSinkPassPass(PassRegistry&);
200200 void initializeLegalizerPass(PassRegistry&);
201 void initializeGISelCSEAnalysisWrapperPassPass(PassRegistry &);
201202 void initializeLibCallsShrinkWrapLegacyPassPass(PassRegistry&);
202203 void initializeLintPass(PassRegistry&);
203204 void initializeLiveDebugValuesPass(PassRegistry&);
146146 bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
147147
148148 friend struct DenseMapInfo;
149 friend class GISelInstProfileBuilder;
149150
150151 private:
151152 /// LLT is packed into 64 bits as follows:
230231 maskAndShift(AddressSpace, PointerVectorAddressSpaceFieldInfo);
231232 }
232233 }
234
235 uint64_t getUniqueRAWLLTData() const {
236 return ((uint64_t)RawData) << 2 | ((uint64_t)IsPointer) << 1 |
237 ((uint64_t)IsVector);
238 }
233239 };
234240
235241 inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
249255 return Invalid;
250256 }
251257 static inline unsigned getHashValue(const LLT &Ty) {
252 uint64_t Val = ((uint64_t)Ty.RawData) << 2 | ((uint64_t)Ty.IsPointer) << 1 |
253 ((uint64_t)Ty.IsVector);
258 uint64_t Val = Ty.getUniqueRAWLLTData();
254259 return DenseMapInfo::getHashValue(Val);
255260 }
256261 static bool isEqual(const LLT &LHS, const LLT &RHS) {
0 add_llvm_library(LLVMGlobalISel
1 CSEInfo.cpp
2 CSEMIRBuilder.cpp
13 CallLowering.cpp
24 GlobalISel.cpp
35 Combiner.cpp
0 //===- CSEInfo.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 //
10 //===----------------------------------------------------------------------===//
11 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
12 #include "llvm/CodeGen/MachineRegisterInfo.h"
13
14 #define DEBUG_TYPE "cseinfo"
15
16 using namespace llvm;
17 char llvm::GISelCSEAnalysisWrapperPass::ID = 0;
18 INITIALIZE_PASS_BEGIN(GISelCSEAnalysisWrapperPass, DEBUG_TYPE,
19 "Analysis containing CSE Info", false, true)
20 INITIALIZE_PASS_END(GISelCSEAnalysisWrapperPass, DEBUG_TYPE,
21 "Analysis containing CSE Info", false, true)
22
23 /// -------- UniqueMachineInstr -------------//
24
25 void UniqueMachineInstr::Profile(FoldingSetNodeID &ID) {
26 GISelInstProfileBuilder(ID, MI->getMF()->getRegInfo()).addNodeID(MI);
27 }
28 /// -----------------------------------------
29
30 /// --------- CSEConfig ---------- ///
31 bool CSEConfig::shouldCSEOpc(unsigned Opc) {
32 switch (Opc) {
33 default:
34 break;
35 case TargetOpcode::G_ADD:
36 case TargetOpcode::G_AND:
37 case TargetOpcode::G_ASHR:
38 case TargetOpcode::G_LSHR:
39 case TargetOpcode::G_MUL:
40 case TargetOpcode::G_OR:
41 case TargetOpcode::G_SHL:
42 case TargetOpcode::G_SUB:
43 case TargetOpcode::G_XOR:
44 case TargetOpcode::G_UDIV:
45 case TargetOpcode::G_SDIV:
46 case TargetOpcode::G_UREM:
47 case TargetOpcode::G_SREM:
48 case TargetOpcode::G_CONSTANT:
49 case TargetOpcode::G_FCONSTANT:
50 case TargetOpcode::G_ZEXT:
51 case TargetOpcode::G_SEXT:
52 case TargetOpcode::G_ANYEXT:
53 case TargetOpcode::G_UNMERGE_VALUES:
54 case TargetOpcode::G_TRUNC:
55 return true;
56 }
57 return false;
58 }
59
60 bool CSEConfigConstantOnly::shouldCSEOpc(unsigned Opc) {
61 return Opc == TargetOpcode::G_CONSTANT;
62 }
63 /// -----------------------------------------
64
65 /// -------- GISelCSEInfo -------------//
66 void GISelCSEInfo::setMF(MachineFunction &MF) {
67 this->MF = &MF;
68 this->MRI = &MF.getRegInfo();
69 }
70
71 GISelCSEInfo::~GISelCSEInfo() {}
72
73 bool GISelCSEInfo::isUniqueMachineInstValid(
74 const UniqueMachineInstr &UMI) const {
75 // Should we check here and assert that the instruction has been fully
76 // constructed?
77 // FIXME: Any other checks required to be done here? Remove this method if
78 // none.
79 return true;
80 }
81
82 void GISelCSEInfo::invalidateUniqueMachineInstr(UniqueMachineInstr *UMI) {
83 bool Removed = CSEMap.RemoveNode(UMI);
84 (void)Removed;
85 assert(Removed && "Invalidation called on invalid UMI");
86 // FIXME: Should UMI be deallocated/destroyed?
87 }
88
89 UniqueMachineInstr *GISelCSEInfo::getNodeIfExists(FoldingSetNodeID &ID,
90 MachineBasicBlock *MBB,
91 void *&InsertPos) {
92 auto *Node = CSEMap.FindNodeOrInsertPos(ID, InsertPos);
93 if (Node) {
94 if (!isUniqueMachineInstValid(*Node)) {
95 invalidateUniqueMachineInstr(Node);
96 return nullptr;
97 }
98
99 if (Node->MI->getParent() != MBB)
100 return nullptr;
101 }
102 return Node;
103 }
104
105 void GISelCSEInfo::insertNode(UniqueMachineInstr *UMI, void *InsertPos) {
106 handleRecordedInsts();
107 assert(UMI);
108 UniqueMachineInstr *MaybeNewNode = UMI;
109 if (InsertPos)
110 CSEMap.InsertNode(UMI, InsertPos);
111 else
112 MaybeNewNode = CSEMap.GetOrInsertNode(UMI);
113 if (MaybeNewNode != UMI) {
114 // A similar node exists in the folding set. Let's ignore this one.
115 return;
116 }
117 assert(InstrMapping.count(UMI->MI) == 0 &&
118 "This instruction should not be in the map");
119 InstrMapping[UMI->MI] = MaybeNewNode;
120 }
121
122 UniqueMachineInstr *GISelCSEInfo::getUniqueInstrForMI(const MachineInstr *MI) {
123 assert(shouldCSE(MI->getOpcode()) && "Trying to CSE an unsupported Node");
124 auto *Node = new (UniqueInstrAllocator) UniqueMachineInstr(MI);
125 return Node;
126 }
127
128 void GISelCSEInfo::insertInstr(MachineInstr *MI, void *InsertPos) {
129 assert(MI);
130 // If it exists in temporary insts, remove it.
131 TemporaryInsts.remove(MI);
132 auto *Node = getUniqueInstrForMI(MI);
133 insertNode(Node, InsertPos);
134 }
135
136 MachineInstr *GISelCSEInfo::getMachineInstrIfExists(FoldingSetNodeID &ID,
137 MachineBasicBlock *MBB,
138 void *&InsertPos) {
139 handleRecordedInsts();
140 if (auto *Inst = getNodeIfExists(ID, MBB, InsertPos)) {
141 LLVM_DEBUG(dbgs() << "CSEInfo: Found Instr " << *Inst->MI << "\n";);
142 return const_cast(Inst->MI);
143 }
144 return nullptr;
145 }
146
147 void GISelCSEInfo::countOpcodeHit(unsigned Opc) {
148 #ifndef NDEBUG
149 if (OpcodeHitTable.count(Opc))
150 OpcodeHitTable[Opc] += 1;
151 else
152 OpcodeHitTable[Opc] = 1;
153 #endif
154 // Else do nothing.
155 }
156
157 void GISelCSEInfo::recordNewInstruction(MachineInstr *MI) {
158 if (shouldCSE(MI->getOpcode())) {
159 TemporaryInsts.insert(MI);
160 LLVM_DEBUG(dbgs() << "CSEInfo: Recording new MI" << *MI << "\n";);
161 }
162 }
163
164 void GISelCSEInfo::handleRecordedInst(MachineInstr *MI) {
165 assert(shouldCSE(MI->getOpcode()) && "Invalid instruction for CSE");
166 auto *UMI = InstrMapping.lookup(MI);
167 LLVM_DEBUG(dbgs() << "CSEInfo: Handling recorded MI" << *MI << "\n";);
168 if (UMI) {
169 // Invalidate this MI.
170 invalidateUniqueMachineInstr(UMI);
171 InstrMapping.erase(MI);
172 }
173 /// Now insert the new instruction.
174 if (UMI) {
175 /// We'll reuse the same UniqueMachineInstr to avoid the new
176 /// allocation.
177 *UMI = UniqueMachineInstr(MI);
178 insertNode(UMI, nullptr);
179 } else {
180 /// This is a new instruction. Allocate a new UniqueMachineInstr and
181 /// Insert.
182 insertInstr(MI);
183 }
184 }
185
186 void GISelCSEInfo::handleRemoveInst(MachineInstr *MI) {
187 if (auto *UMI = InstrMapping.lookup(MI)) {
188 invalidateUniqueMachineInstr(UMI);
189 InstrMapping.erase(MI);
190 }
191 TemporaryInsts.remove(MI);
192 }
193
194 void GISelCSEInfo::handleRecordedInsts() {
195 while (!TemporaryInsts.empty()) {
196 auto *MI = TemporaryInsts.pop_back_val();
197 handleRecordedInst(MI);
198 }
199 }
200
201 bool GISelCSEInfo::shouldCSE(unsigned Opc) const {
202 // Only GISel opcodes are CSEable
203 if (!isPreISelGenericOpcode(Opc))
204 return false;
205 assert(CSEOpt.get() && "CSEConfig not set");
206 return CSEOpt->shouldCSEOpc(Opc);
207 }
208
209 void GISelCSEInfo::erasingInstr(MachineInstr &MI) { handleRemoveInst(&MI); }
210 void GISelCSEInfo::createdInstr(MachineInstr &MI) { recordNewInstruction(&MI); }
211 void GISelCSEInfo::changingInstr(MachineInstr &MI) {
212 // For now, perform erase, followed by insert.
213 erasingInstr(MI);
214 createdInstr(MI);
215 }
216 void GISelCSEInfo::changedInstr(MachineInstr &MI) { changingInstr(MI); }
217
218 void GISelCSEInfo::analyze(MachineFunction &MF) {
219 setMF(MF);
220 for (auto &MBB : MF) {
221 if (MBB.empty())
222 continue;
223 for (MachineInstr &MI : MBB) {
224 if (!shouldCSE(MI.getOpcode()))
225 continue;
226 LLVM_DEBUG(dbgs() << "CSEInfo::Add MI: " << MI << "\n";);
227 insertInstr(&MI);
228 }
229 }
230 }
231
232 void GISelCSEInfo::releaseMemory() {
233 // print();
234 CSEMap.clear();
235 InstrMapping.clear();
236 UniqueInstrAllocator.Reset();
237 TemporaryInsts.clear();
238 CSEOpt.reset();
239 MRI = nullptr;
240 MF = nullptr;
241 #ifndef NDEBUG
242 OpcodeHitTable.clear();
243 #endif
244 }
245
246 void GISelCSEInfo::print() {
247 #ifndef NDEBUG
248 for (auto &It : OpcodeHitTable) {
249 dbgs() << "CSE Count for Opc " << It.first << " : " << It.second << "\n";
250 };
251 #endif
252 }
253 /// -----------------------------------------
254 // ---- Profiling methods for FoldingSetNode --- //
255 const GISelInstProfileBuilder &
256 GISelInstProfileBuilder::addNodeID(const MachineInstr *MI) const {
257 addNodeIDMBB(MI->getParent());
258 addNodeIDOpcode(MI->getOpcode());
259 for (auto &Op : MI->operands())
260 addNodeIDMachineOperand(Op);
261 addNodeIDFlag(MI->getFlags());
262 return *this;
263 }
264
265 const GISelInstProfileBuilder &
266 GISelInstProfileBuilder::addNodeIDOpcode(unsigned Opc) const {
267 ID.AddInteger(Opc);
268 return *this;
269 }
270
271 const GISelInstProfileBuilder &
272 GISelInstProfileBuilder::addNodeIDRegType(const LLT &Ty) const {
273 uint64_t Val = Ty.getUniqueRAWLLTData();
274 ID.AddInteger(Val);
275 return *this;
276 }
277
278 const GISelInstProfileBuilder &
279 GISelInstProfileBuilder::addNodeIDRegType(const TargetRegisterClass *RC) const {
280 ID.AddPointer(RC);
281 return *this;
282 }
283
284 const GISelInstProfileBuilder &
285 GISelInstProfileBuilder::addNodeIDRegType(const RegisterBank *RB) const {
286 ID.AddPointer(RB);
287 return *this;
288 }
289
290 const GISelInstProfileBuilder &
291 GISelInstProfileBuilder::addNodeIDImmediate(int64_t Imm) const {
292 ID.AddInteger(Imm);
293 return *this;
294 }
295
296 const GISelInstProfileBuilder &
297 GISelInstProfileBuilder::addNodeIDRegNum(unsigned Reg) const {
298 ID.AddInteger(Reg);
299 return *this;
300 }
301
302 const GISelInstProfileBuilder &
303 GISelInstProfileBuilder::addNodeIDRegType(const unsigned Reg) const {
304 addNodeIDMachineOperand(MachineOperand::CreateReg(Reg, false));
305 return *this;
306 }
307
308 const GISelInstProfileBuilder &
309 GISelInstProfileBuilder::addNodeIDMBB(const MachineBasicBlock *MBB) const {
310 ID.AddPointer(MBB);
311 return *this;
312 }
313
314 const GISelInstProfileBuilder &
315 GISelInstProfileBuilder::addNodeIDFlag(unsigned Flag) const {
316 if (Flag)
317 ID.AddInteger(Flag);
318 return *this;
319 }
320
321 const GISelInstProfileBuilder &GISelInstProfileBuilder::addNodeIDMachineOperand(
322 const MachineOperand &MO) const {
323 if (MO.isReg()) {
324 unsigned Reg = MO.getReg();
325 if (!MO.isDef())
326 addNodeIDRegNum(Reg);
327 LLT Ty = MRI.getType(Reg);
328 if (Ty.isValid())
329 addNodeIDRegType(Ty);
330 auto *RB = MRI.getRegBankOrNull(Reg);
331 if (RB)
332 addNodeIDRegType(RB);
333 auto *RC = MRI.getRegClassOrNull(Reg);
334 if (RC)
335 addNodeIDRegType(RC);
336 assert(!MO.isImplicit() && "Unhandled case");
337 } else if (MO.isImm())
338 ID.AddInteger(MO.getImm());
339 else if (MO.isCImm())
340 ID.AddPointer(MO.getCImm());
341 else if (MO.isFPImm())
342 ID.AddPointer(MO.getFPImm());
343 else if (MO.isPredicate())
344 ID.AddInteger(MO.getPredicate());
345 else
346 llvm_unreachable("Unhandled operand type");
347 // Handle other types
348 return *this;
349 }
350
351 GISelCSEInfo &GISelCSEAnalysisWrapper::get(std::unique_ptr CSEOpt,
352 bool Recompute) {
353 if (!AlreadyComputed || Recompute) {
354 Info.setCSEConfig(std::move(CSEOpt));
355 Info.analyze(*MF);
356 AlreadyComputed = true;
357 }
358 return Info;
359 }
360 void GISelCSEAnalysisWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
361 AU.setPreservesAll();
362 MachineFunctionPass::getAnalysisUsage(AU);
363 }
364
365 bool GISelCSEAnalysisWrapperPass::runOnMachineFunction(MachineFunction &MF) {
366 releaseMemory();
367 Wrapper.setMF(MF);
368 return false;
369 }
0 //===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.cpp - MIBuilder--*- C++ -*-==//
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 /// \file
9 /// This file implements the CSEMIRBuilder class which CSEs as it builds
10 /// instructions.
11 //===----------------------------------------------------------------------===//
12 //
13
14 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
15 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
16
17 using namespace llvm;
18
19 bool CSEMIRBuilder::dominates(MachineBasicBlock::const_iterator A,
20 MachineBasicBlock::const_iterator B) const {
21 auto MBBEnd = getMBB().end();
22 if (B == MBBEnd)
23 return true;
24 assert(A->getParent() == B->getParent() &&
25 "Iterators should be in same block");
26 const MachineBasicBlock *BBA = A->getParent();
27 MachineBasicBlock::const_iterator I = BBA->begin();
28 for (; &*I != A && &*I != B; ++I)
29 ;
30 return &*I == A;
31 }
32
33 MachineInstrBuilder
34 CSEMIRBuilder::getDominatingInstrForID(FoldingSetNodeID &ID,
35 void *&NodeInsertPos) {
36 GISelCSEInfo *CSEInfo = getCSEInfo();
37 assert(CSEInfo && "Can't get here without setting CSEInfo");
38 MachineBasicBlock *CurMBB = &getMBB();
39 MachineInstr *MI =
40 CSEInfo->getMachineInstrIfExists(ID, CurMBB, NodeInsertPos);
41 if (MI) {
42 auto CurrPos = getInsertPt();
43 if (!dominates(MI, CurrPos))
44 CurMBB->splice(CurrPos, CurMBB, MI);
45 return MachineInstrBuilder(getMF(), MI);
46 }
47 return MachineInstrBuilder();
48 }
49
50 bool CSEMIRBuilder::canPerformCSEForOpc(unsigned Opc) const {
51 const GISelCSEInfo *CSEInfo = getCSEInfo();
52 if (!CSEInfo || !CSEInfo->shouldCSE(Opc))
53 return false;
54 return true;
55 }
56
57 void CSEMIRBuilder::profileDstOp(const DstOp &Op,
58 GISelInstProfileBuilder &B) const {
59 switch (Op.getDstOpKind()) {
60 case DstOp::DstType::Ty_RC:
61 B.addNodeIDRegType(Op.getRegClass());
62 break;
63 default:
64 B.addNodeIDRegType(Op.getLLTTy(*getMRI()));
65 break;
66 }
67 }
68
69 void CSEMIRBuilder::profileSrcOp(const SrcOp &Op,
70 GISelInstProfileBuilder &B) const {
71 switch (Op.getSrcOpKind()) {
72 case SrcOp::SrcType::Ty_Predicate:
73 B.addNodeIDImmediate(static_cast(Op.getPredicate()));
74 break;
75 default:
76 B.addNodeIDRegType(Op.getReg());
77 break;
78 }
79 }
80
81 void CSEMIRBuilder::profileMBBOpcode(GISelInstProfileBuilder &B,
82 unsigned Opc) const {
83 // First add the MBB (Local CSE).
84 B.addNodeIDMBB(&getMBB());
85 // Then add the opcode.
86 B.addNodeIDOpcode(Opc);
87 }
88
89 void CSEMIRBuilder::profileEverything(unsigned Opc, ArrayRef DstOps,
90 ArrayRef SrcOps,
91 Optional Flags,
92 GISelInstProfileBuilder &B) const {
93
94 profileMBBOpcode(B, Opc);
95 // Then add the DstOps.
96 profileDstOps(DstOps, B);
97 // Then add the SrcOps.
98 profileSrcOps(SrcOps, B);
99 // Add Flags if passed in.
100 if (Flags)
101 B.addNodeIDFlag(*Flags);
102 }
103
104 MachineInstrBuilder CSEMIRBuilder::memoizeMI(MachineInstrBuilder MIB,
105 void *NodeInsertPos) {
106 assert(canPerformCSEForOpc(MIB->getOpcode()) &&
107 "Attempting to CSE illegal op");
108 MachineInstr *MIBInstr = MIB;
109 getCSEInfo()->insertInstr(MIBInstr, NodeInsertPos);
110 return MIB;
111 }
112
113 bool CSEMIRBuilder::checkCopyToDefsPossible(ArrayRef DstOps) {
114 if (DstOps.size() == 1)
115 return true; // always possible to emit copy to just 1 vreg.
116
117 return std::all_of(DstOps.begin(), DstOps.end(), [](const DstOp &Op) {
118 DstOp::DstType DT = Op.getDstOpKind();
119 return DT == DstOp::DstType::Ty_LLT || DT == DstOp::DstType::Ty_RC;
120 });
121 }
122
123 MachineInstrBuilder
124 CSEMIRBuilder::generateCopiesIfRequired(ArrayRef DstOps,
125 MachineInstrBuilder &MIB) {
126 assert(checkCopyToDefsPossible(DstOps) &&
127 "Impossible return a single MIB with copies to multiple defs");
128 if (DstOps.size() == 1) {
129 const DstOp &Op = DstOps[0];
130 if (Op.getDstOpKind() == DstOp::DstType::Ty_Reg)
131 return buildCopy(Op.getReg(), MIB->getOperand(0).getReg());
132 }
133 return MIB;
134 }
135
136 MachineInstrBuilder CSEMIRBuilder::buildInstr(unsigned Opc,
137 ArrayRef DstOps,
138 ArrayRef SrcOps,
139 Optional Flag) {
140 switch (Opc) {
141 default:
142 break;
143 case TargetOpcode::G_ADD:
144 case TargetOpcode::G_AND:
145 case TargetOpcode::G_ASHR:
146 case TargetOpcode::G_LSHR:
147 case TargetOpcode::G_MUL:
148 case TargetOpcode::G_OR:
149 case TargetOpcode::G_SHL:
150 case TargetOpcode::G_SUB:
151 case TargetOpcode::G_XOR:
152 case TargetOpcode::G_UDIV:
153 case TargetOpcode::G_SDIV:
154 case TargetOpcode::G_UREM:
155 case TargetOpcode::G_SREM: {
156 // Try to constant fold these.
157 assert(SrcOps.size() == 2 && "Invalid sources");
158 assert(DstOps.size() == 1 && "Invalid dsts");
159 if (Optional Cst = ConstantFoldBinOp(Opc, SrcOps[0].getReg(),
160 SrcOps[1].getReg(), *getMRI()))
161 return buildConstant(DstOps[0], Cst->getSExtValue());
162 break;
163 }
164 }
165 bool CanCopy = checkCopyToDefsPossible(DstOps);
166 if (!canPerformCSEForOpc(Opc))
167 return MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag);
168 // If we can CSE this instruction, but involves generating copies to multiple
169 // regs, give up. This frequently happens to UNMERGEs.
170 if (!CanCopy) {
171 auto MIB = MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag);
172 // CSEInfo would have tracked this instruction. Remove it from the temporary
173 // insts.
174 getCSEInfo()->handleRemoveInst(&*MIB);
175 return MIB;
176 }
177 FoldingSetNodeID ID;
178 GISelInstProfileBuilder ProfBuilder(ID, *getMRI());
179 void *InsertPos = nullptr;
180 profileEverything(Opc, DstOps, SrcOps, Flag, ProfBuilder);
181 MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos);
182 if (MIB) {
183 // Handle generating copies here.
184 return generateCopiesIfRequired(DstOps, MIB);
185 }
186 // This instruction does not exist in the CSEInfo. Build it and CSE it.
187 MachineInstrBuilder NewMIB =
188 MachineIRBuilder::buildInstr(Opc, DstOps, SrcOps, Flag);
189 return memoizeMI(NewMIB, InsertPos);
190 }
191
192 MachineInstrBuilder CSEMIRBuilder::buildConstant(const DstOp &Res,
193 const ConstantInt &Val) {
194 constexpr unsigned Opc = TargetOpcode::G_CONSTANT;
195 if (!canPerformCSEForOpc(Opc))
196 return MachineIRBuilder::buildConstant(Res, Val);
197 FoldingSetNodeID ID;
198 GISelInstProfileBuilder ProfBuilder(ID, *getMRI());
199 void *InsertPos = nullptr;
200 profileMBBOpcode(ProfBuilder, Opc);
201 profileDstOp(Res, ProfBuilder);
202 ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateCImm(&Val));
203 MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos);
204 if (MIB) {
205 // Handle generating copies here.
206 return generateCopiesIfRequired({Res}, MIB);
207 }
208 MachineInstrBuilder NewMIB = MachineIRBuilder::buildConstant(Res, Val);
209 return memoizeMI(NewMIB, InsertPos);
210 }
211
212 MachineInstrBuilder CSEMIRBuilder::buildFConstant(const DstOp &Res,
213 const ConstantFP &Val) {
214 constexpr unsigned Opc = TargetOpcode::G_FCONSTANT;
215 if (!canPerformCSEForOpc(Opc))
216 return MachineIRBuilder::buildFConstant(Res, Val);
217 FoldingSetNodeID ID;
218 GISelInstProfileBuilder ProfBuilder(ID, *getMRI());
219 void *InsertPos = nullptr;
220 profileMBBOpcode(ProfBuilder, Opc);
221 profileDstOp(Res, ProfBuilder);
222 ProfBuilder.addNodeIDMachineOperand(MachineOperand::CreateFPImm(&Val));
223 MachineInstrBuilder MIB = getDominatingInstrForID(ID, InsertPos);
224 if (MIB) {
225 // Handle generating copies here.
226 return generateCopiesIfRequired({Res}, MIB);
227 }
228 MachineInstrBuilder NewMIB = MachineIRBuilder::buildFConstant(Res, Val);
229 return memoizeMI(NewMIB, InsertPos);
230 }
1212
1313 #include "llvm/CodeGen/GlobalISel/Combiner.h"
1414 #include "llvm/ADT/PostOrderIterator.h"
15 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
1516 #include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
17 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
1618 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
1719 #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"
1820 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
3436 /// instruction creation will schedule that instruction for a future visit.
3537 /// Other Combiner implementations may require more complex behaviour from
3638 /// their GISelChangeObserver subclass.
37 class WorkListMaintainer : public GISelChangeObserver,
38 public MachineFunction::Delegate {
39 class WorkListMaintainer : public GISelChangeObserver {
3940 using WorkListTy = GISelWorkList<512>;
40 MachineFunction &MF;
4141 WorkListTy &WorkList;
4242 /// The instructions that have been created but we want to report once they
4343 /// have their operands. This is only maintained if debug output is requested.
4444 SmallPtrSet CreatedInstrs;
4545
4646 public:
47 WorkListMaintainer(MachineFunction &MF, WorkListTy &WorkList)
48 : GISelChangeObserver(), MF(MF), WorkList(WorkList) {
49 MF.setDelegate(this);
50 }
47 WorkListMaintainer(WorkListTy &WorkList)
48 : GISelChangeObserver(), WorkList(WorkList) {}
5149 virtual ~WorkListMaintainer() {
52 MF.resetDelegate(this);
5350 }
5451
55 void erasingInstr(const MachineInstr &MI) override {
52 void erasingInstr(MachineInstr &MI) override {
5653 LLVM_DEBUG(dbgs() << "Erased: " << MI << "\n");
5754 WorkList.remove(&MI);
5855 }
59 void createdInstr(const MachineInstr &MI) override {
56 void createdInstr(MachineInstr &MI) override {
6057 LLVM_DEBUG(dbgs() << "Creating: " << MI << "\n");
6158 WorkList.insert(&MI);
6259 LLVM_DEBUG(CreatedInstrs.insert(&MI));
6360 }
64 void changingInstr(const MachineInstr &MI) override {
61 void changingInstr(MachineInstr &MI) override {
6562 LLVM_DEBUG(dbgs() << "Changing: " << MI << "\n");
6663 WorkList.insert(&MI);
6764 }
68 void changedInstr(const MachineInstr &MI) override {
65 void changedInstr(MachineInstr &MI) override {
6966 LLVM_DEBUG(dbgs() << "Changed: " << MI << "\n");
7067 WorkList.insert(&MI);
7168 }
7875 });
7976 LLVM_DEBUG(CreatedInstrs.clear());
8077 }
81
82 void MF_HandleInsertion(const MachineInstr &MI) override {
83 createdInstr(MI);
84 }
85 void MF_HandleRemoval(const MachineInstr &MI) override {
86 erasingInstr(MI);
87 }
8878 };
8979 }
9080
9383 (void)this->TPC; // FIXME: Remove when used.
9484 }
9585
96 bool Combiner::combineMachineInstrs(MachineFunction &MF) {
86 bool Combiner::combineMachineInstrs(MachineFunction &MF,
87 GISelCSEInfo *CSEInfo) {
9788 // If the ISel pipeline failed, do not bother running this pass.
9889 // FIXME: Should this be here or in individual combiner passes.
9990 if (MF.getProperties().hasProperty(
10091 MachineFunctionProperties::Property::FailedISel))
10192 return false;
10293
94 Builder =
95 CSEInfo ? make_unique() : make_unique();
10396 MRI = &MF.getRegInfo();
104 Builder.setMF(MF);
97 Builder->setMF(MF);
98 if (CSEInfo)
99 Builder->setCSEInfo(CSEInfo);
105100
106101 LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n');
107102
109104
110105 bool MFChanged = false;
111106 bool Changed;
107 MachineIRBuilder &B = *Builder.get();
112108
113109 do {
114110 // Collect all instructions. Do a post order traversal for basic blocks and
115111 // insert with list bottom up, so while we pop_back_val, we'll traverse top
116112 // down RPOT.
117113 Changed = false;
118 GISelWorkList<512> WorkList(&MF);
119 WorkListMaintainer Observer(MF, WorkList);
114 GISelWorkList<512> WorkList;
115 WorkListMaintainer Observer(WorkList);
116 GISelObserverWrapper WrapperObserver(&Observer);
117 if (CSEInfo)
118 WrapperObserver.addObserver(CSEInfo);
119 RAIIDelegateInstaller DelInstall(MF, &WrapperObserver);
120120 for (MachineBasicBlock *MBB : post_order(&MF)) {
121121 if (MBB->empty())
122122 continue;
136136 while (!WorkList.empty()) {
137137 MachineInstr *CurrInst = WorkList.pop_back_val();
138138 LLVM_DEBUG(dbgs() << "\nTry combining " << *CurrInst;);
139 Changed |= CInfo.combine(Observer, *CurrInst, Builder);
139 Changed |= CInfo.combine(WrapperObserver, *CurrInst, B);
140140 Observer.reportFullyCreatedInstrs();
141141 }
142142 MFChanged |= Changed;
2828 changedInstr(*ChangedMI);
2929 }
3030
31 RAIIDelegateInstaller::RAIIDelegateInstaller(MachineFunction &MF,
32 MachineFunction::Delegate *Del)
33 : MF(MF), Delegate(Del) {
34 // Register this as the delegate for handling insertions and deletions of
35 // instructions.
36 MF.setDelegate(Del);
37 }
38
39 RAIIDelegateInstaller::~RAIIDelegateInstaller() { MF.resetDelegate(Delegate); }
1818 #include "llvm/Analysis/OptimizationRemarkEmitter.h"
1919 #include "llvm/CodeGen/Analysis.h"
2020 #include "llvm/CodeGen/GlobalISel/CallLowering.h"
21 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
2122 #include "llvm/CodeGen/LowLevelType.h"
2223 #include "llvm/CodeGen/MachineBasicBlock.h"
2324 #include "llvm/CodeGen/MachineFrameInfo.h"
7475
7576 using namespace llvm;
7677
78 static cl::opt
79 EnableCSEInIRTranslator("enable-cse-in-irtranslator",
80 cl::desc("Should enable CSE in irtranslator"),
81 cl::Optional, cl::init(false));
7782 char IRTranslator::ID = 0;
7883
7984 INITIALIZE_PASS_BEGIN(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",
8085 false, false)
8186 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
87 INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
8288 INITIALIZE_PASS_END(IRTranslator, DEBUG_TYPE, "IRTranslator LLVM IR -> MI",
8389 false, false)
8490
107113 namespace {
108114 /// Verify that every instruction created has the same DILocation as the
109115 /// instruction being translated.
110 class DILocationVerifier : MachineFunction::Delegate {
111 MachineFunction &MF;
116 class DILocationVerifier : public GISelChangeObserver {
112117 const Instruction *CurrInst = nullptr;
113118
114119 public:
115 DILocationVerifier(MachineFunction &MF) : MF(MF) { MF.setDelegate(this); }
116 ~DILocationVerifier() { MF.resetDelegate(this); }
120 DILocationVerifier() = default;
121 ~DILocationVerifier() = default;
117122
118123 const Instruction *getCurrentInst() const { return CurrInst; }
119124 void setCurrentInst(const Instruction *Inst) { CurrInst = Inst; }
120125
121 void MF_HandleInsertion(const MachineInstr &MI) override {
126 void erasingInstr(MachineInstr &MI) override {}
127 void changingInstr(MachineInstr &MI) override {}
128 void changedInstr(MachineInstr &MI) override {}
129
130 void createdInstr(MachineInstr &MI) override {
122131 assert(getCurrentInst() && "Inserted instruction without a current MI");
123132
124133 // Only print the check message if we're actually checking it.
129138 assert(CurrInst->getDebugLoc() == MI.getDebugLoc() &&
130139 "Line info was not transferred to all instructions");
131140 }
132 void MF_HandleRemoval(const MachineInstr &MI) override {}
133141 };
134142 } // namespace
135143 #endif // ifndef NDEBUG
138146 void IRTranslator::getAnalysisUsage(AnalysisUsage &AU) const {
139147 AU.addRequired();
140148 AU.addRequired();
149 AU.addRequired();
141150 getSelectionDAGFallbackAnalysisUsage(AU);
142151 MachineFunctionPass::getAnalysisUsage(AU);
143152 }
15521561
15531562 void IRTranslator::finishPendingPhis() {
15541563 #ifndef NDEBUG
1555 DILocationVerifier Verifier(*MF);
1564 DILocationVerifier Verifier;
1565 GISelObserverWrapper WrapperObserver(&Verifier);
1566 RAIIDelegateInstaller DelInstall(*MF, &WrapperObserver);
15561567 #endif // ifndef NDEBUG
15571568 for (auto &Phi : PendingPHIs) {
15581569 const PHINode *PI = Phi.first;
15591570 ArrayRef ComponentPHIs = Phi.second;
1560 EntryBuilder.setDebugLoc(PI->getDebugLoc());
1571 EntryBuilder->setDebugLoc(PI->getDebugLoc());
15611572 #ifndef NDEBUG
15621573 Verifier.setCurrentInst(PI);
15631574 #endif // ifndef NDEBUG
15981609 }
15991610
16001611 bool IRTranslator::translate(const Instruction &Inst) {
1601 CurBuilder.setDebugLoc(Inst.getDebugLoc());
1602 EntryBuilder.setDebugLoc(Inst.getDebugLoc());
1612 CurBuilder->setDebugLoc(Inst.getDebugLoc());
1613 EntryBuilder->setDebugLoc(Inst.getDebugLoc());
16031614 switch(Inst.getOpcode()) {
1604 #define HANDLE_INST(NUM, OPCODE, CLASS) \
1605 case Instruction::OPCODE: return translate##OPCODE(Inst, CurBuilder);
1615 #define HANDLE_INST(NUM, OPCODE, CLASS) \
1616 case Instruction::OPCODE: \
1617 return translate##OPCODE(Inst, *CurBuilder.get());
16061618 #include "llvm/IR/Instruction.def"
16071619 default:
16081620 return false;
16111623
16121624 bool IRTranslator::translate(const Constant &C, unsigned Reg) {
16131625 if (auto CI = dyn_cast(&C))
1614 EntryBuilder.buildConstant(Reg, *CI);
1626 EntryBuilder->buildConstant(Reg, *CI);
16151627 else if (auto CF = dyn_cast(&C))
1616 EntryBuilder.buildFConstant(Reg, *CF);
1628 EntryBuilder->buildFConstant(Reg, *CF);
16171629 else if (isa(C))
1618 EntryBuilder.buildUndef(Reg);
1630 EntryBuilder->buildUndef(Reg);
16191631 else if (isa(C)) {
16201632 // As we are trying to build a constant val of 0 into a pointer,
16211633 // insert a cast to make them correct with respect to types.
16231635 auto *ZeroTy = Type::getIntNTy(C.getContext(), NullSize);
16241636 auto *ZeroVal = ConstantInt::get(ZeroTy, 0);
16251637 unsigned ZeroReg = getOrCreateVReg(*ZeroVal);
1626 EntryBuilder.buildCast(Reg, ZeroReg);
1638 EntryBuilder->buildCast(Reg, ZeroReg);
16271639 } else if (auto GV = dyn_cast(&C))
1628 EntryBuilder.buildGlobalValue(Reg, GV);
1640 EntryBuilder->buildGlobalValue(Reg, GV);
16291641 else if (auto CAZ = dyn_cast(&C)) {
16301642 if (!CAZ->getType()->isVectorTy())
16311643 return false;
16371649 Constant &Elt = *CAZ->getElementValue(i);
16381650 Ops.push_back(getOrCreateVReg(Elt));
16391651 }
1640 EntryBuilder.buildBuildVector(Reg, Ops);
1652 EntryBuilder->buildBuildVector(Reg, Ops);
16411653 } else if (auto CV = dyn_cast(&C)) {
16421654 // Return the scalar if it is a <1 x Ty> vector.
16431655 if (CV->getNumElements() == 1)
16471659 Constant &Elt = *CV->getElementAsConstant(i);
16481660 Ops.push_back(getOrCreateVReg(Elt));
16491661 }
1650 EntryBuilder.buildBuildVector(Reg, Ops);
1662 EntryBuilder->buildBuildVector(Reg, Ops);
16511663 } else if (auto CE = dyn_cast(&C)) {
16521664 switch(CE->getOpcode()) {
1653 #define HANDLE_INST(NUM, OPCODE, CLASS) \
1654 case Instruction::OPCODE: return translate##OPCODE(*CE, EntryBuilder);
1665 #define HANDLE_INST(NUM, OPCODE, CLASS) \
1666 case Instruction::OPCODE: \
1667 return translate##OPCODE(*CE, *EntryBuilder.get());
16551668 #include "llvm/IR/Instruction.def"
16561669 default:
16571670 return false;
16631676 for (unsigned i = 0; i < CV->getNumOperands(); ++i) {
16641677 Ops.push_back(getOrCreateVReg(*CV->getOperand(i)));
16651678 }
1666 EntryBuilder.buildBuildVector(Reg, Ops);
1679 EntryBuilder->buildBuildVector(Reg, Ops);
16671680 } else if (auto *BA = dyn_cast(&C)) {
1668 EntryBuilder.buildBlockAddress(Reg, BA);
1681 EntryBuilder->buildBlockAddress(Reg, BA);
16691682 } else
16701683 return false;
16711684
16821695 // MachineIRBuilder::DebugLoc can outlive the DILocation it holds. Clear it
16831696 // to avoid accessing free’d memory (in runOnMachineFunction) and to avoid
16841697 // destroying it twice (in ~IRTranslator() and ~LLVMContext())
1685 EntryBuilder = MachineIRBuilder();
1686 CurBuilder = MachineIRBuilder();
1698 EntryBuilder.reset();
1699 CurBuilder.reset();
16871700 }
16881701
16891702 bool IRTranslator::runOnMachineFunction(MachineFunction &CurMF) {
16911704 const Function &F = MF->getFunction();
16921705 if (F.empty())
16931706 return false;
1707 GISelCSEAnalysisWrapper &Wrapper =
1708 getAnalysis().getCSEWrapper();
1709 // Set the CSEConfig and run the analysis.
1710 GISelCSEInfo *CSEInfo = nullptr;
1711 TPC = &getAnalysis();
1712 bool IsO0 = TPC->getOptLevel() == CodeGenOpt::Level::None;
1713 // Disable CSE for O0.
1714 bool EnableCSE = !IsO0 && EnableCSEInIRTranslator;
1715 if (EnableCSE) {
1716 EntryBuilder = make_unique(CurMF);
1717 std::unique_ptr Config = make_unique();
1718 CSEInfo = &Wrapper.get(std::move(Config));
1719 EntryBuilder->setCSEInfo(CSEInfo);
1720 CurBuilder = make_unique(CurMF);
1721 CurBuilder->setCSEInfo(CSEInfo);
1722 } else {
1723 EntryBuilder = make_unique();
1724 CurBuilder = make_unique();
1725 }
16941726 CLI = MF->getSubtarget().getCallLowering();
1695 CurBuilder.setMF(*MF);
1696 EntryBuilder.setMF(*MF);
1727 CurBuilder->setMF(*MF);
1728 EntryBuilder->setMF(*MF);
16971729 MRI = &MF->getRegInfo();
16981730 DL = &F.getParent()->getDataLayout();
1699 TPC = &getAnalysis();
17001731 ORE = llvm::make_unique(&F);
17011732
17021733 assert(PendingPHIs.empty() && "stale PHIs");
17151746 // Setup a separate basic-block for the arguments and constants
17161747 MachineBasicBlock *EntryBB = MF->CreateMachineBasicBlock();
17171748 MF->push_back(EntryBB);
1718 EntryBuilder.setMBB(*EntryBB);
1749 EntryBuilder->setMBB(*EntryBB);
17191750
17201751 // Create all blocks, in IR order, to preserve the layout.
17211752 for (const BasicBlock &BB: F) {
17521783 }
17531784 }
17541785
1755 if (!CLI->lowerFormalArguments(EntryBuilder, F, VRegArgs)) {
1786 if (!CLI->lowerFormalArguments(*EntryBuilder.get(), F, VRegArgs)) {
17561787 OptimizationRemarkMissed R("gisel-irtranslator", "GISelFailure",
17571788 F.getSubprogram(), &F.getEntryBlock());
17581789 R << "unable to lower arguments: " << ore::NV("Prototype", F.getType());
17691800 assert(VRegs.empty() && "VRegs already populated?");
17701801 VRegs.push_back(VArg);
17711802 } else {
1772 unpackRegs(*ArgIt, VArg, EntryBuilder);
1803 unpackRegs(*ArgIt, VArg, *EntryBuilder.get());
17731804 }
17741805 ArgIt++;
17751806 }
17761807
17771808 // Need to visit defs before uses when translating instructions.
1809 GISelObserverWrapper WrapperObserver;
1810 if (EnableCSE && CSEInfo)
1811 WrapperObserver.addObserver(CSEInfo);
17781812 {
17791813 ReversePostOrderTraversal RPOT(&F);
17801814 #ifndef NDEBUG
1781 DILocationVerifier Verifier(*MF);
1815 DILocationVerifier Verifier;
1816 WrapperObserver.addObserver(&Verifier);
17821817 #endif // ifndef NDEBUG
1818 RAIIDelegateInstaller DelInstall(*MF, &WrapperObserver);
17831819 for (const BasicBlock *BB : RPOT) {
17841820 MachineBasicBlock &MBB = getMBB(*BB);
17851821 // Set the insertion point of all the following translations to
17861822 // the end of this basic block.
1787 CurBuilder.setMBB(MBB);
1823 CurBuilder->setMBB(MBB);
17881824
17891825 for (const Instruction &Inst : *BB) {
17901826 #ifndef NDEBUG
18091845 return false;
18101846 }
18111847 }
1848 #ifndef NDEBUG
1849 WrapperObserver.removeObserver(&Verifier);
1850 #endif
18121851 }
18131852
18141853 finishPendingPhis();
1515 #include "llvm/CodeGen/GlobalISel/Legalizer.h"
1616 #include "llvm/ADT/PostOrderIterator.h"
1717 #include "llvm/ADT/SetVector.h"
18 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
19 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
1820 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
1921 #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"
2022 #include "llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h"
3234
3335 using namespace llvm;
3436
37 static cl::opt
38 EnableCSEInLegalizer("enable-cse-in-legalizer",
39 cl::desc("Should enable CSE in Legalizer"),
40 cl::Optional, cl::init(false));
41
3542 char Legalizer::ID = 0;
3643 INITIALIZE_PASS_BEGIN(Legalizer, DEBUG_TYPE,
3744 "Legalize the Machine IR a function's Machine IR", false,
3845 false)
3946 INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
47 INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass)
4048 INITIALIZE_PASS_END(Legalizer, DEBUG_TYPE,
4149 "Legalize the Machine IR a function's Machine IR", false,
4250 false)
4755
4856 void Legalizer::getAnalysisUsage(AnalysisUsage &AU) const {
4957 AU.addRequired();
58 AU.addRequired();
59 AU.addPreserved();
5060 getSelectionDAGFallbackAnalysisUsage(AU);
5161 MachineFunctionPass::getAnalysisUsage(AU);
5262 }
8191 LegalizerWorkListManager(InstListTy &Insts, ArtifactListTy &Arts)
8292 : InstList(Insts), ArtifactList(Arts) {}
8393
84 void createdInstr(const MachineInstr &MI) override {
94 void createdInstr(MachineInstr &MI) override {
8595 // Only legalize pre-isel generic instructions.
8696 // Legalization process could generate Target specific pseudo
8797 // instructions with generic types. Don't record them
94104 LLVM_DEBUG(dbgs() << ".. .. New MI: " << MI);
95105 }
96106
97 void erasingInstr(const MachineInstr &MI) override {
107 void erasingInstr(MachineInstr &MI) override {
98108 LLVM_DEBUG(dbgs() << ".. .. Erasing: " << MI);
99109 InstList.remove(&MI);
100110 ArtifactList.remove(&MI);
101111 }
102112
103 void changingInstr(const MachineInstr &MI) override {
113 void changingInstr(MachineInstr &MI) override {
104114 LLVM_DEBUG(dbgs() << ".. .. Changing MI: " << MI);
105115 }
106116
107 void changedInstr(const MachineInstr &MI) override {
117 void changedInstr(MachineInstr &MI) override {
108118 // When insts change, we want to revisit them to legalize them again.
109119 // We'll consider them the same as created.
110120 LLVM_DEBUG(dbgs() << ".. .. Changed MI: " << MI);
121131 LLVM_DEBUG(dbgs() << "Legalize Machine IR for: " << MF.getName() << '\n');
122132 init(MF);
123133 const TargetPassConfig &TPC = getAnalysis();
134 GISelCSEAnalysisWrapper &Wrapper =
135 getAnalysis().getCSEWrapper();
124136 MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
125137
126138 const size_t NumBlocks = MF.size();
127139 MachineRegisterInfo &MRI = MF.getRegInfo();
128140
129141 // Populate Insts
130 InstListTy InstList(&MF);
131 ArtifactListTy ArtifactList(&MF);
142 InstListTy InstList;
143 ArtifactListTy ArtifactList;
132144 ReversePostOrderTraversal RPOT(&MF);
133145 // Perform legalization bottom up so we can DCE as we legalize.
134146 // Traverse BB in RPOT and within each basic block, add insts top down,
147159 InstList.insert(&MI);
148160 }
149161 }
162 std::unique_ptr MIRBuilder;
163 GISelCSEInfo *CSEInfo = nullptr;
164 bool IsO0 = TPC.getOptLevel() == CodeGenOpt::Level::None;
165 // Disable CSE for O0.
166 bool EnableCSE = !IsO0 && EnableCSEInLegalizer;
167 if (EnableCSE) {
168 MIRBuilder = make_unique();
169 std::unique_ptr Config = make_unique();
170 CSEInfo = &Wrapper.get(std::move(Config));
171 MIRBuilder->setCSEInfo(CSEInfo);
172 } else
173 MIRBuilder = make_unique();
174 // This observer keeps the worklist updated.
150175 LegalizerWorkListManager WorkListObserver(InstList, ArtifactList);
151 LegalizerHelper Helper(MF, WorkListObserver);
176 // We want both WorkListObserver as well as CSEInfo to observe all changes.
177 // Use the wrapper observer.
178 GISelObserverWrapper WrapperObserver(&WorkListObserver);
179 if (EnableCSE && CSEInfo)
180 WrapperObserver.addObserver(CSEInfo);
181 // Now install the observer as the delegate to MF.
182 // This will keep all the observers notified about new insertions/deletions.
183 RAIIDelegateInstaller DelInstall(MF, &WrapperObserver);
184 LegalizerHelper Helper(MF, WrapperObserver, *MIRBuilder.get());
152185 const LegalizerInfo &LInfo(Helper.getLegalizerInfo());
153 LegalizationArtifactCombiner ArtCombiner(Helper.MIRBuilder, MF.getRegInfo(), LInfo);
154 auto RemoveDeadInstFromLists = [&WorkListObserver](MachineInstr *DeadMI) {
155 WorkListObserver.erasingInstr(*DeadMI);
186 LegalizationArtifactCombiner ArtCombiner(*MIRBuilder.get(), MF.getRegInfo(),
187 LInfo);
188 auto RemoveDeadInstFromLists = [&WrapperObserver](MachineInstr *DeadMI) {
189 WrapperObserver.erasingInstr(*DeadMI);
156190 };
157191 bool Changed = false;
158192 do {
3030 using namespace LegalizeActions;
3131
3232 LegalizerHelper::LegalizerHelper(MachineFunction &MF,
33 GISelChangeObserver &Observer)
34 : MRI(MF.getRegInfo()), LI(*MF.getSubtarget().getLegalizerInfo()),
35 Observer(Observer) {
33 GISelChangeObserver &Observer,
34 MachineIRBuilder &Builder)
35 : MIRBuilder(Builder), MRI(MF.getRegInfo()),
36 LI(*MF.getSubtarget().getLegalizerInfo()), Observer(Observer) {
3637 MIRBuilder.setMF(MF);
3738 MIRBuilder.setChangeObserver(Observer);
3839 }
3940
4041 LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI,
41 GISelChangeObserver &Observer)
42 : MRI(MF.getRegInfo()), LI(LI), Observer(Observer) {
42 GISelChangeObserver &Observer,
43 MachineIRBuilder &B)
44 : MIRBuilder(B), MRI(MF.getRegInfo()), LI(LI), Observer(Observer) {
4345 MIRBuilder.setMF(MF);
4446 MIRBuilder.setChangeObserver(Observer);
4547 }
4444 setMBB(*MI.getParent());
4545 State.II = MI.getIterator();
4646 }
47
48 void MachineIRBuilder::setCSEInfo(GISelCSEInfo *Info) { State.CSEInfo = Info; }
4749
4850 void MachineIRBuilder::setInsertPt(MachineBasicBlock &MBB,
4951 MachineBasicBlock::iterator II) {
234234 return APF;
235235 }
236236
237 Optional llvm::ConstantFoldBinOp(unsigned Opcode, const unsigned Op1,
238 const unsigned Op2,
239 const MachineRegisterInfo &MRI) {
240 auto MaybeOp1Cst = getConstantVRegVal(Op1, MRI);
241 auto MaybeOp2Cst = getConstantVRegVal(Op2, MRI);
242 if (MaybeOp1Cst && MaybeOp2Cst) {
243 LLT Ty = MRI.getType(Op1);
244 APInt C1(Ty.getSizeInBits(), *MaybeOp1Cst, true);
245 APInt C2(Ty.getSizeInBits(), *MaybeOp2Cst, true);
246 switch (Opcode) {
247 default:
248 break;
249 case TargetOpcode::G_ADD:
250 return C1 + C2;
251 case TargetOpcode::G_AND:
252 return C1 & C2;
253 case TargetOpcode::G_ASHR:
254 return C1.ashr(C2);
255 case TargetOpcode::G_LSHR:
256 return C1.lshr(C2);
257 case TargetOpcode::G_MUL:
258 return C1 * C2;
259 case TargetOpcode::G_OR:
260 return C1 | C2;
261 case TargetOpcode::G_SHL:
262 return C1 << C2;
263 case TargetOpcode::G_SUB:
264 return C1 - C2;
265 case TargetOpcode::G_XOR:
266 return C1 ^ C2;
267 case TargetOpcode::G_UDIV:
268 if (!C2.getBoolValue())
269 break;
270 return C1.udiv(C2);
271 case TargetOpcode::G_SDIV:
272 if (!C2.getBoolValue())
273 break;
274 return C1.sdiv(C2);
275 case TargetOpcode::G_UREM:
276 if (!C2.getBoolValue())
277 break;
278 return C1.urem(C2);
279 case TargetOpcode::G_SREM:
280 if (!C2.getBoolValue())
281 break;
282 return C1.srem(C2);
283 }
284 }
285 return None;
286 }
287
237288 void llvm::getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU) {
238289 AU.addPreserved();
239290 }
138138 init();
139139 }
140140
141 void MachineFunction::handleInsertion(const MachineInstr &MI) {
141 void MachineFunction::handleInsertion(MachineInstr &MI) {
142142 if (TheDelegate)
143143 TheDelegate->MF_HandleInsertion(MI);
144144 }
145145
146 void MachineFunction::handleRemoval(const MachineInstr &MI) {
146 void MachineFunction::handleRemoval(MachineInstr &MI) {
147147 if (TheDelegate)
148148 TheDelegate->MF_HandleRemoval(MI);
149149 }
8787 auto *TPC = &getAnalysis();
8888 AArch64PreLegalizerCombinerInfo PCInfo;
8989 Combiner C(PCInfo, TPC);
90 return C.combineMachineInstrs(MF);
90 return C.combineMachineInstrs(MF, /*CSEInfo*/ nullptr);
9191 }
9292
9393 char AArch64PreLegalizerCombiner::ID = 0;
7272 auto *TPC = &getAnalysis();
7373 MipsPreLegalizerCombinerInfo PCInfo;
7474 Combiner C(PCInfo, TPC);
75 return C.combineMachineInstrs(MF);
75 return C.combineMachineInstrs(MF, nullptr);
7676 }
7777
7878 char MipsPreLegalizerCombiner::ID = 0;
0 ; RUN: llc -mtriple=aarch64-linux-gnu -O1 -stop-after=irtranslator -enable-cse-in-irtranslator=1 -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s
1
2 ; CHECK-LABEL: name: test_split_struct
3 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
4 ; CHECK: [[LO:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.ptr)
5 ; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
6 ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST]](s64)
7 ; CHECK: [[HI:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 8 from %ir.ptr + 8)
8
9 ; CHECK: [[IMPDEF:%[0-9]+]]:_(s128) = G_IMPLICIT_DEF
10 ; CHECK: [[INS1:%[0-9]+]]:_(s128) = G_INSERT [[IMPDEF]], [[LO]](s64), 0
11 ; CHECK: [[INS2:%[0-9]+]]:_(s128) = G_INSERT [[INS1]], [[HI]](s64), 64
12 ; CHECK: [[EXTLO:%[0-9]+]]:_(s64) = G_EXTRACT [[INS2]](s128), 0
13 ; CHECK: [[EXTHI:%[0-9]+]]:_(s64) = G_EXTRACT [[INS2]](s128), 64
14
15 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
16 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
17 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST2]](s64)
18 ; CHECK: G_STORE [[EXTLO]](s64), [[GEP2]](p0) :: (store 8 into stack, align 0)
19 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
20 ; CHECK: [[CST3:%[0-9]+]]:_(s64) = COPY [[CST]]
21 ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST3]](s64)
22 ; CHECK: G_STORE [[EXTHI]](s64), [[GEP3]](p0) :: (store 8 into stack + 8, align 0)
23 define void @test_split_struct([2 x i64]* %ptr) {
24 %struct = load [2 x i64], [2 x i64]* %ptr
25 call void @take_split_struct([2 x i64]* null, i64 1, i64 2, i64 3,
26 i64 4, i64 5, i64 6,
27 [2 x i64] %struct)
28 ret void
29 }
30
31 declare void @take_split_struct([2 x i64]* %ptr, i64, i64, i64,
32 i64, i64, i64,
33 [2 x i64] %in) ;
4444 ; VERIFY-NEXT: Verify generated machine code
4545 ; ENABLED-NEXT: PreLegalizerCombiner
4646 ; VERIFY-NEXT: Verify generated machine code
47 ; ENABLED-NEXT: Analysis containing CSE Info
4748 ; ENABLED-NEXT: Legalizer
4849 ; VERIFY-NEXT: Verify generated machine code
4950 ; ENABLED-NEXT: RegBankSelect
0 # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
1 # RUN: llc -march=aarch64 -run-pass=legalizer %s -o - -enable-cse-in-legalizer=1 -O1 | FileCheck %s
2 ---
3 name: test_cse_in_legalizer
4 body: |
5 bb.0.entry:
6 ; CHECK-LABEL: name: test_cse_in_legalizer
7 ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x0
8 ; CHECK: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 255
9 ; CHECK: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC [[COPY]](s64)
10 ; CHECK: [[AND:%[0-9]+]]:_(s32) = G_AND [[TRUNC]], [[C]]
11 ; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY [[AND]](s32)
12 ; CHECK: $w0 = COPY [[COPY1]](s32)
13 ; CHECK: $w0 = COPY [[AND]](s32)
14 %0:_(s64) = COPY $x0
15 %1:_(s8) = G_TRUNC %0(s64)
16 %19:_(s32) = G_ZEXT %1(s8)
17 $w0 = COPY %19(s32)
18 %2:_(s8) = G_TRUNC %0(s64)
19 %20:_(s32) = G_ZEXT %2(s8)
20 $w0 = COPY %20(s32)
3131 ; CHECK-NEXT: Safe Stack instrumentation pass
3232 ; CHECK-NEXT: Insert stack protectors
3333 ; CHECK-NEXT: Module Verifier
34 ; CHECK-NEXT: Analysis containing CSE Info
3435 ; CHECK-NEXT: IRTranslator
3536 ; CHECK-NEXT: AArch64PreLegalizerCombiner
37 ; CHECK-NEXT: Analysis containing CSE Info
3638 ; CHECK-NEXT: Legalizer
3739 ; CHECK-NEXT: RegBankSelect
3840 ; CHECK-NEXT: Localizer
1212 LegalizerInfoTest.cpp
1313 PatternMatchTest.cpp
1414 LegalizerHelperTest.cpp
15 CSETest.cpp
1516 )
0 //===- CSETest.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 #include "GISelMITest.h"
10 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
11
12 namespace {
13
14 TEST_F(GISelMITest, TestCSE) {
15 if (!TM)
16 return;
17
18 LLT s16{LLT::scalar(16)};
19 LLT s32{LLT::scalar(32)};
20 auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]});
21 auto MIBInput1 = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[1]});
22 auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
23 GISelCSEInfo CSEInfo;
24 CSEInfo.setCSEConfig(make_unique());
25 CSEInfo.analyze(*MF);
26 B.setCSEInfo(&CSEInfo);
27 CSEMIRBuilder CSEB(B.getState());
28 CSEB.setInsertPt(*EntryMBB, EntryMBB->begin());
29 unsigned AddReg = MRI->createGenericVirtualRegister(s16);
30 auto MIBAddCopy =
31 CSEB.buildInstr(TargetOpcode::G_ADD, {AddReg}, {MIBInput, MIBInput});
32 ASSERT_EQ(MIBAddCopy->getOpcode(), TargetOpcode::COPY);
33 auto MIBAdd2 =
34 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
35 ASSERT_TRUE(&*MIBAdd == &*MIBAdd2);
36 auto MIBAdd4 =
37 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
38 ASSERT_TRUE(&*MIBAdd == &*MIBAdd4);
39 auto MIBAdd5 =
40 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput1});
41 ASSERT_TRUE(&*MIBAdd != &*MIBAdd5);
42
43 // Try building G_CONSTANTS.
44 auto MIBCst = CSEB.buildConstant(s32, 0);
45 auto MIBCst1 = CSEB.buildConstant(s32, 0);
46 ASSERT_TRUE(&*MIBCst == &*MIBCst1);
47 // Try the CFing of BinaryOps.
48 auto MIBCF1 = CSEB.buildInstr(TargetOpcode::G_ADD, {s32}, {MIBCst, MIBCst});
49 ASSERT_TRUE(&*MIBCF1 == &*MIBCst);
50
51 // Try out building FCONSTANTs.
52 auto MIBFP0 = CSEB.buildFConstant(s32, 1.0);
53 auto MIBFP0_1 = CSEB.buildFConstant(s32, 1.0);
54 ASSERT_TRUE(&*MIBFP0 == &*MIBFP0_1);
55 CSEInfo.print();
56
57 // Check G_UNMERGE_VALUES
58 auto MIBUnmerge = CSEB.buildUnmerge({s32, s32}, Copies[0]);
59 auto MIBUnmerge2 = CSEB.buildUnmerge({s32, s32}, Copies[0]);
60 ASSERT_TRUE(&*MIBUnmerge == &*MIBUnmerge2);
61 }
62
63 TEST_F(GISelMITest, TestCSEConstantConfig) {
64 if (!TM)
65 return;
66
67 LLT s16{LLT::scalar(16)};
68 auto MIBInput = B.buildInstr(TargetOpcode::G_TRUNC, {s16}, {Copies[0]});
69 auto MIBAdd = B.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
70 auto MIBZero = B.buildConstant(s16, 0);
71 GISelCSEInfo CSEInfo;
72 CSEInfo.setCSEConfig(make_unique());
73 CSEInfo.analyze(*MF);
74 B.setCSEInfo(&CSEInfo);
75 CSEMIRBuilder CSEB(B.getState());
76 CSEB.setInsertPt(*EntryMBB, EntryMBB->begin());
77 auto MIBAdd1 =
78 CSEB.buildInstr(TargetOpcode::G_ADD, {s16}, {MIBInput, MIBInput});
79 // We should CSE constants only. Adds should not be CSEd.
80 ASSERT_TRUE(MIBAdd1->getOpcode() != TargetOpcode::COPY);
81 ASSERT_TRUE(&*MIBAdd1 != &*MIBAdd);
82 // We should CSE constant.
83 auto MIBZeroTmp = CSEB.buildConstant(s16, 0);
84 ASSERT_TRUE(&*MIBZero == &*MIBZeroTmp);
85 }
86 } // namespace
0 //===- GISelMITest.h
1 //-----------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_UNITTEST_CODEGEN_GLOBALISEL_GISELMI_H
10 #define LLVM_UNITTEST_CODEGEN_GLOBALISEL_GISELMI_H
11
12 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
13 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
14 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
15 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
16 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
17 #include "llvm/CodeGen/GlobalISel/Utils.h"
18 #include "llvm/CodeGen/MIRParser/MIRParser.h"
19 #include "llvm/CodeGen/MachineFunction.h"
20 #include "llvm/CodeGen/MachineModuleInfo.h"
21 #include "llvm/CodeGen/TargetFrameLowering.h"
22 #include "llvm/CodeGen/TargetInstrInfo.h"
23 #include "llvm/CodeGen/TargetLowering.h"
24 #include "llvm/CodeGen/TargetSubtargetInfo.h"
25 #include "llvm/Support/FileCheck.h"
26 #include "llvm/Support/SourceMgr.h"
27 #include "llvm/Support/TargetRegistry.h"
28 #include "llvm/Support/TargetSelect.h"
29 #include "llvm/Target/TargetMachine.h"
30 #include "llvm/Target/TargetOptions.h"
31 #include "gtest/gtest.h"
32
33 using namespace llvm;
34 using namespace MIPatternMatch;
35
36 static inline void initLLVM() {
37 InitializeAllTargets();
38 InitializeAllTargetMCs();
39 InitializeAllAsmPrinters();
40 InitializeAllAsmParsers();
41
42 PassRegistry *Registry = PassRegistry::getPassRegistry();
43 initializeCore(*Registry);
44 initializeCodeGen(*Registry);
45 }
46
47 /// Create a TargetMachine. As we lack a dedicated always available target for
48 /// unittests, we go for "AArch64".
49 static std::unique_ptr createTargetMachine() {
50 Triple TargetTriple("aarch64--");
51 std::string Error;
52 const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
53 if (!T)
54 return nullptr;
55
56 TargetOptions Options;
57 return std::unique_ptr(
58 static_cast(T->createTargetMachine(
59 "AArch64", "", "", Options, None, None, CodeGenOpt::Aggressive)));
60 }
61
62 static std::unique_ptr parseMIR(LLVMContext &Context,
63 std::unique_ptr &MIR,
64 const TargetMachine &TM,
65 StringRef MIRCode, const char *FuncName,
66 MachineModuleInfo &MMI) {
67 SMDiagnostic Diagnostic;
68 std::unique_ptr MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
69 MIR = createMIRParser(std::move(MBuffer), Context);
70 if (!MIR)
71 return nullptr;
72
73 std::unique_ptr M = MIR->parseIRModule();
74 if (!M)
75 return nullptr;
76
77 M->setDataLayout(TM.createDataLayout());
78
79 if (MIR->parseMachineFunctions(*M, MMI))
80 return nullptr;
81
82 return M;
83 }
84
85 static std::pair, std::unique_ptr>
86 createDummyModule(LLVMContext &Context, const LLVMTargetMachine &TM,
87 StringRef MIRFunc) {
88 SmallString<512> S;
89 StringRef MIRString = (Twine(R"MIR(
90 ---
91 ...
92 name: func
93 registers:
94 - { id: 0, class: _ }
95 - { id: 1, class: _ }
96 - { id: 2, class: _ }
97 - { id: 3, class: _ }
98 body: |
99 bb.1:
100 %0(s64) = COPY $x0
101 %1(s64) = COPY $x1
102 %2(s64) = COPY $x2
103 )MIR") + Twine(MIRFunc) + Twine("...\n"))
104 .toNullTerminatedStringRef(S);
105 std::unique_ptr MIR;
106 auto MMI = make_unique(&TM);
107 std::unique_ptr M =
108 parseMIR(Context, MIR, TM, MIRString, "func", *MMI);
109 return make_pair(std::move(M), std::move(MMI));
110 }
111
112 static MachineFunction *getMFFromMMI(const Module *M,
113 const MachineModuleInfo *MMI) {
114 Function *F = M->getFunction("func");
115 auto *MF = MMI->getMachineFunction(*F);
116 return MF;
117 }
118
119 static void collectCopies(SmallVectorImpl &Copies,
120 MachineFunction *MF) {
121 for (auto &MBB : *MF)
122 for (MachineInstr &MI : MBB) {
123 if (MI.getOpcode() == TargetOpcode::COPY)
124 Copies.push_back(MI.getOperand(0).getReg());
125 }
126 }
127
128 class GISelMITest : public ::testing::Test {
129 protected:
130 GISelMITest() : ::testing::Test() {
131 TM = createTargetMachine();
132 if (!TM)
133 return;
134 ModuleMMIPair = createDummyModule(Context, *TM, "");
135 MF = getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
136 collectCopies(Copies, MF);
137 EntryMBB = &*MF->begin();
138 B.setMF(*MF);
139 MRI = &MF->getRegInfo();
140 B.setInsertPt(*EntryMBB, EntryMBB->end());
141 }
142 LLVMContext Context;
143 std::unique_ptr TM;
144 MachineFunction *MF;
145 std::pair, std::unique_ptr>
146 ModuleMMIPair;
147 SmallVector Copies;
148 MachineBasicBlock *EntryMBB;
149 MachineIRBuilder B;
150 MachineRegisterInfo *MRI;
151 };
152
153 #define DefineLegalizerInfo(Name, SettingUpActionsBlock) \
154 class Name##Info : public LegalizerInfo { \
155 public: \
156 Name##Info(const TargetSubtargetInfo &ST) { \
157 using namespace TargetOpcode; \
158 const LLT s8 = LLT::scalar(8); \
159 (void)s8; \
160 const LLT s16 = LLT::scalar(16); \
161 (void)s16; \
162 const LLT s32 = LLT::scalar(32); \
163 (void)s32; \
164 const LLT s64 = LLT::scalar(64); \
165 (void)s64; \
166 do \
167 SettingUpActionsBlock while (0); \
168 computeTables(); \
169 verify(*ST.getInstrInfo()); \
170 } \
171 };
172
173 static inline bool CheckMachineFunction(const MachineFunction &MF,
174 StringRef CheckStr) {
175 SmallString<512> Msg;
176 raw_svector_ostream OS(Msg);
177 MF.print(OS);
178 auto OutputBuf = MemoryBuffer::getMemBuffer(Msg, "Output", false);
179 auto CheckBuf = MemoryBuffer::getMemBuffer(CheckStr, "");
180 SmallString<4096> CheckFileBuffer;
181 FileCheckRequest Req;
182 FileCheck FC(Req);
183 StringRef CheckFileText =
184 FC.CanonicalizeFile(*CheckBuf.get(), CheckFileBuffer);
185 SourceMgr SM;
186 SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(CheckFileText, "CheckFile"),
187 SMLoc());
188 Regex PrefixRE = FC.buildCheckPrefixRegex();
189 std::vector CheckStrings;
190 FC.ReadCheckFile(SM, CheckFileText, PrefixRE, CheckStrings);
191 auto OutBuffer = OutputBuf->getBuffer();
192 SM.AddNewSourceBuffer(std::move(OutputBuf), SMLoc());
193 return FC.CheckInput(SM, OutBuffer, CheckStrings);
194 }
195 #endif
None //===- PatternMatchTest.cpp -----------------------------------------------===//
0 //===- LegalizerHelperTest.cpp
1 //-----------------------------------------------===//
12 //
23 // The LLVM Compiler Infrastructure
34 //
67 //
78 //===----------------------------------------------------------------------===//
89
9 #include "LegalizerHelperTest.h"
10 #include "GISelMITest.h"
1011
1112 namespace {
1213
1314 class DummyGISelObserver : public GISelChangeObserver {
1415 public:
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 {}
16 void changingInstr(MachineInstr &MI) override {}
17 void changedInstr(MachineInstr &MI) override {}
18 void createdInstr(MachineInstr &MI) override {}
19 void erasingInstr(MachineInstr &MI) override {}
1920 };
2021
2122 // Test CTTZ expansion when CTTZ_ZERO_UNDEF is legal or custom,
2223 // in which case it becomes CTTZ_ZERO_UNDEF with select.
23 TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ0) {
24 TEST_F(GISelMITest, LowerBitCountingCTTZ0) {
2425 if (!TM)
2526 return;
2627
3233 B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(64)}, {Copies[0]});
3334 AInfo Info(MF->getSubtarget());
3435 DummyGISelObserver Observer;
35 LegalizerHelper Helper(*MF, Info, Observer);
36 LegalizerHelper Helper(*MF, Info, Observer, B);
3637 // Perform Legalization
3738 ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
3839 LegalizerHelper::LegalizeResult::Legalized);
5051 }
5152
5253 // CTTZ expansion in terms of CTLZ
53 TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ1) {
54 TEST_F(GISelMITest, LowerBitCountingCTTZ1) {
5455 if (!TM)
5556 return;
5657
6263 B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(64)}, {Copies[0]});
6364 AInfo Info(MF->getSubtarget());
6465 DummyGISelObserver Observer;
65 LegalizerHelper Helper(*MF, Info, Observer);
66 LegalizerHelper Helper(*MF, Info, Observer, B);
6667 // Perform Legalization
6768 ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
6869 LegalizerHelper::LegalizeResult::Legalized);
8283 }
8384
8485 // CTTZ expansion in terms of CTPOP
85 TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ2) {
86 TEST_F(GISelMITest, LowerBitCountingCTTZ2) {
8687 if (!TM)
8788 return;
8889
9495 B.buildInstr(TargetOpcode::G_CTTZ, {LLT::scalar(64)}, {Copies[0]});
9596 AInfo Info(MF->getSubtarget());
9697 DummyGISelObserver Observer;
97 LegalizerHelper Helper(*MF, Info, Observer);
98 LegalizerHelper Helper(*MF, Info, Observer, B);
9899 ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
99100 LegalizerHelper::LegalizeResult::Legalized);
100101
111112 }
112113
113114 // CTTZ_ZERO_UNDEF expansion in terms of CTTZ
114 TEST_F(LegalizerHelperTest, LowerBitCountingCTTZ3) {
115 TEST_F(GISelMITest, LowerBitCountingCTTZ3) {
115116 if (!TM)
116117 return;
117118
123124 {LLT::scalar(64)}, {Copies[0]});
124125 AInfo Info(MF->getSubtarget());
125126 DummyGISelObserver Observer;
126 LegalizerHelper Helper(*MF, Info, Observer);
127 LegalizerHelper Helper(*MF, Info, Observer, B);
127128 ASSERT_TRUE(Helper.lower(*MIBCTTZ, 0, LLT::scalar(64)) ==
128129 LegalizerHelper::LegalizeResult::Legalized);
129130
136137 }
137138
138139 // CTLZ expansion in terms of CTLZ_ZERO_UNDEF
139 TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ0) {
140 TEST_F(GISelMITest, LowerBitCountingCTLZ0) {
140141 if (!TM)
141142 return;
142143
148149 B.buildInstr(TargetOpcode::G_CTLZ, {LLT::scalar(64)}, {Copies[0]});
149150 AInfo Info(MF->getSubtarget());
150151 DummyGISelObserver Observer;
151 LegalizerHelper Helper(*MF, Info, Observer);
152 LegalizerHelper Helper(*MF, Info, Observer, B);
152153 ASSERT_TRUE(Helper.lower(*MIBCTLZ, 0, LLT::scalar(64)) ==
153154 LegalizerHelper::LegalizeResult::Legalized);
154155
165166 }
166167
167168 // CTLZ expansion in terms of CTLZ_ZERO_UNDEF if the latter is a libcall
168 TEST_F(LegalizerHelperTest, LowerBitCountingCTLZLibcall) {
169 TEST_F(GISelMITest, LowerBitCountingCTLZLibcall) {
169170 if (!TM)
170171 return;
171172
177178 B.buildInstr(TargetOpcode::G_CTLZ, {LLT::scalar(64)}, {Copies[0]});
178179 AInfo Info(MF->getSubtarget());
179180 DummyGISelObserver Observer;
180 LegalizerHelper Helper(*MF, Info, Observer);
181 LegalizerHelper Helper(*MF, Info, Observer, B);
181182 ASSERT_TRUE(Helper.lower(*MIBCTLZ, 0, LLT::scalar(64)) ==
182183 LegalizerHelper::LegalizeResult::Legalized);
183184
194195 }
195196
196197 // CTLZ expansion
197 TEST_F(LegalizerHelperTest, LowerBitCountingCTLZ1) {
198 TEST_F(GISelMITest, LowerBitCountingCTLZ1) {
198199 if (!TM)
199200 return;
200201
208209 auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, {s8}, {MIBTrunc});
209210 AInfo Info(MF->getSubtarget());
210211 DummyGISelObserver Observer;
211 LegalizerHelper Helper(*MF, Info, Observer);
212 LegalizerHelper Helper(*MF, Info, Observer, B);
212213 ASSERT_TRUE(Helper.lower(*MIBCTLZ, 0, s8) ==
213214 LegalizerHelper::LegalizeResult::Legalized);
214215
233234 }
234235
235236 // CTLZ widening.
236 TEST_F(LegalizerHelperTest, WidenBitCountingCTLZ) {
237 TEST_F(GISelMITest, WidenBitCountingCTLZ) {
237238 if (!TM)
238239 return;
239240
248249 auto MIBCTLZ = B.buildInstr(TargetOpcode::G_CTLZ, {s8}, {MIBTrunc});
249250 AInfo Info(MF->getSubtarget());
250251 DummyGISelObserver Observer;
251 LegalizerHelper Helper(*MF, Info, Observer);
252 LegalizerHelper Helper(*MF, Info, Observer, B);
252253 ASSERT_TRUE(Helper.widenScalar(*MIBCTLZ, 0, s16) ==
253254 LegalizerHelper::LegalizeResult::Legalized);
254255
266267 }
267268
268269 // CTLZ_ZERO_UNDEF widening.
269 TEST_F(LegalizerHelperTest, WidenBitCountingCTLZZeroUndef) {
270 TEST_F(GISelMITest, WidenBitCountingCTLZZeroUndef) {
270271 if (!TM)
271272 return;
272273
282283 B.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF, {s8}, {MIBTrunc});
283284 AInfo Info(MF->getSubtarget());
284285 DummyGISelObserver Observer;
285 LegalizerHelper Helper(*MF, Info, Observer);
286 LegalizerHelper Helper(*MF, Info, Observer, B);
286287 ASSERT_TRUE(Helper.widenScalar(*MIBCTLZ_ZU, 0, s16) ==
287288 LegalizerHelper::LegalizeResult::Legalized);
288289
300301 }
301302
302303 // CTPOP widening.
303 TEST_F(LegalizerHelperTest, WidenBitCountingCTPOP) {
304 TEST_F(GISelMITest, WidenBitCountingCTPOP) {
304305 if (!TM)
305306 return;
306307
315316 auto MIBCTPOP = B.buildInstr(TargetOpcode::G_CTPOP, {s8}, {MIBTrunc});
316317 AInfo Info(MF->getSubtarget());
317318 DummyGISelObserver Observer;
318 LegalizerHelper Helper(*MF, Info, Observer);
319 LegalizerHelper Helper(*MF, Info, Observer, B);
319320 ASSERT_TRUE(Helper.widenScalar(*MIBCTPOP, 0, s16) ==
320321 LegalizerHelper::LegalizeResult::Legalized);
321322
331332 }
332333
333334 // CTTZ_ZERO_UNDEF widening.
334 TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ_ZERO_UNDEF) {
335 TEST_F(GISelMITest, WidenBitCountingCTTZ_ZERO_UNDEF) {
335336 if (!TM)
336337 return;
337338
347348 B.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF, {s8}, {MIBTrunc});
348349 AInfo Info(MF->getSubtarget());
349350 DummyGISelObserver Observer;
350 LegalizerHelper Helper(*MF, Info, Observer);
351 LegalizerHelper Helper(*MF, Info, Observer, B);
351352 ASSERT_TRUE(Helper.widenScalar(*MIBCTTZ_ZERO_UNDEF, 0, s16) ==
352353 LegalizerHelper::LegalizeResult::Legalized);
353354
363364 }
364365
365366 // CTTZ widening.
366 TEST_F(LegalizerHelperTest, WidenBitCountingCTTZ) {
367 TEST_F(GISelMITest, WidenBitCountingCTTZ) {
367368 if (!TM)
368369 return;
369370
378379 auto MIBCTTZ = B.buildInstr(TargetOpcode::G_CTTZ, {s8}, {MIBTrunc});
379380 AInfo Info(MF->getSubtarget());
380381 DummyGISelObserver Observer;
381 LegalizerHelper Helper(*MF, Info, Observer);
382 LegalizerHelper Helper(*MF, Info, Observer, B);
382383 ASSERT_TRUE(Helper.widenScalar(*MIBCTTZ, 0, s16) ==
383384 LegalizerHelper::LegalizeResult::Legalized);
384385
395396 ASSERT_TRUE(CheckMachineFunction(*MF, CheckStr));
396397 }
397398 // UADDO widening.
398 TEST_F(LegalizerHelperTest, WidenUADDO) {
399 TEST_F(GISelMITest, WidenUADDO) {
399400 if (!TM)
400401 return;
401402
412413 B.buildInstr(TargetOpcode::G_UADDO, {s8, CarryReg}, {MIBTrunc, MIBTrunc});
413414 AInfo Info(MF->getSubtarget());
414415 DummyGISelObserver Observer;
415 LegalizerHelper Helper(*MF, Info, Observer);
416 LegalizerHelper Helper(*MF, Info, Observer, B);
416417 ASSERT_TRUE(Helper.widenScalar(*MIBUAddO, 0, s16) ==
417418 LegalizerHelper::LegalizeResult::Legalized);
418419
432433 }
433434
434435 // USUBO widening.
435 TEST_F(LegalizerHelperTest, WidenUSUBO) {
436 TEST_F(GISelMITest, WidenUSUBO) {
436437 if (!TM)
437438 return;
438439
449450 B.buildInstr(TargetOpcode::G_USUBO, {s8, CarryReg}, {MIBTrunc, MIBTrunc});
450451 AInfo Info(MF->getSubtarget());
451452 DummyGISelObserver Observer;
452 LegalizerHelper Helper(*MF, Info, Observer);
453 LegalizerHelper Helper(*MF, Info, Observer, B);
453454 ASSERT_TRUE(Helper.widenScalar(*MIBUSUBO, 0, s16) ==
454455 LegalizerHelper::LegalizeResult::Legalized);
455456
+0
-192
unittests/CodeGen/GlobalISel/LegalizerHelperTest.h less more
None //===- LegalizerHelperTest.h
1 //-----------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
11 #include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
12 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
13 #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h"
14 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
15 #include "llvm/CodeGen/GlobalISel/Utils.h"
16 #include "llvm/CodeGen/MIRParser/MIRParser.h"
17 #include "llvm/CodeGen/MachineFunction.h"
18 #include "llvm/CodeGen/MachineModuleInfo.h"
19 #include "llvm/CodeGen/TargetFrameLowering.h"
20 #include "llvm/CodeGen/TargetInstrInfo.h"
21 #include "llvm/CodeGen/TargetLowering.h"
22 #include "llvm/CodeGen/TargetSubtargetInfo.h"
23 #include "llvm/Support/FileCheck.h"
24 #include "llvm/Support/SourceMgr.h"
25 #include "llvm/Support/TargetRegistry.h"
26 #include "llvm/Support/TargetSelect.h"
27 #include "llvm/Target/TargetMachine.h"
28 #include "llvm/Target/TargetOptions.h"
29 #include "gtest/gtest.h"
30
31 using namespace llvm;
32 using namespace MIPatternMatch;
33
34 void initLLVM() {
35 InitializeAllTargets();
36 InitializeAllTargetMCs();
37 InitializeAllAsmPrinters();
38 InitializeAllAsmParsers();
39
40 PassRegistry *Registry = PassRegistry::getPassRegistry();
41 initializeCore(*Registry);
42 initializeCodeGen(*Registry);
43 }
44
45 /// Create a TargetMachine. As we lack a dedicated always available target for
46 /// unittests, we go for "AArch64".
47 std::unique_ptr createTargetMachine() {
48 Triple TargetTriple("aarch64--");
49 std::string Error;
50 const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
51 if (!T)
52 return nullptr;
53
54 TargetOptions Options;
55 return std::unique_ptr(static_cast(
56 T->createTargetMachine("AArch64", "", "", Options, None, None,
57 CodeGenOpt::Aggressive)));
58 }
59
60 std::unique_ptr parseMIR(LLVMContext &Context,
61 std::unique_ptr &MIR,
62 const TargetMachine &TM, StringRef MIRCode,
63 const char *FuncName, MachineModuleInfo &MMI) {
64 SMDiagnostic Diagnostic;
65 std::unique_ptr MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
66 MIR = createMIRParser(std::move(MBuffer), Context);
67 if (!MIR)
68 return nullptr;
69
70 std::unique_ptr M = MIR->parseIRModule();
71 if (!M)
72 return nullptr;
73
74 M->setDataLayout(TM.createDataLayout());
75
76 if (MIR->parseMachineFunctions(*M, MMI))
77 return nullptr;
78
79 return M;
80 }
81
82 std::pair, std::unique_ptr>
83 createDummyModule(LLVMContext &Context, const LLVMTargetMachine &TM,
84 StringRef MIRFunc) {
85 SmallString<512> S;
86 StringRef MIRString = (Twine(R"MIR(
87 ---
88 ...
89 name: func
90 registers:
91 - { id: 0, class: _ }
92 - { id: 1, class: _ }
93 - { id: 2, class: _ }
94 - { id: 3, class: _ }
95 body: |
96 bb.1:
97 %0(s64) = COPY $x0
98 %1(s64) = COPY $x1
99 %2(s64) = COPY $x2
100 )MIR") + Twine(MIRFunc) + Twine("...\n"))
101 .toNullTerminatedStringRef(S);
102 std::unique_ptr MIR;
103 auto MMI = make_unique(&TM);
104 std::unique_ptr M =
105 parseMIR(Context, MIR, TM, MIRString, "func", *MMI);
106 return make_pair(std::move(M), std::move(MMI));
107 }
108
109 static MachineFunction *getMFFromMMI(const Module *M,
110 const MachineModuleInfo *MMI) {
111 Function *F = M->getFunction("func");
112 auto *MF = MMI->getMachineFunction(*F);
113 return MF;
114 }
115
116 static void collectCopies(SmallVectorImpl &Copies,
117 MachineFunction *MF) {
118 for (auto &MBB : *MF)
119 for (MachineInstr &MI : MBB) {
120 if (MI.getOpcode() == TargetOpcode::COPY)
121 Copies.push_back(MI.getOperand(0).getReg());
122 }
123 }
124
125 class LegalizerHelperTest : public ::testing::Test {
126 protected:
127 LegalizerHelperTest() : ::testing::Test() {
128 TM = createTargetMachine();
129 if (!TM)
130 return;
131 ModuleMMIPair = createDummyModule(Context, *TM, "");
132 MF = getMFFromMMI(ModuleMMIPair.first.get(), ModuleMMIPair.second.get());
133 collectCopies(Copies, MF);
134 EntryMBB = &*MF->begin();
135 B.setMF(*MF);
136 MRI = &MF->getRegInfo();
137 B.setInsertPt(*EntryMBB, EntryMBB->end());
138 }
139 LLVMContext Context;
140 std::unique_ptr TM;
141 MachineFunction *MF;
142 std::pair, std::unique_ptr>
143 ModuleMMIPair;
144 SmallVector Copies;
145 MachineBasicBlock *EntryMBB;
146 MachineIRBuilder B;
147 MachineRegisterInfo *MRI;
148 };
149
150 #define DefineLegalizerInfo(Name, SettingUpActionsBlock) \
151 class Name##Info : public LegalizerInfo { \
152 public: \
153 Name##Info(const TargetSubtargetInfo &ST) { \
154 using namespace TargetOpcode; \
155 const LLT s8 = LLT::scalar(8); \
156 (void)s8; \
157 const LLT s16 = LLT::scalar(16); \
158 (void)s16; \
159 const LLT s32 = LLT::scalar(32); \
160 (void)s32; \
161 const LLT s64 = LLT::scalar(64); \
162 (void)s64; \
163 do \
164 SettingUpActionsBlock while (0); \
165 computeTables(); \
166 verify(*ST.getInstrInfo()); \
167 } \
168 };
169
170 static bool CheckMachineFunction(const MachineFunction &MF,
171 StringRef CheckStr) {
172 SmallString<512> Msg;
173 raw_svector_ostream OS(Msg);
174 MF.print(OS);
175 auto OutputBuf = MemoryBuffer::getMemBuffer(Msg, "Output", false);
176 auto CheckBuf = MemoryBuffer::getMemBuffer(CheckStr, "");
177 SmallString<4096> CheckFileBuffer;
178 FileCheckRequest Req;
179 FileCheck FC(Req);
180 StringRef CheckFileText =
181 FC.CanonicalizeFile(*CheckBuf.get(), CheckFileBuffer);
182 SourceMgr SM;
183 SM.AddNewSourceBuffer(MemoryBuffer::getMemBuffer(CheckFileText, "CheckFile"),
184 SMLoc());
185 Regex PrefixRE = FC.buildCheckPrefixRegex();
186 std::vector CheckStrings;
187 FC.ReadCheckFile(SM, CheckFileText, PrefixRE, CheckStrings);
188 auto OutBuffer = OutputBuf->getBuffer();
189 SM.AddNewSourceBuffer(std::move(OutputBuf), SMLoc());
190 return FC.CheckInput(SM, OutBuffer, CheckStrings);
191 }