X86PartialReduction.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. //===-- X86PartialReduction.cpp -------------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This pass looks for add instructions used by a horizontal reduction to see
  10. // if we might be able to use pmaddwd or psadbw. Some cases of this require
  11. // cross basic block knowledge and can't be done in SelectionDAG.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "X86.h"
  15. #include "X86TargetMachine.h"
  16. #include "llvm/Analysis/ValueTracking.h"
  17. #include "llvm/CodeGen/TargetPassConfig.h"
  18. #include "llvm/IR/Constants.h"
  19. #include "llvm/IR/IRBuilder.h"
  20. #include "llvm/IR/Instructions.h"
  21. #include "llvm/IR/IntrinsicInst.h"
  22. #include "llvm/IR/IntrinsicsX86.h"
  23. #include "llvm/IR/Operator.h"
  24. #include "llvm/IR/PatternMatch.h"
  25. #include "llvm/Pass.h"
  26. #include "llvm/Support/KnownBits.h"
  27. using namespace llvm;
  28. #define DEBUG_TYPE "x86-partial-reduction"
  29. namespace {
  30. class X86PartialReduction : public FunctionPass {
  31. const DataLayout *DL;
  32. const X86Subtarget *ST;
  33. public:
  34. static char ID; // Pass identification, replacement for typeid.
  35. X86PartialReduction() : FunctionPass(ID) { }
  36. bool runOnFunction(Function &Fn) override;
  37. void getAnalysisUsage(AnalysisUsage &AU) const override {
  38. AU.setPreservesCFG();
  39. }
  40. StringRef getPassName() const override {
  41. return "X86 Partial Reduction";
  42. }
  43. private:
  44. bool tryMAddReplacement(Instruction *Op, bool ReduceInOneBB);
  45. bool trySADReplacement(Instruction *Op);
  46. };
  47. }
  48. FunctionPass *llvm::createX86PartialReductionPass() {
  49. return new X86PartialReduction();
  50. }
  51. char X86PartialReduction::ID = 0;
  52. INITIALIZE_PASS(X86PartialReduction, DEBUG_TYPE,
  53. "X86 Partial Reduction", false, false)
  54. // This function should be aligned with detectExtMul() in X86ISelLowering.cpp.
  55. static bool matchVPDPBUSDPattern(const X86Subtarget *ST, BinaryOperator *Mul,
  56. const DataLayout *DL) {
  57. if (!ST->hasVNNI() && !ST->hasAVXVNNI())
  58. return false;
  59. Value *LHS = Mul->getOperand(0);
  60. Value *RHS = Mul->getOperand(1);
  61. if (isa<SExtInst>(LHS))
  62. std::swap(LHS, RHS);
  63. auto IsFreeTruncation = [&](Value *Op) {
  64. if (auto *Cast = dyn_cast<CastInst>(Op)) {
  65. if (Cast->getParent() == Mul->getParent() &&
  66. (Cast->getOpcode() == Instruction::SExt ||
  67. Cast->getOpcode() == Instruction::ZExt) &&
  68. Cast->getOperand(0)->getType()->getScalarSizeInBits() <= 8)
  69. return true;
  70. }
  71. return isa<Constant>(Op);
  72. };
  73. // (dpbusd (zext a), (sext, b)). Since the first operand should be unsigned
  74. // value, we need to check LHS is zero extended value. RHS should be signed
  75. // value, so we just check the signed bits.
  76. if ((IsFreeTruncation(LHS) &&
  77. computeKnownBits(LHS, *DL).countMaxActiveBits() <= 8) &&
  78. (IsFreeTruncation(RHS) && ComputeMaxSignificantBits(RHS, *DL) <= 8))
  79. return true;
  80. return false;
  81. }
  82. bool X86PartialReduction::tryMAddReplacement(Instruction *Op,
  83. bool ReduceInOneBB) {
  84. if (!ST->hasSSE2())
  85. return false;
  86. // Need at least 8 elements.
  87. if (cast<FixedVectorType>(Op->getType())->getNumElements() < 8)
  88. return false;
  89. // Element type should be i32.
  90. if (!cast<VectorType>(Op->getType())->getElementType()->isIntegerTy(32))
  91. return false;
  92. auto *Mul = dyn_cast<BinaryOperator>(Op);
  93. if (!Mul || Mul->getOpcode() != Instruction::Mul)
  94. return false;
  95. Value *LHS = Mul->getOperand(0);
  96. Value *RHS = Mul->getOperand(1);
  97. // If the target support VNNI, leave it to ISel to combine reduce operation
  98. // to VNNI instruction.
  99. // TODO: we can support transforming reduce to VNNI intrinsic for across block
  100. // in this pass.
  101. if (ReduceInOneBB && matchVPDPBUSDPattern(ST, Mul, DL))
  102. return false;
  103. // LHS and RHS should be only used once or if they are the same then only
  104. // used twice. Only check this when SSE4.1 is enabled and we have zext/sext
  105. // instructions, otherwise we use punpck to emulate zero extend in stages. The
  106. // trunc/ we need to do likely won't introduce new instructions in that case.
  107. if (ST->hasSSE41()) {
  108. if (LHS == RHS) {
  109. if (!isa<Constant>(LHS) && !LHS->hasNUses(2))
  110. return false;
  111. } else {
  112. if (!isa<Constant>(LHS) && !LHS->hasOneUse())
  113. return false;
  114. if (!isa<Constant>(RHS) && !RHS->hasOneUse())
  115. return false;
  116. }
  117. }
  118. auto CanShrinkOp = [&](Value *Op) {
  119. auto IsFreeTruncation = [&](Value *Op) {
  120. if (auto *Cast = dyn_cast<CastInst>(Op)) {
  121. if (Cast->getParent() == Mul->getParent() &&
  122. (Cast->getOpcode() == Instruction::SExt ||
  123. Cast->getOpcode() == Instruction::ZExt) &&
  124. Cast->getOperand(0)->getType()->getScalarSizeInBits() <= 16)
  125. return true;
  126. }
  127. return isa<Constant>(Op);
  128. };
  129. // If the operation can be freely truncated and has enough sign bits we
  130. // can shrink.
  131. if (IsFreeTruncation(Op) &&
  132. ComputeNumSignBits(Op, *DL, 0, nullptr, Mul) > 16)
  133. return true;
  134. // SelectionDAG has limited support for truncating through an add or sub if
  135. // the inputs are freely truncatable.
  136. if (auto *BO = dyn_cast<BinaryOperator>(Op)) {
  137. if (BO->getParent() == Mul->getParent() &&
  138. IsFreeTruncation(BO->getOperand(0)) &&
  139. IsFreeTruncation(BO->getOperand(1)) &&
  140. ComputeNumSignBits(Op, *DL, 0, nullptr, Mul) > 16)
  141. return true;
  142. }
  143. return false;
  144. };
  145. // Both Ops need to be shrinkable.
  146. if (!CanShrinkOp(LHS) && !CanShrinkOp(RHS))
  147. return false;
  148. IRBuilder<> Builder(Mul);
  149. auto *MulTy = cast<FixedVectorType>(Op->getType());
  150. unsigned NumElts = MulTy->getNumElements();
  151. // Extract even elements and odd elements and add them together. This will
  152. // be pattern matched by SelectionDAG to pmaddwd. This instruction will be
  153. // half the original width.
  154. SmallVector<int, 16> EvenMask(NumElts / 2);
  155. SmallVector<int, 16> OddMask(NumElts / 2);
  156. for (int i = 0, e = NumElts / 2; i != e; ++i) {
  157. EvenMask[i] = i * 2;
  158. OddMask[i] = i * 2 + 1;
  159. }
  160. // Creating a new mul so the replaceAllUsesWith below doesn't replace the
  161. // uses in the shuffles we're creating.
  162. Value *NewMul = Builder.CreateMul(Mul->getOperand(0), Mul->getOperand(1));
  163. Value *EvenElts = Builder.CreateShuffleVector(NewMul, NewMul, EvenMask);
  164. Value *OddElts = Builder.CreateShuffleVector(NewMul, NewMul, OddMask);
  165. Value *MAdd = Builder.CreateAdd(EvenElts, OddElts);
  166. // Concatenate zeroes to extend back to the original type.
  167. SmallVector<int, 32> ConcatMask(NumElts);
  168. std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
  169. Value *Zero = Constant::getNullValue(MAdd->getType());
  170. Value *Concat = Builder.CreateShuffleVector(MAdd, Zero, ConcatMask);
  171. Mul->replaceAllUsesWith(Concat);
  172. Mul->eraseFromParent();
  173. return true;
  174. }
  175. bool X86PartialReduction::trySADReplacement(Instruction *Op) {
  176. if (!ST->hasSSE2())
  177. return false;
  178. // TODO: There's nothing special about i32, any integer type above i16 should
  179. // work just as well.
  180. if (!cast<VectorType>(Op->getType())->getElementType()->isIntegerTy(32))
  181. return false;
  182. Value *LHS;
  183. if (match(Op, PatternMatch::m_Intrinsic<Intrinsic::abs>())) {
  184. LHS = Op->getOperand(0);
  185. } else {
  186. // Operand should be a select.
  187. auto *SI = dyn_cast<SelectInst>(Op);
  188. if (!SI)
  189. return false;
  190. Value *RHS;
  191. // Select needs to implement absolute value.
  192. auto SPR = matchSelectPattern(SI, LHS, RHS);
  193. if (SPR.Flavor != SPF_ABS)
  194. return false;
  195. }
  196. // Need a subtract of two values.
  197. auto *Sub = dyn_cast<BinaryOperator>(LHS);
  198. if (!Sub || Sub->getOpcode() != Instruction::Sub)
  199. return false;
  200. // Look for zero extend from i8.
  201. auto getZeroExtendedVal = [](Value *Op) -> Value * {
  202. if (auto *ZExt = dyn_cast<ZExtInst>(Op))
  203. if (cast<VectorType>(ZExt->getOperand(0)->getType())
  204. ->getElementType()
  205. ->isIntegerTy(8))
  206. return ZExt->getOperand(0);
  207. return nullptr;
  208. };
  209. // Both operands of the subtract should be extends from vXi8.
  210. Value *Op0 = getZeroExtendedVal(Sub->getOperand(0));
  211. Value *Op1 = getZeroExtendedVal(Sub->getOperand(1));
  212. if (!Op0 || !Op1)
  213. return false;
  214. IRBuilder<> Builder(Op);
  215. auto *OpTy = cast<FixedVectorType>(Op->getType());
  216. unsigned NumElts = OpTy->getNumElements();
  217. unsigned IntrinsicNumElts;
  218. Intrinsic::ID IID;
  219. if (ST->hasBWI() && NumElts >= 64) {
  220. IID = Intrinsic::x86_avx512_psad_bw_512;
  221. IntrinsicNumElts = 64;
  222. } else if (ST->hasAVX2() && NumElts >= 32) {
  223. IID = Intrinsic::x86_avx2_psad_bw;
  224. IntrinsicNumElts = 32;
  225. } else {
  226. IID = Intrinsic::x86_sse2_psad_bw;
  227. IntrinsicNumElts = 16;
  228. }
  229. Function *PSADBWFn = Intrinsic::getDeclaration(Op->getModule(), IID);
  230. if (NumElts < 16) {
  231. // Pad input with zeroes.
  232. SmallVector<int, 32> ConcatMask(16);
  233. for (unsigned i = 0; i != NumElts; ++i)
  234. ConcatMask[i] = i;
  235. for (unsigned i = NumElts; i != 16; ++i)
  236. ConcatMask[i] = (i % NumElts) + NumElts;
  237. Value *Zero = Constant::getNullValue(Op0->getType());
  238. Op0 = Builder.CreateShuffleVector(Op0, Zero, ConcatMask);
  239. Op1 = Builder.CreateShuffleVector(Op1, Zero, ConcatMask);
  240. NumElts = 16;
  241. }
  242. // Intrinsics produce vXi64 and need to be casted to vXi32.
  243. auto *I32Ty =
  244. FixedVectorType::get(Builder.getInt32Ty(), IntrinsicNumElts / 4);
  245. assert(NumElts % IntrinsicNumElts == 0 && "Unexpected number of elements!");
  246. unsigned NumSplits = NumElts / IntrinsicNumElts;
  247. // First collect the pieces we need.
  248. SmallVector<Value *, 4> Ops(NumSplits);
  249. for (unsigned i = 0; i != NumSplits; ++i) {
  250. SmallVector<int, 64> ExtractMask(IntrinsicNumElts);
  251. std::iota(ExtractMask.begin(), ExtractMask.end(), i * IntrinsicNumElts);
  252. Value *ExtractOp0 = Builder.CreateShuffleVector(Op0, Op0, ExtractMask);
  253. Value *ExtractOp1 = Builder.CreateShuffleVector(Op1, Op0, ExtractMask);
  254. Ops[i] = Builder.CreateCall(PSADBWFn, {ExtractOp0, ExtractOp1});
  255. Ops[i] = Builder.CreateBitCast(Ops[i], I32Ty);
  256. }
  257. assert(isPowerOf2_32(NumSplits) && "Expected power of 2 splits");
  258. unsigned Stages = Log2_32(NumSplits);
  259. for (unsigned s = Stages; s > 0; --s) {
  260. unsigned NumConcatElts =
  261. cast<FixedVectorType>(Ops[0]->getType())->getNumElements() * 2;
  262. for (unsigned i = 0; i != 1U << (s - 1); ++i) {
  263. SmallVector<int, 64> ConcatMask(NumConcatElts);
  264. std::iota(ConcatMask.begin(), ConcatMask.end(), 0);
  265. Ops[i] = Builder.CreateShuffleVector(Ops[i*2], Ops[i*2+1], ConcatMask);
  266. }
  267. }
  268. // At this point the final value should be in Ops[0]. Now we need to adjust
  269. // it to the final original type.
  270. NumElts = cast<FixedVectorType>(OpTy)->getNumElements();
  271. if (NumElts == 2) {
  272. // Extract down to 2 elements.
  273. Ops[0] = Builder.CreateShuffleVector(Ops[0], Ops[0], ArrayRef<int>{0, 1});
  274. } else if (NumElts >= 8) {
  275. SmallVector<int, 32> ConcatMask(NumElts);
  276. unsigned SubElts =
  277. cast<FixedVectorType>(Ops[0]->getType())->getNumElements();
  278. for (unsigned i = 0; i != SubElts; ++i)
  279. ConcatMask[i] = i;
  280. for (unsigned i = SubElts; i != NumElts; ++i)
  281. ConcatMask[i] = (i % SubElts) + SubElts;
  282. Value *Zero = Constant::getNullValue(Ops[0]->getType());
  283. Ops[0] = Builder.CreateShuffleVector(Ops[0], Zero, ConcatMask);
  284. }
  285. Op->replaceAllUsesWith(Ops[0]);
  286. Op->eraseFromParent();
  287. return true;
  288. }
  289. // Walk backwards from the ExtractElementInst and determine if it is the end of
  290. // a horizontal reduction. Return the input to the reduction if we find one.
  291. static Value *matchAddReduction(const ExtractElementInst &EE,
  292. bool &ReduceInOneBB) {
  293. ReduceInOneBB = true;
  294. // Make sure we're extracting index 0.
  295. auto *Index = dyn_cast<ConstantInt>(EE.getIndexOperand());
  296. if (!Index || !Index->isNullValue())
  297. return nullptr;
  298. const auto *BO = dyn_cast<BinaryOperator>(EE.getVectorOperand());
  299. if (!BO || BO->getOpcode() != Instruction::Add || !BO->hasOneUse())
  300. return nullptr;
  301. if (EE.getParent() != BO->getParent())
  302. ReduceInOneBB = false;
  303. unsigned NumElems = cast<FixedVectorType>(BO->getType())->getNumElements();
  304. // Ensure the reduction size is a power of 2.
  305. if (!isPowerOf2_32(NumElems))
  306. return nullptr;
  307. const Value *Op = BO;
  308. unsigned Stages = Log2_32(NumElems);
  309. for (unsigned i = 0; i != Stages; ++i) {
  310. const auto *BO = dyn_cast<BinaryOperator>(Op);
  311. if (!BO || BO->getOpcode() != Instruction::Add)
  312. return nullptr;
  313. if (EE.getParent() != BO->getParent())
  314. ReduceInOneBB = false;
  315. // If this isn't the first add, then it should only have 2 users, the
  316. // shuffle and another add which we checked in the previous iteration.
  317. if (i != 0 && !BO->hasNUses(2))
  318. return nullptr;
  319. Value *LHS = BO->getOperand(0);
  320. Value *RHS = BO->getOperand(1);
  321. auto *Shuffle = dyn_cast<ShuffleVectorInst>(LHS);
  322. if (Shuffle) {
  323. Op = RHS;
  324. } else {
  325. Shuffle = dyn_cast<ShuffleVectorInst>(RHS);
  326. Op = LHS;
  327. }
  328. // The first operand of the shuffle should be the same as the other operand
  329. // of the bin op.
  330. if (!Shuffle || Shuffle->getOperand(0) != Op)
  331. return nullptr;
  332. // Verify the shuffle has the expected (at this stage of the pyramid) mask.
  333. unsigned MaskEnd = 1 << i;
  334. for (unsigned Index = 0; Index < MaskEnd; ++Index)
  335. if (Shuffle->getMaskValue(Index) != (int)(MaskEnd + Index))
  336. return nullptr;
  337. }
  338. return const_cast<Value *>(Op);
  339. }
  340. // See if this BO is reachable from this Phi by walking forward through single
  341. // use BinaryOperators with the same opcode. If we get back then we know we've
  342. // found a loop and it is safe to step through this Add to find more leaves.
  343. static bool isReachableFromPHI(PHINode *Phi, BinaryOperator *BO) {
  344. // The PHI itself should only have one use.
  345. if (!Phi->hasOneUse())
  346. return false;
  347. Instruction *U = cast<Instruction>(*Phi->user_begin());
  348. if (U == BO)
  349. return true;
  350. while (U->hasOneUse() && U->getOpcode() == BO->getOpcode())
  351. U = cast<Instruction>(*U->user_begin());
  352. return U == BO;
  353. }
  354. // Collect all the leaves of the tree of adds that feeds into the horizontal
  355. // reduction. Root is the Value that is used by the horizontal reduction.
  356. // We look through single use phis, single use adds, or adds that are used by
  357. // a phi that forms a loop with the add.
  358. static void collectLeaves(Value *Root, SmallVectorImpl<Instruction *> &Leaves) {
  359. SmallPtrSet<Value *, 8> Visited;
  360. SmallVector<Value *, 8> Worklist;
  361. Worklist.push_back(Root);
  362. while (!Worklist.empty()) {
  363. Value *V = Worklist.pop_back_val();
  364. if (!Visited.insert(V).second)
  365. continue;
  366. if (auto *PN = dyn_cast<PHINode>(V)) {
  367. // PHI node should have single use unless it is the root node, then it
  368. // has 2 uses.
  369. if (!PN->hasNUses(PN == Root ? 2 : 1))
  370. break;
  371. // Push incoming values to the worklist.
  372. append_range(Worklist, PN->incoming_values());
  373. continue;
  374. }
  375. if (auto *BO = dyn_cast<BinaryOperator>(V)) {
  376. if (BO->getOpcode() == Instruction::Add) {
  377. // Simple case. Single use, just push its operands to the worklist.
  378. if (BO->hasNUses(BO == Root ? 2 : 1)) {
  379. append_range(Worklist, BO->operands());
  380. continue;
  381. }
  382. // If there is additional use, make sure it is an unvisited phi that
  383. // gets us back to this node.
  384. if (BO->hasNUses(BO == Root ? 3 : 2)) {
  385. PHINode *PN = nullptr;
  386. for (auto *U : BO->users())
  387. if (auto *P = dyn_cast<PHINode>(U))
  388. if (!Visited.count(P))
  389. PN = P;
  390. // If we didn't find a 2-input PHI then this isn't a case we can
  391. // handle.
  392. if (!PN || PN->getNumIncomingValues() != 2)
  393. continue;
  394. // Walk forward from this phi to see if it reaches back to this add.
  395. if (!isReachableFromPHI(PN, BO))
  396. continue;
  397. // The phi forms a loop with this Add, push its operands.
  398. append_range(Worklist, BO->operands());
  399. }
  400. }
  401. }
  402. // Not an add or phi, make it a leaf.
  403. if (auto *I = dyn_cast<Instruction>(V)) {
  404. if (!V->hasNUses(I == Root ? 2 : 1))
  405. continue;
  406. // Add this as a leaf.
  407. Leaves.push_back(I);
  408. }
  409. }
  410. }
  411. bool X86PartialReduction::runOnFunction(Function &F) {
  412. if (skipFunction(F))
  413. return false;
  414. auto *TPC = getAnalysisIfAvailable<TargetPassConfig>();
  415. if (!TPC)
  416. return false;
  417. auto &TM = TPC->getTM<X86TargetMachine>();
  418. ST = TM.getSubtargetImpl(F);
  419. DL = &F.getParent()->getDataLayout();
  420. bool MadeChange = false;
  421. for (auto &BB : F) {
  422. for (auto &I : BB) {
  423. auto *EE = dyn_cast<ExtractElementInst>(&I);
  424. if (!EE)
  425. continue;
  426. bool ReduceInOneBB;
  427. // First find a reduction tree.
  428. // FIXME: Do we need to handle other opcodes than Add?
  429. Value *Root = matchAddReduction(*EE, ReduceInOneBB);
  430. if (!Root)
  431. continue;
  432. SmallVector<Instruction *, 8> Leaves;
  433. collectLeaves(Root, Leaves);
  434. for (Instruction *I : Leaves) {
  435. if (tryMAddReplacement(I, ReduceInOneBB)) {
  436. MadeChange = true;
  437. continue;
  438. }
  439. // Don't do SAD matching on the root node. SelectionDAG already
  440. // has support for that and currently generates better code.
  441. if (I != Root && trySADReplacement(I))
  442. MadeChange = true;
  443. }
  444. }
  445. }
  446. return MadeChange;
  447. }