15517e702SDimitry Andric //===--- ExpandReductions.cpp - Expand experimental reduction intrinsics --===//
25517e702SDimitry Andric //
35517e702SDimitry Andric //                     The LLVM Compiler Infrastructure
45517e702SDimitry Andric //
55517e702SDimitry Andric // This file is distributed under the University of Illinois Open Source
65517e702SDimitry Andric // License. See LICENSE.TXT for details.
75517e702SDimitry Andric //
85517e702SDimitry Andric //===----------------------------------------------------------------------===//
95517e702SDimitry Andric //
105517e702SDimitry Andric // This pass implements IR expansion for reduction intrinsics, allowing targets
115517e702SDimitry Andric // to enable the experimental intrinsics until just before codegen.
125517e702SDimitry Andric //
135517e702SDimitry Andric //===----------------------------------------------------------------------===//
145517e702SDimitry Andric 
155517e702SDimitry Andric #include "llvm/CodeGen/ExpandReductions.h"
16db17bf38SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
175517e702SDimitry Andric #include "llvm/CodeGen/Passes.h"
185517e702SDimitry Andric #include "llvm/IR/Function.h"
195517e702SDimitry Andric #include "llvm/IR/IRBuilder.h"
205517e702SDimitry Andric #include "llvm/IR/InstIterator.h"
215517e702SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
22db17bf38SDimitry Andric #include "llvm/IR/Intrinsics.h"
235517e702SDimitry Andric #include "llvm/IR/Module.h"
245517e702SDimitry Andric #include "llvm/Pass.h"
25db17bf38SDimitry Andric #include "llvm/Transforms/Utils/LoopUtils.h"
265517e702SDimitry Andric 
275517e702SDimitry Andric using namespace llvm;
285517e702SDimitry Andric 
295517e702SDimitry Andric namespace {
305517e702SDimitry Andric 
getOpcode(Intrinsic::ID ID)315517e702SDimitry Andric unsigned getOpcode(Intrinsic::ID ID) {
325517e702SDimitry Andric   switch (ID) {
335517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_fadd:
345517e702SDimitry Andric     return Instruction::FAdd;
355517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_fmul:
365517e702SDimitry Andric     return Instruction::FMul;
375517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_add:
385517e702SDimitry Andric     return Instruction::Add;
395517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_mul:
405517e702SDimitry Andric     return Instruction::Mul;
415517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_and:
425517e702SDimitry Andric     return Instruction::And;
435517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_or:
445517e702SDimitry Andric     return Instruction::Or;
455517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_xor:
465517e702SDimitry Andric     return Instruction::Xor;
475517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_smax:
485517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_smin:
495517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_umax:
505517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_umin:
515517e702SDimitry Andric     return Instruction::ICmp;
525517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_fmax:
535517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_fmin:
545517e702SDimitry Andric     return Instruction::FCmp;
555517e702SDimitry Andric   default:
565517e702SDimitry Andric     llvm_unreachable("Unexpected ID");
575517e702SDimitry Andric   }
585517e702SDimitry Andric }
595517e702SDimitry Andric 
getMRK(Intrinsic::ID ID)605517e702SDimitry Andric RecurrenceDescriptor::MinMaxRecurrenceKind getMRK(Intrinsic::ID ID) {
615517e702SDimitry Andric   switch (ID) {
625517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_smax:
635517e702SDimitry Andric     return RecurrenceDescriptor::MRK_SIntMax;
645517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_smin:
655517e702SDimitry Andric     return RecurrenceDescriptor::MRK_SIntMin;
665517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_umax:
675517e702SDimitry Andric     return RecurrenceDescriptor::MRK_UIntMax;
685517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_umin:
695517e702SDimitry Andric     return RecurrenceDescriptor::MRK_UIntMin;
705517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_fmax:
715517e702SDimitry Andric     return RecurrenceDescriptor::MRK_FloatMax;
725517e702SDimitry Andric   case Intrinsic::experimental_vector_reduce_fmin:
735517e702SDimitry Andric     return RecurrenceDescriptor::MRK_FloatMin;
745517e702SDimitry Andric   default:
755517e702SDimitry Andric     return RecurrenceDescriptor::MRK_Invalid;
765517e702SDimitry Andric   }
775517e702SDimitry Andric }
785517e702SDimitry Andric 
expandReductions(Function & F,const TargetTransformInfo * TTI)795517e702SDimitry Andric bool expandReductions(Function &F, const TargetTransformInfo *TTI) {
805517e702SDimitry Andric   bool Changed = false;
815517e702SDimitry Andric   SmallVector<IntrinsicInst *, 4> Worklist;
825517e702SDimitry Andric   for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I)
835517e702SDimitry Andric     if (auto II = dyn_cast<IntrinsicInst>(&*I))
845517e702SDimitry Andric       Worklist.push_back(II);
855517e702SDimitry Andric 
865517e702SDimitry Andric   for (auto *II : Worklist) {
875517e702SDimitry Andric     IRBuilder<> Builder(II);
88*4ba319b5SDimitry Andric     bool IsOrdered = false;
89*4ba319b5SDimitry Andric     Value *Acc = nullptr;
905517e702SDimitry Andric     Value *Vec = nullptr;
915517e702SDimitry Andric     auto ID = II->getIntrinsicID();
925517e702SDimitry Andric     auto MRK = RecurrenceDescriptor::MRK_Invalid;
935517e702SDimitry Andric     switch (ID) {
945517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_fadd:
955517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_fmul:
965517e702SDimitry Andric       // FMFs must be attached to the call, otherwise it's an ordered reduction
97*4ba319b5SDimitry Andric       // and it can't be handled by generating a shuffle sequence.
982cab237bSDimitry Andric       if (!II->getFastMathFlags().isFast())
99*4ba319b5SDimitry Andric         IsOrdered = true;
100*4ba319b5SDimitry Andric       Acc = II->getArgOperand(0);
1015517e702SDimitry Andric       Vec = II->getArgOperand(1);
1025517e702SDimitry Andric       break;
1035517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_add:
1045517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_mul:
1055517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_and:
1065517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_or:
1075517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_xor:
1085517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_smax:
1095517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_smin:
1105517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_umax:
1115517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_umin:
1125517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_fmax:
1135517e702SDimitry Andric     case Intrinsic::experimental_vector_reduce_fmin:
1145517e702SDimitry Andric       Vec = II->getArgOperand(0);
1155517e702SDimitry Andric       MRK = getMRK(ID);
1165517e702SDimitry Andric       break;
1175517e702SDimitry Andric     default:
1185517e702SDimitry Andric       continue;
1195517e702SDimitry Andric     }
1205517e702SDimitry Andric     if (!TTI->shouldExpandReduction(II))
1215517e702SDimitry Andric       continue;
122*4ba319b5SDimitry Andric     Value *Rdx =
123*4ba319b5SDimitry Andric         IsOrdered ? getOrderedReduction(Builder, Acc, Vec, getOpcode(ID), MRK)
124*4ba319b5SDimitry Andric                   : getShuffleReduction(Builder, Vec, getOpcode(ID), MRK);
1255517e702SDimitry Andric     II->replaceAllUsesWith(Rdx);
1265517e702SDimitry Andric     II->eraseFromParent();
1275517e702SDimitry Andric     Changed = true;
1285517e702SDimitry Andric   }
1295517e702SDimitry Andric   return Changed;
1305517e702SDimitry Andric }
1315517e702SDimitry Andric 
1325517e702SDimitry Andric class ExpandReductions : public FunctionPass {
1335517e702SDimitry Andric public:
1345517e702SDimitry Andric   static char ID;
ExpandReductions()1355517e702SDimitry Andric   ExpandReductions() : FunctionPass(ID) {
1365517e702SDimitry Andric     initializeExpandReductionsPass(*PassRegistry::getPassRegistry());
1375517e702SDimitry Andric   }
1385517e702SDimitry Andric 
runOnFunction(Function & F)1395517e702SDimitry Andric   bool runOnFunction(Function &F) override {
1405517e702SDimitry Andric     const auto *TTI =&getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
1415517e702SDimitry Andric     return expandReductions(F, TTI);
1425517e702SDimitry Andric   }
1435517e702SDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const1445517e702SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
1455517e702SDimitry Andric     AU.addRequired<TargetTransformInfoWrapperPass>();
1465517e702SDimitry Andric     AU.setPreservesCFG();
1475517e702SDimitry Andric   }
1485517e702SDimitry Andric };
1495517e702SDimitry Andric }
1505517e702SDimitry Andric 
1515517e702SDimitry Andric char ExpandReductions::ID;
1525517e702SDimitry Andric INITIALIZE_PASS_BEGIN(ExpandReductions, "expand-reductions",
1535517e702SDimitry Andric                       "Expand reduction intrinsics", false, false)
INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)1545517e702SDimitry Andric INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
1555517e702SDimitry Andric INITIALIZE_PASS_END(ExpandReductions, "expand-reductions",
1565517e702SDimitry Andric                     "Expand reduction intrinsics", false, false)
1575517e702SDimitry Andric 
1585517e702SDimitry Andric FunctionPass *llvm::createExpandReductionsPass() {
1595517e702SDimitry Andric   return new ExpandReductions();
1605517e702SDimitry Andric }
1615517e702SDimitry Andric 
run(Function & F,FunctionAnalysisManager & AM)1625517e702SDimitry Andric PreservedAnalyses ExpandReductionsPass::run(Function &F,
1635517e702SDimitry Andric                                             FunctionAnalysisManager &AM) {
1645517e702SDimitry Andric   const auto &TTI = AM.getResult<TargetIRAnalysis>(F);
1655517e702SDimitry Andric   if (!expandReductions(F, &TTI))
1665517e702SDimitry Andric     return PreservedAnalyses::all();
1675517e702SDimitry Andric   PreservedAnalyses PA;
1685517e702SDimitry Andric   PA.preserveSet<CFGAnalyses>();
1695517e702SDimitry Andric   return PA;
1705517e702SDimitry Andric }
171