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