Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

[LLVM][LV] Improve UF calculation for vscale based scalar loops.#146102

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
paulwalker-arm wants to merge4 commits intollvm:main
base:main
Choose a base branch
Loading
frompaulwalker-arm:interleave-sve-sized-loop

Conversation

paulwalker-arm
Copy link
Collaborator

Update getSmallConstantTripCount() to return scalable ElementCount values that is used to acurrately determine the maximum value for UF, namely:

TripCount / VF ==> X * VScale / Y * VScale ==> X / Y

This improves the chances of being able to remove the scalar loop and also fixes an issue where a UF=2 is choosen for a scalar loop with exactly VF(= X * VScale) iterations.

Update getSmallConstantTripCount() to return scalable ElementCountvalues that is used to acurrately determine the maximum value for UF,namely:  TripCount / VF ==> X * VScale / Y * VScale ==> X / YThis improves the chances of being able to remove the scalar loop andalso fixes an issue where a UF=2 is choosen for a scalar loop withexactly VF(= X * VScale) iterations.
@llvmbot
Copy link
Member

@llvm/pr-subscribers-llvm-transforms

Author: Paul Walker (paulwalker-arm)

Changes

Update getSmallConstantTripCount() to return scalable ElementCount values that is used to acurrately determine the maximum value for UF, namely:

TripCount / VF ==> X * VScale / Y * VScale ==> X / Y

This improves the chances of being able to remove the scalar loop and also fixes an issue where a UF=2 is choosen for a scalar loop with exactly VF(= X * VScale) iterations.


Full diff:https://github.com/llvm/llvm-project/pull/146102.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/LoopVectorize.cpp (+31-6)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.ll (+40-81)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cppindex bb29e4fc6d232..8a4435eed95bf 100644--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp@@ -423,7 +423,26 @@ static bool hasIrregularType(Type *Ty, const DataLayout &DL) { /// ElementCount to include loops whose trip count is a function of vscale. static ElementCount getSmallConstantTripCount(ScalarEvolution *SE,                                               const Loop *L) {-  return ElementCount::getFixed(SE->getSmallConstantTripCount(L));+  if (unsigned ExpectedTC = SE->getSmallConstantTripCount(L))+    return ElementCount::getFixed(ExpectedTC);++  const SCEV *BTC = SE->getBackedgeTakenCount(L);++  if (isa<SCEVCouldNotCompute>(BTC))+    return ElementCount::getFixed(0);++  const SCEV *ExitCount = SE->getTripCountFromExitCount(BTC, BTC->getType(), L);++  if (isa<SCEVVScale>(ExitCount))+    return ElementCount::getScalable(1);++  if (auto *Mul = dyn_cast<SCEVMulExpr>(ExitCount))+    if (Mul->getNumOperands() == 2 && isa<SCEVConstant>(Mul->getOperand(0)) &&+        isa<SCEVVScale>(Mul->getOperand(1)))+      return ElementCount::getScalable(+          cast<SCEVConstant>(Mul->getOperand(0))->getValue()->getZExtValue());++  return ElementCount::getFixed(0); }  /// Returns "best known" trip count, which is either a valid positive trip count@@ -4813,16 +4832,22 @@ LoopVectorizationCostModel::selectInterleaveCount(VPlan &Plan, ElementCount VF,       MaxInterleaveCount = ForceTargetMaxVectorInterleaveFactor;   }-  unsigned EstimatedVF = getEstimatedRuntimeVF(VF, VScaleForTuning);-   // Try to get the exact trip count, or an estimate based on profiling data or   // ConstantMax from PSE, failing that.-  if (auto BestKnownTC = getSmallBestKnownTC(PSE, TheLoop)) {+  auto BestKnownTC = getSmallBestKnownTC(PSE, TheLoop);++  // For fixed length VFs treat a scalable trip count as unknown.+  if (BestKnownTC && (BestKnownTC->isFixed() || VF.isScalable())) {+    // Re-evaluate VF to be in the same numerical space as the trip count.+    unsigned EstimatedVF = VF.getKnownMinValue();+    if (VF.isScalable() && BestKnownTC->isFixed())+      EstimatedVF = getEstimatedRuntimeVF(VF, VScaleForTuning);+     // At least one iteration must be scalar when this constraint holds. So the     // maximum available iterations for interleaving is one less.     unsigned AvailableTC = requiresScalarEpilogue(VF.isVector())-                               ? BestKnownTC->getFixedValue() - 1-                               : BestKnownTC->getFixedValue();+                               ? BestKnownTC->getKnownMinValue() - 1+                               : BestKnownTC->getKnownMinValue();      unsigned InterleaveCountLB = bit_floor(std::max(         1u, std::min(AvailableTC / (EstimatedVF * 2), MaxInterleaveCount)));diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.ll b/llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.llindex e2c7469a97819..dd1606c0f349a 100644--- a/llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.ll+++ b/llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.ll@@ -10,62 +10,35 @@ define void @vscale_mul_4(ptr noalias noundef readonly captures(none) %a, ptr no ; CHECK-NEXT:    [[TMP0:%.*]] = tail call i64 @llvm.vscale.i64() ; CHECK-NEXT:    [[TMP1:%.*]] = shl nuw nsw i64 [[TMP0]], 2 ; CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP3:%.*]] = mul nuw i64 [[TMP2]], 8-; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP1]], [[TMP3]]-; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]-; CHECK:       [[VECTOR_PH]]:+; CHECK-NEXT:    [[TMP3:%.*]] = mul nuw i64 [[TMP2]], 4 ; CHECK-NEXT:    [[TMP4:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP5:%.*]] = mul nuw i64 [[TMP4]], 8+; CHECK-NEXT:    [[TMP5:%.*]] = mul nuw i64 [[TMP4]], 4 ; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP1]], [[TMP5]] ; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP1]], [[N_MOD_VF]]-; CHECK-NEXT:    [[TMP10:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP7:%.*]] = mul nuw i64 [[TMP10]], 8-; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]]-; CHECK:       [[VECTOR_BODY]]:-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]-; CHECK-NEXT:    [[TMP13:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i64 [[INDEX]]-; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds nuw float, ptr [[TMP13]], i32 0-; CHECK-NEXT:    [[TMP18:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP11:%.*]] = mul nuw i64 [[TMP18]], 4-; CHECK-NEXT:    [[TMP26:%.*]] = getelementptr inbounds nuw float, ptr [[TMP13]], i64 [[TMP11]]-; CHECK-NEXT:    [[WIDE_LOAD2:%.*]] = load <vscale x 4 x float>, ptr [[TMP14]], align 4-; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <vscale x 4 x float>, ptr [[TMP26]], align 4-; CHECK-NEXT:    [[TMP12:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDEX]]-; CHECK-NEXT:    [[TMP17:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i32 0-; CHECK-NEXT:    [[TMP15:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP16:%.*]] = mul nuw i64 [[TMP15]], 4-; CHECK-NEXT:    [[TMP27:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i64 [[TMP16]]-; CHECK-NEXT:    [[WIDE_LOAD3:%.*]] = load <vscale x 4 x float>, ptr [[TMP17]], align 4-; CHECK-NEXT:    [[WIDE_LOAD4:%.*]] = load <vscale x 4 x float>, ptr [[TMP27]], align 4-; CHECK-NEXT:    [[TMP19:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD2]], [[WIDE_LOAD3]]-; CHECK-NEXT:    [[TMP28:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD1]], [[WIDE_LOAD4]]-; CHECK-NEXT:    [[TMP20:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP21:%.*]] = mul nuw i64 [[TMP20]], 4-; CHECK-NEXT:    [[TMP22:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i64 [[TMP21]]-; CHECK-NEXT:    store <vscale x 4 x float> [[TMP19]], ptr [[TMP17]], align 4-; CHECK-NEXT:    store <vscale x 4 x float> [[TMP28]], ptr [[TMP22]], align 4-; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP7]]-; CHECK-NEXT:    [[TMP23:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[TMP23]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]-; CHECK:       [[MIDDLE_BLOCK]]:+; CHECK-NEXT:    [[TMP6:%.*]] = call i64 @llvm.vscale.i64()+; CHECK-NEXT:    [[TMP7:%.*]] = mul nuw i64 [[TMP6]], 4+; CHECK-NEXT:    [[TMP8:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i32 0+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <vscale x 4 x float>, ptr [[TMP8]], align 4+; CHECK-NEXT:    [[TMP9:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i32 0+; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <vscale x 4 x float>, ptr [[TMP9]], align 4+; CHECK-NEXT:    [[TMP10:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD]], [[WIDE_LOAD1]]+; CHECK-NEXT:    [[TMP11:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i32 0+; CHECK-NEXT:    store <vscale x 4 x float> [[TMP10]], ptr [[TMP11]], align 4 ; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[TMP1]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[SCALAR_PH]]-; CHECK:       [[SCALAR_PH]]:-; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]-; CHECK-NEXT:    br label %[[FOR_BODY:.*]]+; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY:.*]] ; CHECK:       [[FOR_COND_CLEANUP]]: ; CHECK-NEXT:    ret void ; CHECK:       [[FOR_BODY]]:-; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[FOR_BODY]] ]+; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[N_VEC]], %[[ENTRY]] ] ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i64 [[INDVARS_IV]]-; CHECK-NEXT:    [[TMP24:%.*]] = load float, ptr [[ARRAYIDX]], align 4+; CHECK-NEXT:    [[TMP12:%.*]] = load float, ptr [[ARRAYIDX]], align 4 ; CHECK-NEXT:    [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDVARS_IV]]-; CHECK-NEXT:    [[TMP25:%.*]] = load float, ptr [[ARRAYIDX3]], align 4-; CHECK-NEXT:    [[MUL4:%.*]] = fmul float [[TMP24]], [[TMP25]]+; CHECK-NEXT:    [[TMP13:%.*]] = load float, ptr [[ARRAYIDX3]], align 4+; CHECK-NEXT:    [[MUL4:%.*]] = fmul float [[TMP12]], [[TMP13]] ; CHECK-NEXT:    store float [[MUL4]], ptr [[ARRAYIDX3]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[TMP1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP3:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -136,7 +109,7 @@ define  void @vscale_mul_8(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store float [[MUL5]], ptr [[ARRAYIDX4]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[MUL1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP3:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -166,43 +139,30 @@ define void @vscale_mul_12(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    [[TMP0:%.*]] = tail call i64 @llvm.vscale.i64() ; CHECK-NEXT:    [[MUL1:%.*]] = mul nuw nsw i64 [[TMP0]], 12 ; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP2:%.*]] = mul nuw i64 [[TMP1]], 8+; CHECK-NEXT:    [[TMP2:%.*]] = mul nuw i64 [[TMP1]], 4 ; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[MUL1]], [[TMP2]] ; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] ; CHECK:       [[VECTOR_PH]]: ; CHECK-NEXT:    [[TMP3:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP4:%.*]] = mul nuw i64 [[TMP3]], 8+; CHECK-NEXT:    [[TMP4:%.*]] = mul nuw i64 [[TMP3]], 4 ; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[MUL1]], [[TMP4]] ; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[MUL1]], [[N_MOD_VF]] ; CHECK-NEXT:    [[TMP5:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP6:%.*]] = mul nuw i64 [[TMP5]], 8+; CHECK-NEXT:    [[TMP6:%.*]] = mul nuw i64 [[TMP5]], 4 ; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]] ; CHECK:       [[VECTOR_BODY]]: ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] ; CHECK-NEXT:    [[TMP7:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i64 [[INDEX]] ; CHECK-NEXT:    [[TMP8:%.*]] = getelementptr inbounds nuw float, ptr [[TMP7]], i32 0-; CHECK-NEXT:    [[TMP9:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP10:%.*]] = mul nuw i64 [[TMP9]], 4-; CHECK-NEXT:    [[TMP11:%.*]] = getelementptr inbounds nuw float, ptr [[TMP7]], i64 [[TMP10]]-; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <vscale x 4 x float>, ptr [[TMP8]], align 4-; CHECK-NEXT:    [[WIDE_LOAD2:%.*]] = load <vscale x 4 x float>, ptr [[TMP11]], align 4-; CHECK-NEXT:    [[TMP12:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDEX]]-; CHECK-NEXT:    [[TMP13:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i32 0-; CHECK-NEXT:    [[TMP14:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP15:%.*]] = mul nuw i64 [[TMP14]], 4-; CHECK-NEXT:    [[TMP16:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i64 [[TMP15]]-; CHECK-NEXT:    [[WIDE_LOAD3:%.*]] = load <vscale x 4 x float>, ptr [[TMP13]], align 4-; CHECK-NEXT:    [[WIDE_LOAD4:%.*]] = load <vscale x 4 x float>, ptr [[TMP16]], align 4-; CHECK-NEXT:    [[TMP18:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD1]], [[WIDE_LOAD3]]-; CHECK-NEXT:    [[TMP25:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD2]], [[WIDE_LOAD4]]-; CHECK-NEXT:    [[TMP19:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP20:%.*]] = mul nuw i64 [[TMP19]], 4-; CHECK-NEXT:    [[TMP21:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i64 [[TMP20]]-; CHECK-NEXT:    store <vscale x 4 x float> [[TMP18]], ptr [[TMP13]], align 4-; CHECK-NEXT:    store <vscale x 4 x float> [[TMP25]], ptr [[TMP21]], align 4+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <vscale x 4 x float>, ptr [[TMP8]], align 4+; CHECK-NEXT:    [[TMP9:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDEX]]+; CHECK-NEXT:    [[TMP10:%.*]] = getelementptr inbounds nuw float, ptr [[TMP9]], i32 0+; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <vscale x 4 x float>, ptr [[TMP10]], align 4+; CHECK-NEXT:    [[TMP11:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD]], [[WIDE_LOAD1]]+; CHECK-NEXT:    store <vscale x 4 x float> [[TMP11]], ptr [[TMP10]], align 4 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP6]]-; CHECK-NEXT:    [[TMP22:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]]+; CHECK-NEXT:    [[TMP12:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]+; CHECK-NEXT:    br i1 [[TMP12]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]] ; CHECK:       [[MIDDLE_BLOCK]]: ; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[MUL1]], [[N_VEC]] ; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[SCALAR_PH]]@@ -214,14 +174,14 @@ define void @vscale_mul_12(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK:       [[FOR_BODY]]: ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[FOR_BODY]] ] ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i64 [[INDVARS_IV]]-; CHECK-NEXT:    [[TMP23:%.*]] = load float, ptr [[ARRAYIDX]], align 4+; CHECK-NEXT:    [[TMP13:%.*]] = load float, ptr [[ARRAYIDX]], align 4 ; CHECK-NEXT:    [[ARRAYIDX4:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDVARS_IV]]-; CHECK-NEXT:    [[TMP24:%.*]] = load float, ptr [[ARRAYIDX4]], align 4-; CHECK-NEXT:    [[MUL5:%.*]] = fmul float [[TMP23]], [[TMP24]]+; CHECK-NEXT:    [[TMP14:%.*]] = load float, ptr [[ARRAYIDX4]], align 4+; CHECK-NEXT:    [[MUL5:%.*]] = fmul float [[TMP13]], [[TMP14]] ; CHECK-NEXT:    store float [[MUL5]], ptr [[ARRAYIDX4]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[MUL1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -287,7 +247,7 @@ define void @vscale_mul_31(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store <vscale x 4 x float> [[TMP18]], ptr [[TMP21]], align 4 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP6]] ; CHECK-NEXT:    [[TMP22:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP7:![0-9]+]]+; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]] ; CHECK:       [[MIDDLE_BLOCK]]: ; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[MUL1]], [[N_VEC]] ; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[SCALAR_PH]]@@ -306,7 +266,7 @@ define void @vscale_mul_31(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store float [[MUL5]], ptr [[ARRAYIDX4]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[MUL1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP8:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP7:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -372,7 +332,7 @@ define void @vscale_mul_64(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store <vscale x 4 x float> [[TMP18]], ptr [[TMP21]], align 4 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP6]] ; CHECK-NEXT:    [[TMP22:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP9:![0-9]+]]+; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP8:![0-9]+]] ; CHECK:       [[MIDDLE_BLOCK]]: ; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[MUL1]], [[N_VEC]] ; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[SCALAR_PH]]@@ -391,7 +351,7 @@ define void @vscale_mul_64(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store float [[MUL5]], ptr [[ARRAYIDX4]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[MUL1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP10:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP9:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -419,14 +379,13 @@ declare i64 @llvm.vscale.i64() attributes #0 = { vscale_range(1,16) "target-features"="+sve" } ;. ; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}-; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}-; CHECK: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}-; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]}+; CHECK: [[META1]] = !{!"llvm.loop.unroll.runtime.disable"}+; CHECK: [[META2]] = !{!"llvm.loop.isvectorized", i32 1}+; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META1]], [[META2]]} ; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META2]], [[META1]]} ; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META1]], [[META2]]} ; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META2]], [[META1]]} ; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META1]], [[META2]]} ; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[META2]], [[META1]]} ; CHECK: [[LOOP9]] = distinct !{[[LOOP9]], [[META1]], [[META2]]}-; CHECK: [[LOOP10]] = distinct !{[[LOOP10]], [[META2]], [[META1]]} ;.

@llvmbot
Copy link
Member

@llvm/pr-subscribers-vectorizers

Author: Paul Walker (paulwalker-arm)

Changes

Update getSmallConstantTripCount() to return scalable ElementCount values that is used to acurrately determine the maximum value for UF, namely:

TripCount / VF ==> X * VScale / Y * VScale ==> X / Y

This improves the chances of being able to remove the scalar loop and also fixes an issue where a UF=2 is choosen for a scalar loop with exactly VF(= X * VScale) iterations.


Full diff:https://github.com/llvm/llvm-project/pull/146102.diff

2 Files Affected:

  • (modified) llvm/lib/Transforms/Vectorize/LoopVectorize.cpp (+31-6)
  • (modified) llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.ll (+40-81)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cppindex bb29e4fc6d232..8a4435eed95bf 100644--- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp+++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp@@ -423,7 +423,26 @@ static bool hasIrregularType(Type *Ty, const DataLayout &DL) { /// ElementCount to include loops whose trip count is a function of vscale. static ElementCount getSmallConstantTripCount(ScalarEvolution *SE,                                               const Loop *L) {-  return ElementCount::getFixed(SE->getSmallConstantTripCount(L));+  if (unsigned ExpectedTC = SE->getSmallConstantTripCount(L))+    return ElementCount::getFixed(ExpectedTC);++  const SCEV *BTC = SE->getBackedgeTakenCount(L);++  if (isa<SCEVCouldNotCompute>(BTC))+    return ElementCount::getFixed(0);++  const SCEV *ExitCount = SE->getTripCountFromExitCount(BTC, BTC->getType(), L);++  if (isa<SCEVVScale>(ExitCount))+    return ElementCount::getScalable(1);++  if (auto *Mul = dyn_cast<SCEVMulExpr>(ExitCount))+    if (Mul->getNumOperands() == 2 && isa<SCEVConstant>(Mul->getOperand(0)) &&+        isa<SCEVVScale>(Mul->getOperand(1)))+      return ElementCount::getScalable(+          cast<SCEVConstant>(Mul->getOperand(0))->getValue()->getZExtValue());++  return ElementCount::getFixed(0); }  /// Returns "best known" trip count, which is either a valid positive trip count@@ -4813,16 +4832,22 @@ LoopVectorizationCostModel::selectInterleaveCount(VPlan &Plan, ElementCount VF,       MaxInterleaveCount = ForceTargetMaxVectorInterleaveFactor;   }-  unsigned EstimatedVF = getEstimatedRuntimeVF(VF, VScaleForTuning);-   // Try to get the exact trip count, or an estimate based on profiling data or   // ConstantMax from PSE, failing that.-  if (auto BestKnownTC = getSmallBestKnownTC(PSE, TheLoop)) {+  auto BestKnownTC = getSmallBestKnownTC(PSE, TheLoop);++  // For fixed length VFs treat a scalable trip count as unknown.+  if (BestKnownTC && (BestKnownTC->isFixed() || VF.isScalable())) {+    // Re-evaluate VF to be in the same numerical space as the trip count.+    unsigned EstimatedVF = VF.getKnownMinValue();+    if (VF.isScalable() && BestKnownTC->isFixed())+      EstimatedVF = getEstimatedRuntimeVF(VF, VScaleForTuning);+     // At least one iteration must be scalar when this constraint holds. So the     // maximum available iterations for interleaving is one less.     unsigned AvailableTC = requiresScalarEpilogue(VF.isVector())-                               ? BestKnownTC->getFixedValue() - 1-                               : BestKnownTC->getFixedValue();+                               ? BestKnownTC->getKnownMinValue() - 1+                               : BestKnownTC->getKnownMinValue();      unsigned InterleaveCountLB = bit_floor(std::max(         1u, std::min(AvailableTC / (EstimatedVF * 2), MaxInterleaveCount)));diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.ll b/llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.llindex e2c7469a97819..dd1606c0f349a 100644--- a/llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.ll+++ b/llvm/test/Transforms/LoopVectorize/AArch64/sve-vscale-based-trip-counts.ll@@ -10,62 +10,35 @@ define void @vscale_mul_4(ptr noalias noundef readonly captures(none) %a, ptr no ; CHECK-NEXT:    [[TMP0:%.*]] = tail call i64 @llvm.vscale.i64() ; CHECK-NEXT:    [[TMP1:%.*]] = shl nuw nsw i64 [[TMP0]], 2 ; CHECK-NEXT:    [[TMP2:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP3:%.*]] = mul nuw i64 [[TMP2]], 8-; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[TMP1]], [[TMP3]]-; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]-; CHECK:       [[VECTOR_PH]]:+; CHECK-NEXT:    [[TMP3:%.*]] = mul nuw i64 [[TMP2]], 4 ; CHECK-NEXT:    [[TMP4:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP5:%.*]] = mul nuw i64 [[TMP4]], 8+; CHECK-NEXT:    [[TMP5:%.*]] = mul nuw i64 [[TMP4]], 4 ; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[TMP1]], [[TMP5]] ; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[TMP1]], [[N_MOD_VF]]-; CHECK-NEXT:    [[TMP10:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP7:%.*]] = mul nuw i64 [[TMP10]], 8-; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]]-; CHECK:       [[VECTOR_BODY]]:-; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]-; CHECK-NEXT:    [[TMP13:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i64 [[INDEX]]-; CHECK-NEXT:    [[TMP14:%.*]] = getelementptr inbounds nuw float, ptr [[TMP13]], i32 0-; CHECK-NEXT:    [[TMP18:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP11:%.*]] = mul nuw i64 [[TMP18]], 4-; CHECK-NEXT:    [[TMP26:%.*]] = getelementptr inbounds nuw float, ptr [[TMP13]], i64 [[TMP11]]-; CHECK-NEXT:    [[WIDE_LOAD2:%.*]] = load <vscale x 4 x float>, ptr [[TMP14]], align 4-; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <vscale x 4 x float>, ptr [[TMP26]], align 4-; CHECK-NEXT:    [[TMP12:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDEX]]-; CHECK-NEXT:    [[TMP17:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i32 0-; CHECK-NEXT:    [[TMP15:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP16:%.*]] = mul nuw i64 [[TMP15]], 4-; CHECK-NEXT:    [[TMP27:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i64 [[TMP16]]-; CHECK-NEXT:    [[WIDE_LOAD3:%.*]] = load <vscale x 4 x float>, ptr [[TMP17]], align 4-; CHECK-NEXT:    [[WIDE_LOAD4:%.*]] = load <vscale x 4 x float>, ptr [[TMP27]], align 4-; CHECK-NEXT:    [[TMP19:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD2]], [[WIDE_LOAD3]]-; CHECK-NEXT:    [[TMP28:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD1]], [[WIDE_LOAD4]]-; CHECK-NEXT:    [[TMP20:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP21:%.*]] = mul nuw i64 [[TMP20]], 4-; CHECK-NEXT:    [[TMP22:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i64 [[TMP21]]-; CHECK-NEXT:    store <vscale x 4 x float> [[TMP19]], ptr [[TMP17]], align 4-; CHECK-NEXT:    store <vscale x 4 x float> [[TMP28]], ptr [[TMP22]], align 4-; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP7]]-; CHECK-NEXT:    [[TMP23:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[TMP23]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]]-; CHECK:       [[MIDDLE_BLOCK]]:+; CHECK-NEXT:    [[TMP6:%.*]] = call i64 @llvm.vscale.i64()+; CHECK-NEXT:    [[TMP7:%.*]] = mul nuw i64 [[TMP6]], 4+; CHECK-NEXT:    [[TMP8:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i32 0+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <vscale x 4 x float>, ptr [[TMP8]], align 4+; CHECK-NEXT:    [[TMP9:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i32 0+; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <vscale x 4 x float>, ptr [[TMP9]], align 4+; CHECK-NEXT:    [[TMP10:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD]], [[WIDE_LOAD1]]+; CHECK-NEXT:    [[TMP11:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i32 0+; CHECK-NEXT:    store <vscale x 4 x float> [[TMP10]], ptr [[TMP11]], align 4 ; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[TMP1]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[SCALAR_PH]]-; CHECK:       [[SCALAR_PH]]:-; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]-; CHECK-NEXT:    br label %[[FOR_BODY:.*]]+; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[FOR_BODY:.*]] ; CHECK:       [[FOR_COND_CLEANUP]]: ; CHECK-NEXT:    ret void ; CHECK:       [[FOR_BODY]]:-; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[FOR_BODY]] ]+; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], %[[FOR_BODY]] ], [ [[N_VEC]], %[[ENTRY]] ] ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i64 [[INDVARS_IV]]-; CHECK-NEXT:    [[TMP24:%.*]] = load float, ptr [[ARRAYIDX]], align 4+; CHECK-NEXT:    [[TMP12:%.*]] = load float, ptr [[ARRAYIDX]], align 4 ; CHECK-NEXT:    [[ARRAYIDX3:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDVARS_IV]]-; CHECK-NEXT:    [[TMP25:%.*]] = load float, ptr [[ARRAYIDX3]], align 4-; CHECK-NEXT:    [[MUL4:%.*]] = fmul float [[TMP24]], [[TMP25]]+; CHECK-NEXT:    [[TMP13:%.*]] = load float, ptr [[ARRAYIDX3]], align 4+; CHECK-NEXT:    [[MUL4:%.*]] = fmul float [[TMP12]], [[TMP13]] ; CHECK-NEXT:    store float [[MUL4]], ptr [[ARRAYIDX3]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[TMP1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP3:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -136,7 +109,7 @@ define  void @vscale_mul_8(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store float [[MUL5]], ptr [[ARRAYIDX4]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[MUL1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP3:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -166,43 +139,30 @@ define void @vscale_mul_12(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    [[TMP0:%.*]] = tail call i64 @llvm.vscale.i64() ; CHECK-NEXT:    [[MUL1:%.*]] = mul nuw nsw i64 [[TMP0]], 12 ; CHECK-NEXT:    [[TMP1:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP2:%.*]] = mul nuw i64 [[TMP1]], 8+; CHECK-NEXT:    [[TMP2:%.*]] = mul nuw i64 [[TMP1]], 4 ; CHECK-NEXT:    [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[MUL1]], [[TMP2]] ; CHECK-NEXT:    br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]] ; CHECK:       [[VECTOR_PH]]: ; CHECK-NEXT:    [[TMP3:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP4:%.*]] = mul nuw i64 [[TMP3]], 8+; CHECK-NEXT:    [[TMP4:%.*]] = mul nuw i64 [[TMP3]], 4 ; CHECK-NEXT:    [[N_MOD_VF:%.*]] = urem i64 [[MUL1]], [[TMP4]] ; CHECK-NEXT:    [[N_VEC:%.*]] = sub i64 [[MUL1]], [[N_MOD_VF]] ; CHECK-NEXT:    [[TMP5:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP6:%.*]] = mul nuw i64 [[TMP5]], 8+; CHECK-NEXT:    [[TMP6:%.*]] = mul nuw i64 [[TMP5]], 4 ; CHECK-NEXT:    br label %[[VECTOR_BODY:.*]] ; CHECK:       [[VECTOR_BODY]]: ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ] ; CHECK-NEXT:    [[TMP7:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i64 [[INDEX]] ; CHECK-NEXT:    [[TMP8:%.*]] = getelementptr inbounds nuw float, ptr [[TMP7]], i32 0-; CHECK-NEXT:    [[TMP9:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP10:%.*]] = mul nuw i64 [[TMP9]], 4-; CHECK-NEXT:    [[TMP11:%.*]] = getelementptr inbounds nuw float, ptr [[TMP7]], i64 [[TMP10]]-; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <vscale x 4 x float>, ptr [[TMP8]], align 4-; CHECK-NEXT:    [[WIDE_LOAD2:%.*]] = load <vscale x 4 x float>, ptr [[TMP11]], align 4-; CHECK-NEXT:    [[TMP12:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDEX]]-; CHECK-NEXT:    [[TMP13:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i32 0-; CHECK-NEXT:    [[TMP14:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP15:%.*]] = mul nuw i64 [[TMP14]], 4-; CHECK-NEXT:    [[TMP16:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i64 [[TMP15]]-; CHECK-NEXT:    [[WIDE_LOAD3:%.*]] = load <vscale x 4 x float>, ptr [[TMP13]], align 4-; CHECK-NEXT:    [[WIDE_LOAD4:%.*]] = load <vscale x 4 x float>, ptr [[TMP16]], align 4-; CHECK-NEXT:    [[TMP18:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD1]], [[WIDE_LOAD3]]-; CHECK-NEXT:    [[TMP25:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD2]], [[WIDE_LOAD4]]-; CHECK-NEXT:    [[TMP19:%.*]] = call i64 @llvm.vscale.i64()-; CHECK-NEXT:    [[TMP20:%.*]] = mul nuw i64 [[TMP19]], 4-; CHECK-NEXT:    [[TMP21:%.*]] = getelementptr inbounds nuw float, ptr [[TMP12]], i64 [[TMP20]]-; CHECK-NEXT:    store <vscale x 4 x float> [[TMP18]], ptr [[TMP13]], align 4-; CHECK-NEXT:    store <vscale x 4 x float> [[TMP25]], ptr [[TMP21]], align 4+; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <vscale x 4 x float>, ptr [[TMP8]], align 4+; CHECK-NEXT:    [[TMP9:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDEX]]+; CHECK-NEXT:    [[TMP10:%.*]] = getelementptr inbounds nuw float, ptr [[TMP9]], i32 0+; CHECK-NEXT:    [[WIDE_LOAD1:%.*]] = load <vscale x 4 x float>, ptr [[TMP10]], align 4+; CHECK-NEXT:    [[TMP11:%.*]] = fmul <vscale x 4 x float> [[WIDE_LOAD]], [[WIDE_LOAD1]]+; CHECK-NEXT:    store <vscale x 4 x float> [[TMP11]], ptr [[TMP10]], align 4 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP6]]-; CHECK-NEXT:    [[TMP22:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]]+; CHECK-NEXT:    [[TMP12:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]+; CHECK-NEXT:    br i1 [[TMP12]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]] ; CHECK:       [[MIDDLE_BLOCK]]: ; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[MUL1]], [[N_VEC]] ; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[SCALAR_PH]]@@ -214,14 +174,14 @@ define void @vscale_mul_12(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK:       [[FOR_BODY]]: ; CHECK-NEXT:    [[INDVARS_IV:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[FOR_BODY]] ] ; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw float, ptr [[A]], i64 [[INDVARS_IV]]-; CHECK-NEXT:    [[TMP23:%.*]] = load float, ptr [[ARRAYIDX]], align 4+; CHECK-NEXT:    [[TMP13:%.*]] = load float, ptr [[ARRAYIDX]], align 4 ; CHECK-NEXT:    [[ARRAYIDX4:%.*]] = getelementptr inbounds nuw float, ptr [[B]], i64 [[INDVARS_IV]]-; CHECK-NEXT:    [[TMP24:%.*]] = load float, ptr [[ARRAYIDX4]], align 4-; CHECK-NEXT:    [[MUL5:%.*]] = fmul float [[TMP23]], [[TMP24]]+; CHECK-NEXT:    [[TMP14:%.*]] = load float, ptr [[ARRAYIDX4]], align 4+; CHECK-NEXT:    [[MUL5:%.*]] = fmul float [[TMP13]], [[TMP14]] ; CHECK-NEXT:    store float [[MUL5]], ptr [[ARRAYIDX4]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[MUL1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -287,7 +247,7 @@ define void @vscale_mul_31(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store <vscale x 4 x float> [[TMP18]], ptr [[TMP21]], align 4 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP6]] ; CHECK-NEXT:    [[TMP22:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP7:![0-9]+]]+; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]] ; CHECK:       [[MIDDLE_BLOCK]]: ; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[MUL1]], [[N_VEC]] ; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[SCALAR_PH]]@@ -306,7 +266,7 @@ define void @vscale_mul_31(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store float [[MUL5]], ptr [[ARRAYIDX4]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[MUL1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP8:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP7:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -372,7 +332,7 @@ define void @vscale_mul_64(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store <vscale x 4 x float> [[TMP18]], ptr [[TMP21]], align 4 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], [[TMP6]] ; CHECK-NEXT:    [[TMP22:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]-; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP9:![0-9]+]]+; CHECK-NEXT:    br i1 [[TMP22]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP8:![0-9]+]] ; CHECK:       [[MIDDLE_BLOCK]]: ; CHECK-NEXT:    [[CMP_N:%.*]] = icmp eq i64 [[MUL1]], [[N_VEC]] ; CHECK-NEXT:    br i1 [[CMP_N]], label %[[FOR_COND_CLEANUP:.*]], label %[[SCALAR_PH]]@@ -391,7 +351,7 @@ define void @vscale_mul_64(ptr noalias noundef readonly captures(none) %a, ptr n ; CHECK-NEXT:    store float [[MUL5]], ptr [[ARRAYIDX4]], align 4 ; CHECK-NEXT:    [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 ; CHECK-NEXT:    [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[MUL1]]-; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP10:![0-9]+]]+; CHECK-NEXT:    br i1 [[EXITCOND_NOT]], label %[[FOR_COND_CLEANUP]], label %[[FOR_BODY]], !llvm.loop [[LOOP9:![0-9]+]] ; entry:   %0 = tail call i64 @llvm.vscale.i64()@@ -419,14 +379,13 @@ declare i64 @llvm.vscale.i64() attributes #0 = { vscale_range(1,16) "target-features"="+sve" } ;. ; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]}-; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1}-; CHECK: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"}-; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]}+; CHECK: [[META1]] = !{!"llvm.loop.unroll.runtime.disable"}+; CHECK: [[META2]] = !{!"llvm.loop.isvectorized", i32 1}+; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META1]], [[META2]]} ; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META2]], [[META1]]} ; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META1]], [[META2]]} ; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META2]], [[META1]]} ; CHECK: [[LOOP7]] = distinct !{[[LOOP7]], [[META1]], [[META2]]} ; CHECK: [[LOOP8]] = distinct !{[[LOOP8]], [[META2]], [[META1]]} ; CHECK: [[LOOP9]] = distinct !{[[LOOP9]], [[META1]], [[META2]]}-; CHECK: [[LOOP10]] = distinct !{[[LOOP10]], [[META2]], [[META1]]} ;.

returnElementCount::getScalable(1);

if (auto *Mul = dyn_cast<SCEVMulExpr>(ExitCount))
if (Mul->getNumOperands() ==2 && isa<SCEVConstant>(Mul->getOperand(0)) &&
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Do we need to check overflow here?

Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Fixed both in terms of requiring NUW flags and ensuring the constant fits within the range of ElementCount.

@@ -423,7 +423,26 @@ static bool hasIrregularType(Type *Ty, const DataLayout &DL) {
/// ElementCount to include loops whose trip count is a function of vscale.
static ElementCountgetSmallConstantTripCount(ScalarEvolution *SE,
const Loop *L) {
returnElementCount::getFixed(SE->getSmallConstantTripCount(L));
if (unsigned ExpectedTC = SE->getSmallConstantTripCount(L))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This routine seems like it should live on SCEV itself. I was originally going to propose we change getSmallConstantTripCount to return ElementCount, but that looks mildly invasive. Maybe for the moment have a "getSmallConstantTripElementCount"? Not a huge fan of that name, but it's at least close...

Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

That's the route I started with but was advised to make the function specific to LoopVectorize, presumably until such a time that its applicability extends beyond vectorisation.

auto BestKnownTC =getSmallBestKnownTC(PSE, TheLoop);

// For fixed length VFs treat a scalable trip count as unknown.
if (BestKnownTC && (BestKnownTC->isFixed() || VF.isScalable())) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Style wise:
if (auto BestKnownTC = getSmallBestKnownTC(PSE, TheLoop);
BestKnownTC && (BestKnownTC->isFixed() || VF.isScalable())) {

paulwalker-arm reacted with thumbs up emoji
// At least one iteration must be scalar when this constraint holds. So the
// maximum available iterations for interleaving is one less.
unsigned AvailableTC =requiresScalarEpilogue(VF.isVector())
? BestKnownTC->getFixedValue() -1
: BestKnownTC->getFixedValue();
? BestKnownTC->getKnownMinValue() -1
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

For a scalable trip count, using the min value here seems off. Shouldn't we be using vscalefortuning here?

Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I don't think it matters because whenBestKnownTC is scalableEstimatedVF must also be scalable with all uses being to create ratios between the two. By usinggetKnownMinValue() we're just removing the common vscale factor.

That said, I don't much likegetKnownMinValue() so have changed the implementation to force everything to unsigned, be they know values or estimates, which as expected does not seem to affect the result but I feel looks more readable?

Please let me know if you'd rather I stick with the original approach.

if (auto BestKnownTC = getSmallBestKnownTC(PSE, TheLoop)) {
// ConstantMax from PSE, failing that. For fixed length VFs treat a scalable
// trip count as if unknown.
if (auto BestKnownTC = getSmallBestKnownTC(PSE, TheLoop);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I know this works, but I personally find it more readable to avoid multiple statements separated by; within anif(...) block, i.e. something like

  auto BestKnownTC = getSmallBestKnownTC(PSE, TheLoop);  if (BestKnownTC && (BestKnownTC->isFixed() || VF.isScalable())

Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

That is the style I originally used and@preames requested it be changed to this.

br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
}

; The known component of ElementCount is a 32-bit value.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Shouldn't that beThe known component of ElementCount does not fit into 32 bits?

Copy link
CollaboratorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

No. This is stating a fact, namely "ElementCount stores its known component as a 32-bit value", so as to explain why the test's trip count is too big for ElementCount.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@preamespreamespreames left review comments

@david-armdavid-armdavid-arm left review comments

@fhahnfhahnAwaiting requested review from fhahn

Assignees
No one assigned
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

4 participants
@paulwalker-arm@llvmbot@preames@david-arm

[8]ページ先頭

©2009-2025 Movatter.jp