Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Differential D109240 Diff 470113 llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
Changeset View
Changeset View
Standalone View
Standalone View
llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
Show First 20 Lines • Show All 802 Lines • ▼ Show 20 Lines | bool tryCombineUnmergeDefs(GUnmerge &MI, GISelChangeObserver &Observer, | ||||
// We only want to replace the uses, not the def of the old reg. | // We only want to replace the uses, not the def of the old reg. | ||||
Observer.changingInstr(MI); | Observer.changingInstr(MI); | ||||
MI.getOperand(DefIdx).setReg(DefReg); | MI.getOperand(DefIdx).setReg(DefReg); | ||||
Observer.changedInstr(MI); | Observer.changedInstr(MI); | ||||
DeadDefs[DefIdx] = true; | DeadDefs[DefIdx] = true; | ||||
} | } | ||||
return DeadDefs.all(); | return DeadDefs.all(); | ||||
} | } | ||||
GUnmerge *findUnmergeThatDefinesReg(Register Reg, unsigned Size, | |||||
unsigned &DefOperandIdx) { | |||||
if (Register Def = findValueFromDefImpl(Reg, 0, Size)) { | |||||
if (auto *Unmerge = dyn_cast<GUnmerge>(MRI.getVRegDef(Def))) { | |||||
DefOperandIdx = Unmerge->findRegisterDefOperandIdx(Def); | |||||
return Unmerge; | |||||
} | |||||
} | |||||
return nullptr; | |||||
} | |||||
// Check if sequence of elements from merge-like instruction is defined by | |||||
// another sequence of elements defined by unmerge. Most often this is the | |||||
// same sequence. Search for elements using findValueFromDefImpl. | |||||
bool isSequenceFromUnmerge(GMergeLikeOp &MI, unsigned MergeStartIdx, | |||||
GUnmerge *Unmerge, unsigned UnmergeIdxStart, | |||||
unsigned NumElts, unsigned EltSize) { | |||||
assert(MergeStartIdx + NumElts <= MI.getNumSources()); | |||||
for (unsigned i = MergeStartIdx; i < MergeStartIdx + NumElts; ++i) { | |||||
unsigned EltUnmergeIdx; | |||||
GUnmerge *EltUnmerge = findUnmergeThatDefinesReg( | |||||
MI.getSourceReg(i), EltSize, EltUnmergeIdx); | |||||
// Check if source i comes from the same Unmerge. | |||||
if (!EltUnmerge || EltUnmerge != Unmerge) | |||||
return false; | |||||
// Check that source i's def has same index in sequence in Unmerge. | |||||
if (i - MergeStartIdx != EltUnmergeIdx - UnmergeIdxStart) | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool tryCombineMergeLike(GMergeLikeOp &MI, | |||||
SmallVectorImpl<MachineInstr *> &DeadInsts, | |||||
SmallVectorImpl<Register> &UpdatedDefs, | |||||
GISelChangeObserver &Observer) { | |||||
Register Elt0 = MI.getSourceReg(0); | |||||
LLT EltTy = MRI.getType(Elt0); | |||||
unsigned EltSize = EltTy.getSizeInBits(); | |||||
unsigned Elt0UnmergeIdx; | |||||
// Search for unmerge that will be candidate for combine. | |||||
auto *Unmerge = findUnmergeThatDefinesReg(Elt0, EltSize, Elt0UnmergeIdx); | |||||
if (!Unmerge) | |||||
return false; | |||||
unsigned NumMIElts = MI.getNumSources(); | |||||
Register Dst = MI.getReg(0); | |||||
LLT DstTy = MRI.getType(Dst); | |||||
Register UnmergeSrc = Unmerge->getSourceReg(); | |||||
LLT UnmergeSrcTy = MRI.getType(UnmergeSrc); | |||||
// Recognize copy of UnmergeSrc to Dst. | |||||
// Unmerge UnmergeSrc and reassemble it using merge-like opcode into Dst. | |||||
// | |||||
// %0:_(EltTy), %1, ... = G_UNMERGE_VALUES %UnmergeSrc:_(Ty) | |||||
// %Dst:_(Ty) = G_merge_like_opcode %0:_(EltTy), %1, ... | |||||
// | |||||
// %Dst:_(Ty) = COPY %UnmergeSrc:_(Ty) | |||||
if ((DstTy == UnmergeSrcTy) && (Elt0UnmergeIdx == 0)) { | |||||
if (!isSequenceFromUnmerge(MI, 0, Unmerge, 0, NumMIElts, EltSize)) | |||||
return false; | |||||
replaceRegOrBuildCopy(Dst, UnmergeSrc, MRI, MIB, UpdatedDefs, Observer); | |||||
DeadInsts.push_back(&MI); | |||||
return true; | |||||
} | |||||
return false; | |||||
} | |||||
}; | }; | ||||
bool tryCombineUnmergeValues(GUnmerge &MI, | bool tryCombineUnmergeValues(GUnmerge &MI, | ||||
SmallVectorImpl<MachineInstr *> &DeadInsts, | SmallVectorImpl<MachineInstr *> &DeadInsts, | ||||
SmallVectorImpl<Register> &UpdatedDefs, | SmallVectorImpl<Register> &UpdatedDefs, | ||||
GISelChangeObserver &Observer) { | GISelChangeObserver &Observer) { | ||||
unsigned NumDefs = MI.getNumDefs(); | unsigned NumDefs = MI.getNumDefs(); | ||||
Register SrcReg = MI.getSourceReg(); | Register SrcReg = MI.getSourceReg(); | ||||
▲ Show 20 Lines • Show All 237 Lines • ▼ Show 20 Lines | bool tryCombineExtract(MachineInstr &MI, | ||||
Builder.setInstr(MI); | Builder.setInstr(MI); | ||||
Builder.buildExtract(DstReg, MergeI->getOperand(MergeSrcIdx + 1).getReg(), | Builder.buildExtract(DstReg, MergeI->getOperand(MergeSrcIdx + 1).getReg(), | ||||
Offset - MergeSrcIdx * MergeSrcSize); | Offset - MergeSrcIdx * MergeSrcSize); | ||||
UpdatedDefs.push_back(DstReg); | UpdatedDefs.push_back(DstReg); | ||||
markInstAndDefDead(MI, *MergeI, DeadInsts); | markInstAndDefDead(MI, *MergeI, DeadInsts); | ||||
return true; | return true; | ||||
} | } | ||||
/// Try to combine away MI. | /// Try to combine away MI. | ||||
arsenm: Should this be merged in with ArtifactValueFinder? | |||||
Do you mean whole function or some parts? Petar.Avramovic: Do you mean whole function or some parts?
To me this looks similar to other tryCombine… | |||||
Not Done ReplyInline ActionsI thought the plan was to move everything toward using ArtifactValueFinder, rather than continuing to try to add code to parse every permutation of artifacts arsenm: I thought the plan was to move everything toward using ArtifactValueFinder, rather than… | |||||
/// Returns true if it combined away the MI. | /// Returns true if it combined away the MI. | ||||
/// Adds instructions that are dead as a result of the combine | /// Adds instructions that are dead as a result of the combine | ||||
/// into DeadInsts, which can include MI. | /// into DeadInsts, which can include MI. | ||||
bool tryCombineInstruction(MachineInstr &MI, | bool tryCombineInstruction(MachineInstr &MI, | ||||
Not Done ReplyInline ActionsMove this below to where instructions could actually be inserted arsenm: Move this below to where instructions could actually be inserted | |||||
SmallVectorImpl<MachineInstr *> &DeadInsts, | SmallVectorImpl<MachineInstr *> &DeadInsts, | ||||
GISelObserverWrapper &WrapperObserver) { | GISelObserverWrapper &WrapperObserver) { | ||||
ArtifactValueFinder Finder(MRI, Builder, LI); | |||||
// This might be a recursive call, and we might have DeadInsts already | // This might be a recursive call, and we might have DeadInsts already | ||||
// populated. To avoid bad things happening later with multiple vreg defs | // populated. To avoid bad things happening later with multiple vreg defs | ||||
// etc, process the dead instructions now if any. | // etc, process the dead instructions now if any. | ||||
if (!DeadInsts.empty()) | if (!DeadInsts.empty()) | ||||
deleteMarkedDeadInsts(DeadInsts, WrapperObserver); | deleteMarkedDeadInsts(DeadInsts, WrapperObserver); | ||||
// Put here every vreg that was redefined in such a way that it's at least | // Put here every vreg that was redefined in such a way that it's at least | ||||
// possible that one (or more) of its users (immediate or COPY-separated) | // possible that one (or more) of its users (immediate or COPY-separated) | ||||
Show All 24 Lines | case TargetOpcode::G_CONCAT_VECTORS: | ||||
// artifact worklist in case there's folding that can be done looking up. | // artifact worklist in case there's folding that can be done looking up. | ||||
for (MachineInstr &U : MRI.use_instructions(MI.getOperand(0).getReg())) { | for (MachineInstr &U : MRI.use_instructions(MI.getOperand(0).getReg())) { | ||||
if (U.getOpcode() == TargetOpcode::G_UNMERGE_VALUES || | if (U.getOpcode() == TargetOpcode::G_UNMERGE_VALUES || | ||||
U.getOpcode() == TargetOpcode::G_TRUNC) { | U.getOpcode() == TargetOpcode::G_TRUNC) { | ||||
UpdatedDefs.push_back(MI.getOperand(0).getReg()); | UpdatedDefs.push_back(MI.getOperand(0).getReg()); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
Changed = Finder.tryCombineMergeLike(cast<GMergeLikeOp>(MI), DeadInsts, | |||||
UpdatedDefs, WrapperObserver); | |||||
break; | break; | ||||
case TargetOpcode::G_EXTRACT: | case TargetOpcode::G_EXTRACT: | ||||
Changed = tryCombineExtract(MI, DeadInsts, UpdatedDefs); | Changed = tryCombineExtract(MI, DeadInsts, UpdatedDefs); | ||||
break; | break; | ||||
case TargetOpcode::G_TRUNC: | case TargetOpcode::G_TRUNC: | ||||
Changed = tryCombineTrunc(MI, DeadInsts, UpdatedDefs, WrapperObserver); | Changed = tryCombineTrunc(MI, DeadInsts, UpdatedDefs, WrapperObserver); | ||||
if (!Changed) { | if (!Changed) { | ||||
// Try to combine truncates away even if they are legal. As all artifact | // Try to combine truncates away even if they are legal. As all artifact | ||||
Show All 15 Lines | while (!UpdatedDefs.empty()) { | ||||
switch (Use.getOpcode()) { | switch (Use.getOpcode()) { | ||||
// Keep this list in sync with the list of all artifact combines. | // Keep this list in sync with the list of all artifact combines. | ||||
case TargetOpcode::G_ANYEXT: | case TargetOpcode::G_ANYEXT: | ||||
case TargetOpcode::G_ZEXT: | case TargetOpcode::G_ZEXT: | ||||
case TargetOpcode::G_SEXT: | case TargetOpcode::G_SEXT: | ||||
case TargetOpcode::G_UNMERGE_VALUES: | case TargetOpcode::G_UNMERGE_VALUES: | ||||
case TargetOpcode::G_EXTRACT: | case TargetOpcode::G_EXTRACT: | ||||
case TargetOpcode::G_TRUNC: | case TargetOpcode::G_TRUNC: | ||||
case TargetOpcode::G_BUILD_VECTOR: | |||||
// Adding Use to ArtifactList. | // Adding Use to ArtifactList. | ||||
WrapperObserver.changedInstr(Use); | WrapperObserver.changedInstr(Use); | ||||
break; | break; | ||||
case TargetOpcode::COPY: { | case TargetOpcode::COPY: { | ||||
Register Copy = Use.getOperand(0).getReg(); | Register Copy = Use.getOperand(0).getReg(); | ||||
if (Copy.isVirtual()) | if (Copy.isVirtual()) | ||||
UpdatedDefs.push_back(Copy); | UpdatedDefs.push_back(Copy); | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 154 Lines • Show Last 20 Lines |
Should this be merged in with ArtifactValueFinder?