mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 11:02:59 +02:00
[InstCombine] canonicalize a scalar-select-of-vectors to vector select
This pattern may arise more frequently with an enhancement to SLP vectorization suggested in PR42755: https://bugs.llvm.org/show_bug.cgi?id=42755 ...but we should handle this pattern to make things easier for the backend either way. For all in-tree targets that I looked at, codegen for typical vector sizes looks better when we change to a vector select, so this is safe to do without a cost model (in other words, as a target-independent canonicalization). For example, if the condition of the select is a scalar, we end up with something like this on x86: vpcmpgtd %xmm0, %xmm1, %xmm0 vpextrb $12, %xmm0, %eax testb $1, %al jne LBB0_2 ## %bb.1: vmovaps %xmm3, %xmm2 LBB0_2: vmovaps %xmm2, %xmm0 Rather than the splat-condition variant: vpcmpgtd %xmm0, %xmm1, %xmm0 vpshufd $255, %xmm0, %xmm0 ## xmm0 = xmm0[3,3,3,3] vblendvps %xmm0, %xmm2, %xmm3, %xmm0 Differential Revision: https://reviews.llvm.org/D66095 llvm-svn: 369140
This commit is contained in:
parent
2728670419
commit
a657e27486
@ -1696,6 +1696,30 @@ static Instruction *canonicalizeSelectToShuffle(SelectInst &SI) {
|
||||
ConstantVector::get(Mask));
|
||||
}
|
||||
|
||||
/// If we have a select of vectors with a scalar condition, try to convert that
|
||||
/// to a vector select by splatting the condition. A splat may get folded with
|
||||
/// other operations in IR and having all operands of a select be vector types
|
||||
/// is likely better for vector codegen.
|
||||
static Instruction *canonicalizeScalarSelectOfVecs(
|
||||
SelectInst &Sel, InstCombiner::BuilderTy &Builder) {
|
||||
Type *Ty = Sel.getType();
|
||||
if (!Ty->isVectorTy())
|
||||
return nullptr;
|
||||
|
||||
// We can replace a single-use extract with constant index.
|
||||
Value *Cond = Sel.getCondition();
|
||||
if (!match(Cond, m_OneUse(m_ExtractElement(m_Value(), m_ConstantInt()))))
|
||||
return nullptr;
|
||||
|
||||
// select (extelt V, Index), T, F --> select (splat V, Index), T, F
|
||||
// Splatting the extracted condition reduces code (we could directly create a
|
||||
// splat shuffle of the source vector to eliminate the intermediate step).
|
||||
unsigned NumElts = Ty->getVectorNumElements();
|
||||
Value *SplatCond = Builder.CreateVectorSplat(NumElts, Cond);
|
||||
Sel.setCondition(SplatCond);
|
||||
return &Sel;
|
||||
}
|
||||
|
||||
/// Reuse bitcasted operands between a compare and select:
|
||||
/// select (cmp (bitcast C), (bitcast D)), (bitcast' C), (bitcast' D) -->
|
||||
/// bitcast (select (cmp (bitcast C), (bitcast D)), (bitcast C), (bitcast D))
|
||||
@ -1992,6 +2016,9 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
|
||||
if (Instruction *I = canonicalizeSelectToShuffle(SI))
|
||||
return I;
|
||||
|
||||
if (Instruction *I = canonicalizeScalarSelectOfVecs(SI, Builder))
|
||||
return I;
|
||||
|
||||
// Canonicalize a one-use integer compare with a non-canonical predicate by
|
||||
// inverting the predicate and swapping the select operands. This matches a
|
||||
// compare canonicalization for conditional branches.
|
||||
|
@ -146,8 +146,8 @@ entry:
|
||||
|
||||
define <4 x i32> @extract_cond(<4 x i32> %x, <4 x i32> %y, <4 x i1> %condv) {
|
||||
; CHECK-LABEL: @extract_cond(
|
||||
; CHECK-NEXT: [[COND:%.*]] = extractelement <4 x i1> [[CONDV:%.*]], i32 3
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <4 x i1> [[CONDV:%.*]], <4 x i1> undef, <4 x i32> <i32 3, i32 3, i32 3, i32 3>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[DOTSPLAT]], <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <4 x i32> [[R]]
|
||||
;
|
||||
%cond = extractelement <4 x i1> %condv, i32 3
|
||||
@ -168,6 +168,8 @@ define <4 x i32> @splat_cond(<4 x i32> %x, <4 x i32> %y, <4 x i1> %condv) {
|
||||
|
||||
declare void @extra_use(i1)
|
||||
|
||||
; Negative test
|
||||
|
||||
define <4 x i32> @extract_cond_extra_use(<4 x i32> %x, <4 x i32> %y, <4 x i1> %condv) {
|
||||
; CHECK-LABEL: @extract_cond_extra_use(
|
||||
; CHECK-NEXT: [[COND:%.*]] = extractelement <4 x i1> [[CONDV:%.*]], i32 3
|
||||
@ -181,6 +183,8 @@ define <4 x i32> @extract_cond_extra_use(<4 x i32> %x, <4 x i32> %y, <4 x i1> %c
|
||||
ret <4 x i32> %r
|
||||
}
|
||||
|
||||
; Negative test
|
||||
|
||||
define <4 x i32> @extract_cond_variable_index(<4 x i32> %x, <4 x i32> %y, <4 x i1> %condv, i32 %index) {
|
||||
; CHECK-LABEL: @extract_cond_variable_index(
|
||||
; CHECK-NEXT: [[COND:%.*]] = extractelement <4 x i1> [[CONDV:%.*]], i32 [[INDEX:%.*]]
|
||||
@ -192,10 +196,12 @@ define <4 x i32> @extract_cond_variable_index(<4 x i32> %x, <4 x i32> %y, <4 x i
|
||||
ret <4 x i32> %r
|
||||
}
|
||||
|
||||
; IR shuffle can alter the number of elements in the vector, so this is ok.
|
||||
|
||||
define <4 x i32> @extract_cond_type_mismatch(<4 x i32> %x, <4 x i32> %y, <5 x i1> %condv) {
|
||||
; CHECK-LABEL: @extract_cond_type_mismatch(
|
||||
; CHECK-NEXT: [[COND:%.*]] = extractelement <5 x i1> [[CONDV:%.*]], i32 1
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[COND]], <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: [[DOTSPLAT:%.*]] = shufflevector <5 x i1> [[CONDV:%.*]], <5 x i1> undef, <4 x i32> <i32 1, i32 1, i32 1, i32 1>
|
||||
; CHECK-NEXT: [[R:%.*]] = select <4 x i1> [[DOTSPLAT]], <4 x i32> [[X:%.*]], <4 x i32> [[Y:%.*]]
|
||||
; CHECK-NEXT: ret <4 x i32> [[R]]
|
||||
;
|
||||
%cond = extractelement <5 x i1> %condv, i32 1
|
||||
|
Loading…
Reference in New Issue
Block a user