33#define DEBUG_TYPE "riscv-codegenprepare"
34#define PASS_NAME "RISC-V CodeGenPrepare"
37class RISCVCodeGenPrepareImpl
38 :
public InstVisitor<RISCVCodeGenPrepareImpl, bool> {
47 :
F(
F),
DL(&
F.getDataLayout()), DT(DT), ST(ST) {}
65 RISCVCodeGenPrepareLegacy() : FunctionPass(ID) {}
68 StringRef getPassName()
const override {
return PASS_NAME; }
70 void getAnalysisUsage(AnalysisUsage &AU)
const override {
88 using namespace PatternMatch;
128bool RISCVCodeGenPrepareImpl::visitMul(BinaryOperator &BO) {
129 using namespace PatternMatch;
159 if (
Size != SrcSize * 2)
174 if (
Known.countMaxActiveBits() > SrcSize)
178 Type *ScalarTy = VecTy->getElementType();
181 VecTy->getElementCount(), Builder.CreateTrunc(SplatVal, ScalarTy));
183 Builder.SetInsertPoint(&BO);
223bool RISCVCodeGenPrepareImpl::widenVPMerge(Instruction *Root) {
229 using namespace PatternMatch;
235 if (!
Phi->hasOneUse() ||
Phi->getNumIncomingValues() != 2 ||
237 Phi->getIncomingValue(1) != Root)
241 VectorType::get(IntegerType::getInt8Ty(Root->
getContext()),
245 PHINode *WidePhi = Builder.CreatePHI(WideTy, 2);
247 Phi->getIncomingBlock(0));
248 Builder.SetInsertPoint(Root);
249 Value *WideTrue = Builder.CreateZExt(
True, WideTy);
250 Value *WideMerge = Builder.CreateIntrinsic(Intrinsic::vp_merge, {WideTy},
251 {
Mask, WideTrue, WidePhi, EVL});
253 WideMerge = Builder.CreateFreeze(WideMerge);
255 Value *Trunc = Builder.CreateTrunc(WideMerge, Root->
getType());
260 Phi->setIncomingValue(1,
Phi->getIncomingValue(0));
266bool RISCVCodeGenPrepareImpl::visitFreezeInst(FreezeInst &
I) {
268 if (
II->getIntrinsicID() == Intrinsic::vp_merge)
269 return widenVPMerge(&
I);
304bool RISCVCodeGenPrepareImpl::visitIntrinsicInst(IntrinsicInst &
I) {
305 if (expandVPStrideLoad(
I))
308 if (expandMulReduction(
I))
311 if (widenVPMerge(&
I))
314 if (
I.getIntrinsicID() != Intrinsic::vector_reduce_fadd &&
319 if (!
PHI || !
PHI->hasOneUse() ||
323 Type *VecTy =
I.getOperand(1)->getType();
325 auto *VecPHI = Builder.CreatePHI(VecTy,
PHI->getNumIncomingValues());
327 for (
auto *BB :
PHI->blocks()) {
328 Builder.SetInsertPoint(BB->getTerminator());
329 Value *InsertElt = Builder.CreateInsertElement(
330 VecTy,
PHI->getIncomingValueForBlock(BB), (
uint64_t)0);
331 VecPHI->addIncoming(InsertElt, BB);
334 Builder.SetInsertPoint(&
I);
335 I.setOperand(0, Builder.CreateExtractElement(VecPHI, (
uint64_t)0));
337 PHI->eraseFromParent();
349 unsigned NumPieces = VecTy->getElementCount().getKnownMinValue() / PieceElts;
353 for (
unsigned i = 0; i < NumPieces; i++)
354 Pieces[i] = Builder.CreateExtractVector(PieceTy, Vec, i * PieceElts);
356 while (Pieces.
size() > 1) {
357 for (
unsigned i = 0; i < Pieces.
size() / 2; i++)
359 Builder.CreateMul(Pieces[i * 2], Pieces[i * 2 + 1],
"bin.rdx");
367bool RISCVCodeGenPrepareImpl::expandMulReduction(IntrinsicInst &
II) {
368 if (
II.getIntrinsicID() != Intrinsic::vector_reduce_mul)
374 Value *TmpVec =
II.getArgOperand(0);
379 unsigned MinElts = ScalTy->getMinNumElements();
391 Intrinsic::vector_reduce_mul, {FixedTy}, {Fixed}));
392 II.replaceAllUsesWith(FixedRdx);
393 II.eraseFromParent();
394 expandMulReduction(*FixedRdx);
399 if (MinElts <= M1MinElts || !
isPowerOf2_32(MinElts / M1MinElts))
405 Value *Rdx = Builder.CreateIntrinsic(Intrinsic::vector_reduce_mul,
406 {Reduced->
getType()}, {Reduced});
407 II.replaceAllUsesWith(Rdx);
408 II.eraseFromParent();
414 unsigned M1VF = MinVLen / EltSize;
421 auto *M1Ty = VectorType::get(VecTy->getElementType(), M1EC);
434 for (
unsigned LiveElts = VF; LiveElts > M1VF; LiveElts /= 2) {
435 unsigned Half = LiveElts / 2;
436 std::iota(ShuffleMask.begin(), ShuffleMask.begin() + Half, Half);
437 std::fill(ShuffleMask.begin() + Half, ShuffleMask.end(), -1);
439 Builder.CreateShuffleVector(TmpVec, ShuffleMask,
"rdx.shuf");
440 TmpVec = Builder.CreateMul(TmpVec, Shuf,
"bin.rdx");
444 TmpVec = Builder.CreateExtractVector(M1Ty, TmpVec, (
uint64_t)0,
"rdx.sub");
448 Builder.CreateIntrinsic(Intrinsic::vector_reduce_mul, {M1Ty}, {TmpVec});
449 II.replaceAllUsesWith(Rdx);
450 II.eraseFromParent();
457bool RISCVCodeGenPrepareImpl::expandVPStrideLoad(IntrinsicInst &
II) {
460 using namespace PatternMatch;
467 if (
II.getType()->getScalarSizeInBits() > ST->
getXLen())
476 Type *STy = VTy->getElementType();
477 Value *Val = Builder.CreateLoad(STy, BasePtr);
478 Value *Res = Builder.CreateIntrinsic(
479 Intrinsic::vp_merge, VTy,
480 {
II.getOperand(2), Builder.CreateVectorSplat(VTy->getElementCount(), Val),
483 II.replaceAllUsesWith(Res);
484 II.eraseFromParent();
488bool RISCVCodeGenPrepareImpl::run() {
489 bool MadeChange =
false;
497bool RISCVCodeGenPrepareLegacy::runOnFunction(
Function &
F) {
501 auto &TPC = getAnalysis<TargetPassConfig>();
502 auto &TM = TPC.getTM<RISCVTargetMachine>();
503 auto ST = &TM.getSubtarget<RISCVSubtarget>(
F);
504 auto DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
506 RISCVCodeGenPrepareImpl RVCGP(
F, DT, ST);
516char RISCVCodeGenPrepareLegacy::ID = 0;
519 return new RISCVCodeGenPrepareLegacy();
526 bool Changed = RISCVCodeGenPrepareImpl(
F, DT, ST).run();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static const Function * getParent(const Value *V)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static bool runOnFunction(Function &F, bool PostInlining)
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static Value * buildMulTree(IRBuilder<> &Builder, ElementCount PieceEC, Value *Vec)
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
Target-Independent Code Generator Pass Configuration Options pass.
AnalysisUsage & addRequired()
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Represents analyses that only rely on functions' control flow.
static LLVM_ABI ConstantAggregateZero * get(Type *Ty)
A parsed version of the target data layout string in and methods for querying it.
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
static constexpr ElementCount getScalable(ScalarTy MinVal)
static constexpr ElementCount getFixed(ScalarTy MinVal)
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
This class represents a freeze function that returns random concrete value if an operand is either a ...
FunctionPass class - This class is used to implement most global optimizations.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Base class for instruction visitors.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
A wrapper class for inspecting calls to intrinsic functions.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
bool hasVInstructionsI64() const
unsigned getRealMinVLen() const
bool hasVInstructions() const
std::optional< unsigned > getRealVLen() const
unsigned getRealMaxVLen() const
void truncate(size_type N)
Like resize, but requires that N is less than size().
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Target-Independent Code Generator Pass Configuration Options.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
void setOperand(unsigned i, Value *Val)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
const ParentTy * getParent() const
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
AllOnesConstantMatch m_AllOnes()
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
match_combine_or< Ty... > m_CombineOr(const Ty &...Ps)
Combine pattern matchers matching any of Ps patterns.
match_bind< PHINode > m_Phi(PHINode *&PN)
Match a PHI node, capturing it if we match.
OneOps_match< OpTy, Instruction::Freeze > m_Freeze(const OpTy &Op)
Matches FreezeInst.
bool match(Val *V, const Pattern &P)
match_bind< Instruction > m_Instruction(Instruction *&I)
Match an instruction, capturing it if we match.
auto m_Value()
Match an arbitrary value and ignore it.
NNegZExt_match< OpTy > m_NNegZExt(const OpTy &Op)
CastInst_match< OpTy, ZExtInst > m_ZExt(const OpTy &Op)
Matches ZExt.
Splat_match< T > m_Splat(const T &SubPattern)
Match a vector splat.
is_zero< true > m_Zero()
Match any null constant or a vector with all elements equal to 0.
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
static constexpr unsigned RVVBitsPerBlock
NodeAddr< PhiNode * > Phi
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI bool RecursivelyDeleteTriviallyDeadInstructions(Value *V, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, std::function< void(Value *)> AboutToDeleteCallback=std::function< void(Value *)>())
If the specified value is a trivially dead instruction, delete it.
constexpr bool isInt(int64_t x)
Checks if an integer fits into the given bit width.
@ Known
Known to have no common set bits.
FunctionPass * createRISCVCodeGenPrepareLegacyPass()
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Determine which bits of V are known to be either zero or one and return them in the KnownZero/KnownOn...
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth=0)
Return true if the given value is known to be non-zero when defined.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.