Skip to content

Commit d6c00c0

Browse files
author
Leon Clark
committed
Move transform to VectorCombine and update tests.
1 parent 157074c commit d6c00c0

File tree

6 files changed

+116
-112
lines changed

6 files changed

+116
-112
lines changed

llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp

Lines changed: 0 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -916,94 +916,6 @@ static bool foldPatternedLoads(Instruction &I, const DataLayout &DL) {
916916
return true;
917917
}
918918

919-
// If `I` is a load instruction, used only by shufflevector instructions with
920-
// poison values, attempt to shrink the load to only the lanes being used.
921-
static bool shrinkLoadsForBroadcast(Instruction &I) {
922-
auto *OldLoad = dyn_cast<LoadInst>(&I);
923-
if (!OldLoad || !OldLoad->isSimple())
924-
return false;
925-
926-
auto *VecTy = dyn_cast<FixedVectorType>(I.getType());
927-
if (!VecTy)
928-
return false;
929-
930-
auto IsPoisonOrUndef = [](Value *V) -> bool {
931-
if (auto *C = dyn_cast<Constant>(V)) {
932-
return isa<PoisonValue>(C) || isa<UndefValue>(C);
933-
}
934-
return false;
935-
};
936-
937-
using IndexRange = std::pair<unsigned, unsigned>;
938-
auto GetIndexRangeInShuffles = [&]() -> std::optional<IndexRange> {
939-
auto OutputRange = IndexRange(VecTy->getNumElements(), 0u);
940-
for (auto &Use : I.uses()) {
941-
// All uses must be ShuffleVector instructions.
942-
auto *Shuffle = dyn_cast<ShuffleVectorInst>(Use.getUser());
943-
if (!Shuffle)
944-
return {};
945-
946-
// Get index range for value.
947-
auto *Op0 = Shuffle->getOperand(0u);
948-
auto *Op1 = Shuffle->getOperand(1u);
949-
if (!IsPoisonOrUndef(Op1))
950-
return {};
951-
952-
// Find the min and max indices used by the ShuffleVector instruction.
953-
auto Mask = Shuffle->getShuffleMask();
954-
auto *Op0Ty = cast<FixedVectorType>(Op0->getType());
955-
auto NumElems = Op0Ty->getNumElements();
956-
957-
for (unsigned Index : Mask) {
958-
if (Index < NumElems) {
959-
OutputRange.first = std::min(Index, OutputRange.first);
960-
OutputRange.second = std::max(Index, OutputRange.second);
961-
}
962-
}
963-
}
964-
return OutputRange;
965-
};
966-
967-
if (auto Indices = GetIndexRangeInShuffles()) {
968-
auto OldSize = VecTy->getNumElements();
969-
auto NewSize = Indices->second + 1u;
970-
971-
if (NewSize < OldSize) {
972-
auto Builder = IRBuilder(&I);
973-
Builder.SetCurrentDebugLocation(I.getDebugLoc());
974-
975-
// Create new load of smaller vector.
976-
auto *ElemTy = VecTy->getElementType();
977-
auto *NewVecTy = FixedVectorType::get(ElemTy, NewSize);
978-
auto *NewLoad = cast<LoadInst>(
979-
Builder.CreateLoad(NewVecTy, OldLoad->getPointerOperand()));
980-
NewLoad->copyMetadata(I);
981-
982-
// Replace all users.
983-
auto OldShuffles = SmallVector<ShuffleVectorInst *, 4u>{};
984-
for (auto &Use : I.uses()) {
985-
auto *Shuffle = cast<ShuffleVectorInst>(Use.getUser());
986-
987-
Builder.SetInsertPoint(Shuffle);
988-
Builder.SetCurrentDebugLocation(Shuffle->getDebugLoc());
989-
auto *NewShuffle = Builder.CreateShuffleVector(
990-
NewLoad, PoisonValue::get(NewVecTy), Shuffle->getShuffleMask());
991-
992-
Shuffle->replaceAllUsesWith(NewShuffle);
993-
OldShuffles.push_back(Shuffle);
994-
}
995-
996-
// Erase old users.
997-
for (auto *Shuffle : OldShuffles)
998-
Shuffle->eraseFromParent();
999-
1000-
I.eraseFromParent();
1001-
return true;
1002-
}
1003-
}
1004-
return false;
1005-
}
1006-
1007919
namespace {
1008920
class StrNCmpInliner {
1009921
public:
@@ -1341,7 +1253,6 @@ static bool foldUnusualPatterns(Function &F, DominatorTree &DT,
13411253
MadeChange |= tryToRecognizeTableBasedCttz(I);
13421254
MadeChange |= foldConsecutiveLoads(I, DL, TTI, AA, DT);
13431255
MadeChange |= foldPatternedLoads(I, DL);
1344-
MadeChange |= shrinkLoadsForBroadcast(I);
13451256
// NOTE: This function introduces erasing of the instruction `I`, so it
13461257
// needs to be called at the end of this sequence, otherwise we may make
13471258
// bugs.

llvm/lib/Transforms/Vectorize/VectorCombine.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ class VectorCombine {
131131
bool foldSelectShuffle(Instruction &I, bool FromReduction = false);
132132
bool foldInterleaveIntrinsics(Instruction &I);
133133
bool shrinkType(Instruction &I);
134+
bool shrinkLoadForShuffles(Instruction &I);
134135

135136
void replaceValue(Value &Old, Value &New) {
136137
LLVM_DEBUG(dbgs() << "VC: Replacing: " << Old << '\n');
@@ -3483,6 +3484,101 @@ bool VectorCombine::foldInterleaveIntrinsics(Instruction &I) {
34833484
return true;
34843485
}
34853486

3487+
// If `I` is a load instruction, used only by shufflevector instructions with
3488+
// poison values, attempt to shrink the load to only the lanes being used.
3489+
bool VectorCombine::shrinkLoadForShuffles(Instruction &I) {
3490+
auto *OldLoad = dyn_cast<LoadInst>(&I);
3491+
if (!OldLoad || !OldLoad->isSimple())
3492+
return false;
3493+
3494+
auto *VecTy = dyn_cast<FixedVectorType>(I.getType());
3495+
if (!VecTy)
3496+
return false;
3497+
3498+
auto IsPoisonOrUndef = [](Value *V) -> bool {
3499+
if (auto *C = dyn_cast<Constant>(V)) {
3500+
return isa<PoisonValue>(C) || isa<UndefValue>(C);
3501+
}
3502+
return false;
3503+
};
3504+
3505+
using IndexRange = std::pair<int, int>;
3506+
auto GetIndexRangeInShuffles = [&]() -> std::optional<IndexRange> {
3507+
auto OutputRange = IndexRange(VecTy->getNumElements(), -1);
3508+
for (auto &Use : I.uses()) {
3509+
// All uses must be ShuffleVector instructions.
3510+
auto *Shuffle = dyn_cast<ShuffleVectorInst>(Use.getUser());
3511+
if (!Shuffle)
3512+
return {};
3513+
3514+
// Get index range for value.
3515+
auto *Op0 = Shuffle->getOperand(0u);
3516+
auto *Op1 = Shuffle->getOperand(1u);
3517+
if (!IsPoisonOrUndef(Op1))
3518+
return {};
3519+
3520+
// Find the min and max indices used by the ShuffleVector instruction.
3521+
auto Mask = Shuffle->getShuffleMask();
3522+
auto *Op0Ty = cast<FixedVectorType>(Op0->getType());
3523+
auto NumElems = int(Op0Ty->getNumElements());
3524+
3525+
for (auto Index : Mask) {
3526+
if (Index >= 0 && Index < NumElems) {
3527+
OutputRange.first = std::min(Index, OutputRange.first);
3528+
OutputRange.second = std::max(Index, OutputRange.second);
3529+
}
3530+
}
3531+
3532+
if (OutputRange.second < OutputRange.first)
3533+
return {};
3534+
}
3535+
return OutputRange;
3536+
};
3537+
3538+
if (auto Indices = GetIndexRangeInShuffles()) {
3539+
auto OldSize = VecTy->getNumElements();
3540+
auto NewSize = Indices->second + 1u;
3541+
3542+
if (NewSize < OldSize) {
3543+
auto Builder = IRBuilder(&I);
3544+
Builder.SetCurrentDebugLocation(I.getDebugLoc());
3545+
3546+
// Create new load of smaller vector.
3547+
auto *ElemTy = VecTy->getElementType();
3548+
auto *NewVecTy = FixedVectorType::get(ElemTy, NewSize);
3549+
auto *NewLoad = cast<LoadInst>(
3550+
Builder.CreateLoad(NewVecTy, OldLoad->getPointerOperand()));
3551+
NewLoad->copyMetadata(I);
3552+
3553+
// Compare cost of old and new loads.
3554+
auto OldCost = TTI.getMemoryOpCost(
3555+
Instruction::Load, OldLoad->getType(), OldLoad->getAlign(),
3556+
OldLoad->getPointerAddressSpace(), CostKind);
3557+
auto NewCost = TTI.getMemoryOpCost(
3558+
Instruction::Load, NewLoad->getType(), NewLoad->getAlign(),
3559+
NewLoad->getPointerAddressSpace(), CostKind);
3560+
3561+
if (OldCost < NewCost || !NewCost.isValid())
3562+
return false;
3563+
3564+
// Replace all users.
3565+
for (auto &Use : I.uses()) {
3566+
auto *Shuffle = cast<ShuffleVectorInst>(Use.getUser());
3567+
3568+
Builder.SetInsertPoint(Shuffle);
3569+
Builder.SetCurrentDebugLocation(Shuffle->getDebugLoc());
3570+
auto *NewShuffle = Builder.CreateShuffleVector(
3571+
NewLoad, PoisonValue::get(NewVecTy), Shuffle->getShuffleMask());
3572+
3573+
replaceValue(*Shuffle, *NewShuffle);
3574+
}
3575+
3576+
return true;
3577+
}
3578+
}
3579+
return false;
3580+
}
3581+
34863582
/// This is the entry point for all transforms. Pass manager differences are
34873583
/// handled in the callers of this function.
34883584
bool VectorCombine::run() {
@@ -3561,6 +3657,9 @@ bool VectorCombine::run() {
35613657
case Instruction::BitCast:
35623658
MadeChange |= foldBitcastShuffle(I);
35633659
break;
3660+
case Instruction::Load:
3661+
MadeChange |= shrinkLoadForShuffles(I);
3662+
break;
35643663
default:
35653664
MadeChange |= shrinkType(I);
35663665
break;

llvm/test/Transforms/PhaseOrdering/X86/vec-load-combine.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ $getAt = comdat any
1111

1212
define dso_local noundef <4 x float> @ConvertVectors_ByRef(ptr noundef nonnull align 16 dereferenceable(16) %0) #0 {
1313
; SSE-LABEL: @ConvertVectors_ByRef(
14-
; SSE-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[TMP0:%.*]], align 16
15-
; SSE-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
14+
; SSE-NEXT: [[TMP2:%.*]] = load <3 x float>, ptr [[TMP0:%.*]], align 16
15+
; SSE-NEXT: [[TMP3:%.*]] = shufflevector <3 x float> [[TMP2]], <3 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
1616
; SSE-NEXT: ret <4 x float> [[TMP3]]
1717
;
1818
; AVX-LABEL: @ConvertVectors_ByRef(
19-
; AVX-NEXT: [[TMP2:%.*]] = load <4 x float>, ptr [[TMP0:%.*]], align 16
20-
; AVX-NEXT: [[TMP3:%.*]] = shufflevector <4 x float> [[TMP2]], <4 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
19+
; AVX-NEXT: [[TMP2:%.*]] = load <3 x float>, ptr [[TMP0:%.*]], align 16
20+
; AVX-NEXT: [[TMP3:%.*]] = shufflevector <3 x float> [[TMP2]], <3 x float> poison, <4 x i32> <i32 0, i32 1, i32 2, i32 2>
2121
; AVX-NEXT: ret <4 x float> [[TMP3]]
2222
;
2323
%2 = alloca ptr, align 8

llvm/test/Transforms/VectorCombine/X86/load-widening.ll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ define <8 x float> @load_v2f32_v8f32(ptr dereferenceable(32) %p) {
336336

337337
define <4 x i32> @load_v2i32_v4i32(ptr dereferenceable(16) %p) {
338338
; CHECK-LABEL: @load_v2i32_v4i32(
339-
; CHECK-NEXT: [[S:%.*]] = load <4 x i32>, ptr [[P:%.*]], align 1
339+
; CHECK-NEXT: [[S:%.*]] = load <4 x i32>, ptr [[P:%.*]], align 4
340340
; CHECK-NEXT: ret <4 x i32> [[S]]
341341
;
342342
%l = load <2 x i32>, ptr %p, align 1
@@ -443,8 +443,8 @@ define <8 x float> @load_v2f32_v8f32_hwasan(ptr dereferenceable(32) %p) sanitize
443443

444444
define <4 x i32> @load_v2i32_v4i32_asan(ptr dereferenceable(16) %p) sanitize_address {
445445
; CHECK-LABEL: @load_v2i32_v4i32_asan(
446-
; CHECK-NEXT: [[L:%.*]] = load <2 x i32>, ptr [[P:%.*]], align 1
447-
; CHECK-NEXT: [[S:%.*]] = shufflevector <2 x i32> [[L]], <2 x i32> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
446+
; CHECK-NEXT: [[TMP1:%.*]] = load <1 x i32>, ptr [[P:%.*]], align 4
447+
; CHECK-NEXT: [[S:%.*]] = shufflevector <1 x i32> [[TMP1]], <1 x i32> poison, <4 x i32> <i32 0, i32 poison, i32 poison, i32 poison>
448448
; CHECK-NEXT: ret <4 x i32> [[S]]
449449
;
450450
%l = load <2 x i32>, ptr %p, align 1

llvm/test/Transforms/VectorCombine/X86/shuffle-of-shuffles.ll

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,21 +47,12 @@ define <8 x i32> @concat_extract_subvectors_poison(<8 x i32> %x) {
4747
; broadcast loads are free on AVX (and blends are much cheap than general 2-operand shuffles)
4848

4949
define <4 x double> @blend_broadcasts_v4f64(ptr %p0, ptr %p1) {
50-
; SSE-LABEL: define <4 x double> @blend_broadcasts_v4f64(
51-
; SSE-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) #[[ATTR0]] {
52-
; SSE-NEXT: [[LD0:%.*]] = load <4 x double>, ptr [[P0]], align 32
53-
; SSE-NEXT: [[LD1:%.*]] = load <4 x double>, ptr [[P1]], align 32
54-
; SSE-NEXT: [[BLEND:%.*]] = shufflevector <4 x double> [[LD0]], <4 x double> [[LD1]], <4 x i32> <i32 0, i32 4, i32 4, i32 0>
55-
; SSE-NEXT: ret <4 x double> [[BLEND]]
56-
;
57-
; AVX-LABEL: define <4 x double> @blend_broadcasts_v4f64(
58-
; AVX-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) #[[ATTR0]] {
59-
; AVX-NEXT: [[LD0:%.*]] = load <4 x double>, ptr [[P0]], align 32
60-
; AVX-NEXT: [[LD1:%.*]] = load <4 x double>, ptr [[P1]], align 32
61-
; AVX-NEXT: [[BCST0:%.*]] = shufflevector <4 x double> [[LD0]], <4 x double> undef, <4 x i32> zeroinitializer
62-
; AVX-NEXT: [[BCST1:%.*]] = shufflevector <4 x double> [[LD1]], <4 x double> undef, <4 x i32> zeroinitializer
63-
; AVX-NEXT: [[BLEND:%.*]] = shufflevector <4 x double> [[BCST0]], <4 x double> [[BCST1]], <4 x i32> <i32 0, i32 5, i32 6, i32 3>
64-
; AVX-NEXT: ret <4 x double> [[BLEND]]
50+
; CHECK-LABEL: define <4 x double> @blend_broadcasts_v4f64(
51+
; CHECK-SAME: ptr [[P0:%.*]], ptr [[P1:%.*]]) #[[ATTR0]] {
52+
; CHECK-NEXT: [[TMP1:%.*]] = load <1 x double>, ptr [[P0]], align 8
53+
; CHECK-NEXT: [[TMP2:%.*]] = load <1 x double>, ptr [[P1]], align 8
54+
; CHECK-NEXT: [[BLEND:%.*]] = shufflevector <1 x double> [[TMP1]], <1 x double> [[TMP2]], <4 x i32> <i32 0, i32 1, i32 1, i32 0>
55+
; CHECK-NEXT: ret <4 x double> [[BLEND]]
6556
;
6657
%ld0 = load <4 x double>, ptr %p0, align 32
6758
%ld1 = load <4 x double>, ptr %p1, align 32
@@ -81,3 +72,6 @@ define <2 x float> @PR86068(<2 x float> %a0, <2 x float> %a1) {
8172
%s2 = shufflevector <2 x float> %s1, <2 x float> %a0, <2 x i32> <i32 0, i32 3>
8273
ret <2 x float> %s2
8374
}
75+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
76+
; AVX: {{.*}}
77+
; SSE: {{.*}}

llvm/test/Transforms/AggressiveInstCombine/load-shufflevector.ll renamed to llvm/test/Transforms/VectorCombine/load-shufflevector.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2-
; RUN: opt -passes=aggressive-instcombine -S < %s | FileCheck %s
2+
; RUN: opt -passes=vector-combine -S < %s | FileCheck %s
33

44
define <8 x half> @shuffle_v4_v8f16_r0_1_volatile(ptr addrspace(1) nocapture readonly %arg0) local_unnamed_addr {
55
; CHECK-LABEL: define <8 x half> @shuffle_v4_v8f16_r0_1_volatile(

0 commit comments

Comments
 (0)