| //===--- ExpandReductions.cpp - Expand experimental reduction intrinsics --===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This pass implements IR expansion for reduction intrinsics, allowing targets | |
| // to enable the experimental intrinsics until just before codegen. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/CodeGen/ExpandReductions.h" | |
| #include "llvm/Analysis/TargetTransformInfo.h" | |
| #include "llvm/CodeGen/Passes.h" | |
| #include "llvm/IR/Function.h" | |
| #include "llvm/IR/IRBuilder.h" | |
| #include "llvm/IR/InstIterator.h" | |
| #include "llvm/IR/IntrinsicInst.h" | |
| #include "llvm/IR/Intrinsics.h" | |
| #include "llvm/IR/Module.h" | |
| #include "llvm/Pass.h" | |
| #include "llvm/Transforms/Utils/LoopUtils.h" | |
| using namespace llvm; | |
| namespace { | |
| unsigned getOpcode(Intrinsic::ID ID) { | |
| switch (ID) { | |
| case Intrinsic::experimental_vector_reduce_fadd: | |
| return Instruction::FAdd; | |
| case Intrinsic::experimental_vector_reduce_fmul: | |
| return Instruction::FMul; | |
| case Intrinsic::experimental_vector_reduce_add: | |
| return Instruction::Add; | |
| case Intrinsic::experimental_vector_reduce_mul: | |
| return Instruction::Mul; | |
| case Intrinsic::experimental_vector_reduce_and: | |
| return Instruction::And; | |
| case Intrinsic::experimental_vector_reduce_or: | |
| return Instruction::Or; | |
| case Intrinsic::experimental_vector_reduce_xor: | |
| return Instruction::Xor; | |
| case Intrinsic::experimental_vector_reduce_smax: | |
| case Intrinsic::experimental_vector_reduce_smin: | |
| case Intrinsic::experimental_vector_reduce_umax: | |
| case Intrinsic::experimental_vector_reduce_umin: | |
| return Instruction::ICmp; | |
| case Intrinsic::experimental_vector_reduce_fmax: | |
| case Intrinsic::experimental_vector_reduce_fmin: | |
| return Instruction::FCmp; | |
| default: | |
| llvm_unreachable("Unexpected ID"); | |
| } | |
| } | |
| RecurrenceDescriptor::MinMaxRecurrenceKind getMRK(Intrinsic::ID ID) { | |
| switch (ID) { | |
| case Intrinsic::experimental_vector_reduce_smax: | |
| return RecurrenceDescriptor::MRK_SIntMax; | |
| case Intrinsic::experimental_vector_reduce_smin: | |
| return RecurrenceDescriptor::MRK_SIntMin; | |
| case Intrinsic::experimental_vector_reduce_umax: | |
| return RecurrenceDescriptor::MRK_UIntMax; | |
| case Intrinsic::experimental_vector_reduce_umin: | |
| return RecurrenceDescriptor::MRK_UIntMin; | |
| case Intrinsic::experimental_vector_reduce_fmax: | |
| return RecurrenceDescriptor::MRK_FloatMax; | |
| case Intrinsic::experimental_vector_reduce_fmin: | |
| return RecurrenceDescriptor::MRK_FloatMin; | |
| default: | |
| return RecurrenceDescriptor::MRK_Invalid; | |
| } | |
| } | |
| bool expandReductions(Function &F, const TargetTransformInfo *TTI) { | |
| bool Changed = false; | |
| SmallVector<IntrinsicInst *, 4> Worklist; | |
| for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) | |
| if (auto II = dyn_cast<IntrinsicInst>(&*I)) | |
| Worklist.push_back(II); | |
| for (auto *II : Worklist) { | |
| IRBuilder<> Builder(II); | |
| bool IsOrdered = false; | |
| Value *Acc = nullptr; | |
| Value *Vec = nullptr; | |
| auto ID = II->getIntrinsicID(); | |
| auto MRK = RecurrenceDescriptor::MRK_Invalid; | |
| switch (ID) { | |
| case Intrinsic::experimental_vector_reduce_fadd: | |
| case Intrinsic::experimental_vector_reduce_fmul: | |
| // FMFs must be attached to the call, otherwise it's an ordered reduction | |
| // and it can't be handled by generating a shuffle sequence. | |
| if (!II->getFastMathFlags().isFast()) | |
| IsOrdered = true; | |
| Acc = II->getArgOperand(0); | |
| Vec = II->getArgOperand(1); | |
| break; | |
| case Intrinsic::experimental_vector_reduce_add: | |
| case Intrinsic::experimental_vector_reduce_mul: | |
| case Intrinsic::experimental_vector_reduce_and: | |
| case Intrinsic::experimental_vector_reduce_or: | |
| case Intrinsic::experimental_vector_reduce_xor: | |
| case Intrinsic::experimental_vector_reduce_smax: | |
| case Intrinsic::experimental_vector_reduce_smin: | |
| case Intrinsic::experimental_vector_reduce_umax: | |
| case Intrinsic::experimental_vector_reduce_umin: | |
| case Intrinsic::experimental_vector_reduce_fmax: | |
| case Intrinsic::experimental_vector_reduce_fmin: | |
| Vec = II->getArgOperand(0); | |
| MRK = getMRK(ID); | |
| break; | |
| default: | |
| continue; | |
| } | |
| if (!TTI->shouldExpandReduction(II)) | |
| continue; | |
| Value *Rdx = | |
| IsOrdered ? getOrderedReduction(Builder, Acc, Vec, getOpcode(ID), MRK) | |
| : getShuffleReduction(Builder, Vec, getOpcode(ID), MRK); | |
| II->replaceAllUsesWith(Rdx); | |
| II->eraseFromParent(); | |
| Changed = true; | |
| } | |
| return Changed; | |
| } | |
| class ExpandReductions : public FunctionPass { | |
| public: | |
| static char ID; | |
| ExpandReductions() : FunctionPass(ID) { | |
| initializeExpandReductionsPass(*PassRegistry::getPassRegistry()); | |
| } | |
| bool runOnFunction(Function &F) override { | |
| const auto *TTI =&getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); | |
| return expandReductions(F, TTI); | |
| } | |
| void getAnalysisUsage(AnalysisUsage &AU) const override { | |
| AU.addRequired<TargetTransformInfoWrapperPass>(); | |
| AU.setPreservesCFG(); | |
| } | |
| }; | |
| } | |
| char ExpandReductions::ID; | |
| INITIALIZE_PASS_BEGIN(ExpandReductions, "expand-reductions", | |
| "Expand reduction intrinsics", false, false) | |
| INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) | |
| INITIALIZE_PASS_END(ExpandReductions, "expand-reductions", | |
| "Expand reduction intrinsics", false, false) | |
| FunctionPass *llvm::createExpandReductionsPass() { | |
| return new ExpandReductions(); | |
| } | |
| PreservedAnalyses ExpandReductionsPass::run(Function &F, | |
| FunctionAnalysisManager &AM) { | |
| const auto &TTI = AM.getResult<TargetIRAnalysis>(F); | |
| if (!expandReductions(F, &TTI)) | |
| return PreservedAnalyses::all(); | |
| PreservedAnalyses PA; | |
| PA.preserveSet<CFGAnalyses>(); | |
| return PA; | |
| } |