Skip to content

[SelectOpt] Add handling for not conditions. #92517

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 64 additions & 18 deletions llvm/lib/CodeGen/SelectOptimize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ class SelectOptimizeImpl {
class SelectLike {
SelectLike(Instruction *I) : I(I) {}

/// The select (/or) instruction.
Instruction *I;
/// Whether this select is inverted, "not(cond), FalseVal, TrueVal", as
/// opposed to the original condition.
bool Inverted = false;

public:
/// Match a select or select-like instruction, returning a SelectLike.
Expand All @@ -153,14 +157,22 @@ class SelectOptimizeImpl {
bool isValid() { return I; }
operator bool() { return isValid(); }

/// Invert the select by inverting the condition and switching the operands.
void setInverted() {
assert(!Inverted && "Trying to invert an inverted SelectLike");
assert(isa<Instruction>(getCondition()) &&
cast<Instruction>(getCondition())->getOpcode() ==
Instruction::Xor);
Inverted = true;
}
bool isInverted() const { return Inverted; }

Instruction *getI() { return I; }
const Instruction *getI() const { return I; }

Type *getType() const { return I->getType(); }

/// Return the condition for the SelectLike instruction. For example the
/// condition of a select or c in `or(zext(c), x)`
Value *getCondition() const {
Value *getNonInvertedCondition() const {
if (auto *Sel = dyn_cast<SelectInst>(I))
return Sel->getCondition();
// Or(zext) case
Expand All @@ -177,11 +189,24 @@ class SelectOptimizeImpl {
llvm_unreachable("Unhandled case in getCondition");
}

/// Return the condition for the SelectLike instruction. For example the
/// condition of a select or c in `or(zext(c), x)`
Value *getCondition() const {
Value *CC = getNonInvertedCondition();
// For inverted conditions the CC is checked when created to be a not
// (xor) instruction.
if (Inverted)
return cast<Instruction>(CC)->getOperand(0);
return CC;
}

/// Return the true value for the SelectLike instruction. Note this may not
/// exist for all SelectLike instructions. For example, for `or(zext(c), x)`
/// the true value would be `or(x,1)`. As this value does not exist, nullptr
/// is returned.
Value *getTrueValue() const {
Value *getTrueValue(bool HonorInverts = true) const {
if (Inverted && HonorInverts)
return getFalseValue(/*HonorInverts=*/false);
if (auto *Sel = dyn_cast<SelectInst>(I))
return Sel->getTrueValue();
// Or(zext) case - The true value is Or(X), so return nullptr as the value
Expand All @@ -195,7 +220,9 @@ class SelectOptimizeImpl {
/// Return the false value for the SelectLike instruction. For example the
/// getFalseValue of a select or `x` in `or(zext(c), x)` (which is
/// `select(c, x|1, x)`)
Value *getFalseValue() const {
Value *getFalseValue(bool HonorInverts = true) const {
if (Inverted && HonorInverts)
return getTrueValue(/*HonorInverts=*/false);
if (auto *Sel = dyn_cast<SelectInst>(I))
return Sel->getFalseValue();
// Or(zext) case - return the operand which is not the zext.
Expand All @@ -216,8 +243,8 @@ class SelectOptimizeImpl {
/// InstCostMap. This may need to be generated for select-like instructions.
Scaled64 getTrueOpCost(DenseMap<const Instruction *, CostInfo> &InstCostMap,
const TargetTransformInfo *TTI) {
if (auto *Sel = dyn_cast<SelectInst>(I))
if (auto *I = dyn_cast<Instruction>(Sel->getTrueValue()))
if (isa<SelectInst>(I))
if (auto *I = dyn_cast<Instruction>(getTrueValue()))
return InstCostMap.contains(I) ? InstCostMap[I].NonPredCost
: Scaled64::getZero();

Expand All @@ -242,8 +269,8 @@ class SelectOptimizeImpl {
Scaled64
getFalseOpCost(DenseMap<const Instruction *, CostInfo> &InstCostMap,
const TargetTransformInfo *TTI) {
if (auto *Sel = dyn_cast<SelectInst>(I))
if (auto *I = dyn_cast<Instruction>(Sel->getFalseValue()))
if (isa<SelectInst>(I))
if (auto *I = dyn_cast<Instruction>(getFalseValue()))
return InstCostMap.contains(I) ? InstCostMap[I].NonPredCost
: Scaled64::getZero();

Expand Down Expand Up @@ -510,9 +537,10 @@ getTrueOrFalseValue(SelectOptimizeImpl::SelectLike SI, bool isTrue,
for (SelectInst *DefSI = dyn_cast<SelectInst>(SI.getI());
DefSI != nullptr && Selects.count(DefSI);
DefSI = dyn_cast<SelectInst>(V)) {
assert(DefSI->getCondition() == SI.getCondition() &&
"The condition of DefSI does not match with SI");
V = (isTrue ? DefSI->getTrueValue() : DefSI->getFalseValue());
if (DefSI->getCondition() == SI.getCondition())
V = (isTrue ? DefSI->getTrueValue() : DefSI->getFalseValue());
else // Handle inverted SI
V = (!isTrue ? DefSI->getTrueValue() : DefSI->getFalseValue());
}

if (isa<BinaryOperator>(SI.getI())) {
Expand Down Expand Up @@ -632,18 +660,19 @@ void SelectOptimizeImpl::convertProfitableSIGroups(SelectGroups &ProfSIGroups) {
// Delete the unconditional branch that was just created by the split.
StartBlock->getTerminator()->eraseFromParent();

// Move any debug/pseudo instructions that were in-between the select
// group to the newly-created end block.
SmallVector<Instruction *, 2> DebugPseudoINS;
// Move any debug/pseudo instructions and not's that were in-between the
// select group to the newly-created end block.
SmallVector<Instruction *, 2> SinkInstrs;
auto DIt = SI.getI()->getIterator();
while (&*DIt != LastSI.getI()) {
if (DIt->isDebugOrPseudoInst())
DebugPseudoINS.push_back(&*DIt);
SinkInstrs.push_back(&*DIt);
if (match(&*DIt, m_Not(m_Specific(SI.getCondition()))))
SinkInstrs.push_back(&*DIt);
DIt++;
}
for (auto *DI : DebugPseudoINS) {
for (auto *DI : SinkInstrs)
DI->moveBeforePreserving(&*EndBlock->getFirstInsertionPt());
}

// Duplicate implementation for DbgRecords, the non-instruction debug-info
// format. Helper lambda for moving DbgRecords to the end block.
Expand Down Expand Up @@ -765,6 +794,13 @@ void SelectOptimizeImpl::collectSelectGroups(BasicBlock &BB,
++BBIt;
continue;
}

// Skip not(select(..)), if the not is part of the same select group
if (match(NI, m_Not(m_Specific(SI.getCondition())))) {
++BBIt;
continue;
}

// We only allow selects in the same group, not other select-like
// instructions.
if (!isa<SelectInst>(NI))
Expand All @@ -773,6 +809,10 @@ void SelectOptimizeImpl::collectSelectGroups(BasicBlock &BB,
SelectLike NSI = SelectLike::match(NI);
if (NSI && SI.getCondition() == NSI.getCondition()) {
SIGroup.push_back(NSI);
} else if (NSI && match(NSI.getCondition(),
m_Not(m_Specific(SI.getCondition())))) {
NSI.setInverted();
SIGroup.push_back(NSI);
} else
break;
++BBIt;
Expand All @@ -783,6 +823,12 @@ void SelectOptimizeImpl::collectSelectGroups(BasicBlock &BB,
if (!isSelectKindSupported(SI))
continue;

LLVM_DEBUG({
dbgs() << "New Select group with\n";
for (auto SI : SIGroup)
dbgs() << " " << *SI.getI() << "\n";
});

SIGroups.push_back(SIGroup);
}
}
Expand Down
Loading
Loading