[llvm] [VPlan][LV] Add removeRedundantAndMasks to VPlanTransforms (PR #163534)
John Brawn via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 27 07:43:03 PDT 2025
================
@@ -4406,3 +4406,146 @@ void VPlanTransforms::addExitUsersForFirstOrderRecurrences(VPlan &Plan,
}
}
}
+
+// Use vector.check block to determine if we can eliminate a bounds check on
+// the IV if we know that we can only enter the vector block if the tripcount
+// is within certain bounds.
+static bool canElimAndMaskOnPHI(Instruction *I, VPIRBasicBlock *SCEVCheckBB,
+ Value *SCEVCheckConditional) {
+
+ if (I->getOpcode() != Instruction::And)
+ return false;
+
+ Value *Op0 = I->getOperand(0);
+ Value *Op1 = I->getOperand(1);
+
+ PHINode *IndVar;
+ ConstantInt *Mask;
+
+ if (Mask = dyn_cast<ConstantInt>(Op0))
+ IndVar = dyn_cast<PHINode>(Op1);
+ else if (Mask = dyn_cast<ConstantInt>(Op1))
+ IndVar = dyn_cast<PHINode>(Op0);
+
+ if (!Mask || !IndVar)
+ return false;
+
+ if (auto *CmpI = dyn_cast<CmpInst>(SCEVCheckConditional)) {
+ // Check if the condition for the terminating instruction
+ // is doing some comparison with a constant integer. If not
+ // we can't elim our AND mask
+ Value *CmpOp0 = CmpI->getOperand(0);
+ Value *CmpOp1 = CmpI->getOperand(1);
+ auto *CmpConstant = (dyn_cast<ConstantInt>(CmpOp0))
+ ? dyn_cast<ConstantInt>(CmpOp0)
+ : dyn_cast<ConstantInt>(CmpOp1);
+ if (!CmpConstant)
+ return false;
+
+ unsigned CmpIOpcode = CmpI->getPredicate();
+ if (((CmpConstant == CmpOp1 && CmpIOpcode == CmpInst::ICMP_UGT) ||
+ (CmpConstant == CmpOp0 && CmpIOpcode == CmpInst::ICMP_ULT)) &&
+ (CmpConstant->uge(Mask->getZExtValue())))
+ return true;
+ }
+ return false;
+}
+
+// Check that there's a path from the src BB to the dest BB
+static bool CheckPathFromSrcBBToDestBB(VPBlockBase *Src, VPBlockBase *Dest) {
+ if (!Src || !Dest)
+ return false;
+
+ for (auto *VPBB : Src->getSuccessors()) {
+ if (VPBB == Dest) {
+ return true;
+ } else if (VPBB->getNumSuccessors() > 0 &&
+ CheckPathFromSrcBBToDestBB(VPBB, Dest))
+ return true;
+ }
+ return false;
+};
+
+// Attempt to spot and eliminate no-op AND operations in loop bodies.
+// For example loop Vectorization may create loops like the following.
+//
+// vector.scevcheck:
+// %1 = add i64 %flatten.tripcount, -1
+// %2 = icmp ugt i64 %1, 4294967295
+// br i1 %2, label %scalar.ph, label %vector.ph
+// vector.ph:
+// %iv = phi i64 [ 0, %vector.scevcheck], [ %iv.next, %vector.ph ]
+// %m = and i64 %iv, 4294967295 ; 0xffff_fffe no op
+// %p = getelementptr inbounds <4 x i32>, ptr %A, i64 %m
+// %load = load <4 x i32>, ptr %p, align 4
+// %1 = add <4 x i32> %load, %X
+// store <4 x i32> %1, ptr %p, align 4
+// %iv.next = add nuw i64 %iv, 4
+// %c = icmp ult i64 %iv.next, %N
+// br i1 %c, label %vector.ph, label %exit
+// exit:
+// ret void
+//
+// The vectorizer creates the SCEV check block to perform
+// runtime IV checks. This block can be used to determine true
+// range of the the IV as entry into the vector loop is only possible
+// for certain tripcount values.
+//
+void VPlanTransforms::removeRedundantAndMasks(VPlan &Plan) {
+ if (!Plan.getVectorLoopRegion())
+ return;
+
+ auto FindSCEVCheckBlock = [&]() -> VPIRBasicBlock * {
+ for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
+ vp_depth_first_deep(Plan.getEntry()))) {
+ if (auto *IRBB = dyn_cast<VPIRBasicBlock>(VPBB))
+ if (IRBB->getIRBasicBlock()->getName() == "vector.scevcheck")
----------------
john-brawn-arm wrote:
You shouldn't be checking for the block by name, as it isn't guaranteed to work, e.g. if you have two loops in a function that are vectorized the scev check block of the second will have a number appended to its name, so this transform will fail to apply.
It's GeneratedRTChecks that's generating the check condition, and it has it in SCEVCheckCond, so I think probably you need to get that value here somehow.
https://github.com/llvm/llvm-project/pull/163534
More information about the llvm-commits
mailing list