18 #define DEBUG_TYPE "gi-combiner" 24 : Builder(B),
MRI(Builder.getMF().getRegInfo()), Observer(Observer) {}
27 unsigned ToReg)
const {
40 unsigned ToReg)
const {
67 struct PreferredTuple {
69 unsigned ExtendOpcode;
75 PreferredTuple ChoosePreferredUse(PreferredTuple &CurrentUse,
76 const LLT &TyForCandidate,
77 unsigned OpcodeForCandidate,
79 if (!CurrentUse.Ty.isValid()) {
80 if (CurrentUse.ExtendOpcode == OpcodeForCandidate ||
81 CurrentUse.ExtendOpcode == TargetOpcode::G_ANYEXT)
82 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
93 if (OpcodeForCandidate == TargetOpcode::G_ANYEXT &&
94 CurrentUse.ExtendOpcode != TargetOpcode::G_ANYEXT)
96 else if (CurrentUse.ExtendOpcode == TargetOpcode::G_ANYEXT &&
97 OpcodeForCandidate != TargetOpcode::G_ANYEXT)
98 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
102 if (CurrentUse.Ty == TyForCandidate) {
103 if (CurrentUse.ExtendOpcode == TargetOpcode::G_SEXT &&
104 OpcodeForCandidate == TargetOpcode::G_ZEXT)
106 else if (CurrentUse.ExtendOpcode == TargetOpcode::G_ZEXT &&
107 OpcodeForCandidate == TargetOpcode::G_SEXT)
108 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
116 if (TyForCandidate.
getSizeInBits() > CurrentUse.Ty.getSizeInBits()) {
117 return {TyForCandidate, OpcodeForCandidate, MIForCandidate};
128 static void InsertInsnsWithoutSideEffectsBeforeUse(
139 InsertBB = PredBB->
getMBB();
146 Inserter(InsertBB, std::next(InsertPt));
156 struct InsertionPoint {
162 : UseMO(UseMO), InsertIntoBB(InsertIntoBB), InsertBefore(InsertBefore) {
173 if (MI.
getOpcode() != TargetOpcode::G_LOAD &&
174 MI.
getOpcode() != TargetOpcode::G_SEXTLOAD &&
175 MI.
getOpcode() != TargetOpcode::G_ZEXTLOAD)
179 assert(LoadValue.isReg() &&
"Result wasn't a register?");
181 LLT LoadValueTy =
MRI.getType(LoadValue.getReg());
182 if (!LoadValueTy.isScalar())
190 unsigned PreferredOpcode = MI.
getOpcode() == TargetOpcode::G_LOAD
191 ? TargetOpcode::G_ANYEXT
192 : MI.
getOpcode() == TargetOpcode::G_SEXTLOAD
193 ? TargetOpcode::G_SEXT
194 : TargetOpcode::G_ZEXT;
195 PreferredTuple Preferred = {
LLT(), PreferredOpcode,
nullptr};
196 for (
auto &
UseMI :
MRI.use_instructions(LoadValue.getReg())) {
197 if (
UseMI.getOpcode() == TargetOpcode::G_SEXT ||
198 UseMI.getOpcode() == TargetOpcode::G_ZEXT ||
199 UseMI.getOpcode() == TargetOpcode::G_ANYEXT) {
200 Preferred = ChoosePreferredUse(Preferred,
201 MRI.getType(
UseMI.getOperand(0).getReg()),
211 assert(Preferred.Ty != LoadValueTy &&
"Extending to same type?");
216 unsigned ChosenDstReg = Preferred.MI->getOperand(0).getReg();
217 Observer.changingInstr(MI);
219 Builder.getTII().get(Preferred.ExtendOpcode == TargetOpcode::G_SEXT
220 ? TargetOpcode::G_SEXTLOAD
221 : Preferred.ExtendOpcode == TargetOpcode::G_ZEXT
222 ? TargetOpcode::G_ZEXTLOAD
223 : TargetOpcode::G_LOAD));
228 for (
auto &UseMO :
MRI.use_operands(LoadValue.getReg())) {
233 if (UseMI->
getOpcode() == Preferred.ExtendOpcode ||
234 UseMI->
getOpcode() == TargetOpcode::G_ANYEXT) {
237 const LLT &UseDstTy =
MRI.getType(UseDstReg);
238 if (UseDstReg != ChosenDstReg) {
239 if (Preferred.Ty == UseDstTy) {
250 ScheduleForErase.
push_back(UseMO.getParent());
251 }
else if (Preferred.Ty.getSizeInBits() < UseDstTy.
getSizeInBits()) {
275 InsertInsnsWithoutSideEffectsBeforeUse(
279 ScheduleForInsert.
emplace_back(&UseMO, InsertIntoBB, InsertBefore);
287 ScheduleForErase.
push_back(UseMO.getParent());
293 InsertInsnsWithoutSideEffectsBeforeUse(
297 ScheduleForInsert.
emplace_back(&UseMO, InsertIntoBB, InsertBefore);
302 for (
auto &InsertionInfo : ScheduleForInsert) {
307 MachineInstr *PreviouslyEmitted = EmittedInsns.lookup(InsertIntoBB);
308 if (PreviouslyEmitted) {
309 Observer.changingInstr(*UseMO->
getParent());
311 Observer.changedInstr(*UseMO->
getParent());
315 Builder.setInsertPt(*InsertIntoBB, InsertBefore);
317 MachineInstr *NewMI = Builder.buildTrunc(NewDstReg, ChosenDstReg);
318 EmittedInsns[InsertIntoBB] = NewMI;
321 for (
auto &EraseMI : ScheduleForErase) {
322 Observer.erasingInstr(*EraseMI);
323 EraseMI->eraseFromParent();
326 Observer.changedInstr(MI);
MachineInstr * getParent()
getParent - Return the instruction that this operand belongs to.
MachineBasicBlock * getMBB() const
This class represents lattice values for constants.
void push_back(const T &Elt)
unsigned getReg() const
getReg - Returns the register number.
bool tryCombine(MachineInstr &MI)
Try to transform MI by using all of the above combine functions.
bool constrainRegAttrs(unsigned Reg, unsigned ConstrainingReg, unsigned MinNumRegs=0)
Constrain the register class or the register bank of the virtual register Reg (and low-level type) to...
LLT getType(unsigned Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register...
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B)
void eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
void finishedChangingAllUsesOfReg()
All instructions reported as changing by changingAllUsesOfReg() have finished being changed...
Abstract class that contains various methods for clients to notify about changes. ...
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
unsigned const MachineRegisterInfo * MRI
void replaceRegWith(MachineRegisterInfo &MRI, unsigned FromReg, unsigned ToReg) const
MachineRegisterInfo::replaceRegWith() and inform the observer of the changes.
MachineInstrBuilder & UseMI
Helper class to build MachineInstr.
void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp, unsigned ToReg) const
Replace a single register operand with a new register and inform the observer of the changes...
bool tryCombineExtendingLoads(MachineInstr &MI)
If MI is extend that consumes the result of a load, try to combine it.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
bool tryCombineCopy(MachineInstr &MI)
If MI is COPY, try to combine it.
void changingAllUsesOfReg(const MachineRegisterInfo &MRI, unsigned Reg)
All the instructions using the given register are being changed.
void setDesc(const MCInstrDesc &tid)
Replace the instruction descriptor (thus opcode) of the current instruction with a new one...
MachineOperand class - Representation of each machine instruction operand.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
MachineInstrBuilder MachineInstrBuilder & DefMI
unsigned getSizeInBits() const
Returns the total size of the type. Must only be called on sized types.
This file declares the MachineIRBuilder class.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
virtual void changingInstr(MachineInstr &MI)=0
This instruction is about to be mutated in some way.
void replaceRegWith(unsigned FromReg, unsigned ToReg)
replaceRegWith - Replace all instances of FromReg with ToReg in the machine function.
const MachineBasicBlock * getParent() const
MachineRegisterInfo - Keep track of information for virtual and physical registers, including vreg register classes, use/def chains for registers, etc.
Representation of each machine instruction.
void emplace_back(ArgTypes &&... Args)
void setReg(unsigned Reg)
Change the register this operand corresponds to.
iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
print Print MemDeps of function
const MachineOperand & getOperand(unsigned i) const
virtual void changedInstr(MachineInstr &MI)=0
This instruction was mutated in some way.