24#include "llvm/IR/IntrinsicsX86.h"
32#define DEBUG_TYPE "x86-partial-reduction"
36class X86PartialReduction {
63 StringRef getPassName()
const override {
return "X86 Partial Reduction"; }
68 return new X86PartialReductionLegacy();
71char X86PartialReductionLegacy::ID = 0;
79 if (!ST->hasVNNI() && !ST->hasAVXVNNI())
90 if (Cast->getParent() ==
Mul->getParent() &&
91 (Cast->getOpcode() == Instruction::SExt ||
92 Cast->getOpcode() == Instruction::ZExt) &&
93 Cast->getOperand(0)->getType()->getScalarSizeInBits() <= 8)
112 bool ReduceInOneBB) {
135 if (ReduceInOneBB && matchVPDPBUSDPattern(
ST,
Mul,
DL))
142 if (
ST->hasSSE41()) {
154 auto CanShrinkOp = [&](
Value *
Op) {
158 (Cast->getOpcode() == Instruction::SExt ||
159 Cast->getOpcode() == Instruction::ZExt) &&
160 Cast->getOperand(0)->getType()->getScalarSizeInBits() <= 16)
186 if (!CanShrinkOp(
LHS) && !CanShrinkOp(
RHS))
192 unsigned NumElts = MulTy->getNumElements();
197 SmallVector<int, 16> EvenMask(NumElts / 2);
198 SmallVector<int, 16> OddMask(NumElts / 2);
199 for (
int i = 0, e = NumElts / 2; i !=
e; ++i) {
201 OddMask[i] = i * 2 + 1;
206 Value *EvenElts = Builder.CreateShuffleVector(NewMul, NewMul, EvenMask);
207 Value *OddElts = Builder.CreateShuffleVector(NewMul, NewMul, OddMask);
208 Value *MAdd = Builder.CreateAdd(EvenElts, OddElts);
212 std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
214 Value *
Concat = Builder.CreateShuffleVector(MAdd, Zero, ConcatMask);
222bool X86PartialReduction::trySADReplacement(Instruction *
Op) {
233 LHS =
Op->getOperand(0);
249 if (!
Sub ||
Sub->getOpcode() != Instruction::Sub)
258 return ZExt->getOperand(0);
264 Value *Op0 = getZeroExtendedVal(
Sub->getOperand(0));
265 Value *Op1 = getZeroExtendedVal(
Sub->getOperand(1));
272 unsigned NumElts = OpTy->getNumElements();
274 unsigned IntrinsicNumElts;
276 if (
ST->useBWIRegs() && NumElts >= 64) {
277 IID = Intrinsic::x86_avx512_psad_bw_512;
278 IntrinsicNumElts = 64;
279 }
else if (
ST->hasAVX2() && NumElts >= 32) {
280 IID = Intrinsic::x86_avx2_psad_bw;
281 IntrinsicNumElts = 32;
283 IID = Intrinsic::x86_sse2_psad_bw;
284 IntrinsicNumElts = 16;
292 for (
unsigned i = 0; i != NumElts; ++i)
294 for (
unsigned i = NumElts; i != 16; ++i)
295 ConcatMask[i] = (i % NumElts) + NumElts;
298 Op0 = Builder.CreateShuffleVector(Op0, Zero, ConcatMask);
299 Op1 = Builder.CreateShuffleVector(Op1, Zero, ConcatMask);
307 assert(NumElts % IntrinsicNumElts == 0 &&
"Unexpected number of elements!");
308 unsigned NumSplits = NumElts / IntrinsicNumElts;
311 SmallVector<Value *, 4>
Ops(NumSplits);
312 for (
unsigned i = 0; i != NumSplits; ++i) {
314 std::iota(ExtractMask.begin(), ExtractMask.end(), i * IntrinsicNumElts);
315 Value *ExtractOp0 = Builder.CreateShuffleVector(Op0, Op0, ExtractMask);
316 Value *ExtractOp1 = Builder.CreateShuffleVector(Op1, Op0, ExtractMask);
317 Ops[i] = Builder.CreateCall(PSADBWFn, {ExtractOp0, ExtractOp1});
318 Ops[i] = Builder.CreateBitCast(
Ops[i], I32Ty);
322 unsigned Stages =
Log2_32(NumSplits);
323 for (
unsigned s = Stages; s > 0; --s) {
324 unsigned NumConcatElts =
326 for (
unsigned i = 0; i != 1U << (s - 1); ++i) {
328 std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
329 Ops[i] = Builder.CreateShuffleVector(
Ops[i*2],
Ops[i*2+1], ConcatMask);
338 Ops[0] = Builder.CreateShuffleVector(
Ops[0],
Ops[0], ArrayRef<int>{0, 1});
339 }
else if (NumElts >= 8) {
343 for (
unsigned i = 0; i != SubElts; ++i)
345 for (
unsigned i = SubElts; i != NumElts; ++i)
346 ConcatMask[i] = (i % SubElts) + SubElts;
349 Ops[0] = Builder.CreateShuffleVector(
Ops[0], Zero, ConcatMask);
352 Op->replaceAllUsesWith(
Ops[0]);
353 Op->eraseFromParent();
358bool X86PartialReduction::tryByteSumReplacement(Instruction *
Op) {
365 unsigned ElemBits = OpTy->getElementType()->getScalarSizeInBits();
366 if (ElemBits != 32 && ElemBits != 64)
374 if (!SrcTy || !SrcTy->getElementType()->isIntegerTy(8))
377 unsigned NumElts = OpTy->getNumElements();
384 unsigned IntrinsicNumElts;
386 if (
ST->useBWIRegs() && NumElts >= 64) {
387 IID = Intrinsic::x86_avx512_psad_bw_512;
388 IntrinsicNumElts = 64;
389 }
else if (
ST->hasAVX2() && NumElts >= 32) {
390 IID = Intrinsic::x86_avx2_psad_bw;
391 IntrinsicNumElts = 32;
393 IID = Intrinsic::x86_sse2_psad_bw;
394 IntrinsicNumElts = 16;
397 if (NumElts % IntrinsicNumElts != 0 ||
400 unsigned NumSplits = NumElts / IntrinsicNumElts;
403 Builder.SetCurrentDebugLocation(
Op->getDebugLoc());
413 FixedVectorType *I32PerSplitTy =
419 Value *Src = ZExt->getOperand(0);
420 SmallVector<Value *, 4>
Ops(NumSplits);
421 for (
unsigned i = 0; i != NumSplits; ++i) {
423 std::iota(ExtractMask.begin(), ExtractMask.end(), i * IntrinsicNumElts);
424 Value *ExtractSrc = Builder.CreateShuffleVector(Src, Src, ExtractMask);
425 Ops[i] = Builder.CreateCall(PSADBWFn, {ExtractSrc, Zeroes});
427 Ops[i] = Builder.CreateBitCast(
Ops[i], I32PerSplitTy);
431 unsigned Stages =
Log2_32(NumSplits);
432 for (
unsigned S = Stages; S > 0; --S) {
433 unsigned NumConcatElts =
435 for (
unsigned i = 0; i != 1U << (S - 1); ++i) {
437 std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
439 Builder.CreateShuffleVector(
Ops[i * 2],
Ops[i * 2 + 1], ConcatMask);
446 for (
unsigned i = 0; i != SubElts; ++i)
448 for (
unsigned i = SubElts; i != NumElts; ++i)
449 ConcatMask[i] = (i % SubElts) + SubElts;
451 Ops[0] = Builder.CreateShuffleVector(
Ops[0], Zero, ConcatMask);
453 Op->replaceAllUsesWith(
Ops[0]);
454 Op->eraseFromParent();
461 bool &ReduceInOneBB) {
462 ReduceInOneBB =
true;
465 if (!Index || !Index->isNullValue())
469 if (!BO || BO->getOpcode() != Instruction::Add || !BO->hasOneUse())
472 ReduceInOneBB =
false;
480 unsigned Stages =
Log2_32(NumElems);
481 for (
unsigned i = 0; i != Stages; ++i) {
483 if (!BO || BO->getOpcode() != Instruction::Add)
486 ReduceInOneBB =
false;
490 if (i != 0 && !BO->hasNUses(2))
506 if (!Shuffle || Shuffle->getOperand(0) !=
Op)
510 unsigned MaskEnd = 1 << i;
511 for (
unsigned Index = 0; Index < MaskEnd; ++Index)
512 if (Shuffle->getMaskValue(Index) != (
int)(MaskEnd + Index))
516 return const_cast<Value *
>(
Op);
524 if (!Phi->hasOneUse())
531 while (U->hasOneUse() && U->getOpcode() == BO->
getOpcode())
546 while (!Worklist.
empty()) {
548 if (!Visited.
insert(V).second)
554 if (!PN->hasNUses(PN == Root ? 2 : 1))
564 if (BO->getOpcode() == Instruction::Add) {
566 if (BO->hasNUses(BO == Root ? 2 : 1)) {
573 if (BO->hasNUses(BO == Root ? 3 : 2)) {
575 for (
auto *U : BO->users())
597 if (!V->hasNUses(
I == Root ? 2 : 1))
606bool X86PartialReduction::run(
Function &
F) {
608 DL = &
F.getDataLayout();
610 bool MadeChange =
false;
624 SmallVector<Instruction *, 8> Leaves;
627 for (Instruction *
I : Leaves) {
628 if (tryMAddReplacement(
I, ReduceInOneBB)) {
635 if (
I != Root && trySADReplacement(
I)) {
645 if (
I != Root && tryByteSumReplacement(
I)) {
656bool X86PartialReductionLegacy::runOnFunction(
Function &
F) {
660 auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
664 return X86PartialReduction(&TPC->getTM<X86TargetMachine>()).run(
F);
669 bool Changed = X86PartialReduction(TM).run(
F);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static bool runOnFunction(Function &F, bool PostInlining)
This header defines various interfaces for pass management in LLVM.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
FunctionAnalysisManager FAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static SymbolRef::Type getType(const Symbol *Sym)
Target-Independent Code Generator Pass Configuration Options pass.
static constexpr int Concat[]
static bool isReachableFromPHI(PHINode *Phi, BinaryOperator *BO)
if(isa< SExtInst >(LHS)) std auto IsFreeTruncation
static Value * matchAddReduction(const ExtractElementInst &EE, bool &ReduceInOneBB)
static void collectLeaves(Value *Root, SmallVectorImpl< Instruction * > &Leaves)
Represent the analysis usage information of a pass.
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
BinaryOps getOpcode() const
Represents analyses that only rely on functions' control flow.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
A parsed version of the target data layout string in and methods for querying it.
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
FunctionPass class - This class is used to implement most global optimizations.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
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.
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI bool hasNUses(unsigned N) const
Return true if this Value has exactly N uses.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
const X86Subtarget * getSubtargetImpl(const Function &F) const override
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
const ParentTy * getParent() const
Pass manager infrastructure for declaring and invalidating analyses.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
bool match(Val *V, const Pattern &P)
auto m_Intrinsic(const Ts &...Ops)
Match intrinsic calls like this: m_Intrinsic<Intrinsic::fabs>(m_Value(X))
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
FunctionPass * createX86PartialReductionLegacyPass()
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
@ SPF_ABS
Floating point maxnum.
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=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...
LLVM_ABI SelectPatternResult matchSelectPattern(Value *V, Value *&LHS, Value *&RHS, Instruction::CastOps *CastOp=nullptr, unsigned Depth=0)
Pattern match integer [SU]MIN, [SU]MAX and ABS idioms, returning the kind and providing the out param...
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...
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
@ Sub
Subtraction of integers.
DWARFExpression::Operation Op
LLVM_ABI unsigned ComputeNumSignBits(const Value *Op, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Return the number of times the sign bit of the register is replicated into the other bits.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI unsigned ComputeMaxSignificantBits(const Value *Op, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CxtI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Get the upper bound on bit size for this Value Op as a signed 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.