mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-26 05:25:47 +00:00
LoopVectorize: Handle loops with multiple forward inductions
We used to give up if we saw two integer inductions. After this patch, we base further induction variables on the chosen one like we do in the reverse induction and pointer induction case. Fixes PR15720. radar://13851975 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@181746 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -1389,9 +1389,10 @@ InnerLoopVectorizer::createEmptyLoop(LoopVectorizationLegality *Legal) {
|
|||||||
case LoopVectorizationLegality::IK_NoInduction:
|
case LoopVectorizationLegality::IK_NoInduction:
|
||||||
llvm_unreachable("Unknown induction");
|
llvm_unreachable("Unknown induction");
|
||||||
case LoopVectorizationLegality::IK_IntInduction: {
|
case LoopVectorizationLegality::IK_IntInduction: {
|
||||||
// Handle the integer induction counter:
|
// Handle the integer induction counter.
|
||||||
assert(OrigPhi->getType()->isIntegerTy() && "Invalid type");
|
assert(OrigPhi->getType()->isIntegerTy() && "Invalid type");
|
||||||
assert(OrigPhi == OldInduction && "Unknown integer PHI");
|
|
||||||
|
// We have the canonical induction variable.
|
||||||
if (OrigPhi == OldInduction) {
|
if (OrigPhi == OldInduction) {
|
||||||
// Create a truncated version of the resume value for the scalar loop,
|
// Create a truncated version of the resume value for the scalar loop,
|
||||||
// we might have promoted the type to a larger width.
|
// we might have promoted the type to a larger width.
|
||||||
@@ -1402,11 +1403,20 @@ InnerLoopVectorizer::createEmptyLoop(LoopVectorizationLegality *Legal) {
|
|||||||
for (unsigned I = 0, E = LoopBypassBlocks.size(); I != E; ++I)
|
for (unsigned I = 0, E = LoopBypassBlocks.size(); I != E; ++I)
|
||||||
TruncResumeVal->addIncoming(II.StartValue, LoopBypassBlocks[I]);
|
TruncResumeVal->addIncoming(II.StartValue, LoopBypassBlocks[I]);
|
||||||
TruncResumeVal->addIncoming(EndValue, VecBody);
|
TruncResumeVal->addIncoming(EndValue, VecBody);
|
||||||
|
|
||||||
|
// We know what the end value is.
|
||||||
|
EndValue = IdxEndRoundDown;
|
||||||
|
// We also know which PHI node holds it.
|
||||||
|
ResumeIndex = ResumeVal;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
// We know what the end value is.
|
|
||||||
EndValue = IdxEndRoundDown;
|
// Not the canonical induction variable - add the vector loop count to the
|
||||||
// We also know which PHI node holds it.
|
// start value.
|
||||||
ResumeIndex = ResumeVal;
|
Value *CRD = BypassBuilder.CreateSExtOrTrunc(CountRoundDown,
|
||||||
|
II.StartValue->getType(),
|
||||||
|
"cast.crd");
|
||||||
|
EndValue = BypassBuilder.CreateAdd(CRD, II.StartValue , "ind.end");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LoopVectorizationLegality::IK_ReverseIntInduction: {
|
case LoopVectorizationLegality::IK_ReverseIntInduction: {
|
||||||
@@ -2056,12 +2066,25 @@ InnerLoopVectorizer::vectorizeBlockInLoop(LoopVectorizationLegality *Legal,
|
|||||||
case LoopVectorizationLegality::IK_NoInduction:
|
case LoopVectorizationLegality::IK_NoInduction:
|
||||||
llvm_unreachable("Unknown induction");
|
llvm_unreachable("Unknown induction");
|
||||||
case LoopVectorizationLegality::IK_IntInduction: {
|
case LoopVectorizationLegality::IK_IntInduction: {
|
||||||
assert(P == OldInduction && "Unexpected PHI");
|
assert(P->getType() == II.StartValue->getType() && "Types must match");
|
||||||
// We might have had to extend the type.
|
Type *PhiTy = P->getType();
|
||||||
Value *Trunc = Builder.CreateTrunc(Induction, P->getType());
|
Value *Broadcasted;
|
||||||
Value *Broadcasted = getBroadcastInstrs(Trunc);
|
if (P == OldInduction) {
|
||||||
// After broadcasting the induction variable we need to make the
|
// Handle the canonical induction variable. We might have had to
|
||||||
// vector consecutive by adding 0, 1, 2 ...
|
// extend the type.
|
||||||
|
Broadcasted = Builder.CreateTrunc(Induction, PhiTy);
|
||||||
|
} else {
|
||||||
|
// Handle other induction variables that are now based on the
|
||||||
|
// canonical one.
|
||||||
|
Value *NormalizedIdx = Builder.CreateSub(Induction, ExtendedIdx,
|
||||||
|
"normalized.idx");
|
||||||
|
NormalizedIdx = Builder.CreateSExtOrTrunc(NormalizedIdx, PhiTy);
|
||||||
|
Broadcasted = Builder.CreateAdd(II.StartValue, NormalizedIdx,
|
||||||
|
"offset.idx");
|
||||||
|
}
|
||||||
|
Broadcasted = getBroadcastInstrs(Broadcasted);
|
||||||
|
// After broadcasting the induction variable we need to make the vector
|
||||||
|
// consecutive by adding 0, 1, 2, etc.
|
||||||
for (unsigned part = 0; part < UF; ++part)
|
for (unsigned part = 0; part < UF; ++part)
|
||||||
Entry[part] = getConsecutiveVector(Broadcasted, VF * part, false);
|
Entry[part] = getConsecutiveVector(Broadcasted, VF * part, false);
|
||||||
continue;
|
continue;
|
||||||
@@ -2466,11 +2489,11 @@ bool LoopVectorizationLegality::canVectorizeInstrs() {
|
|||||||
|
|
||||||
// Int inductions are special because we only allow one IV.
|
// Int inductions are special because we only allow one IV.
|
||||||
if (IK == IK_IntInduction) {
|
if (IK == IK_IntInduction) {
|
||||||
if (Induction) {
|
// Use the phi node with the widest type as induction. Use the last
|
||||||
DEBUG(dbgs() << "LV: Found too many inductions."<< *Phi <<"\n");
|
// one if there are multiple (no good reason for doing this other
|
||||||
return false;
|
// than it is expedient).
|
||||||
}
|
if (!Induction || PhiTy == WidestIndTy)
|
||||||
Induction = Phi;
|
Induction = Phi;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG(dbgs() << "LV: Found an induction variable.\n");
|
DEBUG(dbgs() << "LV: Found an induction variable.\n");
|
||||||
|
30
test/Transforms/LoopVectorize/induction.ll
Normal file
30
test/Transforms/LoopVectorize/induction.ll
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
; RUN: opt < %s -loop-vectorize -force-vector-unroll=1 -force-vector-width=2 -S | FileCheck %s
|
||||||
|
|
||||||
|
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
|
||||||
|
|
||||||
|
; Make sure that we can handle multiple integer induction variables.
|
||||||
|
; CHECK: multi_int_induction
|
||||||
|
; CHECK: vector.body:
|
||||||
|
; CHECK: %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
|
||||||
|
; CHECK: %normalized.idx = sub i64 %index, 0
|
||||||
|
; CHECK: %[[VAR:.*]] = trunc i64 %normalized.idx to i32
|
||||||
|
; CHECK: %offset.idx = add i32 190, %[[VAR]]
|
||||||
|
define void @multi_int_induction(i32* %A, i32 %N) {
|
||||||
|
for.body.lr.ph:
|
||||||
|
br label %for.body
|
||||||
|
|
||||||
|
for.body:
|
||||||
|
%indvars.iv = phi i64 [ 0, %for.body.lr.ph ], [ %indvars.iv.next, %for.body ]
|
||||||
|
%count.09 = phi i32 [ 190, %for.body.lr.ph ], [ %inc, %for.body ]
|
||||||
|
%arrayidx2 = getelementptr inbounds i32* %A, i64 %indvars.iv
|
||||||
|
store i32 %count.09, i32* %arrayidx2, align 4
|
||||||
|
%inc = add nsw i32 %count.09, 1
|
||||||
|
%indvars.iv.next = add i64 %indvars.iv, 1
|
||||||
|
%lftr.wideiv = trunc i64 %indvars.iv.next to i32
|
||||||
|
%exitcond = icmp ne i32 %lftr.wideiv, %N
|
||||||
|
br i1 %exitcond, label %for.body, label %for.end
|
||||||
|
|
||||||
|
for.end:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user