Graham Hunter deaef1c1b7
[LV] Adjust exit recipe detection to run on early vplan (#183318)
Splitting out some work from #178454; this covers the enums for
early exit loop type (none, readonly, readwrite) and the style
used (readonly with multiple exit blocks, or masking with the
last iteration done in scalar code), along with changing the early
exit recipe detection to suit moving the transform for handling
early exit readwrite loops earlier in the vplan pipeline.
2026-04-02 17:25:35 +01:00

145 lines
5.0 KiB
C++

//===- llvm/unittest/Transforms/Vectorize/VPlanTestBase.h -----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines a VPlanTestBase class, which provides helpers to parse
/// a LLVM IR string and create VPlans given a loop entry block.
//===----------------------------------------------------------------------===//
#ifndef LLVM_UNITTESTS_TRANSFORMS_VECTORIZE_VPLANTESTBASE_H
#define LLVM_UNITTESTS_TRANSFORMS_VECTORIZE_VPLANTESTBASE_H
#include "../lib/Transforms/Vectorize/VPlan.h"
#include "../lib/Transforms/Vectorize/VPlanHelpers.h"
#include "../lib/Transforms/Vectorize/VPlanTransforms.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
#include "llvm/Analysis/IVDescriptors.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
namespace llvm {
/// Helper class to create a module from an assembly string and VPlans for a
/// given loop entry block.
class VPlanTestIRBase : public testing::Test {
protected:
DataLayout DL;
std::unique_ptr<LLVMContext> Ctx;
std::unique_ptr<Module> M;
std::unique_ptr<LoopInfo> LI;
std::unique_ptr<DominatorTree> DT;
std::unique_ptr<AssumptionCache> AC;
std::unique_ptr<ScalarEvolution> SE;
std::unique_ptr<TargetLibraryInfoImpl> TLII;
std::unique_ptr<TargetLibraryInfo> TLI;
MapVector<PHINode *, InductionDescriptor> Inductions;
VPlanTestIRBase()
: DL("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"),
Ctx(new LLVMContext) {}
Module &parseModule(const char *ModuleString) {
SMDiagnostic Err;
M = parseAssemblyString(ModuleString, Err, *Ctx);
EXPECT_TRUE(M);
TLII = std::make_unique<TargetLibraryInfoImpl>(M->getTargetTriple());
TLI = std::make_unique<TargetLibraryInfo>(*TLII);
return *M;
}
void doAnalysis(Function &F) {
DT.reset(new DominatorTree(F));
LI.reset(new LoopInfo(*DT));
AC.reset(new AssumptionCache(F));
SE.reset(new ScalarEvolution(F, *TLI, *AC, *DT, *LI));
}
/// Build the VPlan for the loop starting from \p LoopHeader.
VPlanPtr buildVPlan(
BasicBlock *LoopHeader,
UncountableExitStyle Style = UncountableExitStyle::NoUncountableExit) {
Function &F = *LoopHeader->getParent();
assert(!verifyFunction(F) && "input function must be valid");
doAnalysis(F);
Loop *L = LI->getLoopFor(LoopHeader);
PredicatedScalarEvolution PSE(*SE, *L);
auto Plan = VPlanTransforms::buildVPlan0(L, *LI, IntegerType::get(*Ctx, 64),
{}, PSE);
if (Style != UncountableExitStyle::NoUncountableExit) {
Inductions.clear();
// handleEarlyExits requires induction phi recipes.
for (PHINode &Phi : LoopHeader->phis()) {
InductionDescriptor ID;
if (InductionDescriptor::isInductionPHI(&Phi, L, PSE, ID))
Inductions[&Phi] = ID;
}
VPlanTransforms::createHeaderPhiRecipes(
*Plan, PSE, *L, Inductions,
MapVector<PHINode *, RecurrenceDescriptor>(),
SmallPtrSet<const PHINode *, 1>(), SmallPtrSet<PHINode *, 1>(),
/*AllowReordering=*/false);
}
VPlanTransforms::handleEarlyExits(*Plan, Style, L, PSE, *DT, AC.get());
VPlanTransforms::addMiddleCheck(*Plan, false);
VPlanTransforms::createLoopRegions(*Plan);
return Plan;
}
VPlanPtr buildVPlan0(BasicBlock *LoopHeader) {
Function &F = *LoopHeader->getParent();
assert(!verifyFunction(F) && "input function must be valid");
doAnalysis(F);
Loop *L = LI->getLoopFor(LoopHeader);
PredicatedScalarEvolution PSE(*SE, *L);
return VPlanTransforms::buildVPlan0(L, *LI, IntegerType::get(*Ctx, 64), {},
PSE);
}
};
class VPlanTestBase : public testing::Test {
protected:
LLVMContext C;
std::unique_ptr<Module> M;
Function *F;
BasicBlock *ScalarHeader;
SmallVector<std::unique_ptr<VPlan>> Plans;
VPlanTestBase() {
M = std::make_unique<Module>("VPlanTestModule", C);
FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), false);
F = Function::Create(FTy, GlobalValue::ExternalLinkage, "f", M.get());
ScalarHeader = BasicBlock::Create(C, "scalar.header", F);
UncondBrInst::Create(ScalarHeader, ScalarHeader);
}
VPlan &getPlan() {
Plans.push_back(std::make_unique<VPlan>(ScalarHeader));
VPlan &Plan = *Plans.back();
VPValue *DefaultTC = Plan.getConstantInt(32, 1024);
Plan.setTripCount(DefaultTC);
return Plan;
}
};
} // namespace llvm
#endif // LLVM_UNITTESTS_TRANSFORMS_VECTORIZE_VPLANTESTBASE_H