Skip to content

Commit 1b89079

Browse files
committed
[LV] Extend FindLastIV to unsigned case
In an effort to not have two different RecurKinds, one for the signed case, and another for the unsigned case, introduce RecurrenceDescriptor::isReduxSigned() to indicate whether the the RecurKind is of the signed or unsigned variant. Demonstrate its use by extending FindLastIV to the unsigned case.
1 parent ba57ff6 commit 1b89079

File tree

5 files changed

+213
-97
lines changed

5 files changed

+213
-97
lines changed

llvm/include/llvm/Analysis/IVDescriptors.h

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,13 @@ class RecurrenceDescriptor {
8080

8181
RecurrenceDescriptor(Value *Start, Instruction *Exit, StoreInst *Store,
8282
RecurKind K, FastMathFlags FMF, Instruction *ExactFP,
83-
Type *RT, bool Signed, bool Ordered,
84-
SmallPtrSetImpl<Instruction *> &CI,
83+
Type *RT, bool IsResultSigned, bool IsReduxSigned,
84+
bool Ordered, SmallPtrSetImpl<Instruction *> &CI,
8585
unsigned MinWidthCastToRecurTy)
8686
: IntermediateStore(Store), StartValue(Start), LoopExitInstr(Exit),
8787
Kind(K), FMF(FMF), ExactFPMathInst(ExactFP), RecurrenceType(RT),
88-
IsSigned(Signed), IsOrdered(Ordered),
88+
IsResultSigned(IsResultSigned), IsReduxSigned(IsReduxSigned),
89+
IsOrdered(Ordered),
8990
MinWidthCastToRecurrenceType(MinWidthCastToRecurTy) {
9091
CastInsts.insert_range(CI);
9192
}
@@ -97,12 +98,14 @@ class RecurrenceDescriptor {
9798
: IsRecurrence(IsRecur), PatternLastInst(I),
9899
RecKind(RecurKind::None), ExactFPMathInst(ExactFP) {}
99100

100-
InstDesc(Instruction *I, RecurKind K, Instruction *ExactFP = nullptr)
101-
: IsRecurrence(true), PatternLastInst(I), RecKind(K),
102-
ExactFPMathInst(ExactFP) {}
101+
InstDesc(Instruction *I, RecurKind K, bool IsSigned = false)
102+
: IsRecurrence(true), IsSigned(IsSigned), PatternLastInst(I),
103+
RecKind(K) {}
103104

104105
bool isRecurrence() const { return IsRecurrence; }
105106

107+
bool isSigned() const { return IsSigned; }
108+
106109
bool needsExactFPMath() const { return ExactFPMathInst != nullptr; }
107110

108111
Instruction *getExactFPMathInst() const { return ExactFPMathInst; }
@@ -114,13 +117,15 @@ class RecurrenceDescriptor {
114117
private:
115118
// Is this instruction a recurrence candidate.
116119
bool IsRecurrence;
120+
// Is this recurrence a signed variant.
121+
bool IsSigned = false;
117122
// The last instruction in a min/max pattern (select of the select(icmp())
118123
// pattern), or the current recurrence instruction otherwise.
119124
Instruction *PatternLastInst;
120125
// If this is a min/max pattern.
121126
RecurKind RecKind;
122127
// Recurrence does not allow floating-point reassociation.
123-
Instruction *ExactFPMathInst;
128+
Instruction *ExactFPMathInst = nullptr;
124129
};
125130

126131
/// Returns a struct describing if the instruction 'I' can be a recurrence
@@ -272,8 +277,9 @@ class RecurrenceDescriptor {
272277
Value *getSentinelValue() const {
273278
assert(isFindLastIVRecurrenceKind(Kind) && "Unexpected recurrence kind");
274279
Type *Ty = StartValue->getType();
275-
return ConstantInt::get(Ty,
276-
APInt::getSignedMinValue(Ty->getIntegerBitWidth()));
280+
unsigned BW = Ty->getIntegerBitWidth();
281+
return ConstantInt::get(Ty, isReduxSigned() ? APInt::getSignedMinValue(BW)
282+
: APInt::getMinValue(BW));
277283
}
278284

279285
/// Returns a reference to the instructions used for type-promoting the
@@ -285,8 +291,11 @@ class RecurrenceDescriptor {
285291
return MinWidthCastToRecurrenceType;
286292
}
287293

288-
/// Returns true if all source operands of the recurrence are SExtInsts.
289-
bool isSigned() const { return IsSigned; }
294+
/// Returns true if the reduction result is signed.
295+
bool isResultSigned() const { return IsResultSigned; }
296+
297+
/// Returns true if the reduction redux is signed.
298+
bool isReduxSigned() const { return IsReduxSigned; }
290299

291300
/// Expose an ordered FP reduction to the instance users.
292301
bool isOrdered() const { return IsOrdered; }
@@ -322,8 +331,10 @@ class RecurrenceDescriptor {
322331
Instruction *ExactFPMathInst = nullptr;
323332
// The type of the recurrence.
324333
Type *RecurrenceType = nullptr;
325-
// True if all source operands of the recurrence are SExtInsts.
326-
bool IsSigned = false;
334+
// True if reduction result is signed.
335+
bool IsResultSigned = false;
336+
// True if reduction redux is signed.
337+
bool IsReduxSigned = false;
327338
// True if this recurrence can be treated as an in-order reduction.
328339
// Currently only a non-reassociative FAdd can be considered in-order,
329340
// if it is also the only FAdd in the PHI's use chain.

llvm/lib/Analysis/IVDescriptors.cpp

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ static Instruction *lookThroughAnd(PHINode *Phi, Type *&RT,
8888
}
8989

9090
/// Compute the minimal bit width needed to represent a reduction whose exit
91-
/// instruction is given by Exit.
91+
/// instruction is given by Exit, along with its signedness.
9292
static std::pair<Type *, bool> computeRecurrenceType(Instruction *Exit,
9393
DemandedBits *DB,
9494
AssumptionCache *AC,
@@ -255,7 +255,7 @@ bool RecurrenceDescriptor::AddReductionVar(
255255
SmallPtrSet<Instruction *, 4> CastInsts;
256256
unsigned MinWidthCastToRecurrenceType;
257257
Instruction *Start = Phi;
258-
bool IsSigned = false;
258+
bool IsResultSigned = false, IsReduxSigned = false;
259259

260260
SmallPtrSet<Instruction *, 8> VisitedInsts;
261261
SmallVector<Instruction *, 8> Worklist;
@@ -396,6 +396,7 @@ bool RecurrenceDescriptor::AddReductionVar(
396396
// state accurate while processing the worklist?
397397
if (ReduxDesc.getRecKind() != RecurKind::None)
398398
Kind = ReduxDesc.getRecKind();
399+
IsReduxSigned = ReduxDesc.isSigned();
399400
}
400401

401402
bool IsASelect = isa<SelectInst>(Cur);
@@ -565,7 +566,7 @@ bool RecurrenceDescriptor::AddReductionVar(
565566
// smaller type. We should just generate a correctly typed expression
566567
// to begin with.
567568
Type *ComputedType;
568-
std::tie(ComputedType, IsSigned) =
569+
std::tie(ComputedType, IsResultSigned) =
569570
computeRecurrenceType(ExitInstruction, DB, AC, DT);
570571
if (ComputedType != RecurrenceType)
571572
return false;
@@ -595,8 +596,9 @@ bool RecurrenceDescriptor::AddReductionVar(
595596

596597
// Save the description of this reduction variable.
597598
RecurrenceDescriptor RD(RdxStart, ExitInstruction, IntermediateStore, Kind,
598-
FMF, ExactFPMathInst, RecurrenceType, IsSigned,
599-
IsOrdered, CastInsts, MinWidthCastToRecurrenceType);
599+
FMF, ExactFPMathInst, RecurrenceType, IsResultSigned,
600+
IsReduxSigned, IsOrdered, CastInsts,
601+
MinWidthCastToRecurrenceType);
600602
RedDes = RD;
601603

602604
return true;
@@ -700,47 +702,59 @@ RecurrenceDescriptor::isFindLastIVPattern(Loop *TheLoop, PHINode *OrigPhi,
700702
m_Value(NonRdxPhi)))))
701703
return InstDesc(false, I);
702704

703-
auto IsIncreasingLoopInduction = [&](Value *V) {
705+
// Returns a non-nullopt boolean indicating the signedness of the recurrence
706+
// when a valid FindLastIV pattern is found.
707+
auto GetInductionSignedness = [&](Value *V) -> std::optional<bool> {
704708
Type *Ty = V->getType();
705709
if (!SE.isSCEVable(Ty))
706-
return false;
710+
return std::nullopt;
707711

708712
auto *AR = dyn_cast<SCEVAddRecExpr>(SE.getSCEV(V));
709713
if (!AR || AR->getLoop() != TheLoop)
710-
return false;
714+
return std::nullopt;
711715

712716
const SCEV *Step = AR->getStepRecurrence(SE);
713717
if (!SE.isKnownPositive(Step))
714-
return false;
718+
return std::nullopt;
715719

716-
const ConstantRange IVRange = SE.getSignedRange(AR);
717-
unsigned NumBits = Ty->getIntegerBitWidth();
718720
// Keep the minimum value of the recurrence type as the sentinel value.
719721
// The maximum acceptable range for the increasing induction variable,
720722
// called the valid range, will be defined as
721723
// [<sentinel value> + 1, <sentinel value>)
722-
// where <sentinel value> is SignedMin(<recurrence type>)
724+
// where <sentinel value> is [Signed|Unsigned]Min(<recurrence type>)
723725
// TODO: This range restriction can be lifted by adding an additional
724726
// virtual OR reduction.
725-
const APInt Sentinel = APInt::getSignedMinValue(NumBits);
726-
const ConstantRange ValidRange =
727-
ConstantRange::getNonEmpty(Sentinel + 1, Sentinel);
728-
LLVM_DEBUG(dbgs() << "LV: FindLastIV valid range is " << ValidRange
729-
<< ", and the signed range of " << *AR << " is "
730-
<< IVRange << "\n");
731-
// Ensure the induction variable does not wrap around by verifying that its
732-
// range is fully contained within the valid range.
733-
return ValidRange.contains(IVRange);
727+
auto CheckRange = [&](bool IsSigned) {
728+
const ConstantRange IVRange =
729+
IsSigned ? SE.getSignedRange(AR) : SE.getUnsignedRange(AR);
730+
unsigned NumBits = Ty->getIntegerBitWidth();
731+
const APInt Sentinel = IsSigned ? APInt::getSignedMinValue(NumBits)
732+
: APInt::getMinValue(NumBits);
733+
const ConstantRange ValidRange =
734+
ConstantRange::getNonEmpty(Sentinel + 1, Sentinel);
735+
LLVM_DEBUG(dbgs() << "LV: FindLastIV valid range is " << ValidRange
736+
<< ", and the range of " << *AR << " is " << IVRange
737+
<< "\n");
738+
739+
// Ensure the induction variable does not wrap around by verifying that
740+
// its range is fully contained within the valid range.
741+
return ValidRange.contains(IVRange);
742+
};
743+
if (CheckRange(true))
744+
return true;
745+
if (CheckRange(false))
746+
return false;
747+
return std::nullopt;
734748
};
735749

736750
// We are looking for selects of the form:
737751
// select(cmp(), phi, increasing_loop_induction) or
738752
// select(cmp(), increasing_loop_induction, phi)
739753
// TODO: Support for monotonically decreasing induction variable
740-
if (!IsIncreasingLoopInduction(NonRdxPhi))
741-
return InstDesc(false, I);
754+
if (auto IsSigned = GetInductionSignedness(NonRdxPhi))
755+
return InstDesc(I, RecurKind::FindLastIV, *IsSigned);
742756

743-
return InstDesc(I, RecurKind::FindLastIV);
757+
return InstDesc(false, I);
744758
}
745759

746760
RecurrenceDescriptor::InstDesc

llvm/lib/Transforms/Vectorize/LoopVectorize.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9203,7 +9203,7 @@ void LoopVectorizationPlanner::adjustRecipesForReductions(
92039203
auto *Trunc =
92049204
new VPWidenCastRecipe(Instruction::Trunc, NewExitingVPV, RdxTy);
92059205
auto *Extnd =
9206-
RdxDesc.isSigned()
9206+
RdxDesc.isResultSigned()
92079207
? new VPWidenCastRecipe(Instruction::SExt, Trunc, PhiTy)
92089208
: new VPWidenCastRecipe(Instruction::ZExt, Trunc, PhiTy);
92099209

llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -621,8 +621,9 @@ Value *VPInstruction::generate(VPTransformState &State) {
621621
unsigned UF = getNumOperands() - 2;
622622
Value *ReducedPartRdx = State.get(getOperand(2));
623623
for (unsigned Part = 1; Part < UF; ++Part) {
624-
ReducedPartRdx = createMinMaxOp(Builder, RecurKind::SMax, ReducedPartRdx,
625-
State.get(getOperand(2 + Part)));
624+
ReducedPartRdx = createMinMaxOp(
625+
Builder, RdxDesc.isReduxSigned() ? RecurKind::SMax : RecurKind::UMax,
626+
ReducedPartRdx, State.get(getOperand(2 + Part)));
626627
}
627628

628629
return createFindLastIVReduction(Builder, ReducedPartRdx,
@@ -697,7 +698,7 @@ Value *VPInstruction::generate(VPTransformState &State) {
697698
// If the reduction can be performed in a smaller type, we need to extend
698699
// the reduction to the wider type before we branch to the original loop.
699700
if (PhiTy != RdxDesc.getRecurrenceType())
700-
ReducedPartRdx = RdxDesc.isSigned()
701+
ReducedPartRdx = RdxDesc.isResultSigned()
701702
? Builder.CreateSExt(ReducedPartRdx, PhiTy)
702703
: Builder.CreateZExt(ReducedPartRdx, PhiTy);
703704
}

0 commit comments

Comments
 (0)