[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
//===------- VectorCombine.cpp - Optimize partial vector operations -------===//
|
|
|
|
//
|
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This pass optimizes scalar/vector interactions using target cost models. The
|
|
|
|
// transforms implemented here may not fit in traditional loop-based or SLP
|
|
|
|
// vectorization passes.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "llvm/Transforms/Vectorize/VectorCombine.h"
|
|
|
|
#include "llvm/ADT/Statistic.h"
|
2020-06-06 21:06:25 +08:00
|
|
|
#include "llvm/Analysis/BasicAliasAnalysis.h"
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
#include "llvm/Analysis/GlobalsModRef.h"
|
|
|
|
#include "llvm/Analysis/TargetTransformInfo.h"
|
[VectorCombine] try to form vector binop to eliminate an extract element
binop (extelt X, C), (extelt Y, C) --> extelt (binop X, Y), C
This is a transform that has been considered for canonicalization (instcombine)
in the past because it reduces instruction count. But as shown in the x86 tests,
it's impossible to know if it's profitable without a cost model. There are many
potential target constraints to consider.
We have implemented similar transforms in the backend (DAGCombiner and
target-specific), but I don't think we have this exact fold there either (and if
we did it in SDAG, it wouldn't work across blocks).
Note: this patch was intended to handle the more general case where the extract
indexes do not match, but it got too big, so I scaled it back to this pattern
for now.
Differential Revision: https://reviews.llvm.org/D74495
2020-02-14 05:08:15 +08:00
|
|
|
#include "llvm/Analysis/ValueTracking.h"
|
2020-04-03 01:21:29 +08:00
|
|
|
#include "llvm/Analysis/VectorUtils.h"
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
#include "llvm/IR/Dominators.h"
|
|
|
|
#include "llvm/IR/Function.h"
|
|
|
|
#include "llvm/IR/IRBuilder.h"
|
|
|
|
#include "llvm/IR/PatternMatch.h"
|
|
|
|
#include "llvm/InitializePasses.h"
|
|
|
|
#include "llvm/Pass.h"
|
2020-02-27 04:14:35 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
#include "llvm/Transforms/Utils/Local.h"
|
2020-06-06 21:06:25 +08:00
|
|
|
#include "llvm/Transforms/Vectorize.h"
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace llvm::PatternMatch;
|
|
|
|
|
|
|
|
#define DEBUG_TYPE "vector-combine"
|
|
|
|
STATISTIC(NumVecCmp, "Number of vector compares formed");
|
[VectorCombine] try to form vector binop to eliminate an extract element
binop (extelt X, C), (extelt Y, C) --> extelt (binop X, Y), C
This is a transform that has been considered for canonicalization (instcombine)
in the past because it reduces instruction count. But as shown in the x86 tests,
it's impossible to know if it's profitable without a cost model. There are many
potential target constraints to consider.
We have implemented similar transforms in the backend (DAGCombiner and
target-specific), but I don't think we have this exact fold there either (and if
we did it in SDAG, it wouldn't work across blocks).
Note: this patch was intended to handle the more general case where the extract
indexes do not match, but it got too big, so I scaled it back to this pattern
for now.
Differential Revision: https://reviews.llvm.org/D74495
2020-02-14 05:08:15 +08:00
|
|
|
STATISTIC(NumVecBO, "Number of vector binops formed");
|
2020-06-13 01:49:38 +08:00
|
|
|
STATISTIC(NumShufOfBitcast, "Number of shuffles moved after bitcast");
|
2020-05-09 04:29:07 +08:00
|
|
|
STATISTIC(NumScalarBO, "Number of scalar binops formed");
|
2020-06-17 01:30:40 +08:00
|
|
|
STATISTIC(NumScalarCmp, "Number of scalar compares formed");
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
|
2020-02-27 04:14:35 +08:00
|
|
|
static cl::opt<bool> DisableVectorCombine(
|
|
|
|
"disable-vector-combine", cl::init(false), cl::Hidden,
|
|
|
|
cl::desc("Disable all vector combine transforms"));
|
|
|
|
|
2020-03-08 21:57:55 +08:00
|
|
|
static cl::opt<bool> DisableBinopExtractShuffle(
|
|
|
|
"disable-binop-extract-shuffle", cl::init(false), cl::Hidden,
|
|
|
|
cl::desc("Disable binop extract to shuffle transforms"));
|
|
|
|
|
|
|
|
|
|
|
|
/// Compare the relative costs of 2 extracts followed by scalar operation vs.
|
|
|
|
/// vector operation(s) followed by extract. Return true if the existing
|
|
|
|
/// instructions are cheaper than a vector alternative. Otherwise, return false
|
|
|
|
/// and if one of the extracts should be transformed to a shufflevector, set
|
|
|
|
/// \p ConvertToShuffle to that extract instruction.
|
2020-02-22 03:25:39 +08:00
|
|
|
static bool isExtractExtractCheap(Instruction *Ext0, Instruction *Ext1,
|
|
|
|
unsigned Opcode,
|
2020-03-08 21:57:55 +08:00
|
|
|
const TargetTransformInfo &TTI,
|
[VectorCombine] try to form a better extractelement
Extracting to the same index that we are going to insert back into
allows forming select ("blend") shuffles and enables further transforms.
Admittedly, this is a quick-fix for a more general problem that I'm
hoping to solve by adding transforms for patterns that start with an
insertelement.
But this might resolve some regressions known to be caused by the
extract-extract transform (although I have not gotten more details on
those yet).
In the motivating case from PR34724:
https://bugs.llvm.org/show_bug.cgi?id=34724
The combination of subsequent instcombine and codegen transforms gets us this improvement:
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm4
vmovshdup %xmm1, %xmm3 ## xmm3 = xmm1[1,1,3,3]
vaddps %xmm0, %xmm2, %xmm0
vaddps %xmm1, %xmm3, %xmm1
vshufps $200, %xmm4, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm4[0,3]
vinsertps $177, %xmm1, %xmm0, %xmm0 ## xmm0 = zero,xmm0[1,2],xmm1[2]
-->
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm1
vaddps %xmm0, %xmm2, %xmm0
vshufps $200, %xmm1, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm1[0,3]
Differential Revision: https://reviews.llvm.org/D76623
2020-04-04 01:53:54 +08:00
|
|
|
Instruction *&ConvertToShuffle,
|
|
|
|
unsigned PreferredExtractIndex) {
|
2020-02-29 02:08:59 +08:00
|
|
|
assert(isa<ConstantInt>(Ext0->getOperand(1)) &&
|
2020-03-08 21:57:55 +08:00
|
|
|
isa<ConstantInt>(Ext1->getOperand(1)) &&
|
|
|
|
"Expected constant extract indexes");
|
2020-02-22 03:25:39 +08:00
|
|
|
Type *ScalarTy = Ext0->getType();
|
2020-04-17 20:29:31 +08:00
|
|
|
auto *VecTy = cast<VectorType>(Ext0->getOperand(0)->getType());
|
2020-02-22 03:25:39 +08:00
|
|
|
int ScalarOpCost, VectorOpCost;
|
|
|
|
|
|
|
|
// Get cost estimates for scalar and vector versions of the operation.
|
|
|
|
bool IsBinOp = Instruction::isBinaryOp(Opcode);
|
|
|
|
if (IsBinOp) {
|
|
|
|
ScalarOpCost = TTI.getArithmeticInstrCost(Opcode, ScalarTy);
|
|
|
|
VectorOpCost = TTI.getArithmeticInstrCost(Opcode, VecTy);
|
|
|
|
} else {
|
|
|
|
assert((Opcode == Instruction::ICmp || Opcode == Instruction::FCmp) &&
|
|
|
|
"Expected a compare");
|
|
|
|
ScalarOpCost = TTI.getCmpSelInstrCost(Opcode, ScalarTy,
|
|
|
|
CmpInst::makeCmpResultType(ScalarTy));
|
|
|
|
VectorOpCost = TTI.getCmpSelInstrCost(Opcode, VecTy,
|
|
|
|
CmpInst::makeCmpResultType(VecTy));
|
|
|
|
}
|
|
|
|
|
2020-03-08 21:57:55 +08:00
|
|
|
// Get cost estimates for the extract elements. These costs will factor into
|
2020-02-22 03:25:39 +08:00
|
|
|
// both sequences.
|
2020-03-08 21:57:55 +08:00
|
|
|
unsigned Ext0Index = cast<ConstantInt>(Ext0->getOperand(1))->getZExtValue();
|
|
|
|
unsigned Ext1Index = cast<ConstantInt>(Ext1->getOperand(1))->getZExtValue();
|
|
|
|
|
|
|
|
int Extract0Cost = TTI.getVectorInstrCost(Instruction::ExtractElement,
|
|
|
|
VecTy, Ext0Index);
|
|
|
|
int Extract1Cost = TTI.getVectorInstrCost(Instruction::ExtractElement,
|
|
|
|
VecTy, Ext1Index);
|
|
|
|
|
|
|
|
// A more expensive extract will always be replaced by a splat shuffle.
|
|
|
|
// For example, if Ext0 is more expensive:
|
|
|
|
// opcode (extelt V0, Ext0), (ext V1, Ext1) -->
|
|
|
|
// extelt (opcode (splat V0, Ext0), V1), Ext1
|
|
|
|
// TODO: Evaluate whether that always results in lowest cost. Alternatively,
|
|
|
|
// check the cost of creating a broadcast shuffle and shuffling both
|
|
|
|
// operands to element 0.
|
|
|
|
int CheapExtractCost = std::min(Extract0Cost, Extract1Cost);
|
2020-02-22 03:25:39 +08:00
|
|
|
|
|
|
|
// Extra uses of the extracts mean that we include those costs in the
|
|
|
|
// vector total because those instructions will not be eliminated.
|
2020-02-22 04:43:05 +08:00
|
|
|
int OldCost, NewCost;
|
2020-03-08 21:57:55 +08:00
|
|
|
if (Ext0->getOperand(0) == Ext1->getOperand(0) && Ext0Index == Ext1Index) {
|
|
|
|
// Handle a special case. If the 2 extracts are identical, adjust the
|
2020-02-22 03:25:39 +08:00
|
|
|
// formulas to account for that. The extra use charge allows for either the
|
|
|
|
// CSE'd pattern or an unoptimized form with identical values:
|
|
|
|
// opcode (extelt V, C), (extelt V, C) --> extelt (opcode V, V), C
|
|
|
|
bool HasUseTax = Ext0 == Ext1 ? !Ext0->hasNUses(2)
|
|
|
|
: !Ext0->hasOneUse() || !Ext1->hasOneUse();
|
2020-03-08 21:57:55 +08:00
|
|
|
OldCost = CheapExtractCost + ScalarOpCost;
|
|
|
|
NewCost = VectorOpCost + CheapExtractCost + HasUseTax * CheapExtractCost;
|
2020-02-22 03:25:39 +08:00
|
|
|
} else {
|
|
|
|
// Handle the general case. Each extract is actually a different value:
|
2020-03-08 21:57:55 +08:00
|
|
|
// opcode (extelt V0, C0), (extelt V1, C1) --> extelt (opcode V0, V1), C
|
|
|
|
OldCost = Extract0Cost + Extract1Cost + ScalarOpCost;
|
|
|
|
NewCost = VectorOpCost + CheapExtractCost +
|
|
|
|
!Ext0->hasOneUse() * Extract0Cost +
|
|
|
|
!Ext1->hasOneUse() * Extract1Cost;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Ext0Index == Ext1Index) {
|
|
|
|
// If the extract indexes are identical, no shuffle is needed.
|
|
|
|
ConvertToShuffle = nullptr;
|
|
|
|
} else {
|
|
|
|
if (IsBinOp && DisableBinopExtractShuffle)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// If we are extracting from 2 different indexes, then one operand must be
|
|
|
|
// shuffled before performing the vector operation. The shuffle mask is
|
|
|
|
// undefined except for 1 lane that is being translated to the remaining
|
|
|
|
// extraction lane. Therefore, it is a splat shuffle. Ex:
|
|
|
|
// ShufMask = { undef, undef, 0, undef }
|
|
|
|
// TODO: The cost model has an option for a "broadcast" shuffle
|
|
|
|
// (splat-from-element-0), but no option for a more general splat.
|
|
|
|
NewCost +=
|
|
|
|
TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, VecTy);
|
|
|
|
|
[VectorCombine] try to form a better extractelement
Extracting to the same index that we are going to insert back into
allows forming select ("blend") shuffles and enables further transforms.
Admittedly, this is a quick-fix for a more general problem that I'm
hoping to solve by adding transforms for patterns that start with an
insertelement.
But this might resolve some regressions known to be caused by the
extract-extract transform (although I have not gotten more details on
those yet).
In the motivating case from PR34724:
https://bugs.llvm.org/show_bug.cgi?id=34724
The combination of subsequent instcombine and codegen transforms gets us this improvement:
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm4
vmovshdup %xmm1, %xmm3 ## xmm3 = xmm1[1,1,3,3]
vaddps %xmm0, %xmm2, %xmm0
vaddps %xmm1, %xmm3, %xmm1
vshufps $200, %xmm4, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm4[0,3]
vinsertps $177, %xmm1, %xmm0, %xmm0 ## xmm0 = zero,xmm0[1,2],xmm1[2]
-->
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm1
vaddps %xmm0, %xmm2, %xmm0
vshufps $200, %xmm1, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm1[0,3]
Differential Revision: https://reviews.llvm.org/D76623
2020-04-04 01:53:54 +08:00
|
|
|
// The more expensive extract will be replaced by a shuffle. If the costs
|
|
|
|
// are equal and there is a preferred extract index, shuffle the opposite
|
|
|
|
// operand. Otherwise, replace the extract with the higher index.
|
2020-03-08 21:57:55 +08:00
|
|
|
if (Extract0Cost > Extract1Cost)
|
|
|
|
ConvertToShuffle = Ext0;
|
|
|
|
else if (Extract1Cost > Extract0Cost)
|
|
|
|
ConvertToShuffle = Ext1;
|
[VectorCombine] try to form a better extractelement
Extracting to the same index that we are going to insert back into
allows forming select ("blend") shuffles and enables further transforms.
Admittedly, this is a quick-fix for a more general problem that I'm
hoping to solve by adding transforms for patterns that start with an
insertelement.
But this might resolve some regressions known to be caused by the
extract-extract transform (although I have not gotten more details on
those yet).
In the motivating case from PR34724:
https://bugs.llvm.org/show_bug.cgi?id=34724
The combination of subsequent instcombine and codegen transforms gets us this improvement:
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm4
vmovshdup %xmm1, %xmm3 ## xmm3 = xmm1[1,1,3,3]
vaddps %xmm0, %xmm2, %xmm0
vaddps %xmm1, %xmm3, %xmm1
vshufps $200, %xmm4, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm4[0,3]
vinsertps $177, %xmm1, %xmm0, %xmm0 ## xmm0 = zero,xmm0[1,2],xmm1[2]
-->
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm1
vaddps %xmm0, %xmm2, %xmm0
vshufps $200, %xmm1, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm1[0,3]
Differential Revision: https://reviews.llvm.org/D76623
2020-04-04 01:53:54 +08:00
|
|
|
else if (PreferredExtractIndex == Ext0Index)
|
|
|
|
ConvertToShuffle = Ext1;
|
|
|
|
else if (PreferredExtractIndex == Ext1Index)
|
|
|
|
ConvertToShuffle = Ext0;
|
2020-03-08 21:57:55 +08:00
|
|
|
else
|
|
|
|
ConvertToShuffle = Ext0Index > Ext1Index ? Ext0 : Ext1;
|
2020-02-22 03:25:39 +08:00
|
|
|
}
|
2020-03-08 21:57:55 +08:00
|
|
|
|
2020-02-25 06:05:44 +08:00
|
|
|
// Aggressively form a vector op if the cost is equal because the transform
|
|
|
|
// may enable further optimization.
|
|
|
|
// Codegen can reverse this transform (scalarize) if it was not profitable.
|
|
|
|
return OldCost < NewCost;
|
2020-02-22 03:25:39 +08:00
|
|
|
}
|
|
|
|
|
2020-02-22 00:49:11 +08:00
|
|
|
/// Try to reduce extract element costs by converting scalar compares to vector
|
|
|
|
/// compares followed by extract.
|
2020-02-22 04:43:05 +08:00
|
|
|
/// cmp (ext0 V0, C), (ext1 V1, C)
|
|
|
|
static void foldExtExtCmp(Instruction *Ext0, Instruction *Ext1,
|
2020-06-12 04:50:03 +08:00
|
|
|
Instruction &I) {
|
2020-02-22 00:49:11 +08:00
|
|
|
assert(isa<CmpInst>(&I) && "Expected a compare");
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
|
|
|
|
// cmp Pred (extelt V0, C), (extelt V1, C) --> extelt (cmp Pred V0, V1), C
|
|
|
|
++NumVecCmp;
|
|
|
|
IRBuilder<> Builder(&I);
|
2020-02-22 00:49:11 +08:00
|
|
|
CmpInst::Predicate Pred = cast<CmpInst>(&I)->getPredicate();
|
2020-02-22 04:43:05 +08:00
|
|
|
Value *V0 = Ext0->getOperand(0), *V1 = Ext1->getOperand(0);
|
2020-02-22 03:25:39 +08:00
|
|
|
Value *VecCmp =
|
|
|
|
Ext0->getType()->isFloatingPointTy() ? Builder.CreateFCmp(Pred, V0, V1)
|
|
|
|
: Builder.CreateICmp(Pred, V0, V1);
|
2020-02-22 00:49:11 +08:00
|
|
|
Value *Extract = Builder.CreateExtractElement(VecCmp, Ext0->getOperand(1));
|
|
|
|
I.replaceAllUsesWith(Extract);
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
}
|
|
|
|
|
[VectorCombine] try to form vector binop to eliminate an extract element
binop (extelt X, C), (extelt Y, C) --> extelt (binop X, Y), C
This is a transform that has been considered for canonicalization (instcombine)
in the past because it reduces instruction count. But as shown in the x86 tests,
it's impossible to know if it's profitable without a cost model. There are many
potential target constraints to consider.
We have implemented similar transforms in the backend (DAGCombiner and
target-specific), but I don't think we have this exact fold there either (and if
we did it in SDAG, it wouldn't work across blocks).
Note: this patch was intended to handle the more general case where the extract
indexes do not match, but it got too big, so I scaled it back to this pattern
for now.
Differential Revision: https://reviews.llvm.org/D74495
2020-02-14 05:08:15 +08:00
|
|
|
/// Try to reduce extract element costs by converting scalar binops to vector
|
|
|
|
/// binops followed by extract.
|
2020-02-22 04:43:05 +08:00
|
|
|
/// bo (ext0 V0, C), (ext1 V1, C)
|
|
|
|
static void foldExtExtBinop(Instruction *Ext0, Instruction *Ext1,
|
2020-06-12 04:50:03 +08:00
|
|
|
Instruction &I) {
|
2020-02-22 00:49:11 +08:00
|
|
|
assert(isa<BinaryOperator>(&I) && "Expected a binary operator");
|
[VectorCombine] try to form vector binop to eliminate an extract element
binop (extelt X, C), (extelt Y, C) --> extelt (binop X, Y), C
This is a transform that has been considered for canonicalization (instcombine)
in the past because it reduces instruction count. But as shown in the x86 tests,
it's impossible to know if it's profitable without a cost model. There are many
potential target constraints to consider.
We have implemented similar transforms in the backend (DAGCombiner and
target-specific), but I don't think we have this exact fold there either (and if
we did it in SDAG, it wouldn't work across blocks).
Note: this patch was intended to handle the more general case where the extract
indexes do not match, but it got too big, so I scaled it back to this pattern
for now.
Differential Revision: https://reviews.llvm.org/D74495
2020-02-14 05:08:15 +08:00
|
|
|
|
2020-02-22 03:25:39 +08:00
|
|
|
// bo (extelt V0, C), (extelt V1, C) --> extelt (bo V0, V1), C
|
|
|
|
++NumVecBO;
|
|
|
|
IRBuilder<> Builder(&I);
|
2020-02-22 04:43:05 +08:00
|
|
|
Value *V0 = Ext0->getOperand(0), *V1 = Ext1->getOperand(0);
|
|
|
|
Value *VecBO =
|
2020-02-22 03:25:39 +08:00
|
|
|
Builder.CreateBinOp(cast<BinaryOperator>(&I)->getOpcode(), V0, V1);
|
2020-02-22 04:43:05 +08:00
|
|
|
|
|
|
|
// All IR flags are safe to back-propagate because any potential poison
|
|
|
|
// created in unused vector elements is discarded by the extract.
|
|
|
|
if (auto *VecBOInst = dyn_cast<Instruction>(VecBO))
|
2020-02-22 03:25:39 +08:00
|
|
|
VecBOInst->copyIRFlags(&I);
|
2020-02-22 04:43:05 +08:00
|
|
|
|
|
|
|
Value *Extract = Builder.CreateExtractElement(VecBO, Ext0->getOperand(1));
|
2020-02-22 03:25:39 +08:00
|
|
|
I.replaceAllUsesWith(Extract);
|
[VectorCombine] try to form vector binop to eliminate an extract element
binop (extelt X, C), (extelt Y, C) --> extelt (binop X, Y), C
This is a transform that has been considered for canonicalization (instcombine)
in the past because it reduces instruction count. But as shown in the x86 tests,
it's impossible to know if it's profitable without a cost model. There are many
potential target constraints to consider.
We have implemented similar transforms in the backend (DAGCombiner and
target-specific), but I don't think we have this exact fold there either (and if
we did it in SDAG, it wouldn't work across blocks).
Note: this patch was intended to handle the more general case where the extract
indexes do not match, but it got too big, so I scaled it back to this pattern
for now.
Differential Revision: https://reviews.llvm.org/D74495
2020-02-14 05:08:15 +08:00
|
|
|
}
|
|
|
|
|
2020-02-22 00:49:11 +08:00
|
|
|
/// Match an instruction with extracted vector operands.
|
|
|
|
static bool foldExtractExtract(Instruction &I, const TargetTransformInfo &TTI) {
|
2020-02-22 04:43:05 +08:00
|
|
|
// It is not safe to transform things like div, urem, etc. because we may
|
|
|
|
// create undefined behavior when executing those on unknown vector elements.
|
|
|
|
if (!isSafeToSpeculativelyExecute(&I))
|
|
|
|
return false;
|
|
|
|
|
2020-02-22 00:49:11 +08:00
|
|
|
Instruction *Ext0, *Ext1;
|
|
|
|
CmpInst::Predicate Pred = CmpInst::BAD_ICMP_PREDICATE;
|
|
|
|
if (!match(&I, m_Cmp(Pred, m_Instruction(Ext0), m_Instruction(Ext1))) &&
|
|
|
|
!match(&I, m_BinOp(m_Instruction(Ext0), m_Instruction(Ext1))))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Value *V0, *V1;
|
|
|
|
uint64_t C0, C1;
|
2020-05-23 22:13:50 +08:00
|
|
|
if (!match(Ext0, m_ExtractElt(m_Value(V0), m_ConstantInt(C0))) ||
|
|
|
|
!match(Ext1, m_ExtractElt(m_Value(V1), m_ConstantInt(C1))) ||
|
2020-02-22 00:49:11 +08:00
|
|
|
V0->getType() != V1->getType())
|
|
|
|
return false;
|
|
|
|
|
[VectorCombine] try to form a better extractelement
Extracting to the same index that we are going to insert back into
allows forming select ("blend") shuffles and enables further transforms.
Admittedly, this is a quick-fix for a more general problem that I'm
hoping to solve by adding transforms for patterns that start with an
insertelement.
But this might resolve some regressions known to be caused by the
extract-extract transform (although I have not gotten more details on
those yet).
In the motivating case from PR34724:
https://bugs.llvm.org/show_bug.cgi?id=34724
The combination of subsequent instcombine and codegen transforms gets us this improvement:
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm4
vmovshdup %xmm1, %xmm3 ## xmm3 = xmm1[1,1,3,3]
vaddps %xmm0, %xmm2, %xmm0
vaddps %xmm1, %xmm3, %xmm1
vshufps $200, %xmm4, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm4[0,3]
vinsertps $177, %xmm1, %xmm0, %xmm0 ## xmm0 = zero,xmm0[1,2],xmm1[2]
-->
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm1
vaddps %xmm0, %xmm2, %xmm0
vshufps $200, %xmm1, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm1[0,3]
Differential Revision: https://reviews.llvm.org/D76623
2020-04-04 01:53:54 +08:00
|
|
|
// If the scalar value 'I' is going to be re-inserted into a vector, then try
|
|
|
|
// to create an extract to that same element. The extract/insert can be
|
|
|
|
// reduced to a "select shuffle".
|
|
|
|
// TODO: If we add a larger pattern match that starts from an insert, this
|
|
|
|
// probably becomes unnecessary.
|
|
|
|
uint64_t InsertIndex = std::numeric_limits<uint64_t>::max();
|
|
|
|
if (I.hasOneUse())
|
2020-05-23 22:13:50 +08:00
|
|
|
match(I.user_back(),
|
|
|
|
m_InsertElt(m_Value(), m_Value(), m_ConstantInt(InsertIndex)));
|
[VectorCombine] try to form a better extractelement
Extracting to the same index that we are going to insert back into
allows forming select ("blend") shuffles and enables further transforms.
Admittedly, this is a quick-fix for a more general problem that I'm
hoping to solve by adding transforms for patterns that start with an
insertelement.
But this might resolve some regressions known to be caused by the
extract-extract transform (although I have not gotten more details on
those yet).
In the motivating case from PR34724:
https://bugs.llvm.org/show_bug.cgi?id=34724
The combination of subsequent instcombine and codegen transforms gets us this improvement:
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm4
vmovshdup %xmm1, %xmm3 ## xmm3 = xmm1[1,1,3,3]
vaddps %xmm0, %xmm2, %xmm0
vaddps %xmm1, %xmm3, %xmm1
vshufps $200, %xmm4, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm4[0,3]
vinsertps $177, %xmm1, %xmm0, %xmm0 ## xmm0 = zero,xmm0[1,2],xmm1[2]
-->
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm1
vaddps %xmm0, %xmm2, %xmm0
vshufps $200, %xmm1, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm1[0,3]
Differential Revision: https://reviews.llvm.org/D76623
2020-04-04 01:53:54 +08:00
|
|
|
|
2020-03-08 21:57:55 +08:00
|
|
|
Instruction *ConvertToShuffle;
|
[VectorCombine] try to form a better extractelement
Extracting to the same index that we are going to insert back into
allows forming select ("blend") shuffles and enables further transforms.
Admittedly, this is a quick-fix for a more general problem that I'm
hoping to solve by adding transforms for patterns that start with an
insertelement.
But this might resolve some regressions known to be caused by the
extract-extract transform (although I have not gotten more details on
those yet).
In the motivating case from PR34724:
https://bugs.llvm.org/show_bug.cgi?id=34724
The combination of subsequent instcombine and codegen transforms gets us this improvement:
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm4
vmovshdup %xmm1, %xmm3 ## xmm3 = xmm1[1,1,3,3]
vaddps %xmm0, %xmm2, %xmm0
vaddps %xmm1, %xmm3, %xmm1
vshufps $200, %xmm4, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm4[0,3]
vinsertps $177, %xmm1, %xmm0, %xmm0 ## xmm0 = zero,xmm0[1,2],xmm1[2]
-->
vmovshdup %xmm0, %xmm2 ## xmm2 = xmm0[1,1,3,3]
vhaddps %xmm1, %xmm1, %xmm1
vaddps %xmm0, %xmm2, %xmm0
vshufps $200, %xmm1, %xmm0, %xmm0 ## xmm0 = xmm0[0,2],xmm1[0,3]
Differential Revision: https://reviews.llvm.org/D76623
2020-04-04 01:53:54 +08:00
|
|
|
if (isExtractExtractCheap(Ext0, Ext1, I.getOpcode(), TTI, ConvertToShuffle,
|
|
|
|
InsertIndex))
|
2020-02-22 04:43:05 +08:00
|
|
|
return false;
|
2020-02-22 00:49:11 +08:00
|
|
|
|
2020-03-08 21:57:55 +08:00
|
|
|
if (ConvertToShuffle) {
|
|
|
|
// The shuffle mask is undefined except for 1 lane that is being translated
|
|
|
|
// to the cheap extraction lane. Example:
|
|
|
|
// ShufMask = { 2, undef, undef, undef }
|
|
|
|
uint64_t SplatIndex = ConvertToShuffle == Ext0 ? C0 : C1;
|
|
|
|
uint64_t CheapExtIndex = ConvertToShuffle == Ext0 ? C1 : C0;
|
2020-04-14 01:51:25 +08:00
|
|
|
auto *VecTy = cast<VectorType>(V0->getType());
|
2020-04-15 18:41:54 +08:00
|
|
|
SmallVector<int, 32> ShufMask(VecTy->getNumElements(), -1);
|
|
|
|
ShufMask[CheapExtIndex] = SplatIndex;
|
2020-03-08 21:57:55 +08:00
|
|
|
IRBuilder<> Builder(ConvertToShuffle);
|
|
|
|
|
|
|
|
// extelt X, C --> extelt (splat X), C'
|
|
|
|
Value *Shuf = Builder.CreateShuffleVector(ConvertToShuffle->getOperand(0),
|
2020-04-15 18:41:54 +08:00
|
|
|
UndefValue::get(VecTy), ShufMask);
|
2020-03-08 21:57:55 +08:00
|
|
|
Value *NewExt = Builder.CreateExtractElement(Shuf, CheapExtIndex);
|
|
|
|
if (ConvertToShuffle == Ext0)
|
|
|
|
Ext0 = cast<Instruction>(NewExt);
|
|
|
|
else
|
|
|
|
Ext1 = cast<Instruction>(NewExt);
|
|
|
|
}
|
2020-02-22 04:43:05 +08:00
|
|
|
|
|
|
|
if (Pred != CmpInst::BAD_ICMP_PREDICATE)
|
2020-06-12 04:50:03 +08:00
|
|
|
foldExtExtCmp(Ext0, Ext1, I);
|
2020-02-22 04:43:05 +08:00
|
|
|
else
|
2020-06-12 04:50:03 +08:00
|
|
|
foldExtExtBinop(Ext0, Ext1, I);
|
2020-02-22 00:49:11 +08:00
|
|
|
|
2020-02-22 04:43:05 +08:00
|
|
|
return true;
|
2020-02-22 00:49:11 +08:00
|
|
|
}
|
|
|
|
|
2020-04-19 20:06:17 +08:00
|
|
|
/// If this is a bitcast of a shuffle, try to bitcast the source vector to the
|
|
|
|
/// destination type followed by shuffle. This can enable further transforms by
|
|
|
|
/// moving bitcasts or shuffles together.
|
2020-04-03 01:21:29 +08:00
|
|
|
static bool foldBitcastShuf(Instruction &I, const TargetTransformInfo &TTI) {
|
|
|
|
Value *V;
|
|
|
|
ArrayRef<int> Mask;
|
2020-05-23 22:13:50 +08:00
|
|
|
if (!match(&I, m_BitCast(
|
|
|
|
m_OneUse(m_Shuffle(m_Value(V), m_Undef(), m_Mask(Mask))))))
|
2020-04-03 01:21:29 +08:00
|
|
|
return false;
|
|
|
|
|
2020-04-19 20:06:17 +08:00
|
|
|
// Disallow non-vector casts and length-changing shuffles.
|
|
|
|
// TODO: We could allow any shuffle.
|
2020-04-14 01:51:25 +08:00
|
|
|
auto *DestTy = dyn_cast<VectorType>(I.getType());
|
|
|
|
auto *SrcTy = cast<VectorType>(V->getType());
|
|
|
|
if (!DestTy || I.getOperand(0)->getType() != SrcTy)
|
2020-04-03 01:21:29 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// The new shuffle must not cost more than the old shuffle. The bitcast is
|
|
|
|
// moved ahead of the shuffle, so assume that it has the same cost as before.
|
|
|
|
if (TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, DestTy) >
|
|
|
|
TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, SrcTy))
|
|
|
|
return false;
|
|
|
|
|
2020-04-19 20:06:17 +08:00
|
|
|
unsigned DestNumElts = DestTy->getNumElements();
|
|
|
|
unsigned SrcNumElts = SrcTy->getNumElements();
|
|
|
|
SmallVector<int, 16> NewMask;
|
|
|
|
if (SrcNumElts <= DestNumElts) {
|
|
|
|
// The bitcast is from wide to narrow/equal elements. The shuffle mask can
|
|
|
|
// always be expanded to the equivalent form choosing narrower elements.
|
|
|
|
assert(DestNumElts % SrcNumElts == 0 && "Unexpected shuffle mask");
|
|
|
|
unsigned ScaleFactor = DestNumElts / SrcNumElts;
|
|
|
|
narrowShuffleMaskElts(ScaleFactor, Mask, NewMask);
|
|
|
|
} else {
|
|
|
|
// The bitcast is from narrow elements to wide elements. The shuffle mask
|
|
|
|
// must choose consecutive elements to allow casting first.
|
|
|
|
assert(SrcNumElts % DestNumElts == 0 && "Unexpected shuffle mask");
|
|
|
|
unsigned ScaleFactor = SrcNumElts / DestNumElts;
|
|
|
|
if (!widenShuffleMaskElts(ScaleFactor, Mask, NewMask))
|
|
|
|
return false;
|
|
|
|
}
|
2020-04-03 01:21:29 +08:00
|
|
|
// bitcast (shuf V, MaskC) --> shuf (bitcast V), MaskC'
|
2020-06-13 01:49:38 +08:00
|
|
|
++NumShufOfBitcast;
|
2020-04-03 01:21:29 +08:00
|
|
|
IRBuilder<> Builder(&I);
|
|
|
|
Value *CastV = Builder.CreateBitCast(V, DestTy);
|
2020-05-23 22:13:50 +08:00
|
|
|
Value *Shuf =
|
|
|
|
Builder.CreateShuffleVector(CastV, UndefValue::get(DestTy), NewMask);
|
2020-04-03 01:21:29 +08:00
|
|
|
I.replaceAllUsesWith(Shuf);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-06-17 01:30:40 +08:00
|
|
|
/// Match a vector binop or compare instruction with at least one inserted
|
|
|
|
/// scalar operand and convert to scalar binop/cmp followed by insertelement.
|
|
|
|
static bool scalarizeBinopOrCmp(Instruction &I,
|
|
|
|
const TargetTransformInfo &TTI) {
|
|
|
|
CmpInst::Predicate Pred = CmpInst::BAD_ICMP_PREDICATE;
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
Value *Ins0, *Ins1;
|
2020-06-17 01:30:40 +08:00
|
|
|
if (!match(&I, m_BinOp(m_Value(Ins0), m_Value(Ins1))) &&
|
|
|
|
!match(&I, m_Cmp(Pred, m_Value(Ins0), m_Value(Ins1))))
|
2020-05-09 04:29:07 +08:00
|
|
|
return false;
|
|
|
|
|
2020-06-17 01:30:40 +08:00
|
|
|
// Do not convert the vector condition of a vector select into a scalar
|
|
|
|
// condition. That may cause problems for codegen because of differences in
|
|
|
|
// boolean formats and register-file transfers.
|
|
|
|
// TODO: Can we account for that in the cost model?
|
|
|
|
bool IsCmp = Pred != CmpInst::Predicate::BAD_ICMP_PREDICATE;
|
|
|
|
if (IsCmp)
|
|
|
|
for (User *U : I.users())
|
|
|
|
if (match(U, m_Select(m_Specific(&I), m_Value(), m_Value())))
|
|
|
|
return false;
|
|
|
|
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
// Match against one or both scalar values being inserted into constant
|
|
|
|
// vectors:
|
2020-06-17 01:30:40 +08:00
|
|
|
// vec_op VecC0, (inselt VecC1, V1, Index)
|
|
|
|
// vec_op (inselt VecC0, V0, Index), VecC1
|
|
|
|
// vec_op (inselt VecC0, V0, Index), (inselt VecC1, V1, Index)
|
2020-05-09 04:29:07 +08:00
|
|
|
// TODO: Deal with mismatched index constants and variable indexes?
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
Constant *VecC0 = nullptr, *VecC1 = nullptr;
|
|
|
|
Value *V0 = nullptr, *V1 = nullptr;
|
|
|
|
uint64_t Index0 = 0, Index1 = 0;
|
2020-05-23 22:13:50 +08:00
|
|
|
if (!match(Ins0, m_InsertElt(m_Constant(VecC0), m_Value(V0),
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
m_ConstantInt(Index0))) &&
|
|
|
|
!match(Ins0, m_Constant(VecC0)))
|
|
|
|
return false;
|
|
|
|
if (!match(Ins1, m_InsertElt(m_Constant(VecC1), m_Value(V1),
|
|
|
|
m_ConstantInt(Index1))) &&
|
|
|
|
!match(Ins1, m_Constant(VecC1)))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
bool IsConst0 = !V0;
|
|
|
|
bool IsConst1 = !V1;
|
|
|
|
if (IsConst0 && IsConst1)
|
|
|
|
return false;
|
|
|
|
if (!IsConst0 && !IsConst1 && Index0 != Index1)
|
2020-05-09 04:29:07 +08:00
|
|
|
return false;
|
|
|
|
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
// Bail for single insertion if it is a load.
|
|
|
|
// TODO: Handle this once getVectorInstrCost can cost for load/stores.
|
|
|
|
auto *I0 = dyn_cast_or_null<Instruction>(V0);
|
|
|
|
auto *I1 = dyn_cast_or_null<Instruction>(V1);
|
|
|
|
if ((IsConst0 && I1 && I1->mayReadFromMemory()) ||
|
|
|
|
(IsConst1 && I0 && I0->mayReadFromMemory()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
uint64_t Index = IsConst0 ? Index1 : Index0;
|
|
|
|
Type *ScalarTy = IsConst0 ? V1->getType() : V0->getType();
|
2020-05-09 04:29:07 +08:00
|
|
|
Type *VecTy = I.getType();
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
assert(VecTy->isVectorTy() &&
|
|
|
|
(IsConst0 || IsConst1 || V0->getType() == V1->getType()) &&
|
2020-05-09 04:29:07 +08:00
|
|
|
(ScalarTy->isIntegerTy() || ScalarTy->isFloatingPointTy()) &&
|
|
|
|
"Unexpected types for insert into binop");
|
|
|
|
|
2020-06-17 01:30:40 +08:00
|
|
|
unsigned Opcode = I.getOpcode();
|
|
|
|
int ScalarOpCost, VectorOpCost;
|
|
|
|
if (IsCmp) {
|
|
|
|
ScalarOpCost = TTI.getCmpSelInstrCost(Opcode, ScalarTy);
|
|
|
|
VectorOpCost = TTI.getCmpSelInstrCost(Opcode, VecTy);
|
|
|
|
} else {
|
|
|
|
ScalarOpCost = TTI.getArithmeticInstrCost(Opcode, ScalarTy);
|
|
|
|
VectorOpCost = TTI.getArithmeticInstrCost(Opcode, VecTy);
|
|
|
|
}
|
2020-05-09 04:29:07 +08:00
|
|
|
|
|
|
|
// Get cost estimate for the insert element. This cost will factor into
|
|
|
|
// both sequences.
|
|
|
|
int InsertCost =
|
|
|
|
TTI.getVectorInstrCost(Instruction::InsertElement, VecTy, Index);
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
int OldCost = (IsConst0 ? 0 : InsertCost) + (IsConst1 ? 0 : InsertCost) +
|
|
|
|
VectorOpCost;
|
2020-05-12 03:20:57 +08:00
|
|
|
int NewCost = ScalarOpCost + InsertCost +
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
(IsConst0 ? 0 : !Ins0->hasOneUse() * InsertCost) +
|
|
|
|
(IsConst1 ? 0 : !Ins1->hasOneUse() * InsertCost);
|
2020-05-09 04:29:07 +08:00
|
|
|
|
|
|
|
// We want to scalarize unless the vector variant actually has lower cost.
|
|
|
|
if (OldCost < NewCost)
|
|
|
|
return false;
|
|
|
|
|
2020-06-17 01:30:40 +08:00
|
|
|
// vec_op (inselt VecC0, V0, Index), (inselt VecC1, V1, Index) -->
|
|
|
|
// inselt NewVecC, (scalar_op V0, V1), Index
|
|
|
|
if (IsCmp)
|
|
|
|
++NumScalarCmp;
|
|
|
|
else
|
|
|
|
++NumScalarBO;
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
|
|
|
|
// For constant cases, extract the scalar element, this should constant fold.
|
2020-06-17 01:30:40 +08:00
|
|
|
IRBuilder<> Builder(&I);
|
[VectorCombine] scalarizeBinop - support an all-constant src vector operand
scalarizeBinop currently folds
vec_bo((inselt VecC0, V0, Index), (inselt VecC1, V1, Index))
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,V1), Index)
This patch extends this to account for cases where one of the vec_bo operands is already all-constant and performs similar cost checks to determine if the scalar binop with a constant still makes sense:
vec_bo((inselt VecC0, V0, Index), VecC1)
->
inselt(vec_bo(VecC0, VecC1), scl_bo(V0,extractelt(V1,Index)), Index)
Fixes PR42174
Differential Revision: https://reviews.llvm.org/D80885
2020-06-10 01:36:14 +08:00
|
|
|
if (IsConst0)
|
|
|
|
V0 = ConstantExpr::getExtractElement(VecC0, Builder.getInt64(Index));
|
|
|
|
if (IsConst1)
|
|
|
|
V1 = ConstantExpr::getExtractElement(VecC1, Builder.getInt64(Index));
|
|
|
|
|
2020-06-17 01:30:40 +08:00
|
|
|
Value *Scalar =
|
|
|
|
IsCmp ? Opcode == Instruction::FCmp ? Builder.CreateFCmp(Pred, V0, V1)
|
|
|
|
: Builder.CreateICmp(Pred, V0, V1)
|
|
|
|
: Builder.CreateBinOp((Instruction::BinaryOps)Opcode, V0, V1);
|
|
|
|
|
|
|
|
Scalar->setName(I.getName() + ".scalar");
|
2020-05-09 04:29:07 +08:00
|
|
|
|
|
|
|
// All IR flags are safe to back-propagate. There is no potential for extra
|
|
|
|
// poison to be created by the scalar instruction.
|
|
|
|
if (auto *ScalarInst = dyn_cast<Instruction>(Scalar))
|
|
|
|
ScalarInst->copyIRFlags(&I);
|
|
|
|
|
|
|
|
// Fold the vector constants in the original vectors into a new base vector.
|
2020-06-17 01:30:40 +08:00
|
|
|
Constant *NewVecC = IsCmp ? ConstantExpr::getCompare(Pred, VecC0, VecC1)
|
|
|
|
: ConstantExpr::get(Opcode, VecC0, VecC1);
|
2020-05-09 04:29:07 +08:00
|
|
|
Value *Insert = Builder.CreateInsertElement(NewVecC, Scalar, Index);
|
|
|
|
I.replaceAllUsesWith(Insert);
|
|
|
|
Insert->takeName(&I);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
/// This is the entry point for all transforms. Pass manager differences are
|
|
|
|
/// handled in the callers of this function.
|
|
|
|
static bool runImpl(Function &F, const TargetTransformInfo &TTI,
|
|
|
|
const DominatorTree &DT) {
|
2020-02-27 04:14:35 +08:00
|
|
|
if (DisableVectorCombine)
|
|
|
|
return false;
|
|
|
|
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
bool MadeChange = false;
|
|
|
|
for (BasicBlock &BB : F) {
|
|
|
|
// Ignore unreachable basic blocks.
|
|
|
|
if (!DT.isReachableFromEntry(&BB))
|
|
|
|
continue;
|
|
|
|
// Do not delete instructions under here and invalidate the iterator.
|
2020-05-17 01:08:01 +08:00
|
|
|
// Walk the block forwards to enable simple iterative chains of transforms.
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
// TODO: It could be more efficient to remove dead instructions
|
|
|
|
// iteratively in this loop rather than waiting until the end.
|
2020-05-17 01:08:01 +08:00
|
|
|
for (Instruction &I : BB) {
|
2020-03-30 01:58:04 +08:00
|
|
|
if (isa<DbgInfoIntrinsic>(I))
|
|
|
|
continue;
|
2020-02-22 00:49:11 +08:00
|
|
|
MadeChange |= foldExtractExtract(I, TTI);
|
2020-04-03 01:21:29 +08:00
|
|
|
MadeChange |= foldBitcastShuf(I, TTI);
|
2020-06-17 01:30:40 +08:00
|
|
|
MadeChange |= scalarizeBinopOrCmp(I, TTI);
|
2020-03-30 01:58:04 +08:00
|
|
|
}
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// We're done with transforms, so remove dead instructions.
|
|
|
|
if (MadeChange)
|
|
|
|
for (BasicBlock &BB : F)
|
|
|
|
SimplifyInstructionsInBlock(&BB);
|
|
|
|
|
|
|
|
return MadeChange;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pass manager boilerplate below here.
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
class VectorCombineLegacyPass : public FunctionPass {
|
|
|
|
public:
|
|
|
|
static char ID;
|
|
|
|
VectorCombineLegacyPass() : FunctionPass(ID) {
|
|
|
|
initializeVectorCombineLegacyPassPass(*PassRegistry::getPassRegistry());
|
|
|
|
}
|
|
|
|
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
|
|
AU.addRequired<DominatorTreeWrapperPass>();
|
|
|
|
AU.addRequired<TargetTransformInfoWrapperPass>();
|
|
|
|
AU.setPreservesCFG();
|
|
|
|
AU.addPreserved<DominatorTreeWrapperPass>();
|
|
|
|
AU.addPreserved<GlobalsAAWrapperPass>();
|
2020-05-23 04:22:27 +08:00
|
|
|
AU.addPreserved<AAResultsWrapperPass>();
|
|
|
|
AU.addPreserved<BasicAAWrapperPass>();
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
FunctionPass::getAnalysisUsage(AU);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool runOnFunction(Function &F) override {
|
|
|
|
if (skipFunction(F))
|
|
|
|
return false;
|
|
|
|
auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
|
|
|
|
auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
|
|
|
|
return runImpl(F, TTI, DT);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
char VectorCombineLegacyPass::ID = 0;
|
|
|
|
INITIALIZE_PASS_BEGIN(VectorCombineLegacyPass, "vector-combine",
|
|
|
|
"Optimize scalar/vector ops", false,
|
|
|
|
false)
|
|
|
|
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
|
|
|
|
INITIALIZE_PASS_END(VectorCombineLegacyPass, "vector-combine",
|
|
|
|
"Optimize scalar/vector ops", false, false)
|
|
|
|
Pass *llvm::createVectorCombinePass() {
|
|
|
|
return new VectorCombineLegacyPass();
|
|
|
|
}
|
|
|
|
|
|
|
|
PreservedAnalyses VectorCombinePass::run(Function &F,
|
|
|
|
FunctionAnalysisManager &FAM) {
|
|
|
|
TargetTransformInfo &TTI = FAM.getResult<TargetIRAnalysis>(F);
|
|
|
|
DominatorTree &DT = FAM.getResult<DominatorTreeAnalysis>(F);
|
|
|
|
if (!runImpl(F, TTI, DT))
|
|
|
|
return PreservedAnalyses::all();
|
|
|
|
PreservedAnalyses PA;
|
|
|
|
PA.preserveSet<CFGAnalyses>();
|
|
|
|
PA.preserve<GlobalsAA>();
|
2020-05-23 04:22:27 +08:00
|
|
|
PA.preserve<AAManager>();
|
|
|
|
PA.preserve<BasicAA>();
|
[VectorCombine] new IR transform pass for partial vector ops
We have several bug reports that could be characterized as "reducing scalarization",
and this topic was also raised on llvm-dev recently:
http://lists.llvm.org/pipermail/llvm-dev/2020-January/138157.html
...so I'm proposing that we deal with these patterns in a new, lightweight IR vector
pass that runs before/after other vectorization passes.
There are 4 alternate options that I can think of to deal with this kind of problem
(and we've seen various attempts at all of these), but they all have flaws:
InstCombine - can't happen without TTI, but we don't want target-specific
folds there.
SDAG - too late to assist other vectorization passes; TLI is not equipped
for these kind of cost queries; limited to a single basic block.
CGP - too late to assist other vectorization passes; would need to re-implement
basic cleanups like CSE/instcombine.
SLP - doesn't fit with existing transforms; limited to a single basic block.
This initial patch/transform is based on existing code in AggressiveInstCombine:
we walk backwards through the function looking for a pattern match. But we diverge
from that cost-independent IR canonicalization pass by using TTI to decide if the
vector alternative is profitable.
We probably have at least 10 similar bug reports/patterns (binops, constants,
inserts, cheap shuffles, etc) that would fit in this pass as follow-up enhancements.
It's possible that we could iterate on a worklist to fix-point like InstCombine does,
but it's safer to start with a most basic case and evolve from there, so I didn't
try to do anything fancy with this initial implementation.
Differential Revision: https://reviews.llvm.org/D73480
2020-02-09 23:04:41 +08:00
|
|
|
return PA;
|
|
|
|
}
|