|
@@ -34,6 +34,116 @@ bool RecurrenceDescriptor::areAllUsesIn(Instruction *I,
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+bool RecurrenceDescriptor::isIntegerRecurrenceKind(RecurrenceKind Kind) {
|
|
|
+ switch (Kind) {
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ case RK_IntegerAdd:
|
|
|
+ case RK_IntegerMult:
|
|
|
+ case RK_IntegerOr:
|
|
|
+ case RK_IntegerAnd:
|
|
|
+ case RK_IntegerXor:
|
|
|
+ case RK_IntegerMinMax:
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+bool RecurrenceDescriptor::isFloatingPointRecurrenceKind(RecurrenceKind Kind) {
|
|
|
+ return (Kind != RK_NoRecurrence) && !isIntegerRecurrenceKind(Kind);
|
|
|
+}
|
|
|
+
|
|
|
+bool RecurrenceDescriptor::isArithmeticRecurrenceKind(RecurrenceKind Kind) {
|
|
|
+ switch (Kind) {
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ case RK_IntegerAdd:
|
|
|
+ case RK_IntegerMult:
|
|
|
+ case RK_FloatAdd:
|
|
|
+ case RK_FloatMult:
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+Instruction *
|
|
|
+RecurrenceDescriptor::lookThroughAnd(PHINode *Phi, Type *&RT,
|
|
|
+ SmallPtrSetImpl<Instruction *> &Visited,
|
|
|
+ SmallPtrSetImpl<Instruction *> &CI) {
|
|
|
+ if (!Phi->hasOneUse())
|
|
|
+ return Phi;
|
|
|
+
|
|
|
+ const APInt *M = nullptr;
|
|
|
+ Instruction *I, *J = cast<Instruction>(Phi->use_begin()->getUser());
|
|
|
+
|
|
|
+ // Matches either I & 2^x-1 or 2^x-1 & I. If we find a match, we update RT
|
|
|
+ // with a new integer type of the corresponding bit width.
|
|
|
+ if (match(J, m_CombineOr(m_And(m_Instruction(I), m_APInt(M)),
|
|
|
+ m_And(m_APInt(M), m_Instruction(I))))) {
|
|
|
+ int32_t Bits = (*M + 1).exactLogBase2();
|
|
|
+ if (Bits > 0) {
|
|
|
+ RT = IntegerType::get(Phi->getContext(), Bits);
|
|
|
+ Visited.insert(Phi);
|
|
|
+ CI.insert(J);
|
|
|
+ return J;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return Phi;
|
|
|
+}
|
|
|
+
|
|
|
+bool RecurrenceDescriptor::getSourceExtensionKind(
|
|
|
+ Instruction *Start, Instruction *Exit, Type *RT, bool &IsSigned,
|
|
|
+ SmallPtrSetImpl<Instruction *> &Visited,
|
|
|
+ SmallPtrSetImpl<Instruction *> &CI) {
|
|
|
+
|
|
|
+ SmallVector<Instruction *, 8> Worklist;
|
|
|
+ bool FoundOneOperand = false;
|
|
|
+ Worklist.push_back(Exit);
|
|
|
+
|
|
|
+ // Traverse the instructions in the reduction expression, beginning with the
|
|
|
+ // exit value.
|
|
|
+ while (!Worklist.empty()) {
|
|
|
+ Instruction *I = Worklist.pop_back_val();
|
|
|
+ for (Use &U : I->operands()) {
|
|
|
+
|
|
|
+ // Terminate the traversal if the operand is not an instruction, or we
|
|
|
+ // reach the starting value.
|
|
|
+ Instruction *J = dyn_cast<Instruction>(U.get());
|
|
|
+ if (!J || J == Start)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ // Otherwise, investigate the operation if it is also in the expression.
|
|
|
+ if (Visited.count(J)) {
|
|
|
+ Worklist.push_back(J);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // If the operand is not in Visited, it is not a reduction operation, but
|
|
|
+ // it does feed into one. Make sure it is either a single-use sign- or
|
|
|
+ // zero-extend of the recurrence type.
|
|
|
+ CastInst *Cast = dyn_cast<CastInst>(J);
|
|
|
+ bool IsSExtInst = isa<SExtInst>(J);
|
|
|
+ if (!Cast || !Cast->hasOneUse() || Cast->getSrcTy() != RT ||
|
|
|
+ !(isa<ZExtInst>(J) || IsSExtInst))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ // Furthermore, ensure that all such extends are of the same kind.
|
|
|
+ if (FoundOneOperand) {
|
|
|
+ if (IsSigned != IsSExtInst)
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ FoundOneOperand = true;
|
|
|
+ IsSigned = IsSExtInst;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Lastly, add the sign- or zero-extend to CI so that we can avoid
|
|
|
+ // accounting for it in the cost model.
|
|
|
+ CI.insert(Cast);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
bool RecurrenceDescriptor::AddReductionVar(PHINode *Phi, RecurrenceKind Kind,
|
|
|
Loop *TheLoop, bool HasFunNoNaNAttr,
|
|
|
RecurrenceDescriptor &RedDes) {
|
|
@@ -68,10 +178,32 @@ bool RecurrenceDescriptor::AddReductionVar(PHINode *Phi, RecurrenceKind Kind,
|
|
|
unsigned NumCmpSelectPatternInst = 0;
|
|
|
InstDesc ReduxDesc(false, nullptr);
|
|
|
|
|
|
+ // Data used for determining if the recurrence has been type-promoted.
|
|
|
+ Type *RecurrenceType = Phi->getType();
|
|
|
+ SmallPtrSet<Instruction *, 4> CastInsts;
|
|
|
+ Instruction *Start = Phi;
|
|
|
+ bool IsSigned = false;
|
|
|
+
|
|
|
SmallPtrSet<Instruction *, 8> VisitedInsts;
|
|
|
SmallVector<Instruction *, 8> Worklist;
|
|
|
- Worklist.push_back(Phi);
|
|
|
- VisitedInsts.insert(Phi);
|
|
|
+
|
|
|
+ // Return early if the recurrence kind does not match the type of Phi. If the
|
|
|
+ // recurrence kind is arithmetic, we attempt to look through AND operations
|
|
|
+ // resulting from the type promotion performed by InstCombine. Vector
|
|
|
+ // operations are not limited to the legal integer widths, so we may be able
|
|
|
+ // to evaluate the reduction in the narrower width.
|
|
|
+ if (RecurrenceType->isFloatingPointTy()) {
|
|
|
+ if (!isFloatingPointRecurrenceKind(Kind))
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ if (!isIntegerRecurrenceKind(Kind))
|
|
|
+ return false;
|
|
|
+ if (isArithmeticRecurrenceKind(Kind))
|
|
|
+ Start = lookThroughAnd(Phi, RecurrenceType, VisitedInsts, CastInsts);
|
|
|
+ }
|
|
|
+
|
|
|
+ Worklist.push_back(Start);
|
|
|
+ VisitedInsts.insert(Start);
|
|
|
|
|
|
// A value in the reduction can be used:
|
|
|
// - By the reduction:
|
|
@@ -110,10 +242,14 @@ bool RecurrenceDescriptor::AddReductionVar(PHINode *Phi, RecurrenceKind Kind,
|
|
|
!VisitedInsts.count(dyn_cast<Instruction>(Cur->getOperand(0))))
|
|
|
return false;
|
|
|
|
|
|
- // Any reduction instruction must be of one of the allowed kinds.
|
|
|
- ReduxDesc = isRecurrenceInstr(Cur, Kind, ReduxDesc, HasFunNoNaNAttr);
|
|
|
- if (!ReduxDesc.isRecurrence())
|
|
|
- return false;
|
|
|
+ // Any reduction instruction must be of one of the allowed kinds. We ignore
|
|
|
+ // the starting value (the Phi or an AND instruction if the Phi has been
|
|
|
+ // type-promoted).
|
|
|
+ if (Cur != Start) {
|
|
|
+ ReduxDesc = isRecurrenceInstr(Cur, Kind, ReduxDesc, HasFunNoNaNAttr);
|
|
|
+ if (!ReduxDesc.isRecurrence())
|
|
|
+ return false;
|
|
|
+ }
|
|
|
|
|
|
// A reduction operation must only have one use of the reduction value.
|
|
|
if (!IsAPhi && Kind != RK_IntegerMinMax && Kind != RK_FloatMinMax &&
|
|
@@ -131,7 +267,7 @@ bool RecurrenceDescriptor::AddReductionVar(PHINode *Phi, RecurrenceKind Kind,
|
|
|
++NumCmpSelectPatternInst;
|
|
|
|
|
|
// Check whether we found a reduction operator.
|
|
|
- FoundReduxOp |= !IsAPhi;
|
|
|
+ FoundReduxOp |= !IsAPhi && Cur != Start;
|
|
|
|
|
|
// Process users of current instruction. Push non-PHI nodes after PHI nodes
|
|
|
// onto the stack. This way we are going to have seen all inputs to PHI
|
|
@@ -193,6 +329,14 @@ bool RecurrenceDescriptor::AddReductionVar(PHINode *Phi, RecurrenceKind Kind,
|
|
|
if (!FoundStartPHI || !FoundReduxOp || !ExitInstruction)
|
|
|
return false;
|
|
|
|
|
|
+ // If we think Phi may have been type-promoted, we also need to ensure that
|
|
|
+ // all source operands of the reduction are either SExtInsts or ZEstInsts. If
|
|
|
+ // so, we will be able to evaluate the reduction in the narrower bit width.
|
|
|
+ if (Start != Phi)
|
|
|
+ if (!getSourceExtensionKind(Start, ExitInstruction, RecurrenceType,
|
|
|
+ IsSigned, VisitedInsts, CastInsts))
|
|
|
+ return false;
|
|
|
+
|
|
|
// We found a reduction var if we have reached the original phi node and we
|
|
|
// only have a single instruction with out-of-loop users.
|
|
|
|
|
@@ -200,10 +344,9 @@ bool RecurrenceDescriptor::AddReductionVar(PHINode *Phi, RecurrenceKind Kind,
|
|
|
// is saved as part of the RecurrenceDescriptor.
|
|
|
|
|
|
// Save the description of this reduction variable.
|
|
|
- RecurrenceDescriptor RD(RdxStart, ExitInstruction, Kind,
|
|
|
- ReduxDesc.getMinMaxKind(),
|
|
|
- ReduxDesc.getUnsafeAlgebraInst());
|
|
|
-
|
|
|
+ RecurrenceDescriptor RD(
|
|
|
+ RdxStart, ExitInstruction, Kind, ReduxDesc.getMinMaxKind(),
|
|
|
+ ReduxDesc.getUnsafeAlgebraInst(), RecurrenceType, IsSigned, CastInsts);
|
|
|
RedDes = RD;
|
|
|
|
|
|
return true;
|
|
@@ -272,9 +415,6 @@ RecurrenceDescriptor::isRecurrenceInstr(Instruction *I, RecurrenceKind Kind,
|
|
|
default:
|
|
|
return InstDesc(false, I);
|
|
|
case Instruction::PHI:
|
|
|
- if (FP &&
|
|
|
- (Kind != RK_FloatMult && Kind != RK_FloatAdd && Kind != RK_FloatMinMax))
|
|
|
- return InstDesc(false, I);
|
|
|
return InstDesc(I, Prev.getMinMaxKind());
|
|
|
case Instruction::Sub:
|
|
|
case Instruction::Add:
|